Compare commits
43 Commits
release_1_
...
release_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5ef01710a | ||
|
|
e70e63612a | ||
|
|
28b26242c7 | ||
|
|
6b279a6f8c | ||
|
|
079f2d6807 | ||
|
|
b09417ca8d | ||
|
|
b15e3f1bbd | ||
|
|
1616b1d1b4 | ||
|
|
f23bc997fd | ||
|
|
8ec119a27f | ||
|
|
e35d05b1d2 | ||
|
|
cdb77dcd7b | ||
|
|
9bf87b195e | ||
|
|
643e3f2441 | ||
|
|
6e75833cb7 | ||
|
|
908d78d208 | ||
|
|
192f55e2a0 | ||
|
|
9d99fd13cd | ||
|
|
07902e9f9a | ||
|
|
0c94a109b9 | ||
|
|
27094c4fc3 | ||
|
|
5aca761e1b | ||
|
|
cc82db7f2d | ||
|
|
137ebf41fd | ||
|
|
49ea4c5057 | ||
|
|
409bddf38c | ||
|
|
c930802f31 | ||
|
|
ca14885884 | ||
|
|
01d6188297 | ||
|
|
759c5208c5 | ||
|
|
8457e06b99 | ||
|
|
8719c4f680 | ||
|
|
574022ab78 | ||
|
|
304d8b9f0c | ||
|
|
6712656eb2 | ||
|
|
415d9c9e15 | ||
|
|
1a8141ab8a | ||
|
|
023c766600 | ||
|
|
fdb46aa2e2 | ||
|
|
2504e7d3ae | ||
|
|
b0765e257c | ||
|
|
73d4c40a87 | ||
|
|
7aed52718f |
124
ChangeLog
124
ChangeLog
@@ -1,3 +1,127 @@
|
||||
2006-12-08 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* bootstrap: Add paxutils files to dot_ignore.
|
||||
|
||||
* configure.ac: Raise version number to 1.16.1
|
||||
* bootstrap (slurp): Create .(cvs|git)ignore if not present
|
||||
* po/.cvsignore, m4/.cvsignore: Remove automatically generated
|
||||
files.
|
||||
|
||||
2006-12-07 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* NEWS: Update
|
||||
* Makefile.am (distclean-local): Fixed
|
||||
* doc/tar.texi: Update documentation of --exclude-tag
|
||||
* src/create.c (dump_dir0): Move checks for exclude tags to
|
||||
dump_file0.
|
||||
(dump_dir): Move calls to ensure_slash to dump_file0
|
||||
* src/extract.c (extract_file): Call skip_member if open fails.
|
||||
Patch proposed by Jan-Benedict Glaw <jbglaw@lug-owl.de>
|
||||
* tests/truncate.at: Use genfile instead of dd, because on some
|
||||
systems /dev/zero is not available.
|
||||
|
||||
2006-12-04 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* NEWS: Fix some race conditions with tar -x --same-owner.
|
||||
* src/extract.c (ARCHIVED_PERMSTATS): Add a comment saying that
|
||||
S_IRWXG | S_IRWXO might be masked out.
|
||||
(set_mode): Set the mode if some bits were masked out originally.
|
||||
(set_stat): Don't chmod before chown, as that might temporarily
|
||||
grant permissions that we don't want to grant. The chmod was
|
||||
there only to work around broken hosts, so add a comment advising
|
||||
users not to use those broken hosts instead.
|
||||
(repair_delayed_set_stat, extract_dir):
|
||||
Remember to mask out current umask before inverting permissions.
|
||||
(extract_dir): If the owner might change, or if the mode has
|
||||
special bits, create the directory 700 at first, but restore it later.
|
||||
(open_output_file): New arg mode; all uses changed.
|
||||
(extract_file, extract_node, extract_fifo): If the owner might
|
||||
change, omit group and other bits at first, but restore them after
|
||||
changing the owner.
|
||||
|
||||
2006-12-04 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* doc/tar.texi (Long Options): Remove doubled word.
|
||||
|
||||
2006-11-30 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/xheader.c (xheader_read): Remove unused variable
|
||||
|
||||
* po/POTFILES.in: Remove src/mangle.c
|
||||
|
||||
* bootstrap: Implement --update-po and .bootstrap
|
||||
|
||||
* src/create.c (dump_dir0): Implement --exclude-tag option
|
||||
* src/tar.c: Likewise
|
||||
* doc/tar.texi (exclude): Document --exclude-tag
|
||||
|
||||
2006-11-29 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
* NEWS: Remove support for mangled names.
|
||||
* doc/tar.texi (verbose tutorial): Likewise.
|
||||
* src/Makefile.am (tar_SOURCES): Remove mangle.c.
|
||||
* src/common.h (extract_mangle): Remove decl.
|
||||
* src/extract.c (extract_mangle_wrapper): Remove.
|
||||
(prepare_to_extract): Remove support for mangled names.
|
||||
* src/list.c (read_and, print_header): Likewise.
|
||||
* src/mangle.c: Remove.
|
||||
* src/tar.h (GNUTYPE_NAMES): Remove.
|
||||
|
||||
Port to latest gnulib. There were a lot of changes, so the
|
||||
simplest way to get this up and running was to switch to coreutils
|
||||
bootstrap procedure. I noticed one feature missing after this
|
||||
merge: the ability to update a single .po file. I can add that
|
||||
later if need be.
|
||||
* README-cvs, bootstrap.conf: New files.
|
||||
* lib/.cvsignore: Remove Makefile.am, printf-parse.c, vasnprintf.c.
|
||||
Add fstatat.c, gnulib.mk, openat-proc.c, same-inode.h, stat_.h,
|
||||
tempname.c, tempname.h, uinttostr.c.
|
||||
* lib/printf-parse.c, lib/vasnprintf.c: New files, from coreutils,
|
||||
to override gnulib, so that we don't need xsize.h.
|
||||
* bootstrap: Replace with coreutils bootstrap, except add support
|
||||
for paxutils.
|
||||
* configure.ac (gl_USE_SYSTEM_EXTENSIONS): Remove, as gl_EARLY now
|
||||
does this.
|
||||
(gl_EARLY, gl_INIT): Add.
|
||||
(tar_GNULIB): Remove.
|
||||
* gnulib.modules: Add configmake.
|
||||
* lib/Makefile.tmpl: Remove, replacing with....
|
||||
* lib/Makefile.am: New file.
|
||||
* src/Makefile.am (tar.o): Remove dependency: Automake does this
|
||||
for us.
|
||||
* src/tar.c: Include <configmake.h> and <rmt-command.h>, not
|
||||
<localedir.h>.
|
||||
|
||||
2006-11-13 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/xheader.c (mtime_coder): Treat non-null data as a pointer to
|
||||
struct timespec, overriding st->mtime
|
||||
* src/create.c (start_header): Pass mtime as a call-specific data
|
||||
to xheader_store.
|
||||
|
||||
* tests/truncate.at: Do not use 'k' modifier in dd options.
|
||||
* tests/append02.at: Do not depend on command timing.
|
||||
|
||||
2006-11-01 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/tar.c (enum read_file_list_state.file_list_skip): New value
|
||||
(read_name_from_file): Skip zero-length entries
|
||||
|
||||
* tests/T-empty.at: New test case
|
||||
* tests/T-null.at: New test case
|
||||
* tests/extrac07.at: New test case
|
||||
* tests/Makefile.am: Add new test cases.
|
||||
* tests/testsuite.at: Add new test cases.
|
||||
* tests/extrac02.at: Add more keywords
|
||||
* tests/extrac04.at: Likewise
|
||||
* tests/extrac06.at: Likewise
|
||||
* tests/shortrec.at: Do not assume tar's default archive is stdout
|
||||
|
||||
2006-10-31 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* src/extract.c, src/xheader.c: Call last_component instead of
|
||||
base_name. The latter returns a malloced string since 2006-03-11.
|
||||
|
||||
2006-10-21 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||
|
||||
* NEWS, configure.ac: Version 1.16
|
||||
|
||||
@@ -28,4 +28,4 @@ dist-hook:
|
||||
GZIP=$(GZIP_ENV) gzip -c > $(distdir).cpio.gz
|
||||
|
||||
distclean-local:
|
||||
-rm -f $(PACKAGE)-$(VERSION).cpio.gz
|
||||
-rm -f $(distdir).cpio.gz
|
||||
|
||||
42
NEWS
42
NEWS
@@ -1,6 +1,30 @@
|
||||
GNU tar NEWS - User visible changes.
|
||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||
|
||||
version 1.16.1
|
||||
|
||||
* New option --exclude-tag allows to specify "exclusion tag files", i.e.
|
||||
files whose presence in a directory means that the directory should not
|
||||
be archived.
|
||||
|
||||
* The --exclude-cache option excludes directories that contain the
|
||||
CACHEDIR.TAG file from being archived. Previous versions excluded
|
||||
directory contents only, while the directories themselves were
|
||||
still added to the archive.
|
||||
|
||||
* Support for reading ustar type 'N' header logical records has been removed.
|
||||
This GNU extension was generated only by very old versions of GNU 'tar'.
|
||||
Unfortunately its implementation had security holes; see
|
||||
<http://archives.neohapsis.com/archives/fulldisclosure/2006-11/0344.html>.
|
||||
We don't expect that any tar archives in practical use have type 'N'
|
||||
records, but if you have one and you trust its contents, you can
|
||||
decode it with GNU tar 1.16 or earlier.
|
||||
|
||||
* Race conditions have been fixed that in some cases briefly allowed
|
||||
files extracted by 'tar -x --same-owner' (or plain 'tar -x', when
|
||||
running as root) to be accessed by users that they shouldn't have been.
|
||||
|
||||
|
||||
version 1.16 - Sergey Poznyakoff, 2006-10-21
|
||||
|
||||
* After creating an archive, tar exits with code 1 if some files were
|
||||
@@ -8,7 +32,7 @@ changed while being read. Previous versions exited with code 2 (fatal
|
||||
error), and only if some files were truncated while being archived.
|
||||
|
||||
* New option --mtime allows to set modification times for all archive
|
||||
members during creation.
|
||||
members during creation.
|
||||
|
||||
* Bug fixes
|
||||
** Avoid running off file descriptors when using multiple -C options.
|
||||
@@ -34,14 +58,14 @@ no longer uses globbing by default. For example, the above invocation
|
||||
is now interpreted as a request to extract from the archive the file
|
||||
named '*.c'.
|
||||
|
||||
To treat member names as globbing patterns, use --wildcards option.
|
||||
To treat member names as globbing patterns, use --wildcards option.
|
||||
If you wish tar to mimic the behavior of versions up to 1.15.90,
|
||||
add --wildcards to the value of the environment variable TAR_OPTIONS.
|
||||
|
||||
The exact way in which tar interprets member names is controlled by the
|
||||
following command line options:
|
||||
|
||||
--wildcards use wildcards
|
||||
--wildcards use wildcards
|
||||
--anchored patterns match file name start
|
||||
--ignore-case ignore case
|
||||
--wildcards-match-slash wildcards match `/'
|
||||
@@ -49,7 +73,7 @@ following command line options:
|
||||
Each of these options has a '--no-' counterpart that disables its
|
||||
effect (e.g. --no-wildcards).
|
||||
|
||||
These options affect both the interpretation of member names from
|
||||
These options affect both the interpretation of member names from
|
||||
command line and that of the exclusion patterns (given with --exclude
|
||||
and --exclude-from options). The defaults are:
|
||||
|
||||
@@ -65,7 +89,7 @@ case-sensitive matching for the rest of command line, one could write:
|
||||
|
||||
** Short option -l is now an alias of --check-links option, which complies
|
||||
with UNIX98. This ends the transition period started with version 1.14.
|
||||
|
||||
|
||||
* New features
|
||||
|
||||
** New option --transform allows to transform file names before storing them
|
||||
@@ -80,19 +104,19 @@ will add 'prefix/' to all file names stored in foo.tar.
|
||||
versions it worked only with --extract.
|
||||
|
||||
** New option --show-transformed-names enables display of transformed file
|
||||
or archive. It generalizes --show-stored-names option, introduced in
|
||||
1.15.90. In particular, when creating an archive in verbose mode, it lists
|
||||
or archive. It generalizes --show-stored-names option, introduced in
|
||||
1.15.90. In particular, when creating an archive in verbose mode, it lists
|
||||
member names as stored in the archive, i.e., with any eventual prefixes
|
||||
removed and file name transformations applied. The option is useful,
|
||||
for example, while comparing `tar cv' and `tar tv' outputs.
|
||||
|
||||
** New incremental snapshot file format keeps information about file names
|
||||
** New incremental snapshot file format keeps information about file names
|
||||
as well as that about directories.
|
||||
|
||||
** The --checkpoint option takes an optional argument specifying the number
|
||||
of records between the two successive checkpoints. Optional dot
|
||||
starting the argument intructs tar to print dots instead of textual
|
||||
checkpoints.
|
||||
checkpoints.
|
||||
|
||||
** The --totals option can be used with any tar operation (previous versions
|
||||
understood it only with --create). If an argument to this option is
|
||||
|
||||
70
README-cvs
Normal file
70
README-cvs
Normal file
@@ -0,0 +1,70 @@
|
||||
-*- outline -*-
|
||||
|
||||
These notes intend to help people working on the CVS version of
|
||||
this package.
|
||||
|
||||
* Requirements
|
||||
|
||||
Only the sources are installed in the CVS repository (to ease the
|
||||
maintenance, merges etc.), therefore you will have to get the latest
|
||||
stable versions of the maintainer tools we depend upon, including:
|
||||
|
||||
- Automake <http://www.gnu.org/software/automake/>
|
||||
- Autoconf <http://www.gnu.org/software/autoconf/>
|
||||
- Bison <http://www.gnu.org/software/bison/>
|
||||
- Gettext <http://www.gnu.org/software/gettext/>
|
||||
- Gzip <http://www.gnu.org/software/gzip/>
|
||||
- Tar <http://www.gnu.org/software/tar/>
|
||||
- Wget <http://www.gnu.org/software/wget/>
|
||||
|
||||
As of this writing, the latest stable version of Gzip is 1.2.4 but we
|
||||
suggest using test version 1.3.5 (or later, if one becomes available).
|
||||
|
||||
Valgrind <http://valgrind.org/> is also highly recommended, if
|
||||
Valgrind supports your architecture.
|
||||
|
||||
Only building the initial full source tree will be a bit painful,
|
||||
later, a plain `cvs update -P && make' should be sufficient.
|
||||
|
||||
* First CVS checkout
|
||||
|
||||
Obviously, if you are reading these notes, you did manage to check out
|
||||
this package from CVS. The next step is to get other files needed to
|
||||
build, which are extracted from other source packages:
|
||||
|
||||
$ ./bootstrap
|
||||
|
||||
And there you are! Just
|
||||
|
||||
$ ./configure
|
||||
$ make
|
||||
$ make check
|
||||
|
||||
At this point, there should be no difference between your local copy,
|
||||
and the CVS master copy:
|
||||
|
||||
$ cvs diff
|
||||
|
||||
should output no difference.
|
||||
|
||||
Enjoy!
|
||||
|
||||
-----
|
||||
|
||||
Copyright (C) 2002, 2003, 2004, 2005, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA.
|
||||
734
bootstrap
734
bootstrap
@@ -21,10 +21,8 @@
|
||||
|
||||
# Written by Paul Eggert and Sergey Poznyakoff.
|
||||
|
||||
package=tar
|
||||
|
||||
# Translation Project URL, for the registry of all projects.
|
||||
TP_URL='http://www.iro.umontreal.ca/translation/registry.cgi?domain='
|
||||
nl='
|
||||
'
|
||||
|
||||
# Ensure file names are sorted consistently across platforms.
|
||||
# Also, ensure diagnostics are in English, e.g., "wget --help" below.
|
||||
@@ -32,75 +30,186 @@ LC_ALL=C
|
||||
export LC_ALL
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
usage: $0 [--gnulib-srcdir=DIR][--paxutils-srcdir=DIR][--cvs-auth=AUTH-METHOD][--cvs-user=USERNAME][--no-po]
|
||||
Options are:
|
||||
--paxutils-srcdir=DIRNAME Specify the local directory where paxutils
|
||||
sources reside. Use this if you already
|
||||
have paxutils sources on your machine, and
|
||||
do not want to waste your bandwidth dowloading
|
||||
them again.
|
||||
--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.
|
||||
--update-po[=LANG] Update po file(s) and exit.
|
||||
echo >&2 "\
|
||||
Usage: $0 [OPTION]...
|
||||
Bootstrap this package from the checked-out sources.
|
||||
|
||||
If the file \`.bootstrap' exists in the current working directory, its
|
||||
contents is read, comments and empty lines removed, shell variables expanded
|
||||
and the result is prepended to the command line options.
|
||||
Options:
|
||||
--paxutils-srcdir=DIRNAME Specify the local directory where paxutils
|
||||
sources reside. Use this if you already
|
||||
have paxutils sources on your machine, and
|
||||
do not want to waste your bandwidth dowloading
|
||||
them again.
|
||||
--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.
|
||||
--copy Copy files instead of creating symbolic links.
|
||||
--force Attempt to bootstrap even if the sources seem
|
||||
not to have been checked out.
|
||||
--skip-po Do not download po files.
|
||||
--update-po[=LANG] Update po file(s) and exit.
|
||||
--cvs-user=USERNAME Set the CVS username to be used when accessing
|
||||
the gnulib repository.
|
||||
|
||||
Running without arguments will suffice in most cases. It is equivalent
|
||||
to
|
||||
If the file bootstrap.conf exists in the current working directory, its
|
||||
contents are read as shell variables to configure the bootstrap.
|
||||
|
||||
./bootstrap --cvs-auth=pserver
|
||||
Local defaults can be provided by placing the file \`.bootstrap' in the
|
||||
current working directory. The file is read after bootstrap.conf, comments
|
||||
and empty lines are removed, shell variables expanded and the result is
|
||||
prepended to the command line options.
|
||||
|
||||
EOF
|
||||
Running without arguments will suffice in most cases.
|
||||
"
|
||||
}
|
||||
|
||||
# Read configuration file
|
||||
checkout() {
|
||||
if [ ! -d $1 ]; then
|
||||
echo "$0: getting $1 files..."
|
||||
|
||||
case ${CVS_AUTH-pserver} in
|
||||
pserver)
|
||||
CVS_PREFIX=':pserver:anonymous@';;
|
||||
ssh)
|
||||
CVS_PREFIX="$CVS_USER${CVS_USER+@}";;
|
||||
*)
|
||||
echo "$0: $CVS_AUTH: Unknown CVS access method" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
|
||||
case $CVS_RSH in
|
||||
'') CVS_RSH=ssh; export CVS_RSH;;
|
||||
esac
|
||||
|
||||
trap "cleanup $1" 1 2 13 15
|
||||
|
||||
cvs -z3 -q -d ${CVS_PREFIX}cvs.savannah.gnu.org:/cvsroot/"$1" co $1 ||
|
||||
cleanup $1
|
||||
|
||||
trap - 1 2 13 15
|
||||
fi
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
status=$?
|
||||
rm -fr $1
|
||||
exit $status
|
||||
}
|
||||
|
||||
# Configuration.
|
||||
|
||||
# List of gnulib modules needed.
|
||||
gnulib_modules=
|
||||
|
||||
# Any gnulib files needed that are not in modules.
|
||||
gnulib_files=
|
||||
|
||||
# Translation Project URL, for the registry of all projects
|
||||
# and for the translation-team master directory.
|
||||
TP_URL='http://www.iro.umontreal.ca/translation/registry.cgi?domain='
|
||||
TP_PO_URL='http://www.iro.umontreal.ca/translation/teams/PO/'
|
||||
|
||||
extract_package_name='
|
||||
/^AC_INIT(/{
|
||||
/.*,.*,.*,/{
|
||||
s///
|
||||
s/[][]//g
|
||||
p
|
||||
q
|
||||
}
|
||||
s/AC_INIT(\[*//
|
||||
s/]*,.*//
|
||||
s/^GNU //
|
||||
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
|
||||
s/[^A-Za-z0-9_]/-/g
|
||||
p
|
||||
}
|
||||
'
|
||||
package=`sed -n "$extract_package_name" configure.ac` || exit
|
||||
|
||||
# Extra files from gnulib, which override files from other sources.
|
||||
gnulib_extra_files='
|
||||
build-aux/announce-gen
|
||||
build-aux/install-sh
|
||||
build-aux/missing
|
||||
build-aux/mdate-sh
|
||||
build-aux/texinfo.tex
|
||||
build-aux/depcomp
|
||||
build-aux/config.guess
|
||||
build-aux/config.sub
|
||||
doc/INSTALL
|
||||
'
|
||||
|
||||
# Other locale categories that need message catalogs.
|
||||
EXTRA_LOCALE_CATEGORIES=
|
||||
|
||||
# Additional xgettext options to use. Use "\\\newline" to break lines.
|
||||
XGETTEXT_OPTIONS='\\\
|
||||
--flag=_:1:pass-c-format\\\
|
||||
--flag=N_:1:pass-c-format\\\
|
||||
--flag=error:3:c-format --flag=error_at_line:5:c-format\\\
|
||||
'
|
||||
|
||||
# Files we don't want to import.
|
||||
excluded_files=
|
||||
|
||||
# File that should exist in the top directory of a checked out hierarchy,
|
||||
# but not in a distribution tarball.
|
||||
CVS_only_file=README-cvs
|
||||
|
||||
# Whether to use copies instead of symlinks.
|
||||
copy=false
|
||||
|
||||
# Override the default configuration, if necessary.
|
||||
test -r bootstrap.conf && . ./bootstrap.conf
|
||||
|
||||
# Read local configuration file
|
||||
if [ -r .bootstrap ]; then
|
||||
echo "$0: Reading configuration file .bootstrap"
|
||||
eval set -- "`sed 's/#.*$//;/^$/d' .bootstrap | tr '\n' ' '` $*"
|
||||
fi
|
||||
|
||||
# Translate configuration into internal form.
|
||||
|
||||
# Parse options.
|
||||
|
||||
DOWNLOAD_PO=yes
|
||||
for option
|
||||
do
|
||||
case $option in
|
||||
--help)
|
||||
usage
|
||||
exit;;
|
||||
--gnulib-srcdir=*)
|
||||
GNULIB_SRCDIR=`expr "$option" : '--gnulib-srcdir=\(.*\)'`;;
|
||||
--paxutils-srcdir=*)
|
||||
PAXUTILS_SRCDIR=`expr "$option" : '--paxutils-srcdir=\(.*\)'`;;
|
||||
--cvs-auth=*)
|
||||
CVS_AUTH=`expr "$option" : '--cvs-auth=\(.*\)'`;;
|
||||
--gnulib-srcdir=*)
|
||||
GNULIB_SRCDIR=`expr "$option" : '--gnulib-srcdir=\(.*\)'`;;
|
||||
--cvs-user=*)
|
||||
CVS_USER=`expr "$option" : '--cvs-user=\(.*\)'`;;
|
||||
--no-po)
|
||||
DOWNLOAD_PO=no;;
|
||||
--skip-po | --no-po) # --no-po is for compatibility with 'tar' tradition.
|
||||
DOWNLOAD_PO=skip;;
|
||||
--update-po=*)
|
||||
DOWNLOAD_PO=`expr "$option" : '--update-po=\(.*\)'`;;
|
||||
--update-po)
|
||||
DOWNLOAD_PO=only;;
|
||||
--force)
|
||||
CVS_only_file=;;
|
||||
--copy)
|
||||
copy=true;;
|
||||
*)
|
||||
echo >&2 "$0: $option: unknown option"
|
||||
exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if test -n "$CVS_only_file" && test ! -r "$CVS_only_file"; then
|
||||
echo "$0: Bootstrapping from a non-checked-out distribution is risky." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$0: Bootstrapping CVS $package..."
|
||||
|
||||
# Get translations.
|
||||
|
||||
get_translations() {
|
||||
@@ -108,141 +217,105 @@ get_translations() {
|
||||
domain=$2
|
||||
po_file=$3
|
||||
|
||||
echo "$0: getting translations into $subdir for $domain..."
|
||||
case $WGET_COMMAND in
|
||||
'')
|
||||
echo "$0: wget not available; skipping translations";;
|
||||
?*)
|
||||
echo "$0: getting ${po_file:-translations} into $subdir for $domain..." &&
|
||||
case $po_file in
|
||||
'') (cd $subdir && rm -f dummy `ls | sed -n '/\.gmo$/p; /\.po/p'`);;
|
||||
esac &&
|
||||
|
||||
$WGET_COMMAND -O "$subdir/$domain.html" "$TP_URL$domain" &&
|
||||
|
||||
case $po_file in
|
||||
'') (cd $subdir && rm -f dummy `ls | sed -n '/\.gmo$/p; /\.po/p'`);;
|
||||
sed -n 's|.*"http://[^"]*/translation/teams/PO/\([^/"]*\)/'"$domain"'-\([^/"]*\)\.[^."]*\.po".*|\1.\2|p' <"$subdir/$domain.html" |
|
||||
sort -k 1,1 -k 2,2n -k2,2 -k3,3n -k3,3 -k4,4n -k4,4 -k5,5n -k5.5 |
|
||||
awk -F. '
|
||||
{ if (lang && $1 != lang) print lang, ver }
|
||||
{ lang = $1; ver = substr($0, index($0, ".") + 1) }
|
||||
END { if (lang) print lang, ver }
|
||||
' | awk -v domain="$domain" -v po_file="$po_file" -v subdir="$subdir" '
|
||||
{
|
||||
lang = $1
|
||||
if (po_file && po_file != (lang ".po")) next
|
||||
|
||||
ver = $2
|
||||
urlfmt = ""
|
||||
printf "{ $WGET_COMMAND -O %s/%s.po '\'"$TP_PO_URL"'/%s/%s-%s.%s.po'\'' &&\n", subdir, lang, lang, domain, ver, lang
|
||||
printf " msgfmt -c -o /dev/null %s/%s.po || {\n", subdir, lang
|
||||
printf " echo >&2 '\'"$0"': omitting translation for %s'\''\n", lang
|
||||
printf " rm -f %s/%s.po; }; } &&\n", subdir, lang
|
||||
}
|
||||
END { print ":" }
|
||||
' | WGET_COMMAND="$WGET_COMMAND" sh;;
|
||||
esac &&
|
||||
|
||||
$WGET_COMMAND -O "$subdir/$domain.html" "$TP_URL$domain" &&
|
||||
|
||||
sed -n 's|.*"http://[^"]*/translation/teams/PO/\([^/"]*\)/'"$domain"'-\([^/"]*\)\.[^."]*\.po".*|\1.\2|p' <"$subdir/$domain.html" |
|
||||
sort -k 1,1 -k 2,2n -k2,2 -k3,3n -k3,3 -k4,4n -k4,4 -k5,5n -k5.5 |
|
||||
awk -F. '
|
||||
{ if (lang && $1 != lang) print lang, ver }
|
||||
{ lang = $1; ver = substr($0, index($0, ".") + 1) }
|
||||
END { if (lang) print lang, ver }
|
||||
' |
|
||||
awk -v domain="$domain" -v po_file="$po_file" -v subdir="$subdir" '
|
||||
{
|
||||
lang = $1
|
||||
if (po_file && po_file != (lang ".po")) next
|
||||
|
||||
# Work around bugs in translations uncovered by gettext 0.15.
|
||||
# This workaround can be removed once the translations are fixed.
|
||||
if (lang == "hu" || lang == "zh_TW") next
|
||||
|
||||
ver = $2
|
||||
urlfmt = ""
|
||||
printf "$WGET_COMMAND -O %s/%s.po 'http://www.iro.umontreal.ca/translation/teams/PO/%s/%s-%s.%s.po' &&\n", subdir, lang, lang, domain, ver, lang
|
||||
}
|
||||
END { print ":" }
|
||||
' |
|
||||
sh &&
|
||||
ls "$subdir"/*.po | sed 's|.*/||; s|\.po$||' >"$subdir/LINGUAS" &&
|
||||
rm "$subdir/$domain.html"
|
||||
ls "$subdir"/*.po 2>/dev/null |
|
||||
sed 's|.*/||; s|\.po$||' >"$subdir/LINGUAS" &&
|
||||
rm -f "$subdir/$domain.html"
|
||||
}
|
||||
|
||||
update_po() {
|
||||
if [ $# = 1 ]; then
|
||||
case $1 in
|
||||
*.po) POFILE=$1;;
|
||||
*) POFILE=${1}.po;;
|
||||
esac
|
||||
get_translations po $package "$POFILE"
|
||||
else
|
||||
get_translations po $package
|
||||
fi
|
||||
}
|
||||
|
||||
case $DOWNLOAD_PO in
|
||||
no) ;;
|
||||
case `wget --help` in
|
||||
*'--no-cache'*)
|
||||
WGET_COMMAND='wget -nv --no-cache';;
|
||||
*'--cache=on/off'*)
|
||||
WGET_COMMAND='wget -nv --cache=off';;
|
||||
*'--non-verbose'*)
|
||||
WGET_COMMAND='wget -nv';;
|
||||
*)
|
||||
case `wget --help` in
|
||||
*'--no-cache'*)
|
||||
no_cache='--no-cache';;
|
||||
*'--cache=on/off'*)
|
||||
no_cache='--cache=off';;
|
||||
*)
|
||||
no_cache='';;
|
||||
esac
|
||||
|
||||
WGET_COMMAND="wget -nv $no_cache"
|
||||
export WGET_COMMAND
|
||||
WGET_COMMAND='';;
|
||||
esac
|
||||
|
||||
case $DOWNLOAD_PO in
|
||||
only) update_po
|
||||
exit
|
||||
;;
|
||||
no|yes) ;;
|
||||
*) update_po $DOWNLOAD_PO
|
||||
exit
|
||||
'skip')
|
||||
;;
|
||||
'')
|
||||
get_translations po $package || exit
|
||||
;;
|
||||
'only')
|
||||
get_translations po $package
|
||||
exit
|
||||
;;
|
||||
*.po)
|
||||
get_translations po $package "$DOWNLOAD_PO"
|
||||
exit
|
||||
;;
|
||||
*)
|
||||
get_translations po $package "${DOWNLOAD_PO}.po"
|
||||
exit
|
||||
esac
|
||||
|
||||
# Get paxutils files.
|
||||
|
||||
echo "$0: Bootstrapping CVS $package..."
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
# checkout package
|
||||
checkout() {
|
||||
if [ ! -d $1 ]; then
|
||||
echo "$0: getting $1 files..."
|
||||
|
||||
trap exit 1 2 13 15
|
||||
trap 'rm -fr $1; exit 1' 0
|
||||
|
||||
case "${CVS_AUTH-pserver}" in
|
||||
pserver) build_cvs_prefix pserver ${CVS_USER:-anonymous}
|
||||
;;
|
||||
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
|
||||
cvs -q -d ${CVS_PREFIX}cvs.sv.gnu.org:/cvsroot/$1 co $1 || exit
|
||||
|
||||
trap - 0
|
||||
fi
|
||||
}
|
||||
|
||||
gnulib_modules=
|
||||
newline='
|
||||
'
|
||||
|
||||
get_modules() {
|
||||
new_gnulib_modules=`sed '/^[ ]*#/d; /^[ ]*$/d' $*`
|
||||
case $gnulib_modules,$new_gnulib_modules in
|
||||
?*,?*) new_gnulib_modules=$newline$new_gnulib_modules;;
|
||||
esac
|
||||
gnulib_modules=$gnulib_modules$new_gnulib_modules
|
||||
}
|
||||
|
||||
# Get paxutils files
|
||||
case ${PAXUTILS_SRCDIR--} in
|
||||
-) checkout paxutils
|
||||
PAXUTILS_SRCDIR=paxutils
|
||||
esac
|
||||
|
||||
if [ -r $PAXUTILS_SRCDIR/gnulib.modules ]; then
|
||||
get_modules $PAXUTILS_SRCDIR/gnulib.modules
|
||||
gnulib_modules=`
|
||||
(echo "$gnulib_modules"; grep '^[^#]' $PAXUTILS_SRCDIR/gnulib.modules) |
|
||||
sort -u
|
||||
`
|
||||
fi
|
||||
|
||||
ignore_file_list=
|
||||
cleanup_ifl() {
|
||||
test -n "$ignore_file_list" && rm -f $ignore_file_list
|
||||
}
|
||||
|
||||
trap 'cleanup_ifl' 1 2 3 15
|
||||
|
||||
# ignorefile DIR FILE
|
||||
# add FILE to the temporary ignorelist in the directory DIR
|
||||
ignorefile() {
|
||||
file=$1/.ignore.$$
|
||||
echo "$2" >> $file
|
||||
if `echo $ignore_list | grep -qv $file`; then
|
||||
ignore_file_list="$ignore_file_list
|
||||
$file"
|
||||
fi
|
||||
}
|
||||
|
||||
# copy_files srcdir dstdir
|
||||
copy_files() {
|
||||
for file in `cat $1/DISTFILES`
|
||||
@@ -259,6 +332,7 @@ copy_files() {
|
||||
fi
|
||||
echo "$0: Copying file $1/$file to $2/$dst"
|
||||
cp -p $1/$file $2/$dst
|
||||
ignorefile $2 $dst
|
||||
done
|
||||
}
|
||||
|
||||
@@ -269,6 +343,7 @@ echo "$0: Creating m4/paxutils.m4"
|
||||
echo "AC_DEFUN([${package}_PAXUTILS],["
|
||||
cat ${PAXUTILS_SRCDIR}/m4/DISTFILES | sed '/^#/d;s/\(.*\)\.m4/pu_\1/' | tr a-z A-Z
|
||||
echo "])") > ./m4/paxutils.m4
|
||||
ignorefile m4 paxutils.m4
|
||||
|
||||
if [ -d rmt ]; then
|
||||
:
|
||||
@@ -286,111 +361,237 @@ copy_files ${PAXUTILS_SRCDIR}/paxlib lib pax
|
||||
# Get gnulib files.
|
||||
|
||||
case ${GNULIB_SRCDIR--} in
|
||||
-) checkout gnulib
|
||||
GNULIB_SRCDIR=gnulib
|
||||
-)
|
||||
checkout gnulib
|
||||
GNULIB_SRCDIR=gnulib
|
||||
esac
|
||||
|
||||
gnulib_tool=$GNULIB_SRCDIR/gnulib-tool
|
||||
<$gnulib_tool || exit
|
||||
|
||||
get_modules gnulib.modules
|
||||
symlink_to_gnulib()
|
||||
{
|
||||
src=$GNULIB_SRCDIR/$1
|
||||
dst=${2-$1}
|
||||
|
||||
gnulib_modules=`echo "$gnulib_modules" | sort -u`
|
||||
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_tool --extract-dependencies $gnulib_module
|
||||
done) | sort -u
|
||||
`
|
||||
test -f "$src" && {
|
||||
if $copy; then
|
||||
{
|
||||
test ! -h "$dst" || {
|
||||
echo "$0: rm -f $dst" &&
|
||||
rm -f "$dst"
|
||||
}
|
||||
} &&
|
||||
test -f "$dst" &&
|
||||
cmp -s "$src" "$dst" || {
|
||||
echo "$0: cp -fp $src $dst" &&
|
||||
cp -fp "$src" "$dst"
|
||||
}
|
||||
else
|
||||
test -h "$dst" &&
|
||||
src_ls=`ls -diL "$src" 2>/dev/null` && set $src_ls && src_i=$1 &&
|
||||
dst_ls=`ls -diL "$dst" 2>/dev/null` && set $dst_ls && dst_i=$1 &&
|
||||
test "$src_i" = "$dst_i" || {
|
||||
dot_dots=
|
||||
case $src in
|
||||
/*) ;;
|
||||
*)
|
||||
case /$dst/ in
|
||||
*//* | */../* | */./* | /*/*/*/*/*/)
|
||||
echo >&2 "$0: invalid symlink calculation: $src -> $dst"
|
||||
exit 1;;
|
||||
/*/*/*/*/) dot_dots=../../../;;
|
||||
/*/*/*/) dot_dots=../../;;
|
||||
/*/*/) dot_dots=../;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
echo "$0: ln -fs $dot_dots$src $dst" &&
|
||||
ln -fs "$dot_dots$src" "$dst"
|
||||
}
|
||||
fi
|
||||
}
|
||||
}
|
||||
|
||||
cp_mark_as_generated()
|
||||
{
|
||||
cp_src=$1
|
||||
cp_dst=$2
|
||||
|
||||
if cmp -s "$cp_src" "$GNULIB_SRCDIR/$cp_dst"; then
|
||||
symlink_to_gnulib "$cp_dst"
|
||||
else
|
||||
case $cp_dst in
|
||||
*.[ch]) c1='/* '; c2=' */';;
|
||||
*.texi) c1='@c '; c2= ;;
|
||||
*.m4|*/Make*|Make*) c1='# ' ; c2= ;;
|
||||
*) c1= ; c2= ;;
|
||||
esac
|
||||
|
||||
if test -z "$c1"; then
|
||||
cmp -s "$cp_src" "$cp_dst" || {
|
||||
echo "$0: cp -f $cp_src $cp_dst" &&
|
||||
cp -f "$cp_src" "$cp_dst"
|
||||
}
|
||||
else
|
||||
# Copy the file first to get proper permissions if it
|
||||
# doesn't already exist. Then overwrite the copy.
|
||||
cp "$cp_src" "$cp_dst-t" &&
|
||||
(
|
||||
echo "$c1-*- buffer-read-only: t -*- vi: set ro:$c2" &&
|
||||
echo "${c1}DO NOT EDIT! GENERATED AUTOMATICALLY!$c2" &&
|
||||
cat "$cp_src"
|
||||
) > $cp_dst-t &&
|
||||
if cmp -s "$cp_dst-t" "$cp_dst"; then
|
||||
rm -f "$cp_dst-t"
|
||||
else
|
||||
echo "$0: cp $cp_src $cp_dst # with edits" &&
|
||||
mv -f "$cp_dst-t" "$cp_dst"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
version_controlled_file() {
|
||||
dir=$1
|
||||
file=$2
|
||||
found=no
|
||||
if test -d CVS; then
|
||||
grep -F "/$file/" $dir/CVS/Entries 2>/dev/null |
|
||||
grep '^/[^/]*/[0-9]' > /dev/null && found=yes
|
||||
elif test -d .git; then
|
||||
git-rm -n "$dir/$file" > /dev/null 2>&1 && found=yes
|
||||
else
|
||||
echo "$0: no version control for $dir/$file?" >&2
|
||||
fi
|
||||
test $found = yes
|
||||
}
|
||||
|
||||
slurp() {
|
||||
for dir in . `(cd $1 && find * -type d -print)`; do
|
||||
copied=
|
||||
sep=
|
||||
for file in `ls $1/$dir`; do
|
||||
test -d $1/$dir/$file && continue
|
||||
for excluded_file in $excluded_files; do
|
||||
test "$dir/$file" = "$excluded_file" && continue 2
|
||||
done
|
||||
if test $file = Makefile.am; then
|
||||
copied=$copied${sep}gnulib.mk; sep=$nl
|
||||
remove_intl='/^[^#].*\/intl/s/^/#/'
|
||||
sed "$remove_intl" $1/$dir/$file | cmp -s - $dir/gnulib.mk || {
|
||||
echo "$0: Copying $1/$dir/$file to $dir/gnulib.mk ..." &&
|
||||
rm -f $dir/gnulib.mk &&
|
||||
sed "$remove_intl" $1/$dir/$file >$dir/gnulib.mk
|
||||
}
|
||||
elif { test "${2+set}" = set && test -r $2/$dir/$file; } ||
|
||||
version_controlled_file $dir $file; then
|
||||
echo "$0: $dir/$file overrides $1/$dir/$file"
|
||||
else
|
||||
copied=$copied$sep$file; sep=$nl
|
||||
if test $file = gettext.m4; then
|
||||
echo "$0: patching m4/gettext.m4 to remove need for intl/* ..."
|
||||
rm -f $dir/$file
|
||||
sed '
|
||||
/^AC_DEFUN(\[AM_INTL_SUBDIR],/,/^]/c\
|
||||
AC_DEFUN([AM_INTL_SUBDIR], [
|
||||
/^AC_DEFUN(\[gt_INTL_SUBDIR_CORE],/,/^]/c\
|
||||
AC_DEFUN([gt_INTL_SUBDIR_CORE], [])
|
||||
$a\
|
||||
AC_DEFUN([gl_LOCK_EARLY], [])
|
||||
' $1/$dir/$file >$dir/$file
|
||||
else
|
||||
cp_mark_as_generated $1/$dir/$file $dir/$file
|
||||
fi
|
||||
fi || exit
|
||||
done
|
||||
|
||||
if test -n "$copied"; then
|
||||
copied="Makefile
|
||||
Makefile.in
|
||||
$copied"
|
||||
if test -d CVS; then
|
||||
dot_ig=.cvsignore
|
||||
else
|
||||
dor_ig=.gitignore
|
||||
fi
|
||||
|
||||
ig=$dir/$dot_ig
|
||||
if [ -f $dir/.ignore.$$ ]; then
|
||||
tfile=$dir/.ignore.$$
|
||||
else
|
||||
tfile=
|
||||
fi
|
||||
if test -f $ig; then
|
||||
echo "$copied" | sort -u - $ig | cmp -s - $ig ||
|
||||
echo "$copied" | sort -u - $ig $tfile -o $ig
|
||||
else
|
||||
copied="$dot_ig
|
||||
$copied"
|
||||
if [ "$dir" = "po" ]; then
|
||||
copied="LINGUAS
|
||||
Makevars
|
||||
POTFILES
|
||||
*.mo
|
||||
*.gmo
|
||||
*.po
|
||||
remove-potcdate.sed
|
||||
stamp-po
|
||||
$package.pot
|
||||
$copied"
|
||||
fi
|
||||
echo "$copied" | sort -u - $tfile -o $ig
|
||||
fi || exit
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# Create boot temporary directories to import from gnulib and gettext.
|
||||
|
||||
bt='.#bootmp'
|
||||
bt2=${bt}2
|
||||
rm -fr $bt $bt2 &&
|
||||
mkdir $bt $bt2 || exit
|
||||
|
||||
# Import from gnulib.
|
||||
|
||||
test -d build-aux || {
|
||||
echo "$0: mkdir build-aux ..." &&
|
||||
mkdir build-aux
|
||||
} || exit
|
||||
gnulib_tool_options="\
|
||||
--import\
|
||||
--no-changelog\
|
||||
--aux-dir $bt/build-aux\
|
||||
--doc-base $bt/doc\
|
||||
--lib lib$package\
|
||||
--m4-base $bt/m4/\
|
||||
--source-base $bt/lib/\
|
||||
--tests-base $bt/tests\
|
||||
--local-dir gl\
|
||||
"
|
||||
echo "$0: $gnulib_tool $gnulib_tool_options --import ..."
|
||||
$gnulib_tool $gnulib_tool_options --import $gnulib_modules &&
|
||||
slurp $bt || exit
|
||||
|
||||
for file in $gnulib_files; do
|
||||
symlink_to_gnulib $file || exit
|
||||
done
|
||||
|
||||
gnulib_files=`
|
||||
(for gnulib_module in $gnulib_modules; do
|
||||
$gnulib_tool --extract-filelist $gnulib_module
|
||||
done) | sort -u
|
||||
`
|
||||
|
||||
gnulib_dirs=`echo "$gnulib_files" | sed 's,/[^/]*$,,' | sort -u`
|
||||
mkdir -p $gnulib_dirs || exit
|
||||
# Import from gettext.
|
||||
|
||||
for gnulib_file in $gnulib_files; do
|
||||
dest=$gnulib_file
|
||||
rm -f $dest &&
|
||||
echo "$0: Copying file $GNULIB_SRCDIR/$gnulib_file" &&
|
||||
cp -p $GNULIB_SRCDIR/$gnulib_file $dest || exit
|
||||
done
|
||||
echo "$0: (cd $bt2; autopoint) ..."
|
||||
cp configure.ac $bt2 &&
|
||||
(cd $bt2 && autopoint && rm configure.ac) &&
|
||||
slurp $bt2 $bt || exit
|
||||
|
||||
# This suppresses a bogus diagnostic
|
||||
# "warning: macro `AM_LANGINFO_CODESET' not found in library".
|
||||
echo "$0: patching m4/gettext.m4 to remove need for intl/* ..."
|
||||
sed '
|
||||
/^AC_DEFUN(\[AM_INTL_SUBDIR],/,/^]/c\
|
||||
AC_DEFUN([AM_INTL_SUBDIR], [])
|
||||
/^AC_DEFUN(\[gt_INTL_SUBDIR_CORE],/,/^]/c\
|
||||
AC_DEFUN([gt_INTL_SUBDIR_CORE], [])
|
||||
' m4/gettext.m4 >m4/gettext_gl.m4 || exit
|
||||
rm -fr $bt $bt2 || exit
|
||||
|
||||
echo "$0: Creating m4/gnulib.m4"
|
||||
(echo "# This file is generated automatically. Please, do not edit."
|
||||
echo "#"
|
||||
echo "AC_DEFUN([${package}_GNULIB],["
|
||||
for gnulib_module in $gnulib_modules; do
|
||||
echo "# $gnulib_module"
|
||||
$gnulib_tool --extract-autoconf-snippet $gnulib_module
|
||||
done | sed '/AM_GNU_GETTEXT/d'
|
||||
echo "])") > ./m4/gnulib.m4
|
||||
|
||||
echo "$0: Creating lib/Makefile.am"
|
||||
(echo "# This file is generated automatically. Do not edit!"
|
||||
cat lib/Makefile.tmpl
|
||||
|
||||
for gnulib_module in $gnulib_modules; do
|
||||
echo "# $gnulib_module"
|
||||
$gnulib_tool --extract-automake-snippet $gnulib_module
|
||||
done | sed "s/lib_SOURCES/lib${package}_a_SOURCES/g" ) > lib/Makefile.am
|
||||
|
||||
# Get translations.
|
||||
if test "$DOWNLOAD_PO" = "yes"; then
|
||||
update_po
|
||||
fi
|
||||
|
||||
# Reconfigure, getting other files.
|
||||
|
||||
echo "$0: autopoint --force ..."
|
||||
autopoint --force || exit
|
||||
|
||||
# We don't need intl, so remove it.
|
||||
intl_files_to_remove='
|
||||
intl
|
||||
m4/gettext.m4
|
||||
m4/glibc2.m4
|
||||
m4/intdiv0.m4
|
||||
m4/intmax.m4
|
||||
m4/lcmessage.m4
|
||||
m4/lock.m4
|
||||
m4/printf-posix.m4
|
||||
m4/visibility.m4
|
||||
'
|
||||
echo $0: rm -fr $intl_files_to_remove ...
|
||||
rm -fr $intl_files_to_remove || exit
|
||||
|
||||
|
||||
# Undo changes to gnulib files that autoreconf made.
|
||||
|
||||
for gnulib_file in $gnulib_files; do
|
||||
test ! -f $gnulib_file || cmp -s $gnulib_file $GNULIB_SRCDIR/$gnulib_file || {
|
||||
rm -f $gnulib_file &&
|
||||
echo "$0: Copying file $GNULIB_SRCDIR/$gnulib_file again" &&
|
||||
cp -p $GNULIB_SRCDIR/$gnulib_file $gnulib_file || exit
|
||||
}
|
||||
done
|
||||
|
||||
# Make sure aclocal.m4 is not older than input files.
|
||||
sleep 1
|
||||
|
||||
for command in \
|
||||
'aclocal --force -I m4' \
|
||||
'autoconf --force' \
|
||||
@@ -402,25 +603,46 @@ do
|
||||
done
|
||||
|
||||
|
||||
# Get some extra files from gnulib, overriding existing files.
|
||||
|
||||
for file in $gnulib_extra_files; do
|
||||
case $file in
|
||||
*/INSTALL) dst=INSTALL;;
|
||||
*) dst=$file;;
|
||||
esac
|
||||
symlink_to_gnulib $file $dst || exit
|
||||
done
|
||||
|
||||
|
||||
# Create gettext configuration.
|
||||
echo "$0: Creating po/Makevars from po/Makevars.template ..."
|
||||
rm -f po/Makevars
|
||||
sed '
|
||||
/^EXTRA_LOCALE_CATEGORIES *=/s/=.*/= '"$EXTRA_LOCALE_CATEGORIES"'/
|
||||
/^MSGID_BUGS_ADDRESS *=/s/=.*/= bug-'"$package"'@gnu.org/
|
||||
/^XGETTEXT_OPTIONS *=/{
|
||||
s/$/ \\/
|
||||
a\
|
||||
--flag=_:1:pass-c-format \\\
|
||||
--flag=N_:1:pass-c-format \\\
|
||||
--flag=error:3:c-format --flag=error_at_line:5:c-format \\\
|
||||
--flag=asnprintf:3:c-format --flag=vasnprintf:3:c-format \\\
|
||||
--flag=argp_error:2:c-format \\\
|
||||
--flag=__argp_error:2:c-format \\\
|
||||
--flag=argp_failure:4:c-format \\\
|
||||
--flag=__argp_failure:4:c-format \\\
|
||||
--flag=argp_fmtstream_printf:2:c-format \\\
|
||||
--flag=__argp_fmtstream_printf:2:c-format
|
||||
'"$XGETTEXT_OPTIONS"' $${end_of_xgettext_options+}
|
||||
}
|
||||
' po/Makevars.template >po/Makevars
|
||||
|
||||
if test -d runtime-po; then
|
||||
# Similarly for runtime-po/Makevars, but not quite the same.
|
||||
rm -f runtime-po/Makevars
|
||||
sed '
|
||||
/^DOMAIN *=.*/s/=.*/= '"$package"'-runtime/
|
||||
/^subdir *=.*/s/=.*/= runtime-po/
|
||||
/^MSGID_BUGS_ADDRESS *=/s/=.*/= bug-'"$package"'@gnu.org/
|
||||
/^XGETTEXT_OPTIONS *=/{
|
||||
s/$/ \\/
|
||||
a\
|
||||
'"$XGETTEXT_OPTIONS_RUNTIME"' $${end_of_xgettext_options+}
|
||||
}
|
||||
' <po/Makevars.template >runtime-po/Makevars
|
||||
|
||||
# Copy identical files from po to runtime-po.
|
||||
(cd po && cp -p Makefile.in.in *-quot *.header *.sed *.sin ../runtime-po)
|
||||
fi
|
||||
cleanup_ifl
|
||||
echo "$0: done. Now you can run './configure'."
|
||||
|
||||
61
bootstrap.conf
Normal file
61
bootstrap.conf
Normal file
@@ -0,0 +1,61 @@
|
||||
# Bootstrap configuration.
|
||||
|
||||
# Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
|
||||
# We don't need these modules, even though gnulib-tool mistakenly
|
||||
# includes them because of gettext dependencies.
|
||||
avoided_gnulib_modules='
|
||||
--avoid=lock
|
||||
--avoid=size_max
|
||||
--avoid=xsize
|
||||
'
|
||||
|
||||
# gnulib modules used by this package.
|
||||
gnulib_modules="$avoided_gnulib_modules
|
||||
`grep '^[^#]' gnulib.modules`
|
||||
"
|
||||
|
||||
# Additional xgettext options to use. Use "\\\newline" to break lines.
|
||||
XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\
|
||||
--flag=_:1:pass-c-format\\\
|
||||
--flag=N_:1:pass-c-format\\\
|
||||
--flag=error:3:c-format --flag=error_at_line:5:c-format\\\
|
||||
--flag=asnprintf:3:c-format --flag=vasnprintf:3:c-format\\\
|
||||
--flag=argp_error:2:c-format\\\
|
||||
--flag=__argp_error:2:c-format\\\
|
||||
--flag=argp_failure:4:c-format\\\
|
||||
--flag=__argp_failure:4:c-format\\\
|
||||
--flag=argp_fmtstream_printf:2:c-format\\\
|
||||
--flag=__argp_fmtstream_printf:2:c-format\\\
|
||||
'
|
||||
|
||||
# Gettext supplies these files, but we don't need them since
|
||||
# we don't have an intl subdirectory.
|
||||
excluded_files='
|
||||
m4/glibc2.m4
|
||||
m4/intdiv0.m4
|
||||
m4/lcmessage.m4
|
||||
m4/lock.m4
|
||||
m4/printf-posix.m4
|
||||
m4/size_max.m4
|
||||
m4/uintmax_t.m4
|
||||
m4/ulonglong.m4
|
||||
m4/visibility.m4
|
||||
m4/xsize.m4
|
||||
'
|
||||
@@ -18,18 +18,19 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
AC_INIT([GNU tar], [1.16], [bug-tar@gnu.org])
|
||||
AC_INIT([GNU tar], [1.16.1], [bug-tar@gnu.org])
|
||||
AC_CONFIG_SRCDIR([src/tar.c])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_HEADERS([config.h:config.hin])
|
||||
AC_PREREQ([2.60])
|
||||
AM_INIT_AUTOMAKE([1.9 gnits tar-ustar dist-bzip2 dist-shar std-options])
|
||||
|
||||
gl_USE_SYSTEM_EXTENSIONS
|
||||
AC_PROG_CC
|
||||
AC_EXEEXT
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_YACC
|
||||
gl_EARLY
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
AC_ISC_POSIX
|
||||
AC_C_INLINE
|
||||
@@ -82,7 +83,7 @@ AC_CHECK_TYPE(ino_t, unsigned)
|
||||
gt_TYPE_SSIZE_T
|
||||
|
||||
# gnulib modules
|
||||
tar_GNULIB
|
||||
gl_INIT
|
||||
# paxutils modules
|
||||
tar_PAXUTILS
|
||||
|
||||
@@ -213,7 +214,7 @@ AC_CHECK_TYPE(iconv_t,:,
|
||||
|
||||
# Gettext.
|
||||
AM_GNU_GETTEXT([external], [need-formatstring-macros])
|
||||
AM_GNU_GETTEXT_VERSION([0.15])
|
||||
AM_GNU_GETTEXT_VERSION([0.16])
|
||||
|
||||
# Initialize the test suite.
|
||||
AC_CONFIG_TESTDIR(tests)
|
||||
|
||||
149
doc/tar.texi
149
doc/tar.texi
@@ -20,7 +20,7 @@
|
||||
@include rendition.texi
|
||||
@include value.texi
|
||||
|
||||
@defcodeindex op
|
||||
@defcodeindex op
|
||||
|
||||
@c Put everything in one index (arbitrarily chosen to be the concept index).
|
||||
@syncodeindex fn cp
|
||||
@@ -898,7 +898,7 @@ clear, and we will give many examples both using and not using
|
||||
@option{--verbose} to show the differences.
|
||||
|
||||
Each instance of @option{--verbose} on the command line increases the
|
||||
verbosity level by one, so if you need more details on the output,
|
||||
verbosity level by one, so if you need more details on the output,
|
||||
specify it twice.
|
||||
|
||||
When reading archives (@option{--list}, @option{--extract},
|
||||
@@ -911,7 +911,7 @@ In contrast, when writing archives (@option{--create}, @option{--append},
|
||||
default. So, a single @option{--verbose} option shows the file names
|
||||
being added to the archive, while two @option{--verbose} options
|
||||
enable the full listing.
|
||||
|
||||
|
||||
For example, to create an archive in verbose mode:
|
||||
|
||||
@smallexample
|
||||
@@ -998,13 +998,7 @@ The archive member is a GNU @dfn{volume header} (@pxref{Tape Files}).
|
||||
Encountered only at the beginning of a multi-volume archive
|
||||
(@pxref{Using Multiple Tapes}). This archive member is a continuation
|
||||
from the previous volume. The number @var{n} gives the offset where
|
||||
the original file was split.
|
||||
|
||||
@item --Mangled file names--
|
||||
This archive member contains @dfn{mangled file names} declarations,
|
||||
a special member type that was used by early versions of @GNUTAR{}.
|
||||
You probably will never encounter this, unless you are reading a very
|
||||
old archive.
|
||||
the original file was split.
|
||||
|
||||
@item unknown file type @var{c}
|
||||
An archive member of unknown type. @var{c} is the type character from
|
||||
@@ -1378,7 +1372,7 @@ particular archive contains. You can use the @option{--list}
|
||||
appear in the archive, as well as various attributes of the files at
|
||||
the time they were archived. For example, you can examine the archive
|
||||
@file{collection.tar} that you created in the last section with the
|
||||
command,
|
||||
command,
|
||||
|
||||
@smallexample
|
||||
$ @kbd{tar --list --file=collection.tar}
|
||||
@@ -1580,7 +1574,7 @@ mistakenly deleted one of the files you had placed in the archive
|
||||
@file{collection.tar} earlier (say, @file{blues}), you can extract it
|
||||
from the archive without changing the archive's structure. Its
|
||||
contents will be identical to the original file @file{blues} that you
|
||||
deleted.
|
||||
deleted.
|
||||
|
||||
First, make sure you are in the @file{practice} directory, and list the
|
||||
files in the directory. Now, delete the file, @samp{blues}, and list
|
||||
@@ -1630,7 +1624,7 @@ Here, @option{--wildcards} instructs @command{tar} to treat
|
||||
command line arguments as globbing patterns and @option{--no-anchored}
|
||||
informs it that the patterns apply to member names after any @samp{/}
|
||||
delimiter. The use of globbing patterns is discussed in detail in
|
||||
@xref{wildcards}.
|
||||
@xref{wildcards}.
|
||||
|
||||
You can extract a file to standard output by combining the above options
|
||||
with the @option{--to-stdout} (@option{-O}) option (@pxref{Writing to Standard
|
||||
@@ -2000,7 +1994,7 @@ Some options @emph{may} take an argument. Such options may have at
|
||||
most long and short forms, they do not have old style equivalent. The
|
||||
rules for specifying an argument for such options are stricter than
|
||||
those for specifying mandatory arguments. Please, pay special
|
||||
attention to them.
|
||||
attention to them.
|
||||
|
||||
@menu
|
||||
* Long Options:: Long Option Style
|
||||
@@ -2015,7 +2009,7 @@ attention to them.
|
||||
Each option has at least one @dfn{long} (or @dfn{mnemonic}) name starting with two
|
||||
dashes in a row, e.g., @option{--list}. The long names are more clear than
|
||||
their corresponding short or old names. It sometimes happens that a
|
||||
single long option has many different different names which are
|
||||
single long option has many different names which are
|
||||
synonymous, such as @option{--compare} and @option{--diff}. In addition,
|
||||
long option names can be given unique abbreviations. For example,
|
||||
@option{--cre} can be used in place of @option{--create} because there is no
|
||||
@@ -2453,7 +2447,7 @@ total number of hard links for the file, a warning message will be
|
||||
output @footnote{Earlier versions of @GNUTAR{} understood @option{-l} as a
|
||||
synonym for @option{--one-file-system}. The current semantics, which
|
||||
complies to UNIX98, was introduced with version
|
||||
1.15.91. @xref{Changes}, for more information.}.
|
||||
1.15.91. @xref{Changes}, for more information.}.
|
||||
|
||||
@opsummary{compress}
|
||||
@opsummary{uncompress}
|
||||
@@ -2511,6 +2505,11 @@ patterns in the file @var{file}. @xref{exclude}.
|
||||
Automatically excludes all directories
|
||||
containing a cache directory tag. @xref{exclude}.
|
||||
|
||||
@opsummary{exclude-tag}
|
||||
@item --exclude-tag=@var{file}
|
||||
|
||||
Exclude all directories, containing file named @var{file}. @xref{exclude}.
|
||||
|
||||
@opsummary{file}
|
||||
@item --file=@var{archive}
|
||||
@itemx -f @var{archive}
|
||||
@@ -2596,7 +2595,7 @@ options to @command{tar} and exit. @xref{help}.
|
||||
@opsummary{ignore-case}
|
||||
@item --ignore-case
|
||||
Ignore case when matching member or file names with
|
||||
patterns. @xref{controlling pattern-matching}.
|
||||
patterns. @xref{controlling pattern-matching}.
|
||||
|
||||
@opsummary{ignore-command-error}
|
||||
@item --ignore-command-error
|
||||
@@ -2908,7 +2907,7 @@ discussion, @xref{transform}.
|
||||
|
||||
To see transformed member names in verbose listings, use
|
||||
@option{--show-transformed-names} option
|
||||
(@pxref{show-transformed-names}).
|
||||
(@pxref{show-transformed-names}).
|
||||
|
||||
@opsummary{quote-chars}
|
||||
@item --quote-chars=@var{string}
|
||||
@@ -3297,7 +3296,7 @@ them with the equivalent long option.
|
||||
@item -m @tab @ref{--touch}.
|
||||
|
||||
@item -o @tab When creating, @ref{--no-same-owner}, when extracting ---
|
||||
@ref{--portability}.
|
||||
@ref{--portability}.
|
||||
|
||||
The later usage is deprecated. It is retained for compatibility with
|
||||
the earlier versions of @GNUTAR{}. In the future releases
|
||||
@@ -3433,7 +3432,7 @@ values in the form of @command{tar} command line options:
|
||||
@smallexample
|
||||
@group
|
||||
@kbd{tar --show-defaults}
|
||||
--format=gnu -f- -b20 --quoting-style=escape
|
||||
--format=gnu -f- -b20 --quoting-style=escape
|
||||
--rmt-command=/etc/rmt --rsh-command=/usr/bin/rsh
|
||||
@end group
|
||||
@end smallexample
|
||||
@@ -3548,14 +3547,14 @@ statistics is to be printed:
|
||||
Print statistics upon delivery of signal @var{signo}. Valid arguments
|
||||
are: @code{SIGHUP}, @code{SIGQUIT}, @code{SIGINT}, @code{SIGUSR1} and
|
||||
@code{SIGUSR2}. Shortened names without @samp{SIG} prefix are also
|
||||
accepted.
|
||||
accepted.
|
||||
@end table
|
||||
|
||||
Both forms of @option{--totals} option can be used simultaneously.
|
||||
Thus, @kbd{tar -x --totals --totals=USR1} instructs @command{tar} to
|
||||
extract all members from its default archive and print statistics
|
||||
after finishing the extraction, as well as when receiving signal
|
||||
@code{SIGUSR1}.
|
||||
@code{SIGUSR1}.
|
||||
|
||||
@anchor{Progress information}
|
||||
@cindex Progress information
|
||||
@@ -3960,7 +3959,7 @@ archive in the order in which they were archived. Thus, when the
|
||||
archive is extracted, a file archived later in time will replace a
|
||||
file of the same name which was archived earlier, even though the
|
||||
older version of the file will remain in the archive unless you delete
|
||||
all versions of the file.
|
||||
all versions of the file.
|
||||
|
||||
Supposing you change the file @file{blues} and then append the changed
|
||||
version to @file{collection.tar}. As you saw above, the original
|
||||
@@ -4272,7 +4271,7 @@ tar: funk not found in archive
|
||||
The spirit behind the @option{--compare} (@option{--diff},
|
||||
@option{-d}) option is to check whether the archive represents the
|
||||
current state of files on disk, more than validating the integrity of
|
||||
the archive media. For this later goal, @xref{verify}.
|
||||
the archive media. For this later goal, @xref{verify}.
|
||||
|
||||
@node create options
|
||||
@section Options Used by @option{--create}
|
||||
@@ -4679,7 +4678,7 @@ Use in conjunction with @option{--extract} (@option{--get}, @option{-x}).
|
||||
To set the modes (access permissions) of extracted files to those
|
||||
recorded for those files in the archive, use @option{--same-permissions}
|
||||
in conjunction with the @option{--extract} (@option{--get},
|
||||
@option{-x}) operation.
|
||||
@option{-x}) operation.
|
||||
|
||||
@table @option
|
||||
@opindex preserve-permissions
|
||||
@@ -6170,7 +6169,7 @@ can be inhibited by using the @option{--force-local} option.
|
||||
When the archive is being created to @file{/dev/null}, @GNUTAR{}
|
||||
tries to minimize input and output operations. The Amanda backup
|
||||
system, when used with @GNUTAR{}, has an initial sizing pass which
|
||||
uses this feature.
|
||||
uses this feature.
|
||||
|
||||
@node Selecting Archive Members
|
||||
@section Selecting Archive Members
|
||||
@@ -6198,9 +6197,9 @@ name, replacing @dfn{escape sequences} according to the following
|
||||
table:
|
||||
|
||||
@multitable @columnfractions 0.20 0.60
|
||||
@headitem Escape @tab Replaced with
|
||||
@headitem Escape @tab Replaced with
|
||||
@item \a @tab Audible bell (ASCII 7)
|
||||
@item \b @tab Backspace (ASCII 8)
|
||||
@item \b @tab Backspace (ASCII 8)
|
||||
@item \f @tab Form feed (ASCII 12)
|
||||
@item \n @tab New line (ASCII 10)
|
||||
@item \r @tab Carriage return (ASCII 13)
|
||||
@@ -6256,7 +6255,7 @@ By default, @command{tar} takes file names from the command line. However,
|
||||
there are other ways to specify file or member names, or to modify the
|
||||
manner in which @command{tar} selects the files or members upon which to
|
||||
operate. In general, these methods work both for specifying the names
|
||||
of files and archive members.
|
||||
of files and archive members.
|
||||
|
||||
@node files
|
||||
@section Reading Names from a File
|
||||
@@ -6268,7 +6267,7 @@ Instead of giving the names of files or archive members on the command
|
||||
line, you can put the names into a file, and then use the
|
||||
@option{--files-from=@var{file-of-names}} (@option{-T
|
||||
@var{file-of-names}}) option to @command{tar}. Give the name of the
|
||||
file which contains the list of files to include as the argument to
|
||||
file which contains the list of files to include as the argument to
|
||||
@option{--files-from}. In the list, the file names should be separated by
|
||||
newlines. You will frequently use this option when you have generated
|
||||
the list of files to archive with the @command{find} utility.
|
||||
@@ -6397,7 +6396,7 @@ The @option{--null} option causes
|
||||
@option{--files-from=@var{file-of-names}} (@option{-T @var{file-of-names}})
|
||||
to read file names terminated by a @code{NUL} instead of a newline, so
|
||||
files whose names contain newlines can be archived using
|
||||
@option{--files-from}.
|
||||
@option{--files-from}.
|
||||
|
||||
@table @option
|
||||
@opindex null
|
||||
@@ -6448,7 +6447,7 @@ Causes @command{tar} to ignore files that match the @var{pattern}.
|
||||
@findex exclude
|
||||
The @option{--exclude=@var{pattern}} option prevents any file or
|
||||
member whose name matches the shell wildcard (@var{pattern}) from
|
||||
being operated on.
|
||||
being operated on.
|
||||
For example, to create an archive with all the contents of the directory
|
||||
@file{src} except for files whose names end in @file{.o}, use the
|
||||
command @samp{tar -cf src.tar --exclude='*.o' src}.
|
||||
@@ -6487,6 +6486,38 @@ Various applications write cache directory tags into directories they
|
||||
use to hold regenerable, non-precious data, so that such data can be
|
||||
more easily excluded from backups.
|
||||
|
||||
@findex exclude-tag
|
||||
Another option, @option{--exclude-tag}, provides a generalization of
|
||||
this concept. It takes a single argument, a file name to look for.
|
||||
Any directory that contains this file will be excluded from the dump.
|
||||
|
||||
@table @option
|
||||
@opindex exclude-tag
|
||||
@item --exclude-tag=@var{file}
|
||||
Causes @command{tar} to ignore directories containing @var{file}.
|
||||
Multiple @option{--exclude-tag} options can be given.
|
||||
@end table
|
||||
|
||||
For example:
|
||||
|
||||
@smallexample
|
||||
$ @kbd{find dir}
|
||||
dir
|
||||
dir/blues
|
||||
dir/jazz
|
||||
dir/folk
|
||||
dir/folk/tagfile
|
||||
$ @kbd{tar -cf archive.tar --exclude-tag=tagfile -v}
|
||||
dir/
|
||||
dir/blues
|
||||
dir/jazz
|
||||
./tar: dir/folk/: contains a cache directory tag tagfile; not dumped
|
||||
$ @kbd{tar -tf archive.tar}
|
||||
dir/
|
||||
dir/blues
|
||||
dir/jazz
|
||||
@end smallexample
|
||||
|
||||
@menu
|
||||
* problems with exclude::
|
||||
@end menu
|
||||
@@ -6546,7 +6577,7 @@ might fail.
|
||||
@item
|
||||
@FIXME{The change in semantics must have occurred before 1.11,
|
||||
so I doubt if it is worth mentioning at all. Anyway, should at
|
||||
least specify in which version the semantics changed.}
|
||||
least specify in which version the semantics changed.}
|
||||
In earlier versions of @command{tar}, what is now the
|
||||
@option{--exclude-from} option was called @option{--exclude} instead.
|
||||
Now, @option{--exclude} applies to patterns listed on the command
|
||||
@@ -6631,7 +6662,7 @@ There are no inclusion members in create mode (@option{--create} and
|
||||
command line refer to @emph{files}, not archive members.
|
||||
|
||||
By default, inclusion members are compared with archive members
|
||||
literally @footnote{Notice that earlier @GNUTAR{} versions used
|
||||
literally @footnote{Notice that earlier @GNUTAR{} versions used
|
||||
globbing for inclusion members, which contradicted to UNIX98
|
||||
specification and was not documented. @xref{Changes}, for more
|
||||
information on this and other changes.} and exclusion members are
|
||||
@@ -6659,7 +6690,7 @@ This behavior can be altered by using the following options:
|
||||
@table @option
|
||||
@opindex wildcards
|
||||
@item --wildcards
|
||||
Treat all member names as wildcards.
|
||||
Treat all member names as wildcards.
|
||||
|
||||
@opindex no-wildcards
|
||||
@item --no-wildcards
|
||||
@@ -6842,7 +6873,7 @@ Quoting styles:
|
||||
No quoting, display each character as is:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
@group
|
||||
$ @kbd{tar tf arch.tar --quoting-style=literal}
|
||||
./
|
||||
./a space
|
||||
@@ -6985,7 +7016,7 @@ quoting style would not quote them.
|
||||
@end table
|
||||
|
||||
For example, using @samp{escape} quoting (compare with the usual
|
||||
escape listing above):
|
||||
escape listing above):
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
@@ -7058,7 +7089,7 @@ $ @kbd{tar -xf usr.tar --strip=2 usr/include/stdlib.h}
|
||||
|
||||
The option @option{--strip=2} instructs @command{tar} to strip the
|
||||
two leading components (@file{usr/} and @file{include/}) off the file
|
||||
name.
|
||||
name.
|
||||
|
||||
If you add to the above invocation @option{--verbose} (@option{-v})
|
||||
option, you will note that the verbose listing still contains the
|
||||
@@ -7154,7 +7185,7 @@ follows the GNU @command{sed} implementation in this regard, so
|
||||
the interaction is defined to be: ignore matches before the
|
||||
@var{number}th, and then match and replace all matches from the
|
||||
@var{number}th on.
|
||||
|
||||
|
||||
@end table
|
||||
|
||||
Any delimiter can be used in lieue of @samp{/}, the only requirement being
|
||||
@@ -7222,7 +7253,7 @@ $ @kbd{tar -cf arch.tar --transform='s,^usr/,var/,' \
|
||||
If both @option{--strip-components} and @option{--transform} are used
|
||||
together, then @option{--transform} is applied first, and the required
|
||||
number of components is then stripped from its result.
|
||||
|
||||
|
||||
@node after
|
||||
@section Operating Only on New Files
|
||||
@UNREVISED
|
||||
@@ -7907,7 +7938,7 @@ implement your own filters, not necessarily dealing with
|
||||
compression/decompression. For example, suppose you wish to implement
|
||||
PGP encryption on top of compression, using @command{gpg} (@pxref{Top,
|
||||
gpg, gpg ---- encryption and signing tool, gpg, GNU Privacy Guard
|
||||
Manual}). The following script does that:
|
||||
Manual}). The following script does that:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
@@ -7960,9 +7991,9 @@ The above is based on the following discussion:
|
||||
that capability. Supposing I were to actually do such a thing and
|
||||
get it (apparently) working, do you accept contributed changes to
|
||||
utilities like that? (Leigh Clayton @file{loc@@soliton.com}, May 1995).
|
||||
|
||||
|
||||
Isn't that exactly the role of the
|
||||
@option{--use-compress-prog=@var{program}} option?
|
||||
@option{--use-compress-prog=@var{program}} option?
|
||||
I never tried it myself, but I suspect you may want to write a
|
||||
@var{prog} script or program able to filter stdin to stdout to
|
||||
way you want. It should recognize the @option{-d} option, for when
|
||||
@@ -8010,7 +8041,7 @@ has no effect on extraction.
|
||||
|
||||
Consider using @option{--sparse} when performing file system backups,
|
||||
to avoid archiving the expanded forms of files stored sparsely in the
|
||||
system.
|
||||
system.
|
||||
|
||||
Even if your system has no sparse files currently, some may be
|
||||
created in the future. If you use @option{--sparse} while making file
|
||||
@@ -8058,7 +8089,7 @@ formats}. A sparse format is identified by its @dfn{number},
|
||||
consisting, as usual of two decimal numbers, delimited by a dot. By
|
||||
default, format @samp{1.0} is used. If, for some reason, you wish to
|
||||
use an earlier format, you can select it using
|
||||
@option{--sparse-version} option.
|
||||
@option{--sparse-version} option.
|
||||
|
||||
@table @option
|
||||
@opindex sparse-version
|
||||
@@ -8136,7 +8167,7 @@ separately. If it can't find a user name (because the user id is not
|
||||
in @file{/etc/passwd}), then it does not write one. When restoring,
|
||||
it tries to look the name (if one was written) up in
|
||||
@file{/etc/passwd}. If it fails, then it uses the user id stored in
|
||||
the archive instead.
|
||||
the archive instead.
|
||||
|
||||
@opindex no-same-owner
|
||||
@item --no-same-owner
|
||||
@@ -8367,7 +8398,7 @@ Starting from version 1.14 @GNUTAR{} features full support for
|
||||
A @acronym{POSIX} conformant archive will be created if @command{tar}
|
||||
was given @option{--format=posix} (@option{--format=pax}) option. No
|
||||
special option is required to read and extract from a @acronym{POSIX}
|
||||
archive.
|
||||
archive.
|
||||
|
||||
@menu
|
||||
* PAX keywords:: Controlling Extended Header Keywords.
|
||||
@@ -8570,7 +8601,7 @@ extract archives containing GNU-specific members using some
|
||||
third-party @command{tar} implementation or an older version of
|
||||
@GNUTAR{}. Of course your best bet is to have @GNUTAR{} installed,
|
||||
but if it is for some reason impossible, this section will explain
|
||||
how to cope without it.
|
||||
how to cope without it.
|
||||
|
||||
When we speak about @dfn{GNU-specific} members we mean two classes of
|
||||
them: members split between the volumes of a multi-volume archive and
|
||||
@@ -8677,7 +8708,7 @@ more warnings and more files generated on your disk, e.g.:
|
||||
@group
|
||||
$ @kbd{tar xf vol-1.tar}
|
||||
var/PaxHeaders.27962/longfile: Unknown file type 'x', extracted as
|
||||
normal file
|
||||
normal file
|
||||
Unexpected EOF in archive
|
||||
$ @kbd{tar xf vol-2.tar}
|
||||
tmp/GlobalHead.27962.1: Unknown file type 'g', extracted as normal file
|
||||
@@ -8714,7 +8745,7 @@ version 1.0}@footnote{@xref{PAX 1}.}, which are the easiest to expand.
|
||||
The condensed file will contain both file map and file data, so no
|
||||
additional data will be needed to restore it. If the original file
|
||||
name was @file{@var{dir}/@var{name}}, then the condensed file will be
|
||||
named @file{@var{dir}/@/GNUSparseFile.@var{n}/@/@var{name}}, where
|
||||
named @file{@var{dir}/@/GNUSparseFile.@var{n}/@/@var{name}}, where
|
||||
@var{n} is a decimal number@footnote{technically speaking, @var{n} is a
|
||||
@dfn{process ID} of the @command{tar} process which created the
|
||||
archive (@pxref{PAX keywords}).}.
|
||||
@@ -8822,10 +8853,10 @@ expanding sparse version 1.0 members, use of extended headers is
|
||||
mandatory when expanding sparse members in older sparse formats: v.0.0
|
||||
and v.0.1 (The sparse formats are described in detail in @ref{Sparse
|
||||
Formats}.) So, for this format, the question is: how to obtain
|
||||
extended headers from the archive?
|
||||
extended headers from the archive?
|
||||
|
||||
If you use a @command{tar} implementation that does not support PAX
|
||||
format, extended headers for each member will be extracted as a
|
||||
format, extended headers for each member will be extracted as a
|
||||
separate file. If we represent the member name as
|
||||
@file{@var{dir}/@var{name}}, then the extended header file will be
|
||||
named @file{@var{dir}/@/PaxHeaders.@var{n}/@/@var{name}}, where
|
||||
@@ -8836,7 +8867,7 @@ does support PAX headers, because in this case you will have to
|
||||
manually extract the headers. We recommend the following algorithm:
|
||||
|
||||
@enumerate 1
|
||||
@item
|
||||
@item
|
||||
Consult the documentation of your @command{tar} implementation for an
|
||||
option that prints @dfn{block numbers} along with the archive
|
||||
listing (analogous to @GNUTAR{}'s @option{-R} option). For example,
|
||||
@@ -8868,7 +8899,7 @@ block 897: 65391 -rw-r--r-- gray/users Jun 24 20:06 2006 README
|
||||
@item
|
||||
Let @var{size} be the size of the sparse member, @var{Bs} be its block number
|
||||
and @var{Bn} be the block number of the next member.
|
||||
Compute:
|
||||
Compute:
|
||||
|
||||
@smallexample
|
||||
@var{N} = @var{Bs} - @var{Bn} - @var{size}/512 - 2
|
||||
@@ -9912,7 +9943,7 @@ on several media volumes of fixed size. Although in this section we will
|
||||
often call @samp{volume} a @dfn{tape}, there is absolutely no
|
||||
requirement for multi-volume archives to be stored on tapes. Instead,
|
||||
they can use whatever media type the user finds convenient, they can
|
||||
even be located on files.
|
||||
even be located on files.
|
||||
|
||||
When creating a multi-volume archive, @GNUTAR{} continues to fill
|
||||
current volume until it runs out of space, then it switches to
|
||||
@@ -9920,7 +9951,7 @@ next volume (usually the operator is queried to replace the tape on
|
||||
this point), and continues working on the new volume. This operation
|
||||
continues until all requested files are dumped. If @GNUTAR{} detects
|
||||
end of media while dumping a file, such a file is archived in split
|
||||
form. Some very big files can even be split across several volumes.
|
||||
form. Some very big files can even be split across several volumes.
|
||||
|
||||
Each volume is itself a valid @GNUTAR{} archive, so it can be read
|
||||
without any special options. Consequently any file member residing
|
||||
@@ -9998,7 +10029,7 @@ $ @kbd{tar --create --tape-length=41943040 --file=/dev/tape @var{files}}
|
||||
When @GNUTAR{} comes to the end of a storage media, it asks you to
|
||||
change the volume. The built-in prompt for POSIX locale
|
||||
is@footnote{If you run @GNUTAR{} under a different locale, the
|
||||
translation to the locale's language will be used.}:
|
||||
translation to the locale's language will be used.}:
|
||||
|
||||
@smallexample
|
||||
Prepare volume #@var{n} for `@var{archive}' and hit return:
|
||||
@@ -10053,7 +10084,7 @@ the number used in the prompt.)
|
||||
If you want more elaborate behavior than this, you can write a special
|
||||
@dfn{new volume script}, that will be responsible for changing the
|
||||
volume, and instruct @command{tar} to use it instead of its normal
|
||||
prompting procedure:
|
||||
prompting procedure:
|
||||
|
||||
@table @option
|
||||
@item --info-script=@var{script-name}
|
||||
@@ -10117,7 +10148,7 @@ $ @kbd{tar cMff /dev/tape0 /dev/tape1 @var{files}}
|
||||
@end smallexample
|
||||
|
||||
The second method is to use the @samp{n} response to the tape-change
|
||||
prompt.
|
||||
prompt.
|
||||
|
||||
Finally, the most flexible approach is to use a volume script, that
|
||||
writes new archive name to the file descriptor #3. For example, the
|
||||
|
||||
@@ -6,6 +6,7 @@ argmatch
|
||||
argp
|
||||
backupfile
|
||||
closeout
|
||||
configmake
|
||||
dirname
|
||||
error
|
||||
exclude
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.am
|
||||
Makefile.in
|
||||
__fpending.c
|
||||
__fpending.h
|
||||
@@ -63,6 +62,7 @@ fnmatch.c
|
||||
fnmatch.h
|
||||
fnmatch_.h
|
||||
fnmatch_loop.c
|
||||
fstatat.c
|
||||
ftruncate.c
|
||||
full-write.c
|
||||
full-write.h
|
||||
@@ -84,6 +84,7 @@ getpagesize.h
|
||||
gettext.h
|
||||
gettime.c
|
||||
gettimeofday.c
|
||||
gnulib.mk
|
||||
hash.c
|
||||
hash.h
|
||||
human.c
|
||||
@@ -124,6 +125,7 @@ offtostr.c
|
||||
open-safer.c
|
||||
openat-die.c
|
||||
openat-priv.h
|
||||
openat-proc.c
|
||||
openat.c
|
||||
openat.h
|
||||
paxerror.c
|
||||
@@ -133,7 +135,6 @@ paxnames.c
|
||||
pipe-safer.c
|
||||
printf-args.c
|
||||
printf-args.h
|
||||
printf-parse.c
|
||||
printf-parse.h
|
||||
quote.c
|
||||
quote.h
|
||||
@@ -157,6 +158,7 @@ safe-read.c
|
||||
safe-read.h
|
||||
safe-write.c
|
||||
safe-write.h
|
||||
same-inode.h
|
||||
save-cwd.c
|
||||
save-cwd.h
|
||||
savedir.c
|
||||
@@ -166,6 +168,7 @@ setenv.h
|
||||
size_max.h
|
||||
stat-macros.h
|
||||
stat-time.h
|
||||
stat_.h
|
||||
stdbool.h
|
||||
stdbool_.h
|
||||
stdint.h
|
||||
@@ -196,9 +199,12 @@ sysexit_.h
|
||||
sysexits.h
|
||||
system-ioctl.h
|
||||
system.h
|
||||
tempname.c
|
||||
tempname.h
|
||||
time_r.c
|
||||
time_r.h
|
||||
timespec.h
|
||||
uinttostr.c
|
||||
umaxtostr.c
|
||||
unistd--.h
|
||||
unistd-safer.h
|
||||
@@ -209,7 +215,6 @@ unsetenv.c
|
||||
utime.c
|
||||
utimens.c
|
||||
utimens.h
|
||||
vasnprintf.c
|
||||
vasnprintf.h
|
||||
verify.h
|
||||
version-etc-fsf.c
|
||||
|
||||
41
lib/Makefile.am
Normal file
41
lib/Makefile.am
Normal file
@@ -0,0 +1,41 @@
|
||||
# Makefile for GNU tar library. -*- Makefile -*-
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2004,
|
||||
# 2005, 2006 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 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
include gnulib.mk
|
||||
|
||||
rmt-command.h : Makefile
|
||||
rm -f $@-t $@
|
||||
echo "#ifndef DEFAULT_RMT_COMMAND" >> $@-t
|
||||
echo "# define DEFAULT_RMT_COMMAND \"$(DEFAULT_RMT_DIR)/`echo rmt | sed '$(transform)'`$(EXEEXT)\"" >> $@-t
|
||||
echo "#endif" >> $@-t
|
||||
mv $@-t $@
|
||||
BUILT_SOURCES += rmt-command.h
|
||||
CLEANFILES += rmt-command.h rmt-command.h-t
|
||||
|
||||
noinst_HEADERS += system.h system-ioctl.h rmt.h paxlib.h stdopen.h
|
||||
libtar_a_SOURCES += \
|
||||
paxerror.c paxexit.c paxlib.h paxnames.c \
|
||||
prepargs.c prepargs.h \
|
||||
rtapelib.c \
|
||||
rmt.h \
|
||||
stdopen.c stdopen.h \
|
||||
system.h system-ioctl.h
|
||||
|
||||
libtar_a_LIBADD += $(LIBOBJS)
|
||||
libtar_a_DEPENDENCIES += $(LIBOBJS)
|
||||
@@ -1,56 +0,0 @@
|
||||
# Makefile for GNU tar library. -*- Makefile -*-
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2004,
|
||||
# 2005, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
## 02110-1301, USA.
|
||||
|
||||
noinst_LIBRARIES = libtar.a
|
||||
noinst_HEADERS = system.h system-ioctl.h localedir.h rmt.h paxlib.h stdopen.h
|
||||
libtar_a_SOURCES = prepargs.c prepargs.h rtapelib.c paxerror.c paxexit.c paxnames.c stdopen.c
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
|
||||
DISTCLEANFILES = localedir.h
|
||||
localedir.h : Makefile
|
||||
echo '#define LOCALEDIR "$(localedir)"' >$@
|
||||
echo "#ifndef DEFAULT_RMT_COMMAND" >> $@
|
||||
echo "# define DEFAULT_RMT_COMMAND \"$(DEFAULT_RMT_DIR)/`echo rmt | sed '$(transform)'`$(EXEEXT)\"" >> $@
|
||||
echo "#endif" >> $@
|
||||
|
||||
rtapelib.o: localedir.h
|
||||
|
||||
libtar_a_LIBADD = $(LIBOBJS) $(ALLOCA)
|
||||
libtar_a_DEPENDENCIES = $(libtar_a_LIBADD)
|
||||
|
||||
BUILT_SOURCES =
|
||||
AM_CPPFLAGS =
|
||||
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
|
||||
|
||||
SUFFIXES = .o .c .h
|
||||
CLEANFILES =
|
||||
# gnulib modules
|
||||
535
lib/printf-parse.c
Normal file
535
lib/printf-parse.c
Normal file
@@ -0,0 +1,535 @@
|
||||
/* Formatted output to strings.
|
||||
Copyright (C) 1999-2000, 2002-2004, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#if WIDE_CHAR_VERSION
|
||||
# include "wprintf-parse.h"
|
||||
#else
|
||||
# include "printf-parse.h"
|
||||
#endif
|
||||
|
||||
/* Get size_t, NULL. */
|
||||
#include <stddef.h>
|
||||
|
||||
/* Get intmax_t. */
|
||||
#if HAVE_STDINT_H_WITH_UINTMAX
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
#if HAVE_INTTYPES_H_WITH_UINTMAX
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
/* malloc(), realloc(), free(). */
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX ((size_t) -1)
|
||||
#endif
|
||||
|
||||
#if WIDE_CHAR_VERSION
|
||||
# define PRINTF_PARSE wprintf_parse
|
||||
# define CHAR_T wchar_t
|
||||
# define DIRECTIVE wchar_t_directive
|
||||
# define DIRECTIVES wchar_t_directives
|
||||
#else
|
||||
# define PRINTF_PARSE printf_parse
|
||||
# define CHAR_T char
|
||||
# define DIRECTIVE char_directive
|
||||
# define DIRECTIVES char_directives
|
||||
#endif
|
||||
|
||||
#ifdef STATIC
|
||||
STATIC
|
||||
#endif
|
||||
int
|
||||
PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
{
|
||||
const CHAR_T *cp = format; /* pointer into format */
|
||||
size_t arg_posn = 0; /* number of regular arguments consumed */
|
||||
size_t d_allocated; /* allocated elements of d->dir */
|
||||
size_t a_allocated; /* allocated elements of a->arg */
|
||||
size_t max_width_length = 0;
|
||||
size_t max_precision_length = 0;
|
||||
|
||||
d->count = 0;
|
||||
d_allocated = 1;
|
||||
d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
|
||||
if (d->dir == NULL)
|
||||
/* Out of memory. */
|
||||
return -1;
|
||||
|
||||
a->count = 0;
|
||||
a_allocated = 0;
|
||||
a->arg = NULL;
|
||||
|
||||
#define REGISTER_ARG(_index_,_type_) \
|
||||
{ \
|
||||
size_t n = (_index_); \
|
||||
if (n >= a_allocated) \
|
||||
{ \
|
||||
size_t memory_size; \
|
||||
argument *memory; \
|
||||
\
|
||||
a_allocated *= 2; \
|
||||
if (a_allocated <= n) \
|
||||
a_allocated = n + 1; \
|
||||
if (SIZE_MAX / sizeof (argument) < a_allocated) \
|
||||
/* Overflow, would lead to out of memory. */ \
|
||||
goto error; \
|
||||
memory_size = a_allocated * sizeof (argument); \
|
||||
memory = (a->arg \
|
||||
? realloc (a->arg, memory_size) \
|
||||
: malloc (memory_size)); \
|
||||
if (memory == NULL) \
|
||||
/* Out of memory. */ \
|
||||
goto error; \
|
||||
a->arg = memory; \
|
||||
} \
|
||||
while (a->count <= n) \
|
||||
a->arg[a->count++].type = TYPE_NONE; \
|
||||
if (a->arg[n].type == TYPE_NONE) \
|
||||
a->arg[n].type = (_type_); \
|
||||
else if (a->arg[n].type != (_type_)) \
|
||||
/* Ambiguous type for positional argument. */ \
|
||||
goto error; \
|
||||
}
|
||||
|
||||
while (*cp != '\0')
|
||||
{
|
||||
CHAR_T c = *cp++;
|
||||
if (c == '%')
|
||||
{
|
||||
size_t arg_index = ARG_NONE;
|
||||
DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
|
||||
|
||||
/* Initialize the next directive. */
|
||||
dp->dir_start = cp - 1;
|
||||
dp->flags = 0;
|
||||
dp->width_start = NULL;
|
||||
dp->width_end = NULL;
|
||||
dp->width_arg_index = ARG_NONE;
|
||||
dp->precision_start = NULL;
|
||||
dp->precision_end = NULL;
|
||||
dp->precision_arg_index = ARG_NONE;
|
||||
dp->arg_index = ARG_NONE;
|
||||
|
||||
/* Test for positional argument. */
|
||||
if (*cp >= '0' && *cp <= '9')
|
||||
{
|
||||
const CHAR_T *np;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
;
|
||||
if (*np == '$')
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
if (n < SIZE_MAX / 10)
|
||||
n = 10 * n + (*np - '0');
|
||||
else
|
||||
/* n too large for memory. */
|
||||
goto error;
|
||||
if (n == 0)
|
||||
/* Positional argument 0. */
|
||||
goto error;
|
||||
arg_index = n - 1;
|
||||
cp = np + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the flags. */
|
||||
for (;;)
|
||||
{
|
||||
if (*cp == '\'')
|
||||
{
|
||||
dp->flags |= FLAG_GROUP;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == '-')
|
||||
{
|
||||
dp->flags |= FLAG_LEFT;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == '+')
|
||||
{
|
||||
dp->flags |= FLAG_SHOWSIGN;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == ' ')
|
||||
{
|
||||
dp->flags |= FLAG_SPACE;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == '#')
|
||||
{
|
||||
dp->flags |= FLAG_ALT;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == '0')
|
||||
{
|
||||
dp->flags |= FLAG_ZERO;
|
||||
cp++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Parse the field width. */
|
||||
if (*cp == '*')
|
||||
{
|
||||
dp->width_start = cp;
|
||||
cp++;
|
||||
dp->width_end = cp;
|
||||
if (max_width_length < 1)
|
||||
max_width_length = 1;
|
||||
|
||||
/* Test for positional argument. */
|
||||
if (*cp >= '0' && *cp <= '9')
|
||||
{
|
||||
const CHAR_T *np;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
;
|
||||
if (*np == '$')
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
if (n < SIZE_MAX / 10)
|
||||
n = 10 * n + (*np - '0');
|
||||
else
|
||||
/* n too large for memory. */
|
||||
goto error;
|
||||
if (n == 0)
|
||||
/* Positional argument 0. */
|
||||
goto error;
|
||||
dp->width_arg_index = n - 1;
|
||||
cp = np + 1;
|
||||
}
|
||||
}
|
||||
if (dp->width_arg_index == ARG_NONE)
|
||||
{
|
||||
dp->width_arg_index = arg_posn++;
|
||||
if (dp->width_arg_index == ARG_NONE)
|
||||
/* arg_posn wrapped around. */
|
||||
goto error;
|
||||
}
|
||||
REGISTER_ARG (dp->width_arg_index, TYPE_INT);
|
||||
}
|
||||
else if (*cp >= '0' && *cp <= '9')
|
||||
{
|
||||
size_t width_length;
|
||||
|
||||
dp->width_start = cp;
|
||||
for (; *cp >= '0' && *cp <= '9'; cp++)
|
||||
;
|
||||
dp->width_end = cp;
|
||||
width_length = dp->width_end - dp->width_start;
|
||||
if (max_width_length < width_length)
|
||||
max_width_length = width_length;
|
||||
}
|
||||
|
||||
/* Parse the precision. */
|
||||
if (*cp == '.')
|
||||
{
|
||||
cp++;
|
||||
if (*cp == '*')
|
||||
{
|
||||
dp->precision_start = cp - 1;
|
||||
cp++;
|
||||
dp->precision_end = cp;
|
||||
if (max_precision_length < 2)
|
||||
max_precision_length = 2;
|
||||
|
||||
/* Test for positional argument. */
|
||||
if (*cp >= '0' && *cp <= '9')
|
||||
{
|
||||
const CHAR_T *np;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
;
|
||||
if (*np == '$')
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
if (n < SIZE_MAX / 10)
|
||||
n = 10 * n + (*np - '0');
|
||||
else
|
||||
/* n too large for memory. */
|
||||
goto error;
|
||||
if (n == 0)
|
||||
/* Positional argument 0. */
|
||||
goto error;
|
||||
dp->precision_arg_index = n - 1;
|
||||
cp = np + 1;
|
||||
}
|
||||
}
|
||||
if (dp->precision_arg_index == ARG_NONE)
|
||||
{
|
||||
dp->precision_arg_index = arg_posn++;
|
||||
if (dp->precision_arg_index == ARG_NONE)
|
||||
/* arg_posn wrapped around. */
|
||||
goto error;
|
||||
}
|
||||
REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t precision_length;
|
||||
|
||||
dp->precision_start = cp - 1;
|
||||
for (; *cp >= '0' && *cp <= '9'; cp++)
|
||||
;
|
||||
dp->precision_end = cp;
|
||||
precision_length = dp->precision_end - dp->precision_start;
|
||||
if (max_precision_length < precision_length)
|
||||
max_precision_length = precision_length;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
arg_type type;
|
||||
|
||||
/* Parse argument type/size specifiers. */
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (*cp == 'h')
|
||||
{
|
||||
flags |= (1 << (flags & 1));
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == 'L')
|
||||
{
|
||||
flags |= 4;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == 'l')
|
||||
{
|
||||
flags += 8;
|
||||
cp++;
|
||||
}
|
||||
#ifdef HAVE_INTMAX_T
|
||||
else if (*cp == 'j')
|
||||
{
|
||||
if (sizeof (intmax_t) > sizeof (long))
|
||||
{
|
||||
/* intmax_t = long long */
|
||||
flags += 16;
|
||||
}
|
||||
else if (sizeof (intmax_t) > sizeof (int))
|
||||
{
|
||||
/* intmax_t = long */
|
||||
flags += 8;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
#endif
|
||||
else if (*cp == 'z' || *cp == 'Z')
|
||||
{
|
||||
/* 'z' is standardized in ISO C 99, but glibc uses 'Z'
|
||||
because the warning facility in gcc-2.95.2 understands
|
||||
only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
|
||||
if (sizeof (size_t) > sizeof (long))
|
||||
{
|
||||
/* size_t = long long */
|
||||
flags += 16;
|
||||
}
|
||||
else if (sizeof (size_t) > sizeof (int))
|
||||
{
|
||||
/* size_t = long */
|
||||
flags += 8;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == 't')
|
||||
{
|
||||
if (sizeof (ptrdiff_t) > sizeof (long))
|
||||
{
|
||||
/* ptrdiff_t = long long */
|
||||
flags += 16;
|
||||
}
|
||||
else if (sizeof (ptrdiff_t) > sizeof (int))
|
||||
{
|
||||
/* ptrdiff_t = long */
|
||||
flags += 8;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read the conversion character. */
|
||||
c = *cp++;
|
||||
switch (c)
|
||||
{
|
||||
case 'd': case 'i':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_LONGLONGINT;
|
||||
else
|
||||
#endif
|
||||
if (flags >= 8)
|
||||
type = TYPE_LONGINT;
|
||||
else if (flags & 2)
|
||||
type = TYPE_SCHAR;
|
||||
else if (flags & 1)
|
||||
type = TYPE_SHORT;
|
||||
else
|
||||
type = TYPE_INT;
|
||||
break;
|
||||
case 'o': case 'u': case 'x': case 'X':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_ULONGLONGINT;
|
||||
else
|
||||
#endif
|
||||
if (flags >= 8)
|
||||
type = TYPE_ULONGINT;
|
||||
else if (flags & 2)
|
||||
type = TYPE_UCHAR;
|
||||
else if (flags & 1)
|
||||
type = TYPE_USHORT;
|
||||
else
|
||||
type = TYPE_UINT;
|
||||
break;
|
||||
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
|
||||
case 'a': case 'A':
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_LONGDOUBLE;
|
||||
else
|
||||
#endif
|
||||
type = TYPE_DOUBLE;
|
||||
break;
|
||||
case 'c':
|
||||
if (flags >= 8)
|
||||
#ifdef HAVE_WINT_T
|
||||
type = TYPE_WIDE_CHAR;
|
||||
#else
|
||||
goto error;
|
||||
#endif
|
||||
else
|
||||
type = TYPE_CHAR;
|
||||
break;
|
||||
#ifdef HAVE_WINT_T
|
||||
case 'C':
|
||||
type = TYPE_WIDE_CHAR;
|
||||
c = 'c';
|
||||
break;
|
||||
#endif
|
||||
case 's':
|
||||
if (flags >= 8)
|
||||
#ifdef HAVE_WCHAR_T
|
||||
type = TYPE_WIDE_STRING;
|
||||
#else
|
||||
goto error;
|
||||
#endif
|
||||
else
|
||||
type = TYPE_STRING;
|
||||
break;
|
||||
#ifdef HAVE_WCHAR_T
|
||||
case 'S':
|
||||
type = TYPE_WIDE_STRING;
|
||||
c = 's';
|
||||
break;
|
||||
#endif
|
||||
case 'p':
|
||||
type = TYPE_POINTER;
|
||||
break;
|
||||
case 'n':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_COUNT_LONGLONGINT_POINTER;
|
||||
else
|
||||
#endif
|
||||
if (flags >= 8)
|
||||
type = TYPE_COUNT_LONGINT_POINTER;
|
||||
else if (flags & 2)
|
||||
type = TYPE_COUNT_SCHAR_POINTER;
|
||||
else if (flags & 1)
|
||||
type = TYPE_COUNT_SHORT_POINTER;
|
||||
else
|
||||
type = TYPE_COUNT_INT_POINTER;
|
||||
break;
|
||||
case '%':
|
||||
type = TYPE_NONE;
|
||||
break;
|
||||
default:
|
||||
/* Unknown conversion character. */
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (type != TYPE_NONE)
|
||||
{
|
||||
dp->arg_index = arg_index;
|
||||
if (dp->arg_index == ARG_NONE)
|
||||
{
|
||||
dp->arg_index = arg_posn++;
|
||||
if (dp->arg_index == ARG_NONE)
|
||||
/* arg_posn wrapped around. */
|
||||
goto error;
|
||||
}
|
||||
REGISTER_ARG (dp->arg_index, type);
|
||||
}
|
||||
dp->conversion = c;
|
||||
dp->dir_end = cp;
|
||||
}
|
||||
|
||||
d->count++;
|
||||
if (d->count >= d_allocated)
|
||||
{
|
||||
DIRECTIVE *memory;
|
||||
|
||||
if (SIZE_MAX / (2 * sizeof (DIRECTIVE)) < d_allocated)
|
||||
/* Overflow, would lead to out of memory. */
|
||||
goto error;
|
||||
d_allocated *= 2;
|
||||
memory = realloc (d->dir, d_allocated * sizeof (DIRECTIVE));
|
||||
if (memory == NULL)
|
||||
/* Out of memory. */
|
||||
goto error;
|
||||
d->dir = memory;
|
||||
}
|
||||
}
|
||||
}
|
||||
d->dir[d->count].dir_start = cp;
|
||||
|
||||
d->max_width_length = max_width_length;
|
||||
d->max_precision_length = max_precision_length;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (a->arg)
|
||||
free (a->arg);
|
||||
if (d->dir)
|
||||
free (d->dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#undef DIRECTIVES
|
||||
#undef DIRECTIVE
|
||||
#undef CHAR_T
|
||||
#undef PRINTF_PARSE
|
||||
918
lib/vasnprintf.c
Normal file
918
lib/vasnprintf.c
Normal file
@@ -0,0 +1,918 @@
|
||||
/* vsprintf with automatic memory allocation.
|
||||
Copyright (C) 1999, 2002-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* Tell glibc's <stdio.h> to provide a prototype for snprintf().
|
||||
This must come before <config.h> because <config.h> may include
|
||||
<features.h>, and once <features.h> has been included, it's too late. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifndef IN_LIBINTL
|
||||
# include <alloca.h>
|
||||
#endif
|
||||
|
||||
/* Specification. */
|
||||
#if WIDE_CHAR_VERSION
|
||||
# include "vasnwprintf.h"
|
||||
#else
|
||||
# include "vasnprintf.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h> /* snprintf(), sprintf() */
|
||||
#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
|
||||
#include <string.h> /* memcpy(), strlen() */
|
||||
#include <errno.h> /* errno */
|
||||
#include <limits.h> /* CHAR_BIT, INT_MAX */
|
||||
#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */
|
||||
#if WIDE_CHAR_VERSION
|
||||
# include "wprintf-parse.h"
|
||||
#else
|
||||
# include "printf-parse.h"
|
||||
#endif
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX ((size_t) -1)
|
||||
#endif
|
||||
|
||||
/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
|
||||
#ifndef EOVERFLOW
|
||||
# define EOVERFLOW E2BIG
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WCHAR_T
|
||||
# ifdef HAVE_WCSLEN
|
||||
# define local_wcslen wcslen
|
||||
# else
|
||||
/* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
|
||||
a dependency towards this library, here is a local substitute.
|
||||
Define this substitute only once, even if this file is included
|
||||
twice in the same compilation unit. */
|
||||
# ifndef local_wcslen_defined
|
||||
# define local_wcslen_defined 1
|
||||
static size_t
|
||||
local_wcslen (const wchar_t *s)
|
||||
{
|
||||
const wchar_t *ptr;
|
||||
|
||||
for (ptr = s; *ptr != (wchar_t) 0; ptr++)
|
||||
;
|
||||
return ptr - s;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if WIDE_CHAR_VERSION
|
||||
# define VASNPRINTF vasnwprintf
|
||||
# define CHAR_T wchar_t
|
||||
# define DIRECTIVE wchar_t_directive
|
||||
# define DIRECTIVES wchar_t_directives
|
||||
# define PRINTF_PARSE wprintf_parse
|
||||
# define USE_SNPRINTF 1
|
||||
# if HAVE_DECL__SNWPRINTF
|
||||
/* On Windows, the function swprintf() has a different signature than
|
||||
on Unix; we use the _snwprintf() function instead. */
|
||||
# define SNPRINTF _snwprintf
|
||||
# else
|
||||
/* Unix. */
|
||||
# define SNPRINTF swprintf
|
||||
# endif
|
||||
#else
|
||||
# define VASNPRINTF vasnprintf
|
||||
# define CHAR_T char
|
||||
# define DIRECTIVE char_directive
|
||||
# define DIRECTIVES char_directives
|
||||
# define PRINTF_PARSE printf_parse
|
||||
# define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)
|
||||
# if HAVE_DECL__SNPRINTF
|
||||
/* Windows. */
|
||||
# define SNPRINTF _snprintf
|
||||
# else
|
||||
/* Unix. */
|
||||
# define SNPRINTF snprintf
|
||||
# endif
|
||||
#endif
|
||||
|
||||
CHAR_T *
|
||||
VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
|
||||
{
|
||||
DIRECTIVES d;
|
||||
arguments a;
|
||||
|
||||
if (PRINTF_PARSE (format, &d, &a) < 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define CLEANUP() \
|
||||
free (d.dir); \
|
||||
if (a.arg) \
|
||||
free (a.arg);
|
||||
|
||||
if (printf_fetchargs (args, &a) < 0)
|
||||
{
|
||||
CLEANUP ();
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
{
|
||||
size_t buf_neededlength;
|
||||
CHAR_T *buf;
|
||||
CHAR_T *buf_malloced;
|
||||
const CHAR_T *cp;
|
||||
size_t i;
|
||||
DIRECTIVE *dp;
|
||||
/* Output string accumulator. */
|
||||
CHAR_T *result;
|
||||
size_t allocated;
|
||||
size_t length;
|
||||
|
||||
/* Allocate a small buffer that will hold a directive passed to
|
||||
sprintf or snprintf. */
|
||||
buf_neededlength = 7 + d.max_width_length + d.max_precision_length + 6;
|
||||
#if HAVE_ALLOCA
|
||||
if (buf_neededlength < 4000 / sizeof (CHAR_T))
|
||||
{
|
||||
buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
|
||||
buf_malloced = NULL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (SIZE_MAX / sizeof (CHAR_T) < buf_neededlength)
|
||||
goto out_of_memory_1;
|
||||
buf = (CHAR_T *) malloc (buf_neededlength * sizeof (CHAR_T));
|
||||
if (buf == NULL)
|
||||
goto out_of_memory_1;
|
||||
buf_malloced = buf;
|
||||
}
|
||||
|
||||
if (resultbuf != NULL)
|
||||
{
|
||||
result = resultbuf;
|
||||
allocated = *lengthp;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NULL;
|
||||
allocated = 0;
|
||||
}
|
||||
length = 0;
|
||||
/* Invariants:
|
||||
result is either == resultbuf or == NULL or malloc-allocated.
|
||||
If length > 0, then result != NULL. */
|
||||
|
||||
/* Ensures that allocated >= length + extra. Aborts through a jump to
|
||||
out_of_memory if size is too big. */
|
||||
#define ENSURE_ALLOCATION(extra) \
|
||||
{ \
|
||||
size_t needed = length + (extra); \
|
||||
if (needed < length) \
|
||||
goto out_of_memory; \
|
||||
if (needed > allocated) \
|
||||
{ \
|
||||
size_t memory_size; \
|
||||
CHAR_T *memory; \
|
||||
\
|
||||
allocated = (allocated > 0 ? 2 * allocated : 12); \
|
||||
if (needed > allocated) \
|
||||
allocated = needed; \
|
||||
if (SIZE_MAX / sizeof (CHAR_T) < allocated) \
|
||||
goto out_of_memory; \
|
||||
memory_size = allocated * sizeof (CHAR_T); \
|
||||
if (result == resultbuf || result == NULL) \
|
||||
memory = (CHAR_T *) malloc (memory_size); \
|
||||
else \
|
||||
memory = (CHAR_T *) realloc (result, memory_size); \
|
||||
if (memory == NULL) \
|
||||
goto out_of_memory; \
|
||||
if (result == resultbuf && length > 0) \
|
||||
memcpy (memory, result, length * sizeof (CHAR_T)); \
|
||||
result = memory; \
|
||||
} \
|
||||
}
|
||||
|
||||
for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
|
||||
{
|
||||
if (cp != dp->dir_start)
|
||||
{
|
||||
size_t n = dp->dir_start - cp;
|
||||
|
||||
ENSURE_ALLOCATION (n);
|
||||
memcpy (result + length, cp, n * sizeof (CHAR_T));
|
||||
length += n;
|
||||
}
|
||||
if (i == d.count)
|
||||
break;
|
||||
|
||||
/* Execute a single directive. */
|
||||
if (dp->conversion == '%')
|
||||
{
|
||||
if (!(dp->arg_index == ARG_NONE))
|
||||
abort ();
|
||||
ENSURE_ALLOCATION (1);
|
||||
result[length] = '%';
|
||||
length += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(dp->arg_index != ARG_NONE))
|
||||
abort ();
|
||||
|
||||
if (dp->conversion == 'n')
|
||||
{
|
||||
switch (a.arg[dp->arg_index].type)
|
||||
{
|
||||
case TYPE_COUNT_SCHAR_POINTER:
|
||||
*a.arg[dp->arg_index].a.a_count_schar_pointer = length;
|
||||
break;
|
||||
case TYPE_COUNT_SHORT_POINTER:
|
||||
*a.arg[dp->arg_index].a.a_count_short_pointer = length;
|
||||
break;
|
||||
case TYPE_COUNT_INT_POINTER:
|
||||
*a.arg[dp->arg_index].a.a_count_int_pointer = length;
|
||||
break;
|
||||
case TYPE_COUNT_LONGINT_POINTER:
|
||||
*a.arg[dp->arg_index].a.a_count_longint_pointer = length;
|
||||
break;
|
||||
#ifdef HAVE_LONG_LONG
|
||||
case TYPE_COUNT_LONGLONGINT_POINTER:
|
||||
*a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arg_type type = a.arg[dp->arg_index].type;
|
||||
CHAR_T *p;
|
||||
unsigned int prefix_count;
|
||||
int prefixes[2];
|
||||
#if !USE_SNPRINTF
|
||||
size_t tmp_length;
|
||||
CHAR_T tmpbuf[700];
|
||||
CHAR_T *tmp;
|
||||
|
||||
/* Allocate a temporary buffer of sufficient size for calling
|
||||
sprintf. */
|
||||
{
|
||||
size_t width;
|
||||
size_t precision;
|
||||
|
||||
width = 0;
|
||||
if (dp->width_start != dp->width_end)
|
||||
{
|
||||
if (dp->width_arg_index != ARG_NONE)
|
||||
{
|
||||
int arg;
|
||||
|
||||
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
|
||||
abort ();
|
||||
arg = a.arg[dp->width_arg_index].a.a_int;
|
||||
width = (arg < 0 ? (unsigned int) (-arg) : arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
const CHAR_T *digitp = dp->width_start;
|
||||
|
||||
do
|
||||
{
|
||||
size_t w_tmp = width * 10 + (*digitp++ - '0');
|
||||
if (SIZE_MAX / 10 < width || w_tmp < width)
|
||||
goto out_of_memory;
|
||||
width = w_tmp;
|
||||
}
|
||||
while (digitp != dp->width_end);
|
||||
}
|
||||
}
|
||||
|
||||
precision = 6;
|
||||
if (dp->precision_start != dp->precision_end)
|
||||
{
|
||||
if (dp->precision_arg_index != ARG_NONE)
|
||||
{
|
||||
int arg;
|
||||
|
||||
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
|
||||
abort ();
|
||||
arg = a.arg[dp->precision_arg_index].a.a_int;
|
||||
precision = (arg < 0 ? 0 : arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
const CHAR_T *digitp = dp->precision_start + 1;
|
||||
|
||||
precision = 0;
|
||||
while (digitp != dp->precision_end)
|
||||
{
|
||||
size_t p1 = 10 * precision + (*digitp++ - '0');
|
||||
precision = ((SIZE_MAX / 10 < precision
|
||||
|| p1 < precision)
|
||||
? SIZE_MAX : p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (dp->conversion)
|
||||
{
|
||||
|
||||
case 'd': case 'i': case 'u':
|
||||
# ifdef HAVE_LONG_LONG
|
||||
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
|
||||
* 0.30103 /* binary -> decimal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
else
|
||||
# endif
|
||||
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
|
||||
* 0.30103 /* binary -> decimal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
else
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
|
||||
* 0.30103 /* binary -> decimal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
if (tmp_length < precision)
|
||||
tmp_length = precision;
|
||||
/* Multiply by 2, as an estimate for FLAG_GROUP. */
|
||||
/* Add 1, to account for a leading sign. */
|
||||
tmp_length = (tmp_length < SIZE_MAX / 2
|
||||
? 2 * tmp_length + 1
|
||||
: SIZE_MAX);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
# ifdef HAVE_LONG_LONG
|
||||
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
|
||||
* 0.333334 /* binary -> octal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
else
|
||||
# endif
|
||||
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
|
||||
* 0.333334 /* binary -> octal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
else
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
|
||||
* 0.333334 /* binary -> octal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
if (tmp_length < precision)
|
||||
tmp_length = precision;
|
||||
/* Add 1, to account for a leading sign. */
|
||||
tmp_length += (tmp_length < SIZE_MAX);
|
||||
break;
|
||||
|
||||
case 'x': case 'X':
|
||||
# ifdef HAVE_LONG_LONG
|
||||
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
|
||||
* 0.25 /* binary -> hexadecimal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
else
|
||||
# endif
|
||||
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
|
||||
* 0.25 /* binary -> hexadecimal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
else
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
|
||||
* 0.25 /* binary -> hexadecimal */
|
||||
)
|
||||
+ 1; /* turn floor into ceil */
|
||||
if (tmp_length < precision)
|
||||
tmp_length = precision;
|
||||
/* Add 2, to account for a leading sign or alternate form. */
|
||||
if (tmp_length <= SIZE_MAX / 2)
|
||||
tmp_length *= 2;
|
||||
break;
|
||||
|
||||
case 'f': case 'F':
|
||||
# ifdef HAVE_LONG_DOUBLE
|
||||
if (type == TYPE_LONGDOUBLE)
|
||||
tmp_length =
|
||||
(unsigned int) (LDBL_MAX_EXP
|
||||
* 0.30103 /* binary -> decimal */
|
||||
* 2 /* estimate for FLAG_GROUP */
|
||||
)
|
||||
+ 1 /* turn floor into ceil */
|
||||
+ 10; /* sign, decimal point etc. */
|
||||
else
|
||||
# endif
|
||||
tmp_length =
|
||||
(unsigned int) (DBL_MAX_EXP
|
||||
* 0.30103 /* binary -> decimal */
|
||||
* 2 /* estimate for FLAG_GROUP */
|
||||
)
|
||||
+ 1 /* turn floor into ceil */
|
||||
+ 10; /* sign, decimal point etc. */
|
||||
tmp_length += precision;
|
||||
if (tmp_length < precision)
|
||||
goto out_of_memory;
|
||||
break;
|
||||
|
||||
case 'e': case 'E': case 'g': case 'G':
|
||||
case 'a': case 'A':
|
||||
tmp_length =
|
||||
12; /* sign, decimal point, exponent etc. */
|
||||
tmp_length += precision;
|
||||
if (tmp_length < precision)
|
||||
goto out_of_memory;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
# if defined HAVE_WINT_T && !WIDE_CHAR_VERSION
|
||||
if (type == TYPE_WIDE_CHAR)
|
||||
tmp_length = MB_CUR_MAX;
|
||||
else
|
||||
# endif
|
||||
tmp_length = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
# ifdef HAVE_WCHAR_T
|
||||
if (type == TYPE_WIDE_STRING)
|
||||
{
|
||||
tmp_length =
|
||||
local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
|
||||
|
||||
# if !WIDE_CHAR_VERSION
|
||||
if (SIZE_MAX / MB_CUR_MAX < tmp_length)
|
||||
goto out_of_memory;
|
||||
tmp_length *= MB_CUR_MAX;
|
||||
# endif
|
||||
}
|
||||
else
|
||||
# endif
|
||||
tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
tmp_length =
|
||||
(unsigned int) (sizeof (void *) * CHAR_BIT
|
||||
* 0.25 /* binary -> hexadecimal */
|
||||
)
|
||||
+ 1 /* turn floor into ceil */
|
||||
+ 2; /* account for leading 0x */
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (tmp_length < width)
|
||||
tmp_length = width;
|
||||
|
||||
tmp_length++; /* account for trailing NUL */
|
||||
if (!tmp_length)
|
||||
goto out_of_memory;
|
||||
}
|
||||
|
||||
if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
|
||||
tmp = tmpbuf;
|
||||
else
|
||||
{
|
||||
if (SIZE_MAX / sizeof (CHAR_T) < tmp_length)
|
||||
/* Overflow, would lead to out of memory. */
|
||||
goto out_of_memory;
|
||||
tmp = (CHAR_T *) malloc (tmp_length * sizeof (CHAR_T));
|
||||
if (tmp == NULL)
|
||||
/* Out of memory. */
|
||||
goto out_of_memory;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Construct the format string for calling snprintf or
|
||||
sprintf. */
|
||||
p = buf;
|
||||
*p++ = '%';
|
||||
if (dp->flags & FLAG_GROUP)
|
||||
*p++ = '\'';
|
||||
if (dp->flags & FLAG_LEFT)
|
||||
*p++ = '-';
|
||||
if (dp->flags & FLAG_SHOWSIGN)
|
||||
*p++ = '+';
|
||||
if (dp->flags & FLAG_SPACE)
|
||||
*p++ = ' ';
|
||||
if (dp->flags & FLAG_ALT)
|
||||
*p++ = '#';
|
||||
if (dp->flags & FLAG_ZERO)
|
||||
*p++ = '0';
|
||||
if (dp->width_start != dp->width_end)
|
||||
{
|
||||
size_t n = dp->width_end - dp->width_start;
|
||||
memcpy (p, dp->width_start, n * sizeof (CHAR_T));
|
||||
p += n;
|
||||
}
|
||||
if (dp->precision_start != dp->precision_end)
|
||||
{
|
||||
size_t n = dp->precision_end - dp->precision_start;
|
||||
memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
|
||||
p += n;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
#ifdef HAVE_LONG_LONG
|
||||
case TYPE_LONGLONGINT:
|
||||
case TYPE_ULONGLONGINT:
|
||||
*p++ = 'l';
|
||||
/*FALLTHROUGH*/
|
||||
#endif
|
||||
case TYPE_LONGINT:
|
||||
case TYPE_ULONGINT:
|
||||
#ifdef HAVE_WINT_T
|
||||
case TYPE_WIDE_CHAR:
|
||||
#endif
|
||||
#ifdef HAVE_WCHAR_T
|
||||
case TYPE_WIDE_STRING:
|
||||
#endif
|
||||
*p++ = 'l';
|
||||
break;
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
case TYPE_LONGDOUBLE:
|
||||
*p++ = 'L';
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*p = dp->conversion;
|
||||
#if USE_SNPRINTF
|
||||
p[1] = '%';
|
||||
p[2] = 'n';
|
||||
p[3] = '\0';
|
||||
#else
|
||||
p[1] = '\0';
|
||||
#endif
|
||||
|
||||
/* Construct the arguments for calling snprintf or sprintf. */
|
||||
prefix_count = 0;
|
||||
if (dp->width_arg_index != ARG_NONE)
|
||||
{
|
||||
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
|
||||
abort ();
|
||||
prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
|
||||
}
|
||||
if (dp->precision_arg_index != ARG_NONE)
|
||||
{
|
||||
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
|
||||
abort ();
|
||||
prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
|
||||
}
|
||||
|
||||
#if USE_SNPRINTF
|
||||
/* Prepare checking whether snprintf returns the count
|
||||
via %n. */
|
||||
ENSURE_ALLOCATION (1);
|
||||
result[length] = '\0';
|
||||
#endif
|
||||
|
||||
for (;;)
|
||||
{
|
||||
size_t maxlen;
|
||||
int count;
|
||||
int retcount;
|
||||
|
||||
maxlen = allocated - length;
|
||||
count = -1;
|
||||
retcount = 0;
|
||||
|
||||
#if USE_SNPRINTF
|
||||
# define SNPRINTF_BUF(arg) \
|
||||
switch (prefix_count) \
|
||||
{ \
|
||||
case 0: \
|
||||
retcount = SNPRINTF (result + length, maxlen, buf, \
|
||||
arg, &count); \
|
||||
break; \
|
||||
case 1: \
|
||||
retcount = SNPRINTF (result + length, maxlen, buf, \
|
||||
prefixes[0], arg, &count); \
|
||||
break; \
|
||||
case 2: \
|
||||
retcount = SNPRINTF (result + length, maxlen, buf, \
|
||||
prefixes[0], prefixes[1], arg, \
|
||||
&count); \
|
||||
break; \
|
||||
default: \
|
||||
abort (); \
|
||||
}
|
||||
#else
|
||||
# define SNPRINTF_BUF(arg) \
|
||||
switch (prefix_count) \
|
||||
{ \
|
||||
case 0: \
|
||||
count = sprintf (tmp, buf, arg); \
|
||||
break; \
|
||||
case 1: \
|
||||
count = sprintf (tmp, buf, prefixes[0], arg); \
|
||||
break; \
|
||||
case 2: \
|
||||
count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
|
||||
arg); \
|
||||
break; \
|
||||
default: \
|
||||
abort (); \
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TYPE_SCHAR:
|
||||
{
|
||||
int arg = a.arg[dp->arg_index].a.a_schar;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
case TYPE_UCHAR:
|
||||
{
|
||||
unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
{
|
||||
int arg = a.arg[dp->arg_index].a.a_short;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
case TYPE_USHORT:
|
||||
{
|
||||
unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
case TYPE_INT:
|
||||
{
|
||||
int arg = a.arg[dp->arg_index].a.a_int;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
case TYPE_UINT:
|
||||
{
|
||||
unsigned int arg = a.arg[dp->arg_index].a.a_uint;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
case TYPE_LONGINT:
|
||||
{
|
||||
long int arg = a.arg[dp->arg_index].a.a_longint;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
case TYPE_ULONGINT:
|
||||
{
|
||||
unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_LONG_LONG
|
||||
case TYPE_LONGLONGINT:
|
||||
{
|
||||
long long int arg = a.arg[dp->arg_index].a.a_longlongint;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
case TYPE_ULONGLONGINT:
|
||||
{
|
||||
unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TYPE_DOUBLE:
|
||||
{
|
||||
double arg = a.arg[dp->arg_index].a.a_double;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
case TYPE_LONGDOUBLE:
|
||||
{
|
||||
long double arg = a.arg[dp->arg_index].a.a_longdouble;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TYPE_CHAR:
|
||||
{
|
||||
int arg = a.arg[dp->arg_index].a.a_char;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_WINT_T
|
||||
case TYPE_WIDE_CHAR:
|
||||
{
|
||||
wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TYPE_STRING:
|
||||
{
|
||||
const char *arg = a.arg[dp->arg_index].a.a_string;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_WCHAR_T
|
||||
case TYPE_WIDE_STRING:
|
||||
{
|
||||
const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TYPE_POINTER:
|
||||
{
|
||||
void *arg = a.arg[dp->arg_index].a.a_pointer;
|
||||
SNPRINTF_BUF (arg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
#if USE_SNPRINTF
|
||||
/* Portability: Not all implementations of snprintf()
|
||||
are ISO C 99 compliant. Determine the number of
|
||||
bytes that snprintf() has produced or would have
|
||||
produced. */
|
||||
if (count >= 0)
|
||||
{
|
||||
/* Verify that snprintf() has NUL-terminated its
|
||||
result. */
|
||||
if (count < maxlen && result[length + count] != '\0')
|
||||
abort ();
|
||||
/* Portability hack. */
|
||||
if (retcount > count)
|
||||
count = retcount;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* snprintf() doesn't understand the '%n'
|
||||
directive. */
|
||||
if (p[1] != '\0')
|
||||
{
|
||||
/* Don't use the '%n' directive; instead, look
|
||||
at the snprintf() return value. */
|
||||
p[1] = '\0';
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Look at the snprintf() return value. */
|
||||
if (retcount < 0)
|
||||
{
|
||||
/* HP-UX 10.20 snprintf() is doubly deficient:
|
||||
It doesn't understand the '%n' directive,
|
||||
*and* it returns -1 (rather than the length
|
||||
that would have been required) when the
|
||||
buffer is too small. */
|
||||
size_t bigger_need =
|
||||
(allocated > 12 ? allocated : 12);
|
||||
ENSURE_ALLOCATION (bigger_need);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
count = retcount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Attempt to handle failure. */
|
||||
if (count < 0)
|
||||
{
|
||||
if (!(result == resultbuf || result == NULL))
|
||||
free (result);
|
||||
if (buf_malloced != NULL)
|
||||
free (buf_malloced);
|
||||
CLEANUP ();
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !USE_SNPRINTF
|
||||
if (count >= tmp_length)
|
||||
/* tmp_length was incorrectly calculated - fix the
|
||||
code above! */
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
/* Make room for the result. */
|
||||
if (count >= maxlen)
|
||||
{
|
||||
/* Need at least count bytes. But allocate
|
||||
proportionally, to avoid looping eternally if
|
||||
snprintf() reports a too small count. */
|
||||
ENSURE_ALLOCATION (count < allocated
|
||||
? allocated : count);
|
||||
#if USE_SNPRINTF
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USE_SNPRINTF
|
||||
/* The snprintf() result did fit. */
|
||||
#else
|
||||
/* Append the sprintf() result. */
|
||||
memcpy (result + length, tmp, count * sizeof (CHAR_T));
|
||||
if (tmp != tmpbuf)
|
||||
free (tmp);
|
||||
#endif
|
||||
|
||||
length += count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the final NUL. */
|
||||
ENSURE_ALLOCATION (1);
|
||||
result[length] = '\0';
|
||||
|
||||
if (result != resultbuf && length + 1 < allocated)
|
||||
{
|
||||
/* Shrink the allocated memory if possible. */
|
||||
CHAR_T *memory;
|
||||
|
||||
memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
|
||||
if (memory != NULL)
|
||||
result = memory;
|
||||
}
|
||||
|
||||
if (buf_malloced != NULL)
|
||||
free (buf_malloced);
|
||||
CLEANUP ();
|
||||
*lengthp = length;
|
||||
if (length > INT_MAX)
|
||||
goto length_overflow;
|
||||
return result;
|
||||
|
||||
length_overflow:
|
||||
/* We could produce such a big string, but its length doesn't fit into
|
||||
an 'int'. POSIX says that snprintf() fails with errno = EOVERFLOW in
|
||||
this case. */
|
||||
if (result != resultbuf)
|
||||
free (result);
|
||||
errno = EOVERFLOW;
|
||||
return NULL;
|
||||
|
||||
out_of_memory:
|
||||
if (!(result == resultbuf || result == NULL))
|
||||
free (result);
|
||||
if (buf_malloced != NULL)
|
||||
free (buf_malloced);
|
||||
out_of_memory_1:
|
||||
CLEANUP ();
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SNPRINTF
|
||||
#undef USE_SNPRINTF
|
||||
#undef PRINTF_PARSE
|
||||
#undef DIRECTIVES
|
||||
#undef DIRECTIVE
|
||||
#undef CHAR_T
|
||||
#undef VASNPRINTF
|
||||
@@ -1,3 +0,0 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
*.m4
|
||||
@@ -1,21 +0,0 @@
|
||||
index.html
|
||||
*.po
|
||||
LINGUAS
|
||||
Makefile.in.in
|
||||
Makevars
|
||||
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
|
||||
@@ -46,7 +46,6 @@ src/delete.c
|
||||
src/extract.c
|
||||
src/incremen.c
|
||||
src/list.c
|
||||
src/mangle.c
|
||||
src/misc.c
|
||||
src/names.c
|
||||
src/tar.c
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Makefile for GNU tar sources.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2003, 2006
|
||||
# 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
|
||||
@@ -30,7 +30,6 @@ tar_SOURCES = \
|
||||
xheader.c\
|
||||
incremen.c\
|
||||
list.c\
|
||||
mangle.c\
|
||||
misc.c\
|
||||
names.c\
|
||||
sparse.c\
|
||||
@@ -40,9 +39,7 @@ tar_SOURCES = \
|
||||
update.c\
|
||||
utf8.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/lib -I../ -I../lib
|
||||
|
||||
tar.o: ../lib/localedir.h
|
||||
INCLUDES = -I$(top_srcdir)/lib -I../ -I../lib
|
||||
|
||||
LDADD = ../lib/libtar.a $(LIBINTL) $(LIBICONV)
|
||||
|
||||
|
||||
10
src/common.h
10
src/common.h
@@ -254,7 +254,7 @@ GLOBAL bool show_omitted_dirs_option;
|
||||
GLOBAL bool sparse_option;
|
||||
GLOBAL unsigned tar_sparse_major;
|
||||
GLOBAL unsigned tar_sparse_minor;
|
||||
|
||||
|
||||
GLOBAL bool starting_file_option;
|
||||
|
||||
/* Specified maximum byte length of each tape volume (multiple of 1024). */
|
||||
@@ -296,7 +296,7 @@ GLOBAL int archive;
|
||||
/* Nonzero when outputting to /dev/null. */
|
||||
GLOBAL bool dev_null_output;
|
||||
|
||||
/* Timestamps: */
|
||||
/* Timestamps: */
|
||||
GLOBAL struct timespec start_time; /* when we started execution */
|
||||
GLOBAL struct timespec volume_start_time; /* when the current volume was
|
||||
opened*/
|
||||
@@ -546,10 +546,6 @@ enum read_header tar_checksum (union block *header, bool silent);
|
||||
void skip_file (off_t size);
|
||||
void skip_member (void);
|
||||
|
||||
/* Module mangle.c. */
|
||||
|
||||
void extract_mangle (void);
|
||||
|
||||
/* Module misc.c. */
|
||||
|
||||
void assign_string (char **dest, const char *src);
|
||||
@@ -727,5 +723,3 @@ bool utf8_convert (bool to_utf, char const *input, char **output);
|
||||
void set_transform_expr (const char *expr);
|
||||
bool transform_name (char **pinput);
|
||||
bool transform_name_fp (char **pinput, char *(*fun)(char *));
|
||||
|
||||
|
||||
|
||||
95
src/create.c
95
src/create.c
@@ -33,6 +33,65 @@ struct link
|
||||
size_t nlink;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct exclude_tag
|
||||
{
|
||||
const char *name;
|
||||
size_t length;
|
||||
struct exclude_tag *next;
|
||||
};
|
||||
|
||||
static struct exclude_tag *exclude_tags;
|
||||
|
||||
void
|
||||
add_exclude_tag (const char *name)
|
||||
{
|
||||
struct exclude_tag *tag = xmalloc (sizeof tag[0]);
|
||||
tag->next = exclude_tags;
|
||||
tag->name = name;
|
||||
tag->length = strlen (name);
|
||||
exclude_tags = tag;
|
||||
}
|
||||
|
||||
static bool
|
||||
check_exclude_tags (char *dirname)
|
||||
{
|
||||
static char *tagname;
|
||||
static size_t tagsize;
|
||||
struct exclude_tag *tag;
|
||||
size_t dlen = strlen (dirname);
|
||||
char *nptr = NULL;
|
||||
char *ret = NULL;
|
||||
|
||||
for (tag = exclude_tags; tag; tag = tag->next)
|
||||
{
|
||||
size_t size = dlen + tag->length + 1;
|
||||
if (size > tagsize)
|
||||
{
|
||||
tagsize = size;
|
||||
tagname = xrealloc (tagname, tagsize);
|
||||
}
|
||||
|
||||
if (!nptr)
|
||||
{
|
||||
strcpy (tagname, dirname);
|
||||
nptr = tagname + dlen;
|
||||
}
|
||||
strcpy (nptr, tag->name);
|
||||
if (access (tagname, F_OK) == 0)
|
||||
{
|
||||
if (verbose_option)
|
||||
WARN ((0, 0,
|
||||
_("%s: contains a cache directory tag %s; not dumped"),
|
||||
quotearg_colon (dirname),
|
||||
quotearg_n (1, tag->name)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* The maximum uintmax_t value that can be represented with DIGITS digits,
|
||||
assuming that each digit is BITS_PER_DIGIT wide. */
|
||||
@@ -742,7 +801,7 @@ start_header (struct tar_stat_info *st)
|
||||
{
|
||||
if (MAX_OCTAL_VAL (header->header.mtime) < mtime.tv_sec
|
||||
|| mtime.tv_nsec != 0)
|
||||
xheader_store ("mtime", st, NULL);
|
||||
xheader_store ("mtime", st, &mtime);
|
||||
if (MAX_OCTAL_VAL (header->header.mtime) < mtime.tv_sec)
|
||||
mtime.tv_sec = 0;
|
||||
}
|
||||
@@ -983,6 +1042,7 @@ dump_regular_file (int fd, struct tar_stat_info *st)
|
||||
return dump_status_ok;
|
||||
}
|
||||
|
||||
|
||||
/* Look in directory DIRNAME for a cache directory tag file
|
||||
with the magic name "CACHEDIR.TAG" and a standard header,
|
||||
as described at:
|
||||
@@ -1000,7 +1060,7 @@ check_cache_directory (char *dirname)
|
||||
static char tagname[] = "CACHEDIR.TAG";
|
||||
char *tagpath;
|
||||
int fd;
|
||||
int tag_present = false;
|
||||
bool tag_present = false;
|
||||
|
||||
tagpath = xmalloc (strlen (dirname) + strlen (tagname) + 1);
|
||||
strcpy (tagpath, dirname);
|
||||
@@ -1113,17 +1173,7 @@ dump_dir0 (char *directory,
|
||||
quotearg_colon (st->orig_file_name)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (exclude_caches_option
|
||||
&& check_cache_directory(st->orig_file_name))
|
||||
{
|
||||
if (verbose_option)
|
||||
WARN ((0, 0,
|
||||
_("%s: contains a cache directory tag; not dumped"),
|
||||
quotearg_colon (st->orig_file_name)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
char const *entry;
|
||||
size_t entry_len;
|
||||
@@ -1174,9 +1224,6 @@ dump_dir (int fd, struct tar_stat_info *st, int top_level, dev_t parent_device)
|
||||
return false;
|
||||
}
|
||||
|
||||
ensure_slash (&st->orig_file_name);
|
||||
ensure_slash (&st->file_name);
|
||||
|
||||
dump_dir0 (directory, st, top_level, parent_device);
|
||||
|
||||
free (directory);
|
||||
@@ -1497,6 +1544,22 @@ dump_file0 (struct tar_stat_info *st, const char *p,
|
||||
|
||||
if (is_dir)
|
||||
{
|
||||
ensure_slash (&st->orig_file_name);
|
||||
ensure_slash (&st->file_name);
|
||||
|
||||
if (exclude_caches_option
|
||||
&& check_cache_directory (st->orig_file_name))
|
||||
{
|
||||
if (verbose_option)
|
||||
WARN ((0, 0,
|
||||
_("%s: contains a cache directory tag; not dumped"),
|
||||
quotearg_colon (st->orig_file_name)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (check_exclude_tags (st->orig_file_name))
|
||||
return;
|
||||
|
||||
ok = dump_dir (fd, st, top_level, parent_device);
|
||||
|
||||
/* dump_dir consumes FD if successful. */
|
||||
|
||||
114
src/extract.c
114
src/extract.c
@@ -37,7 +37,8 @@ enum permstatus
|
||||
/* This file may have existed already; its permissions are unknown. */
|
||||
UNKNOWN_PERMSTATUS,
|
||||
|
||||
/* This file was created using the permissions from the archive. */
|
||||
/* This file was created using the permissions from the archive,
|
||||
except with S_IRWXG | S_IRWXO masked out if 0 < same_owner_option. */
|
||||
ARCHIVED_PERMSTATUS,
|
||||
|
||||
/* This is an intermediate directory; the archive did not specify
|
||||
@@ -149,12 +150,15 @@ set_mode (char const *file_name,
|
||||
{
|
||||
mode = stat_info->st_mode;
|
||||
|
||||
/* If we created the file and it has a usual mode, then its mode
|
||||
is normally set correctly already. But on many hosts, some
|
||||
/* If we created the file and it has a mode that we set already
|
||||
with O_CREAT, then its mode is often set correctly already.
|
||||
But if we are changing ownership, the mode's group and and
|
||||
other permission bits were omitted originally, so it's less
|
||||
likely that the mode is OK now. Also, on many hosts, some
|
||||
directories inherit the setgid bits from their parents, so we
|
||||
we must set directories' modes explicitly. */
|
||||
if (permstatus == ARCHIVED_PERMSTATUS
|
||||
&& ! (mode & ~ MODE_RWX)
|
||||
if ((permstatus == ARCHIVED_PERMSTATUS
|
||||
&& ! (mode & ~ (0 < same_owner_option ? S_IRWXU : MODE_RWX)))
|
||||
&& typeflag != DIRTYPE
|
||||
&& typeflag != GNUTYPE_DUMPDIR)
|
||||
return;
|
||||
@@ -217,7 +221,7 @@ check_time (char const *file_name, struct timespec t)
|
||||
/* Restore stat attributes (owner, group, mode and times) for
|
||||
FILE_NAME, using information given in *ST.
|
||||
If CUR_INFO is nonzero, *CUR_INFO is the
|
||||
file's currernt status.
|
||||
file's current status.
|
||||
If not restoring permissions, invert the
|
||||
INVERT_PERMISSIONS bits from the file's current permissions.
|
||||
PERMSTATUS specifies the status of the file's permissions.
|
||||
@@ -265,11 +269,11 @@ set_stat (char const *file_name,
|
||||
}
|
||||
|
||||
/* Some systems allow non-root users to give files away. Once this
|
||||
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, &st->stat, cur_info,
|
||||
invert_permissions, permstatus, typeflag);
|
||||
done, it is not possible anymore to change file permissions.
|
||||
However, setting file permissions now would be incorrect, since
|
||||
they would apply to the wrong user, and there would be a race
|
||||
condition. So, don't use systems that allow non-root users to
|
||||
give files away. */
|
||||
}
|
||||
|
||||
if (0 < same_owner_option && permstatus != INTERDIR_PERMSTATUS)
|
||||
@@ -278,29 +282,36 @@ set_stat (char const *file_name,
|
||||
the symbolic link itself. In this case, a mere chown would change
|
||||
the attributes of the file the symbolic link is pointing to, and
|
||||
should be avoided. */
|
||||
int chown_result = 1;
|
||||
|
||||
if (typeflag == SYMTYPE)
|
||||
{
|
||||
#if HAVE_LCHOWN
|
||||
if (lchown (file_name, st->stat.st_uid, st->stat.st_gid) < 0)
|
||||
chown_error_details (file_name,
|
||||
st->stat.st_uid, st->stat.st_gid);
|
||||
chown_result = lchown (file_name, st->stat.st_uid, st->stat.st_gid);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chown (file_name, st->stat.st_uid, st->stat.st_gid) < 0)
|
||||
chown_error_details (file_name,
|
||||
st->stat.st_uid, st->stat.st_gid);
|
||||
|
||||
/* On a few systems, and in particular, those allowing to give files
|
||||
away, changing the owner or group destroys the suid or sgid bits.
|
||||
So let's attempt setting these bits once more. */
|
||||
if (st->stat.st_mode & (S_ISUID | S_ISGID | S_ISVTX))
|
||||
set_mode (file_name, &st->stat, 0,
|
||||
invert_permissions, permstatus, typeflag);
|
||||
chown_result = chown (file_name, st->stat.st_uid, st->stat.st_gid);
|
||||
}
|
||||
|
||||
if (chown_result == 0)
|
||||
{
|
||||
/* Changing the owner can flip st_mode bits in some cases, so
|
||||
ignore cur_info if it might be obsolete now. */
|
||||
if (cur_info
|
||||
&& cur_info->st_mode & S_IXUGO
|
||||
&& cur_info->st_mode & (S_ISUID | S_ISGID))
|
||||
cur_info = NULL;
|
||||
}
|
||||
else if (chown_result < 0)
|
||||
chown_error_details (file_name,
|
||||
st->stat.st_uid, st->stat.st_gid);
|
||||
}
|
||||
|
||||
if (typeflag != SYMTYPE)
|
||||
set_mode (file_name, &st->stat, cur_info,
|
||||
invert_permissions, permstatus, typeflag);
|
||||
}
|
||||
|
||||
/* Remember to restore stat attributes (owner, group, mode and times)
|
||||
@@ -374,7 +385,8 @@ repair_delayed_set_stat (char const *dir,
|
||||
data->atime = current_stat_info.atime;
|
||||
data->mtime = current_stat_info.mtime;
|
||||
data->invert_permissions =
|
||||
(MODE_RWX & (current_stat_info.stat.st_mode ^ st.st_mode));
|
||||
((current_stat_info.stat.st_mode ^ st.st_mode)
|
||||
& MODE_RWX & ~ current_umask);
|
||||
data->permstatus = ARCHIVED_PERMSTATUS;
|
||||
return;
|
||||
}
|
||||
@@ -626,8 +638,9 @@ extract_dir (char *file_name, int typeflag)
|
||||
else if (typeflag == GNUTYPE_DUMPDIR)
|
||||
skip_member ();
|
||||
|
||||
mode = (current_stat_info.stat.st_mode |
|
||||
(we_are_root ? 0 : MODE_WXUSR)) & MODE_RWX;
|
||||
mode = current_stat_info.stat.st_mode | (we_are_root ? 0 : MODE_WXUSR);
|
||||
if (0 < same_owner_option || current_stat_info.stat.st_mode & ~ MODE_RWX)
|
||||
mode &= S_IRWXU;
|
||||
|
||||
while ((status = mkdir (file_name, mode)))
|
||||
{
|
||||
@@ -670,7 +683,8 @@ extract_dir (char *file_name, int typeflag)
|
||||
{
|
||||
if (status == 0)
|
||||
delay_set_stat (file_name, ¤t_stat_info,
|
||||
MODE_RWX & (mode ^ current_stat_info.stat.st_mode),
|
||||
((mode ^ current_stat_info.stat.st_mode)
|
||||
& MODE_RWX & ~ current_umask),
|
||||
ARCHIVED_PERMSTATUS);
|
||||
else /* For an already existing directory, invert_perms must be 0 */
|
||||
delay_set_stat (file_name, ¤t_stat_info,
|
||||
@@ -682,14 +696,13 @@ extract_dir (char *file_name, int typeflag)
|
||||
|
||||
|
||||
static int
|
||||
open_output_file (char *file_name, int typeflag)
|
||||
open_output_file (char *file_name, int typeflag, mode_t mode)
|
||||
{
|
||||
int fd;
|
||||
int openflag = (O_WRONLY | O_BINARY | O_CREAT
|
||||
| (old_files_option == OVERWRITE_OLD_FILES
|
||||
? O_TRUNC
|
||||
: O_EXCL));
|
||||
mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
|
||||
|
||||
#if O_CTG
|
||||
/* Contiguous files (on the Masscomp) have to specify the size in
|
||||
@@ -728,6 +741,9 @@ extract_file (char *file_name, int typeflag)
|
||||
size_t count;
|
||||
size_t written;
|
||||
int interdir_made = 0;
|
||||
mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
|
||||
mode_t invert_permissions =
|
||||
0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) : 0;
|
||||
|
||||
/* FIXME: deal with protection issues. */
|
||||
|
||||
@@ -745,11 +761,12 @@ extract_file (char *file_name, int typeflag)
|
||||
else
|
||||
{
|
||||
do
|
||||
fd = open_output_file (file_name, typeflag);
|
||||
fd = open_output_file (file_name, typeflag, mode ^ invert_permissions);
|
||||
while (fd < 0 && maybe_recoverable (file_name, &interdir_made));
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
skip_member ();
|
||||
open_error (file_name);
|
||||
return 1;
|
||||
}
|
||||
@@ -810,7 +827,7 @@ extract_file (char *file_name, int typeflag)
|
||||
if (to_command_option)
|
||||
sys_wait_command ();
|
||||
else
|
||||
set_stat (file_name, ¤t_stat_info, NULL, 0,
|
||||
set_stat (file_name, ¤t_stat_info, NULL, invert_permissions,
|
||||
(old_files_option == OVERWRITE_OLD_FILES ?
|
||||
UNKNOWN_PERMSTATUS : ARCHIVED_PERMSTATUS),
|
||||
typeflag);
|
||||
@@ -871,7 +888,7 @@ create_placeholder_file (char *file_name, bool is_symlink, int *interdir_made)
|
||||
if (h && ! h->after_links
|
||||
&& 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))
|
||||
&& (last_component (file_name) == file_name + h->file_name_len + 1))
|
||||
{
|
||||
do
|
||||
{
|
||||
@@ -988,16 +1005,19 @@ extract_node (char *file_name, int typeflag)
|
||||
{
|
||||
int status;
|
||||
int interdir_made = 0;
|
||||
mode_t mode = current_stat_info.stat.st_mode & ~ current_umask;
|
||||
mode_t invert_permissions =
|
||||
0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) : 0;
|
||||
|
||||
do
|
||||
status = mknod (file_name, current_stat_info.stat.st_mode,
|
||||
status = mknod (file_name, mode ^ invert_permissions,
|
||||
current_stat_info.stat.st_rdev);
|
||||
while (status && maybe_recoverable (file_name, &interdir_made));
|
||||
|
||||
if (status != 0)
|
||||
mknod_error (file_name);
|
||||
else
|
||||
set_stat (file_name, ¤t_stat_info, NULL, 0,
|
||||
set_stat (file_name, ¤t_stat_info, NULL, invert_permissions,
|
||||
ARCHIVED_PERMSTATUS, typeflag);
|
||||
return status;
|
||||
}
|
||||
@@ -1009,13 +1029,16 @@ extract_fifo (char *file_name, int typeflag)
|
||||
{
|
||||
int status;
|
||||
int interdir_made = 0;
|
||||
mode_t mode = current_stat_info.stat.st_mode & ~ current_umask;
|
||||
mode_t invert_permissions =
|
||||
0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) : 0;
|
||||
|
||||
while ((status = mkfifo (file_name, current_stat_info.stat.st_mode)))
|
||||
while ((status = mkfifo (file_name, mode)) != 0)
|
||||
if (!maybe_recoverable (file_name, &interdir_made))
|
||||
break;
|
||||
|
||||
if (status == 0)
|
||||
set_stat (file_name, ¤t_stat_info, NULL, 0,
|
||||
set_stat (file_name, ¤t_stat_info, NULL, invert_permissions,
|
||||
ARCHIVED_PERMSTATUS, typeflag);
|
||||
else
|
||||
mkfifo_error (file_name);
|
||||
@@ -1023,13 +1046,6 @@ extract_fifo (char *file_name, int typeflag)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
extract_mangle_wrapper (char *file_name, int typeflag)
|
||||
{
|
||||
extract_mangle ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
extract_volhdr (char *file_name, int typeflag)
|
||||
{
|
||||
@@ -1121,10 +1137,6 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
|
||||
*fun = extract_volhdr;
|
||||
break;
|
||||
|
||||
case GNUTYPE_NAMES:
|
||||
*fun = extract_mangle_wrapper;
|
||||
break;
|
||||
|
||||
case GNUTYPE_MULTIVOL:
|
||||
ERROR ((0, 0,
|
||||
_("%s: Cannot extract -- file is continued from another volume"),
|
||||
@@ -1331,10 +1343,10 @@ rename_directory (char *src, char *dst)
|
||||
e = errno;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case EXDEV:
|
||||
/* FIXME: Fall back to recursive copying */
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1346,7 +1358,7 @@ rename_directory (char *src, char *dst)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fatal_exit (void)
|
||||
{
|
||||
|
||||
@@ -107,7 +107,6 @@ read_and (void (*do_something) (void))
|
||||
{
|
||||
case GNUTYPE_VOLHDR:
|
||||
case GNUTYPE_MULTIVOL:
|
||||
case GNUTYPE_NAMES:
|
||||
break;
|
||||
|
||||
case DIRTYPE:
|
||||
@@ -1047,10 +1046,6 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
|
||||
modes[0] = 'M';
|
||||
break;
|
||||
|
||||
case GNUTYPE_NAMES:
|
||||
modes[0] = 'N';
|
||||
break;
|
||||
|
||||
case GNUTYPE_LONGNAME:
|
||||
case GNUTYPE_LONGLINK:
|
||||
modes[0] = 'L';
|
||||
@@ -1234,10 +1229,6 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
|
||||
uintbuf));
|
||||
fprintf (stdlis, _("--Continued at byte %s--\n"), size);
|
||||
break;
|
||||
|
||||
case GNUTYPE_NAMES:
|
||||
fprintf (stdlis, _("--Mangled file names--\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
fflush (stdlis);
|
||||
|
||||
121
src/mangle.c
121
src/mangle.c
@@ -1,121 +0,0 @@
|
||||
/* Encode long filenames for GNU tar.
|
||||
Copyright 1988, 92, 94, 96, 97, 99, 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 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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include <system.h>
|
||||
#include "common.h"
|
||||
#include <quotearg.h>
|
||||
|
||||
struct mangled
|
||||
{
|
||||
struct mangled *next;
|
||||
int type;
|
||||
char mangled[NAME_FIELD_SIZE];
|
||||
char *linked_to;
|
||||
char normal[1];
|
||||
};
|
||||
|
||||
/* Extract a GNUTYPE_NAMES record contents. It seems that such are
|
||||
not produced anymore by GNU tar, but we leave the reading code
|
||||
around nevertheless, for salvaging old tapes. */
|
||||
void
|
||||
extract_mangle (void)
|
||||
{
|
||||
off_t size = current_stat_info.stat.st_size;
|
||||
char *buffer = xmalloc ((size_t) (size + 1));
|
||||
char *copy = buffer;
|
||||
char *cursor = buffer;
|
||||
|
||||
if (size != (size_t) size || size == (size_t) -1)
|
||||
xalloc_die ();
|
||||
|
||||
buffer[size] = '\0';
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
union block *block = find_next_block ();
|
||||
size_t available;
|
||||
|
||||
if (!block)
|
||||
{
|
||||
ERROR ((0, 0, _("Unexpected EOF in mangled names")));
|
||||
return;
|
||||
}
|
||||
available = available_space_after (block);
|
||||
if (available > size)
|
||||
available = size;
|
||||
memcpy (copy, block->buffer, available);
|
||||
copy += available;
|
||||
size -= available;
|
||||
set_next_block_after ((union block *) (block->buffer + available - 1));
|
||||
}
|
||||
|
||||
while (*cursor)
|
||||
{
|
||||
char *next_cursor;
|
||||
char *name;
|
||||
char *name_end;
|
||||
|
||||
next_cursor = strchr (cursor, '\n');
|
||||
*next_cursor++ = '\0';
|
||||
|
||||
if (!strncmp (cursor, "Rename ", 7))
|
||||
{
|
||||
|
||||
name = cursor + 7;
|
||||
name_end = strchr (name, ' ');
|
||||
while (strncmp (name_end, " to ", 4))
|
||||
{
|
||||
name_end++;
|
||||
name_end = strchr (name_end, ' ');
|
||||
}
|
||||
*name_end = '\0';
|
||||
if (next_cursor[-2] == '/')
|
||||
next_cursor[-2] = '\0';
|
||||
unquote_string (name_end + 4);
|
||||
if (rename (name, name_end + 4))
|
||||
ERROR ((0, errno, _("%s: Cannot rename to %s"),
|
||||
quotearg_colon (name), quote_n (1, name_end + 4)));
|
||||
else if (verbose_option)
|
||||
WARN ((0, 0, _("Renamed %s to %s"), name, name_end + 4));
|
||||
}
|
||||
#ifdef HAVE_SYMLINK
|
||||
else if (!strncmp (cursor, "Symlink ", 8))
|
||||
{
|
||||
name = cursor + 8;
|
||||
name_end = strchr (name, ' ');
|
||||
while (strncmp (name_end, " to ", 4))
|
||||
{
|
||||
name_end++;
|
||||
name_end = strchr (name_end, ' ');
|
||||
}
|
||||
*name_end = '\0';
|
||||
unquote_string (name);
|
||||
unquote_string (name_end + 4);
|
||||
if (symlink (name, name_end + 4)
|
||||
&& (unlink (name_end + 4) || symlink (name, name_end + 4)))
|
||||
ERROR ((0, errno, _("%s: Cannot symlink to %s"),
|
||||
quotearg_colon (name), quote_n (1, name_end + 4)));
|
||||
else if (verbose_option)
|
||||
WARN ((0, 0, _("Symlinked %s to %s"), name, name_end + 4));
|
||||
}
|
||||
#endif
|
||||
else
|
||||
ERROR ((0, 0, _("Unknown demangling command %s"), cursor));
|
||||
|
||||
cursor = next_cursor;
|
||||
}
|
||||
}
|
||||
72
src/tar.c
72
src/tar.c
@@ -41,10 +41,11 @@
|
||||
|
||||
#include <argmatch.h>
|
||||
#include <closeout.h>
|
||||
#include <configmake.h>
|
||||
#include <exitfail.h>
|
||||
#include <getdate.h>
|
||||
#include <localedir.h>
|
||||
#include <rmt.h>
|
||||
#include <rmt-command.h>
|
||||
#include <prepargs.h>
|
||||
#include <quotearg.h>
|
||||
#include <version-etc.h>
|
||||
@@ -254,6 +255,7 @@ enum
|
||||
DELETE_OPTION,
|
||||
EXCLUDE_CACHES_OPTION,
|
||||
EXCLUDE_OPTION,
|
||||
EXCLUDE_TAG_OPTION,
|
||||
FORCE_LOCAL_OPTION,
|
||||
GROUP_OPTION,
|
||||
HANG_OPTION,
|
||||
@@ -603,6 +605,8 @@ static struct argp_option options[] = {
|
||||
N_("exclude patterns listed in FILE"), GRID+1 },
|
||||
{"exclude-caches", EXCLUDE_CACHES_OPTION, 0, 0,
|
||||
N_("exclude directories containing a cache tag"), GRID+1 },
|
||||
{"exclude-tag", EXCLUDE_TAG_OPTION, N_("FILE"), 0,
|
||||
N_("exclude directories containing FILE"), GRID+1 },
|
||||
{"no-recursion", NO_RECURSION_OPTION, 0, 0,
|
||||
N_("avoid descending automatically in directories"), GRID+1 },
|
||||
{"one-file-system", ONE_FILE_SYSTEM_OPTION, 0, 0,
|
||||
@@ -953,7 +957,8 @@ enum read_file_list_state /* Result of reading file name from the list file */
|
||||
{
|
||||
file_list_success, /* OK, name read successfully */
|
||||
file_list_end, /* End of list file */
|
||||
file_list_zero /* Zero separator encountered where it should not */
|
||||
file_list_zero, /* Zero separator encountered where it should not */
|
||||
file_list_skip /* Empty (zero-length) entry encountered, skip it */
|
||||
};
|
||||
|
||||
/* Read from FP a sequence of characters up to FILENAME_TERMINATOR and put them
|
||||
@@ -971,13 +976,15 @@ read_name_from_file (FILE *fp, struct obstack *stk)
|
||||
{
|
||||
/* We have read a zero separator. The file possibly is
|
||||
zero-separated */
|
||||
/* FATAL_ERROR((0, 0, N_("file name contains null character"))); */
|
||||
return file_list_zero;
|
||||
}
|
||||
obstack_1grow (stk, c);
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (counter == 0 && c != EOF)
|
||||
return file_list_skip;
|
||||
|
||||
obstack_1grow (stk, 0);
|
||||
|
||||
return (counter == 0 && c == EOF) ? file_list_end : file_list_success;
|
||||
@@ -1058,31 +1065,42 @@ update_argv (const char *filename, struct argp_state *state)
|
||||
open_fatal (filename);
|
||||
}
|
||||
|
||||
while ((read_state = read_name_from_file (fp, &argv_stk)) == file_list_success)
|
||||
count++;
|
||||
|
||||
if (read_state == file_list_zero)
|
||||
while ((read_state = read_name_from_file (fp, &argv_stk)) != file_list_end)
|
||||
{
|
||||
size_t size;
|
||||
switch (read_state)
|
||||
{
|
||||
case file_list_success:
|
||||
count++;
|
||||
break;
|
||||
|
||||
WARN ((0, 0, N_("%s: file name read contains nul character"),
|
||||
quotearg_colon (filename)));
|
||||
case file_list_end: /* won't happen, just to pacify gcc */
|
||||
break;
|
||||
|
||||
/* Prepare new stack contents */
|
||||
size = obstack_object_size (&argv_stk);
|
||||
p = obstack_finish (&argv_stk);
|
||||
for (; size > 0; size--, p++)
|
||||
if (*p)
|
||||
obstack_1grow (&argv_stk, *p);
|
||||
else
|
||||
obstack_1grow (&argv_stk, '\n');
|
||||
obstack_1grow (&argv_stk, 0);
|
||||
count = 1;
|
||||
case file_list_zero:
|
||||
{
|
||||
size_t size;
|
||||
|
||||
/* Read rest of files using new filename terminator */
|
||||
filename_terminator = 0;
|
||||
while (read_name_from_file (fp, &argv_stk) == file_list_success)
|
||||
count++;
|
||||
WARN ((0, 0, N_("%s: file name read contains nul character"),
|
||||
quotearg_colon (filename)));
|
||||
|
||||
/* Prepare new stack contents */
|
||||
size = obstack_object_size (&argv_stk);
|
||||
p = obstack_finish (&argv_stk);
|
||||
for (; size > 0; size--, p++)
|
||||
if (*p)
|
||||
obstack_1grow (&argv_stk, *p);
|
||||
else
|
||||
obstack_1grow (&argv_stk, '\n');
|
||||
obstack_1grow (&argv_stk, 0);
|
||||
count = 1;
|
||||
/* Read rest of files using new filename terminator */
|
||||
filename_terminator = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case file_list_skip:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_stdin)
|
||||
@@ -1492,6 +1510,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
|
||||
exclude_caches_option = true;
|
||||
break;
|
||||
|
||||
case EXCLUDE_TAG_OPTION:
|
||||
add_exclude_tag (arg);
|
||||
break;
|
||||
|
||||
case FORCE_LOCAL_OPTION:
|
||||
force_local_option = true;
|
||||
break;
|
||||
@@ -2332,7 +2354,7 @@ main (int argc, char **argv)
|
||||
|
||||
if (stdlis == stdout)
|
||||
close_stdout ();
|
||||
else if (ferror (stderr) || fclose (stderr) != 0)
|
||||
else if (ferror (stderr) || fclose (stderr) != 0)
|
||||
exit_status = TAREXIT_FAILURE;
|
||||
|
||||
return exit_status;
|
||||
|
||||
@@ -165,6 +165,7 @@ struct oldgnu_header
|
||||
'A' Solaris Access Control List
|
||||
'E' Solaris Extended Attribute File
|
||||
'I' Inode only, as in 'star'
|
||||
'N' Obsolete GNU tar, for file names that do not fit into the main header.
|
||||
'X' POSIX 1003.1-2001 eXtended (VU version) */
|
||||
|
||||
/* This is a dir entry that contains the names of files that were in the
|
||||
@@ -180,9 +181,6 @@ struct oldgnu_header
|
||||
/* This is the continuation of a file that began on another volume. */
|
||||
#define GNUTYPE_MULTIVOL 'M'
|
||||
|
||||
/* For storing filenames that do not fit into the main header. */
|
||||
#define GNUTYPE_NAMES 'N'
|
||||
|
||||
/* This is for sparse files. */
|
||||
#define GNUTYPE_SPARSE 'S'
|
||||
|
||||
@@ -320,5 +318,3 @@ union block
|
||||
struct star_in_header star_in_header;
|
||||
struct star_ext_header star_ext_header;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
|
||||
case 'f':
|
||||
if (st)
|
||||
{
|
||||
base = base_name (st->orig_file_name);
|
||||
base = last_component (st->orig_file_name);
|
||||
len += strlen (base) - 2;
|
||||
}
|
||||
break;
|
||||
@@ -647,12 +647,10 @@ void
|
||||
xheader_read (union block *p, size_t size)
|
||||
{
|
||||
size_t j = 0;
|
||||
size_t nblocks;
|
||||
|
||||
free (extended_header.buffer);
|
||||
size += BLOCKSIZE;
|
||||
extended_header.size = size;
|
||||
nblocks = (size + BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
extended_header.buffer = xmalloc (size + 1);
|
||||
extended_header.buffer[size] = '\0';
|
||||
|
||||
@@ -1094,9 +1092,10 @@ ctime_decoder (struct tar_stat_info *st,
|
||||
|
||||
static void
|
||||
mtime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void const *data __attribute__ ((unused)))
|
||||
struct xheader *xhdr, void const *data)
|
||||
{
|
||||
code_time (st->mtime, keyword, xhdr);
|
||||
const struct timespec mtime = data ? *(struct timespec *) data : st->mtime;
|
||||
code_time (mtime, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -46,6 +46,8 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||
## ------------ ##
|
||||
|
||||
TESTSUITE_AT = \
|
||||
T-empty.at\
|
||||
T-null.at\
|
||||
testsuite.at\
|
||||
append.at\
|
||||
append01.at\
|
||||
@@ -63,6 +65,7 @@ TESTSUITE_AT = \
|
||||
extrac04.at\
|
||||
extrac05.at\
|
||||
extrac06.at\
|
||||
extrac07.at\
|
||||
gzip.at\
|
||||
grow.at\
|
||||
incremental.at\
|
||||
|
||||
52
tests/T-empty.at
Normal file
52
tests/T-empty.at
Normal file
@@ -0,0 +1,52 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Tar 1.16 coredumped if a filelist file contained empty (zero-length)
|
||||
# entries
|
||||
# Reported by: Karl Berry <karl@freefriends.org>
|
||||
# References: <200610301353.k9UDr1O30680@f7.net>
|
||||
|
||||
AT_SETUP([files-from: empty entries])
|
||||
AT_KEYWORDS([files-from empty])
|
||||
|
||||
AT_DATA([file-list],
|
||||
[jeden
|
||||
dwa
|
||||
|
||||
trzy
|
||||
])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
genfile --file jeden
|
||||
genfile --file dwa
|
||||
genfile --file trzy
|
||||
|
||||
tar cfvT archive ../file-list | sort
|
||||
],
|
||||
[0],
|
||||
[dwa
|
||||
jeden
|
||||
trzy
|
||||
],
|
||||
[],[],[],[ustar]) # Testing one format is enough
|
||||
|
||||
AT_CLEANUP
|
||||
46
tests/T-null.at
Normal file
46
tests/T-null.at
Normal file
@@ -0,0 +1,46 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
AT_SETUP([files-from: 0-separated file without -0])
|
||||
AT_KEYWORDS([files-from null])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
echo dwa > temp
|
||||
echo trzy >> temp
|
||||
cat temp | tr '\n' '\0' > temp1
|
||||
echo jeden > file-list
|
||||
cat temp1 >> file-list
|
||||
|
||||
genfile -f "jeden
|
||||
dwa"
|
||||
genfile -f trzy
|
||||
|
||||
tar cfTv archive file-list | sort
|
||||
],
|
||||
[0],
|
||||
[jeden\ndwa
|
||||
trzy
|
||||
],
|
||||
[tar: file-list: file name read contains nul character
|
||||
],[],[ustar]) # Testing one format is enough
|
||||
|
||||
AT_CLEANUP
|
||||
@@ -44,19 +44,22 @@ AT_TAR_CHECK([
|
||||
genfile --file file1
|
||||
genfile --file file2
|
||||
|
||||
# Make sure file timestamps in the archive will not differ
|
||||
MTIME="--mtime=@0"
|
||||
|
||||
# For PAX archives, we need to make sure extended header names are
|
||||
# reproducible.
|
||||
# reproducible and that their contents won't change with time
|
||||
if test $[]TEST_TAR_FORMAT = posix; then
|
||||
TAR_OPTIONS="$TAR_OPTIONS --pax-option=exthdr.name=%d/PaxHeaders/%f"
|
||||
TAR_OPTIONS="$TAR_OPTIONS --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=mtime,delete=atime,delete=ctime"
|
||||
fi
|
||||
|
||||
echo Creating archive.1
|
||||
tar cf archive.1 file1 file2
|
||||
tar $MTIME -cf archive.1 file1 file2
|
||||
|
||||
echo Creating archive.2
|
||||
tar cfT archive.2 /dev/null
|
||||
tar rf archive.2 file1
|
||||
tar rf archive.2 file2
|
||||
tar $MTIME -cf archive.2 -T /dev/null
|
||||
tar $MTIME -rf archive.2 file1
|
||||
tar $MTIME -rf archive.2 file2
|
||||
|
||||
echo Comparing archives
|
||||
cmp archive.1 archive.2
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2006 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,7 +21,7 @@
|
||||
# Could not extract symlinks over an existing file.
|
||||
|
||||
AT_SETUP([extracting symlinks over an existing file])
|
||||
AT_KEYWORDS([extract extract02])
|
||||
AT_KEYWORDS([extract extract02 symlink])
|
||||
|
||||
# FIXME: Skip if symlinks are not supported on the system
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
# Check for fnmatch problems in glibc 2.1.95.
|
||||
|
||||
AT_SETUP([extract + fnmatch])
|
||||
AT_KEYWORDS([extract extract04])
|
||||
AT_KEYWORDS([extract extract04 fnmatch])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
AT_SORT_PREREQ
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#
|
||||
|
||||
AT_SETUP([mode of extracted directories])
|
||||
AT_KEYWORDS([extract extract06])
|
||||
AT_KEYWORDS([extract extract06 directory mode])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
|
||||
|
||||
56
tests/extrac07.at
Normal file
56
tests/extrac07.at
Normal file
@@ -0,0 +1,56 @@
|
||||
# Process this file with autom4te to create testsuite. -*- Autotest -*-
|
||||
|
||||
# Test suite for GNU tar.
|
||||
# Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
|
||||
# Tar 1.16 failed to extract archives that have symlinks
|
||||
# in read-only directories.
|
||||
#
|
||||
# Reported-by: Eelco Dolstra <eelco@cs.uu.nl>
|
||||
# References: <45475D78.8050708@cs.uu.nl>
|
||||
|
||||
AT_SETUP([extracting symlinks to a read-only dir])
|
||||
AT_KEYWORDS([extract extract07 read-only symlink])
|
||||
|
||||
AT_TAR_CHECK([
|
||||
echo Prepare the directory
|
||||
mkdir dir
|
||||
genfile -f foo
|
||||
cd dir
|
||||
ln -s ../foo .
|
||||
cd ..
|
||||
chmod -w dir
|
||||
|
||||
echo Create the archive
|
||||
tar cf archive dir || exit 1
|
||||
|
||||
echo Extract
|
||||
mkdir out
|
||||
tar -C out -xvf archive
|
||||
],
|
||||
[0],
|
||||
[Prepare the directory
|
||||
Create the archive
|
||||
Extract
|
||||
dir/
|
||||
dir/foo
|
||||
],[],[],[ustar]) # Testing one format is enough
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ AT_KEYWORDS([shortrec.at])
|
||||
AT_TAR_CHECK([
|
||||
mkdir directory
|
||||
(cd directory && touch a b c d e f g h i j k l m n o p q r)
|
||||
tar -c -b 1 directory | tar -t -f - >/dev/null
|
||||
tar -c -b 1 -f - directory | tar -t -f - >/dev/null
|
||||
tar -c -b 1 -f archive directory
|
||||
tar -t -f archive >/dev/null
|
||||
tar -t -f - < archive >/dev/null
|
||||
|
||||
@@ -100,6 +100,9 @@ m4_include([pipe.at])
|
||||
m4_include([options.at])
|
||||
m4_include([options02.at])
|
||||
|
||||
m4_include([T-empty.at])
|
||||
m4_include([T-null.at])
|
||||
|
||||
m4_include([indexfile.at])
|
||||
m4_include([verbose.at])
|
||||
|
||||
@@ -119,6 +122,7 @@ m4_include([extrac03.at])
|
||||
m4_include([extrac04.at])
|
||||
m4_include([extrac05.at])
|
||||
m4_include([extrac06.at])
|
||||
m4_include([extrac07.at])
|
||||
|
||||
m4_include([gzip.at])
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ genfile --run 'tar -vcf bar foo baz' --checkpoint 10 --length 49995k --truncate
|
||||
echo Exit status: $?
|
||||
echo separator
|
||||
sleep 1
|
||||
dd if=/dev/zero of=foo bs=1k seek=49995 count=5 >/dev/null 2>&1
|
||||
genfile --file foo --seek 49995k --length 5k --pattern=zeros
|
||||
tar dvf bar],
|
||||
[1],
|
||||
[foo
|
||||
|
||||
Reference in New Issue
Block a user