diff options
| author | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2008-06-08 11:04:43 +0200 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2008-06-08 11:04:43 +0200 |
| commit | 16f738ecee689c6feb2acb7e4ef4d9bb4144ae7d (patch) | |
| tree | 3d22f54f7298f81b18ed66d05a62fa8bfab359ab /libarchive/libarchive-2.4.17/tar | |
| download | tuxcmd-modules-16f738ecee689c6feb2acb7e4ef4d9bb4144ae7d.tar.xz | |
Initial commitv0.6.36release-0.6.36-dev
Diffstat (limited to 'libarchive/libarchive-2.4.17/tar')
28 files changed, 10092 insertions, 0 deletions
diff --git a/libarchive/libarchive-2.4.17/tar/bsdtar.1 b/libarchive/libarchive-2.4.17/tar/bsdtar.1 new file mode 100644 index 0000000..ec22160 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/bsdtar.1 @@ -0,0 +1,760 @@ +.\" Copyright (c) 2003-2007 Tim Kientzle +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.37 2008/01/22 07:23:44 kientzle Exp $ +.\" +.Dd April 13, 2004 +.Dt BSDTAR 1 +.Os +.Sh NAME +.Nm tar +.Nd manipulate tape archives +.Sh SYNOPSIS +.Nm +.Op Ar bundled-flags Ao args Ac +.Op Ao Ar file Ac | Ao Ar pattern Ac ... +.Nm +.Brq Fl c +.Op Ar options +.Op Ar files | directories +.Nm +.Brq Fl r | Fl u +.Fl f Ar archive-file +.Op Ar options +.Op Ar files | directories +.Nm +.Brq Fl t | Fl x +.Op Ar options +.Op Ar patterns +.Sh DESCRIPTION +.Nm +creates and manipulates streaming archive files. +This implementation can extract from tar, pax, cpio, zip, jar, ar, +and ISO 9660 cdrom images and can create tar, pax, cpio, ar, +and shar archives. +.Pp +The first synopsis form shows a +.Dq bundled +option word. +This usage is provided for compatibility with historical implementations. +See COMPATIBILITY below for details. +.Pp +The other synopsis forms show the preferred usage. +The first option to +.Nm +is a mode indicator from the following list: +.Bl -tag -compact -width indent +.It Fl c +Create a new archive containing the specified items. +.It Fl r +Like +.Fl c , +but new entries are appended to the archive. +Note that this only works on uncompressed archives stored in regular files. +The +.Fl f +option is required. +.It Fl t +List archive contents to stdout. +.It Fl u +Like +.Fl r , +but new entries are added only if they have a modification date +newer than the corresponding entry in the archive. +Note that this only works on uncompressed archives stored in regular files. +The +.Fl f +option is required. +.It Fl x +Extract to disk from the archive. +If a file with the same name appears more than once in the archive, +each copy will be extracted, with later copies overwriting (replacing) +earlier copies. +.El +.Pp +In +.Fl c , +.Fl r , +or +.Fl u +mode, each specified file or directory is added to the +archive in the order specified on the command line. +By default, the contents of each directory are also archived. +.Pp +In extract or list mode, the entire command line +is read and parsed before the archive is opened. +The pathnames or patterns on the command line indicate +which items in the archive should be processed. +Patterns are shell-style globbing patterns as +documented in +.Xr tcsh 1 . +.Sh OPTIONS +Unless specifically stated otherwise, options are applicable in +all operating modes. +.Bl -tag -width indent +.It Cm @ Ns Pa archive +(c and r mode only) +The specified archive is opened and the entries +in it will be appended to the current archive. +As a simple example, +.Dl Nm Fl c Fl f Pa - Pa newfile Cm @ Ns Pa original.tar +writes a new archive to standard output containing a file +.Pa newfile +and all of the entries from +.Pa original.tar . +In contrast, +.Dl Nm Fl c Fl f Pa - Pa newfile Pa original.tar +creates a new archive with only two entries. +Similarly, +.Dl Nm Fl czf Pa - Fl -format Cm pax Cm @ Ns Pa - +reads an archive from standard input (whose format will be determined +automatically) and converts it into a gzip-compressed +pax-format archive on stdout. +In this way, +.Nm +can be used to convert archives from one format to another. +.It Fl b Ar blocksize +Specify the block size, in 512-byte records, for tape drive I/O. +As a rule, this argument is only needed when reading from or writing +to tape drives, and usually not even then as the default block size of +20 records (10240 bytes) is very common. +.It Fl C Ar directory +In c and r mode, this changes the directory before adding +the following files. +In x mode, change directories after opening the archive +but before extracting entries from the archive. +.It Fl -check-links ( Fl W Cm check-links ) +(c and r modes only) +Issue a warning message unless all links to each file are archived. +.It Fl -exclude Ar pattern ( Fl W Cm exclude Ns = Ns Ar pattern ) +Do not process files or directories that match the +specified pattern. +Note that exclusions take precedence over patterns or filenames +specified on the command line. +.It Fl -format Ar format ( Fl W Cm format Ns = Ns Ar format ) +(c mode only) +Use the specified format for the created archive. +Supported formats include +.Dq cpio , +.Dq pax , +.Dq shar , +and +.Dq ustar . +Other formats may also be supported; see +.Xr libarchive-formats 5 +for more information about currently-supported formats. +.It Fl f Ar file +Read the archive from or write the archive to the specified file. +The filename can be +.Pa - +for standard input or standard output. +If not specified, the default tape device will be used. +(On +.Fx , +the default tape device is +.Pa /dev/sa0 . ) +.It Fl -fast-read ( Fl W Cm fast-read ) +(x and t mode only) +Extract or list only the first archive entry that matches each pattern +or filename operand. +Exit as soon as each specified pattern or filename has been matched. +By default, the archive is always read to the very end, since +there can be multiple entries with the same name and, by convention, +later entries overwrite earlier entries. +This option is provided as a performance optimization. +.It Fl H +(c and r mode only) +Symbolic links named on the command line will be followed; the +target of the link will be archived, not the link itself. +.It Fl h +(c and r mode only) +Synonym for +.Fl L . +.It Fl I +Synonym for +.Fl T . +.It Fl -include Ar pattern ( Fl W Cm include Ns = Ns Ar pattern ) +Process only files or directories that match the specified pattern. +Note that exclusions specified with +.Fl -exclude +take precedence over inclusions. +If no inclusions are explicitly specified, all entries are processed by +default. +The +.Fl -include +option is especially useful when filtering archives. +For example, the command +.Dl Nm Fl c Fl f Pa new.tar Fl -include='*foo*' Cm @ Ns Pa old.tgz +creates a new archive +.Pa new.tar +containing only the entries from +.Pa old.tgz +containing the string +.Sq foo . +.It Fl j +(c mode only) +Compress the resulting archive with +.Xr bzip2 1 . +In extract or list modes, this option is ignored. +Note that, unlike other +.Nm tar +implementations, this implementation recognizes bzip2 compression +automatically when reading archives. +.It Fl k +(x mode only) +Do not overwrite existing files. +In particular, if a file appears more than once in an archive, +later copies will not overwrite earlier copies. +.It Fl L +(c and r mode only) +All symbolic links will be followed. +Normally, symbolic links are archived as such. +With this option, the target of the link will be archived instead. +.It Fl l +This is a synonym for the +.Fl -check-links +option. +.It Fl m +(x mode only) +Do not extract modification time. +By default, the modification time is set to the time stored in the archive. +.It Fl n +(c, r, u modes only) +Do not recursively archive the contents of directories. +.It Fl -newer Ar date ( Fl W Cm newer Ns = Ns Ar date ) +(c, r, u modes only) +Only include files and directories newer than the specified date. +This compares ctime entries. +.It Fl -newer-mtime Ar date ( Fl W Cm newer-mtime Ns = Ns Ar date ) +(c, r, u modes only) +Like +.Fl -newer , +except it compares mtime entries instead of ctime entries. +.It Fl -newer-than Pa file ( Fl W Cm newer-than Ns = Ns Pa file ) +(c, r, u modes only) +Only include files and directories newer than the specified file. +This compares ctime entries. +.It Fl -newer-mtime-than Pa file ( Fl W Cm newer-mtime-than Ns = Ns Pa file ) +(c, r, u modes only) +Like +.Fl -newer-than , +except it compares mtime entries instead of ctime entries. +.It Fl -nodump ( Fl W Cm nodump ) +(c and r modes only) +Honor the nodump file flag by skipping this file. +.It Fl -null ( Fl W Cm null ) +(use with +.Fl I , +.Fl T , +or +.Fl X ) +Filenames or patterns are separated by null characters, +not by newlines. +This is often used to read filenames output by the +.Fl print0 +option to +.Xr find 1 . +.It Fl O +(x, t modes only) +In extract (-x) mode, files will be written to standard out rather than +being extracted to disk. +In list (-t) mode, the file listing will be written to stderr rather than +the usual stdout. +.It Fl o +(x mode only) +Use the user and group of the user running the program rather +than those specified in the archive. +Note that this has no significance unless +.Fl p +is specified, and the program is being run by the root user. +In this case, the file modes and flags from +the archive will be restored, but ACLs or owner information in +the archive will be discarded. +.It Fl -one-file-system ( Fl W Cm one-file-system ) +(c, r, and u modes) +Do not cross mount points. +.It Fl P +Preserve pathnames. +By default, absolute pathnames (those that begin with a / +character) have the leading slash removed both when creating archives +and extracting from them. +Also, +.Nm +will refuse to extract archive entries whose pathnames contain +.Pa .. +or whose target directory would be altered by a symlink. +This option suppresses these behaviors. +.It Fl p +(x mode only) +Preserve file permissions. +Attempt to restore the full permissions, including owner, file modes, file +flags and ACLs, if available, for each item extracted from the archive. +By default, newly-created files are owned by the user running +.Nm , +the file mode is restored for newly-created regular files, and +all other types of entries receive default permissions. +If +.Nm +is being run by root, the default is to restore the owner unless the +.Fl o +option is also specified. +.It Fl -strip-components Ar count ( Fl W Cm strip-components Ns = Ns Ar count ) +(x and t mode only) +Remove the specified number of leading path elements. +Pathnames with fewer elements will be silently skipped. +Note that the pathname is edited after checking inclusion/exclusion patterns +but before security checks. +.It Fl T Ar filename +In x or t mode, +.Nm +will read the list of names to be extracted from +.Pa filename . +In c mode, +.Nm +will read names to be archived from +.Pa filename . +The special name +.Dq -C +on a line by itself will cause the current directory to be changed to +the directory specified on the following line. +Names are terminated by newlines unless +.Fl -null +is specified. +Note that +.Fl -null +also disables the special handling of lines containing +.Dq -C . +.It Fl U +(x mode only) +Unlink files before creating them. +Without this option, +.Nm +overwrites existing files, which preserves existing hardlinks. +With this option, existing hardlinks will be broken, as will any +symlink that would affect the location of an extracted file. +.It Fl -use-compress-program Ar program +Pipe the input (in x or t mode) or the output (in c mode) through +.Pa program +instead of using the builtin compression support. +.It Fl v +Produce verbose output. +In create and extract modes, +.Nm +will list each file name as it is read from or written to +the archive. +In list mode, +.Nm +will produce output similar to that of +.Xr ls 1 . +Additional +.Fl v +options will provide additional detail. +.It Fl W Ar longopt=value +Long options (preceded by +.Fl - ) +are only supported directly on systems that have the +.Xr getopt_long 3 +function. +The +.Fl W +option can be used to access long options on systems that +do not support this function. +.It Fl w +Ask for confirmation for every action. +.It Fl X Ar filename +Read a list of exclusion patterns from the specified file. +See +.Fl -exclude +for more information about the handling of exclusions. +.It Fl y +(c mode only) +Compress the resulting archive with +.Xr bzip2 1 . +In extract or list modes, this option is ignored. +Note that, unlike other +.Nm tar +implementations, this implementation recognizes bzip2 compression +automatically when reading archives. +.It Fl z +(c mode only) +Compress the resulting archive with +.Xr gzip 1 . +In extract or list modes, this option is ignored. +Note that, unlike other +.Nm tar +implementations, this implementation recognizes gzip compression +automatically when reading archives. +.El +.Sh ENVIRONMENT +The following environment variables affect the execution of +.Nm : +.Bl -tag -width ".Ev BLOCKSIZE" +.It Ev LANG +The locale to use. +See +.Xr environ 7 +for more information. +.It Ev TAPE +The default tape device. +The +.Fl f +option overrides this. +.It Ev TZ +The timezone to use when displaying dates. +See +.Xr environ 7 +for more information. +.El +.Sh FILES +.Bl -tag -width ".Ev BLOCKSIZE" +.It Pa /dev/sa0 +The default tape device, if not overridden by the +.Ev TAPE +environment variable or the +.Fl f +option. +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +The following creates a new archive +called +.Ar file.tar.gz +that contains two files +.Ar source.c +and +.Ar source.h : +.Dl Nm Fl czf Pa file.tar.gz Pa source.c Pa source.h +.Pp +To view a detailed table of contents for this +archive: +.Dl Nm Fl tvf Pa file.tar.gz +.Pp +To extract all entries from the archive on +the default tape drive: +.Dl Nm Fl x +.Pp +To examine the contents of an ISO 9660 cdrom image: +.Dl Nm Fl tf Pa image.iso +.Pp +To move file hierarchies, invoke +.Nm +as +.Dl Nm Fl cf Pa - Fl C Pa srcdir\ . | Nm Fl xpf Pa - Fl C Pa destdir +or more traditionally +.Dl cd srcdir \&; Nm Fl cf Pa -\ . | ( cd destdir \&; Nm Fl xpf Pa - ) +.Pp +In create mode, the list of files and directories to be archived +can also include directory change instructions of the form +.Cm -C Ns Pa foo/baz +and archive inclusions of the form +.Cm @ Ns Pa archive-file . +For example, the command line +.Dl Nm Fl c Fl f Pa new.tar Pa foo1 Cm @ Ns Pa old.tgz Cm -C Ns Pa /tmp Pa foo2 +will create a new archive +.Pa new.tar . +.Nm +will read the file +.Pa foo1 +from the current directory and add it to the output archive. +It will then read each entry from +.Pa old.tgz +and add those entries to the output archive. +Finally, it will switch to the +.Pa /tmp +directory and add +.Pa foo2 +to the output archive. +.Pp +The +.Fl -newer +and +.Fl -newer-mtime +switches accept a variety of common date and time specifications, including +.Dq 12 Mar 2005 7:14:29pm , +.Dq 2005-03-12 19:14 , +.Dq 5 minutes ago , +and +.Dq 19:14 PST May 1 . +.Sh COMPATIBILITY +The bundled-arguments format is supported for compatibility +with historic implementations. +It consists of an initial word (with no leading - character) in which +each character indicates an option. +Arguments follow as separate words. +The order of the arguments must match the order +of the corresponding characters in the bundled command word. +For example, +.Dl Nm Cm tbf 32 Pa file.tar +specifies three flags +.Cm t , +.Cm b , +and +.Cm f . +The +.Cm b +and +.Cm f +flags both require arguments, +so there must be two additional items +on the command line. +The +.Ar 32 +is the argument to the +.Cm b +flag, and +.Ar file.tar +is the argument to the +.Cm f +flag. +.Pp +The mode options c, r, t, u, and x and the options +b, f, l, m, o, v, and w comply with SUSv2. +.Pp +For maximum portability, scripts that invoke +.Nm tar +should use the bundled-argument format above, should limit +themselves to the +.Cm c , +.Cm t , +and +.Cm x +modes, and the +.Cm b , +.Cm f , +.Cm m , +.Cm v , +and +.Cm w +options. +.Pp +On systems that support getopt_long(), additional long options +are available to improve compatibility with other tar implementations. +.Sh SECURITY +Certain security issues are common to many archiving programs, including +.Nm . +In particular, carefully-crafted archives can request that +.Nm +extract files to locations outside of the target directory. +This can potentially be used to cause unwitting users to overwrite +files they did not intend to overwrite. +If the archive is being extracted by the superuser, any file +on the system can potentially be overwritten. +There are three ways this can happen. +Although +.Nm +has mechanisms to protect against each one, +savvy users should be aware of the implications: +.Bl -bullet -width indent +.It +Archive entries can have absolute pathnames. +By default, +.Nm +removes the leading +.Pa / +character from filenames before restoring them to guard against this problem. +.It +Archive entries can have pathnames that include +.Pa .. +components. +By default, +.Nm +will not extract files containing +.Pa .. +components in their pathname. +.It +Archive entries can exploit symbolic links to restore +files to other directories. +An archive can restore a symbolic link to another directory, +then use that link to restore a file into that directory. +To guard against this, +.Nm +checks each extracted path for symlinks. +If the final path element is a symlink, it will be removed +and replaced with the archive entry. +If +.Fl U +is specified, any intermediate symlink will also be unconditionally removed. +If neither +.Fl U +nor +.Fl P +is specified, +.Nm +will refuse to extract the entry. +.El +To protect yourself, you should be wary of any archives that +come from untrusted sources. +You should examine the contents of an archive with +.Dl Nm Fl tf Pa filename +before extraction. +You should use the +.Fl k +option to ensure that +.Nm +will not overwrite any existing files or the +.Fl U +option to remove any pre-existing files. +You should generally not extract archives while running with super-user +privileges. +Note that the +.Fl P +option to +.Nm +disables the security checks above and allows you to extract +an archive while preserving any absolute pathnames, +.Pa .. +components, or symlinks to other directories. +.Sh SEE ALSO +.Xr bzip2 1 , +.Xr cpio 1 , +.Xr gzip 1 , +.Xr mt 1 , +.Xr pax 1 , +.Xr shar 1 , +.Xr libarchive 3 , +.Xr libarchive-formats 5 , +.Xr tar 5 +.Sh STANDARDS +There is no current POSIX standard for the tar command; it appeared +in +.St -p1003.1-96 +but was dropped from +.St -p1003.1-2001 . +The options used by this implementation were developed by surveying a +number of existing tar implementations as well as the old POSIX specification +for tar and the current POSIX specification for pax. +.Pp +The ustar and pax interchange file formats are defined by +.St -p1003.1-2001 +for the pax command. +.Sh HISTORY +A +.Nm tar +command appeared in Seventh Edition Unix, which was released in January, 1979. +There have been numerous other implementations, +many of which extended the file format. +John Gilmore's +.Nm pdtar +public-domain implementation (circa November, 1987) +was quite influential, and formed the basis of GNU tar. +GNU tar was included as the standard system tar +in +.Fx +beginning with +.Fx 1.0 . +.Pp +This is a complete re-implementation based on the +.Xr libarchive 3 +library. +.Sh BUGS +This program follows +.St -p1003.1-96 +for the definition of the +.Fl l +option. +Note that GNU tar prior to version 1.15 treated +.Fl l +as a synonym for the +.Fl -one-file-system +option. +.Pp +The +.Fl C Pa dir +option may differ from historic implementations. +.Pp +All archive output is written in correctly-sized blocks, even +if the output is being compressed. +Whether or not the last output block is padded to a full +block size varies depending on the format and the +output device. +For tar and cpio formats, the last block of output is padded +to a full block size if the output is being +written to standard output or to a character or block device such as +a tape drive. +If the output is being written to a regular file, the last block +will not be padded. +Many compressors, including +.Xr gzip 1 +and +.Xr bzip2 1 , +complain about the null padding when decompressing an archive created by +.Nm , +although they still extract it correctly. +.Pp +The compression and decompression is implemented internally, so +there may be insignificant differences between the compressed output +generated by +.Dl Nm Fl czf Pa - file +and that generated by +.Dl Nm Fl cf Pa - file | Nm gzip +.Pp +The default should be to read and write archives to the standard I/O paths, +but tradition (and POSIX) dictates otherwise. +.Pp +The +.Cm r +and +.Cm u +modes require that the archive be uncompressed +and located in a regular file on disk. +Other archives can be modified using +.Cm c +mode with the +.Pa @archive-file +extension. +.Pp +To archive a file called +.Pa @foo +or +.Pa -foo +you must specify it as +.Pa ./@foo +or +.Pa ./-foo , +respectively. +.Pp +In create mode, a leading +.Pa ./ +is always removed. +A leading +.Pa / +is stripped unless the +.Fl P +option is specified. +.Pp +There needs to be better support for file selection on both create +and extract. +.Pp +There is not yet any support for multi-volume archives or for archiving +sparse files. +.Pp +Converting between dissimilar archive formats (such as tar and cpio) using the +.Cm @ Ns Pa - +convention can cause hard link information to be lost. +(This is a consequence of the incompatible ways that different archive +formats store hardlink information.) +.Pp +There are alternative long options for many of the short options that +are deliberately not documented. diff --git a/libarchive/libarchive-2.4.17/tar/bsdtar.c b/libarchive/libarchive-2.4.17/tar/bsdtar.c new file mode 100644 index 0000000..fbc66c1 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/bsdtar.c @@ -0,0 +1,931 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bsdtar_platform.h" +__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.79 2008/01/22 07:23:44 kientzle Exp $"); + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_GETOPT_LONG +#include <getopt.h> +#else +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; +#define no_argument 0 +#define required_argument 1 +#endif +#ifdef HAVE_LANGINFO_H +#include <langinfo.h> +#endif +#ifdef HAVE_LOCALE_H +#include <locale.h> +#endif +#ifdef HAVE_PATHS_H +#include <paths.h> +#endif +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_ZLIB_H +#include <zlib.h> +#endif + +#include "bsdtar.h" + +#if !HAVE_DECL_OPTARG +extern int optarg; +#endif + +#if !HAVE_DECL_OPTIND +extern int optind; +#endif + +/* + * Per POSIX.1-1988, tar defaults to reading/writing archives to/from + * the default tape device for the system. Pick something reasonable here. + */ +#ifdef __linux +#define _PATH_DEFTAPE "/dev/st0" +#endif + +#ifndef _PATH_DEFTAPE +#define _PATH_DEFTAPE "/dev/tape" +#endif + +/* External function to parse a date/time string (from getdate.y) */ +time_t get_date(const char *); + +static int bsdtar_getopt(struct bsdtar *, const char *optstring, + const struct option **poption); +static void long_help(struct bsdtar *); +static void only_mode(struct bsdtar *, const char *opt, + const char *valid); +static char ** rewrite_argv(struct bsdtar *, + int *argc, char ** src_argv, + const char *optstring); +static void set_mode(struct bsdtar *, char opt); +static void version(void); + +/* + * The leading '+' here forces the GNU version of getopt() (as well as + * both the GNU and BSD versions of getopt_long) to stop at the first + * non-option. Otherwise, GNU getopt() permutes the arguments and + * screws up -C processing. + */ +static const char *tar_opts = "+Bb:C:cf:HhI:jkLlmnOoPprtT:UuvW:wX:xyZz"; + +/* + * Most of these long options are deliberately not documented. They + * are provided only to make life easier for people who also use GNU tar. + * The only long options documented in the manual page are the ones + * with no corresponding short option, such as --exclude, --nodump, + * and --fast-read. + * + * On systems that lack getopt_long, long options can be specified + * using -W longopt and -W longopt=value, e.g. "-W nodump" is the same + * as "--nodump" and "-W exclude=pattern" is the same as "--exclude + * pattern". This does not rely the GNU getopt() "W;" extension, so + * should work correctly on any system with a POSIX-compliant getopt(). + */ + +/* Fake short equivalents for long options that otherwise lack them. */ +enum { + OPTION_CHECK_LINKS=1, + OPTION_EXCLUDE, + OPTION_FAST_READ, + OPTION_FORMAT, + OPTION_HELP, + OPTION_INCLUDE, + OPTION_NEWER_CTIME, + OPTION_NEWER_CTIME_THAN, + OPTION_NEWER_MTIME, + OPTION_NEWER_MTIME_THAN, + OPTION_NODUMP, + OPTION_NO_SAME_OWNER, + OPTION_NO_SAME_PERMISSIONS, + OPTION_NULL, + OPTION_ONE_FILE_SYSTEM, + OPTION_POSIX, + OPTION_STRIP_COMPONENTS, + OPTION_TOTALS, + OPTION_USE_COMPRESS_PROGRAM, + OPTION_VERSION +}; + +/* + * If you add anything, be very careful to keep this list properly + * sorted, as the -W logic relies on it. + */ +static const struct option tar_longopts[] = { + { "absolute-paths", no_argument, NULL, 'P' }, + { "append", no_argument, NULL, 'r' }, + { "block-size", required_argument, NULL, 'b' }, + { "bunzip2", no_argument, NULL, 'j' }, + { "bzip", no_argument, NULL, 'j' }, + { "bzip2", no_argument, NULL, 'j' }, + { "cd", required_argument, NULL, 'C' }, + { "check-links", no_argument, NULL, OPTION_CHECK_LINKS }, + { "confirmation", no_argument, NULL, 'w' }, + { "create", no_argument, NULL, 'c' }, + { "dereference", no_argument, NULL, 'L' }, + { "directory", required_argument, NULL, 'C' }, + { "exclude", required_argument, NULL, OPTION_EXCLUDE }, + { "exclude-from", required_argument, NULL, 'X' }, + { "extract", no_argument, NULL, 'x' }, + { "fast-read", no_argument, NULL, OPTION_FAST_READ }, + { "file", required_argument, NULL, 'f' }, + { "files-from", required_argument, NULL, 'T' }, + { "format", required_argument, NULL, OPTION_FORMAT }, + { "gunzip", no_argument, NULL, 'z' }, + { "gzip", no_argument, NULL, 'z' }, + { "help", no_argument, NULL, OPTION_HELP }, + { "include", required_argument, NULL, OPTION_INCLUDE }, + { "interactive", no_argument, NULL, 'w' }, + { "keep-old-files", no_argument, NULL, 'k' }, + { "list", no_argument, NULL, 't' }, + { "modification-time", no_argument, NULL, 'm' }, + { "newer", required_argument, NULL, OPTION_NEWER_CTIME }, + { "newer-ctime", required_argument, NULL, OPTION_NEWER_CTIME }, + { "newer-ctime-than", required_argument, NULL, OPTION_NEWER_CTIME_THAN }, + { "newer-mtime", required_argument, NULL, OPTION_NEWER_MTIME }, + { "newer-mtime-than", required_argument, NULL, OPTION_NEWER_MTIME_THAN }, + { "newer-than", required_argument, NULL, OPTION_NEWER_CTIME_THAN }, + { "nodump", no_argument, NULL, OPTION_NODUMP }, + { "norecurse", no_argument, NULL, 'n' }, + { "no-recursion", no_argument, NULL, 'n' }, + { "no-same-owner", no_argument, NULL, OPTION_NO_SAME_OWNER }, + { "no-same-permissions",no_argument, NULL, OPTION_NO_SAME_PERMISSIONS }, + { "null", no_argument, NULL, OPTION_NULL }, + { "one-file-system", no_argument, NULL, OPTION_ONE_FILE_SYSTEM }, + { "posix", no_argument, NULL, OPTION_POSIX }, + { "preserve-permissions", no_argument, NULL, 'p' }, + { "read-full-blocks", no_argument, NULL, 'B' }, + { "same-permissions", no_argument, NULL, 'p' }, + { "strip-components", required_argument, NULL, OPTION_STRIP_COMPONENTS }, + { "to-stdout", no_argument, NULL, 'O' }, + { "totals", no_argument, NULL, OPTION_TOTALS }, + { "unlink", no_argument, NULL, 'U' }, + { "unlink-first", no_argument, NULL, 'U' }, + { "update", no_argument, NULL, 'u' }, + { "use-compress-program", + required_argument, NULL, OPTION_USE_COMPRESS_PROGRAM }, + { "verbose", no_argument, NULL, 'v' }, + { "version", no_argument, NULL, OPTION_VERSION }, + { NULL, 0, NULL, 0 } +}; + +/* A basic set of security flags to request from libarchive. */ +#define SECURITY \ + (ARCHIVE_EXTRACT_SECURE_SYMLINKS \ + | ARCHIVE_EXTRACT_SECURE_NODOTDOT) + +int +main(int argc, char **argv) +{ + struct bsdtar *bsdtar, bsdtar_storage; + const struct option *option; + int opt, t; + char option_o; + char possible_help_request; + char buff[16]; + + /* + * Use a pointer for consistency, but stack-allocated storage + * for ease of cleanup. + */ + bsdtar = &bsdtar_storage; + memset(bsdtar, 0, sizeof(*bsdtar)); + bsdtar->fd = -1; /* Mark as "unused" */ + option_o = 0; + + /* Need bsdtar->progname before calling bsdtar_warnc. */ + if (*argv == NULL) + bsdtar->progname = "bsdtar"; + else { + bsdtar->progname = strrchr(*argv, '/'); + if (bsdtar->progname != NULL) + bsdtar->progname++; + else + bsdtar->progname = *argv; + } + + if (setlocale(LC_ALL, "") == NULL) + bsdtar_warnc(bsdtar, 0, "Failed to set default locale"); +#if defined(HAVE_NL_LANGINFO) && defined(HAVE_D_MD_ORDER) + bsdtar->day_first = (*nl_langinfo(D_MD_ORDER) == 'd'); +#endif + possible_help_request = 0; + + /* Look up uid of current user for future reference */ + bsdtar->user_uid = geteuid(); + + /* Default: open tape drive. */ + bsdtar->filename = getenv("TAPE"); + if (bsdtar->filename == NULL) + bsdtar->filename = _PATH_DEFTAPE; + + /* Default: preserve mod time on extract */ + bsdtar->extract_flags = ARCHIVE_EXTRACT_TIME; + + /* Default: Perform basic security checks. */ + bsdtar->extract_flags |= SECURITY; + + /* Defaults for root user: */ + if (bsdtar->user_uid == 0) { + /* --same-owner */ + bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER; + /* -p */ + bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; + bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; + bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; + bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; + } + + /* Rewrite traditional-style tar arguments, if used. */ + argv = rewrite_argv(bsdtar, &argc, argv, tar_opts); + + bsdtar->argv = argv; + bsdtar->argc = argc; + + /* Process all remaining arguments now. */ + /* + * Comments following each option indicate where that option + * originated: SUSv2, POSIX, GNU tar, star, etc. If there's + * no such comment, then I don't know of anyone else who + * implements that option. + */ + while ((opt = bsdtar_getopt(bsdtar, tar_opts, &option)) != -1) { + switch (opt) { + case 'B': /* GNU tar */ + /* libarchive doesn't need this; just ignore it. */ + break; + case 'b': /* SUSv2 */ + t = atoi(optarg); + if (t <= 0 || t > 1024) + bsdtar_errc(bsdtar, 1, 0, + "Argument to -b is out of range (1..1024)"); + bsdtar->bytes_per_block = 512 * t; + break; + case 'C': /* GNU tar */ + set_chdir(bsdtar, optarg); + break; + case 'c': /* SUSv2 */ + set_mode(bsdtar, opt); + break; + case OPTION_CHECK_LINKS: /* GNU tar */ + bsdtar->option_warn_links = 1; + break; + case OPTION_EXCLUDE: /* GNU tar */ + if (exclude(bsdtar, optarg)) + bsdtar_errc(bsdtar, 1, 0, + "Couldn't exclude %s\n", optarg); + break; + case OPTION_FORMAT: /* GNU tar, others */ + bsdtar->create_format = optarg; + break; + case 'f': /* SUSv2 */ + bsdtar->filename = optarg; + if (strcmp(bsdtar->filename, "-") == 0) + bsdtar->filename = NULL; + break; + case OPTION_FAST_READ: /* GNU tar */ + bsdtar->option_fast_read = 1; + break; + case 'H': /* BSD convention */ + bsdtar->symlink_mode = 'H'; + break; + case 'h': /* Linux Standards Base, gtar; synonym for -L */ + bsdtar->symlink_mode = 'L'; + /* Hack: -h by itself is the "help" command. */ + possible_help_request = 1; + break; + case OPTION_HELP: /* GNU tar, others */ + long_help(bsdtar); + exit(0); + break; + case 'I': /* GNU tar */ + /* + * TODO: Allow 'names' to come from an archive, + * not just a text file. Design a good UI for + * allowing names and mode/owner to be read + * from an archive, with contents coming from + * disk. This can be used to "refresh" an + * archive or to design archives with special + * permissions without having to create those + * permissions on disk. + */ + bsdtar->names_from_file = optarg; + break; + case OPTION_INCLUDE: + /* + * Noone else has the @archive extension, so + * noone else needs this to filter entries + * when transforming archives. + */ + if (include(bsdtar, optarg)) + bsdtar_errc(bsdtar, 1, 0, + "Failed to add %s to inclusion list", + optarg); + break; + case 'j': /* GNU tar */ +#if HAVE_LIBBZ2 + if (bsdtar->create_compression != '\0') + bsdtar_errc(bsdtar, 1, 0, + "Can't specify both -%c and -%c", opt, + bsdtar->create_compression); + bsdtar->create_compression = opt; +#else + bsdtar_warnc(bsdtar, 0, "-j compression not supported by this version of bsdtar"); + usage(bsdtar); +#endif + break; + case 'k': /* GNU tar */ + bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE; + break; + case 'L': /* BSD convention */ + bsdtar->symlink_mode = 'L'; + break; + case 'l': /* SUSv2 and GNU tar beginning with 1.16 */ + /* GNU tar 1.13 used -l for --one-file-system */ + bsdtar->option_warn_links = 1; + break; + case 'm': /* SUSv2 */ + bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_TIME; + break; + case 'n': /* GNU tar */ + bsdtar->option_no_subdirs = 1; + break; + /* + * Selecting files by time: + * --newer-?time='date' Only files newer than 'date' + * --newer-?time-than='file' Only files newer than time + * on specified file (useful for incremental backups) + * TODO: Add corresponding "older" options to reverse these. + */ + case OPTION_NEWER_CTIME: /* GNU tar */ + bsdtar->newer_ctime_sec = get_date(optarg); + break; + case OPTION_NEWER_CTIME_THAN: + { + struct stat st; + if (stat(optarg, &st) != 0) + bsdtar_errc(bsdtar, 1, 0, + "Can't open file %s", optarg); + bsdtar->newer_ctime_sec = st.st_ctime; + bsdtar->newer_ctime_nsec = + ARCHIVE_STAT_CTIME_NANOS(&st); + } + break; + case OPTION_NEWER_MTIME: /* GNU tar */ + bsdtar->newer_mtime_sec = get_date(optarg); + break; + case OPTION_NEWER_MTIME_THAN: + { + struct stat st; + if (stat(optarg, &st) != 0) + bsdtar_errc(bsdtar, 1, 0, + "Can't open file %s", optarg); + bsdtar->newer_mtime_sec = st.st_mtime; + bsdtar->newer_mtime_nsec = + ARCHIVE_STAT_MTIME_NANOS(&st); + } + break; + case OPTION_NODUMP: /* star */ + bsdtar->option_honor_nodump = 1; + break; + case OPTION_NO_SAME_OWNER: /* GNU tar */ + bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; + break; + case OPTION_NO_SAME_PERMISSIONS: /* GNU tar */ + bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_PERM; + bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_ACL; + bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_XATTR; + bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_FFLAGS; + break; + case OPTION_NULL: /* GNU tar */ + bsdtar->option_null++; + break; + case 'O': /* GNU tar */ + bsdtar->option_stdout = 1; + break; + case 'o': /* SUSv2 and GNU conflict here, but not fatally */ + option_o = 1; /* Record it and resolve it later. */ + break; + case OPTION_ONE_FILE_SYSTEM: /* GNU tar */ + bsdtar->option_dont_traverse_mounts = 1; + break; +#if 0 + /* + * The common BSD -P option is not necessary, since + * our default is to archive symlinks, not follow + * them. This is convenient, as -P conflicts with GNU + * tar anyway. + */ + case 'P': /* BSD convention */ + /* Default behavior, no option necessary. */ + break; +#endif + case 'P': /* GNU tar */ + bsdtar->extract_flags &= ~SECURITY; + bsdtar->option_absolute_paths = 1; + break; + case 'p': /* GNU tar, star */ + bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; + bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; + bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; + bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; + break; + case OPTION_POSIX: /* GNU tar */ + bsdtar->create_format = "pax"; + break; + case 'r': /* SUSv2 */ + set_mode(bsdtar, opt); + break; + case OPTION_STRIP_COMPONENTS: /* GNU tar 1.15 */ + bsdtar->strip_components = atoi(optarg); + break; + case 'T': /* GNU tar */ + bsdtar->names_from_file = optarg; + break; + case 't': /* SUSv2 */ + set_mode(bsdtar, opt); + bsdtar->verbose++; + break; + case OPTION_TOTALS: /* GNU tar */ + bsdtar->option_totals++; + break; + case 'U': /* GNU tar */ + bsdtar->extract_flags |= ARCHIVE_EXTRACT_UNLINK; + bsdtar->option_unlink_first = 1; + break; + case 'u': /* SUSv2 */ + set_mode(bsdtar, opt); + break; + case 'v': /* SUSv2 */ + bsdtar->verbose++; + break; + case OPTION_VERSION: /* GNU convention */ + version(); + break; +#if 0 + /* + * The -W longopt feature is handled inside of + * bsdtar_getop(), so -W is not available here. + */ + case 'W': /* Obscure, but useful GNU convention. */ + break; +#endif + case 'w': /* SUSv2 */ + bsdtar->option_interactive = 1; + break; + case 'X': /* GNU tar */ + if (exclude_from_file(bsdtar, optarg)) + bsdtar_errc(bsdtar, 1, 0, + "failed to process exclusions from file %s", + optarg); + break; + case 'x': /* SUSv2 */ + set_mode(bsdtar, opt); + break; + case 'y': /* FreeBSD version of GNU tar */ +#if HAVE_LIBBZ2 + if (bsdtar->create_compression != '\0') + bsdtar_errc(bsdtar, 1, 0, + "Can't specify both -%c and -%c", opt, + bsdtar->create_compression); + bsdtar->create_compression = opt; +#else + bsdtar_warnc(bsdtar, 0, "-y compression not supported by this version of bsdtar"); + usage(bsdtar); +#endif + break; + case 'Z': /* GNU tar */ + if (bsdtar->create_compression != '\0') + bsdtar_errc(bsdtar, 1, 0, + "Can't specify both -%c and -%c", opt, + bsdtar->create_compression); + bsdtar->create_compression = opt; + break; + case 'z': /* GNU tar, star, many others */ +#if HAVE_LIBZ + if (bsdtar->create_compression != '\0') + bsdtar_errc(bsdtar, 1, 0, + "Can't specify both -%c and -%c", opt, + bsdtar->create_compression); + bsdtar->create_compression = opt; +#else + bsdtar_warnc(bsdtar, 0, "-z compression not supported by this version of bsdtar"); + usage(bsdtar); +#endif + break; + case OPTION_USE_COMPRESS_PROGRAM: + bsdtar->compress_program = optarg; + break; + default: + usage(bsdtar); + } + } + + /* + * Sanity-check options. + */ + + /* If no "real" mode was specified, treat -h as --help. */ + if ((bsdtar->mode == '\0') && possible_help_request) { + long_help(bsdtar); + exit(0); + } + + /* Otherwise, a mode is required. */ + if (bsdtar->mode == '\0') + bsdtar_errc(bsdtar, 1, 0, + "Must specify one of -c, -r, -t, -u, -x"); + + /* Check boolean options only permitted in certain modes. */ + if (bsdtar->option_dont_traverse_mounts) + only_mode(bsdtar, "--one-file-system", "cru"); + if (bsdtar->option_fast_read) + only_mode(bsdtar, "--fast-read", "xt"); + if (bsdtar->option_honor_nodump) + only_mode(bsdtar, "--nodump", "cru"); + if (option_o > 0) { + switch (bsdtar->mode) { + case 'c': + /* + * In GNU tar, -o means "old format." The + * "ustar" format is the closest thing + * supported by libarchive. + */ + bsdtar->create_format = "ustar"; + /* TODO: bsdtar->create_format = "v7"; */ + break; + case 'x': + /* POSIX-compatible behavior. */ + bsdtar->option_no_owner = 1; + bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; + break; + default: + only_mode(bsdtar, "-o", "xc"); + break; + } + } + if (bsdtar->option_no_subdirs) + only_mode(bsdtar, "-n", "cru"); + if (bsdtar->option_stdout) + only_mode(bsdtar, "-O", "xt"); + if (bsdtar->option_unlink_first) + only_mode(bsdtar, "-U", "x"); + if (bsdtar->option_warn_links) + only_mode(bsdtar, "--check-links", "cr"); + + /* Check other parameters only permitted in certain modes. */ + if (bsdtar->create_compression == 'Z' && bsdtar->mode == 'c') { + bsdtar_warnc(bsdtar, 0, ".Z compression not supported"); + usage(bsdtar); + } + if (bsdtar->create_compression != '\0') { + strcpy(buff, "-?"); + buff[1] = bsdtar->create_compression; + only_mode(bsdtar, buff, "cxt"); + } + if (bsdtar->create_format != NULL) + only_mode(bsdtar, "--format", "c"); + if (bsdtar->symlink_mode != '\0') { + strcpy(buff, "-?"); + buff[1] = bsdtar->symlink_mode; + only_mode(bsdtar, buff, "cru"); + } + if (bsdtar->strip_components != 0) + only_mode(bsdtar, "--strip-components", "xt"); + + bsdtar->argc -= optind; + bsdtar->argv += optind; + + switch(bsdtar->mode) { + case 'c': + tar_mode_c(bsdtar); + break; + case 'r': + tar_mode_r(bsdtar); + break; + case 't': + tar_mode_t(bsdtar); + break; + case 'u': + tar_mode_u(bsdtar); + break; + case 'x': + tar_mode_x(bsdtar); + break; + } + + cleanup_exclusions(bsdtar); + if (bsdtar->return_value != 0) + bsdtar_warnc(bsdtar, 0, + "Error exit delayed from previous errors."); + return (bsdtar->return_value); +} + +static void +set_mode(struct bsdtar *bsdtar, char opt) +{ + if (bsdtar->mode != '\0' && bsdtar->mode != opt) + bsdtar_errc(bsdtar, 1, 0, + "Can't specify both -%c and -%c", opt, bsdtar->mode); + bsdtar->mode = opt; +} + +/* + * Verify that the mode is correct. + */ +static void +only_mode(struct bsdtar *bsdtar, const char *opt, const char *valid_modes) +{ + if (strchr(valid_modes, bsdtar->mode) == NULL) + bsdtar_errc(bsdtar, 1, 0, + "Option %s is not permitted in mode -%c", + opt, bsdtar->mode); +} + + +/*- + * Convert traditional tar arguments into new-style. + * For example, + * tar tvfb file.tar 32 --exclude FOO + * will be converted to + * tar -t -v -f file.tar -b 32 --exclude FOO + * + * This requires building a new argv array. The initial bundled word + * gets expanded into a new string that looks like "-t\0-v\0-f\0-b\0". + * The new argv array has pointers into this string intermingled with + * pointers to the existing arguments. Arguments are moved to + * immediately follow their options. + * + * The optstring argument here is the same one passed to getopt(3). + * It is used to determine which option letters have trailing arguments. + */ +char ** +rewrite_argv(struct bsdtar *bsdtar, int *argc, char **src_argv, + const char *optstring) +{ + char **new_argv, **dest_argv; + const char *p; + char *src, *dest; + + if (src_argv[0] == NULL || + src_argv[1] == NULL || src_argv[1][0] == '-') + return (src_argv); + + *argc += strlen(src_argv[1]) - 1; + new_argv = malloc((*argc + 1) * sizeof(new_argv[0])); + if (new_argv == NULL) + bsdtar_errc(bsdtar, 1, errno, "No Memory"); + + dest_argv = new_argv; + *dest_argv++ = *src_argv++; + + dest = malloc(strlen(*src_argv) * 3); + if (dest == NULL) + bsdtar_errc(bsdtar, 1, errno, "No memory"); + for (src = *src_argv++; *src != '\0'; src++) { + *dest_argv++ = dest; + *dest++ = '-'; + *dest++ = *src; + *dest++ = '\0'; + /* If option takes an argument, insert that into the list. */ + for (p = optstring; p != NULL && *p != '\0'; p++) { + if (*p != *src) + continue; + if (p[1] != ':') /* No arg required, done. */ + break; + if (*src_argv == NULL) /* No arg available? Error. */ + bsdtar_errc(bsdtar, 1, 0, + "Option %c requires an argument", + *src); + *dest_argv++ = *src_argv++; + break; + } + } + + /* Copy remaining arguments, including trailing NULL. */ + while ((*dest_argv++ = *src_argv++) != NULL) + ; + + return (new_argv); +} + +void +usage(struct bsdtar *bsdtar) +{ + const char *p; + + p = bsdtar->progname; + + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " List: %s -tf <archive-filename>\n", p); + fprintf(stderr, " Extract: %s -xf <archive-filename>\n", p); + fprintf(stderr, " Create: %s -cf <archive-filename> [filenames...]\n", p); +#ifdef HAVE_GETOPT_LONG + fprintf(stderr, " Help: %s --help\n", p); +#else + fprintf(stderr, " Help: %s -h\n", p); +#endif + exit(1); +} + +static void +version(void) +{ + printf("bsdtar %s - %s\n", + BSDTAR_VERSION_STRING, + archive_version()); + exit(1); +} + +static const char *long_help_msg = + "First option must be a mode specifier:\n" + " -c Create -r Add/Replace -t List -u Update -x Extract\n" + "Common Options:\n" + " -b # Use # 512-byte records per I/O block\n" + " -f <filename> Location of archive (default " _PATH_DEFTAPE ")\n" + " -v Verbose\n" + " -w Interactive\n" + "Create: %p -c [options] [<file> | <dir> | @<archive> | -C <dir> ]\n" + " <file>, <dir> add these items to archive\n" + " -z, -j Compress archive with gzip/bzip2\n" + " --format {ustar|pax|cpio|shar} Select archive format\n" +#ifdef HAVE_GETOPT_LONG + " --exclude <pattern> Skip files that match pattern\n" +#else + " -W exclude=<pattern> Skip files that match pattern\n" +#endif + " -C <dir> Change to <dir> before processing remaining files\n" + " @<archive> Add entries from <archive> to output\n" + "List: %p -t [options] [<patterns>]\n" + " <patterns> If specified, list only entries that match\n" + "Extract: %p -x [options] [<patterns>]\n" + " <patterns> If specified, extract only entries that match\n" + " -k Keep (don't overwrite) existing files\n" + " -m Don't restore modification times\n" + " -O Write entries to stdout, don't restore to disk\n" + " -p Restore permissions (including ACLs, owner, file flags)\n"; + + +/* + * Note that the word 'bsdtar' will always appear in the first line + * of output. + * + * In particular, /bin/sh scripts that need to test for the presence + * of bsdtar can use the following template: + * + * if (tar --help 2>&1 | grep bsdtar >/dev/null 2>&1 ) then \ + * echo bsdtar; else echo not bsdtar; fi + */ +static void +long_help(struct bsdtar *bsdtar) +{ + const char *prog; + const char *p; + + prog = bsdtar->progname; + + fflush(stderr); + + p = (strcmp(prog,"bsdtar") != 0) ? "(bsdtar)" : ""; + printf("%s%s: manipulate archive files\n", prog, p); + + for (p = long_help_msg; *p != '\0'; p++) { + if (*p == '%') { + if (p[1] == 'p') { + fputs(prog, stdout); + p++; + } else + putchar('%'); + } else + putchar(*p); + } + version(); +} + +static int +bsdtar_getopt(struct bsdtar *bsdtar, const char *optstring, + const struct option **poption) +{ + char *p, *q; + const struct option *option; + int opt; + int option_index; + size_t option_length; + + option_index = -1; + *poption = NULL; + +#ifdef HAVE_GETOPT_LONG + opt = getopt_long(bsdtar->argc, bsdtar->argv, optstring, + tar_longopts, &option_index); + if (option_index > -1) + *poption = tar_longopts + option_index; +#else + opt = getopt(bsdtar->argc, bsdtar->argv, optstring); +#endif + + /* Support long options through -W longopt=value */ + if (opt == 'W') { + p = optarg; + q = strchr(optarg, '='); + if (q != NULL) { + option_length = (size_t)(q - p); + optarg = q + 1; + } else { + option_length = strlen(p); + optarg = NULL; + } + option = tar_longopts; + while (option->name != NULL && + (strlen(option->name) < option_length || + strncmp(p, option->name, option_length) != 0 )) { + option++; + } + + if (option->name != NULL) { + *poption = option; + opt = option->val; + + /* If the first match was exact, we're done. */ + if (strncmp(p, option->name, strlen(option->name)) == 0) { + while (option->name != NULL) + option++; + } else { + /* Check if there's another match. */ + option++; + while (option->name != NULL && + (strlen(option->name) < option_length || + strncmp(p, option->name, option_length) != 0)) { + option++; + } + } + if (option->name != NULL) + bsdtar_errc(bsdtar, 1, 0, + "Ambiguous option %s " + "(matches both %s and %s)", + p, (*poption)->name, option->name); + + if ((*poption)->has_arg == required_argument + && optarg == NULL) + bsdtar_errc(bsdtar, 1, 0, + "Option \"%s\" requires argument", p); + } else { + opt = '?'; + /* TODO: Set up a fake 'struct option' for + * error reporting... ? ? ? */ + } + } + + return (opt); +} diff --git a/libarchive/libarchive-2.4.17/tar/bsdtar.h b/libarchive/libarchive-2.4.17/tar/bsdtar.h new file mode 100644 index 0000000..fb10678 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/bsdtar.h @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/usr.bin/tar/bsdtar.h,v 1.29 2008/01/02 00:21:27 kientzle Exp $ + */ + +#include "bsdtar_platform.h" +#include <stdio.h> + +#define DEFAULT_BYTES_PER_BLOCK (20*512) + +/* + * The internal state for the "bsdtar" program. + * + * Keeping all of the state in a structure like this simplifies memory + * leak testing (at exit, anything left on the heap is suspect). A + * pointer to this structure is passed to most bsdtar internal + * functions. + */ +struct bsdtar { + /* Options */ + const char *filename; /* -f filename */ + const char *create_format; /* -F format */ + char *pending_chdir; /* -C dir */ + const char *names_from_file; /* -T file */ + time_t newer_ctime_sec; /* --newer/--newer-than */ + long newer_ctime_nsec; /* --newer/--newer-than */ + time_t newer_mtime_sec; /* --newer-mtime */ + long newer_mtime_nsec; /* --newer-mtime-than */ + int bytes_per_block; /* -b block_size */ + int verbose; /* -v */ + int extract_flags; /* Flags for extract operation */ + int strip_components; /* Remove this many leading dirs */ + char mode; /* Program mode: 'c', 't', 'r', 'u', 'x' */ + char symlink_mode; /* H or L, per BSD conventions */ + char create_compression; /* j, y, or z */ + const char *compress_program; + char option_absolute_paths; /* -P */ + char option_dont_traverse_mounts; /* --one-file-system */ + char option_fast_read; /* --fast-read */ + char option_honor_nodump; /* --nodump */ + char option_interactive; /* -w */ + char option_no_owner; /* -o */ + char option_no_subdirs; /* -n */ + char option_null; /* --null */ + char option_stdout; /* -O */ + char option_totals; /* --totals */ + char option_unlink_first; /* -U */ + char option_warn_links; /* --check-links */ + char day_first; /* show day before month in -tv output */ + + /* If >= 0, then close this when done. */ + int fd; + + /* Miscellaneous state information */ + struct archive *archive; + const char *progname; + int argc; + char **argv; + size_t gs_width; /* For 'list_item' in read.c */ + size_t u_width; /* for 'list_item' in read.c */ + uid_t user_uid; /* UID running this program */ + int return_value; /* Value returned by main() */ + char warned_lead_slash; /* Already displayed warning */ + char next_line_is_dir; /* Used for -C parsing in -cT */ + + /* + * Data for various subsystems. Full definitions are located in + * the file where they are used. + */ + struct archive_dir *archive_dir; /* for write.c */ + struct name_cache *gname_cache; /* for write.c */ + struct links_cache *links_cache; /* for write.c */ + struct matching *matching; /* for matching.c */ + struct security *security; /* for read.c */ + struct name_cache *uname_cache; /* for write.c */ +}; + +void bsdtar_errc(struct bsdtar *, int _eval, int _code, + const char *fmt, ...); +void bsdtar_warnc(struct bsdtar *, int _code, const char *fmt, ...); +void cleanup_exclusions(struct bsdtar *); +void do_chdir(struct bsdtar *); +int edit_pathname(struct bsdtar *, struct archive_entry *); +int exclude(struct bsdtar *, const char *pattern); +int exclude_from_file(struct bsdtar *, const char *pathname); +int excluded(struct bsdtar *, const char *pathname); +int include(struct bsdtar *, const char *pattern); +int include_from_file(struct bsdtar *, const char *pathname); +int pathcmp(const char *a, const char *b); +int process_lines(struct bsdtar *bsdtar, const char *pathname, + int (*process)(struct bsdtar *, const char *)); +void safe_fprintf(FILE *, const char *fmt, ...); +void set_chdir(struct bsdtar *, const char *newdir); +void tar_mode_c(struct bsdtar *bsdtar); +void tar_mode_r(struct bsdtar *bsdtar); +void tar_mode_t(struct bsdtar *bsdtar); +void tar_mode_u(struct bsdtar *bsdtar); +void tar_mode_x(struct bsdtar *bsdtar); +int unmatched_inclusions(struct bsdtar *bsdtar); +void usage(struct bsdtar *); +int yes(const char *fmt, ...); + diff --git a/libarchive/libarchive-2.4.17/tar/bsdtar_platform.h b/libarchive/libarchive-2.4.17/tar/bsdtar_platform.h new file mode 100644 index 0000000..ccb9d3c --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/bsdtar_platform.h @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/usr.bin/tar/bsdtar_platform.h,v 1.25 2008/01/02 00:23:00 kientzle Exp $ + */ + +/* + * This header is the first thing included in any of the bsdtar + * source files. As far as possible, platform-specific issues should + * be dealt with here and not within individual source files. + */ + +#ifndef BSDTAR_PLATFORM_H_INCLUDED +#define BSDTAR_PLATFORM_H_INCLUDED + +#if defined(PLATFORM_CONFIG_H) +/* Use hand-built config.h in environments that need it. */ +#include PLATFORM_CONFIG_H +#elif defined(HAVE_CONFIG_H) +/* Most POSIX platforms use the 'configure' script to build config.h */ +#include "../config.h" +#else +/* Warn if bsdtar hasn't been (automatically or manually) configured. */ +#error Oops: No config.h and no built-in configuration in bsdtar_platform.h. +#endif /* !HAVE_CONFIG_H */ + +/* No non-FreeBSD platform will have __FBSDID, so just define it here. */ +#ifdef __FreeBSD__ +#include <sys/cdefs.h> /* For __FBSDID */ +#else +/* Just leaving this macro replacement empty leads to a dangling semicolon. */ +#define __FBSDID(a) struct _undefined_hack +#endif + +#ifdef HAVE_LIBARCHIVE +/* If we're using the platform libarchive, include system headers. */ +#include <archive.h> +#include <archive_entry.h> +#else +/* Otherwise, include user headers. */ +#include "archive.h" +#include "archive_entry.h" +#endif + +/* + * Does this platform have complete-looking POSIX-style ACL support, + * including some variant of the acl_get_perm() function (which was + * omitted from the POSIX.1e draft)? + */ +#if HAVE_SYS_ACL_H && HAVE_ACL_PERMSET_T && HAVE_ACL_USER +#if HAVE_ACL_GET_PERM || HAVE_ACL_GET_PERM_NP +#define HAVE_POSIX_ACL 1 +#endif +#endif + +#ifdef HAVE_LIBACL +#include <acl/libacl.h> +#endif + +#if HAVE_ACL_GET_PERM +#define ACL_GET_PERM acl_get_perm +#else +#if HAVE_ACL_GET_PERM_NP +#define ACL_GET_PERM acl_get_perm_np +#endif +#endif + +/* + * Include "dirent.h" (or it's equivalent on several different platforms). + * + * This is slightly modified from the GNU autoconf recipe. + * In particular, FreeBSD includes d_namlen in it's dirent structure, + * so my configure script includes an explicit test for the d_namlen + * field. + */ +#if HAVE_DIRENT_H +# include <dirent.h> +# if HAVE_DIRENT_D_NAMLEN +# define DIRENT_NAMLEN(dirent) (dirent)->d_namlen +# else +# define DIRENT_NAMLEN(dirent) strlen((dirent)->d_name) +# endif +#else +# define dirent direct +# define DIRENT_NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + + +/* + * We need to be able to display a filesize using printf(). The type + * and format string here must be compatible with one another and + * large enough for any file. + */ +#if HAVE_UINTMAX_T +#define BSDTAR_FILESIZE_TYPE uintmax_t +#define BSDTAR_FILESIZE_PRINTF "%ju" +#else +#if HAVE_UNSIGNED_LONG_LONG +#define BSDTAR_FILESIZE_TYPE unsigned long long +#define BSDTAR_FILESIZE_PRINTF "%llu" +#else +#define BSDTAR_FILESIZE_TYPE unsigned long +#define BSDTAR_FILESIZE_PRINTF "%lu" +#endif +#endif + +#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC +#define ARCHIVE_STAT_CTIME_NANOS(st) (st)->st_ctimespec.tv_nsec +#define ARCHIVE_STAT_MTIME_NANOS(st) (st)->st_mtimespec.tv_nsec +#else +#if HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC +#define ARCHIVE_STAT_CTIME_NANOS(st) (st)->st_ctim.tv_nsec +#define ARCHIVE_STAT_MTIME_NANOS(st) (st)->st_mtim.tv_nsec +#else +#define ARCHIVE_STAT_CTIME_NANOS(st) (0) +#define ARCHIVE_STAT_MTIME_NANOS(st) (0) +#endif +#endif + +#endif /* !BSDTAR_PLATFORM_H_INCLUDED */ diff --git a/libarchive/libarchive-2.4.17/tar/getdate.c b/libarchive/libarchive-2.4.17/tar/getdate.c new file mode 100644 index 0000000..31a0dfe --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/getdate.c @@ -0,0 +1,1370 @@ +#include <stdlib.h> +#ifndef lint +#ifdef __unused +__unused +#endif +static char const +yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.37 2003/02/12 18:03:55 davidc Exp $"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING() (yyerrflag!=0) +#if defined(__cplusplus) || __STDC__ +static int yygrowstack(void); +#else +static int yygrowstack(); +#endif +#define YYPREFIX "yy" +#line 2 "getdate.y" +/* + * March 2005: Further modified and simplified by Tim Kientzle: + * Eliminate minutes-based calculations (just do everything in + * seconds), have lexer only recognize unsigned integers (handle '+' + * and '-' characters in grammar), combine tables into one table with + * explicit abbreviation notes, do am/pm adjustments in the grammar + * (eliminate some state variables and post-processing). Among other + * things, these changes eliminated two shift/reduce conflicts. (Went + * from 10 to 8.) + * All of Tim Kientzle's changes to this file are public domain. + */ + +/* +** Originally written by Steven M. Bellovin <smb@research.att.com> while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990; +** +** This grammar has 10 shift/reduce conflicts. +** +** This code is in the public domain and has no copyright. +*/ +/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ +/* SUPPRESS 288 on yyerrlab *//* Label unused */ + +#ifdef __FreeBSD__ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/tar/getdate.y,v 1.9 2007/07/20 01:27:50 kientzle Exp $"); +#endif + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#define yyparse getdate_yyparse +#define yylex getdate_yylex +#define yyerror getdate_yyerror + +static int yyparse(void); +static int yylex(void); +static int yyerror(const char *); + +time_t get_date(char *); + +#define EPOCH 1970 +#define HOUR(x) ((time_t)(x) * 60) +#define SECSPERDAY (24L * 60L * 60L) + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + +/* +** Meridian: am or pm. +*/ +enum { tAM, tPM }; + +/* +** Global variables. We could get rid of most of these by using a good +** union as the yacc stack. (This routine was originally written before +** yacc had the %union construct.) Maybe someday; right now we only use +** the %union very rarely. +*/ +static char *yyInput; + +static DSTMODE yyDSTmode; +static time_t yyDayOrdinal; +static time_t yyDayNumber; +static int yyHaveDate; +static int yyHaveDay; +static int yyHaveRel; +static int yyHaveTime; +static int yyHaveZone; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static time_t yyRelMonth; +static time_t yyRelSeconds; + +#line 92 "getdate.y" +typedef union { + time_t Number; +} YYSTYPE; +#line 117 "getdate.c" +#define YYERRCODE 256 +#define tAGO 257 +#define tDAY 258 +#define tDAYZONE 259 +#define tAMPM 260 +#define tMONTH 261 +#define tMONTH_UNIT 262 +#define tSEC_UNIT 263 +#define tUNUMBER 264 +#define tZONE 265 +#define tDST 266 +const short yylhs[] = { -1, + 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 8, 8, 3, 3, 3, 5, 5, + 5, 4, 4, 4, 4, 4, 4, 4, 4, 6, + 6, 9, 9, 9, 9, 9, 9, 9, 9, 7, +}; +const short yylen[] = { 2, + 0, 2, 1, 1, 1, 1, 1, 1, 2, 1, + 2, 3, 3, 3, 5, 1, 1, 2, 1, 2, + 2, 3, 5, 5, 5, 2, 4, 2, 3, 2, + 1, 3, 3, 2, 1, 3, 3, 2, 1, 1, +}; +const short yydefred[] = { 1, + 0, 0, 17, 0, 39, 35, 0, 0, 0, 0, + 2, 3, 4, 5, 6, 7, 8, 0, 0, 20, + 0, 21, 9, 0, 38, 34, 0, 0, 0, 18, + 0, 0, 11, 0, 0, 30, 0, 29, 0, 0, + 0, 0, 37, 33, 36, 32, 12, 13, 27, 0, + 0, 0, 0, 25, 24, 15, 23, +}; +const short yydgoto[] = { 1, + 11, 12, 13, 14, 15, 16, 17, 18, 19, +}; +const short yysindex[] = { 0, + -43, -40, 0, -259, 0, 0, -35, -252, -253, -248, + 0, 0, 0, 0, 0, 0, 0, -30, -237, 0, + -23, 0, 0, -242, 0, 0, -258, -240, -238, 0, + -255, -244, 0, -236, -235, 0, -234, 0, -18, -14, + -26, -13, 0, 0, 0, 0, 0, 0, 0, -229, + -228, -227, -226, 0, 0, 0, 0, +}; +const short yyrindex[] = { 0, + 0, 9, 0, 0, 0, 0, 64, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 57, 25, 0, + 33, 0, 0, 49, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 41, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, +}; +const short yygindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define YYTABLESIZE 329 +const short yytable[] = { 9, + 14, 10, 39, 20, 21, 40, 43, 44, 19, 27, + 31, 29, 34, 30, 35, 32, 16, 45, 46, 36, + 37, 38, 28, 41, 31, 42, 50, 47, 48, 49, + 51, 52, 26, 53, 54, 55, 56, 57, 0, 0, + 22, 0, 0, 14, 0, 14, 0, 0, 28, 0, + 0, 19, 0, 19, 0, 0, 10, 0, 0, 16, + 0, 16, 0, 40, 0, 0, 0, 31, 0, 31, + 0, 0, 0, 0, 0, 26, 0, 26, 0, 0, + 0, 0, 0, 22, 0, 22, 0, 0, 0, 0, + 0, 28, 0, 28, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 3, 0, 4, 5, 6, + 7, 8, 22, 0, 23, 24, 25, 26, 0, 33, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, + 14, 14, 14, 14, 14, 14, 19, 19, 0, 19, + 19, 19, 19, 19, 16, 16, 0, 16, 16, 16, + 16, 16, 31, 31, 0, 31, 31, 31, 31, 31, + 26, 26, 0, 26, 26, 26, 26, 26, 22, 22, + 0, 22, 22, 22, 22, 22, 28, 28, 0, 28, + 28, 28, 0, 28, 10, 10, 0, 10, 10, 10, + 10, 10, 40, 0, 0, 0, 0, 40, 40, +}; +const short yycheck[] = { 43, + 0, 45, 261, 44, 264, 264, 262, 263, 0, 45, + 264, 47, 43, 266, 45, 264, 0, 262, 263, 257, + 44, 264, 58, 264, 0, 264, 45, 264, 264, 264, + 45, 58, 0, 47, 264, 264, 264, 264, -1, -1, + 0, -1, -1, 43, -1, 45, -1, -1, 0, -1, + -1, 43, -1, 45, -1, -1, 0, -1, -1, 43, + -1, 45, -1, 0, -1, -1, -1, 43, -1, 45, + -1, -1, -1, -1, -1, 43, -1, 45, -1, -1, + -1, -1, -1, 43, -1, 45, -1, -1, -1, -1, + -1, 43, -1, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 258, 259, -1, 261, 262, 263, + 264, 265, 258, -1, 260, 261, 262, 263, -1, 260, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 258, 259, + 260, 261, 262, 263, 264, 265, 258, 259, -1, 261, + 262, 263, 264, 265, 258, 259, -1, 261, 262, 263, + 264, 265, 258, 259, -1, 261, 262, 263, 264, 265, + 258, 259, -1, 261, 262, 263, 264, 265, 258, 259, + -1, 261, 262, 263, 264, 265, 258, 259, -1, 261, + 262, 263, -1, 265, 258, 259, -1, 261, 262, 263, + 264, 265, 259, -1, -1, -1, -1, 264, 265, +}; +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 266 +#if YYDEBUG +const char * const yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,"'+'","','","'-'",0,"'/'",0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"tAGO","tDAY", +"tDAYZONE","tAMPM","tMONTH","tMONTH_UNIT","tSEC_UNIT","tUNUMBER","tZONE","tDST", +}; +const char * const yyrule[] = { +"$accept : spec", +"spec :", +"spec : spec item", +"item : time", +"item : zone", +"item : date", +"item : day", +"item : rel", +"item : number", +"time : tUNUMBER tAMPM", +"time : bare_time", +"time : bare_time tAMPM", +"time : bare_time '+' tUNUMBER", +"time : bare_time '-' tUNUMBER", +"bare_time : tUNUMBER ':' tUNUMBER", +"bare_time : tUNUMBER ':' tUNUMBER ':' tUNUMBER", +"zone : tZONE", +"zone : tDAYZONE", +"zone : tZONE tDST", +"day : tDAY", +"day : tDAY ','", +"day : tUNUMBER tDAY", +"date : tUNUMBER '/' tUNUMBER", +"date : tUNUMBER '/' tUNUMBER '/' tUNUMBER", +"date : tUNUMBER '-' tUNUMBER '-' tUNUMBER", +"date : tUNUMBER '-' tMONTH '-' tUNUMBER", +"date : tMONTH tUNUMBER", +"date : tMONTH tUNUMBER ',' tUNUMBER", +"date : tUNUMBER tMONTH", +"date : tUNUMBER tMONTH tUNUMBER", +"rel : relunit tAGO", +"rel : relunit", +"relunit : '-' tUNUMBER tSEC_UNIT", +"relunit : '+' tUNUMBER tSEC_UNIT", +"relunit : tUNUMBER tSEC_UNIT", +"relunit : tSEC_UNIT", +"relunit : '-' tUNUMBER tMONTH_UNIT", +"relunit : '+' tUNUMBER tMONTH_UNIT", +"relunit : tUNUMBER tMONTH_UNIT", +"relunit : tMONTH_UNIT", +"number : tUNUMBER", +}; +#endif +#if YYDEBUG +#include <stdio.h> +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 10000 +#define YYMAXDEPTH 10000 +#endif +#endif +#define YYINITSTACKSIZE 200 +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short *yyss; +short *yysslim; +YYSTYPE *yyvs; +int yystacksize; +#line 328 "getdate.y" + +static struct TABLE { + size_t abbrev; + const char *name; + int type; + time_t value; +} const TimeWords[] = { + /* am/pm */ + { 0, "am", tAMPM, tAM }, + { 0, "pm", tAMPM, tPM }, + + /* Month names. */ + { 3, "january", tMONTH, 1 }, + { 3, "february", tMONTH, 2 }, + { 3, "march", tMONTH, 3 }, + { 3, "april", tMONTH, 4 }, + { 3, "may", tMONTH, 5 }, + { 3, "june", tMONTH, 6 }, + { 3, "july", tMONTH, 7 }, + { 3, "august", tMONTH, 8 }, + { 3, "september", tMONTH, 9 }, + { 3, "october", tMONTH, 10 }, + { 3, "november", tMONTH, 11 }, + { 3, "december", tMONTH, 12 }, + + /* Days of the week. */ + { 2, "sunday", tDAY, 0 }, + { 3, "monday", tDAY, 1 }, + { 2, "tuesday", tDAY, 2 }, + { 3, "wednesday", tDAY, 3 }, + { 2, "thursday", tDAY, 4 }, + { 2, "friday", tDAY, 5 }, + { 2, "saturday", tDAY, 6 }, + + /* Timezones: Offsets are in minutes. */ + { 0, "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { 0, "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ + { 0, "utc", tZONE, HOUR( 0) }, + { 0, "wet", tZONE, HOUR( 0) }, /* Western European */ + { 0, "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { 0, "wat", tZONE, HOUR( 1) }, /* West Africa */ + { 0, "at", tZONE, HOUR( 2) }, /* Azores */ + /* { 0, "bst", tZONE, HOUR( 3) }, */ /* Brazil Standard: Conflict */ + /* { 0, "gst", tZONE, HOUR( 3) }, */ /* Greenland Standard: Conflict*/ + { 0, "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */ + { 0, "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */ + { 0, "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */ + { 0, "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { 0, "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { 0, "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { 0, "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { 0, "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { 0, "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { 0, "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { 0, "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { 0, "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { 0, "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { 0, "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { 0, "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { 0, "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { 0, "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ + { 0, "cat", tZONE, HOUR(10) }, /* Central Alaska */ + { 0, "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ + { 0, "nt", tZONE, HOUR(11) }, /* Nome */ + { 0, "idlw", tZONE, HOUR(12) }, /* Intl Date Line West */ + { 0, "cet", tZONE, -HOUR(1) }, /* Central European */ + { 0, "met", tZONE, -HOUR(1) }, /* Middle European */ + { 0, "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { 0, "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { 0, "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { 0, "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { 0, "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { 0, "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { 0, "eet", tZONE, -HOUR(2) }, /* Eastern Eur, USSR Zone 1 */ + { 0, "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ + { 0, "it", tZONE, -HOUR(3)-30 },/* Iran */ + { 0, "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { 0, "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ + { 0, "ist", tZONE, -HOUR(5)-30 },/* Indian Standard */ + { 0, "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ + /* { 0, "nst", tZONE, -HOUR(6.5) }, */ /* North Sumatra: Conflict */ + /* { 0, "sst", tZONE, -HOUR(7) }, */ /* So Sumatra, USSR 6: Conflict */ + { 0, "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ + { 0, "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ + { 0, "jt", tZONE, -HOUR(7)-30 },/* Java (3pm in Cronusland!)*/ + { 0, "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ + { 0, "jst", tZONE, -HOUR(9) }, /* Japan Std, USSR Zone 8 */ + { 0, "cast", tZONE, -HOUR(9)-30 },/* Central Australian Std */ + { 0, "cadt", tDAYZONE, -HOUR(9)-30 },/* Central Australian Daylt */ + { 0, "east", tZONE, -HOUR(10) }, /* Eastern Australian Std */ + { 0, "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylt */ + { 0, "gst", tZONE, -HOUR(10) }, /* Guam Std, USSR Zone 9 */ + { 0, "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { 0, "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { 0, "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + { 0, "idle", tZONE, -HOUR(12) }, /* Intl Date Line East */ + + { 0, "dst", tDST, 0 }, + + /* Time units. */ + { 4, "years", tMONTH_UNIT, 12 }, + { 5, "months", tMONTH_UNIT, 1 }, + { 9, "fortnights", tSEC_UNIT, 14 * 24 * 60 * 60 }, + { 4, "weeks", tSEC_UNIT, 7 * 24 * 60 * 60 }, + { 3, "days", tSEC_UNIT, 1 * 24 * 60 * 60 }, + { 4, "hours", tSEC_UNIT, 60 * 60 }, + { 3, "minutes", tSEC_UNIT, 60 }, + { 3, "seconds", tSEC_UNIT, 1 }, + + /* Relative-time words. */ + { 0, "tomorrow", tSEC_UNIT, 1 * 24 * 60 * 60 }, + { 0, "yesterday", tSEC_UNIT, -1 * 24 * 60 * 60 }, + { 0, "today", tSEC_UNIT, 0 }, + { 0, "now", tSEC_UNIT, 0 }, + { 0, "last", tUNUMBER, -1 }, + { 0, "this", tSEC_UNIT, 0 }, + { 0, "next", tUNUMBER, 2 }, + { 0, "first", tUNUMBER, 1 }, + { 0, "1st", tUNUMBER, 1 }, +/* { 0, "second", tUNUMBER, 2 }, */ + { 0, "2nd", tUNUMBER, 2 }, + { 0, "third", tUNUMBER, 3 }, + { 0, "3rd", tUNUMBER, 3 }, + { 0, "fourth", tUNUMBER, 4 }, + { 0, "4th", tUNUMBER, 4 }, + { 0, "fifth", tUNUMBER, 5 }, + { 0, "5th", tUNUMBER, 5 }, + { 0, "sixth", tUNUMBER, 6 }, + { 0, "seventh", tUNUMBER, 7 }, + { 0, "eighth", tUNUMBER, 8 }, + { 0, "ninth", tUNUMBER, 9 }, + { 0, "tenth", tUNUMBER, 10 }, + { 0, "eleventh", tUNUMBER, 11 }, + { 0, "twelfth", tUNUMBER, 12 }, + { 0, "ago", tAGO, 1 }, + + /* Military timezones. */ + { 0, "a", tZONE, HOUR( 1) }, + { 0, "b", tZONE, HOUR( 2) }, + { 0, "c", tZONE, HOUR( 3) }, + { 0, "d", tZONE, HOUR( 4) }, + { 0, "e", tZONE, HOUR( 5) }, + { 0, "f", tZONE, HOUR( 6) }, + { 0, "g", tZONE, HOUR( 7) }, + { 0, "h", tZONE, HOUR( 8) }, + { 0, "i", tZONE, HOUR( 9) }, + { 0, "k", tZONE, HOUR( 10) }, + { 0, "l", tZONE, HOUR( 11) }, + { 0, "m", tZONE, HOUR( 12) }, + { 0, "n", tZONE, HOUR(- 1) }, + { 0, "o", tZONE, HOUR(- 2) }, + { 0, "p", tZONE, HOUR(- 3) }, + { 0, "q", tZONE, HOUR(- 4) }, + { 0, "r", tZONE, HOUR(- 5) }, + { 0, "s", tZONE, HOUR(- 6) }, + { 0, "t", tZONE, HOUR(- 7) }, + { 0, "u", tZONE, HOUR(- 8) }, + { 0, "v", tZONE, HOUR(- 9) }, + { 0, "w", tZONE, HOUR(-10) }, + { 0, "x", tZONE, HOUR(-11) }, + { 0, "y", tZONE, HOUR(-12) }, + { 0, "z", tZONE, HOUR( 0) }, + + /* End of table. */ + { 0, NULL, 0, 0 } +}; + + + + +/* ARGSUSED */ +static int +yyerror(const char *s) +{ + (void)s; + return 0; +} + +static time_t +ToSeconds(time_t Hours, time_t Minutes, time_t Seconds) +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) + return -1; + if (Hours < 0 || Hours > 23) + return -1; + return (Hours * 60L + Minutes) * 60L + Seconds; +} + + +/* Year is either + * A number from 0 to 99, which means a year from 1970 to 2069, or + * The actual year (>=100). */ +static time_t +Convert(time_t Month, time_t Day, time_t Year, + time_t Hours, time_t Minutes, time_t Seconds, DSTMODE DSTmode) +{ + static int DaysInMonth[12] = { + 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + time_t tod; + time_t Julian; + int i; + + if (Year < 69) + Year += 2000; + else if (Year < 100) + Year += 1900; + DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) + ? 29 : 28; + /* Checking for 2038 bogusly assumes that time_t is 32 bits. But + I'm too lazy to try to check for time_t overflow in another way. */ + if (Year < EPOCH || Year > 2038 + || Month < 1 || Month > 12 + /* Lint fluff: "conversion from long may lose accuracy" */ + || Day < 1 || Day > DaysInMonth[(int)--Month]) + return -1; + + Julian = Day - 1; + for (i = 0; i < Month; i++) + Julian += DaysInMonth[i]; + for (i = EPOCH; i < Year; i++) + Julian += 365 + (i % 4 == 0); + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds)) < 0) + return -1; + Julian += tod; + if (DSTmode == DSTon + || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) + Julian -= 60 * 60; + return Julian; +} + + +static time_t +DSTcorrect(time_t Start, time_t Future) +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; +} + + +static time_t +RelativeDate(time_t Start, time_t DayOrdinal, time_t DayNumber) +{ + struct tm *tm; + time_t now; + + now = Start; + tm = localtime(&now); + now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); + now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); + return DSTcorrect(Start, now); +} + + +static time_t +RelativeMonth(time_t Start, time_t RelMonth) +{ + struct tm *tm; + time_t Month; + time_t Year; + + if (RelMonth == 0) + return 0; + tm = localtime(&Start); + Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth; + Year = Month / 12; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + DSTmaybe)); +} + +static int +yylex(void) +{ + char c; + char buff[64]; + + for ( ; ; ) { + while (isspace((unsigned char)*yyInput)) + yyInput++; + + /* Skip parenthesized comments. */ + if (*yyInput == '(') { + int Count = 0; + do { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } while (Count > 0); + continue; + } + + /* Try the next token in the word table first. */ + /* This allows us to match "2nd", for example. */ + { + char *src = yyInput; + const struct TABLE *tp; + unsigned i = 0; + + /* Force to lowercase and strip '.' characters. */ + while (*src != '\0' + && (isalnum((unsigned char)*src) || *src == '.') + && i < sizeof(buff)-1) { + if (*src != '.') { + if (isupper((unsigned char)*src)) + buff[i++] = tolower((unsigned char)*src); + else + buff[i++] = *src; + } + src++; + } + buff[i++] = '\0'; + + /* + * Find the first match. If the word can be + * abbreviated, make sure we match at least + * the minimum abbreviation. + */ + for (tp = TimeWords; tp->name; tp++) { + size_t abbrev = tp->abbrev; + if (abbrev == 0) + abbrev = strlen(tp->name); + if (strlen(buff) >= abbrev + && strncmp(tp->name, buff, strlen(buff)) + == 0) { + /* Skip over token. */ + yyInput = src; + /* Return the match. */ + yylval.Number = tp->value; + return tp->type; + } + } + } + + /* + * Not in the word table, maybe it's a number. Note: + * Because '-' and '+' have other special meanings, I + * don't deal with signed numbers here. + */ + if (isdigit((unsigned char)(c = *yyInput))) { + for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); ) + yylval.Number = 10 * yylval.Number + c - '0'; + yyInput--; + return (tUNUMBER); + } + + return (*yyInput++); + } +} + +#define TM_YEAR_ORIGIN 1900 + +/* Yield A - B, measured in seconds. */ +static long +difftm (struct tm *a, struct tm *b) +{ + int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); + int by = b->tm_year + (TM_YEAR_ORIGIN - 1); + int days = ( + /* difference in day of year */ + a->tm_yday - b->tm_yday + /* + intervening leap days */ + + ((ay >> 2) - (by >> 2)) + - (ay/100 - by/100) + + ((ay/100 >> 2) - (by/100 >> 2)) + /* + difference in years * 365 */ + + (long)(ay-by) * 365 + ); + return (60*(60*(24*days + (a->tm_hour - b->tm_hour)) + + (a->tm_min - b->tm_min)) + + (a->tm_sec - b->tm_sec)); +} + +time_t +get_date(char *p) +{ + struct tm *tm; + struct tm gmt, *gmt_ptr; + time_t Start; + time_t tod; + time_t nowtime; + long tzone; + + memset(&gmt, 0, sizeof(gmt)); + yyInput = p; + + (void)time (&nowtime); + + gmt_ptr = gmtime (&nowtime); + if (gmt_ptr != NULL) { + /* Copy, in case localtime and gmtime use the same buffer. */ + gmt = *gmt_ptr; + } + + if (! (tm = localtime (&nowtime))) + return -1; + + if (gmt_ptr != NULL) + tzone = difftm (&gmt, tm) / 60; + else + /* This system doesn't understand timezones; fake it. */ + tzone = 0; + if(tm->tm_isdst) + tzone += 60; + + yyYear = tm->tm_year + 1900; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; + yyTimezone = tzone; + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveDay = 0; + yyHaveRel = 0; + yyHaveTime = 0; + yyHaveZone = 0; + + if (yyparse() + || yyHaveTime > 1 || yyHaveZone > 1 + || yyHaveDate > 1 || yyHaveDay > 1) + return -1; + + if (yyHaveDate || yyHaveTime || yyHaveDay) { + Start = Convert(yyMonth, yyDay, yyYear, + yyHour, yyMinutes, yySeconds, yyDSTmode); + if (Start < 0) + return -1; + } else { + Start = nowtime; + if (!yyHaveRel) + Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; + } + + Start += yyRelSeconds; + Start += RelativeMonth(Start, yyRelMonth); + + if (yyHaveDay && !yyHaveDate) { + tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); + Start += tod; + } + + /* Have to do *something* with a legitimate -1 so it's + * distinguishable from the error return value. (Alternately + * could set errno on error.) */ + return Start == -1 ? 0 : Start; +} + + +#if defined(TEST) + +/* ARGSUSED */ +int +main(int argc, char **argv) +{ + time_t d; + + while (*++argv != NULL) { + (void)printf("Input: %s\n", *argv); + d = get_date(*argv); + if (d == -1) + (void)printf("Bad format - couldn't convert.\n"); + else + (void)printf("Output: %s\n", ctime(&d)); + } + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ +#line 814 "getdate.c" +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +static int yygrowstack() +{ + int newsize, i; + short *newss; + YYSTYPE *newvs; + + if ((newsize = yystacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return -1; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + i = yyssp - yyss; + newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) : + (short *)malloc(newsize * sizeof *newss); + if (newss == NULL) + return -1; + yyss = newss; + yyssp = newss + i; + newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) : + (YYSTYPE *)malloc(newsize * sizeof *newvs); + if (newvs == NULL) + return -1; + yyvs = newvs; + yyvsp = newvs + i; + yystacksize = newsize; + yysslim = yyss + newsize - 1; + return 0; +} + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab + +#ifndef YYPARSE_PARAM +#if defined(__cplusplus) || __STDC__ +#define YYPARSE_PARAM_ARG void +#define YYPARSE_PARAM_DECL +#else /* ! ANSI-C/C++ */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* ANSI-C/C++ */ +#else /* YYPARSE_PARAM */ +#ifndef YYPARSE_PARAM_TYPE +#define YYPARSE_PARAM_TYPE void * +#endif +#if defined(__cplusplus) || __STDC__ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM_TYPE YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* ! ANSI-C/C++ */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL YYPARSE_PARAM_TYPE YYPARSE_PARAM; +#endif /* ANSI-C/C++ */ +#endif /* ! YYPARSE_PARAM */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + int yym, yyn, yystate; +#if YYDEBUG + const char *yys; + + if ((yys = getenv("YYDEBUG"))) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + if (yyss == NULL && yygrowstack()) goto yyoverflow; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if ((yyn = yydefred[yystate])) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#if defined(lint) || defined(__GNUC__) + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#if defined(lint) || defined(__GNUC__) + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 3: +#line 108 "getdate.y" +{ yyHaveTime++; } +break; +case 4: +#line 109 "getdate.y" +{ yyHaveZone++; } +break; +case 5: +#line 110 "getdate.y" +{ yyHaveDate++; } +break; +case 6: +#line 111 "getdate.y" +{ yyHaveDay++; } +break; +case 7: +#line 112 "getdate.y" +{ yyHaveRel++; } +break; +case 9: +#line 116 "getdate.y" +{ + /* "7am" */ + yyHour = yyvsp[-1].Number; + if (yyHour == 12) + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + if (yyvsp[0].Number == tPM) + yyHour += 12; + } +break; +case 10: +#line 126 "getdate.y" +{ + /* "7:12:18" "19:17" */ + } +break; +case 11: +#line 129 "getdate.y" +{ + /* "7:12pm", "12:20:13am" */ + if (yyHour == 12) + yyHour = 0; + if (yyvsp[0].Number == tPM) + yyHour += 12; + } +break; +case 12: +#line 136 "getdate.y" +{ + /* "7:14+0700" */ + yyDSTmode = DSToff; + yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60); + } +break; +case 13: +#line 141 "getdate.y" +{ + /* "19:14:12-0530" */ + yyDSTmode = DSToff; + yyTimezone = + (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60); + } +break; +case 14: +#line 148 "getdate.y" +{ + yyHour = yyvsp[-2].Number; + yyMinutes = yyvsp[0].Number; + yySeconds = 0; + } +break; +case 15: +#line 153 "getdate.y" +{ + yyHour = yyvsp[-4].Number; + yyMinutes = yyvsp[-2].Number; + yySeconds = yyvsp[0].Number; + } +break; +case 16: +#line 160 "getdate.y" +{ + yyTimezone = yyvsp[0].Number; + yyDSTmode = DSToff; + } +break; +case 17: +#line 164 "getdate.y" +{ + yyTimezone = yyvsp[0].Number; + yyDSTmode = DSTon; + } +break; +case 18: +#line 168 "getdate.y" +{ + yyTimezone = yyvsp[-1].Number; + yyDSTmode = DSTon; + } +break; +case 19: +#line 174 "getdate.y" +{ + yyDayOrdinal = 1; + yyDayNumber = yyvsp[0].Number; + } +break; +case 20: +#line 178 "getdate.y" +{ + /* "tue," "wednesday," */ + yyDayOrdinal = 1; + yyDayNumber = yyvsp[-1].Number; + } +break; +case 21: +#line 183 "getdate.y" +{ + /* "second tues" "3 wed" */ + yyDayOrdinal = yyvsp[-1].Number; + yyDayNumber = yyvsp[0].Number; + } +break; +case 22: +#line 190 "getdate.y" +{ + /* "1/15" */ + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } +break; +case 23: +#line 195 "getdate.y" +{ + if (yyvsp[-4].Number >= 13) { + /* First number is big: 2004/01/29, 99/02/17 */ + yyYear = yyvsp[-4].Number; + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } else if ((yyvsp[0].Number >= 13) || (yyvsp[-2].Number >= 13)) { + /* Last number is big: 01/07/98 */ + /* Middle number is big: 01/29/04 */ + yyMonth = yyvsp[-4].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } else { + /* No significant clues: 02/03/04 */ + yyMonth = yyvsp[-4].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } + } +break; +case 24: +#line 214 "getdate.y" +{ + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = yyvsp[-4].Number; + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } +break; +case 25: +#line 220 "getdate.y" +{ + if (yyvsp[-4].Number > 31) { + /* e.g. 1992-Jun-17 */ + yyYear = yyvsp[-4].Number; + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } else { + /* e.g. 17-JUN-1992. */ + yyDay = yyvsp[-4].Number; + yyMonth = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } + } +break; +case 26: +#line 233 "getdate.y" +{ + /* "May 3" */ + yyMonth = yyvsp[-1].Number; + yyDay = yyvsp[0].Number; + } +break; +case 27: +#line 238 "getdate.y" +{ + /* "June 17, 2001" */ + yyMonth = yyvsp[-3].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } +break; +case 28: +#line 244 "getdate.y" +{ + /* "12 Sept" */ + yyDay = yyvsp[-1].Number; + yyMonth = yyvsp[0].Number; + } +break; +case 29: +#line 249 "getdate.y" +{ + /* "12 Sept 1997" */ + yyDay = yyvsp[-2].Number; + yyMonth = yyvsp[-1].Number; + yyYear = yyvsp[0].Number; + } +break; +case 30: +#line 257 "getdate.y" +{ + yyRelSeconds = -yyRelSeconds; + yyRelMonth = -yyRelMonth; + } +break; +case 32: +#line 264 "getdate.y" +{ + /* "-3 hours" */ + yyRelSeconds -= yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 33: +#line 268 "getdate.y" +{ + /* "+1 minute" */ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 34: +#line 272 "getdate.y" +{ + /* "1 day" */ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 35: +#line 276 "getdate.y" +{ + /* "hour" */ + yyRelSeconds += yyvsp[0].Number; + } +break; +case 36: +#line 280 "getdate.y" +{ + /* "-3 months" */ + yyRelMonth -= yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 37: +#line 284 "getdate.y" +{ + /* "+5 years" */ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 38: +#line 288 "getdate.y" +{ + /* "2 years" */ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 39: +#line 292 "getdate.y" +{ + /* "6 months" */ + yyRelMonth += yyvsp[0].Number; + } +break; +case 40: +#line 298 "getdate.y" +{ + if (yyHaveTime && yyHaveDate && !yyHaveRel) + yyYear = yyvsp[0].Number; + else { + if(yyvsp[0].Number>10000) { + /* "20040301" */ + yyHaveDate++; + yyDay= (yyvsp[0].Number)%100; + yyMonth= (yyvsp[0].Number/100)%100; + yyYear = yyvsp[0].Number/10000; + } + else { + /* "513" is same as "5:13" */ + yyHaveTime++; + if (yyvsp[0].Number < 100) { + yyHour = yyvsp[0].Number; + yyMinutes = 0; + } + else { + yyHour = yyvsp[0].Number / 100; + yyMinutes = yyvsp[0].Number % 100; + } + yySeconds = 0; + } + } + } +break; +#line 1315 "getdate.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/libarchive/libarchive-2.4.17/tar/getdate.y b/libarchive/libarchive-2.4.17/tar/getdate.y new file mode 100644 index 0000000..3253f6d --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/getdate.y @@ -0,0 +1,811 @@ +%{ +/* + * March 2005: Further modified and simplified by Tim Kientzle: + * Eliminate minutes-based calculations (just do everything in + * seconds), have lexer only recognize unsigned integers (handle '+' + * and '-' characters in grammar), combine tables into one table with + * explicit abbreviation notes, do am/pm adjustments in the grammar + * (eliminate some state variables and post-processing). Among other + * things, these changes eliminated two shift/reduce conflicts. (Went + * from 10 to 8.) + * All of Tim Kientzle's changes to this file are public domain. + */ + +/* +** Originally written by Steven M. Bellovin <smb@research.att.com> while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990; +** +** This grammar has 10 shift/reduce conflicts. +** +** This code is in the public domain and has no copyright. +*/ +/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ +/* SUPPRESS 288 on yyerrlab *//* Label unused */ + +#ifdef __FreeBSD__ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/tar/getdate.y,v 1.9 2007/07/20 01:27:50 kientzle Exp $"); +#endif + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#define yyparse getdate_yyparse +#define yylex getdate_yylex +#define yyerror getdate_yyerror + +static int yyparse(void); +static int yylex(void); +static int yyerror(const char *); + +time_t get_date(char *); + +#define EPOCH 1970 +#define HOUR(x) ((time_t)(x) * 60) +#define SECSPERDAY (24L * 60L * 60L) + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + +/* +** Meridian: am or pm. +*/ +enum { tAM, tPM }; + +/* +** Global variables. We could get rid of most of these by using a good +** union as the yacc stack. (This routine was originally written before +** yacc had the %union construct.) Maybe someday; right now we only use +** the %union very rarely. +*/ +static char *yyInput; + +static DSTMODE yyDSTmode; +static time_t yyDayOrdinal; +static time_t yyDayNumber; +static int yyHaveDate; +static int yyHaveDay; +static int yyHaveRel; +static int yyHaveTime; +static int yyHaveZone; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static time_t yyRelMonth; +static time_t yyRelSeconds; + +%} + +%union { + time_t Number; +} + +%token tAGO tDAY tDAYZONE tAMPM tMONTH tMONTH_UNIT tSEC_UNIT tUNUMBER +%token tZONE tDST + +%type <Number> tDAY tDAYZONE tMONTH tMONTH_UNIT +%type <Number> tSEC_UNIT tUNUMBER tZONE tAMPM + +%% + +spec : /* NULL */ + | spec item + ; + +item : time { yyHaveTime++; } + | zone { yyHaveZone++; } + | date { yyHaveDate++; } + | day { yyHaveDay++; } + | rel { yyHaveRel++; } + | number + ; + +time : tUNUMBER tAMPM { + /* "7am" */ + yyHour = $1; + if (yyHour == 12) + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + if ($2 == tPM) + yyHour += 12; + } + | bare_time { + /* "7:12:18" "19:17" */ + } + | bare_time tAMPM { + /* "7:12pm", "12:20:13am" */ + if (yyHour == 12) + yyHour = 0; + if ($2 == tPM) + yyHour += 12; + } + | bare_time '+' tUNUMBER { + /* "7:14+0700" */ + yyDSTmode = DSToff; + yyTimezone = - ($3 % 100 + ($3 / 100) * 60); + } + | bare_time '-' tUNUMBER { + /* "19:14:12-0530" */ + yyDSTmode = DSToff; + yyTimezone = + ($3 % 100 + ($3 / 100) * 60); + } + ; + +bare_time : tUNUMBER ':' tUNUMBER { + yyHour = $1; + yyMinutes = $3; + yySeconds = 0; + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + } + ; + +zone : tZONE { + yyTimezone = $1; + yyDSTmode = DSToff; + } + | tDAYZONE { + yyTimezone = $1; + yyDSTmode = DSTon; + } + | tZONE tDST { + yyTimezone = $1; + yyDSTmode = DSTon; + } + ; + +day : tDAY { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tDAY ',' { + /* "tue," "wednesday," */ + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tUNUMBER tDAY { + /* "second tues" "3 wed" */ + yyDayOrdinal = $1; + yyDayNumber = $2; + } + ; + +date : tUNUMBER '/' tUNUMBER { + /* "1/15" */ + yyMonth = $1; + yyDay = $3; + } + | tUNUMBER '/' tUNUMBER '/' tUNUMBER { + if ($1 >= 13) { + /* First number is big: 2004/01/29, 99/02/17 */ + yyYear = $1; + yyMonth = $3; + yyDay = $5; + } else if (($5 >= 13) || ($3 >= 13)) { + /* Last number is big: 01/07/98 */ + /* Middle number is big: 01/29/04 */ + yyMonth = $1; + yyDay = $3; + yyYear = $5; + } else { + /* No significant clues: 02/03/04 */ + yyMonth = $1; + yyDay = $3; + yyYear = $5; + } + } + | tUNUMBER '-' tUNUMBER '-' tUNUMBER { + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = $1; + yyMonth = $3; + yyDay = $5; + } + | tUNUMBER '-' tMONTH '-' tUNUMBER { + if ($1 > 31) { + /* e.g. 1992-Jun-17 */ + yyYear = $1; + yyMonth = $3; + yyDay = $5; + } else { + /* e.g. 17-JUN-1992. */ + yyDay = $1; + yyMonth = $3; + yyYear = $5; + } + } + | tMONTH tUNUMBER { + /* "May 3" */ + yyMonth = $1; + yyDay = $2; + } + | tMONTH tUNUMBER ',' tUNUMBER { + /* "June 17, 2001" */ + yyMonth = $1; + yyDay = $2; + yyYear = $4; + } + | tUNUMBER tMONTH { + /* "12 Sept" */ + yyDay = $1; + yyMonth = $2; + } + | tUNUMBER tMONTH tUNUMBER { + /* "12 Sept 1997" */ + yyDay = $1; + yyMonth = $2; + yyYear = $3; + } + ; + +rel : relunit tAGO { + yyRelSeconds = -yyRelSeconds; + yyRelMonth = -yyRelMonth; + } + | relunit + ; + +relunit : '-' tUNUMBER tSEC_UNIT { + /* "-3 hours" */ + yyRelSeconds -= $2 * $3; + } + | '+' tUNUMBER tSEC_UNIT { + /* "+1 minute" */ + yyRelSeconds += $2 * $3; + } + | tUNUMBER tSEC_UNIT { + /* "1 day" */ + yyRelSeconds += $1 * $2; + } + | tSEC_UNIT { + /* "hour" */ + yyRelSeconds += $1; + } + | '-' tUNUMBER tMONTH_UNIT { + /* "-3 months" */ + yyRelMonth -= $2 * $3; + } + | '+' tUNUMBER tMONTH_UNIT { + /* "+5 years" */ + yyRelMonth += $2 * $3; + } + | tUNUMBER tMONTH_UNIT { + /* "2 years" */ + yyRelMonth += $1 * $2; + } + | tMONTH_UNIT { + /* "6 months" */ + yyRelMonth += $1; + } + ; + +number : tUNUMBER { + if (yyHaveTime && yyHaveDate && !yyHaveRel) + yyYear = $1; + else { + if($1>10000) { + /* "20040301" */ + yyHaveDate++; + yyDay= ($1)%100; + yyMonth= ($1/100)%100; + yyYear = $1/10000; + } + else { + /* "513" is same as "5:13" */ + yyHaveTime++; + if ($1 < 100) { + yyHour = $1; + yyMinutes = 0; + } + else { + yyHour = $1 / 100; + yyMinutes = $1 % 100; + } + yySeconds = 0; + } + } + } + ; + + +%% + +static struct TABLE { + size_t abbrev; + const char *name; + int type; + time_t value; +} const TimeWords[] = { + /* am/pm */ + { 0, "am", tAMPM, tAM }, + { 0, "pm", tAMPM, tPM }, + + /* Month names. */ + { 3, "january", tMONTH, 1 }, + { 3, "february", tMONTH, 2 }, + { 3, "march", tMONTH, 3 }, + { 3, "april", tMONTH, 4 }, + { 3, "may", tMONTH, 5 }, + { 3, "june", tMONTH, 6 }, + { 3, "july", tMONTH, 7 }, + { 3, "august", tMONTH, 8 }, + { 3, "september", tMONTH, 9 }, + { 3, "october", tMONTH, 10 }, + { 3, "november", tMONTH, 11 }, + { 3, "december", tMONTH, 12 }, + + /* Days of the week. */ + { 2, "sunday", tDAY, 0 }, + { 3, "monday", tDAY, 1 }, + { 2, "tuesday", tDAY, 2 }, + { 3, "wednesday", tDAY, 3 }, + { 2, "thursday", tDAY, 4 }, + { 2, "friday", tDAY, 5 }, + { 2, "saturday", tDAY, 6 }, + + /* Timezones: Offsets are in minutes. */ + { 0, "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { 0, "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ + { 0, "utc", tZONE, HOUR( 0) }, + { 0, "wet", tZONE, HOUR( 0) }, /* Western European */ + { 0, "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { 0, "wat", tZONE, HOUR( 1) }, /* West Africa */ + { 0, "at", tZONE, HOUR( 2) }, /* Azores */ + /* { 0, "bst", tZONE, HOUR( 3) }, */ /* Brazil Standard: Conflict */ + /* { 0, "gst", tZONE, HOUR( 3) }, */ /* Greenland Standard: Conflict*/ + { 0, "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */ + { 0, "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */ + { 0, "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */ + { 0, "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { 0, "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { 0, "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { 0, "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { 0, "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { 0, "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { 0, "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { 0, "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { 0, "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { 0, "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { 0, "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { 0, "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { 0, "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { 0, "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ + { 0, "cat", tZONE, HOUR(10) }, /* Central Alaska */ + { 0, "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ + { 0, "nt", tZONE, HOUR(11) }, /* Nome */ + { 0, "idlw", tZONE, HOUR(12) }, /* Intl Date Line West */ + { 0, "cet", tZONE, -HOUR(1) }, /* Central European */ + { 0, "met", tZONE, -HOUR(1) }, /* Middle European */ + { 0, "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { 0, "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { 0, "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { 0, "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { 0, "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { 0, "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { 0, "eet", tZONE, -HOUR(2) }, /* Eastern Eur, USSR Zone 1 */ + { 0, "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ + { 0, "it", tZONE, -HOUR(3)-30 },/* Iran */ + { 0, "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { 0, "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ + { 0, "ist", tZONE, -HOUR(5)-30 },/* Indian Standard */ + { 0, "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ + /* { 0, "nst", tZONE, -HOUR(6.5) }, */ /* North Sumatra: Conflict */ + /* { 0, "sst", tZONE, -HOUR(7) }, */ /* So Sumatra, USSR 6: Conflict */ + { 0, "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ + { 0, "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ + { 0, "jt", tZONE, -HOUR(7)-30 },/* Java (3pm in Cronusland!)*/ + { 0, "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ + { 0, "jst", tZONE, -HOUR(9) }, /* Japan Std, USSR Zone 8 */ + { 0, "cast", tZONE, -HOUR(9)-30 },/* Central Australian Std */ + { 0, "cadt", tDAYZONE, -HOUR(9)-30 },/* Central Australian Daylt */ + { 0, "east", tZONE, -HOUR(10) }, /* Eastern Australian Std */ + { 0, "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylt */ + { 0, "gst", tZONE, -HOUR(10) }, /* Guam Std, USSR Zone 9 */ + { 0, "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { 0, "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { 0, "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + { 0, "idle", tZONE, -HOUR(12) }, /* Intl Date Line East */ + + { 0, "dst", tDST, 0 }, + + /* Time units. */ + { 4, "years", tMONTH_UNIT, 12 }, + { 5, "months", tMONTH_UNIT, 1 }, + { 9, "fortnights", tSEC_UNIT, 14 * 24 * 60 * 60 }, + { 4, "weeks", tSEC_UNIT, 7 * 24 * 60 * 60 }, + { 3, "days", tSEC_UNIT, 1 * 24 * 60 * 60 }, + { 4, "hours", tSEC_UNIT, 60 * 60 }, + { 3, "minutes", tSEC_UNIT, 60 }, + { 3, "seconds", tSEC_UNIT, 1 }, + + /* Relative-time words. */ + { 0, "tomorrow", tSEC_UNIT, 1 * 24 * 60 * 60 }, + { 0, "yesterday", tSEC_UNIT, -1 * 24 * 60 * 60 }, + { 0, "today", tSEC_UNIT, 0 }, + { 0, "now", tSEC_UNIT, 0 }, + { 0, "last", tUNUMBER, -1 }, + { 0, "this", tSEC_UNIT, 0 }, + { 0, "next", tUNUMBER, 2 }, + { 0, "first", tUNUMBER, 1 }, + { 0, "1st", tUNUMBER, 1 }, +/* { 0, "second", tUNUMBER, 2 }, */ + { 0, "2nd", tUNUMBER, 2 }, + { 0, "third", tUNUMBER, 3 }, + { 0, "3rd", tUNUMBER, 3 }, + { 0, "fourth", tUNUMBER, 4 }, + { 0, "4th", tUNUMBER, 4 }, + { 0, "fifth", tUNUMBER, 5 }, + { 0, "5th", tUNUMBER, 5 }, + { 0, "sixth", tUNUMBER, 6 }, + { 0, "seventh", tUNUMBER, 7 }, + { 0, "eighth", tUNUMBER, 8 }, + { 0, "ninth", tUNUMBER, 9 }, + { 0, "tenth", tUNUMBER, 10 }, + { 0, "eleventh", tUNUMBER, 11 }, + { 0, "twelfth", tUNUMBER, 12 }, + { 0, "ago", tAGO, 1 }, + + /* Military timezones. */ + { 0, "a", tZONE, HOUR( 1) }, + { 0, "b", tZONE, HOUR( 2) }, + { 0, "c", tZONE, HOUR( 3) }, + { 0, "d", tZONE, HOUR( 4) }, + { 0, "e", tZONE, HOUR( 5) }, + { 0, "f", tZONE, HOUR( 6) }, + { 0, "g", tZONE, HOUR( 7) }, + { 0, "h", tZONE, HOUR( 8) }, + { 0, "i", tZONE, HOUR( 9) }, + { 0, "k", tZONE, HOUR( 10) }, + { 0, "l", tZONE, HOUR( 11) }, + { 0, "m", tZONE, HOUR( 12) }, + { 0, "n", tZONE, HOUR(- 1) }, + { 0, "o", tZONE, HOUR(- 2) }, + { 0, "p", tZONE, HOUR(- 3) }, + { 0, "q", tZONE, HOUR(- 4) }, + { 0, "r", tZONE, HOUR(- 5) }, + { 0, "s", tZONE, HOUR(- 6) }, + { 0, "t", tZONE, HOUR(- 7) }, + { 0, "u", tZONE, HOUR(- 8) }, + { 0, "v", tZONE, HOUR(- 9) }, + { 0, "w", tZONE, HOUR(-10) }, + { 0, "x", tZONE, HOUR(-11) }, + { 0, "y", tZONE, HOUR(-12) }, + { 0, "z", tZONE, HOUR( 0) }, + + /* End of table. */ + { 0, NULL, 0, 0 } +}; + + + + +/* ARGSUSED */ +static int +yyerror(const char *s) +{ + (void)s; + return 0; +} + +static time_t +ToSeconds(time_t Hours, time_t Minutes, time_t Seconds) +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) + return -1; + if (Hours < 0 || Hours > 23) + return -1; + return (Hours * 60L + Minutes) * 60L + Seconds; +} + + +/* Year is either + * A number from 0 to 99, which means a year from 1970 to 2069, or + * The actual year (>=100). */ +static time_t +Convert(time_t Month, time_t Day, time_t Year, + time_t Hours, time_t Minutes, time_t Seconds, DSTMODE DSTmode) +{ + static int DaysInMonth[12] = { + 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + time_t tod; + time_t Julian; + int i; + + if (Year < 69) + Year += 2000; + else if (Year < 100) + Year += 1900; + DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) + ? 29 : 28; + /* Checking for 2038 bogusly assumes that time_t is 32 bits. But + I'm too lazy to try to check for time_t overflow in another way. */ + if (Year < EPOCH || Year > 2038 + || Month < 1 || Month > 12 + /* Lint fluff: "conversion from long may lose accuracy" */ + || Day < 1 || Day > DaysInMonth[(int)--Month]) + return -1; + + Julian = Day - 1; + for (i = 0; i < Month; i++) + Julian += DaysInMonth[i]; + for (i = EPOCH; i < Year; i++) + Julian += 365 + (i % 4 == 0); + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds)) < 0) + return -1; + Julian += tod; + if (DSTmode == DSTon + || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) + Julian -= 60 * 60; + return Julian; +} + + +static time_t +DSTcorrect(time_t Start, time_t Future) +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; +} + + +static time_t +RelativeDate(time_t Start, time_t DayOrdinal, time_t DayNumber) +{ + struct tm *tm; + time_t now; + + now = Start; + tm = localtime(&now); + now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); + now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); + return DSTcorrect(Start, now); +} + + +static time_t +RelativeMonth(time_t Start, time_t RelMonth) +{ + struct tm *tm; + time_t Month; + time_t Year; + + if (RelMonth == 0) + return 0; + tm = localtime(&Start); + Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth; + Year = Month / 12; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + DSTmaybe)); +} + +static int +yylex(void) +{ + char c; + char buff[64]; + + for ( ; ; ) { + while (isspace((unsigned char)*yyInput)) + yyInput++; + + /* Skip parenthesized comments. */ + if (*yyInput == '(') { + int Count = 0; + do { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } while (Count > 0); + continue; + } + + /* Try the next token in the word table first. */ + /* This allows us to match "2nd", for example. */ + { + char *src = yyInput; + const struct TABLE *tp; + unsigned i = 0; + + /* Force to lowercase and strip '.' characters. */ + while (*src != '\0' + && (isalnum((unsigned char)*src) || *src == '.') + && i < sizeof(buff)-1) { + if (*src != '.') { + if (isupper((unsigned char)*src)) + buff[i++] = tolower((unsigned char)*src); + else + buff[i++] = *src; + } + src++; + } + buff[i++] = '\0'; + + /* + * Find the first match. If the word can be + * abbreviated, make sure we match at least + * the minimum abbreviation. + */ + for (tp = TimeWords; tp->name; tp++) { + size_t abbrev = tp->abbrev; + if (abbrev == 0) + abbrev = strlen(tp->name); + if (strlen(buff) >= abbrev + && strncmp(tp->name, buff, strlen(buff)) + == 0) { + /* Skip over token. */ + yyInput = src; + /* Return the match. */ + yylval.Number = tp->value; + return tp->type; + } + } + } + + /* + * Not in the word table, maybe it's a number. Note: + * Because '-' and '+' have other special meanings, I + * don't deal with signed numbers here. + */ + if (isdigit((unsigned char)(c = *yyInput))) { + for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); ) + yylval.Number = 10 * yylval.Number + c - '0'; + yyInput--; + return (tUNUMBER); + } + + return (*yyInput++); + } +} + +#define TM_YEAR_ORIGIN 1900 + +/* Yield A - B, measured in seconds. */ +static long +difftm (struct tm *a, struct tm *b) +{ + int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); + int by = b->tm_year + (TM_YEAR_ORIGIN - 1); + int days = ( + /* difference in day of year */ + a->tm_yday - b->tm_yday + /* + intervening leap days */ + + ((ay >> 2) - (by >> 2)) + - (ay/100 - by/100) + + ((ay/100 >> 2) - (by/100 >> 2)) + /* + difference in years * 365 */ + + (long)(ay-by) * 365 + ); + return (60*(60*(24*days + (a->tm_hour - b->tm_hour)) + + (a->tm_min - b->tm_min)) + + (a->tm_sec - b->tm_sec)); +} + +time_t +get_date(char *p) +{ + struct tm *tm; + struct tm gmt, *gmt_ptr; + time_t Start; + time_t tod; + time_t nowtime; + long tzone; + + memset(&gmt, 0, sizeof(gmt)); + yyInput = p; + + (void)time (&nowtime); + + gmt_ptr = gmtime (&nowtime); + if (gmt_ptr != NULL) { + /* Copy, in case localtime and gmtime use the same buffer. */ + gmt = *gmt_ptr; + } + + if (! (tm = localtime (&nowtime))) + return -1; + + if (gmt_ptr != NULL) + tzone = difftm (&gmt, tm) / 60; + else + /* This system doesn't understand timezones; fake it. */ + tzone = 0; + if(tm->tm_isdst) + tzone += 60; + + yyYear = tm->tm_year + 1900; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; + yyTimezone = tzone; + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveDay = 0; + yyHaveRel = 0; + yyHaveTime = 0; + yyHaveZone = 0; + + if (yyparse() + || yyHaveTime > 1 || yyHaveZone > 1 + || yyHaveDate > 1 || yyHaveDay > 1) + return -1; + + if (yyHaveDate || yyHaveTime || yyHaveDay) { + Start = Convert(yyMonth, yyDay, yyYear, + yyHour, yyMinutes, yySeconds, yyDSTmode); + if (Start < 0) + return -1; + } else { + Start = nowtime; + if (!yyHaveRel) + Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; + } + + Start += yyRelSeconds; + Start += RelativeMonth(Start, yyRelMonth); + + if (yyHaveDay && !yyHaveDate) { + tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); + Start += tod; + } + + /* Have to do *something* with a legitimate -1 so it's + * distinguishable from the error return value. (Alternately + * could set errno on error.) */ + return Start == -1 ? 0 : Start; +} + + +#if defined(TEST) + +/* ARGSUSED */ +int +main(int argc, char **argv) +{ + time_t d; + + while (*++argv != NULL) { + (void)printf("Input: %s\n", *argv); + d = get_date(*argv); + if (d == -1) + (void)printf("Bad format - couldn't convert.\n"); + else + (void)printf("Output: %s\n", ctime(&d)); + } + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ diff --git a/libarchive/libarchive-2.4.17/tar/matching.c b/libarchive/libarchive-2.4.17/tar/matching.c new file mode 100644 index 0000000..f0ca0c9 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/matching.c @@ -0,0 +1,421 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bsdtar_platform.h" +__FBSDID("$FreeBSD: src/usr.bin/tar/matching.c,v 1.11 2007/03/11 10:36:42 kientzle Exp $"); + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#include "bsdtar.h" + +struct match { + struct match *next; + int matches; + char pattern[1]; +}; + +struct matching { + struct match *exclusions; + int exclusions_count; + struct match *inclusions; + int inclusions_count; + int inclusions_unmatched_count; +}; + + +static void add_pattern(struct bsdtar *, struct match **list, + const char *pattern); +static int bsdtar_fnmatch(const char *p, const char *s); +static void initialize_matching(struct bsdtar *); +static int match_exclusion(struct match *, const char *pathname); +static int match_inclusion(struct match *, const char *pathname); + +/* + * The matching logic here needs to be re-thought. I started out to + * try to mimic gtar's matching logic, but it's not entirely + * consistent. In particular 'tar -t' and 'tar -x' interpret patterns + * on the command line as anchored, but --exclude doesn't. + */ + +/* + * Utility functions to manage exclusion/inclusion patterns + */ + +int +exclude(struct bsdtar *bsdtar, const char *pattern) +{ + struct matching *matching; + + if (bsdtar->matching == NULL) + initialize_matching(bsdtar); + matching = bsdtar->matching; + add_pattern(bsdtar, &(matching->exclusions), pattern); + matching->exclusions_count++; + return (0); +} + +int +exclude_from_file(struct bsdtar *bsdtar, const char *pathname) +{ + return (process_lines(bsdtar, pathname, &exclude)); +} + +int +include(struct bsdtar *bsdtar, const char *pattern) +{ + struct matching *matching; + + if (bsdtar->matching == NULL) + initialize_matching(bsdtar); + matching = bsdtar->matching; + add_pattern(bsdtar, &(matching->inclusions), pattern); + matching->inclusions_count++; + matching->inclusions_unmatched_count++; + return (0); +} + +int +include_from_file(struct bsdtar *bsdtar, const char *pathname) +{ + return (process_lines(bsdtar, pathname, &include)); +} + +static void +add_pattern(struct bsdtar *bsdtar, struct match **list, const char *pattern) +{ + struct match *match; + + match = malloc(sizeof(*match) + strlen(pattern) + 1); + if (match == NULL) + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + if (pattern[0] == '/') + pattern++; + strcpy(match->pattern, pattern); + /* Both "foo/" and "foo" should match "foo/bar". */ + if (match->pattern[strlen(match->pattern)-1] == '/') + match->pattern[strlen(match->pattern)-1] = '\0'; + match->next = *list; + *list = match; + match->matches = 0; +} + + +int +excluded(struct bsdtar *bsdtar, const char *pathname) +{ + struct matching *matching; + struct match *match; + struct match *matched; + + matching = bsdtar->matching; + if (matching == NULL) + return (0); + + /* Exclusions take priority */ + for (match = matching->exclusions; match != NULL; match = match->next){ + if (match_exclusion(match, pathname)) + return (1); + } + + /* Then check for inclusions */ + matched = NULL; + for (match = matching->inclusions; match != NULL; match = match->next){ + if (match_inclusion(match, pathname)) { + /* + * If this pattern has never been matched, + * then we're done. + */ + if (match->matches == 0) { + match->matches++; + matching->inclusions_unmatched_count++; + return (0); + } + /* + * Otherwise, remember the match but keep checking + * in case we can tick off an unmatched pattern. + */ + matched = match; + } + } + /* + * We didn't find a pattern that had never been matched, but + * we did find a match, so count it and exit. + */ + if (matched != NULL) { + matched->matches++; + return (0); + } + + /* If there were inclusions, default is to exclude. */ + if (matching->inclusions != NULL) + return (1); + + /* No explicit inclusions, default is to match. */ + return (0); +} + +/* + * This is a little odd, but it matches the default behavior of + * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' + * + */ +int +match_exclusion(struct match *match, const char *pathname) +{ + const char *p; + + if (*match->pattern == '*' || *match->pattern == '/') + return (bsdtar_fnmatch(match->pattern, pathname) == 0); + + for (p = pathname; p != NULL; p = strchr(p, '/')) { + if (*p == '/') + p++; + if (bsdtar_fnmatch(match->pattern, p) == 0) + return (1); + } + return (0); +} + +/* + * Again, mimic gtar: inclusions are always anchored (have to match + * the beginning of the path) even though exclusions are not anchored. + */ +int +match_inclusion(struct match *match, const char *pathname) +{ + return (bsdtar_fnmatch(match->pattern, pathname) == 0); +} + +void +cleanup_exclusions(struct bsdtar *bsdtar) +{ + struct match *p, *q; + + if (bsdtar->matching) { + p = bsdtar->matching->inclusions; + while (p != NULL) { + q = p; + p = p->next; + free(q); + } + p = bsdtar->matching->exclusions; + while (p != NULL) { + q = p; + p = p->next; + free(q); + } + free(bsdtar->matching); + } +} + +static void +initialize_matching(struct bsdtar *bsdtar) +{ + bsdtar->matching = malloc(sizeof(*bsdtar->matching)); + if (bsdtar->matching == NULL) + bsdtar_errc(bsdtar, 1, errno, "No memory"); + memset(bsdtar->matching, 0, sizeof(*bsdtar->matching)); +} + +int +unmatched_inclusions(struct bsdtar *bsdtar) +{ + struct matching *matching; + + matching = bsdtar->matching; + if (matching == NULL) + return (0); + return (matching->inclusions_unmatched_count); +} + + + +#if defined(HAVE_FNMATCH) && defined(HAVE_FNM_LEADING_DIR) + +/* Use system fnmatch() if it suits our needs. */ +/* On Linux, _GNU_SOURCE must be defined to get FNM_LEADING_DIR. */ +#define _GNU_SOURCE +#include <fnmatch.h> +static int +bsdtar_fnmatch(const char *pattern, const char *string) +{ + return (fnmatch(pattern, string, FNM_LEADING_DIR)); +} + +#else +/* + * The following was hacked from BSD C library + * code: src/lib/libc/gen/fnmatch.c,v 1.15 2002/02/01 + * + * In particular, most of the flags were ripped out: this always + * behaves like FNM_LEADING_DIR is set and other flags specified + * by POSIX are unset. + * + * Normally, I would not conditionally compile something like this: If + * I have to support it anyway, everyone may as well use it. ;-) + * However, the full POSIX spec for fnmatch() includes a lot of + * advanced character handling that I'm not ready to put in here, so + * it's probably best if people use a local version when it's available. + */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +static int +bsdtar_fnmatch(const char *pattern, const char *string) +{ + const char *saved_pattern; + int negate, matched; + char c; + + for (;;) { + switch (c = *pattern++) { + case '\0': + if (*string == '/' || *string == '\0') + return (0); + return (1); + case '?': + if (*string == '\0') + return (1); + ++string; + break; + case '*': + c = *pattern; + /* Collapse multiple stars. */ + while (c == '*') + c = *++pattern; + + /* Optimize for pattern with * at end. */ + if (c == '\0') + return (0); + + /* General case, use recursion. */ + while (*string != '\0') { + if (!bsdtar_fnmatch(pattern, string)) + return (0); + ++string; + } + return (1); + case '[': + if (*string == '\0') + return (1); + saved_pattern = pattern; + if (*pattern == '!' || *pattern == '^') { + negate = 1; + ++pattern; + } else + negate = 0; + matched = 0; + c = *pattern++; + do { + if (c == '\\') + c = *pattern++; + if (c == '\0') { + pattern = saved_pattern; + c = '['; + goto norm; + } + if (*pattern == '-') { + char c2 = *(pattern + 1); + if (c2 == '\0') { + pattern = saved_pattern; + c = '['; + goto norm; + } + if (c2 == ']') { + /* [a-] is not a range. */ + if (c == *string + || '-' == *string) + matched = 1; + pattern ++; + } else { + if (c <= *string + && *string <= c2) + matched = 1; + pattern += 2; + } + } else if (c == *string) + matched = 1; + c = *pattern++; + } while (c != ']'); + if (matched == negate) + return (1); + ++string; + break; + case '\\': + if ((c = *pattern++) == '\0') { + c = '\\'; + --pattern; + } + /* FALLTHROUGH */ + default: + norm: + if (c != *string) + return (1); + string++; + break; + } + } + /* NOTREACHED */ +} + +#endif diff --git a/libarchive/libarchive-2.4.17/tar/read.c b/libarchive/libarchive-2.4.17/tar/read.c new file mode 100644 index 0000000..edda317 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/read.c @@ -0,0 +1,358 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bsdtar_platform.h" +__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.35 2008/01/02 00:21:27 kientzle Exp $"); + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef MAJOR_IN_MKDEV +#include <sys/mkdev.h> +#elif defined(MAJOR_IN_SYSMACROS) +#include <sys/sysmacros.h> +#endif +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_GRP_H +#include <grp.h> +#endif +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "bsdtar.h" + +static void list_item_verbose(struct bsdtar *, FILE *, + struct archive_entry *); +static void read_archive(struct bsdtar *bsdtar, char mode); + +void +tar_mode_t(struct bsdtar *bsdtar) +{ + read_archive(bsdtar, 't'); +} + +void +tar_mode_x(struct bsdtar *bsdtar) +{ + read_archive(bsdtar, 'x'); +} + +/* + * Handle 'x' and 't' modes. + */ +static void +read_archive(struct bsdtar *bsdtar, char mode) +{ + FILE *out; + struct archive *a; + struct archive_entry *entry; + const struct stat *st; + int r; + + while (*bsdtar->argv) { + include(bsdtar, *bsdtar->argv); + bsdtar->argv++; + } + + if (bsdtar->names_from_file != NULL) + include_from_file(bsdtar, bsdtar->names_from_file); + + a = archive_read_new(); + if (bsdtar->compress_program != NULL) + archive_read_support_compression_program(a, bsdtar->compress_program); + else + archive_read_support_compression_all(a); + archive_read_support_format_all(a); + if (archive_read_open_file(a, bsdtar->filename, + bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block : + DEFAULT_BYTES_PER_BLOCK)) + bsdtar_errc(bsdtar, 1, 0, "Error opening archive: %s", + archive_error_string(a)); + + do_chdir(bsdtar); + for (;;) { + /* Support --fast-read option */ + if (bsdtar->option_fast_read && + unmatched_inclusions(bsdtar) == 0) + break; + + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_EOF) + break; + if (r < ARCHIVE_OK) + bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); + if (r <= ARCHIVE_WARN) + bsdtar->return_value = 1; + if (r == ARCHIVE_RETRY) { + /* Retryable error: try again */ + bsdtar_warnc(bsdtar, 0, "Retrying..."); + continue; + } + if (r == ARCHIVE_FATAL) + break; + + /* + * Exclude entries that are too old. + */ + st = archive_entry_stat(entry); + if (bsdtar->newer_ctime_sec > 0) { + if (st->st_ctime < bsdtar->newer_ctime_sec) + continue; /* Too old, skip it. */ + if (st->st_ctime == bsdtar->newer_ctime_sec + && ARCHIVE_STAT_CTIME_NANOS(st) + <= bsdtar->newer_ctime_nsec) + continue; /* Too old, skip it. */ + } + if (bsdtar->newer_mtime_sec > 0) { + if (st->st_mtime < bsdtar->newer_mtime_sec) + continue; /* Too old, skip it. */ + if (st->st_mtime == bsdtar->newer_mtime_sec + && ARCHIVE_STAT_MTIME_NANOS(st) + <= bsdtar->newer_mtime_nsec) + continue; /* Too old, skip it. */ + } + + /* + * Note that pattern exclusions are checked before + * pathname rewrites are handled. This gives more + * control over exclusions, since rewrites always lose + * information. (For example, consider a rewrite + * s/foo[0-9]/foo/. If we check exclusions after the + * rewrite, there would be no way to exclude foo1/bar + * while allowing foo2/bar.) + */ + if (excluded(bsdtar, archive_entry_pathname(entry))) + continue; /* Excluded by a pattern test. */ + + /* + * Modify the pathname as requested by the user. We + * do this for -t as well to give users a way to + * preview the effects of their rewrites. We also do + * this before extraction security checks (including + * leading '/' removal). Note that some rewrite + * failures prevent extraction. + */ + if (edit_pathname(bsdtar, entry)) + continue; /* Excluded by a rewrite failure. */ + + if (mode == 't') { + /* Perversely, gtar uses -O to mean "send to stderr" + * when used with -t. */ + out = bsdtar->option_stdout ? stderr : stdout; + + if (bsdtar->verbose < 2) + safe_fprintf(out, "%s", + archive_entry_pathname(entry)); + else + list_item_verbose(bsdtar, out, entry); + fflush(out); + r = archive_read_data_skip(a); + if (r == ARCHIVE_WARN) { + fprintf(out, "\n"); + bsdtar_warnc(bsdtar, 0, "%s", + archive_error_string(a)); + } + if (r == ARCHIVE_RETRY) { + fprintf(out, "\n"); + bsdtar_warnc(bsdtar, 0, "%s", + archive_error_string(a)); + } + if (r == ARCHIVE_FATAL) { + fprintf(out, "\n"); + bsdtar_warnc(bsdtar, 0, "%s", + archive_error_string(a)); + bsdtar->return_value = 1; + break; + } + fprintf(out, "\n"); + } else { + if (bsdtar->option_interactive && + !yes("extract '%s'", archive_entry_pathname(entry))) + continue; + + /* + * Format here is from SUSv2, including the + * deferred '\n'. + */ + if (bsdtar->verbose) { + safe_fprintf(stderr, "x %s", + archive_entry_pathname(entry)); + fflush(stderr); + } + if (bsdtar->option_stdout) + r = archive_read_data_into_fd(a, 1); + else + r = archive_read_extract(a, entry, + bsdtar->extract_flags); + if (r != ARCHIVE_OK) { + if (!bsdtar->verbose) + safe_fprintf(stderr, "%s", + archive_entry_pathname(entry)); + safe_fprintf(stderr, ": %s", + archive_error_string(a)); + if (!bsdtar->verbose) + fprintf(stderr, "\n"); + bsdtar->return_value = 1; + } + if (bsdtar->verbose) + fprintf(stderr, "\n"); + if (r == ARCHIVE_FATAL) + break; + } + } + + if (bsdtar->verbose > 2) + fprintf(stdout, "Archive Format: %s, Compression: %s\n", + archive_format_name(a), archive_compression_name(a)); + + archive_read_finish(a); +} + + +/* + * Display information about the current file. + * + * The format here roughly duplicates the output of 'ls -l'. + * This is based on SUSv2, where 'tar tv' is documented as + * listing additional information in an "unspecified format," + * and 'pax -l' is documented as using the same format as 'ls -l'. + */ +static void +list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) +{ + const struct stat *st; + char tmp[100]; + size_t w; + const char *p; + const char *fmt; + time_t tim; + static time_t now; + + st = archive_entry_stat(entry); + + /* + * We avoid collecting the entire list in memory at once by + * listing things as we see them. However, that also means we can't + * just pre-compute the field widths. Instead, we start with guesses + * and just widen them as necessary. These numbers are completely + * arbitrary. + */ + if (!bsdtar->u_width) { + bsdtar->u_width = 6; + bsdtar->gs_width = 13; + } + if (!now) + time(&now); + fprintf(out, "%s %d ", + archive_entry_strmode(entry), + (int)(st->st_nlink)); + + /* Use uname if it's present, else uid. */ + p = archive_entry_uname(entry); + if ((p == NULL) || (*p == '\0')) { + sprintf(tmp, "%lu ", (unsigned long)st->st_uid); + p = tmp; + } + w = strlen(p); + if (w > bsdtar->u_width) + bsdtar->u_width = w; + fprintf(out, "%-*s ", (int)bsdtar->u_width, p); + + /* Use gname if it's present, else gid. */ + p = archive_entry_gname(entry); + if (p != NULL && p[0] != '\0') { + fprintf(out, "%s", p); + w = strlen(p); + } else { + sprintf(tmp, "%lu", (unsigned long)st->st_gid); + w = strlen(tmp); + fprintf(out, "%s", tmp); + } + + /* + * Print device number or file size, right-aligned so as to make + * total width of group and devnum/filesize fields be gs_width. + * If gs_width is too small, grow it. + */ + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { + sprintf(tmp, "%lu,%lu", + (unsigned long)major(st->st_rdev), + (unsigned long)minor(st->st_rdev)); /* ls(1) also casts here. */ + } else { + /* + * Note the use of platform-dependent macros to format + * the filesize here. We need the format string and the + * corresponding type for the cast. + */ + sprintf(tmp, BSDTAR_FILESIZE_PRINTF, + (BSDTAR_FILESIZE_TYPE)st->st_size); + } + if (w + strlen(tmp) >= bsdtar->gs_width) + bsdtar->gs_width = w+strlen(tmp)+1; + fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp); + + /* Format the time using 'ls -l' conventions. */ + tim = (time_t)st->st_mtime; + if (abs(tim - now) > (365/2)*86400) + fmt = bsdtar->day_first ? "%e %b %Y" : "%b %e %Y"; + else + fmt = bsdtar->day_first ? "%e %b %R" : "%b %e %R"; + strftime(tmp, sizeof(tmp), fmt, localtime(&tim)); + fprintf(out, " %s ", tmp); + safe_fprintf(out, "%s", archive_entry_pathname(entry)); + + /* Extra information for links. */ + if (archive_entry_hardlink(entry)) /* Hard link */ + safe_fprintf(out, " link to %s", + archive_entry_hardlink(entry)); + else if (S_ISLNK(st->st_mode)) /* Symbolic link */ + safe_fprintf(out, " -> %s", archive_entry_symlink(entry)); +} diff --git a/libarchive/libarchive-2.4.17/tar/test/main.c b/libarchive/libarchive-2.4.17/tar/test/main.c new file mode 100644 index 0000000..263e2cb --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/main.c @@ -0,0 +1,766 @@ +/* + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This same file is used pretty much verbatim for all test harnesses. + * + * The next line is used to define various environment variables, etc. + * + * The tar and cpio test harnesses are identical except for this line; + * the libarchive test harness omits some code that is needed only for + * testing standalone executables. + */ +#define PROGRAM "BSDTAR" + +/* + * Various utility routines useful for test programs. + * Each test program is linked against this file. + */ +#include <errno.h> +#include <stdarg.h> +#include <time.h> + +#include "test.h" +__FBSDID("$FreeBSD$"); + +/* + * "list.h" is simply created by "grep DEFINE_TEST"; it has + * a line like + * DEFINE_TEST(test_function) + * for each test. + * Include it here with a suitable DEFINE_TEST to declare all of the + * test functions. + */ +#undef DEFINE_TEST +#define DEFINE_TEST(name) void name(void); +#include "list.h" + +/* Interix doesn't define these in a standard header. */ +#if __INTERIX__ +extern char *optarg; +extern int optind; +#endif + +/* Default is to crash and try to force a core dump on failure. */ +static int dump_on_failure = 1; +/* Default is to print some basic information about each test. */ +static int quiet_flag = 0; +/* Cumulative count of component failures. */ +static int failures = 0; +/* Cumulative count of skipped component tests. */ +static int skips = 0; +/* Cumulative count of assertions. */ +static int assertions = 0; + +/* + * My own implementation of the standard assert() macro emits the + * message in the same format as GCC (file:line: message). + * It also includes some additional useful information. + * This makes it a lot easier to skim through test failures in + * Emacs. ;-) + * + * It also supports a few special features specifically to simplify + * test harnesses: + * failure(fmt, args) -- Stores a text string that gets + * printed if the following assertion fails, good for + * explaining subtle tests. + */ +static char msg[4096]; + +/* + * For each test source file, we remember how many times each + * failure was reported. + */ +static const char *failed_filename; +static struct line { + int line; + int count; +} failed_lines[1000]; + +/* + * Count this failure; return the number of previous failures. + */ +static int +previous_failures(const char *filename, int line) +{ + unsigned int i; + int count; + + if (failed_filename == NULL || strcmp(failed_filename, filename) != 0) + memset(failed_lines, 0, sizeof(failed_lines)); + failed_filename = filename; + + for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { + if (failed_lines[i].line == line) { + count = failed_lines[i].count; + failed_lines[i].count++; + return (count); + } + if (failed_lines[i].line == 0) { + failed_lines[i].line = line; + failed_lines[i].count = 1; + return (0); + } + } + return (0); +} + +/* + * Copy arguments into file-local variables. + */ +static const char *test_filename; +static int test_line; +static void *test_extra; +void test_setup(const char *filename, int line) +{ + test_filename = filename; + test_line = line; +} + +/* + * Inform user that we're skipping a test. + */ +void +test_skipping(const char *fmt, ...) +{ + va_list ap; + + if (previous_failures(test_filename, test_line)) + return; + + va_start(ap, fmt); + fprintf(stderr, " *** SKIPPING: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + ++skips; +} + +/* Common handling of failed tests. */ +static void +report_failure(void *extra) +{ + if (msg[0] != '\0') { + fprintf(stderr, " Description: %s\n", msg); + msg[0] = '\0'; + } + + (void)extra; /* UNUSED */ + + if (dump_on_failure) { + fprintf(stderr, + " *** forcing core dump so failure can be debugged ***\n"); + *(char *)(NULL) = 0; + exit(1); + } +} + +/* + * Summarize repeated failures in the just-completed test file. + * The reports above suppress multiple failures from the same source + * line; this reports on any tests that did fail multiple times. + */ +static int +summarize_comparator(const void *a0, const void *b0) +{ + const struct line *a = a0, *b = b0; + if (a->line == 0 && b->line == 0) + return (0); + if (a->line == 0) + return (1); + if (b->line == 0) + return (-1); + return (a->line - b->line); +} + +static void +summarize(void) +{ + unsigned int i; + + qsort(failed_lines, sizeof(failed_lines)/sizeof(failed_lines[0]), + sizeof(failed_lines[0]), summarize_comparator); + for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { + if (failed_lines[i].line == 0) + break; + if (failed_lines[i].count > 1) + fprintf(stderr, "%s:%d: Failed %d times\n", + failed_filename, failed_lines[i].line, + failed_lines[i].count); + } + /* Clear the failure history for the next file. */ + memset(failed_lines, 0, sizeof(failed_lines)); +} + +/* Set up a message to display only after a test fails. */ +void +failure(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vsprintf(msg, fmt, ap); + va_end(ap); +} + +/* Generic assert() just displays the failed condition. */ +void +test_assert(const char *file, int line, int value, const char *condition, void *extra) +{ + ++assertions; + if (value) { + msg[0] = '\0'; + return; + } + failures ++; + if (previous_failures(file, line)) + return; + fprintf(stderr, "%s:%d: Assertion failed\n", file, line); + fprintf(stderr, " Condition: %s\n", condition); + report_failure(extra); +} + +/* assertEqualInt() displays the values of the two integers. */ +void +test_assert_equal_int(const char *file, int line, + int v1, const char *e1, int v2, const char *e2, void *extra) +{ + ++assertions; + if (v1 == v2) { + msg[0] = '\0'; + return; + } + failures ++; + if (previous_failures(file, line)) + return; + fprintf(stderr, "%s:%d: Assertion failed: Ints not equal\n", + file, line); + fprintf(stderr, " %s=%d\n", e1, v1); + fprintf(stderr, " %s=%d\n", e2, v2); + report_failure(extra); +} + +/* assertEqualString() displays the values of the two strings. */ +void +test_assert_equal_string(const char *file, int line, + const char *v1, const char *e1, + const char *v2, const char *e2, + void *extra) +{ + ++assertions; + if (v1 == NULL || v2 == NULL) { + if (v1 == v2) { + msg[0] = '\0'; + return; + } + } else if (strcmp(v1, v2) == 0) { + msg[0] = '\0'; + return; + } + failures ++; + if (previous_failures(file, line)) + return; + fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n", + file, line); + fprintf(stderr, " %s = \"%s\"\n", e1, v1); + fprintf(stderr, " %s = \"%s\"\n", e2, v2); + report_failure(extra); +} + +static void wcsdump(const wchar_t *w) +{ + if (w == NULL) { + fprintf(stderr, "(null)"); + return; + } + fprintf(stderr, "\""); + while (*w != L'\0') { + unsigned int c = *w++; + if (c >= 32 && c < 127) + fprintf(stderr, "%c", c); + else if (c < 256) + fprintf(stderr, "\\x%02X", c); + else if (c < 0x10000) + fprintf(stderr, "\\u%04X", c); + else + fprintf(stderr, "\\U%08X", c); + } + fprintf(stderr, "\""); +} + +/* assertEqualWString() displays the values of the two strings. */ +void +test_assert_equal_wstring(const char *file, int line, + const wchar_t *v1, const char *e1, + const wchar_t *v2, const char *e2, + void *extra) +{ + ++assertions; + if (v1 == NULL) { + if (v2 == NULL) { + msg[0] = '\0'; + return (1); + } + } else if (v2 == NULL) { + if (v1 == NULL) { + msg[0] = '\0'; + return (1); + } + } else if (wcscmp(v1, v2) == 0) { + msg[0] = '\0'; + return; + } + failures ++; + if (previous_failures(file, line)) + return; + fprintf(stderr, "%s:%d: Assertion failed: Unicode strings not equal\n", + file, line); + fprintf(stderr, " %s = ", e1); + wcsdump(v1); + fprintf(stderr, "\n"); + fprintf(stderr, " %s = ", e2); + wcsdump(v2); + fprintf(stderr, "\n"); + report_failure(extra); +} + +/* + * Pretty standard hexdump routine. As a bonus, if ref != NULL, then + * any bytes in p that differ from ref will be highlighted with '_' + * before and after the hex value. + */ +static void +hexdump(const char *p, const char *ref, size_t l, size_t offset) +{ + size_t i, j; + char sep; + + for(i=0; i < l; i+=16) { + fprintf(stderr, "%04x", i + offset); + sep = ' '; + for (j = 0; j < 16 && i + j < l; j++) { + if (ref != NULL && p[i + j] != ref[i + j]) + sep = '_'; + fprintf(stderr, "%c%02x", sep, p[i+j]); + if (ref != NULL && p[i + j] == ref[i + j]) + sep = ' '; + } + for (; j < 16; j++) { + fprintf(stderr, "%c ", sep); + sep = ' '; + } + fprintf(stderr, "%c", sep); + for (j=0; j < 16 && i + j < l; j++) { + int c = p[i + j]; + if (c >= ' ' && c <= 126) + fprintf(stderr, "%c", c); + else + fprintf(stderr, "."); + } + fprintf(stderr, "\n"); + } +} + +/* assertEqualMem() displays the values of the two memory blocks. */ +/* TODO: For long blocks, hexdump the first bytes that actually differ. */ +void +test_assert_equal_mem(const char *file, int line, + const char *v1, const char *e1, + const char *v2, const char *e2, + size_t l, const char *ld, void *extra) +{ + ++assertions; + if (v1 == NULL || v2 == NULL) { + if (v1 == v2) { + msg[0] = '\0'; + return; + } + } else if (memcmp(v1, v2, l) == 0) { + msg[0] = '\0'; + return; + } + failures ++; + if (previous_failures(file, line)) + return; + fprintf(stderr, "%s:%d: Assertion failed: memory not equal\n", + file, line); + fprintf(stderr, " size %s = %d\n", ld, (int)l); + fprintf(stderr, " Dump of %s\n", e1); + hexdump(v1, v2, l < 32 ? l : 32, 0); + fprintf(stderr, " Dump of %s\n", e2); + hexdump(v2, v1, l < 32 ? l : 32, 0); + fprintf(stderr, "\n"); + report_failure(extra); +} + +void +test_assert_empty_file(const char *f1fmt, ...) +{ + char f1[1024]; + struct stat st; + va_list ap; + + va_start(ap, f1fmt); + vsprintf(f1, f1fmt, ap); + va_end(ap); + + if (stat(f1, &st) != 0) { + fprintf(stderr, "%s:%d: Could not stat: %s\n", test_filename, test_line, f1); + report_failure(NULL); + } else if (st.st_size > 0) { + fprintf(stderr, "%s:%d: File not empty: %s\n", test_filename, test_line, f1); + fprintf(stderr, " File size: %d\n", (int)st.st_size); + report_failure(NULL); + } +} + +/* assertEqualFile() asserts that two files have the same contents. */ +/* TODO: hexdump the first bytes that actually differ. */ +void +test_assert_equal_file(const char *f1, const char *f2pattern, ...) +{ + char f2[1024]; + va_list ap; + char buff1[1024]; + char buff2[1024]; + int fd1, fd2; + int n1, n2; + + va_start(ap, f2pattern); + vsprintf(f2, f2pattern, ap); + va_end(ap); + + fd1 = open(f1, O_RDONLY); + fd2 = open(f2, O_RDONLY); + for (;;) { + n1 = read(fd1, buff1, sizeof(buff1)); + n2 = read(fd2, buff2, sizeof(buff2)); + if (n1 != n2) + break; + if (n1 == 0 && n2 == 0) + return; + if (memcmp(buff1, buff2, n1) != 0) + break; + } + fprintf(stderr, "%s:%d: Files are not identical\n", test_filename, test_line); + fprintf(stderr, " file1=\"%s\"\n", f1); + fprintf(stderr, " file2=\"%s\"\n", f2); + report_failure(test_extra); +} + + +/* + * Call standard system() call, but build up the command line using + * sprintf() conventions. + */ +int +systemf(const char *fmt, ...) +{ + char buff[8192]; + va_list ap; + int r; + + va_start(ap, fmt); + vsprintf(buff, fmt, ap); + r = system(buff); + va_end(ap); + return (r); +} + +/* + * Slurp a file into memory for ease of comparison and testing. + * Returns size of file in 'sizep' if non-NULL, null-terminates + * data in memory for ease of use. + */ +char * +slurpfile(size_t * sizep, const char *fmt, ...) +{ + char filename[8192]; + struct stat st; + va_list ap; + char *p; + ssize_t bytes_read; + int fd; + int r; + + va_start(ap, fmt); + vsprintf(filename, fmt, ap); + va_end(ap); + + fd = open(filename, O_RDONLY); + if (fd < 0) { + /* Note: No error; non-existent file is okay here. */ + return (NULL); + } + r = fstat(fd, &st); + if (r != 0) { + fprintf(stderr, "Can't stat file %s\n", filename); + close(fd); + return (NULL); + } + p = malloc(st.st_size + 1); + if (p == NULL) { + fprintf(stderr, "Can't allocate %ld bytes of memory to read file %s\n", (long int)st.st_size, filename); + close(fd); + return (NULL); + } + bytes_read = read(fd, p, st.st_size); + if (bytes_read < st.st_size) { + fprintf(stderr, "Can't read file %s\n", filename); + close(fd); + free(p); + return (NULL); + } + p[st.st_size] = '\0'; + if (sizep != NULL) + *sizep = (size_t)st.st_size; + close(fd); + return (p); +} + +/* + * "list.h" is automatically generated; it just has a lot of lines like: + * DEFINE_TEST(function_name) + * It's used above to declare all of the test functions. + * We reuse it here to define a list of all tests (functions and names). + */ +#undef DEFINE_TEST +#define DEFINE_TEST(n) { n, #n }, +struct { void (*func)(void); const char *name; } tests[] = { + #include "list.h" +}; + +/* + * Each test is run in a private work dir. Those work dirs + * do have consistent and predictable names, in case a group + * of tests need to collaborate. However, there is no provision + * for requiring that tests run in a certain order. + */ +static int test_run(int i, const char *tmpdir) +{ + int failures_before = failures; + + if (!quiet_flag) + printf("%d: %s\n", i, tests[i].name); + /* + * Always explicitly chdir() in case the last test moved us to + * a strange place. + */ + if (chdir(tmpdir)) { + fprintf(stderr, + "ERROR: Couldn't chdir to temp dir %s\n", + tmpdir); + exit(1); + } + /* Create a temp directory for this specific test. */ + if (mkdir(tests[i].name, 0755)) { + fprintf(stderr, + "ERROR: Couldn't create temp dir ``%s''\n", + tests[i].name); + exit(1); + } + /* Chdir() to that work directory. */ + if (chdir(tests[i].name)) { + fprintf(stderr, + "ERROR: Couldn't chdir to temp dir ``%s''\n", + tests[i].name); + exit(1); + } + /* Run the actual test. */ + (*tests[i].func)(); + /* Summarize the results of this test. */ + summarize(); + /* Return appropriate status. */ + return (failures == failures_before ? 0 : 1); +} + +static void usage(const char *program) +{ + static const int limit = sizeof(tests) / sizeof(tests[0]); + int i; + + printf("Usage: %s [options] <test> <test> ...\n", program); + printf("Default is to run all tests.\n"); + printf("Otherwise, specify the numbers of the tests you wish to run.\n"); + printf("Options:\n"); + printf(" -k Keep running after failures.\n"); + printf(" Default: Core dump after any failure.\n"); + printf(" -p <path> Path to executable to be tested.\n"); + printf(" Default: path taken from " PROGRAM " environment variable.\n"); + printf(" -q Quiet.\n"); + printf(" -r <dir> Path to dir containing reference files.\n"); + printf(" Default: Current directory.\n"); + printf("Available tests:\n"); + for (i = 0; i < limit; i++) + printf(" %d: %s\n", i, tests[i].name); + exit(1); +} + +int main(int argc, char **argv) +{ + static const int limit = sizeof(tests) / sizeof(tests[0]); + int i, tests_run = 0, tests_failed = 0, opt; + time_t now; + char *refdir_alloc = NULL; + char *progname, *p; + char tmpdir[256]; + char tmpdir_timestamp[256]; + + /* + * Name of this program, used to build root of our temp directory + * tree. + */ + progname = p = argv[0]; + while (*p != '\0') { + if (*p == '/') + progname = p + 1; + ++p; + } + + /* Get the target program from environment, if available. */ + testprog = getenv(PROGRAM); + + /* Allow -k to be controlled through the environment. */ + if (getenv(PROGRAM "_KEEP_GOING") != NULL) + dump_on_failure = 0; + + /* Get the directory holding test files from environment. */ + refdir = getenv(PROGRAM "_TEST_FILES"); + + /* + * Parse options. + */ + while ((opt = getopt(argc, argv, "kp:qr:")) != -1) { + switch (opt) { + case 'k': + dump_on_failure = 0; + break; + case 'p': + testprog = optarg; + break; + case 'q': + quiet_flag++; + break; + case 'r': + refdir = optarg; + break; + case '?': + default: + usage(progname); + } + } + argc -= optind; + argv += optind; + + /* + * Sanity-check that our options make sense. + */ + if (testprog == NULL) + usage(progname); + + + /* + * Create a temp directory for the following tests. + * Include the time the tests started as part of the name, + * to make it easier to track the results of multiple tests. + */ + now = time(NULL); + for (i = 0; i < 1000; i++) { + strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp), + "%Y-%m-%dT%H.%M.%S", + localtime(&now)); + sprintf(tmpdir, "/tmp/%s.%s-%03d", progname, tmpdir_timestamp, i); + if (mkdir(tmpdir,0755) == 0) + break; + if (errno == EEXIST) + continue; + fprintf(stderr, "ERROR: Unable to create temp directory %s\n", + tmpdir); + exit(1); + } + + /* + * If the user didn't specify a directory for locating + * reference files, use the current directory for that. + */ + if (refdir == NULL) { + systemf("/bin/pwd > %s/refdir", tmpdir); + refdir = refdir_alloc = slurpfile(NULL, "%s/refdir", tmpdir); + p = refdir + strlen(refdir); + while (p[-1] == '\n') { + --p; + *p = '\0'; + } + } + + /* + * Banner with basic information. + */ + if (!quiet_flag) { + printf("Running tests in: %s\n", tmpdir); + printf("Reference files will be read from: %s\n", refdir); + printf("Running tests on: %s\n", testprog); + } + + /* + * Run some or all of the individual tests. + */ + if (argc == 0) { + /* Default: Run all tests. */ + for (i = 0; i < limit; i++) { + if (test_run(i, tmpdir)) + tests_failed++; + tests_run++; + } + } else { + while (*(argv) != NULL) { + i = atoi(*argv); + if (**argv < '0' || **argv > '9' || i < 0 || i >= limit) { + printf("*** INVALID Test %s\n", *argv); + usage(progname); + } else { + if (test_run(i, tmpdir)) + tests_failed++; + tests_run++; + } + argv++; + } + } + + /* + * Report summary statistics. + */ + if (!quiet_flag) { + printf("\n"); + printf("%d of %d tests reported failures\n", + tests_failed, tests_run); + printf(" Total of %d assertions checked.\n", assertions); + printf(" Total of %d assertions failed.\n", failures); + printf(" Total of %d assertions skipped.\n", skips); + } + + free(refdir_alloc); + + return (tests_failed); +} diff --git a/libarchive/libarchive-2.4.17/tar/test/old/config.sh b/libarchive/libarchive-2.4.17/tar/test/old/config.sh new file mode 100755 index 0000000..2d884f8 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/old/config.sh @@ -0,0 +1,75 @@ +# +# Copyright (c) 2007 Tim Kientzle +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD: src/usr.bin/tar/test/config.sh,v 1.2 2007/03/11 19:33:45 kientzle Exp $ + +THISDIR=`cd \`dirname $0\`;/bin/pwd` + +# TESTDIR defaults to /tmp/bsdtar- + the name of the script +if [ -z "$TESTDIR" ]; then + TESTDIR=/tmp/bsdtar-`echo $0 | sed -e 's|.*/||' -e 's|\.sh||' -e 's/[^a-z0-9_-]/_/g'` +fi + +# Find bsdtar +# The first three paths here are the usual locations of a bsdtar +# that has just been built. The remaining paths might find a bsdtar +# installed on the local system somewhere. +if [ -z "$BSDTAR" ]; then + for T in "$THISDIR/../bsdtar" "$THISDIR/../../bsdtar" \ + "/usr/obj`dirname $THISDIR`/bsdtar" "/usr/local/bin/bsdtar" \ + "/usr/bin/bsdtar" "/usr/bin/tar" "bsdtar" "tar" + do + if ( /bin/sh -c "$T --version" | grep "bsdtar" ) >/dev/null 2>&1; then + BSDTAR="$T" + break + fi + done +fi + +# Find GNU tar +if [ -z "$GTAR" ]; then + for T in gtar gnutar tar /usr/local/bin/gtar* /usr/local/bin/gnutar* /usr/bin/gtar* /usr/bin/gnutar* + do + if ( /bin/sh -c "$T --version" | grep "GNU tar" ) >/dev/null 2>&1; then + GTAR="$T" + break + fi + done +fi + +# Find CPIO +if [ -z "$CPIO" ]; then + CPIO=cpio +fi + +echo BSDTAR=$BSDTAR '('`$BSDTAR --version`')' +echo GTAR=$GTAR '('`$GTAR --version | head -n 1`')' +echo CPIO=$CPIO '('`$CPIO --version`')' + +# Remove and recreate the directory we'll use for these tests +rm -rf $TESTDIR +mkdir -p $TESTDIR || exit 1 +cd $TESTDIR || exit 1 +echo TESTDIR=$TESTDIR + diff --git a/libarchive/libarchive-2.4.17/tar/test/old/test-acl.sh b/libarchive/libarchive-2.4.17/tar/test/old/test-acl.sh new file mode 100755 index 0000000..818607d --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/old/test-acl.sh @@ -0,0 +1,76 @@ +#!/bin/sh +# Copyright (c) 2007 Tim Kientzle +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD: src/usr.bin/tar/test/test-acl.sh,v 1.1 2007/03/11 10:36:42 kientzle Exp $ + +# Exercise copying of ACLs +echo "ACL handling" +# Basic test configuration +TESTDIR=/mnt/da0/acl-test +. `dirname $0`/config.sh + +# Create some files with ACLs +mkdir original +cd original +touch a +chmod 664 a +setfacl -m user:bin:rw- -m group:78:r-x a \ + || echo XXX failed to set access ACL on a XXX +mkdir d +chmod 775 d +setfacl -m user:daemon:rw- -m group:78:r-x d \ + || echo XXX failed to set access ACL on d XXX +setfacl -d -m user::rw- -m group::rw- -m other::rw- -m group:79:r-- d \ + || echo XXX failed to set default ACL on d XXX +cd .. + +# Copy the dir with -p +echo " -p preserves ACLs" +mkdir copy +(cd original && ${BSDTAR} -cf - .) | (cd copy; ${BSDTAR} -xpf -) + +# Verify the ACLs +cd copy +if [ "user::rw- user:bin:rw- group::rw- group:78:r-x mask::rwx other::r--" \ + = "`echo \`getfacl -q a\``" ]; then + # It matches!! +else + echo XXX a has wrong ACL XXX `getfacl -q a` +fi + +if [ "user::rwx user:daemon:rw- group::rwx group:78:r-x mask::rwx other::r-x" \ + = "`echo \`getfacl -q d\``" ]; then + # It matches!! +else + echo XXX d has wrong ACL XXX `getfacl -q d` +fi + + +if [ "user::rw- group::rw- group:79:r-- mask::rw- other::rw-" \ + = "`echo \`getfacl -q -d d\``" ]; then + # It matches!! +else + echo XXX d has wrong ACL XXX `getfacl -q -d d` +fi + diff --git a/libarchive/libarchive-2.4.17/tar/test/old/test-basic.sh b/libarchive/libarchive-2.4.17/tar/test/old/test-basic.sh new file mode 100755 index 0000000..0564bc7 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/old/test-basic.sh @@ -0,0 +1,432 @@ +#!/bin/sh +# Copyright (c) 2007 Tim Kientzle +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD: src/usr.bin/tar/test/test-basic.sh,v 1.5 2007/04/18 04:35:17 kientzle Exp $ + +# Generate a dir tree with various data and copy it using +# a variety of tools and flags. This mostly checks that +# we can read archives we write and those written by gtar +# and cpio. + +echo "Basic archiving/copy interoperability tests" +# Basic configuration +. `dirname $0`/config.sh + +# We need some files to archive; generate some random files and files +# with very long names and other special attributes +mkdir -p original +cd original +# Create some long files with random text data +for f in f0 f1 f2 f3 f4 f5 f6 f7 f8 f9; do + dd if=/dev/urandom bs=1k count=100 2>/dev/null | od > $f +done +# A sparse file +dd if=/dev/zero of=sparse bs=1 count=1 oseek=100000 2>/dev/null +# Files with long names +touch a +touch ab +touch abc +touch abcd +touch abcde +touch abcdef +touch abcdefg +touch abcdefgh +touch abcdefghi +touch abcdefghij +touch abcdefghijk +touch abcdefghijkl +touch abcdefghijklm +touch abcdefghijklmn +touch abcdefghijklmno +touch abcdefghijklmnop +touch abcdefghijklmnopq +touch abcdefghijklmnopqr +touch abcdefghijklmnopqrs +touch abcdefghijklmnopqrst +touch abcdefghijklmnopqrstu +touch abcdefghijklmnopqrstuv +touch abcdefghijklmnopqrstuvw +touch abcdefghijklmnopqrstuvwx +touch abcdefghijklmnopqrstuvwxy +touch abcdefghijklmnopqrstuvwxyz + +touch abcdefghijklmnopqrstuvwxyza +touch abcdefghijklmnopqrstuvwxyzab +touch abcdefghijklmnopqrstuvwxyzabc +touch abcdefghijklmnopqrstuvwxyzabcd +touch abcdefghijklmnopqrstuvwxyzabcde +touch abcdefghijklmnopqrstuvwxyzabcdef +touch abcdefghijklmnopqrstuvwxyzabcdefg +touch abcdefghijklmnopqrstuvwxyzabcdefgh +touch abcdefghijklmnopqrstuvwxyzabcdefghi +touch abcdefghijklmnopqrstuvwxyzabcdefghij +touch abcdefghijklmnopqrstuvwxyzabcdefghijk +touch abcdefghijklmnopqrstuvwxyzabcdefghijkl +touch abcdefghijklmnopqrstuvwxyzabcdefghijklm +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmn +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmno +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnop +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopq +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcde +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefgh +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmno +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnop +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopq +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcde +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefgh +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmno +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnop +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopq +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcde +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefgh +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmno +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnop +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopq +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcde +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefgh +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmno +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnop +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopq +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcde +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefgh +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmno +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnop +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopq +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcde +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefgh +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmno +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnop +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopq +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyza +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcde +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefgh +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmno +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnop +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopq +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuv +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy +touch abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz + +# A file with a long pathname +mkdir -p 1abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz +cd .. + +# Basic test of archiving/dearchiving +echo " bsdtar -c | bsdtar -x" +mkdir copy-default +(cd original && ${BSDTAR} -cf - .) | (cd copy-default; ${BSDTAR} -xf -) +(diff -r original copy-default || echo XXX FAILED XXX 1>&2) | head + +# Exercise gzip compression (test compressed output with gunzip -t +echo " bsdtar -cz | gunzip -t" +(cd original && ${BSDTAR} -czf - .) | gunzip -tq + +# Ensure our compression works with gunzip program +echo " bsdtar -cz | gunzip | bsdtar -x" +mkdir copy-gzip2 +(cd original && ${BSDTAR} -czf - .) | gunzip -q | (cd copy-gzip2; ${BSDTAR} -xf -) +(diff -r original copy-gzip2 || echo XXX FAILED XXX 1>&2) | head + +# Ensure our decompression works with gzip program +echo " bsdtar -c | gzip | bsdtar -x" +mkdir copy-gunzip +(cd original && ${BSDTAR} -cf - .) | gzip | (cd copy-gunzip; ${BSDTAR} -xf -) +(diff -r original copy-gunzip || echo XXX FAILED XXX 1>&2) | head + +# Ensure our gzip compression/decompression work with each other +echo " bsdtar -cz | bsdtar -x" +mkdir copy-gzip-gunzip +(cd original && ${BSDTAR} -czf - .) | (cd copy-gzip-gunzip; ${BSDTAR} -xf -) +(diff -r original copy-gzip-gunzip || echo XXX FAILED XXX 1>&2) | head + +# Ensure our decompression works with bzip2 program +echo " bsdtar -c | bzip2 | bsdtar -x" +mkdir copy-bunzip +(cd original && ${BSDTAR} -cf - .) | bzip2 | (cd copy-bunzip; ${BSDTAR} -xf -) +(diff -r original copy-bunzip || echo XXX FAILED XXX 1>&2) | head + +# Ensure our compression works with bunzip2 program +echo " bsdtar -cy | bunzip2 | bsdtar -x" +mkdir copy-bzip2 +(cd original && ${BSDTAR} -cyf - .) | bunzip2 -q | (cd copy-bzip2; ${BSDTAR} -xf -) +(diff -r original copy-bzip2 || echo XXX FAILED XXX 1>&2) | head + +# Ensure our bzip2 compression/decompression work with each other +echo " bsdtar -cy | bsdtar -x" +mkdir copy-bzip2-bunzip2 +(cd original && ${BSDTAR} -cyf - .) | (cd copy-bzip2-bunzip2; ${BSDTAR} -xf -) +(diff -r original copy-bzip2-bunzip2 || echo XXX FAILED XXX 1>&2) | head + +# Ensure that archive listing works +echo " bsdtar -c | bsdtar -t" +(cd original && find .) | sort > list-original +(cd original && ${BSDTAR} -cf - .) | ${BSDTAR} -tf - | sed 's|/$||' | sort > list-default +(diff list-original list-default || echo XXX FAILED XXX 1>&2) | head + +# Ensure that listing of deflated archives works +echo " bsdtar -cz | bsdtar -t" +(cd original && ${BSDTAR} -czf - .) | ${BSDTAR} -tf - | sed 's|/$||' | sort > list-gzip +(diff list-original list-gzip || echo XXX FAILED XXX 1>&2) | head + +# Ensure that listing of bzip2ed archives works +echo " bsdtar -cy | bsdtar -t" +(cd original && ${BSDTAR} -cyf - .) | ${BSDTAR} -tf - | sed 's|/$||' | sort > list-bzip2 +(diff list-original list-bzip2 || echo XXX FAILED XXX 1>&2) | head + +# Filtering exercises different areas of the library. +echo " Convert tar archive to a tar archive" +mkdir filter-tar-tar +(cd original && ${BSDTAR} -cf - .) | ${BSDTAR} -cf - @- | (cd filter-tar-tar; ${BSDTAR} -xf -) +(diff -r original filter-tar-tar || echo XXX FAILED XXX 1>&2) | head + +# Make sure that reading and writing a tar archive doesn't change it. +echo " bsdtar -cf- @- | cmp" +(cd original && ${BSDTAR} -cf - .) > original.tar +${BSDTAR} -cf - @- < original.tar | cmp - original.tar || echo XXX FAILED XXX + +# Filtering as format conversion +echo " Convert tar archive to cpio archive" +mkdir filter-tar-cpio +(cd original && ${BSDTAR} -cf - .) | ${BSDTAR} -cf - --format=cpio @- | (cd filter-tar-cpio; ${BSDTAR} -xf -) +(diff -r original filter-tar-cpio || echo XXX FAILED XXX 1>&2) | head + +# Test basic --include selection logic +echo " Convert tar to cpio with selection" +mkdir filter-tar-selected +(cd original && ${BSDTAR} -cf - .) | ${BSDTAR} -cf - --format=cpio --include=./f3 @- | (cd filter-tar-selected; ${BSDTAR} -xf -) +(diff -r original/f3 filter-tar-selected/f3 || echo XXX FAILED XXX 1>&2) | head +# Should be no files in copy except for 'f3' +(cd filter-tar-selected ; ls | grep -v f3 | grep .) && echo XXX FAILED XXX + +# Test --include with wildcards +echo " Convert tar to cpio selecting with wildcards" +mkdir filter-tar-selected2 +(cd original && ${BSDTAR} -cf - .) | ${BSDTAR} -cf - --format=cpio --include='./f*' @- | (cd filter-tar-selected2; ${BSDTAR} -xf -) +for f in f1 f2 f3 f4 f5 f6 f7 f8 f9; do + (diff -r original/$f filter-tar-selected2/$f || echo XXX FAILED XXX 1>&2) | head +done +# Should be no files in copy except for 'f[0-9]' +(cd filter-tar-selected2 ; ls | grep -v 'f[0-9]' | grep .) && echo XXX FAILED XXX + +# Check read/write of basic odc cpio format +echo " bsdtar -c --format=cpio | bsdtar -x" +mkdir copy-cpio +(cd original && ${BSDTAR} -cf - --format cpio .) | (cd copy-cpio; ${BSDTAR} -xf -) +(diff -r original copy-cpio || echo XXX FAILED XXX 1>&2) | head + +# Ensure we can read gtar archives +echo " gtar -c | bsdtar -x" +mkdir copy-gtar +(cd original && ${GTAR} -cf - .) | (cd copy-gtar; ${BSDTAR} -xf -) +(diff -r original copy-gtar || echo XXX FAILED XXX 1>&2) | head + +# Ensure we can read svr4crc cpio archives +echo " cpio -H crc | bsdtar -x" +mkdir copy-svr4crc +(cd original && find . | ${CPIO} -o -H crc 2>/dev/null) | (cd copy-svr4crc; ${BSDTAR} -xf -) +(diff -r original copy-svr4crc || echo XXX FAILED XXX 1>&2) | head + +# Ensure we generate proper shar output +echo " bsdtar -c --format=shar | /bin/sh" +mkdir copy-shar +(cd original && ${BSDTAR} -cf - --format=shar --exclude=sparse .) | (cd copy-shar; /bin/sh >/dev/null) +(diff -r --exclude=sparse original copy-shar || echo XXX FAILED XXX 1>&2) | head + +# Check that -u (update) picks up no new files +echo " bsdtar -u doesn't pick up unchanged files" +(cd original && ${BSDTAR} -cf ../test-u.tar -b 1 .) +cp test-u.tar test-u1.tar +(cd original && ${BSDTAR} -uf ../test-u1.tar .) +(diff test-u.tar test-u1.tar || echo XXX FAILED XXX 1>&2) | head + +# Check that -u (update) does pick up actual changed files +echo " bsdtar -u does pick up changed files" +(cd original && echo hello >>f0) +cp test-u.tar test-u2.tar +(cd original && ${BSDTAR} -uf ../test-u2.tar .) +# All this really tests is that the archive did change. +cmp -s test-u.tar test-u2.tar && echo XXX FAILED XXX +# Now, unpack the archive and verify the contents (including the change to f0) +mkdir copy-u-test2 +(cd copy-u-test2 && ${BSDTAR} -xf ../test-u2.tar) +(diff -r original copy-u-test2 || echo XXX FAILED XXX 1>&2) | head diff --git a/libarchive/libarchive-2.4.17/tar/test/old/test-deep-dir.sh b/libarchive/libarchive-2.4.17/tar/test/old/test-deep-dir.sh new file mode 100755 index 0000000..22cf1c8 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/old/test-deep-dir.sh @@ -0,0 +1,60 @@ +#!/bin/sh +# Copyright (c) 2007 Tim Kientzle +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD: src/usr.bin/tar/test/test-deep-dir.sh,v 1.1 2007/03/11 10:36:42 kientzle Exp $ + +# Stress the deep directory logic; the actual depth here seems to +# be limited by the shell. This should be restructured to get around +# that limit (possibly by using perl to build the deep tree?) +echo Deep directory tests + +# Basic test configuration +. `dirname $0`/config.sh + +# Create a deep dir (shell seems to be limited by PATH_MAX) +mkdir original +cd original +I=0 +while [ $I -lt 200 ] +do + mkdir a$I + cd a$I + I=$(($I + 1)) +done +while [ $I -gt 0 ] ; do cd ..; I=$(($I - 1)); done +cd .. + +# Copy this using bsdtar +echo " tar -c | tar -x" +mkdir copy +(cd original; ${BSDTAR} -cf - .) | (cd copy; ${BSDTAR} -xf -) +diff -r original copy || echo XXX FAILURE XXX + +# Copy gtar->bsdtar +echo " gtar -c | tar -x" +mkdir copy-gtar +(cd original; ${GTAR} -cf - .) | (cd copy-gtar; ${BSDTAR} -xf -) +diff -r original copy-gtar || echo XXX FAILURE XXX +cd .. + diff --git a/libarchive/libarchive-2.4.17/tar/test/old/test-flags.sh b/libarchive/libarchive-2.4.17/tar/test/old/test-flags.sh new file mode 100755 index 0000000..bfbf542 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/old/test-flags.sh @@ -0,0 +1,74 @@ +#!/bin/sh +# Copyright (c) 2007 Tim Kientzle +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD: src/usr.bin/tar/test/test-flags.sh,v 1.1 2007/03/11 10:36:42 kientzle Exp $ + +# Exercise copying of file flags +echo "File Flag handling" +# Basic test configuration +. `dirname $0`/config.sh + +# Create some files with various flags set +mkdir original +FLAGS='uchg opaque nodump uappnd' +for f in $FLAGS; do + touch original/test.$f + chflags $f original/test.$f +done +#ls -ol ${TESTDIR}/original + +# Copy the dir with -p +echo " -p preserves flags" +mkdir copy +(cd original && ${BSDTAR} -cf - .) | (cd copy; ${BSDTAR} -xpf -) +# Verify that the flags are set +for f in $FLAGS; do + [ "$f" = `ls -ol copy/test.$f | awk '{print $5}'` ] \ + || echo XXX FAIL: $f not preserved with -p XXX +done +#ls -ol ${TESTDIR}/copy + +# Copy the dir without -p +echo " flags omitted without -p" +mkdir copy2 +(cd original && ${BSDTAR} -cf - .) | (cd copy2; ${BSDTAR} -xf -) +# Verify that the flags are not set +for f in $FLAGS; do + [ "$f" = `ls -ol copy2/test.$f | awk '{print $5}'` ] \ + && echo XXX FAIL: $f copied without -p XXX +done +#ls -ol ${TESTDIR}/copy2 + +# Strip off the flags so we can clean this directory on the next test +for f in $FLAGS; do + if [ $f = 'nodump' ]; then + chflags dump original/test.$f + chflags dump copy/test.$f + else + chflags no$f original/test.$f + chflags no$f copy/test.$f + fi +done +cd .. + diff --git a/libarchive/libarchive-2.4.17/tar/test/old/test-nodump.sh b/libarchive/libarchive-2.4.17/tar/test/old/test-nodump.sh new file mode 100755 index 0000000..1d21b49 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/old/test-nodump.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# Copyright (c) 2007 Tim Kientzle +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD: src/usr.bin/tar/test/test-nodump.sh,v 1.1 2007/03/11 10:36:42 kientzle Exp $ + +# Test that archiving obeys the 'nodump' flag +echo "Verify 'nodump'" +# Basic test configuration +. `dirname $0`/config.sh + +# Create some sample files, 'b' is marked nodump +mkdir original +cd original +touch a +touch b +touch c +# 'chflags' on FreeBSD, 'chattr' on Linux +( chflags nodump b || chattr +d b ) >/dev/null 2>&1 || echo XXX NO chflags/chattr command XXX + +# Copy files with --nodump +cd .. +mkdir copy +(cd original && ${BSDTAR} -cf - --nodump .) | (cd copy; ${BSDTAR} -xf -) + +# Verify that 'b' wasn't copied +echo " File marked nodump wasn't copied" +if [ -e copy/b ] ; then echo XXX Copied nodump file XXX; fi +echo " File not marked nodump was copied" +if [ \! -e copy/a ] ; then echo XXX Failed to copy non-nodump file a XXX; fi +diff -r --exclude=b original copy || echo XXX FAILURE XXX +cd .. diff --git a/libarchive/libarchive-2.4.17/tar/test/old/test-overwrite.sh b/libarchive/libarchive-2.4.17/tar/test/old/test-overwrite.sh new file mode 100755 index 0000000..b920890 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/old/test-overwrite.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# Copyright (c) 2007 Tim Kientzle +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD: src/usr.bin/tar/test/test-overwrite.sh,v 1.1 2007/03/11 10:36:42 kientzle Exp $ + +echo "Test overwrite avoidance" +. `dirname $0`/config.sh + +# Create a file with some data. +# This ensures that test.tar actually has some data in it +# by the time tar tries to add it to itself. +dd if=/dev/urandom of=a bs=1k count=100 >/dev/null 2>&1 + +# Now try to implicitly add archive to itself +${BSDTAR} -cf test.tar . || echo XXX FAILED XXX + +# Create another file +dd if=/dev/urandom of=b bs=1k count=100 >/dev/null 2>&1 + +# Try again. +${BSDTAR} -cf test.tar . || echo XXX FAILED XXX + +# Extract the archive and check that the two files got archived, despite the warning +mkdir compare +cd compare +${BSDTAR} -xf ../test.tar +cmp a ../a || echo XXX a didn't archive correctly XXX +cmp b ../b || echo XXX b didn't archive correctly XXX + +# TODO: Test overwrite avoidance on extract diff --git a/libarchive/libarchive-2.4.17/tar/test/old/test-utf8.sh b/libarchive/libarchive-2.4.17/tar/test/old/test-utf8.sh new file mode 100755 index 0000000..c1b18a6 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/old/test-utf8.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# Copyright (c) 2007 Tim Kientzle +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD: src/usr.bin/tar/test/test-utf8.sh,v 1.1 2007/03/11 10:36:42 kientzle Exp $ + +echo "Test UTF8 filenames" +. `dirname $0`/config.sh + +# Create some files with names in UTF8 +export LC_ALL=en_US.UTF-8 +touch "Greek: Γειά σας" +touch "Hebrew: שלום" +touch "Russian: Здравствуйте!" +touch "Japanese: �����, コンニチハ" +touch "Chinese: ��" + +tar -cf test.tar . + +# TODO: Verify the resulting archive
\ No newline at end of file diff --git a/libarchive/libarchive-2.4.17/tar/test/test.h b/libarchive/libarchive-2.4.17/tar/test/test.h new file mode 100644 index 0000000..a19d44c --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/test.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2003-2006 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/lib/libarchive/test/test.h,v 1.6 2007/07/14 17:52:01 kientzle Exp $ + */ + +/* Every test program should #include "test.h" as the first thing. */ + +/* + * The goal of this file (and the matching test.c) is to + * simplify the very repetitive test-*.c test programs. + */ + +#define _FILE_OFFSET_BITS 64 + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include <wchar.h> + +#ifdef USE_DMALLOC +#include <dmalloc.h> +#endif + +#if defined(HAVE_CONFIG_H) +/* Most POSIX platforms use the 'configure' script to build config.h */ +#include "../../config.h" +#elif defined(__FreeBSD__) +/* Building as part of FreeBSD system requires a pre-built config.h. */ +#include "../config_freebsd.h" +#elif defined(_WIN32) +/* Win32 can't run the 'configure' script. */ +#include "../config_windows.h" +#else +/* Warn if the library hasn't been (automatically or manually) configured. */ +#error Oops: No config.h and no pre-built configuration in test.h. +#endif + +/* No non-FreeBSD platform will have __FBSDID, so just define it here. */ +#ifdef __FreeBSD__ +#include <sys/cdefs.h> /* For __FBSDID */ +#else +#define __FBSDID(a) /* null */ +#endif + +/* + * Redefine DEFINE_TEST for use in defining the test functions. + */ +#undef DEFINE_TEST +#define DEFINE_TEST(name) void name(void); void name(void) + +/* An implementation of the standard assert() macro */ +#define assert(e) test_assert(__FILE__, __LINE__, (e), #e, NULL) + +/* Assert two integers are the same. Reports value of each one if not. */ +#define assertEqualInt(v1,v2) \ + test_assert_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) + +/* Assert two strings are the same. Reports value of each one if not. */ +#define assertEqualString(v1,v2) \ + test_assert_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) +/* As above, but v1 and v2 are wchar_t * */ +#define assertEqualWString(v1,v2) \ + test_assert_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) +/* As above, but raw blocks of bytes. */ +#define assertEqualMem(v1, v2, l) \ + test_assert_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL) +/* Assert two files are the same; allow printf-style expansion of second name. + * See below for comments about variable arguments here... + */ +#define assertEqualFile \ + test_setup(__FILE__, __LINE__);test_assert_equal_file +/* Assert that a file is empty; supports printf-style arguments. */ +#define assertEmptyFile \ + test_setup(__FILE__, __LINE__);test_assert_empty_file + +/* + * This would be simple with C99 variadic macros, but I don't want to + * require that. Instead, I insert a function call before each + * skipping() call to pass the file and line information down. Crude, + * but effective. + */ +#define skipping \ + test_setup(__FILE__, __LINE__);test_skipping + +/* Function declarations. These are defined in test_utility.c. */ +void failure(const char *fmt, ...); +void test_setup(const char *, int); +void test_skipping(const char *fmt, ...); +void test_assert(const char *, int, int, const char *, void *); +void test_assert_empty_file(const char *, ...); +void test_assert_equal_file(const char *, const char *, ...); +void test_assert_equal_int(const char *, int, int, const char *, int, const char *, void *); +void test_assert_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *); +void test_assert_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *); +void test_assert_equal_mem(const char *, int, const char *, const char *, const char *, const char *, size_t, const char *, void *); + +/* Like sprintf, then system() */ +int systemf(const char * fmt, ...); + +/* Suck file into string allocated via malloc(). Call free() when done. */ +/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */ +char *slurpfile(size_t *, const char *fmt, ...); + +/* + * Global vars + */ + +/* Directory holding reference files. */ +char *refdir; + +/* + * Special interfaces for bsdtar test harness. + */ + +/* Pathname of exe to be tested. */ +char *testprog; + diff --git a/libarchive/libarchive-2.4.17/tar/test/test_basic.c b/libarchive/libarchive-2.4.17/tar/test/test_basic.c new file mode 100644 index 0000000..50be289 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/test_basic.c @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + + +static void +basic_tar(const char *target, const char *pack_options, const char *unpack_options) +{ + struct stat st, st2; + char buff[128]; + int r; + + assertEqualInt(0, mkdir(target, 0775)); + + /* Use the tar program to create an archive. */ + r = systemf("%s cf - %s `cat filelist` >%s/archive 2>%s/pack.err", testprog, pack_options, target, target); + failure("Error invoking %s cf -", testprog, pack_options); + assertEqualInt(r, 0); + + chdir(target); + + /* Verify that nothing went to stderr. */ + assertEmptyFile("pack.err"); + + /* + * Use tar to unpack the archive into another directory. + */ + r = systemf("%s xf archive %s >unpack.out 2>unpack.err", testprog, unpack_options); + failure("Error invoking %s xf archive %s", testprog, unpack_options); + assertEqualInt(r, 0); + + /* Verify that nothing went to stderr. */ + assertEmptyFile("unpack.err"); + + /* + * Verify unpacked files. + */ + + /* Regular file with 2 links. */ + r = lstat("file", &st); + failure("Failed to stat file %s/file, errno=%d", target, errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st.st_mode)); + assertEqualInt(0644, st.st_mode & 0777); + assertEqualInt(10, st.st_size); + failure("file %s/file", target); + assertEqualInt(2, st.st_nlink); + } + + /* Another name for the same file. */ + r = lstat("linkfile", &st2); + failure("Failed to stat file %s/linkfile, errno=%d", target, errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st2.st_mode)); + assertEqualInt(0644, st2.st_mode & 0777); + assertEqualInt(10, st2.st_size); + failure("file %s/linkfile", target); + assertEqualInt(2, st2.st_nlink); + /* Verify that the two are really hardlinked. */ + assertEqualInt(st.st_dev, st2.st_dev); + failure("%s/linkfile and %s/file aren't really hardlinks", target, target); + assertEqualInt(st.st_ino, st2.st_ino); + } + + /* Symlink */ + r = lstat("symlink", &st); + failure("Failed to stat file %s/symlink, errno=%d", target, errno); + assertEqualInt(r, 0); + if (r == 0) { + failure("symlink should be a symlink; actual mode is %o", + st.st_mode); + assert(S_ISLNK(st.st_mode)); + if (S_ISLNK(st.st_mode)) { + r = readlink("symlink", buff, sizeof(buff)); + assertEqualInt(r, 4); + buff[r] = '\0'; + assertEqualString(buff, "file"); + } + } + + /* dir */ + r = lstat("dir", &st); + if (r == 0) { + assertEqualInt(r, 0); + assert(S_ISDIR(st.st_mode)); + assertEqualInt(0775, st.st_mode & 0777); + } + + chdir(".."); +} + +DEFINE_TEST(test_basic) +{ + int fd; + int filelist; + int oldumask; + + oldumask = umask(0); + + /* + * Create an assortment of files on disk. + */ + filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + + /* File with 10 bytes content. */ + fd = open("file", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(10, write(fd, "123456789", 10)); + close(fd); + write(filelist, "file\n", 5); + + /* hardlink to above file. */ + assertEqualInt(0, link("file", "linkfile")); + write(filelist, "linkfile\n", 9); + + /* Symlink to above file. */ + assertEqualInt(0, symlink("file", "symlink")); + write(filelist, "symlink\n", 8); + + /* Directory. */ + assertEqualInt(0, mkdir("dir", 0775)); + write(filelist, "dir\n", 4); + /* All done. */ + close(filelist); + + /* Archive/dearchive with a variety of options. */ + basic_tar("copy", "", ""); + /* tar doesn't handle cpio symlinks correctly */ + /* basic_tar("copy_odc", "--format=odc", ""); */ + basic_tar("copy_ustar", "--format=ustar", ""); + + umask(oldumask); +} diff --git a/libarchive/libarchive-2.4.17/tar/test/test_copy.c b/libarchive/libarchive-2.4.17/tar/test/test_copy.c new file mode 100644 index 0000000..83fbd76 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/test_copy.c @@ -0,0 +1,279 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +static void +create_tree(void) +{ + char buff[260]; + char buff2[260]; + int i; + int fd; + + assertEqualInt(0, mkdir("original", 0775)); + chdir("original"); + + buff[0] = 'f'; + buff[1] = '_'; + for (i = 0; i < 200; i++) { + /* Create a file named "f_abcdef..." */ + buff[i + 2] = 'a' + (i % 26); + buff[i + 3] = '\0'; + fd = open(buff, O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(i + 3, write(fd, buff, strlen(buff))); + close(fd); + + /* Create a link named "l_abcdef..." to the above. */ + strcpy(buff2, buff); + buff2[0] = 'l'; + assertEqualInt(0, link(buff, buff2)); + + /* Create a link named "m_abcdef..." to the above. */ + strcpy(buff2, buff); + buff2[0] = 'm'; + assertEqualInt(0, link(buff, buff2)); + + /* Create a symlink named "s_abcdef..." to the above. */ + buff2[0] = 's'; + assertEqualInt(0, symlink(buff, buff2)); + + /* Create a dir named "d_abcdef...". */ + buff2[0] = 'd'; + assertEqualInt(0, mkdir(buff2, 0775)); + } + + chdir(".."); +} + +#define LIMIT_NONE 0 +#define LIMIT_USTAR 1 + +static void +verify_tree(int limit) +{ + struct stat st, st2; + char buff[260]; + char buff2[260]; + int i, r; + int fd; + int len; + const char *p; + DIR *d; + struct dirent *de; + + /* Generate the names we know should be there and verify them. */ + for (i = 0; i < 200; i++) { + /* Verify a file named "f_abcdef..." */ + buff[0] = 'f'; + buff[1] = '_'; + buff[i + 2] = 'a' + (i % 26); + buff[i + 3] = '\0'; + if (limit != LIMIT_USTAR || strlen(buff) <= 100) { + fd = open(buff, O_RDONLY); + failure("Couldn't open \"%s\": %s", + buff, strerror(errno)); + assert(fd >= 0); + len = read(fd, buff2, i + 10); + close(fd); + assertEqualInt(len, i + 3); + /* Verify contents of 'buff2' */ + buff2[len] = '\0'; + assertEqualString(buff, buff2); + /* stat() file and get dev/ino for next check */ + assertEqualInt(0, lstat(buff, &st)); + } + + /* + * ustar allows 100 chars for links, and we have + * "original/" as part of the name, so the link + * names here can't exceed 91 chars. + */ + if (limit != LIMIT_USTAR || strlen(buff) <= 91) { + /* Verify hardlink "l_abcdef..." */ + buff[0] = 'l'; + assertEqualInt(0, (r = lstat(buff, &st2))); + if (r == 0) { + assertEqualInt(st2.st_dev, st.st_dev); + assertEqualInt(st2.st_ino, st.st_ino); + } + + /* Verify hardlink "m_abcdef..." */ + buff[0] = 'm'; + assertEqualInt(0, (r = lstat(buff, &st2))); + if (r == 0) { + assertEqualInt(st2.st_dev, st.st_dev); + assertEqualInt(st2.st_ino, st.st_ino); + } + } + + /* + * Symlink text doesn't include the 'original/' prefix, + * so the limit here is 100 characters. + */ + /* Verify symlink "s_abcdef..." */ + buff[0] = 's'; + if (limit != LIMIT_USTAR || strlen(buff) <= 100) { + /* This is a symlink. */ + assertEqualInt(0, lstat(buff, &st2)); + assert(S_ISLNK(st2.st_mode)); + /* This is a symlink to the file above. */ + assertEqualInt(0, stat(buff, &st2)); + assertEqualInt(st2.st_dev, st.st_dev); + assertEqualInt(st2.st_ino, st.st_ino); + } + + /* Verify dir "d_abcdef...". */ + buff[0] = 'd'; + if (limit != LIMIT_USTAR || strlen(buff) <= 100) { + /* This is a dir. */ + assertEqualInt(0, lstat(buff, &st2)); + assert(S_ISDIR(st2.st_mode)); + /* TODO: opendir/readdir this directory and + * make sure it's empty. + */ + } + } + + /* Now make sure nothing is there that shouldn't be. */ + d = opendir("."); + while ((de = readdir(d)) != NULL) { + p = de->d_name; + switch(p[0]) { + case 'l': case 'm': + if (limit == LIMIT_USTAR) + assert(strlen(p) <= 91); + case 'd': case 'f': case 's': + if (limit == LIMIT_USTAR) + assert(strlen(p) <= 100); + /* Our files have very particular filename patterns. */ + assert(p[1] == '_' && p[2] == 'a'); + assert(p[2] == 'a'); + p += 2; + for (i = 0; p[i] != '\0' && i < 200; i++) + assert(p[i] == 'a' + (i % 26)); + assert(p[i] == '\0'); + break; + case '.': + assert(p[1] == '\0' || (p[1] == '.' && p[2] == '\0')); + break; + default: + failure("File %s shouldn't be here", p); + assert(0); + } + + } + closedir(d); +} + +static void +copy_basic(void) +{ + int r; + + assertEqualInt(0, mkdir("plain", 0775)); + chdir("plain"); + + /* + * Use the tar program to create an archive. + */ + r = systemf("%s cf archive -C .. original >pack.out 2>pack.err", + testprog); + failure("Error invoking \"%s cf\"", testprog); + assertEqualInt(r, 0); + + /* Verify that nothing went to stdout or stderr. */ + assertEmptyFile("pack.err"); + assertEmptyFile("pack.out"); + + /* + * Use tar to unpack the archive into another directory. + */ + r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog); + failure("Error invoking %s xf archive", testprog); + assertEqualInt(r, 0); + + /* Verify that nothing went to stdout or stderr. */ + assertEmptyFile("unpack.err"); + assertEmptyFile("unpack.out"); + + chdir("original"); + verify_tree(LIMIT_NONE); + chdir("../.."); +} + +static void +copy_ustar(void) +{ + const char *target = "ustar"; + int r; + + assertEqualInt(0, mkdir(target, 0775)); + chdir(target); + + /* + * Use the tar program to create an archive. + */ + r = systemf("%s cf archive --format=ustar -C .. original >pack.out 2>pack.err", + testprog); + failure("Error invoking \"%s cf\"", testprog); + assertEqualInt(r, 0); + + /* Verify that nothing went to stdout. */ + assertEmptyFile("pack.out"); + + /* + * Use tar to unpack the archive into another directory. + */ + r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog); + failure("Error invoking %s xf archive", testprog); + assertEqualInt(r, 0); + + /* Verify that nothing went to stdout or stderr. */ + assertEmptyFile("unpack.err"); + assertEmptyFile("unpack.out"); + + chdir("original"); + verify_tree(LIMIT_USTAR); + chdir("../.."); +} + +DEFINE_TEST(test_copy) +{ + int oldumask; + + oldumask = umask(0); + + create_tree(); /* Create sample files in "original" dir. */ + + /* Test simple "tar -c | tar -x" pipeline copy. */ + copy_basic(); + + /* Same, but constrain to ustar format. */ + copy_ustar(); + + umask(oldumask); +} diff --git a/libarchive/libarchive-2.4.17/tar/test/test_getdate.c b/libarchive/libarchive-2.4.17/tar/test/test_getdate.c new file mode 100644 index 0000000..7ed447b --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/test_getdate.c @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +/* + * Verify that the getdate() function works. + */ + +time_t get_date(const char *); + +DEFINE_TEST(test_getdate) +{ + assertEqualInt(0, get_date("Jan 1, 1970 UTC")); + /* TODO: Lots more tests here. */ +} diff --git a/libarchive/libarchive-2.4.17/tar/test/test_help.c b/libarchive/libarchive-2.4.17/tar/test/test_help.c new file mode 100644 index 0000000..c547dbc --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/test_help.c @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +/* + * Test that "--help", "-h", and "-W help" options all work and + * generate reasonable output. + */ + +static int +in_first_line(const char *p, const char *substring) +{ + size_t l = strlen(substring); + + while (*p != '\0' && *p != '\n') { + if (memcmp(p, substring, l) == 0) + return (1); + ++p; + } + return (0); +} + +DEFINE_TEST(test_help) +{ + int r; + char *p; + size_t plen; + + /* Exercise --help option. */ + r = systemf("%s --help >help.stdout 2>help.stderr", testprog); + failure("--help should generate nothing to stderr."); + assertEmptyFile("help.stderr"); + /* Help message should start with name of program. */ + p = slurpfile(&plen, "help.stdout"); + failure("Help output should be long enough."); + assert(plen >= 6); + failure("First line of help output should contain 'bsdtar': %s", p); + assert(in_first_line(p, "bsdtar")); + /* + * TODO: Extend this check to further verify that --help output + * looks approximately right. + */ + free(p); + + /* -h option should generate the same output. */ + r = systemf("%s -h >h.stdout 2>h.stderr", testprog); + failure("-h should generate nothing to stderr."); + assertEmptyFile("h.stderr"); + failure("stdout should be same for -h and --help"); + assertEqualFile("h.stdout", "help.stdout"); + + /* -W help should be another synonym. */ + r = systemf("%s -W help >Whelp.stdout 2>Whelp.stderr", testprog); + failure("-W help should generate nothing to stderr."); + assertEmptyFile("Whelp.stderr"); + failure("stdout should be same for -W help and --help"); + assertEqualFile("Whelp.stdout", "help.stdout"); +} diff --git a/libarchive/libarchive-2.4.17/tar/test/test_stdio.c b/libarchive/libarchive-2.4.17/tar/test/test_stdio.c new file mode 100644 index 0000000..2d24ae3 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/test_stdio.c @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +DEFINE_TEST(test_stdio) +{ + int fd; + int filelist; + int oldumask; + int r; + + oldumask = umask(0); + + /* + * Create a couple of files on disk. + */ + filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + /* File */ + fd = open("f", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + write(fd, "f\n", 2); + close(fd); + write(filelist, "f\n", 2); + /* Link to above file. */ + assertEqualInt(0, link("f", "l")); + write(filelist, "l\n", 2); + close(filelist); + + /* + * Archive/dearchive with a variety of options, verifying + * stdio paths. + */ + + /* 'cf' should generate no output unless there's an error. */ + r = systemf("%s cf archive f l >cf.out 2>cf.err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("cf.out"); + assertEmptyFile("cf.err"); + + /* 'cvf' should generate file list on stderr, empty stdout. */ + r = systemf("%s cvf archive f l >cvf.out 2>cvf.err", testprog); + assertEqualInt(r, 0); + failure("'cv' writes filenames to stderr, nothing to stdout (SUSv2)\n" + "Note that GNU tar writes the file list to stdout by default."); + assertEmptyFile("cvf.out"); + /* TODO: Verify cvf.err has file list in SUSv2-prescribed format. */ + + /* 'cvf -' should generate file list on stderr, archive on stdout. */ + r = systemf("%s cvf - f l >cvf-.out 2>cvf-.err", testprog); + assertEqualInt(r, 0); + failure("cvf - should write archive to stdout"); + /* TODO: Verify cvf-.out has archive. */ + failure("cvf - should write file list to stderr (SUSv2)"); + /* TODO: Verify cvf-.err has verbose file list. */ + + /* 'tf' should generate file list on stdout, empty stderr. */ + r = systemf("%s tf archive >tf.out 2>tf.err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("tf.err"); + failure("'t' mode should write results to stdout"); + /* TODO: Verify tf.out has file list. */ + + /* 'tvf' should generate file list on stdout, empty stderr. */ + r = systemf("%s tvf archive >tvf.out 2>tvf.err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("tvf.err"); + failure("'tv' mode should write results to stdout"); + /* TODO: Verify tvf.out has file list. */ + + /* 'tvf -' uses stdin, file list on stdout, empty stderr. */ + r = systemf("%s tvf - < archive >tvf-.out 2>tvf-.err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("tvf-.err"); + /* TODO: Verify tvf-.out has file list. */ + + /* Basic 'xf' should generate no output on stdout or stderr. */ + r = systemf("%s xf archive >xf.out 2>xf.err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("xf.err"); + assertEmptyFile("xf.out"); + + /* 'xvf' should generate list on stderr, empty stdout. */ + r = systemf("%s xvf archive >xvf.out 2>xvf.err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("xvf.out"); + /* TODO: Verify xvf.err */ + + /* 'xvOf' should generate list on stderr, file contents on stdout. */ + r = systemf("%s xvOf archive >xvOf.out 2>xvOf.err", testprog); + assertEqualInt(r, 0); + /* TODO: Verify xvOf.out */ + /* TODO: Verify xvf.err */ + + /* 'xvf -' should generate list on stderr, empty stdout. */ + r = systemf("%s xvf - < archive >xvf-.out 2>xvf-.err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("xvf-.out"); + /* TODO: Verify xvf-.err */ + + umask(oldumask); +} diff --git a/libarchive/libarchive-2.4.17/tar/test/test_version.c b/libarchive/libarchive-2.4.17/tar/test/test_version.c new file mode 100644 index 0000000..5ac6f88 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/test/test_version.c @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +/* + * Test that --version option works and generates reasonable output. + */ + +DEFINE_TEST(test_version) +{ + int r; + char *p, *q; + size_t s; + + + r = systemf("%s --version >version.stdout 2>version.stderr", testprog); + /* --version should generate nothing to stdout. */ + assertEmptyFile("version.stderr"); + /* Verify format of version message. */ + q = p = slurpfile(&s, "version.stdout"); + /* Version message should start with name of program, then space. */ + assert(s > 6); + assertEqualMem(q, "bsdtar ", 7); + q += 7; s -= 7; + /* Version number is a series of digits and periods. */ + while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) { + ++q; + --s; + } + /* Version number terminated by space. */ + assert(s > 1); + assert(*q == ' '); + ++q; --s; + /* Separator. */ + assertEqualMem(q, "- ", 2); + q += 2; s -= 2; + /* libarchive name and version number */ + assert(s > 11); + assertEqualMem(q, "libarchive ", 11); + q += 11; s -= 11; + /* Version number is a series of digits and periods. */ + while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) { + ++q; + --s; + } + /* All terminated by a newline. */ + assert(s >= 1); + assertEqualMem(q, "\n", 1); + free(p); +} diff --git a/libarchive/libarchive-2.4.17/tar/tree.c b/libarchive/libarchive-2.4.17/tar/tree.c new file mode 100644 index 0000000..23e64e3 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/tree.c @@ -0,0 +1,542 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * This is a new directory-walking system that addresses a number + * of problems I've had with fts(3). In particular, it has no + * pathname-length limits (other than the size of 'int'), handles + * deep logical traversals, uses considerably less memory, and has + * an opaque interface (easier to modify in the future). + * + * Internally, it keeps a single list of "tree_entry" items that + * represent filesystem objects that require further attention. + * Non-directories are not kept in memory: they are pulled from + * readdir(), returned to the client, then freed as soon as possible. + * Any directory entry to be traversed gets pushed onto the stack. + * + * There is surprisingly little information that needs to be kept for + * each item on the stack. Just the name, depth (represented here as the + * string length of the parent directory's pathname), and some markers + * indicating how to get back to the parent (via chdir("..") for a + * regular dir or via fchdir(2) for a symlink). + */ +#include "bsdtar_platform.h" +__FBSDID("$FreeBSD: src/usr.bin/tar/tree.c,v 1.8 2007/03/11 10:36:42 kientzle Exp $"); + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_DIRENT_H +#include <dirent.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "tree.h" + +/* + * TODO: + * 1) Loop checking. + * 3) Arbitrary logical traversals by closing/reopening intermediate fds. + */ + +struct tree_entry { + struct tree_entry *next; + struct tree_entry *parent; + char *name; + size_t dirname_length; + dev_t dev; + ino_t ino; + int fd; + int flags; +}; + +/* Definitions for tree_entry.flags bitmap. */ +#define isDir 1 /* This entry is a regular directory. */ +#define isDirLink 2 /* This entry is a symbolic link to a directory. */ +#define needsPreVisit 4 /* This entry needs to be previsited. */ +#define needsPostVisit 8 /* This entry needs to be postvisited. */ + +/* + * Local data for this package. + */ +struct tree { + struct tree_entry *stack; + struct tree_entry *current; + DIR *d; + int initialDirFd; + int flags; + int visit_type; + int tree_errno; /* Error code from last failed operation. */ + + char *buff; + const char *basename; + size_t buff_length; + size_t path_length; + size_t dirname_length; + + int depth; + int openCount; + int maxOpenCount; + + struct stat lst; + struct stat st; +}; + +/* Definitions for tree.flags bitmap. */ +#define needsReturn 8 /* Marks first entry as not having been returned yet. */ +#define hasStat 16 /* The st entry is set. */ +#define hasLstat 32 /* The lst entry is set. */ + + +#ifdef HAVE_DIRENT_D_NAMLEN +/* BSD extension; avoids need for a strlen() call. */ +#define D_NAMELEN(dp) (dp)->d_namlen +#else +#define D_NAMELEN(dp) (strlen((dp)->d_name)) +#endif + +#if 0 +#include <stdio.h> +void +tree_dump(struct tree *t, FILE *out) +{ + struct tree_entry *te; + + fprintf(out, "\tdepth: %d\n", t->depth); + fprintf(out, "\tbuff: %s\n", t->buff); + fprintf(out, "\tpwd: "); fflush(stdout); system("pwd"); + fprintf(out, "\taccess: %s\n", t->basename); + fprintf(out, "\tstack:\n"); + for (te = t->stack; te != NULL; te = te->next) { + fprintf(out, "\t\tte->name: %s%s%s\n", te->name, + te->flags & needsPreVisit ? "" : " *", + t->current == te ? " (current)" : ""); + } +} +#endif + +/* + * Add a directory path to the current stack. + */ +static void +tree_push(struct tree *t, const char *path) +{ + struct tree_entry *te; + + te = malloc(sizeof(*te)); + memset(te, 0, sizeof(*te)); + te->next = t->stack; + t->stack = te; + te->fd = -1; + te->name = strdup(path); + te->flags = needsPreVisit | needsPostVisit; + te->dirname_length = t->dirname_length; +} + +/* + * Append a name to the current path. + */ +static void +tree_append(struct tree *t, const char *name, size_t name_length) +{ + char *p; + + if (t->buff != NULL) + t->buff[t->dirname_length] = '\0'; + /* Strip trailing '/' from name, unless entire name is "/". */ + while (name_length > 1 && name[name_length - 1] == '/') + name_length--; + + /* Resize pathname buffer as needed. */ + while (name_length + 1 + t->dirname_length >= t->buff_length) { + t->buff_length *= 2; + if (t->buff_length < 1024) + t->buff_length = 1024; + t->buff = realloc(t->buff, t->buff_length); + } + p = t->buff + t->dirname_length; + t->path_length = t->dirname_length + name_length; + /* Add a separating '/' if it's needed. */ + if (t->dirname_length > 0 && p[-1] != '/') { + *p++ = '/'; + t->path_length ++; + } + strncpy(p, name, name_length); + p[name_length] = '\0'; + t->basename = p; +} + +/* + * Open a directory tree for traversal. + */ +struct tree * +tree_open(const char *path) +{ + struct tree *t; + + t = malloc(sizeof(*t)); + memset(t, 0, sizeof(*t)); + tree_append(t, path, strlen(path)); + t->initialDirFd = open(".", O_RDONLY); + /* + * During most of the traversal, items are set up and then + * returned immediately from tree_next(). That doesn't work + * for the very first entry, so we set a flag for this special + * case. + */ + t->flags = needsReturn; + return (t); +} + +/* + * We've finished a directory; ascend back to the parent. + */ +static void +tree_ascend(struct tree *t) +{ + struct tree_entry *te; + + te = t->stack; + t->depth--; + if (te->flags & isDirLink) { + fchdir(te->fd); + close(te->fd); + t->openCount--; + } else { + chdir(".."); + } +} + +/* + * Pop the working stack. + */ +static void +tree_pop(struct tree *t) +{ + struct tree_entry *te; + + t->buff[t->dirname_length] = '\0'; + if (t->stack == t->current && t->current != NULL) + t->current = t->current->parent; + te = t->stack; + t->stack = te->next; + t->dirname_length = te->dirname_length; + t->basename = t->buff + t->dirname_length; + /* Special case: starting dir doesn't skip leading '/'. */ + if (t->dirname_length > 0) + t->basename++; + free(te->name); + free(te); +} + +/* + * Get the next item in the tree traversal. + */ +int +tree_next(struct tree *t) +{ + struct dirent *de = NULL; + + /* Handle the startup case by returning the initial entry. */ + if (t->flags & needsReturn) { + t->flags &= ~needsReturn; + return (t->visit_type = TREE_REGULAR); + } + + while (t->stack != NULL) { + /* If there's an open dir, get the next entry from there. */ + while (t->d != NULL) { + de = readdir(t->d); + if (de == NULL) { + closedir(t->d); + t->d = NULL; + } else if (de->d_name[0] == '.' + && de->d_name[1] == '\0') { + /* Skip '.' */ + } else if (de->d_name[0] == '.' + && de->d_name[1] == '.' + && de->d_name[2] == '\0') { + /* Skip '..' */ + } else { + /* + * Append the path to the current path + * and return it. + */ + tree_append(t, de->d_name, D_NAMELEN(de)); + t->flags &= ~hasLstat; + t->flags &= ~hasStat; + return (t->visit_type = TREE_REGULAR); + } + } + + /* If the current dir needs to be visited, set it up. */ + if (t->stack->flags & needsPreVisit) { + t->current = t->stack; + tree_append(t, t->stack->name, strlen(t->stack->name)); + t->stack->flags &= ~needsPreVisit; + /* If it is a link, set up fd for the ascent. */ + if (t->stack->flags & isDirLink) { + t->stack->fd = open(".", O_RDONLY); + t->openCount++; + if (t->openCount > t->maxOpenCount) + t->maxOpenCount = t->openCount; + } + t->dirname_length = t->path_length; + if (chdir(t->stack->name) != 0) { + /* chdir() failed; return error */ + tree_pop(t); + t->tree_errno = errno; + return (t->visit_type = TREE_ERROR_DIR); + } + t->depth++; + t->d = opendir("."); + if (t->d == NULL) { + tree_ascend(t); /* Undo "chdir" */ + tree_pop(t); + t->tree_errno = errno; + return (t->visit_type = TREE_ERROR_DIR); + } + t->flags &= ~hasLstat; + t->flags &= ~hasStat; + t->basename = "."; + return (t->visit_type = TREE_POSTDESCENT); + } + + /* We've done everything necessary for the top stack entry. */ + if (t->stack->flags & needsPostVisit) { + tree_ascend(t); + tree_pop(t); + t->flags &= ~hasLstat; + t->flags &= ~hasStat; + return (t->visit_type = TREE_POSTASCENT); + } + } + return (t->visit_type = 0); +} + +/* + * Return error code. + */ +int +tree_errno(struct tree *t) +{ + return (t->tree_errno); +} + +/* + * Called by the client to mark the directory just returned from + * tree_next() as needing to be visited. + */ +void +tree_descend(struct tree *t) +{ + if (t->visit_type != TREE_REGULAR) + return; + + if (tree_current_is_physical_dir(t)) { + tree_push(t, t->basename); + t->stack->flags |= isDir; + } else if (tree_current_is_dir(t)) { + tree_push(t, t->basename); + t->stack->flags |= isDirLink; + } +} + +/* + * Get the stat() data for the entry just returned from tree_next(). + */ +const struct stat * +tree_current_stat(struct tree *t) +{ + if (!(t->flags & hasStat)) { + if (stat(t->basename, &t->st) != 0) + return NULL; + t->flags |= hasStat; + } + return (&t->st); +} + +/* + * Get the lstat() data for the entry just returned from tree_next(). + */ +const struct stat * +tree_current_lstat(struct tree *t) +{ + if (!(t->flags & hasLstat)) { + if (lstat(t->basename, &t->lst) != 0) + return NULL; + t->flags |= hasLstat; + } + return (&t->lst); +} + +/* + * Test whether current entry is a dir or link to a dir. + */ +int +tree_current_is_dir(struct tree *t) +{ + const struct stat *st; + + /* + * If we already have lstat() info, then try some + * cheap tests to determine if this is a dir. + */ + if (t->flags & hasLstat) { + /* If lstat() says it's a dir, it must be a dir. */ + if (S_ISDIR(tree_current_lstat(t)->st_mode)) + return 1; + /* Not a dir; might be a link to a dir. */ + /* If it's not a link, then it's not a link to a dir. */ + if (!S_ISLNK(tree_current_lstat(t)->st_mode)) + return 0; + /* + * It's a link, but we don't know what it's a link to, + * so we'll have to use stat(). + */ + } + + st = tree_current_stat(t); + /* If we can't stat it, it's not a dir. */ + if (st == NULL) + return 0; + /* Use the definitive test. Hopefully this is cached. */ + return (S_ISDIR(st->st_mode)); +} + +/* + * Test whether current entry is a physical directory. Usually, we + * already have at least one of stat() or lstat() in memory, so we + * use tricks to try to avoid an extra trip to the disk. + */ +int +tree_current_is_physical_dir(struct tree *t) +{ + const struct stat *st; + + /* + * If stat() says it isn't a dir, then it's not a dir. + * If stat() data is cached, this check is free, so do it first. + */ + if ((t->flags & hasStat) + && (!S_ISDIR(tree_current_stat(t)->st_mode))) + return 0; + + /* + * Either stat() said it was a dir (in which case, we have + * to determine whether it's really a link to a dir) or + * stat() info wasn't available. So we use lstat(), which + * hopefully is already cached. + */ + + st = tree_current_lstat(t); + /* If we can't stat it, it's not a dir. */ + if (st == NULL) + return 0; + /* Use the definitive test. Hopefully this is cached. */ + return (S_ISDIR(st->st_mode)); +} + +/* + * Test whether current entry is a symbolic link. + */ +int +tree_current_is_physical_link(struct tree *t) +{ + const struct stat *st = tree_current_lstat(t); + if (st == NULL) + return 0; + return (S_ISLNK(st->st_mode)); +} + +/* + * Return the access path for the entry just returned from tree_next(). + */ +const char * +tree_current_access_path(struct tree *t) +{ + return (t->basename); +} + +/* + * Return the full path for the entry just returned from tree_next(). + */ +const char * +tree_current_path(struct tree *t) +{ + return (t->buff); +} + +/* + * Return the length of the path for the entry just returned from tree_next(). + */ +size_t +tree_current_pathlen(struct tree *t) +{ + return (t->path_length); +} + +/* + * Return the nesting depth of the entry just returned from tree_next(). + */ +int +tree_current_depth(struct tree *t) +{ + return (t->depth); +} + +/* + * Terminate the traversal and release any resources. + */ +void +tree_close(struct tree *t) +{ + /* Release anything remaining in the stack. */ + while (t->stack != NULL) + tree_pop(t); + if (t->buff) + free(t->buff); + /* chdir() back to where we started. */ + if (t->initialDirFd >= 0) { + fchdir(t->initialDirFd); + close(t->initialDirFd); + t->initialDirFd = -1; + } + free(t); +} diff --git a/libarchive/libarchive-2.4.17/tar/tree.h b/libarchive/libarchive-2.4.17/tar/tree.h new file mode 100644 index 0000000..a32a15f --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/tree.h @@ -0,0 +1,115 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/usr.bin/tar/tree.h,v 1.3 2007/01/09 08:12:17 kientzle Exp $ + */ + +/*- + * A set of routines for traversing directory trees. + * Similar in concept to the fts library, but with a few + * important differences: + * * Uses less memory. In particular, fts stores an entire directory + * in memory at a time. This package only keeps enough subdirectory + * information in memory to track the traversal. Information + * about non-directories is discarded as soon as possible. + * * Supports very deep logical traversals. The fts package + * uses "non-chdir" approach for logical traversals. This + * package does use a chdir approach for logical traversals + * and can therefore handle pathnames much longer than + * PATH_MAX. + * * Supports deep physical traversals "out of the box." + * Due to the memory optimizations above, there's no need to + * limit dir names to 32k. + */ + +#include <sys/stat.h> +#include <stdio.h> + +struct tree; + +/* Initiate/terminate a tree traversal. */ +struct tree *tree_open(const char * /* pathname */); +void tree_close(struct tree *); + +/* + * tree_next() returns Zero if there is no next entry, non-zero if there is. + * Note that directories are potentially visited three times. The first + * time as "regular" file. If tree_descend() is invoked at that time, + * the directory is added to a work list and will be visited two more + * times: once just after descending into the directory and again + * just after ascending back to the parent. + * + * TREE_ERROR is returned if the descent failed (because the + * directory couldn't be opened, for instance). This is returned + * instead of TREE_PREVISIT/TREE_POSTVISIT. + */ +#define TREE_REGULAR 1 +#define TREE_POSTDESCENT 2 +#define TREE_POSTASCENT 3 +#define TREE_ERROR_DIR -1 +int tree_next(struct tree *); + +int tree_errno(struct tree *); + +/* + * Request that current entry be visited. If you invoke it on every + * directory, you'll get a physical traversal. This is ignored if the + * current entry isn't a directory or a link to a directory. So, if + * you invoke this on every returned path, you'll get a full logical + * traversal. + */ +void tree_descend(struct tree *); + +/* + * Return information about the current entry. + */ + +int tree_current_depth(struct tree *); +/* + * The current full pathname, length of the full pathname, + * and a name that can be used to access the file. + * Because tree does use chdir extensively, the access path is + * almost never the same as the full current path. + */ +const char *tree_current_path(struct tree *); +size_t tree_current_pathlen(struct tree *); +const char *tree_current_access_path(struct tree *); +/* + * Request the lstat() or stat() data for the current path. Since the + * tree package needs to do some of this anyway, and caches the + * results, you should take advantage of it here if you need it rather + * than make a redundant stat() or lstat() call of your own. + */ +const struct stat *tree_current_stat(struct tree *); +const struct stat *tree_current_lstat(struct tree *); +/* The following tests may use mechanisms much faster than stat()/lstat(). */ +/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */ +int tree_current_is_physical_dir(struct tree *); +/* "is_physical_link" is equivalent to S_ISLNK(tree_current_lstat()->st_mode) */ +int tree_current_is_physical_link(struct tree *); +/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */ +int tree_current_is_dir(struct tree *); + +/* For testing/debugging: Dump the internal status to the given filehandle. */ +void tree_dump(struct tree *, FILE *); diff --git a/libarchive/libarchive-2.4.17/tar/util.c b/libarchive/libarchive-2.4.17/tar/util.c new file mode 100644 index 0000000..68ff8d8 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/util.c @@ -0,0 +1,437 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bsdtar_platform.h" +__FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.18 2008/01/02 00:21:27 kientzle Exp $"); + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> /* Linux doesn't define mode_t, etc. in sys/stat.h. */ +#endif +#include <ctype.h> +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_STDARG_H +#include <stdarg.h> +#endif +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#include "bsdtar.h" + +static void bsdtar_vwarnc(struct bsdtar *, int code, + const char *fmt, va_list ap); + +/* + * Print a string, taking care with any non-printable characters. + */ + +void +safe_fprintf(FILE *f, const char *fmt, ...) +{ + char *buff; + char *buff_heap; + int buff_length; + int length; + va_list ap; + char *p; + unsigned i; + char buff_stack[256]; + char copy_buff[256]; + + /* Use a stack-allocated buffer if we can, for speed and safety. */ + buff_heap = NULL; + buff_length = sizeof(buff_stack); + buff = buff_stack; + + va_start(ap, fmt); + length = vsnprintf(buff, buff_length, fmt, ap); + va_end(ap); + /* If the result is too large, allocate a buffer on the heap. */ + if (length >= buff_length) { + buff_length = length+1; + buff_heap = malloc(buff_length); + /* Failsafe: use the truncated string if malloc fails. */ + if (buff_heap != NULL) { + buff = buff_heap; + va_start(ap, fmt); + length = vsnprintf(buff, buff_length, fmt, ap); + va_end(ap); + } + } + + /* Write data, expanding unprintable characters. */ + p = buff; + i = 0; + while (*p != '\0') { + unsigned char c = *p++; + + if (isprint(c) && c != '\\') + copy_buff[i++] = c; + else { + copy_buff[i++] = '\\'; + switch (c) { + case '\a': copy_buff[i++] = 'a'; break; + case '\b': copy_buff[i++] = 'b'; break; + case '\f': copy_buff[i++] = 'f'; break; + case '\n': copy_buff[i++] = 'n'; break; +#if '\r' != '\n' + /* On some platforms, \n and \r are the same. */ + case '\r': copy_buff[i++] = 'r'; break; +#endif + case '\t': copy_buff[i++] = 't'; break; + case '\v': copy_buff[i++] = 'v'; break; + case '\\': copy_buff[i++] = '\\'; break; + default: + sprintf(copy_buff + i, "%03o", c); + i += 3; + } + } + + /* If our temp buffer is full, dump it and keep going. */ + if (i > (sizeof(copy_buff) - 8)) { + copy_buff[i++] = '\0'; + fprintf(f, "%s", copy_buff); + i = 0; + } + } + copy_buff[i++] = '\0'; + fprintf(f, "%s", copy_buff); + + /* If we allocated a heap-based buffer, free it now. */ + if (buff_heap != NULL) + free(buff_heap); +} + +static void +bsdtar_vwarnc(struct bsdtar *bsdtar, int code, const char *fmt, va_list ap) +{ + fprintf(stderr, "%s: ", bsdtar->progname); + vfprintf(stderr, fmt, ap); + if (code != 0) + fprintf(stderr, ": %s", strerror(code)); + fprintf(stderr, "\n"); +} + +void +bsdtar_warnc(struct bsdtar *bsdtar, int code, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + bsdtar_vwarnc(bsdtar, code, fmt, ap); + va_end(ap); +} + +void +bsdtar_errc(struct bsdtar *bsdtar, int eval, int code, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + bsdtar_vwarnc(bsdtar, code, fmt, ap); + va_end(ap); + exit(eval); +} + +int +yes(const char *fmt, ...) +{ + char buff[32]; + char *p; + ssize_t l; + + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, " (y/N)? "); + fflush(stderr); + + l = read(2, buff, sizeof(buff)); + if (l <= 0) + return (0); + buff[l] = 0; + + for (p = buff; *p != '\0'; p++) { + if (isspace(0xff & (int)*p)) + continue; + switch(*p) { + case 'y': case 'Y': + return (1); + case 'n': case 'N': + return (0); + default: + return (0); + } + } + + return (0); +} + +/* + * Read lines from file and do something with each one. If option_null + * is set, lines are terminated with zero bytes; otherwise, they're + * terminated with newlines. + * + * This uses a self-sizing buffer to handle arbitrarily-long lines. + * If the "process" function returns non-zero for any line, this + * function will return non-zero after attempting to process all + * remaining lines. + */ +int +process_lines(struct bsdtar *bsdtar, const char *pathname, + int (*process)(struct bsdtar *, const char *)) +{ + FILE *f; + char *buff, *buff_end, *line_start, *line_end, *p; + size_t buff_length, bytes_read, bytes_wanted; + int separator; + int ret; + + separator = bsdtar->option_null ? '\0' : '\n'; + ret = 0; + + if (strcmp(pathname, "-") == 0) + f = stdin; + else + f = fopen(pathname, "r"); + if (f == NULL) + bsdtar_errc(bsdtar, 1, errno, "Couldn't open %s", pathname); + buff_length = 8192; + buff = malloc(buff_length); + if (buff == NULL) + bsdtar_errc(bsdtar, 1, ENOMEM, "Can't read %s", pathname); + line_start = line_end = buff_end = buff; + for (;;) { + /* Get some more data into the buffer. */ + bytes_wanted = buff + buff_length - buff_end; + bytes_read = fread(buff_end, 1, bytes_wanted, f); + buff_end += bytes_read; + /* Process all complete lines in the buffer. */ + while (line_end < buff_end) { + if (*line_end == separator) { + *line_end = '\0'; + if ((*process)(bsdtar, line_start) != 0) + ret = -1; + line_start = line_end + 1; + line_end = line_start; + } else + line_end++; + } + if (feof(f)) + break; + if (ferror(f)) + bsdtar_errc(bsdtar, 1, errno, + "Can't read %s", pathname); + if (line_start > buff) { + /* Move a leftover fractional line to the beginning. */ + memmove(buff, line_start, buff_end - line_start); + buff_end -= line_start - buff; + line_end -= line_start - buff; + line_start = buff; + } else { + /* Line is too big; enlarge the buffer. */ + p = realloc(buff, buff_length *= 2); + if (p == NULL) + bsdtar_errc(bsdtar, 1, ENOMEM, + "Line too long in %s", pathname); + buff_end = p + (buff_end - buff); + line_end = p + (line_end - buff); + line_start = buff = p; + } + } + /* At end-of-file, handle the final line. */ + if (line_end > line_start) { + *line_end = '\0'; + if ((*process)(bsdtar, line_start) != 0) + ret = -1; + } + free(buff); + if (f != stdin) + fclose(f); + return (ret); +} + +/*- + * The logic here for -C <dir> attempts to avoid + * chdir() as long as possible. For example: + * "-C /foo -C /bar file" needs chdir("/bar") but not chdir("/foo") + * "-C /foo -C bar file" needs chdir("/foo/bar") + * "-C /foo -C bar /file1" does not need chdir() + * "-C /foo -C bar /file1 file2" needs chdir("/foo/bar") before file2 + * + * The only correct way to handle this is to record a "pending" chdir + * request and combine multiple requests intelligently until we + * need to process a non-absolute file. set_chdir() adds the new dir + * to the pending list; do_chdir() actually executes any pending chdir. + * + * This way, programs that build tar command lines don't have to worry + * about -C with non-existent directories; such requests will only + * fail if the directory must be accessed. + */ +void +set_chdir(struct bsdtar *bsdtar, const char *newdir) +{ + if (newdir[0] == '/') { + /* The -C /foo -C /bar case; dump first one. */ + free(bsdtar->pending_chdir); + bsdtar->pending_chdir = NULL; + } + if (bsdtar->pending_chdir == NULL) + /* Easy case: no previously-saved dir. */ + bsdtar->pending_chdir = strdup(newdir); + else { + /* The -C /foo -C bar case; concatenate */ + char *old_pending = bsdtar->pending_chdir; + size_t old_len = strlen(old_pending); + bsdtar->pending_chdir = malloc(old_len + strlen(newdir) + 2); + if (old_pending[old_len - 1] == '/') + old_pending[old_len - 1] = '\0'; + if (bsdtar->pending_chdir != NULL) + sprintf(bsdtar->pending_chdir, "%s/%s", + old_pending, newdir); + free(old_pending); + } + if (bsdtar->pending_chdir == NULL) + bsdtar_errc(bsdtar, 1, errno, "No memory"); +} + +void +do_chdir(struct bsdtar *bsdtar) +{ + if (bsdtar->pending_chdir == NULL) + return; + + if (chdir(bsdtar->pending_chdir) != 0) { + bsdtar_errc(bsdtar, 1, 0, "could not chdir to '%s'\n", + bsdtar->pending_chdir); + } + free(bsdtar->pending_chdir); + bsdtar->pending_chdir = NULL; +} + +/* + * Handle --strip-components and any future path-rewriting options. + * Returns non-zero if the pathname should not be extracted. + * + * TODO: Support pax-style regex path rewrites. + */ +int +edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry) +{ + const char *name = archive_entry_pathname(entry); + + /* Strip leading dir names as per --strip-components option. */ + if (bsdtar->strip_components > 0) { + int r = bsdtar->strip_components; + const char *p = name; + + while (r > 0) { + switch (*p++) { + case '/': + r--; + name = p; + break; + case '\0': + /* Path is too short, skip it. */ + return (1); + } + } + } + + /* Strip redundant leading '/' characters. */ + while (name[0] == '/' && name[1] == '/') + name++; + + /* Strip leading '/' unless user has asked us not to. */ + if (name[0] == '/' && !bsdtar->option_absolute_paths) { + /* Generate a warning the first time this happens. */ + if (!bsdtar->warned_lead_slash) { + bsdtar_warnc(bsdtar, 0, + "Removing leading '/' from member names"); + bsdtar->warned_lead_slash = 1; + } + name++; + /* Special case: Stripping leading '/' from "/" yields ".". */ + if (*name == '\0') + name = "."; + } + + /* Safely replace name in archive_entry. */ + if (name != archive_entry_pathname(entry)) { + char *q = strdup(name); + archive_entry_copy_pathname(entry, q); + free(q); + } + return (0); +} + +/* + * Like strcmp(), but try to be a little more aware of the fact that + * we're comparing two paths. Right now, it just handles leading + * "./" and trailing '/' specially, so that "a/b/" == "./a/b" + * + * TODO: Make this better, so that "./a//b/./c/" == "a/b/c" + * TODO: After this works, push it down into libarchive. + * TODO: Publish the path normalization routines in libarchive so + * that bsdtar can normalize paths and use fast strcmp() instead + * of this. + */ + +int +pathcmp(const char *a, const char *b) +{ + /* Skip leading './' */ + if (a[0] == '.' && a[1] == '/' && a[2] != '\0') + a += 2; + if (b[0] == '.' && b[1] == '/' && b[2] != '\0') + b += 2; + /* Find the first difference, or return (0) if none. */ + while (*a == *b) { + if (*a == '\0') + return (0); + a++; + b++; + } + /* + * If one ends in '/' and the other one doesn't, + * they're the same. + */ + if (a[0] == '/' && a[1] == '\0' && b[0] == '\0') + return (0); + if (a[0] == '\0' && b[0] == '/' && b[1] == '\0') + return (0); + /* They're really different, return the correct sign. */ + return (*(const unsigned char *)a - *(const unsigned char *)b); +} diff --git a/libarchive/libarchive-2.4.17/tar/write.c b/libarchive/libarchive-2.4.17/tar/write.c new file mode 100644 index 0000000..3b8cc51 --- /dev/null +++ b/libarchive/libarchive-2.4.17/tar/write.c @@ -0,0 +1,1550 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bsdtar_platform.h" +__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.64 2008/02/19 05:27:17 kientzle Exp $"); + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_ACL_H +#include <sys/acl.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_ATTR_XATTR_H +#include <attr/xattr.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include <ext2fs/ext2_fs.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_FNMATCH_H +#include <fnmatch.h> +#endif +#ifdef HAVE_GRP_H +#include <grp.h> +#endif +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#ifdef HAVE_LINUX_FS_H +#include <linux/fs.h> /* for Linux file flags */ +#endif +#ifdef HAVE_LINUX_EXT2_FS_H +#include <linux/ext2_fs.h> /* for Linux file flags */ +#endif +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "bsdtar.h" +#include "tree.h" + +/* Fixed size of uname/gname caches. */ +#define name_cache_size 101 + +static const char * const NO_NAME = "(noname)"; + +/* Initial size of link cache. */ +#define links_cache_initial_size 1024 + +struct archive_dir_entry { + struct archive_dir_entry *next; + time_t mtime_sec; + int mtime_nsec; + char *name; +}; + +struct archive_dir { + struct archive_dir_entry *head, *tail; +}; + +struct links_cache { + unsigned long number_entries; + size_t number_buckets; + struct links_entry **buckets; +}; + +struct links_entry { + struct links_entry *next; + struct links_entry *previous; + int links; + dev_t dev; + ino_t ino; + char *name; +}; + +struct name_cache { + int probes; + int hits; + size_t size; + struct { + id_t id; + const char *name; + } cache[name_cache_size]; +}; + +static void add_dir_list(struct bsdtar *bsdtar, const char *path, + time_t mtime_sec, int mtime_nsec); +static int append_archive(struct bsdtar *, struct archive *, + struct archive *ina); +static int append_archive_filename(struct bsdtar *, + struct archive *, const char *fname); +static void archive_names_from_file(struct bsdtar *bsdtar, + struct archive *a); +static int archive_names_from_file_helper(struct bsdtar *bsdtar, + const char *line); +static int copy_file_data(struct bsdtar *bsdtar, + struct archive *a, struct archive *ina); +static void create_cleanup(struct bsdtar *); +static void free_buckets(struct bsdtar *, struct links_cache *); +static void free_cache(struct name_cache *cache); +static const char * lookup_gname(struct bsdtar *bsdtar, gid_t gid); +static int lookup_gname_helper(struct bsdtar *bsdtar, + const char **name, id_t gid); +static void lookup_hardlink(struct bsdtar *, + struct archive_entry *entry, const struct stat *); +static const char * lookup_uname(struct bsdtar *bsdtar, uid_t uid); +static int lookup_uname_helper(struct bsdtar *bsdtar, + const char **name, id_t uid); +static int new_enough(struct bsdtar *, const char *path, + const struct stat *); +static void setup_acls(struct bsdtar *, struct archive_entry *, + const char *path); +static void setup_xattrs(struct bsdtar *, struct archive_entry *, + const char *path); +static void test_for_append(struct bsdtar *); +static void write_archive(struct archive *, struct bsdtar *); +static void write_entry(struct bsdtar *, struct archive *, + const struct stat *, const char *pathname, + const char *accpath); +static int write_file_data(struct bsdtar *, struct archive *, + int fd); +static void write_hierarchy(struct bsdtar *, struct archive *, + const char *); + +void +tar_mode_c(struct bsdtar *bsdtar) +{ + struct archive *a; + int r; + + if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) + bsdtar_errc(bsdtar, 1, 0, "no files or directories specified"); + + a = archive_write_new(); + + /* Support any format that the library supports. */ + if (bsdtar->create_format == NULL) { + r = archive_write_set_format_pax_restricted(a); + bsdtar->create_format = "pax restricted"; + } else { + r = archive_write_set_format_by_name(a, bsdtar->create_format); + } + if (r != ARCHIVE_OK) { + fprintf(stderr, "Can't use format %s: %s\n", + bsdtar->create_format, + archive_error_string(a)); + usage(bsdtar); + } + + /* + * If user explicitly set the block size, then assume they + * want the last block padded as well. Otherwise, use the + * default block size and accept archive_write_open_file()'s + * default padding decisions. + */ + if (bsdtar->bytes_per_block != 0) { + archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); + archive_write_set_bytes_in_last_block(a, + bsdtar->bytes_per_block); + } else + archive_write_set_bytes_per_block(a, DEFAULT_BYTES_PER_BLOCK); + + if (bsdtar->compress_program) { + archive_write_set_compression_program(a, bsdtar->compress_program); + } else { + switch (bsdtar->create_compression) { + case 0: + archive_write_set_compression_none(a); + break; +#ifdef HAVE_LIBBZ2 + case 'j': case 'y': + archive_write_set_compression_bzip2(a); + break; +#endif +#ifdef HAVE_LIBZ + case 'z': + archive_write_set_compression_gzip(a); + break; +#endif + default: + bsdtar_errc(bsdtar, 1, 0, + "Unrecognized compression option -%c", + bsdtar->create_compression); + } + } + + r = archive_write_open_file(a, bsdtar->filename); + if (r != ARCHIVE_OK) + bsdtar_errc(bsdtar, 1, 0, archive_error_string(a)); + + write_archive(a, bsdtar); + + if (bsdtar->option_totals) { + fprintf(stderr, "Total bytes written: " BSDTAR_FILESIZE_PRINTF "\n", + (BSDTAR_FILESIZE_TYPE)archive_position_compressed(a)); + } + + archive_write_finish(a); +} + +/* + * Same as 'c', except we only support tar or empty formats in + * uncompressed files on disk. + */ +void +tar_mode_r(struct bsdtar *bsdtar) +{ + off_t end_offset; + int format; + struct archive *a; + struct archive_entry *entry; + int r; + + /* Sanity-test some arguments and the file. */ + test_for_append(bsdtar); + + format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; + + bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT, 0666); + if (bsdtar->fd < 0) + bsdtar_errc(bsdtar, 1, errno, + "Cannot open %s", bsdtar->filename); + + a = archive_read_new(); + archive_read_support_compression_all(a); + archive_read_support_format_tar(a); + archive_read_support_format_gnutar(a); + r = archive_read_open_fd(a, bsdtar->fd, 10240); + if (r != ARCHIVE_OK) + bsdtar_errc(bsdtar, 1, archive_errno(a), + "Can't read archive %s: %s", bsdtar->filename, + archive_error_string(a)); + while (0 == archive_read_next_header(a, &entry)) { + if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) { + archive_read_finish(a); + close(bsdtar->fd); + bsdtar_errc(bsdtar, 1, 0, + "Cannot append to compressed archive."); + } + /* Keep going until we hit end-of-archive */ + format = archive_format(a); + } + + end_offset = archive_read_header_position(a); + archive_read_finish(a); + + /* Re-open archive for writing */ + a = archive_write_new(); + archive_write_set_compression_none(a); + /* + * Set the format to be used for writing. To allow people to + * extend empty files, we need to allow them to specify the format, + * which opens the possibility that they will specify a format that + * doesn't match the existing format. Hence, the following bit + * of arcane ugliness. + */ + + if (bsdtar->create_format != NULL) { + /* If the user requested a format, use that, but ... */ + archive_write_set_format_by_name(a, + bsdtar->create_format); + /* ... complain if it's not compatible. */ + format &= ARCHIVE_FORMAT_BASE_MASK; + if (format != (int)(archive_format(a) & ARCHIVE_FORMAT_BASE_MASK) + && format != ARCHIVE_FORMAT_EMPTY) { + bsdtar_errc(bsdtar, 1, 0, + "Format %s is incompatible with the archive %s.", + bsdtar->create_format, bsdtar->filename); + } + } else { + /* + * Just preserve the current format, with a little care + * for formats that libarchive can't write. + */ + if (format == ARCHIVE_FORMAT_TAR_GNUTAR) + /* TODO: When gtar supports pax, use pax restricted. */ + format = ARCHIVE_FORMAT_TAR_USTAR; + if (format == ARCHIVE_FORMAT_EMPTY) + format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; + archive_write_set_format(a, format); + } + lseek(bsdtar->fd, end_offset, SEEK_SET); /* XXX check return val XXX */ + archive_write_open_fd(a, bsdtar->fd); /* XXX check return val XXX */ + + write_archive(a, bsdtar); /* XXX check return val XXX */ + + if (bsdtar->option_totals) { + fprintf(stderr, "Total bytes written: " BSDTAR_FILESIZE_PRINTF "\n", + (BSDTAR_FILESIZE_TYPE)archive_position_compressed(a)); + } + + archive_write_finish(a); + close(bsdtar->fd); + bsdtar->fd = -1; +} + +void +tar_mode_u(struct bsdtar *bsdtar) +{ + off_t end_offset; + struct archive *a; + struct archive_entry *entry; + int format; + struct archive_dir_entry *p; + struct archive_dir archive_dir; + + bsdtar->archive_dir = &archive_dir; + memset(&archive_dir, 0, sizeof(archive_dir)); + + format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; + + /* Sanity-test some arguments and the file. */ + test_for_append(bsdtar); + + bsdtar->fd = open(bsdtar->filename, O_RDWR); + if (bsdtar->fd < 0) + bsdtar_errc(bsdtar, 1, errno, + "Cannot open %s", bsdtar->filename); + + a = archive_read_new(); + archive_read_support_compression_all(a); + archive_read_support_format_tar(a); + archive_read_support_format_gnutar(a); + if (archive_read_open_fd(a, bsdtar->fd, + bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block : + DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { + bsdtar_errc(bsdtar, 1, 0, + "Can't open %s: %s", bsdtar->filename, + archive_error_string(a)); + } + + /* Build a list of all entries and their recorded mod times. */ + while (0 == archive_read_next_header(a, &entry)) { + if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) { + archive_read_finish(a); + close(bsdtar->fd); + bsdtar_errc(bsdtar, 1, 0, + "Cannot append to compressed archive."); + } + add_dir_list(bsdtar, archive_entry_pathname(entry), + archive_entry_mtime(entry), + archive_entry_mtime_nsec(entry)); + /* Record the last format determination we see */ + format = archive_format(a); + /* Keep going until we hit end-of-archive */ + } + + end_offset = archive_read_header_position(a); + archive_read_finish(a); + + /* Re-open archive for writing. */ + a = archive_write_new(); + archive_write_set_compression_none(a); + /* + * Set format to same one auto-detected above, except that + * we don't write GNU tar format, so use ustar instead. + */ + if (format == ARCHIVE_FORMAT_TAR_GNUTAR) + format = ARCHIVE_FORMAT_TAR_USTAR; + archive_write_set_format(a, format); + if (bsdtar->bytes_per_block != 0) { + archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block); + archive_write_set_bytes_in_last_block(a, + bsdtar->bytes_per_block); + } else + archive_write_set_bytes_per_block(a, DEFAULT_BYTES_PER_BLOCK); + lseek(bsdtar->fd, end_offset, SEEK_SET); + ftruncate(bsdtar->fd, end_offset); + archive_write_open_fd(a, bsdtar->fd); + + write_archive(a, bsdtar); + + if (bsdtar->option_totals) { + fprintf(stderr, "Total bytes written: " BSDTAR_FILESIZE_PRINTF "\n", + (BSDTAR_FILESIZE_TYPE)archive_position_compressed(a)); + } + + archive_write_finish(a); + close(bsdtar->fd); + bsdtar->fd = -1; + + while (bsdtar->archive_dir->head != NULL) { + p = bsdtar->archive_dir->head->next; + free(bsdtar->archive_dir->head->name); + free(bsdtar->archive_dir->head); + bsdtar->archive_dir->head = p; + } + bsdtar->archive_dir->tail = NULL; +} + + +/* + * Write user-specified files/dirs to opened archive. + */ +static void +write_archive(struct archive *a, struct bsdtar *bsdtar) +{ + const char *arg; + + if (bsdtar->names_from_file != NULL) + archive_names_from_file(bsdtar, a); + + while (*bsdtar->argv) { + arg = *bsdtar->argv; + if (arg[0] == '-' && arg[1] == 'C') { + arg += 2; + if (*arg == '\0') { + bsdtar->argv++; + arg = *bsdtar->argv; + if (arg == NULL) { + bsdtar_warnc(bsdtar, 1, 0, + "Missing argument for -C"); + bsdtar->return_value = 1; + return; + } + } + set_chdir(bsdtar, arg); + } else { + if (*arg != '/' && (arg[0] != '@' || arg[1] != '/')) + do_chdir(bsdtar); /* Handle a deferred -C */ + if (*arg == '@') { + if (append_archive_filename(bsdtar, a, + arg + 1) != 0) + break; + } else + write_hierarchy(bsdtar, a, arg); + } + bsdtar->argv++; + } + + create_cleanup(bsdtar); + if (archive_write_close(a)) { + bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); + bsdtar->return_value = 1; + } +} + +/* + * Archive names specified in file. + * + * Unless --null was specified, a line containing exactly "-C" will + * cause the next line to be a directory to pass to chdir(). If + * --null is specified, then a line "-C" is just another filename. + */ +void +archive_names_from_file(struct bsdtar *bsdtar, struct archive *a) +{ + bsdtar->archive = a; + + bsdtar->next_line_is_dir = 0; + process_lines(bsdtar, bsdtar->names_from_file, + archive_names_from_file_helper); + if (bsdtar->next_line_is_dir) + bsdtar_errc(bsdtar, 1, errno, + "Unexpected end of filename list; " + "directory expected after -C"); +} + +static int +archive_names_from_file_helper(struct bsdtar *bsdtar, const char *line) +{ + if (bsdtar->next_line_is_dir) { + set_chdir(bsdtar, line); + bsdtar->next_line_is_dir = 0; + } else if (!bsdtar->option_null && strcmp(line, "-C") == 0) + bsdtar->next_line_is_dir = 1; + else { + if (*line != '/') + do_chdir(bsdtar); /* Handle a deferred -C */ + write_hierarchy(bsdtar, bsdtar->archive, line); + } + return (0); +} + +/* + * Copy from specified archive to current archive. Returns non-zero + * for write errors (which force us to terminate the entire archiving + * operation). If there are errors reading the input archive, we set + * bsdtar->return_value but return zero, so the overall archiving + * operation will complete and return non-zero. + */ +static int +append_archive_filename(struct bsdtar *bsdtar, struct archive *a, + const char *filename) +{ + struct archive *ina; + int rc; + + if (strcmp(filename, "-") == 0) + filename = NULL; /* Library uses NULL for stdio. */ + + ina = archive_read_new(); + archive_read_support_format_all(ina); + archive_read_support_compression_all(ina); + if (archive_read_open_file(ina, filename, 10240)) { + bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(ina)); + bsdtar->return_value = 1; + return (0); + } + + rc = append_archive(bsdtar, a, ina); + + if (archive_errno(ina)) { + bsdtar_warnc(bsdtar, 0, "Error reading archive %s: %s", + filename, archive_error_string(ina)); + bsdtar->return_value = 1; + } + archive_read_finish(ina); + + return (rc); +} + +static int +append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) +{ + struct archive_entry *in_entry; + int e; + + while (0 == archive_read_next_header(ina, &in_entry)) { + if (!new_enough(bsdtar, archive_entry_pathname(in_entry), + archive_entry_stat(in_entry))) + continue; + if (excluded(bsdtar, archive_entry_pathname(in_entry))) + continue; + if (bsdtar->option_interactive && + !yes("copy '%s'", archive_entry_pathname(in_entry))) + continue; + if (bsdtar->verbose) + safe_fprintf(stderr, "a %s", + archive_entry_pathname(in_entry)); + + e = archive_write_header(a, in_entry); + if (e != ARCHIVE_OK) { + if (!bsdtar->verbose) + bsdtar_warnc(bsdtar, 0, "%s: %s", + archive_entry_pathname(in_entry), + archive_error_string(a)); + else + fprintf(stderr, ": %s", archive_error_string(a)); + } + if (e == ARCHIVE_FATAL) + exit(1); + + if (e >= ARCHIVE_WARN) + if (copy_file_data(bsdtar, a, ina)) + exit(1); + + if (bsdtar->verbose) + fprintf(stderr, "\n"); + } + + /* Note: If we got here, we saw no write errors, so return success. */ + return (0); +} + +/* Helper function to copy data between archives. */ +static int +copy_file_data(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) +{ + char buff[64*1024]; + ssize_t bytes_read; + ssize_t bytes_written; + + bytes_read = archive_read_data(ina, buff, sizeof(buff)); + while (bytes_read > 0) { + bytes_written = archive_write_data(a, buff, bytes_read); + if (bytes_written < bytes_read) { + bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); + return (-1); + } + bytes_read = archive_read_data(ina, buff, sizeof(buff)); + } + + return (0); +} + +/* + * Add the file or dir hierarchy named by 'path' to the archive + */ +static void +write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) +{ + struct tree *tree; + char symlink_mode = bsdtar->symlink_mode; + dev_t first_dev = 0; + int dev_recorded = 0; + int tree_ret; +#ifdef __linux + int fd, r; + unsigned long fflags; +#endif + + tree = tree_open(path); + + if (!tree) { + bsdtar_warnc(bsdtar, errno, "%s: Cannot open", path); + bsdtar->return_value = 1; + return; + } + + while ((tree_ret = tree_next(tree))) { + const char *name = tree_current_path(tree); + const struct stat *st = NULL, *lst = NULL; + int descend; + + if (tree_ret == TREE_ERROR_DIR) + bsdtar_warnc(bsdtar, errno, "%s: Couldn't visit directory", name); + if (tree_ret != TREE_REGULAR) + continue; + lst = tree_current_lstat(tree); + if (lst == NULL) { + /* Couldn't lstat(); must not exist. */ + bsdtar_warnc(bsdtar, errno, "%s: Cannot stat", name); + + /* + * Report an error via the exit code if the failed + * path is a prefix of what the user provided via + * the command line. (Testing for string equality + * here won't work due to trailing '/' characters.) + */ + if (memcmp(name, path, strlen(name)) == 0) + bsdtar->return_value = 1; + + continue; + } + if (S_ISLNK(lst->st_mode)) + st = tree_current_stat(tree); + /* Default: descend into any dir or symlink to dir. */ + /* We'll adjust this later on. */ + descend = 0; + if ((st != NULL) && S_ISDIR(st->st_mode)) + descend = 1; + if ((lst != NULL) && S_ISDIR(lst->st_mode)) + descend = 1; + + /* + * If user has asked us not to cross mount points, + * then don't descend into into a dir on a different + * device. + */ + if (!dev_recorded) { + first_dev = lst->st_dev; + dev_recorded = 1; + } + if (bsdtar->option_dont_traverse_mounts) { + if (lst != NULL && lst->st_dev != first_dev) + descend = 0; + } + + /* + * If this file/dir is flagged "nodump" and we're + * honoring such flags, skip this file/dir. + */ +#ifdef HAVE_CHFLAGS + if (bsdtar->option_honor_nodump && + (lst->st_flags & UF_NODUMP)) + continue; +#endif + +#ifdef __linux + /* + * Linux has a nodump flag too but to read it + * we have to open() the file/dir and do an ioctl on it... + */ + if (bsdtar->option_honor_nodump && + ((fd = open(name, O_RDONLY|O_NONBLOCK)) >= 0) && + ((r = ioctl(fd, EXT2_IOC_GETFLAGS, &fflags)), + close(fd), r) >= 0 && + (fflags & EXT2_NODUMP_FL)) + continue; +#endif + + /* + * If this file/dir is excluded by a filename + * pattern, skip it. + */ + if (excluded(bsdtar, name)) + continue; + + /* + * If the user vetoes this file/directory, skip it. + */ + if (bsdtar->option_interactive && + !yes("add '%s'", name)) + continue; + + /* + * If this is a dir, decide whether or not to recurse. + */ + if (bsdtar->option_no_subdirs) + descend = 0; + + /* + * Distinguish 'L'/'P'/'H' symlink following. + */ + switch(symlink_mode) { + case 'H': + /* 'H': After the first item, rest like 'P'. */ + symlink_mode = 'P'; + /* 'H': First item (from command line) like 'L'. */ + /* FALLTHROUGH */ + case 'L': + /* 'L': Do descend through a symlink to dir. */ + /* 'L': Archive symlink to file as file. */ + lst = tree_current_stat(tree); + /* If stat fails, we have a broken symlink; + * in that case, archive the link as such. */ + if (lst == NULL) + lst = tree_current_lstat(tree); + break; + default: + /* 'P': Don't descend through a symlink to dir. */ + if (!S_ISDIR(lst->st_mode)) + descend = 0; + /* 'P': Archive symlink to file as symlink. */ + /* lst = tree_current_lstat(tree); */ + break; + } + + if (descend) + tree_descend(tree); + + /* + * Write the entry. Note that write_entry() handles + * pathname editing and newness testing. + */ + write_entry(bsdtar, a, lst, name, + tree_current_access_path(tree)); + } + tree_close(tree); +} + +/* + * Add a single filesystem object to the archive. + */ +static void +write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st, + const char *pathname, const char *accpath) +{ + struct archive_entry *entry; + int e; + int fd; +#ifdef __linux + int r; + unsigned long stflags; +#endif + static char linkbuffer[PATH_MAX+1]; + + fd = -1; + entry = archive_entry_new(); + + archive_entry_set_pathname(entry, pathname); + + /* + * Rewrite the pathname to be archived. If rewrite + * fails, skip the entry. + */ + if (edit_pathname(bsdtar, entry)) + goto abort; + + /* + * In -u mode, check that the file is newer than what's + * already in the archive; in all modes, obey --newerXXX flags. + */ + if (!new_enough(bsdtar, archive_entry_pathname(entry), st)) + goto abort; + + if (!S_ISDIR(st->st_mode) && (st->st_nlink > 1)) + lookup_hardlink(bsdtar, entry, st); + + /* Display entry as we process it. This format is required by SUSv2. */ + if (bsdtar->verbose) + safe_fprintf(stderr, "a %s", archive_entry_pathname(entry)); + + /* Read symbolic link information. */ + if ((st->st_mode & S_IFMT) == S_IFLNK) { + int lnklen; + + lnklen = readlink(accpath, linkbuffer, PATH_MAX); + if (lnklen < 0) { + if (!bsdtar->verbose) + bsdtar_warnc(bsdtar, errno, + "%s: Couldn't read symbolic link", + pathname); + else + safe_fprintf(stderr, + ": Couldn't read symbolic link: %s", + strerror(errno)); + goto cleanup; + } + linkbuffer[lnklen] = 0; + archive_entry_set_symlink(entry, linkbuffer); + } + + /* Look up username and group name. */ + archive_entry_set_uname(entry, lookup_uname(bsdtar, st->st_uid)); + archive_entry_set_gname(entry, lookup_gname(bsdtar, st->st_gid)); + +#ifdef HAVE_CHFLAGS + if (st->st_flags != 0) + archive_entry_set_fflags(entry, st->st_flags, 0); +#endif + +#ifdef __linux + if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) && + ((fd = open(accpath, O_RDONLY|O_NONBLOCK)) >= 0) && + ((r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags)), close(fd), (fd = -1), r) >= 0 && + stflags) { + archive_entry_set_fflags(entry, stflags, 0); + } +#endif + + archive_entry_copy_stat(entry, st); + setup_acls(bsdtar, entry, accpath); + setup_xattrs(bsdtar, entry, accpath); + + /* + * If it's a regular file (and non-zero in size) make sure we + * can open it before we start to write. In particular, note + * that we can always archive a zero-length file, even if we + * can't read it. + */ + if (S_ISREG(st->st_mode) && st->st_size > 0) { + fd = open(accpath, O_RDONLY); + if (fd < 0) { + if (!bsdtar->verbose) + bsdtar_warnc(bsdtar, errno, "%s: could not open file", pathname); + else + fprintf(stderr, ": %s", strerror(errno)); + goto cleanup; + } + } + + /* Non-regular files get archived with zero size. */ + if (!S_ISREG(st->st_mode)) + archive_entry_set_size(entry, 0); + + e = archive_write_header(a, entry); + if (e != ARCHIVE_OK) { + if (!bsdtar->verbose) + bsdtar_warnc(bsdtar, 0, "%s: %s", pathname, + archive_error_string(a)); + else + fprintf(stderr, ": %s", archive_error_string(a)); + } + + if (e == ARCHIVE_FATAL) + exit(1); + + /* + * If we opened a file earlier, write it out now. Note that + * the format handler might have reset the size field to zero + * to inform us that the archive body won't get stored. In + * that case, just skip the write. + */ + if (e >= ARCHIVE_WARN && fd >= 0 && archive_entry_size(entry) > 0) + if (write_file_data(bsdtar, a, fd)) + exit(1); + +cleanup: + if (bsdtar->verbose) + fprintf(stderr, "\n"); + +abort: + if (fd >= 0) + close(fd); + + if (entry != NULL) + archive_entry_free(entry); +} + + +/* Helper function to copy file to archive, with stack-allocated buffer. */ +static int +write_file_data(struct bsdtar *bsdtar, struct archive *a, int fd) +{ + char buff[64*1024]; + ssize_t bytes_read; + ssize_t bytes_written; + + /* XXX TODO: Allocate buffer on heap and store pointer to + * it in bsdtar structure; arrange cleanup as well. XXX */ + + bytes_read = read(fd, buff, sizeof(buff)); + while (bytes_read > 0) { + bytes_written = archive_write_data(a, buff, bytes_read); + if (bytes_written < 0) { + /* Write failed; this is bad */ + bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); + return (-1); + } + if (bytes_written < bytes_read) { + /* Write was truncated; warn but continue. */ + bsdtar_warnc(bsdtar, 0, + "Truncated write; file may have grown while being archived."); + return (0); + } + bytes_read = read(fd, buff, sizeof(buff)); + } + return 0; +} + + +static void +create_cleanup(struct bsdtar *bsdtar) +{ + /* Free inode->pathname map used for hardlink detection. */ + if (bsdtar->links_cache != NULL) { + free_buckets(bsdtar, bsdtar->links_cache); + free(bsdtar->links_cache); + bsdtar->links_cache = NULL; + } + + free_cache(bsdtar->uname_cache); + bsdtar->uname_cache = NULL; + free_cache(bsdtar->gname_cache); + bsdtar->gname_cache = NULL; +} + + +static void +free_buckets(struct bsdtar *bsdtar, struct links_cache *links_cache) +{ + size_t i; + + if (links_cache->buckets == NULL) + return; + + for (i = 0; i < links_cache->number_buckets; i++) { + while (links_cache->buckets[i] != NULL) { + struct links_entry *lp = links_cache->buckets[i]->next; + if (bsdtar->option_warn_links) + bsdtar_warnc(bsdtar, 0, "Missing links to %s", + links_cache->buckets[i]->name); + if (links_cache->buckets[i]->name != NULL) + free(links_cache->buckets[i]->name); + free(links_cache->buckets[i]); + links_cache->buckets[i] = lp; + } + } + free(links_cache->buckets); + links_cache->buckets = NULL; +} + +static void +lookup_hardlink(struct bsdtar *bsdtar, struct archive_entry *entry, + const struct stat *st) +{ + struct links_cache *links_cache; + struct links_entry *le, **new_buckets; + int hash; + size_t i, new_size; + + /* If necessary, initialize the links cache. */ + links_cache = bsdtar->links_cache; + if (links_cache == NULL) { + bsdtar->links_cache = malloc(sizeof(struct links_cache)); + if (bsdtar->links_cache == NULL) + bsdtar_errc(bsdtar, 1, ENOMEM, + "No memory for hardlink detection."); + links_cache = bsdtar->links_cache; + memset(links_cache, 0, sizeof(struct links_cache)); + links_cache->number_buckets = links_cache_initial_size; + links_cache->buckets = malloc(links_cache->number_buckets * + sizeof(links_cache->buckets[0])); + if (links_cache->buckets == NULL) { + bsdtar_errc(bsdtar, 1, ENOMEM, + "No memory for hardlink detection."); + } + for (i = 0; i < links_cache->number_buckets; i++) + links_cache->buckets[i] = NULL; + } + + /* If the links cache overflowed and got flushed, don't bother. */ + if (links_cache->buckets == NULL) + return; + + /* If the links cache is getting too full, enlarge the hash table. */ + if (links_cache->number_entries > links_cache->number_buckets * 2) + { + new_size = links_cache->number_buckets * 2; + new_buckets = malloc(new_size * sizeof(struct links_entry *)); + + if (new_buckets != NULL) { + memset(new_buckets, 0, + new_size * sizeof(struct links_entry *)); + for (i = 0; i < links_cache->number_buckets; i++) { + while (links_cache->buckets[i] != NULL) { + /* Remove entry from old bucket. */ + le = links_cache->buckets[i]; + links_cache->buckets[i] = le->next; + + /* Add entry to new bucket. */ + hash = (le->dev ^ le->ino) % new_size; + + if (new_buckets[hash] != NULL) + new_buckets[hash]->previous = + le; + le->next = new_buckets[hash]; + le->previous = NULL; + new_buckets[hash] = le; + } + } + free(links_cache->buckets); + links_cache->buckets = new_buckets; + links_cache->number_buckets = new_size; + } else { + free_buckets(bsdtar, links_cache); + bsdtar_warnc(bsdtar, ENOMEM, + "No more memory for recording hard links"); + bsdtar_warnc(bsdtar, 0, + "Remaining links will be dumped as full files"); + } + } + + /* Try to locate this entry in the links cache. */ + hash = ( st->st_dev ^ st->st_ino ) % links_cache->number_buckets; + for (le = links_cache->buckets[hash]; le != NULL; le = le->next) { + if (le->dev == st->st_dev && le->ino == st->st_ino) { + archive_entry_copy_hardlink(entry, le->name); + + /* + * Decrement link count each time and release + * the entry if it hits zero. This saves + * memory and is necessary for proper -l + * implementation. + */ + if (--le->links <= 0) { + if (le->previous != NULL) + le->previous->next = le->next; + if (le->next != NULL) + le->next->previous = le->previous; + if (le->name != NULL) + free(le->name); + if (links_cache->buckets[hash] == le) + links_cache->buckets[hash] = le->next; + links_cache->number_entries--; + free(le); + } + + return; + } + } + + /* Add this entry to the links cache. */ + le = malloc(sizeof(struct links_entry)); + if (le != NULL) + le->name = strdup(archive_entry_pathname(entry)); + if ((le == NULL) || (le->name == NULL)) { + free_buckets(bsdtar, links_cache); + bsdtar_warnc(bsdtar, ENOMEM, + "No more memory for recording hard links"); + bsdtar_warnc(bsdtar, 0, + "Remaining hard links will be dumped as full files"); + if (le != NULL) + free(le); + return; + } + if (links_cache->buckets[hash] != NULL) + links_cache->buckets[hash]->previous = le; + links_cache->number_entries++; + le->next = links_cache->buckets[hash]; + le->previous = NULL; + links_cache->buckets[hash] = le; + le->dev = st->st_dev; + le->ino = st->st_ino; + le->links = st->st_nlink - 1; +} + +#ifdef HAVE_POSIX_ACL +static void setup_acl(struct bsdtar *bsdtar, + struct archive_entry *entry, const char *accpath, + int acl_type, int archive_entry_acl_type); + +static void +setup_acls(struct bsdtar *bsdtar, struct archive_entry *entry, + const char *accpath) +{ + archive_entry_acl_clear(entry); + + setup_acl(bsdtar, entry, accpath, + ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); + /* Only directories can have default ACLs. */ + if (S_ISDIR(archive_entry_mode(entry))) + setup_acl(bsdtar, entry, accpath, + ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); +} + +static void +setup_acl(struct bsdtar *bsdtar, struct archive_entry *entry, + const char *accpath, int acl_type, int archive_entry_acl_type) +{ + acl_t acl; + acl_tag_t acl_tag; + acl_entry_t acl_entry; + acl_permset_t acl_permset; + int s, ae_id, ae_tag, ae_perm; + const char *ae_name; + + /* Retrieve access ACL from file. */ + acl = acl_get_file(accpath, acl_type); + if (acl != NULL) { + s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); + while (s == 1) { + ae_id = -1; + ae_name = NULL; + + acl_get_tag_type(acl_entry, &acl_tag); + if (acl_tag == ACL_USER) { + ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry); + ae_name = lookup_uname(bsdtar, ae_id); + ae_tag = ARCHIVE_ENTRY_ACL_USER; + } else if (acl_tag == ACL_GROUP) { + ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry); + ae_name = lookup_gname(bsdtar, ae_id); + ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + } else if (acl_tag == ACL_MASK) { + ae_tag = ARCHIVE_ENTRY_ACL_MASK; + } else if (acl_tag == ACL_USER_OBJ) { + ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + } else if (acl_tag == ACL_GROUP_OBJ) { + ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + } else if (acl_tag == ACL_OTHER) { + ae_tag = ARCHIVE_ENTRY_ACL_OTHER; + } else { + /* Skip types that libarchive can't support. */ + continue; + } + + acl_get_permset(acl_entry, &acl_permset); + ae_perm = 0; + /* + * acl_get_perm() is spelled differently on different + * platforms; see bsdtar_platform.h for details. + */ + if (ACL_GET_PERM(acl_permset, ACL_EXECUTE)) + ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE; + if (ACL_GET_PERM(acl_permset, ACL_READ)) + ae_perm |= ARCHIVE_ENTRY_ACL_READ; + if (ACL_GET_PERM(acl_permset, ACL_WRITE)) + ae_perm |= ARCHIVE_ENTRY_ACL_WRITE; + + archive_entry_acl_add_entry(entry, + archive_entry_acl_type, ae_perm, ae_tag, + ae_id, ae_name); + + s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); + } + acl_free(acl); + } +} +#else +static void +setup_acls(struct bsdtar *bsdtar, struct archive_entry *entry, + const char *accpath) +{ + (void)bsdtar; + (void)entry; + (void)accpath; +} +#endif + +#if HAVE_LISTXATTR && HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR + +static void +setup_xattr(struct bsdtar *bsdtar, struct archive_entry *entry, + const char *accpath, const char *name) +{ + size_t size; + void *value = NULL; + char symlink_mode = bsdtar->symlink_mode; + + if (symlink_mode == 'H') + size = getxattr(accpath, name, NULL, 0); + else + size = lgetxattr(accpath, name, NULL, 0); + + if (size == -1) { + bsdtar_warnc(bsdtar, errno, "Couldn't get extended attribute"); + return; + } + + if (size > 0 && (value = malloc(size)) == NULL) { + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + return; + } + + if (symlink_mode == 'H') + size = getxattr(accpath, name, value, size); + else + size = lgetxattr(accpath, name, value, size); + + if (size == -1) { + bsdtar_warnc(bsdtar, errno, "Couldn't get extended attribute"); + return; + } + + archive_entry_xattr_add_entry(entry, name, value, size); + + free(value); +} + +/* + * Linux extended attribute support + */ +static void +setup_xattrs(struct bsdtar *bsdtar, struct archive_entry *entry, + const char *accpath) +{ + char *list, *p; + size_t list_size; + char symlink_mode = bsdtar->symlink_mode; + + if (symlink_mode == 'H') + list_size = listxattr(accpath, NULL, 0); + else + list_size = llistxattr(accpath, NULL, 0); + + if (list_size == -1) { + bsdtar_warnc(bsdtar, errno, + "Couldn't list extended attributes"); + return; + } else if (list_size == 0) + return; + + if ((list = malloc(list_size)) == NULL) { + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + return; + } + + if (symlink_mode == 'H') + list_size = listxattr(accpath, list, list_size); + else + list_size = llistxattr(accpath, list, list_size); + + if (list_size == -1) { + bsdtar_warnc(bsdtar, errno, + "Couldn't list extended attributes"); + free(list); + return; + } + + for (p = list; (p - list) < list_size; p += strlen(p) + 1) { + if (strncmp(p, "system.", 7) == 0 || + strncmp(p, "xfsroot.", 8) == 0) + continue; + + setup_xattr(bsdtar, entry, accpath, p); + } + + free(list); +} + +#else + +/* + * Generic (stub) extended attribute support. + */ +static void +setup_xattrs(struct bsdtar *bsdtar, struct archive_entry *entry, + const char *accpath) +{ + (void)bsdtar; /* UNUSED */ + (void)entry; /* UNUSED */ + (void)accpath; /* UNUSED */ +} + +#endif + +static void +free_cache(struct name_cache *cache) +{ + size_t i; + + if (cache != NULL) { + for (i = 0; i < cache->size; i++) { + if (cache->cache[i].name != NULL && + cache->cache[i].name != NO_NAME) + free((void *)(uintptr_t)cache->cache[i].name); + } + free(cache); + } +} + +/* + * Lookup uid/gid from uname/gname, return NULL if no match. + */ +static const char * +lookup_name(struct bsdtar *bsdtar, struct name_cache **name_cache_variable, + int (*lookup_fn)(struct bsdtar *, const char **, id_t), id_t id) +{ + struct name_cache *cache; + const char *name; + int slot; + + + if (*name_cache_variable == NULL) { + *name_cache_variable = malloc(sizeof(struct name_cache)); + if (*name_cache_variable == NULL) + bsdtar_errc(bsdtar, 1, ENOMEM, "No more memory"); + memset(*name_cache_variable, 0, sizeof(struct name_cache)); + (*name_cache_variable)->size = name_cache_size; + } + + cache = *name_cache_variable; + cache->probes++; + + slot = id % cache->size; + if (cache->cache[slot].name != NULL) { + if (cache->cache[slot].id == id) { + cache->hits++; + if (cache->cache[slot].name == NO_NAME) + return (NULL); + return (cache->cache[slot].name); + } + if (cache->cache[slot].name != NO_NAME) + free((void *)(uintptr_t)cache->cache[slot].name); + cache->cache[slot].name = NULL; + } + + if (lookup_fn(bsdtar, &name, id) == 0) { + if (name == NULL || name[0] == '\0') { + /* Cache the negative response. */ + cache->cache[slot].name = NO_NAME; + cache->cache[slot].id = id; + } else { + cache->cache[slot].name = strdup(name); + if (cache->cache[slot].name != NULL) { + cache->cache[slot].id = id; + return (cache->cache[slot].name); + } + /* + * Conveniently, NULL marks an empty slot, so + * if the strdup() fails, we've just failed to + * cache it. No recovery necessary. + */ + } + } + return (NULL); +} + +static const char * +lookup_uname(struct bsdtar *bsdtar, uid_t uid) +{ + return (lookup_name(bsdtar, &bsdtar->uname_cache, + &lookup_uname_helper, (id_t)uid)); +} + +static int +lookup_uname_helper(struct bsdtar *bsdtar, const char **name, id_t id) +{ + struct passwd *pwent; + + (void)bsdtar; /* UNUSED */ + + errno = 0; + pwent = getpwuid((uid_t)id); + if (pwent == NULL) { + *name = NULL; + if (errno != 0) + bsdtar_warnc(bsdtar, errno, "getpwuid(%d) failed", id); + return (errno); + } + + *name = pwent->pw_name; + return (0); +} + +static const char * +lookup_gname(struct bsdtar *bsdtar, gid_t gid) +{ + return (lookup_name(bsdtar, &bsdtar->gname_cache, + &lookup_gname_helper, (id_t)gid)); +} + +static int +lookup_gname_helper(struct bsdtar *bsdtar, const char **name, id_t id) +{ + struct group *grent; + + (void)bsdtar; /* UNUSED */ + + errno = 0; + grent = getgrgid((gid_t)id); + if (grent == NULL) { + *name = NULL; + if (errno != 0) + bsdtar_warnc(bsdtar, errno, "getgrgid(%d) failed", id); + return (errno); + } + + *name = grent->gr_name; + return (0); +} + +/* + * Test if the specified file is new enough to include in the archive. + */ +int +new_enough(struct bsdtar *bsdtar, const char *path, const struct stat *st) +{ + struct archive_dir_entry *p; + + /* + * If this file/dir is excluded by a time comparison, skip it. + */ + if (bsdtar->newer_ctime_sec > 0) { + if (st->st_ctime < bsdtar->newer_ctime_sec) + return (0); /* Too old, skip it. */ + if (st->st_ctime == bsdtar->newer_ctime_sec + && ARCHIVE_STAT_CTIME_NANOS(st) + <= bsdtar->newer_ctime_nsec) + return (0); /* Too old, skip it. */ + } + if (bsdtar->newer_mtime_sec > 0) { + if (st->st_mtime < bsdtar->newer_mtime_sec) + return (0); /* Too old, skip it. */ + if (st->st_mtime == bsdtar->newer_mtime_sec + && ARCHIVE_STAT_MTIME_NANOS(st) + <= bsdtar->newer_mtime_nsec) + return (0); /* Too old, skip it. */ + } + + /* + * In -u mode, we only write an entry if it's newer than + * what was already in the archive. + */ + if (bsdtar->archive_dir != NULL && + bsdtar->archive_dir->head != NULL) { + for (p = bsdtar->archive_dir->head; p != NULL; p = p->next) { + if (pathcmp(path, p->name)==0) + return (p->mtime_sec < st->st_mtime || + (p->mtime_sec == st->st_mtime && + p->mtime_nsec + < ARCHIVE_STAT_MTIME_NANOS(st))); + } + } + + /* If the file wasn't rejected, include it. */ + return (1); +} + +/* + * Add an entry to the dir list for 'u' mode. + * + * XXX TODO: Make this fast. + */ +static void +add_dir_list(struct bsdtar *bsdtar, const char *path, + time_t mtime_sec, int mtime_nsec) +{ + struct archive_dir_entry *p; + + /* + * Search entire list to see if this file has appeared before. + * If it has, override the timestamp data. + */ + p = bsdtar->archive_dir->head; + while (p != NULL) { + if (strcmp(path, p->name)==0) { + p->mtime_sec = mtime_sec; + p->mtime_nsec = mtime_nsec; + return; + } + p = p->next; + } + + p = malloc(sizeof(*p)); + if (p == NULL) + bsdtar_errc(bsdtar, 1, ENOMEM, "Can't read archive directory"); + + p->name = strdup(path); + if (p->name == NULL) + bsdtar_errc(bsdtar, 1, ENOMEM, "Can't read archive directory"); + p->mtime_sec = mtime_sec; + p->mtime_nsec = mtime_nsec; + p->next = NULL; + if (bsdtar->archive_dir->tail == NULL) { + bsdtar->archive_dir->head = bsdtar->archive_dir->tail = p; + } else { + bsdtar->archive_dir->tail->next = p; + bsdtar->archive_dir->tail = p; + } +} + +void +test_for_append(struct bsdtar *bsdtar) +{ + struct stat s; + + if (*bsdtar->argv == NULL) + bsdtar_errc(bsdtar, 1, 0, "no files or directories specified"); + if (bsdtar->filename == NULL) + bsdtar_errc(bsdtar, 1, 0, "Cannot append to stdout."); + + if (bsdtar->create_compression != 0) + bsdtar_errc(bsdtar, 1, 0, + "Cannot append to %s with compression", bsdtar->filename); + + if (stat(bsdtar->filename, &s) != 0) + return; + + if (!S_ISREG(s.st_mode) && !S_ISBLK(s.st_mode)) + bsdtar_errc(bsdtar, 1, 0, + "Cannot append to %s: not a regular file.", + bsdtar->filename); +} |
