Initial commit of bsdcpio 0.9.11b.
A new implementation of cpio that uses libarchive as it's back-end archiving/dearchiving infrastructure. Includes test harness; "make check" in the bsdcpio directory to build and run the test harness.
This commit is contained in:
parent
eb36031906
commit
1e38350b0a
19
usr.bin/cpio/Makefile
Normal file
19
usr.bin/cpio/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= bsdcpio
|
||||
BSDCPIO_VERSION_STRING=0.9.11b
|
||||
SRCS= cpio.c cmdline.c err.c matching.c pathmatch.c
|
||||
WARNS?= 6
|
||||
DPADD= ${LIBARCHIVE} ${LIBZ} ${LIBBZ2}
|
||||
CFLAGS+= -DBSDCPIO_VERSION_STRING=\"${BSDCPIO_VERSION_STRING}\"
|
||||
CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\" -O0 -g
|
||||
LDADD+= -larchive -lz -lbz2
|
||||
SYMLINKS=bsdcpio ${BINDIR}/cpio
|
||||
MLINKS= bsdcpio.1 cpio.1
|
||||
|
||||
.PHONY: check test
|
||||
|
||||
check test: $(PROG) bsdcpio.1.gz
|
||||
cd ${.CURDIR}/test && make clean test
|
||||
|
||||
.include <bsd.prog.mk>
|
367
usr.bin/cpio/bsdcpio.1
Normal file
367
usr.bin/cpio/bsdcpio.1
Normal file
@ -0,0 +1,367 @@
|
||||
.\" 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$
|
||||
.\"
|
||||
.Dd December 21, 2007
|
||||
.Dt BSDCPIO 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm cpio
|
||||
.Nd copy files to and from archives
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Brq Fl i
|
||||
.Op Ar options
|
||||
.Op Ar pattern ...
|
||||
.Op Ar < archive
|
||||
.Nm
|
||||
.Brq Fl o
|
||||
.Op Ar options
|
||||
.Ar < name-list
|
||||
.Op Ar > archive
|
||||
.Nm
|
||||
.Brq Fl p
|
||||
.Op Ar options
|
||||
.Ar dest-dir
|
||||
.Ar < name-list
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
copies files between archives and directories.
|
||||
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 option to
|
||||
.Nm
|
||||
is a mode indicator from the following list:
|
||||
.Bl -tag -compact -width indent
|
||||
.It Fl i
|
||||
Input.
|
||||
Read an archive from standard input (unless overriden) and extract the
|
||||
contents to disk or (if the
|
||||
.Fl t
|
||||
option is specified)
|
||||
list the contents to standard output.
|
||||
If one or more file patterns are specified, only files matching
|
||||
one of the patterns will be extracted.
|
||||
.It Fl o
|
||||
Output.
|
||||
Read a list of filenames from standard input and produce a new archive
|
||||
on standard output (unless overriden) containing the specified items.
|
||||
.It Fl p
|
||||
Pass-through.
|
||||
Read a list of filenames from standard input and copy the files to the
|
||||
specified directory.
|
||||
.El
|
||||
.Pp
|
||||
.Sh OPTIONS
|
||||
Unless specifically stated otherwise, options are applicable in
|
||||
all operating modes.
|
||||
.Bl -tag -width indent
|
||||
.It Fl A
|
||||
(o mode only)
|
||||
Append to the specified archive.
|
||||
(Not yet implemented.)
|
||||
.It Fl a
|
||||
(o and p modes)
|
||||
Reset access times on files after they are read.
|
||||
.It Fl B
|
||||
(o mode only)
|
||||
Block output to records of 5120 bytes.
|
||||
.It Fl C Ar size
|
||||
(o mode only)
|
||||
Block output to records of
|
||||
.Ar size
|
||||
bytes.
|
||||
.It Fl c
|
||||
(o mode only)
|
||||
Use the old POSIX portable character format.
|
||||
Equivalent to
|
||||
.Fl -format Ar odc .
|
||||
.It Fl d
|
||||
(i and p modes)
|
||||
Create directories as necessary.
|
||||
.It Fl E Ar file
|
||||
(i mode only)
|
||||
Read list of file name patterns from
|
||||
.Ar file
|
||||
to list and extract.
|
||||
.It Fl F Ar file
|
||||
Read archive from or write archive to
|
||||
.Ar file .
|
||||
.It Fl f Ar pattern
|
||||
(i mode only)
|
||||
Ignore files that match
|
||||
.Ar pattern .
|
||||
.It Fl -format Ar format
|
||||
(o mode only)
|
||||
Produce the output archive in the specified format.
|
||||
Supported formats include:
|
||||
.Pp
|
||||
.Bl -tag -width "iso9660" -compact
|
||||
.It Ar cpio
|
||||
Synonym for
|
||||
.Ar odc .
|
||||
.It Ar newc
|
||||
The SVR4 portable cpio format.
|
||||
.It Ar odc
|
||||
The old POSIX.1 portable octet-oriented cpio format.
|
||||
.It Ar pax
|
||||
The POSIX.1 pax format, an extension of the ustar format.
|
||||
.It Ar ustar
|
||||
The POSIX.1 tar format.
|
||||
.El
|
||||
.Pp
|
||||
The default format is
|
||||
.Ar odc .
|
||||
See
|
||||
.Xr libarchive_formats 5
|
||||
for more complete information about the
|
||||
formats currently supported by the underlying
|
||||
.Xr libarchive 3
|
||||
library.
|
||||
.It Fl I Ar file
|
||||
Read archive from
|
||||
.Ar file .
|
||||
.It Fl i
|
||||
Input mode.
|
||||
See above for description.
|
||||
.It Fl -insecure
|
||||
(i and p mode only)
|
||||
Disable security checks during extraction or copying.
|
||||
This allows extraction via symbolic links and path names containing
|
||||
.Sq ..
|
||||
in the name.
|
||||
.It Fl L
|
||||
(o and p modes)
|
||||
All symbolic links will be followed.
|
||||
Normally, symbolic links are archived and copied as symbolic links.
|
||||
With this option, the target of the link will be archived or copied instead.
|
||||
.It Fl l
|
||||
(p mode only)
|
||||
Create links from the target directory to the original files,
|
||||
instead of copying.
|
||||
.It Fl m
|
||||
(i and p modes)
|
||||
Set file modification time on created files to match
|
||||
those in the source.
|
||||
.It Fl O Ar file
|
||||
Write archive to
|
||||
.Ar file .
|
||||
.It Fl o
|
||||
Output mode.
|
||||
See above for description.
|
||||
.It Fl p
|
||||
Pass-through mode.
|
||||
See above for description.
|
||||
.It Fl -quiet
|
||||
Suppress unnecessary messages.
|
||||
.It Fl R Oo user Oc Ns Oo : Oc Ns Oo group Oc
|
||||
Set the owner and/or group on files in the output.
|
||||
If group is specified with no user
|
||||
(for example,
|
||||
.Fl R Ar :wheel )
|
||||
then the group will be set but not the user.
|
||||
If the user is specified with a trailing colon and no group
|
||||
(for example,
|
||||
.Fl R Ar root: )
|
||||
then the group will be set to the user's default group.
|
||||
If the user is specified with no trailing colon, then
|
||||
the user will be set but not the group.
|
||||
In
|
||||
.Fl i
|
||||
and
|
||||
.Fl p
|
||||
modes, this option can only be used by the super-user.
|
||||
(For compatibility, a period can be used in place of the colon.)
|
||||
.It Fl r
|
||||
(All modes.)
|
||||
Rename files interactively.
|
||||
For each file, a prompt is written to
|
||||
.Pa /dev/tty
|
||||
containing the name of the file and a line is read from
|
||||
.Pa /dev/tty .
|
||||
If the line read is blank, the file is skipped.
|
||||
If the line contains a single period, the file is processed normally.
|
||||
Otherwise, the line is taken to be the new name of the file.
|
||||
.It Fl t
|
||||
(i mode only)
|
||||
List the contents of the archive to stdout;
|
||||
do not restore the contents to disk.
|
||||
.It Fl u
|
||||
(i and p modes)
|
||||
Unconditionally overwrite existing files.
|
||||
Ordinarily, an older file will not overwrite a newer file on disk.
|
||||
.It Fl v
|
||||
Print the name of each file to stderr as it is processed.
|
||||
With
|
||||
.Fl t ,
|
||||
provide a detailed listing of each file.
|
||||
.It Fl -version
|
||||
Print the program version information and exit.
|
||||
.It Fl y
|
||||
(o mode only)
|
||||
Compress the archive with bzip2-compatible compression before writing it.
|
||||
In input mode, this option is ignored;
|
||||
bzip2 compression is recognized automatically on input.
|
||||
.It Fl Z
|
||||
(o mode only)
|
||||
Compress the archive with compress-compatible compression before writing it.
|
||||
In input mode, this option is ignored;
|
||||
compression is recognized automatically on input.
|
||||
.It Fl z
|
||||
(o mode only)
|
||||
Compress the archive with gzip-compatible compression before writing it.
|
||||
In input mode, this option is ignored;
|
||||
gzip compression is recognized automatically on input.
|
||||
.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 TZ
|
||||
The timezone to use when displaying dates.
|
||||
See
|
||||
.Xr environ 7
|
||||
for more information.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh EXAMPLES
|
||||
The
|
||||
.Nm
|
||||
command is traditionally used to copy file heirarchies in conjunction
|
||||
with the
|
||||
.Xr find 1
|
||||
command.
|
||||
The first example here simply copies all files from
|
||||
.Pa src
|
||||
to
|
||||
.Pa dest :
|
||||
.Dl Nm find Pa src | Nm Fl pmud Pa dest
|
||||
.Pp
|
||||
By carefully selecting options to the
|
||||
.Xr find 1
|
||||
command and combining it with other standard utilities,
|
||||
it is possible to exercise very fine control over which files are copied.
|
||||
This next example copies files from
|
||||
.Pa src
|
||||
to
|
||||
.Pa dest
|
||||
that are more than 2 days old and whose names match a particular pattern:
|
||||
.Dl Nm find Pa src Fl mtime Ar +2 | Nm grep foo[bar] | Nm Fl pdmu Pa dest
|
||||
.Pp
|
||||
This example copies files from
|
||||
.Pa src
|
||||
to
|
||||
.Pa dest
|
||||
that are more than 2 days old and which contain the word
|
||||
.Do foobar Dc :
|
||||
.Dl Nm find Pa src Fl mtime Ar +2 | Nm xargs Nm grep -l foobar | Nm Fl pdmu Pa dest
|
||||
.Sh COMPATIBILITY
|
||||
The mode options i, o, and p and the options
|
||||
a, B, c, d, f, l, m, r, t, u, and v comply with SUSv2.
|
||||
.Pp
|
||||
The old POSIX.1 standard specified that only
|
||||
.Fl i ,
|
||||
.Fl o ,
|
||||
and
|
||||
.Fl p
|
||||
were interpreted as command-line options.
|
||||
Each took a single argument of a list of modifier
|
||||
characters.
|
||||
For example, the standard syntax allows
|
||||
.Fl imu
|
||||
but does not support
|
||||
.Fl miu
|
||||
or
|
||||
.Fl i Fl m Fl u ,
|
||||
since
|
||||
.Ar m
|
||||
and
|
||||
.Ar u
|
||||
are only modifiers to
|
||||
.Fl i ,
|
||||
they are not command-line options in their own right.
|
||||
The syntax supported by this implementation is backwards-compatible
|
||||
with the standard.
|
||||
For best compatibility, scripts should limit themselves to the
|
||||
standard syntax.
|
||||
.Sh SEE ALSO
|
||||
.Xr bzip2 1 ,
|
||||
.Xr tar 1 ,
|
||||
.Xr gzip 1 ,
|
||||
.Xr mt 1 ,
|
||||
.Xr pax 1 ,
|
||||
.Xr libarchive 3 ,
|
||||
.Xr cpio 5 ,
|
||||
.Xr libarchive-formats 5 ,
|
||||
.Xr tar 5
|
||||
.Sh STANDARDS
|
||||
There is no current POSIX standard for the cpio command; it appeared
|
||||
in
|
||||
.St -p1003.1-96
|
||||
but was dropped from
|
||||
.St -p1003.1-2001 .
|
||||
.Pp
|
||||
The cpio, ustar, and pax interchange file formats are defined by
|
||||
.St -p1003.1-2001
|
||||
for the pax command.
|
||||
.Sh HISTORY
|
||||
The original
|
||||
.Nm cpio
|
||||
and
|
||||
.Nm find
|
||||
utilities were written by Dick Haight
|
||||
while working in AT&T's Unix Support Group.
|
||||
They first appeared in 1977 in PWB/UNIX 1.0, the
|
||||
.Dq Programmer's Work Bench
|
||||
system developed for use within AT&T.
|
||||
They were first released outside of AT&T as part of System III Unix in 1981.
|
||||
As a result,
|
||||
.Nm cpio
|
||||
actually predates
|
||||
.Nm tar ,
|
||||
even though it was not well-known outside of AT&T until some time later.
|
||||
.Pp
|
||||
This is a complete re-implementation based on the
|
||||
.Xr libarchive 3
|
||||
library.
|
||||
.Sh BUGS
|
||||
The cpio archive format has several basic limitations:
|
||||
It does not store user and group names, only numbers.
|
||||
As a result, it cannot be reliably used to transfer
|
||||
files between systems with dissimilar user and group numbering.
|
||||
Older cpio formats limit the user and group numbers to
|
||||
16 or 18 bits, which is insufficient for modern systems.
|
||||
The cpio archive formats cannot support files over 4 gigabytes,
|
||||
except for the
|
||||
.Dq odc
|
||||
variant, which can support files up to 8 gigabytes.
|
247
usr.bin/cpio/cmdline.c
Normal file
247
usr.bin/cpio/cmdline.c
Normal file
@ -0,0 +1,247 @@
|
||||
/*-
|
||||
* 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
|
||||
* in this position and unchanged.
|
||||
* 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 "cpio_platform.h"
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.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_GRP_H
|
||||
#include <grp.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
|
||||
|
||||
#include "cpio.h"
|
||||
|
||||
/*
|
||||
*
|
||||
* Option parsing routines for bsdcpio.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
static const char *cpio_opts = "AaBC:F:O:cdE:f:H:hijLlmopR:rtuvW:yZz";
|
||||
|
||||
/*
|
||||
* On systems that lack getopt_long, long options can be specified
|
||||
* using -W longopt and -W longopt=value, e.g. "-W version" is the
|
||||
* same as "--version" and "-W format=ustar" is the same as "--format
|
||||
* ustar". This does not rely the GNU getopt() "W;" extension, so
|
||||
* should work correctly on any system with a POSIX-compliant
|
||||
* getopt().
|
||||
*/
|
||||
|
||||
/*
|
||||
* If you add anything, be very careful to keep this list properly
|
||||
* sorted, as the -W logic below relies on it.
|
||||
*/
|
||||
static const struct option cpio_longopts[] = {
|
||||
{ "file", required_argument, NULL, 'F' },
|
||||
{ "format", required_argument, NULL, 'H' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "insecure", no_argument, NULL, OPTION_INSECURE },
|
||||
{ "owner", required_argument, NULL, 'R' },
|
||||
{ "quiet", no_argument, NULL, OPTION_QUIET },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "version", no_argument, NULL, OPTION_VERSION },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Parse command-line options using system-provided getopt() or getopt_long().
|
||||
* If option is -W, then parse argument as a long option.
|
||||
*/
|
||||
int
|
||||
cpio_getopt(struct cpio *cpio)
|
||||
{
|
||||
char *p, *q;
|
||||
const struct option *option, *option2;
|
||||
int opt;
|
||||
int option_index;
|
||||
size_t option_length;
|
||||
|
||||
option_index = -1;
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
opt = getopt_long(cpio->argc, cpio->argv, cpio_opts,
|
||||
cpio_longopts, &option_index);
|
||||
#else
|
||||
opt = getopt(cpio->argc, cpio->argv, cpio_opts);
|
||||
#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 = cpio_longopts;
|
||||
while (option->name != NULL &&
|
||||
(strlen(option->name) < option_length ||
|
||||
strncmp(p, option->name, option_length) != 0 )) {
|
||||
option++;
|
||||
}
|
||||
|
||||
if (option->name != NULL) {
|
||||
option2 = 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)
|
||||
cpio_errc(1, 0,
|
||||
"Ambiguous option %s "
|
||||
"(matches both %s and %s)",
|
||||
p, option2->name, option->name);
|
||||
|
||||
if (option2->has_arg == required_argument
|
||||
&& optarg == NULL)
|
||||
cpio_errc(1, 0,
|
||||
"Option \"%s\" requires argument", p);
|
||||
} else {
|
||||
opt = '?';
|
||||
}
|
||||
}
|
||||
|
||||
return (opt);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse the argument to the -R or --owner flag.
|
||||
*
|
||||
* The format is one of the following:
|
||||
* <user> - Override user but not group
|
||||
* <user>: - Override both, group is user's default group
|
||||
* <user>:<group> - Override both
|
||||
* :<group> - Override group but not user
|
||||
*
|
||||
* A period can be used instead of the colon.
|
||||
*
|
||||
* Sets uid/gid as appropriate, -1 indicates uid/gid not specified.
|
||||
*
|
||||
*/
|
||||
int
|
||||
owner_parse(const char *spec, int *uid, int *gid)
|
||||
{
|
||||
const char *u, *ue, *g;
|
||||
|
||||
*uid = -1;
|
||||
*gid = -1;
|
||||
|
||||
/*
|
||||
* Split spec into [user][:.][group]
|
||||
* u -> first char of username, NULL if no username
|
||||
* ue -> first char after username (colon, period, or \0)
|
||||
* g -> first char of group name
|
||||
*/
|
||||
if (*spec == ':' || *spec == '.') {
|
||||
/* If spec starts with ':' or '.', then just group. */
|
||||
ue = u = NULL;
|
||||
g = spec + 1;
|
||||
} else {
|
||||
/* Otherwise, [user] or [user][:] or [user][:][group] */
|
||||
ue = u = spec;
|
||||
while (*ue != ':' && *ue != '.' && *ue != '\0')
|
||||
++ue;
|
||||
g = ue;
|
||||
if (*g != '\0') /* Skip : or . to find first char of group. */
|
||||
++g;
|
||||
}
|
||||
|
||||
if (u != NULL) {
|
||||
/* Look up user: ue is first char after end of user. */
|
||||
char *user;
|
||||
struct passwd *pwent;
|
||||
|
||||
user = (char *)malloc(ue - u + 1);
|
||||
if (user == NULL) {
|
||||
cpio_warnc(errno, "Couldn't allocate memory");
|
||||
return (1);
|
||||
}
|
||||
memcpy(user, u, ue - u);
|
||||
user[ue - u] = '\0';
|
||||
pwent = getpwnam(user);
|
||||
if (pwent == NULL) {
|
||||
cpio_warnc(errno, "Couldn't lookup user ``%s''", user);
|
||||
return (1);
|
||||
}
|
||||
free(user);
|
||||
*uid = pwent->pw_uid;
|
||||
if (*ue != '\0' && *g == '\0')
|
||||
*gid = pwent->pw_gid;
|
||||
}
|
||||
if (*g != '\0') {
|
||||
struct group *grp;
|
||||
grp = getgrnam(g);
|
||||
if (grp != NULL)
|
||||
*gid = grp->gr_gid;
|
||||
else {
|
||||
cpio_warnc(errno, "Couldn't look up group ``%s''", g);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
109
usr.bin/cpio/config_freebsd.h
Normal file
109
usr.bin/cpio/config_freebsd.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*-
|
||||
* 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$
|
||||
*/
|
||||
|
||||
/* A default configuration for FreeBSD, used if there is no config.h. */
|
||||
|
||||
#include <sys/param.h> /* __FreeBSD_version */
|
||||
|
||||
#if __FreeBSD__ > 4
|
||||
#define HAVE_ACL_GET_PERM 0
|
||||
#define HAVE_ACL_GET_PERM_NP 1
|
||||
#define HAVE_ACL_PERMSET_T 1
|
||||
#define HAVE_ACL_USER 1
|
||||
#endif
|
||||
#undef HAVE_ATTR_XATTR_H
|
||||
#define HAVE_BZLIB_H 1
|
||||
#define HAVE_CHFLAGS 1
|
||||
#define HAVE_DECL_OPTARG 1
|
||||
#define HAVE_DECL_OPTIND 1
|
||||
#define HAVE_DIRENT_D_NAMLEN 1
|
||||
#define HAVE_DIRENT_H 1
|
||||
#define HAVE_D_MD_ORDER 1
|
||||
#define HAVE_ERRNO_H 1
|
||||
#undef HAVE_EXT2FS_EXT2_FS_H
|
||||
#define HAVE_FCHDIR 1
|
||||
#define HAVE_FCNTL_H 1
|
||||
#define HAVE_FNMATCH 1
|
||||
#define HAVE_FNMATCH_H 1
|
||||
#define HAVE_FNM_LEADING_DIR 1
|
||||
#define HAVE_FTRUNCATE 1
|
||||
#define HAVE_FUTIMES 1
|
||||
#define HAVE_GETOPT_LONG 1
|
||||
#undef HAVE_GETXATTR
|
||||
#define HAVE_GRP_H 1
|
||||
#define HAVE_INTTYPES_H 1
|
||||
#define HAVE_LANGINFO_H 1
|
||||
#undef HAVE_LGETXATTR
|
||||
#undef HAVE_LIBACL
|
||||
#define HAVE_LIBARCHIVE 1
|
||||
#define HAVE_LIBBZ2 1
|
||||
#define HAVE_LIBZ 1
|
||||
#define HAVE_LIMITS_H 1
|
||||
#undef HAVE_LINUX_EXT2_FS_H
|
||||
#undef HAVE_LINUX_FS_H
|
||||
#undef HAVE_LISTXATTR
|
||||
#undef HAVE_LLISTXATTR
|
||||
#define HAVE_LOCALE_H 1
|
||||
#define HAVE_LUTIMES 1
|
||||
#define HAVE_MALLOC 1
|
||||
#define HAVE_MEMMOVE 1
|
||||
#define HAVE_MEMORY_H 1
|
||||
#define HAVE_MEMSET 1
|
||||
#if __FreeBSD_version >= 450002 /* nl_langinfo introduced */
|
||||
#define HAVE_NL_LANGINFO 1
|
||||
#endif
|
||||
#define HAVE_PATHS_H 1
|
||||
#define HAVE_PWD_H 1
|
||||
#define HAVE_SETLOCALE 1
|
||||
#define HAVE_STDARG_H 1
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_STDLIB_H 1
|
||||
#define HAVE_STRCHR 1
|
||||
#define HAVE_STRDUP 1
|
||||
#define HAVE_STRERROR 1
|
||||
#define HAVE_STRFTIME 1
|
||||
#define HAVE_STRINGS_H 1
|
||||
#define HAVE_STRING_H 1
|
||||
#define HAVE_STRRCHR 1
|
||||
#undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
||||
#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
|
||||
#define HAVE_STRUCT_STAT_ST_RDEV 1
|
||||
#define HAVE_SYS_ACL_H 1
|
||||
#define HAVE_SYS_IOCTL_H 1
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
#define HAVE_TIME_H 1
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_UINTMAX_T 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define HAVE_UNSIGNED_LONG_LONG 1
|
||||
#define HAVE_UTIMES 1
|
||||
#define HAVE_VPRINTF 1
|
||||
#define HAVE_ZLIB_H 1
|
||||
#undef MAJOR_IN_MKDEV
|
||||
#define STDC_HEADERS 1
|
||||
|
946
usr.bin/cpio/cpio.c
Normal file
946
usr.bin/cpio/cpio.c
Normal file
@ -0,0 +1,946 @@
|
||||
/*-
|
||||
* 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
|
||||
* in this position and unchanged.
|
||||
* 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 "cpio_platform.h"
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
#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_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
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "cpio.h"
|
||||
#include "matching.h"
|
||||
|
||||
static int copy_data(struct archive *, struct archive *);
|
||||
static const char *cpio_rename(const char *name);
|
||||
static int entry_to_archive(struct cpio *, struct archive_entry *);
|
||||
static int file_to_archive(struct cpio *, const char *);
|
||||
static void long_help(void);
|
||||
static void mode_in(struct cpio *);
|
||||
static void mode_list(struct cpio *);
|
||||
static void mode_out(struct cpio *);
|
||||
static void mode_pass(struct cpio *, const char *);
|
||||
static void restore_time(struct cpio *, struct archive_entry *,
|
||||
const char *, int fd);
|
||||
static void usage(void);
|
||||
static void version(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
static char buff[16384];
|
||||
struct cpio _cpio; /* Allocated on stack. */
|
||||
struct cpio *cpio;
|
||||
int uid, gid;
|
||||
int opt;
|
||||
|
||||
cpio = &_cpio;
|
||||
memset(cpio, 0, sizeof(*cpio));
|
||||
cpio->buff = buff;
|
||||
cpio->buff_size = sizeof(buff);
|
||||
|
||||
/* Need cpio_progname before calling cpio_warnc. */
|
||||
if (*argv == NULL)
|
||||
cpio_progname = "bsdcpio";
|
||||
else {
|
||||
cpio_progname = strrchr(*argv, '/');
|
||||
if (cpio_progname != NULL)
|
||||
cpio_progname++;
|
||||
else
|
||||
cpio_progname = *argv;
|
||||
}
|
||||
|
||||
cpio->uid_override = -1;
|
||||
cpio->gid_override = -1;
|
||||
cpio->argv = argv;
|
||||
cpio->argc = argc;
|
||||
cpio->mode = '\0';
|
||||
cpio->verbose = 0;
|
||||
cpio->compress = '\0';
|
||||
/* TODO: Implement old binary format in libarchive, use that here. */
|
||||
cpio->format = "odc"; /* Default format */
|
||||
cpio->extract_flags = ARCHIVE_EXTRACT_NO_AUTODIR;
|
||||
cpio->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
|
||||
cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS;
|
||||
cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT;
|
||||
/* TODO: If run by root, set owner as well. */
|
||||
cpio->bytes_per_block = 512;
|
||||
cpio->filename = NULL;
|
||||
|
||||
while ((opt = cpio_getopt(cpio)) != -1) {
|
||||
switch (opt) {
|
||||
case 'A': /* NetBSD/OpenBSD */
|
||||
cpio->option_append = 1;
|
||||
break;
|
||||
case 'a': /* POSIX 1997 */
|
||||
cpio->option_atime_restore = 1;
|
||||
break;
|
||||
case 'B': /* POSIX 1997 */
|
||||
cpio->bytes_per_block = 5120;
|
||||
break;
|
||||
case 'C': /* NetBSD/OpenBSD */
|
||||
cpio->bytes_per_block = atoi(optarg);
|
||||
if (cpio->bytes_per_block <= 0)
|
||||
cpio_errc(1, 0, "Invalid blocksize %s", optarg);
|
||||
break;
|
||||
case 'c': /* POSIX 1997 */
|
||||
cpio->format = "odc";
|
||||
break;
|
||||
case 'd': /* POSIX 1997 */
|
||||
cpio->extract_flags &= ~ARCHIVE_EXTRACT_NO_AUTODIR;
|
||||
break;
|
||||
case 'E': /* NetBSD/OpenBSD */
|
||||
include_from_file(cpio, optarg);
|
||||
break;
|
||||
case 'F': /* NetBSD/OpenBSD/GNU cpio */
|
||||
cpio->filename = optarg;
|
||||
break;
|
||||
case 'f': /* POSIX 1997 */
|
||||
exclude(cpio, optarg);
|
||||
break;
|
||||
case 'H': /* GNU cpio (also --format) */
|
||||
cpio->format = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
long_help();
|
||||
break;
|
||||
case 'I': /* NetBSD/OpenBSD */
|
||||
cpio->filename = optarg;
|
||||
break;
|
||||
case 'i': /* POSIX 1997 */
|
||||
cpio->mode = opt;
|
||||
break;
|
||||
case OPTION_INSECURE:
|
||||
cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_SYMLINKS;
|
||||
cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT;
|
||||
break;
|
||||
case 'L': /* GNU cpio */
|
||||
cpio->option_follow_links = 1;
|
||||
break;
|
||||
case 'l': /* POSIX 1997 */
|
||||
cpio->option_link = 1;
|
||||
break;
|
||||
case 'm': /* POSIX 1997 */
|
||||
cpio->extract_flags |= ARCHIVE_EXTRACT_TIME;
|
||||
break;
|
||||
case 'O': /* GNU cpio */
|
||||
cpio->filename = optarg;
|
||||
break;
|
||||
case 'o': /* POSIX 1997 */
|
||||
cpio->mode = opt;
|
||||
break;
|
||||
case 'p': /* POSIX 1997 */
|
||||
cpio->mode = opt;
|
||||
break;
|
||||
case OPTION_QUIET: /* GNU cpio */
|
||||
cpio->quiet = 1;
|
||||
break;
|
||||
case 'R': /* GNU cpio, also --owner */
|
||||
if (owner_parse(optarg, &uid, &gid))
|
||||
usage();
|
||||
if (uid != -1)
|
||||
cpio->uid_override = uid;
|
||||
if (gid != -1)
|
||||
cpio->gid_override = gid;
|
||||
break;
|
||||
case 'r': /* POSIX 1997 */
|
||||
cpio->option_rename = 1;
|
||||
break;
|
||||
case 't': /* POSIX 1997 */
|
||||
cpio->option_list = 1;
|
||||
break;
|
||||
case 'u': /* POSIX 1997 */
|
||||
cpio->extract_flags
|
||||
&= ~ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
|
||||
break;
|
||||
case 'v': /* POSIX 1997 */
|
||||
cpio->verbose++;
|
||||
break;
|
||||
case OPTION_VERSION: /* GNU convention */
|
||||
version();
|
||||
break;
|
||||
#if 0
|
||||
/*
|
||||
* cpio_getopt() handles -W specially, so it's not
|
||||
* available here.
|
||||
*/
|
||||
case 'W': /* Obscure, but useful GNU convention. */
|
||||
break;
|
||||
#endif
|
||||
case 'y': /* tar convention */
|
||||
cpio->compress = opt;
|
||||
break;
|
||||
case 'Z': /* tar convention */
|
||||
cpio->compress = opt;
|
||||
break;
|
||||
case 'z': /* tar convention */
|
||||
cpio->compress = opt;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Sanity-check args, error out on nonsensical combinations. */
|
||||
|
||||
cpio->argc -= optind;
|
||||
cpio->argv += optind;
|
||||
|
||||
switch (cpio->mode) {
|
||||
case 'o':
|
||||
mode_out(cpio);
|
||||
break;
|
||||
case 'i':
|
||||
while (*cpio->argv != NULL) {
|
||||
include(cpio, *cpio->argv);
|
||||
--cpio->argc;
|
||||
++cpio->argv;
|
||||
}
|
||||
if (cpio->option_list)
|
||||
mode_list(cpio);
|
||||
else
|
||||
mode_in(cpio);
|
||||
break;
|
||||
case 'p':
|
||||
if (*cpio->argv == NULL || **cpio->argv == '\0')
|
||||
cpio_errc(1, 0,
|
||||
"-p mode requires a target directory");
|
||||
mode_pass(cpio, *cpio->argv);
|
||||
break;
|
||||
default:
|
||||
cpio_errc(1, 0,
|
||||
"Must specify at least one of -i, -o, or -p");
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = cpio_progname;
|
||||
|
||||
fprintf(stderr, "Brief Usage:\n");
|
||||
fprintf(stderr, " List: %s -it < archive\n", p);
|
||||
fprintf(stderr, " Extract: %s -i < archive\n", p);
|
||||
fprintf(stderr, " Create: %s -o < filenames > archive\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 const char *long_help_msg =
|
||||
"First option must be a mode specifier:\n"
|
||||
" -i Input -o Output -p Pass\n"
|
||||
"Common Options:\n"
|
||||
" -v Verbose\n"
|
||||
"Create: %p -o [options] < [list of files] > [archive]\n"
|
||||
" -z, -y Compress archive with gzip/bzip2\n"
|
||||
" --format {odc|newc|ustar} Select archive format\n"
|
||||
"List: %p -it < [archive]\n"
|
||||
"Extract: %p -i [options] < [archive]\n";
|
||||
|
||||
|
||||
/*
|
||||
* Note that the word 'bsdcpio' will always appear in the first line
|
||||
* of output.
|
||||
*
|
||||
* In particular, /bin/sh scripts that need to test for the presence
|
||||
* of bsdcpio can use the following template:
|
||||
*
|
||||
* if (cpio --help 2>&1 | grep bsdcpio >/dev/null 2>&1 ) then \
|
||||
* echo bsdcpio; else echo not bsdcpio; fi
|
||||
*/
|
||||
static void
|
||||
long_help(void)
|
||||
{
|
||||
const char *prog;
|
||||
const char *p;
|
||||
|
||||
prog = cpio_progname;
|
||||
|
||||
fflush(stderr);
|
||||
|
||||
p = (strcmp(prog,"bsdcpio") != 0) ? "(bsdcpio)" : "";
|
||||
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 void
|
||||
version(void)
|
||||
{
|
||||
fprintf(stdout,"bsdcpio %s -- %s\n",
|
||||
BSDCPIO_VERSION_STRING,
|
||||
archive_version());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
mode_out(struct cpio *cpio)
|
||||
{
|
||||
struct archive_entry *entry, *spare;
|
||||
unsigned long blocks;
|
||||
int r;
|
||||
|
||||
if (cpio->option_append)
|
||||
cpio_errc(1, 0, "Append mode not yet supported.");
|
||||
cpio->archive = archive_write_new();
|
||||
if (cpio->archive == NULL)
|
||||
cpio_errc(1, 0, "Failed to allocate archive object");
|
||||
switch (cpio->compress) {
|
||||
case 'j': case 'y':
|
||||
archive_write_set_compression_bzip2(cpio->archive);
|
||||
break;
|
||||
case 'z':
|
||||
archive_write_set_compression_gzip(cpio->archive);
|
||||
break;
|
||||
case 'Z':
|
||||
archive_write_set_compression_compress(cpio->archive);
|
||||
break;
|
||||
default:
|
||||
archive_write_set_compression_none(cpio->archive);
|
||||
break;
|
||||
}
|
||||
r = archive_write_set_format_by_name(cpio->archive, cpio->format);
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_errc(1, 0, archive_error_string(cpio->archive));
|
||||
archive_write_set_bytes_per_block(cpio->archive, cpio->bytes_per_block);
|
||||
cpio->linkresolver = archive_entry_linkresolver_new();
|
||||
archive_entry_linkresolver_set_strategy(cpio->linkresolver,
|
||||
archive_format(cpio->archive));
|
||||
|
||||
r = archive_write_open_file(cpio->archive, cpio->filename);
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_errc(1, 0, archive_error_string(cpio->archive));
|
||||
process_lines(cpio, "-", file_to_archive);
|
||||
|
||||
/*
|
||||
* The hardlink detection may have queued up a couple of entries
|
||||
* that can now be flushed.
|
||||
*/
|
||||
entry = NULL;
|
||||
archive_entry_linkify(cpio->linkresolver, &entry, &spare);
|
||||
while (entry != NULL) {
|
||||
entry_to_archive(cpio, entry);
|
||||
archive_entry_free(entry);
|
||||
entry = NULL;
|
||||
archive_entry_linkify(cpio->linkresolver, &entry, &spare);
|
||||
}
|
||||
|
||||
r = archive_write_close(cpio->archive);
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_errc(1, 0, archive_error_string(cpio->archive));
|
||||
|
||||
if (!cpio->quiet) {
|
||||
blocks = (archive_position_uncompressed(cpio->archive) + 511)
|
||||
/ 512;
|
||||
fprintf(stderr, "%lu %s\n", blocks,
|
||||
blocks == 1 ? "block" : "blocks");
|
||||
}
|
||||
archive_write_finish(cpio->archive);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used by both out mode (to copy objects from disk into
|
||||
* an archive) and pass mode (to copy objects from disk to
|
||||
* an archive_write_disk "archive").
|
||||
*/
|
||||
static int
|
||||
file_to_archive(struct cpio *cpio, const char *srcpath)
|
||||
{
|
||||
struct stat st;
|
||||
const char *destpath;
|
||||
struct archive_entry *entry, *spare;
|
||||
size_t len;
|
||||
const char *p;
|
||||
int lnklen;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* Create an archive_entry describing the source file.
|
||||
*/
|
||||
entry = archive_entry_new();
|
||||
if (entry == NULL)
|
||||
cpio_errc(1, 0, "Couldn't allocate entry");
|
||||
archive_entry_copy_sourcepath(entry, srcpath);
|
||||
|
||||
/* Get stat information. */
|
||||
if (cpio->option_follow_links)
|
||||
r = stat(srcpath, &st);
|
||||
else
|
||||
r = lstat(srcpath, &st);
|
||||
if (r != 0) {
|
||||
cpio_warnc(errno, "Couldn't stat \"%s\"", srcpath);
|
||||
archive_entry_free(entry);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (cpio->uid_override >= 0)
|
||||
st.st_uid = cpio->uid_override;
|
||||
if (cpio->gid_override >= 0)
|
||||
st.st_gid = cpio->uid_override;
|
||||
archive_entry_copy_stat(entry, &st);
|
||||
|
||||
/* If its a symlink, pull the target. */
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
lnklen = readlink(srcpath, cpio->buff, cpio->buff_size);
|
||||
if (lnklen < 0) {
|
||||
cpio_warnc(errno,
|
||||
"%s: Couldn't read symbolic link", srcpath);
|
||||
archive_entry_free(entry);
|
||||
return (0);
|
||||
}
|
||||
cpio->buff[lnklen] = 0;
|
||||
archive_entry_set_symlink(entry, cpio->buff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a destination path for this entry.
|
||||
* "destination path" is the name to which it will be copied in
|
||||
* pass mode or the name that will go into the archive in
|
||||
* output mode.
|
||||
*/
|
||||
destpath = srcpath;
|
||||
if (cpio->destdir) {
|
||||
len = strlen(cpio->destdir) + strlen(srcpath) + 8;
|
||||
if (len >= cpio->pass_destpath_alloc) {
|
||||
while (len >= cpio->pass_destpath_alloc) {
|
||||
cpio->pass_destpath_alloc += 512;
|
||||
cpio->pass_destpath_alloc *= 2;
|
||||
}
|
||||
free(cpio->pass_destpath);
|
||||
cpio->pass_destpath = malloc(cpio->pass_destpath_alloc);
|
||||
if (cpio->pass_destpath == NULL)
|
||||
cpio_errc(1, ENOMEM,
|
||||
"Can't allocate path buffer");
|
||||
}
|
||||
strcpy(cpio->pass_destpath, cpio->destdir);
|
||||
p = srcpath;
|
||||
while (p[0] == '/')
|
||||
++p;
|
||||
strcat(cpio->pass_destpath, p);
|
||||
destpath = cpio->pass_destpath;
|
||||
}
|
||||
if (cpio->option_rename)
|
||||
destpath = cpio_rename(destpath);
|
||||
if (destpath == NULL)
|
||||
return (0);
|
||||
archive_entry_copy_pathname(entry, destpath);
|
||||
|
||||
/*
|
||||
* If we're trying to preserve hardlinks, match them here.
|
||||
*/
|
||||
spare = NULL;
|
||||
if (cpio->linkresolver != NULL
|
||||
&& !S_ISDIR(st.st_mode)) {
|
||||
archive_entry_linkify(cpio->linkresolver, &entry, &spare);
|
||||
}
|
||||
|
||||
if (entry != NULL) {
|
||||
r = entry_to_archive(cpio, entry);
|
||||
archive_entry_free(entry);
|
||||
}
|
||||
if (spare != NULL) {
|
||||
if (r == 0)
|
||||
r = entry_to_archive(cpio, spare);
|
||||
archive_entry_free(spare);
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
|
||||
{
|
||||
const char *destpath = archive_entry_pathname(entry);
|
||||
const char *srcpath = archive_entry_sourcepath(entry);
|
||||
int fd = -1;
|
||||
ssize_t bytes_read;
|
||||
int r;
|
||||
|
||||
/* Print out the destination name to the user. */
|
||||
if (cpio->verbose)
|
||||
fprintf(stderr,"%s", destpath);
|
||||
|
||||
/*
|
||||
* Obviously, this only gets invoked in pass mode.
|
||||
*/
|
||||
if (cpio->option_link) {
|
||||
/* Note: link(2) doesn't create parent directories. */
|
||||
archive_entry_set_hardlink(entry, srcpath);
|
||||
r = archive_write_header(cpio->archive, entry);
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_warnc(archive_errno(cpio->archive),
|
||||
archive_error_string(cpio->archive));
|
||||
if (r == ARCHIVE_FATAL)
|
||||
exit(1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we can open the file (if necessary) before
|
||||
* trying to write the header.
|
||||
*/
|
||||
if (archive_entry_filetype(entry) == AE_IFREG) {
|
||||
if (archive_entry_size(entry) > 0) {
|
||||
fd = open(srcpath, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
cpio_warnc(errno,
|
||||
"%s: could not open file", srcpath);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
archive_entry_set_size(entry, 0);
|
||||
}
|
||||
|
||||
r = archive_write_header(cpio->archive, entry);
|
||||
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_warnc(archive_errno(cpio->archive),
|
||||
"%s: %s",
|
||||
destpath,
|
||||
archive_error_string(cpio->archive));
|
||||
|
||||
if (r == ARCHIVE_FATAL)
|
||||
exit(1);
|
||||
|
||||
if (r >= ARCHIVE_WARN && fd >= 0) {
|
||||
bytes_read = read(fd, cpio->buff, cpio->buff_size);
|
||||
while (bytes_read > 0) {
|
||||
r = archive_write_data(cpio->archive,
|
||||
cpio->buff, bytes_read);
|
||||
if (r < 0)
|
||||
cpio_errc(1, archive_errno(cpio->archive),
|
||||
archive_error_string(cpio->archive));
|
||||
if (r < bytes_read) {
|
||||
cpio_warnc(0,
|
||||
"Truncated write; file may have grown while being archived.");
|
||||
}
|
||||
bytes_read = read(fd, cpio->buff, cpio->buff_size);
|
||||
}
|
||||
}
|
||||
|
||||
restore_time(cpio, entry, srcpath, fd);
|
||||
|
||||
cleanup:
|
||||
if (cpio->verbose)
|
||||
fprintf(stderr,"\n");
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
restore_time(struct cpio *cpio, struct archive_entry *entry,
|
||||
const char *name, int fd)
|
||||
{
|
||||
#ifndef HAVE_UTIMES
|
||||
static int warned = 0;
|
||||
|
||||
(void)cpio; /* UNUSED */
|
||||
(void)entry; /* UNUSED */
|
||||
(void)name; /* UNUSED */
|
||||
(void)fd; /* UNUSED */
|
||||
|
||||
if (!warned)
|
||||
cpio_warnc(0, "Can't restore access times on this platform");
|
||||
warned = 1;
|
||||
return;
|
||||
#else
|
||||
struct timeval times[2];
|
||||
|
||||
if (!cpio->option_atime_restore)
|
||||
return;
|
||||
|
||||
times[1].tv_sec = archive_entry_mtime(entry);
|
||||
times[1].tv_usec = archive_entry_mtime_nsec(entry) / 1000;
|
||||
|
||||
times[0].tv_sec = archive_entry_atime(entry);
|
||||
times[0].tv_usec = archive_entry_atime_nsec(entry) / 1000;
|
||||
|
||||
#ifdef HAVE_FUTIMES
|
||||
if (fd >= 0 && futimes(fd, times) == 0)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LUTIMES
|
||||
if (lutimes(name, times) != 0)
|
||||
#else
|
||||
if (!S_ISLNK(archive_entry_mode(entry)) && utimes(name, times) != 0)
|
||||
#endif
|
||||
cpio_warnc(errno, "Can't update time for %s", name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mode_in(struct cpio *cpio)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
struct archive *ext;
|
||||
const char *destpath;
|
||||
unsigned long blocks;
|
||||
int r;
|
||||
|
||||
ext = archive_write_disk_new();
|
||||
if (ext == NULL)
|
||||
cpio_errc(1, 0, "Couldn't allocate restore object");
|
||||
r = archive_write_disk_set_options(ext, cpio->extract_flags);
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_errc(1, 0, archive_error_string(ext));
|
||||
a = archive_read_new();
|
||||
if (a == NULL)
|
||||
cpio_errc(1, 0, "Couldn't allocate archive object");
|
||||
archive_read_support_compression_all(a);
|
||||
archive_read_support_format_all(a);
|
||||
|
||||
if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block))
|
||||
cpio_errc(1, archive_errno(a),
|
||||
archive_error_string(a));
|
||||
for (;;) {
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_EOF)
|
||||
break;
|
||||
if (r != ARCHIVE_OK) {
|
||||
cpio_errc(1, archive_errno(a),
|
||||
archive_error_string(a));
|
||||
}
|
||||
if (excluded(cpio, archive_entry_pathname(entry)))
|
||||
continue;
|
||||
if (cpio->option_rename) {
|
||||
destpath = cpio_rename(archive_entry_pathname(entry));
|
||||
archive_entry_set_pathname(entry, destpath);
|
||||
} else
|
||||
destpath = archive_entry_pathname(entry);
|
||||
if (destpath == NULL)
|
||||
continue;
|
||||
if (cpio->verbose)
|
||||
fprintf(stdout, "%s\n", destpath);
|
||||
if (cpio->uid_override >= 0)
|
||||
archive_entry_set_uid(entry, cpio->uid_override);
|
||||
if (cpio->gid_override >= 0)
|
||||
archive_entry_set_gid(entry, cpio->gid_override);
|
||||
r = archive_write_header(ext, entry);
|
||||
if (r != ARCHIVE_OK) {
|
||||
fprintf(stderr, "%s: %s\n",
|
||||
archive_entry_pathname(entry),
|
||||
archive_error_string(ext));
|
||||
} else if (archive_entry_size(entry) > 0) {
|
||||
r = copy_data(a, ext);
|
||||
}
|
||||
}
|
||||
r = archive_read_close(a);
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_errc(1, 0, archive_error_string(a));
|
||||
r = archive_write_close(ext);
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_errc(1, 0, archive_error_string(ext));
|
||||
if (!cpio->quiet) {
|
||||
blocks = (archive_position_uncompressed(a) + 511)
|
||||
/ 512;
|
||||
fprintf(stderr, "%lu %s\n", blocks,
|
||||
blocks == 1 ? "block" : "blocks");
|
||||
}
|
||||
archive_read_finish(a);
|
||||
archive_write_finish(ext);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int
|
||||
copy_data(struct archive *ar, struct archive *aw)
|
||||
{
|
||||
int r;
|
||||
size_t size;
|
||||
const void *block;
|
||||
off_t offset;
|
||||
|
||||
for (;;) {
|
||||
r = archive_read_data_block(ar, &block, &size, &offset);
|
||||
if (r == ARCHIVE_EOF)
|
||||
return (ARCHIVE_OK);
|
||||
if (r != ARCHIVE_OK) {
|
||||
cpio_warnc(archive_errno(ar),
|
||||
"%s", archive_error_string(ar));
|
||||
return (r);
|
||||
}
|
||||
r = archive_write_data_block(aw, block, size, offset);
|
||||
if (r != ARCHIVE_OK) {
|
||||
cpio_warnc(archive_errno(aw),
|
||||
archive_error_string(aw));
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mode_list(struct cpio *cpio)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
unsigned long blocks;
|
||||
int r;
|
||||
|
||||
a = archive_read_new();
|
||||
if (a == NULL)
|
||||
cpio_errc(1, 0, "Couldn't allocate archive object");
|
||||
archive_read_support_compression_all(a);
|
||||
archive_read_support_format_all(a);
|
||||
|
||||
if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block))
|
||||
cpio_errc(1, archive_errno(a),
|
||||
archive_error_string(a));
|
||||
for (;;) {
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_EOF)
|
||||
break;
|
||||
if (r != ARCHIVE_OK) {
|
||||
cpio_errc(1, archive_errno(a),
|
||||
archive_error_string(a));
|
||||
}
|
||||
if (excluded(cpio, archive_entry_pathname(entry)))
|
||||
continue;
|
||||
if (cpio->verbose) {
|
||||
/* TODO: uname/gname lookups */
|
||||
/* TODO: Clean this up. */
|
||||
fprintf(stdout,
|
||||
"%s%3d %8s%8s " CPIO_FILESIZE_PRINTF " %s\n",
|
||||
archive_entry_strmode(entry),
|
||||
archive_entry_nlink(entry),
|
||||
archive_entry_uname(entry),
|
||||
archive_entry_gname(entry),
|
||||
(CPIO_FILESIZE_TYPE)archive_entry_size(entry),
|
||||
archive_entry_pathname(entry));
|
||||
} else
|
||||
fprintf(stdout, "%s\n", archive_entry_pathname(entry));
|
||||
}
|
||||
r = archive_read_close(a);
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_errc(1, 0, archive_error_string(a));
|
||||
if (!cpio->quiet) {
|
||||
blocks = (archive_position_uncompressed(a) + 511)
|
||||
/ 512;
|
||||
fprintf(stderr, "%lu %s\n", blocks,
|
||||
blocks == 1 ? "block" : "blocks");
|
||||
}
|
||||
archive_read_finish(a);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
mode_pass(struct cpio *cpio, const char *destdir)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* Ensure target dir has a trailing '/' to simplify path surgery. */
|
||||
cpio->destdir = malloc(strlen(destdir) + 8);
|
||||
strcpy(cpio->destdir, destdir);
|
||||
if (destdir[strlen(destdir) - 1] != '/')
|
||||
strcat(cpio->destdir, "/");
|
||||
|
||||
cpio->archive = archive_write_disk_new();
|
||||
if (cpio->archive == NULL)
|
||||
cpio_errc(1, 0, "Failed to allocate archive object");
|
||||
r = archive_write_disk_set_options(cpio->archive, cpio->extract_flags);
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_errc(1, 0, archive_error_string(cpio->archive));
|
||||
cpio->linkresolver = archive_entry_linkresolver_new();
|
||||
archive_write_disk_set_standard_lookup(cpio->archive);
|
||||
process_lines(cpio, "-", file_to_archive);
|
||||
|
||||
archive_entry_linkresolver_free(cpio->linkresolver);
|
||||
r = archive_write_close(cpio->archive);
|
||||
if (r != ARCHIVE_OK)
|
||||
cpio_errc(1, 0, archive_error_string(cpio->archive));
|
||||
archive_write_finish(cpio->archive);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prompt for a new name for this entry. Returns a pointer to the
|
||||
* new name or NULL if the entry should not be copied. This
|
||||
* implements the semantics defined in POSIX.1-1996, which specifies
|
||||
* that an input of '.' means the name should be unchanged. GNU cpio
|
||||
* treats '.' as a literal new name.
|
||||
*/
|
||||
static const char *
|
||||
cpio_rename(const char *name)
|
||||
{
|
||||
static char buff[1024];
|
||||
FILE *t;
|
||||
char *p, *ret;
|
||||
|
||||
t = fopen("/dev/tty", "r+");
|
||||
if (t == NULL)
|
||||
return (name);
|
||||
fprintf(t, "%s (Enter/./(new name))? ", name);
|
||||
fflush(t);
|
||||
|
||||
p = fgets(buff, sizeof(buff), t);
|
||||
fclose(t);
|
||||
if (p == NULL)
|
||||
/* End-of-file is a blank line. */
|
||||
return (NULL);
|
||||
|
||||
while (*p == ' ' || *p == '\t')
|
||||
++p;
|
||||
if (*p == '\n' || *p == '\0')
|
||||
/* Empty line. */
|
||||
return (NULL);
|
||||
if (*p == '.' && p[1] == '\n')
|
||||
/* Single period preserves original name. */
|
||||
return (name);
|
||||
ret = p;
|
||||
/* Trim the final newline. */
|
||||
while (*p != '\0' && *p != '\n')
|
||||
++p;
|
||||
/* Overwrite the final \n with a null character. */
|
||||
*p = '\0';
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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 cpio *cpio, const char *pathname,
|
||||
int (*process)(struct cpio *, 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 = cpio->option_null ? '\0' : '\n';
|
||||
ret = 0;
|
||||
|
||||
if (strcmp(pathname, "-") == 0)
|
||||
f = stdin;
|
||||
else
|
||||
f = fopen(pathname, "r");
|
||||
if (f == NULL)
|
||||
cpio_errc(1, errno, "Couldn't open %s", pathname);
|
||||
buff_length = 8192;
|
||||
buff = malloc(buff_length);
|
||||
if (buff == NULL)
|
||||
cpio_errc(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)(cpio, line_start) != 0)
|
||||
ret = -1;
|
||||
line_start = line_end + 1;
|
||||
line_end = line_start;
|
||||
} else
|
||||
line_end++;
|
||||
}
|
||||
if (feof(f))
|
||||
break;
|
||||
if (ferror(f))
|
||||
cpio_errc(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)
|
||||
cpio_errc(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)(cpio, line_start) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
free(buff);
|
||||
if (f != stdin)
|
||||
fclose(f);
|
||||
return (ret);
|
||||
}
|
106
usr.bin/cpio/cpio.h
Normal file
106
usr.bin/cpio/cpio.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*-
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef CPIO_H_INCLUDED
|
||||
#define CPIO_H_INCLUDED
|
||||
|
||||
#include "cpio_platform.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define DEFAULT_BYTES_PER_BLOCK (20*512)
|
||||
|
||||
/*
|
||||
* The internal state for the "cpio" 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 cpio internal
|
||||
* functions.
|
||||
*/
|
||||
struct cpio {
|
||||
/* Options */
|
||||
char *filename;
|
||||
char mode; /* -i -o -p */
|
||||
char compress; /* -j, -y, or -z */
|
||||
const char *format; /* -H format */
|
||||
int bytes_per_block; /* -b block_size */
|
||||
int verbose; /* -v */
|
||||
int quiet; /* --quiet */
|
||||
int extract_flags; /* Flags for extract operation */
|
||||
char symlink_mode; /* H or L, per BSD conventions */
|
||||
const char *compress_program;
|
||||
int option_append; /* -A, only relevant for -o */
|
||||
int option_atime_restore; /* -a */
|
||||
int option_follow_links; /* -L */
|
||||
int option_link; /* -l */
|
||||
int option_list; /* -t */
|
||||
int option_null; /* -0 --null */
|
||||
int option_rename; /* -r */
|
||||
char *destdir;
|
||||
size_t pass_destpath_alloc;
|
||||
char *pass_destpath;
|
||||
int uid_override;
|
||||
int gid_override;
|
||||
|
||||
/* If >= 0, then close this when done. */
|
||||
int fd;
|
||||
|
||||
/* Miscellaneous state information */
|
||||
struct archive *archive;
|
||||
int argc;
|
||||
char **argv;
|
||||
int return_value; /* Value returned by main() */
|
||||
struct archive_entry_linkresolver *linkresolver;
|
||||
|
||||
/* Work data. */
|
||||
struct matching *matching;
|
||||
char *buff;
|
||||
size_t buff_size;
|
||||
};
|
||||
|
||||
/* Name of this program; used in error reporting, initialized in main(). */
|
||||
const char *cpio_progname;
|
||||
|
||||
void cpio_errc(int _eval, int _code, const char *fmt, ...);
|
||||
void cpio_warnc(int _code, const char *fmt, ...);
|
||||
|
||||
int owner_parse(const char *, int *, int *);
|
||||
|
||||
|
||||
/* Fake short equivalents for long options that otherwise lack them. */
|
||||
enum {
|
||||
OPTION_INSECURE = 1,
|
||||
OPTION_QUIET,
|
||||
OPTION_VERSION
|
||||
};
|
||||
|
||||
int cpio_getopt(struct cpio *cpio);
|
||||
int process_lines(struct cpio *cpio, const char *pathname,
|
||||
int (*process)(struct cpio *, const char *));
|
||||
int include_from_file(struct cpio *, const char *);
|
||||
|
||||
#endif
|
84
usr.bin/cpio/cpio_platform.h
Normal file
84
usr.bin/cpio/cpio_platform.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*-
|
||||
* 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$
|
||||
*/
|
||||
|
||||
/*
|
||||
* This header is the first thing included in any of the cpio
|
||||
* source files. As far as possible, platform-specific issues should
|
||||
* be dealt with here and not within individual source files.
|
||||
*/
|
||||
|
||||
#ifndef CPIO_PLATFORM_H_INCLUDED
|
||||
#define CPIO_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 cpio hasn't been (automatically or manually) configured. */
|
||||
#error Oops: No config.h and no built-in configuration in cpio_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
|
||||
|
||||
/*
|
||||
* 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 CPIO_FILESIZE_TYPE uintmax_t
|
||||
#define CPIO_FILESIZE_PRINTF "%ju"
|
||||
#else
|
||||
#if HAVE_UNSIGNED_LONG_LONG
|
||||
#define CPIO_FILESIZE_TYPE unsigned long long
|
||||
#define CPIO_FILESIZE_PRINTF "%llu"
|
||||
#else
|
||||
#define CPIO_FILESIZE_TYPE unsigned long
|
||||
#define CPIO_FILESIZE_PRINTF "%lu"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* !CPIO_PLATFORM_H_INCLUDED */
|
73
usr.bin/cpio/err.c
Normal file
73
usr.bin/cpio/err.c
Normal file
@ -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
|
||||
* in this position and unchanged.
|
||||
* 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 "cpio_platform.h"
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#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 "cpio.h"
|
||||
|
||||
static void
|
||||
cpio_vwarnc(int code, const char *fmt, va_list ap)
|
||||
{
|
||||
fprintf(stderr, "%s: ", cpio_progname);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
if (code != 0)
|
||||
fprintf(stderr, ": %s", strerror(code));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
cpio_warnc(int code, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
cpio_vwarnc(code, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
cpio_errc(int eval, int code, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
cpio_vwarnc(code, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(eval);
|
||||
}
|
250
usr.bin/cpio/matching.c
Normal file
250
usr.bin/cpio/matching.c
Normal file
@ -0,0 +1,250 @@
|
||||
/*-
|
||||
* 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 "cpio_platform.h"
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#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 "matching.h"
|
||||
#include "pathmatch.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 match **list, const char *pattern);
|
||||
static void initialize_matching(struct cpio *);
|
||||
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 cpio *cpio, const char *pattern)
|
||||
{
|
||||
struct matching *matching;
|
||||
|
||||
if (cpio->matching == NULL)
|
||||
initialize_matching(cpio);
|
||||
matching = cpio->matching;
|
||||
add_pattern(&(matching->exclusions), pattern);
|
||||
matching->exclusions_count++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
exclude_from_file(struct cpio *cpio, const char *pathname)
|
||||
{
|
||||
return (process_lines(cpio, pathname, &exclude));
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
include(struct cpio *cpio, const char *pattern)
|
||||
{
|
||||
struct matching *matching;
|
||||
|
||||
if (cpio->matching == NULL)
|
||||
initialize_matching(cpio);
|
||||
matching = cpio->matching;
|
||||
add_pattern(&(matching->inclusions), pattern);
|
||||
matching->inclusions_count++;
|
||||
matching->inclusions_unmatched_count++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
include_from_file(struct cpio *cpio, const char *pathname)
|
||||
{
|
||||
return (process_lines(cpio, pathname, &include));
|
||||
}
|
||||
|
||||
static void
|
||||
add_pattern(struct match **list, const char *pattern)
|
||||
{
|
||||
struct match *match;
|
||||
|
||||
match = malloc(sizeof(*match) + strlen(pattern) + 1);
|
||||
if (match == NULL)
|
||||
cpio_errc(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 cpio *cpio, const char *pathname)
|
||||
{
|
||||
struct matching *matching;
|
||||
struct match *match;
|
||||
struct match *matched;
|
||||
|
||||
matching = cpio->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)
|
||||
{
|
||||
return (pathmatch(match->pattern,
|
||||
pathname,
|
||||
PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (pathmatch(match->pattern, pathname, 0));
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_exclusions(struct cpio *cpio)
|
||||
{
|
||||
struct match *p, *q;
|
||||
|
||||
if (cpio->matching) {
|
||||
p = cpio->matching->inclusions;
|
||||
while (p != NULL) {
|
||||
q = p;
|
||||
p = p->next;
|
||||
free(q);
|
||||
}
|
||||
p = cpio->matching->exclusions;
|
||||
while (p != NULL) {
|
||||
q = p;
|
||||
p = p->next;
|
||||
free(q);
|
||||
}
|
||||
free(cpio->matching);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
initialize_matching(struct cpio *cpio)
|
||||
{
|
||||
cpio->matching = malloc(sizeof(*cpio->matching));
|
||||
if (cpio->matching == NULL)
|
||||
cpio_errc(1, errno, "No memory");
|
||||
memset(cpio->matching, 0, sizeof(*cpio->matching));
|
||||
}
|
||||
|
||||
int
|
||||
unmatched_inclusions(struct cpio *cpio)
|
||||
{
|
||||
struct matching *matching;
|
||||
|
||||
matching = cpio->matching;
|
||||
if (matching == NULL)
|
||||
return (0);
|
||||
return (matching->inclusions_unmatched_count);
|
||||
}
|
40
usr.bin/cpio/matching.h
Normal file
40
usr.bin/cpio/matching.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*-
|
||||
* 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
|
||||
* in this position and unchanged.
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef MATCHING_H
|
||||
#define MATCHING_H
|
||||
|
||||
#include "cpio.h"
|
||||
|
||||
int exclude(struct cpio *, const char *pattern);
|
||||
int include(struct cpio *, const char *pattern);
|
||||
int excluded(struct cpio *cpio, const char *pathname);
|
||||
void cleanup_exclusions(struct cpio *cpio);
|
||||
int unmatched_inclusions(struct cpio *cpio);
|
||||
|
||||
#endif
|
250
usr.bin/cpio/pathmatch.c
Normal file
250
usr.bin/cpio/pathmatch.c
Normal file
@ -0,0 +1,250 @@
|
||||
/*-
|
||||
* 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
|
||||
* in this position and unchanged.
|
||||
* 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 "cpio_platform.h"
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "pathmatch.h"
|
||||
|
||||
/*
|
||||
* Check whether a character 'c' is matched by a list specification [...]:
|
||||
* * Leading '!' negates the class.
|
||||
* * <char>-<char> is a range of characters
|
||||
* * \<char> removes any special meaning for <char>
|
||||
*
|
||||
* Some interesting boundary cases:
|
||||
* a-d-e is one range (a-d) followed by two single characters - and e.
|
||||
* \a-\d is same as a-d
|
||||
* a\-d is three single characters: a, d, -
|
||||
* Trailing - is not special (so [a-] is two characters a and -).
|
||||
* Initial - is not special ([a-] is same as [-a] is same as [\\-a])
|
||||
* This function never sees a trailing \.
|
||||
* [] always fails
|
||||
* [!] always succeeds
|
||||
*/
|
||||
static int
|
||||
pm_list(const char *start, const char *end, const char c, int flags)
|
||||
{
|
||||
const char *p = start;
|
||||
char rangeStart = '\0', nextRangeStart;
|
||||
int match = 1, nomatch = 0;
|
||||
|
||||
/* This will be used soon... */
|
||||
(void)flags; /* UNUSED */
|
||||
|
||||
/* If this is a negated class, return success for nomatch. */
|
||||
if (*p == '!' && p < end) {
|
||||
match = 0;
|
||||
nomatch = 1;
|
||||
++p;
|
||||
}
|
||||
|
||||
while (p < end) {
|
||||
nextRangeStart = '\0';
|
||||
switch (*p) {
|
||||
case '-':
|
||||
/* Trailing or initial '-' is not special. */
|
||||
if ((rangeStart == '\0') || (p == end - 1)) {
|
||||
if (*p == c)
|
||||
return (match);
|
||||
} else {
|
||||
char rangeEnd = *++p;
|
||||
if (rangeEnd == '\\')
|
||||
rangeEnd = *++p;
|
||||
if ((rangeStart <= c) && (c <= rangeEnd))
|
||||
return (match);
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
++p;
|
||||
/* Fall through */
|
||||
default:
|
||||
if (*p == c)
|
||||
return (match);
|
||||
nextRangeStart = *p; /* Possible start of range. */
|
||||
}
|
||||
rangeStart = nextRangeStart;
|
||||
++p;
|
||||
}
|
||||
return (nomatch);
|
||||
}
|
||||
|
||||
/*
|
||||
* If s is pointing to "./", ".//", "./././" or the like, skip it.
|
||||
*/
|
||||
static const char *
|
||||
pm_slashskip(const char *s) {
|
||||
while (*s == '.' || *s == '/') {
|
||||
if (s[0] != '/' && s[1] != '/')
|
||||
break;
|
||||
++s;
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
|
||||
static int
|
||||
pm(const char *p, const char *s, int flags)
|
||||
{
|
||||
const char *end;
|
||||
|
||||
/*
|
||||
* Ignore leading './', './/', '././', etc.
|
||||
*/
|
||||
if (s[0] == '.' && s[1] == '/')
|
||||
s = pm_slashskip(s + 1);
|
||||
if (p[0] == '.' && p[1] == '/')
|
||||
p = pm_slashskip(p + 1);
|
||||
|
||||
for (;;) {
|
||||
switch (*p) {
|
||||
case '\0':
|
||||
if (s[0] == '/') {
|
||||
if (flags & PATHMATCH_NO_ANCHOR_END)
|
||||
return (1);
|
||||
/* "dir" == "dir/" == "dir/." */
|
||||
s = pm_slashskip(s);
|
||||
if (s[0] == '.' && s[1] == '\0')
|
||||
return (1);
|
||||
}
|
||||
return (*s == '\0');
|
||||
break;
|
||||
case '?':
|
||||
/* ? always succeds, unless we hit end of 's' */
|
||||
if (*s == '\0')
|
||||
return (0);
|
||||
break;
|
||||
case '*':
|
||||
/* "*" == "**" == "***" ... */
|
||||
while (*p == '*')
|
||||
++p;
|
||||
/* Trailing '*' always succeeds. */
|
||||
if (*p == '\0')
|
||||
return (1);
|
||||
while (*s) {
|
||||
if (pathmatch(p, s, flags))
|
||||
return (1);
|
||||
++s;
|
||||
}
|
||||
return (0);
|
||||
break;
|
||||
case '[':
|
||||
/*
|
||||
* Find the end of the [...] character class,
|
||||
* ignoring \] that might occur within the class.
|
||||
*/
|
||||
end = p + 1;
|
||||
while (*end != '\0' && *end != ']') {
|
||||
if (*end == '\\' && end[1] != '\0')
|
||||
++end;
|
||||
++end;
|
||||
}
|
||||
if (*end == ']') {
|
||||
/* We found [...], try to match it. */
|
||||
if (!pm_list(p + 1, end, *s, flags))
|
||||
return (0);
|
||||
p = end; /* Jump to trailing ']' char. */
|
||||
break;
|
||||
} else
|
||||
/* No final ']', so just match '['. */
|
||||
if (*p != *s)
|
||||
return (0);
|
||||
break;
|
||||
default:
|
||||
if (*p == *s)
|
||||
break;
|
||||
if ((*s == '\0') && (*p == '/')) {
|
||||
p = pm_slashskip(p);
|
||||
if (*p == '\0')
|
||||
return (1);
|
||||
if (p[0] == '.' && p[1] == '\0')
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
return (0);
|
||||
break;
|
||||
case '\\':
|
||||
/* Trailing '\\' matches itself. */
|
||||
if (p[1] == '\0') {
|
||||
if (*s != '\\')
|
||||
return (0);
|
||||
} else {
|
||||
++p;
|
||||
if (*p != *s)
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* TODO: pattern of "\/\.\/" should not match plain "/",
|
||||
* it should only match explicit "/./".
|
||||
*/
|
||||
if (*p == '/')
|
||||
p = pm_slashskip(p);
|
||||
else
|
||||
++p;
|
||||
if (*s == '/')
|
||||
s = pm_slashskip(s);
|
||||
else
|
||||
++s;
|
||||
}
|
||||
}
|
||||
|
||||
/* Main entry point. */
|
||||
int
|
||||
pathmatch(const char *p, const char *s, int flags)
|
||||
{
|
||||
/* Empty pattern only matches the empty string. */
|
||||
if (p == NULL || *p == '\0')
|
||||
return (s == NULL || *s == '\0');
|
||||
|
||||
/* Leading '^' anchors the start of the pattern. */
|
||||
if (*p == '^') {
|
||||
++p;
|
||||
flags &= ~PATHMATCH_NO_ANCHOR_START;
|
||||
}
|
||||
|
||||
/* Certain patterns anchor implicitly. */
|
||||
if (*p == '*' || *p == '/')
|
||||
return (pm(p, s, flags));
|
||||
|
||||
/* If start is unanchored, try to match start of each path element. */
|
||||
if (flags & PATHMATCH_NO_ANCHOR_START) {
|
||||
for ( ; p != NULL; p = strchr(p, '/')) {
|
||||
if (*p == '/')
|
||||
p++;
|
||||
if (pm(p, s, flags))
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Default: Match from beginning. */
|
||||
return (pm(p, s, flags));
|
||||
}
|
37
usr.bin/cpio/pathmatch.h
Normal file
37
usr.bin/cpio/pathmatch.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*-
|
||||
* 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
|
||||
* in this position and unchanged.
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef PATHMATCH_H
|
||||
#define PATHMATCH_H
|
||||
|
||||
#define PATHMATCH_NO_ANCHOR_START 1
|
||||
#define PATHMATCH_NO_ANCHOR_END 2
|
||||
|
||||
int pathmatch(const char *p, const char *s, int flags);
|
||||
|
||||
#endif
|
72
usr.bin/cpio/test/Makefile
Normal file
72
usr.bin/cpio/test/Makefile
Normal file
@ -0,0 +1,72 @@
|
||||
# $FreeBSD$
|
||||
|
||||
# Where to find the cpio sources (for the internal unit tests)
|
||||
CPIO_SRCDIR=${.CURDIR}/..
|
||||
.PATH: ${CPIO_SRCDIR}
|
||||
|
||||
# Some cpio sources are pulled in for white-box tests
|
||||
CPIO_SRCS= cmdline.c err.c pathmatch.c
|
||||
|
||||
TESTS= \
|
||||
test_0.c \
|
||||
test_basic.c \
|
||||
test_format_newc.c \
|
||||
test_gcpio_compat.c \
|
||||
test_option_a.c \
|
||||
test_option_B.c \
|
||||
test_option_c.c \
|
||||
test_option_d.c \
|
||||
test_option_f.c \
|
||||
test_option_help.c \
|
||||
test_option_L.c \
|
||||
test_option_ell.c \
|
||||
test_option_m.c \
|
||||
test_option_t.c \
|
||||
test_option_u.c \
|
||||
test_option_version.c \
|
||||
test_option_y.c \
|
||||
test_option_z.c \
|
||||
test_owner_parse.c \
|
||||
test_pathmatch.c \
|
||||
|
||||
# Build the test program
|
||||
SRCS= list.h \
|
||||
${CPIO_SRCS} \
|
||||
${TESTS} \
|
||||
main.c
|
||||
|
||||
CLEANFILES+= list.h
|
||||
|
||||
NO_MAN=yes
|
||||
|
||||
PROG=bsdcpio_test
|
||||
DPADD=${LIBARCHIVE} ${LIBBZ2} ${LIBZ}
|
||||
CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\"
|
||||
CFLAGS+= -I..
|
||||
LDADD= -larchive -lz -lbz2
|
||||
CFLAGS+= -static -g -O2 -Wall
|
||||
CFLAGS+= -I${.OBJDIR}
|
||||
CFLAGS+= -I${CPIO_SRCDIR}
|
||||
|
||||
# Uncomment to link against dmalloc
|
||||
#LDADD+= -L/usr/local/lib -ldmalloc
|
||||
#CFLAGS+= -I/usr/local/include -DUSE_DMALLOC
|
||||
WARNS=6
|
||||
|
||||
check test: bsdcpio_test
|
||||
${.OBJDIR}/bsdcpio_test -p ${.OBJDIR}/../bsdcpio -r ${.CURDIR}
|
||||
|
||||
${.OBJDIR}/list.h list.h: ${TESTS} Makefile
|
||||
(cd ${.CURDIR}; cat ${TESTS}) | grep DEFINE_TEST > list.h
|
||||
|
||||
clean:
|
||||
rm -f *.out
|
||||
rm -f *.o
|
||||
rm -f *.core
|
||||
rm -f *~
|
||||
rm -f list.h
|
||||
rm -f archive.h ../archive.h
|
||||
-chmod -R +w /tmp/bsdcpio_test.*
|
||||
rm -rf /tmp/bsdcpio_test.*
|
||||
|
||||
.include <bsd.prog.mk>
|
970
usr.bin/cpio/test/main.c
Normal file
970
usr.bin/cpio/test/main.c
Normal file
@ -0,0 +1,970 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Various utility routines useful for test programs.
|
||||
* Each test program is linked against this file.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "test.h"
|
||||
|
||||
/*
|
||||
* This same file is used pretty much verbatim for all test harnesses.
|
||||
*
|
||||
* The next few lines are the only differences.
|
||||
*/
|
||||
#define PROGRAM "bsdcpio" /* Name of program being tested. */
|
||||
#define ENVBASE "BSDCPIO" /* Prefix for environment variables. */
|
||||
#undef EXTRA_DUMP /* How to dump extra data */
|
||||
/* How to generate extra version info. */
|
||||
#define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "")
|
||||
__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
|
||||
|
||||
/* Enable core dump on failure. */
|
||||
static int dump_on_failure = 0;
|
||||
/* Default is to remove temp dirs for successful tests. */
|
||||
static int keep_temp_files = 0;
|
||||
/* Default is to print some basic information about each test. */
|
||||
static int quiet_flag = 0;
|
||||
/* Default is to summarize repeated failures. */
|
||||
static int verbose = 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;
|
||||
|
||||
/* Directory where uuencoded reference files can be found. */
|
||||
static char *refdir;
|
||||
|
||||
/*
|
||||
* 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 = NULL;
|
||||
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';
|
||||
}
|
||||
|
||||
#ifdef EXTRA_DUMP
|
||||
if (extra != NULL)
|
||||
fprintf(stderr, " detail: %s\n", EXTRA_DUMP(extra));
|
||||
#else
|
||||
(void)extra; /* UNUSED */
|
||||
#endif
|
||||
|
||||
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. */
|
||||
int
|
||||
test_assert(const char *file, int line, int value, const char *condition, void *extra)
|
||||
{
|
||||
++assertions;
|
||||
if (value) {
|
||||
msg[0] = '\0';
|
||||
return (value);
|
||||
}
|
||||
failures ++;
|
||||
if (!verbose && previous_failures(file, line))
|
||||
return (value);
|
||||
fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
|
||||
fprintf(stderr, " Condition: %s\n", condition);
|
||||
report_failure(extra);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* assertEqualInt() displays the values of the two integers. */
|
||||
int
|
||||
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 (1);
|
||||
}
|
||||
failures ++;
|
||||
if (!verbose && previous_failures(file, line))
|
||||
return (0);
|
||||
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);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void strdump(const char *p)
|
||||
{
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "(null)");
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "\"");
|
||||
while (*p != '\0') {
|
||||
unsigned int c = 0xff & *p++;
|
||||
switch (c) {
|
||||
case '\a': fprintf(stderr, "\a"); break;
|
||||
case '\b': fprintf(stderr, "\b"); break;
|
||||
case '\n': fprintf(stderr, "\n"); break;
|
||||
case '\r': fprintf(stderr, "\r"); break;
|
||||
default:
|
||||
if (c >= 32 && c < 127)
|
||||
fprintf(stderr, "%c", c);
|
||||
else
|
||||
fprintf(stderr, "\\x%02X", c);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\"");
|
||||
}
|
||||
|
||||
/* assertEqualString() displays the values of the two strings. */
|
||||
int
|
||||
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 (1);
|
||||
}
|
||||
} else if (strcmp(v1, v2) == 0) {
|
||||
msg[0] = '\0';
|
||||
return (1);
|
||||
}
|
||||
failures ++;
|
||||
if (!verbose && previous_failures(file, line))
|
||||
return (0);
|
||||
fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n",
|
||||
file, line);
|
||||
fprintf(stderr, " %s = ", e1);
|
||||
strdump(v1);
|
||||
fprintf(stderr, " (length %d)\n", v1 == NULL ? 0 : strlen(v1));
|
||||
fprintf(stderr, " %s = ", e2);
|
||||
strdump(v2);
|
||||
fprintf(stderr, " (length %d)\n", v2 == NULL ? 0 : strlen(v2));
|
||||
report_failure(extra);
|
||||
return (0);
|
||||
}
|
||||
|
||||
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. */
|
||||
int
|
||||
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 (1);
|
||||
}
|
||||
failures ++;
|
||||
if (!verbose && previous_failures(file, line))
|
||||
return (0);
|
||||
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);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, 0xff & (int)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. */
|
||||
int
|
||||
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 (1);
|
||||
}
|
||||
} else if (memcmp(v1, v2, l) == 0) {
|
||||
msg[0] = '\0';
|
||||
return (1);
|
||||
}
|
||||
failures ++;
|
||||
if (!verbose && previous_failures(file, line))
|
||||
return (0);
|
||||
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);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
test_assert_empty_file(const char *f1fmt, ...)
|
||||
{
|
||||
char buff[1024];
|
||||
char f1[1024];
|
||||
struct stat st;
|
||||
va_list ap;
|
||||
ssize_t s;
|
||||
int fd;
|
||||
|
||||
|
||||
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);
|
||||
return (0);
|
||||
}
|
||||
if (st.st_size == 0)
|
||||
return (1);
|
||||
|
||||
failures ++;
|
||||
if (!verbose && previous_failures(test_filename, test_line))
|
||||
return (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);
|
||||
fprintf(stderr, " Contents:\n");
|
||||
fd = open(f1, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, " Unable to open %s\n", f1);
|
||||
} else {
|
||||
s = sizeof(buff) < st.st_size ? sizeof(buff) : st.st_size;
|
||||
s = read(fd, buff, s);
|
||||
hexdump(buff, NULL, s, 0);
|
||||
}
|
||||
report_failure(NULL);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* assertEqualFile() asserts that two files have the same contents. */
|
||||
/* TODO: hexdump the first bytes that actually differ. */
|
||||
int
|
||||
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 (1);
|
||||
if (memcmp(buff1, buff2, n1) != 0)
|
||||
break;
|
||||
}
|
||||
failures ++;
|
||||
if (!verbose && previous_failures(test_filename, test_line))
|
||||
return (0);
|
||||
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);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* assertFileContents() asserts the contents of a file. */
|
||||
int
|
||||
test_assert_file_contents(const void *buff, int s, const char *fpattern, ...)
|
||||
{
|
||||
char f[1024];
|
||||
va_list ap;
|
||||
char *contents;
|
||||
int fd;
|
||||
int n;
|
||||
|
||||
va_start(ap, fpattern);
|
||||
vsprintf(f, fpattern, ap);
|
||||
va_end(ap);
|
||||
|
||||
fd = open(f, O_RDONLY);
|
||||
contents = malloc(s * 2);
|
||||
n = read(fd, contents, s * 2);
|
||||
if (n == s && memcmp(buff, contents, s) == 0) {
|
||||
free(contents);
|
||||
return (1);
|
||||
}
|
||||
failures ++;
|
||||
if (!previous_failures(test_filename, test_line)) {
|
||||
fprintf(stderr, "%s:%d: File contents don't match\n",
|
||||
test_filename, test_line);
|
||||
fprintf(stderr, " file=\"%s\"\n", f);
|
||||
if (n > 0)
|
||||
hexdump(contents, buff, n, 0);
|
||||
else {
|
||||
fprintf(stderr, " File empty, contents should be:\n");
|
||||
hexdump(buff, NULL, s, 0);
|
||||
}
|
||||
report_failure(test_extra);
|
||||
}
|
||||
free(contents);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
/* Explicitly reset the locale before each test. */
|
||||
setlocale(LC_ALL, "C");
|
||||
/* Run the actual test. */
|
||||
(*tests[i].func)();
|
||||
/* Summarize the results of this test. */
|
||||
summarize();
|
||||
/* If there were no failures, we can remove the work dir. */
|
||||
if (failures == failures_before) {
|
||||
if (!keep_temp_files && chdir(tmpdir) == 0) {
|
||||
systemf("rm -rf %s", tests[i].name);
|
||||
}
|
||||
}
|
||||
/* 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(" -d Dump core after any failure, for debugging.\n");
|
||||
printf(" -k Keep all temp files.\n");
|
||||
printf(" Default: temp files for successful tests deleted.\n");
|
||||
#ifdef PROGRAM
|
||||
printf(" -p <path> Path to executable to be tested.\n");
|
||||
printf(" Default: path taken from " ENVBASE " environment variable.\n");
|
||||
#endif
|
||||
printf(" -q Quiet.\n");
|
||||
printf(" -r <dir> Path to dir containing reference files.\n");
|
||||
printf(" Default: Current directory.\n");
|
||||
printf(" -v Verbose.\n");
|
||||
printf("Available tests:\n");
|
||||
for (i = 0; i < limit; i++)
|
||||
printf(" %d: %s\n", i, tests[i].name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
|
||||
|
||||
void
|
||||
extract_reference_file(const char *name)
|
||||
{
|
||||
char buff[1024];
|
||||
FILE *in, *out;
|
||||
|
||||
sprintf(buff, "%s/%s.uu", refdir, name);
|
||||
in = fopen(buff, "r");
|
||||
failure("Couldn't open reference file %s", buff);
|
||||
assert(in != NULL);
|
||||
if (in == NULL)
|
||||
return;
|
||||
/* Read up to and including the 'begin' line. */
|
||||
for (;;) {
|
||||
if (fgets(buff, sizeof(buff), in) == NULL) {
|
||||
/* TODO: This is a failure. */
|
||||
return;
|
||||
}
|
||||
if (memcmp(buff, "begin ", 6) == 0)
|
||||
break;
|
||||
}
|
||||
/* Now, decode the rest and write it. */
|
||||
/* Not a lot of error checking here; the input better be right. */
|
||||
out = fopen(name, "w");
|
||||
while (fgets(buff, sizeof(buff), in) != NULL) {
|
||||
char *p = buff;
|
||||
int bytes;
|
||||
|
||||
if (memcmp(buff, "end", 3) == 0)
|
||||
break;
|
||||
|
||||
bytes = UUDECODE(*p++);
|
||||
while (bytes > 0) {
|
||||
int n = 0;
|
||||
/* Write out 1-3 bytes from that. */
|
||||
if (bytes > 0) {
|
||||
n = UUDECODE(*p++) << 18;
|
||||
n |= UUDECODE(*p++) << 12;
|
||||
fputc(n >> 16, out);
|
||||
--bytes;
|
||||
}
|
||||
if (bytes > 0) {
|
||||
n |= UUDECODE(*p++) << 6;
|
||||
fputc((n >> 8) & 0xFF, out);
|
||||
--bytes;
|
||||
}
|
||||
if (bytes > 0) {
|
||||
n |= UUDECODE(*p++);
|
||||
fputc(n & 0xFF, out);
|
||||
--bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef PROGRAM
|
||||
/* Get the target program from environment, if available. */
|
||||
testprog = getenv(ENVBASE);
|
||||
#endif
|
||||
|
||||
/* Allow -d to be controlled through the environment. */
|
||||
if (getenv(ENVBASE "_DEBUG") != NULL)
|
||||
dump_on_failure = 1;
|
||||
|
||||
/* Get the directory holding test files from environment. */
|
||||
refdir = getenv(ENVBASE "_TEST_FILES");
|
||||
|
||||
/*
|
||||
* Parse options.
|
||||
*/
|
||||
while ((opt = getopt(argc, argv, "dkp:qr:v")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dump_on_failure = 1;
|
||||
break;
|
||||
case 'k':
|
||||
keep_temp_files = 1;
|
||||
break;
|
||||
case 'p':
|
||||
#ifdef PROGRAM
|
||||
testprog = optarg;
|
||||
#else
|
||||
usage(progname);
|
||||
#endif
|
||||
break;
|
||||
case 'q':
|
||||
quiet_flag++;
|
||||
break;
|
||||
case 'r':
|
||||
refdir = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage(progname);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/*
|
||||
* Sanity-check that our options make sense.
|
||||
*/
|
||||
#ifdef PROGRAM
|
||||
if (testprog == NULL)
|
||||
usage(progname);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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';
|
||||
}
|
||||
systemf("rm %s/refdir", tmpdir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Banner with basic information.
|
||||
*/
|
||||
if (!quiet_flag) {
|
||||
printf("Running tests in: %s\n", tmpdir);
|
||||
printf("Reference files will be read from: %s\n", refdir);
|
||||
#ifdef PROGRAM
|
||||
printf("Running tests on: %s\n", testprog);
|
||||
#endif
|
||||
printf("Exercising: ");
|
||||
fflush(stdout);
|
||||
printf("%s\n", EXTRA_VERSION);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* If the final tmpdir is empty, we can remove it. */
|
||||
/* This should be the usual case when all tests succeed. */
|
||||
rmdir(tmpdir);
|
||||
|
||||
return (tests_failed);
|
||||
}
|
147
usr.bin/cpio/test/test.h
Normal file
147
usr.bin/cpio/test/test.h
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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$
|
||||
*/
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#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
|
||||
/* Assert that file contents match a string; supports printf-style arguments. */
|
||||
#define assertFileContents \
|
||||
test_setup(__FILE__, __LINE__);test_assert_file_contents
|
||||
|
||||
/*
|
||||
* 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, ...);
|
||||
int test_assert(const char *, int, int, const char *, void *);
|
||||
int test_assert_empty_file(const char *, ...);
|
||||
int test_assert_equal_file(const char *, const char *, ...);
|
||||
int test_assert_equal_int(const char *, int, int, const char *, int, const char *, void *);
|
||||
int test_assert_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *);
|
||||
int test_assert_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
|
||||
int test_assert_equal_mem(const char *, int, const char *, const char *, const char *, const char *, size_t, const char *, void *);
|
||||
int test_assert_file_contents(const void *, int, const char *, ...);
|
||||
|
||||
/* 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, ...);
|
||||
|
||||
/* Extracts named reference file to the current directory. */
|
||||
void extract_reference_file(const char *);
|
||||
|
||||
/*
|
||||
* Special interfaces for program test harness.
|
||||
*/
|
||||
|
||||
/* Pathname of exe to be tested. */
|
||||
char *testprog;
|
||||
|
62
usr.bin/cpio/test/test_0.c
Normal file
62
usr.bin/cpio/test/test_0.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*-
|
||||
* 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$");
|
||||
|
||||
/*
|
||||
* This first test does basic sanity checks on the environment. For
|
||||
* most of these, we just exit on failure.
|
||||
*/
|
||||
|
||||
DEFINE_TEST(test_0)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
failure("File %s does not exist?!", testprog);
|
||||
if (!assertEqualInt(0, stat(testprog, &st)))
|
||||
exit(1);
|
||||
|
||||
failure("%s is not executable?!", testprog);
|
||||
if (!assert((st.st_mode & 0111) != 0))
|
||||
exit(1);
|
||||
|
||||
/*
|
||||
* Try to succesfully run the program; this requires that
|
||||
* we know some option that will succeed.
|
||||
*/
|
||||
if (0 == systemf("%s --version >/dev/null", testprog)) {
|
||||
/* This worked. */
|
||||
} else if (0 == systemf("%s -W version >/dev/null", testprog)) {
|
||||
/* This worked. */
|
||||
} else {
|
||||
failure("Unable to successfully run any of the following:\n"
|
||||
" * %s --version\n"
|
||||
" * %s -W version\n",
|
||||
testprog, testprog);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* TODO: Ensure that our reference files are available. */
|
||||
}
|
204
usr.bin/cpio/test/test_basic.c
Normal file
204
usr.bin/cpio/test/test_basic.c
Normal file
@ -0,0 +1,204 @@
|
||||
/*-
|
||||
* 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
|
||||
verify_files(const char *target)
|
||||
{
|
||||
struct stat st, st2;
|
||||
char buff[128];
|
||||
int r;
|
||||
|
||||
/*
|
||||
* 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 should have 2 links", 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 should have 2 links", 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 should be hardlinked",
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
basic_cpio(const char *target,
|
||||
const char *pack_options,
|
||||
const char *unpack_options,
|
||||
const char *se)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!assertEqualInt(0, mkdir(target, 0775)))
|
||||
return;
|
||||
|
||||
/* Use the cpio program to create an archive. */
|
||||
r = systemf("%s -o %s < filelist >%s/archive 2>%s/pack.err",
|
||||
testprog, pack_options, target, target);
|
||||
failure("Error invoking %s -o %s", testprog, pack_options);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
chdir(target);
|
||||
|
||||
/* Verify stderr. */
|
||||
failure("Expected: %s, options=%s", se, pack_options);
|
||||
assertFileContents(se, strlen(se), "pack.err");
|
||||
|
||||
/*
|
||||
* Use cpio to unpack the archive into another directory.
|
||||
*/
|
||||
r = systemf("%s -i %s< archive >unpack.out 2>unpack.err",
|
||||
testprog, unpack_options);
|
||||
failure("Error invoking %s -i %s", testprog, unpack_options);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
/* Verify stderr. */
|
||||
failure("Error invoking %s -i %s in dir %s", testprog, unpack_options, target);
|
||||
assertFileContents(se, strlen(se), "unpack.err");
|
||||
|
||||
verify_files(target);
|
||||
|
||||
chdir("..");
|
||||
}
|
||||
|
||||
static void
|
||||
passthrough(const char *target)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!assertEqualInt(0, mkdir(target, 0775)))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Use cpio passthrough mode to copy files to another directory.
|
||||
*/
|
||||
r = systemf("%s -p -W quiet %s <filelist >%s/stdout 2>%s/stderr",
|
||||
testprog, target, target, target);
|
||||
failure("Error invoking %s -p", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
chdir(target);
|
||||
|
||||
/* Verify stderr. */
|
||||
failure("Error invoking %s -p in dir %s",
|
||||
testprog, target);
|
||||
assertEmptyFile("stderr");
|
||||
|
||||
verify_files(target);
|
||||
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_cpio("copy", "", "", "1 block\n");
|
||||
basic_cpio("copy_odc", "--format=odc", "", "1 block\n");
|
||||
basic_cpio("copy_newc", "-H newc", "", "2 blocks\n");
|
||||
basic_cpio("copy_cpio", "-H odc", "", "1 block\n");
|
||||
basic_cpio("copy_ustar", "-H ustar", "", "7 blocks\n");
|
||||
/* Copy in one step using -p */
|
||||
passthrough("passthrough");
|
||||
|
||||
umask(oldumask);
|
||||
}
|
245
usr.bin/cpio/test/test_format_newc.c
Normal file
245
usr.bin/cpio/test/test_format_newc.c
Normal file
@ -0,0 +1,245 @@
|
||||
/*-
|
||||
* 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 int
|
||||
is_hex(const char *p, size_t l)
|
||||
{
|
||||
while (l > 0) {
|
||||
if ((*p >= '0' && *p <= '9')
|
||||
|| (*p >= 'a' && *p <= 'f')
|
||||
|| (*p >= 'A' && *p <= 'F'))
|
||||
{
|
||||
--l;
|
||||
++p;
|
||||
} else
|
||||
return (0);
|
||||
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
from_hex(const char *p, size_t l)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
while (l > 0) {
|
||||
r *= 16;
|
||||
if (*p >= 'a' && *p <= 'f')
|
||||
r += *p + 10 - 'a';
|
||||
else if (*p >= 'A' && *p <= 'F')
|
||||
r += *p + 10 - 'A';
|
||||
else
|
||||
r += *p - '0';
|
||||
--l;
|
||||
++p;
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
DEFINE_TEST(test_format_newc)
|
||||
{
|
||||
int fd, list;
|
||||
int r;
|
||||
int devmajor, devminor, ino, gid;
|
||||
time_t t, t2, now;
|
||||
char *p, *e;
|
||||
size_t s;
|
||||
mode_t oldmask;
|
||||
|
||||
oldmask = umask(0);
|
||||
|
||||
/*
|
||||
* Create an assortment of files.
|
||||
* TODO: Extend this to cover more filetypes.
|
||||
*/
|
||||
list = open("list", O_CREAT | O_WRONLY, 0644);
|
||||
|
||||
/* "file1" */
|
||||
fd = open("file1", O_CREAT | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
assertEqualInt(10, write(fd, "123456789", 10));
|
||||
close(fd);
|
||||
assertEqualInt(6, write(list, "file1\n", 6));
|
||||
|
||||
/* "hardlink" */
|
||||
assertEqualInt(0, link("file1", "hardlink"));
|
||||
assertEqualInt(9, write(list, "hardlink\n", 9));
|
||||
|
||||
/* Another hardlink, but this one won't be archived. */
|
||||
assertEqualInt(0, link("file1", "hardlink2"));
|
||||
|
||||
/* "symlink" */
|
||||
assertEqualInt(0, symlink("file1", "symlink"));
|
||||
assertEqualInt(8, write(list, "symlink\n", 8));
|
||||
|
||||
/* "dir" */
|
||||
assertEqualInt(0, mkdir("dir", 0775));
|
||||
assertEqualInt(4, write(list, "dir\n", 4));
|
||||
|
||||
/* Record some facts about what we just created: */
|
||||
now = time(NULL); /* They were all created w/in last two seconds. */
|
||||
|
||||
/* Use the cpio program to create an archive. */
|
||||
close(list);
|
||||
r = systemf("%s -o --format=newc <list >newc.out 2>newc.err",
|
||||
testprog);
|
||||
if (!assertEqualInt(r, 0))
|
||||
return;
|
||||
|
||||
/* Verify that nothing went to stderr. */
|
||||
assertFileContents("2 blocks\n", 9, "newc.err");
|
||||
|
||||
/* Verify that stdout is a well-formed cpio file in "newc" format. */
|
||||
p = slurpfile(&s, "newc.out");
|
||||
assertEqualInt(s, 1024);
|
||||
e = p;
|
||||
|
||||
/*
|
||||
* Some of these assertions could be stronger, but it's
|
||||
* a little tricky because they depend on the local environment.
|
||||
*/
|
||||
|
||||
/* First entry is "file1" */
|
||||
assert(is_hex(e, 110)); /* Entire header is octal digits. */
|
||||
assertEqualMem(e + 0, "070701", 6); /* Magic */
|
||||
ino = from_hex(e + 6, 8); /* ino */
|
||||
assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */
|
||||
assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */
|
||||
gid = from_hex(e + 30, 8); /* gid */
|
||||
assertEqualMem(e + 38, "00000003", 8); /* nlink */
|
||||
t = from_hex(e + 46, 8); /* mtime */
|
||||
failure("t=0x%08x now=0x%08x=%d", t, now, now);
|
||||
assert(t <= now); /* File wasn't created in future. */
|
||||
failure("t=0x%08x now - 2=0x%08x = %d", t, now - 2, now - 2);
|
||||
assert(t >= now - 2); /* File was created w/in last 2 secs. */
|
||||
failure("newc format stores body only with last appearance of a link\n"
|
||||
" first appearance should be empty, so this file size\n"
|
||||
" field should be zero");
|
||||
assertEqualInt(0, from_hex(e + 54, 8)); /* File size */
|
||||
devmajor = from_hex(e + 62, 8); /* devmajor */
|
||||
devminor = from_hex(e + 70, 8); /* devminor */
|
||||
assert(is_hex(e + 78, 8)); /* rdevmajor */
|
||||
assert(is_hex(e + 86, 8)); /* rdevminor */
|
||||
assertEqualMem(e + 94, "00000006", 8); /* Name size */
|
||||
assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
|
||||
assertEqualMem(e + 110, "file1\0", 6); /* Name contents */
|
||||
/* Since there's another link, no file contents here. */
|
||||
/* But add in file size so that an error here doesn't cascade. */
|
||||
e += 116 + from_hex(e + 54, 8) + (3 & -from_hex(e + 54, 8));
|
||||
/* "symlink" pointing to "file1" */
|
||||
assert(is_hex(e, 110));
|
||||
assertEqualMem(e + 0, "070701", 6); /* Magic */
|
||||
assert(is_hex(e + 6, 8)); /* ino */
|
||||
assertEqualInt(0xa1ff, from_hex(e + 14, 8)); /* Mode */
|
||||
assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */
|
||||
assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
|
||||
assertEqualMem(e + 38, "00000001", 8); /* nlink */
|
||||
t2 = from_hex(e + 46, 8); /* mtime */
|
||||
failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2);
|
||||
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
|
||||
assertEqualMem(e + 54, "00000005", 8); /* File size */
|
||||
assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */
|
||||
assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */
|
||||
assert(is_hex(e + 78, 8)); /* rdevmajor */
|
||||
assert(is_hex(e + 86, 8)); /* rdevminor */
|
||||
assertEqualMem(e + 94, "00000008", 8); /* Name size */
|
||||
assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
|
||||
assertEqualMem(e + 110, "symlink\0\0\0", 10); /* Name contents */
|
||||
assertEqualMem(e + 120, "file1\0\0\0", 8); /* symlink target */
|
||||
e += 120 + from_hex(e + 54, 8) + (3 & -from_hex(e + 54, 8));
|
||||
|
||||
/* "dir" */
|
||||
assert(is_hex(e, 110));
|
||||
assertEqualMem(e + 0, "070701", 6); /* Magic */
|
||||
assert(is_hex(e + 6, 8)); /* ino */
|
||||
assertEqualInt(0x41fd, from_hex(e + 14, 8)); /* Mode */
|
||||
assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */
|
||||
assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
|
||||
assertEqualMem(e + 38, "00000002", 8); /* nlink */
|
||||
t2 = from_hex(e + 46, 8); /* mtime */
|
||||
failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2);
|
||||
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
|
||||
assertEqualMem(e + 54, "00000000", 8); /* File size */
|
||||
assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */
|
||||
assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */
|
||||
assert(is_hex(e + 78, 8)); /* rdevmajor */
|
||||
assert(is_hex(e + 86, 8)); /* rdevminor */
|
||||
assertEqualMem(e + 94, "00000004", 8); /* Name size */
|
||||
assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
|
||||
assertEqualMem(e + 110, "dir\0\0\0", 6); /* Name contents */
|
||||
e += 116;
|
||||
|
||||
/* TODO: Verify other types of entries. */
|
||||
|
||||
/* Hardlink identical to "file1" */
|
||||
/* Since we only wrote two of the three links to this
|
||||
* file, this link should get deferred by the hardlink logic. */
|
||||
assert(is_hex(e, 110));
|
||||
assertEqualMem(e + 0, "070701", 6); /* Magic */
|
||||
failure("If these aren't the same, then the hardlink detection failed to match them.");
|
||||
assertEqualInt(ino, from_hex(e + 6, 8)); /* ino */
|
||||
assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */
|
||||
assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */
|
||||
assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
|
||||
assertEqualMem(e + 38, "00000003", 8); /* nlink */
|
||||
t2 = from_hex(e + 46, 8); /* mtime */
|
||||
failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2);
|
||||
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
|
||||
assertEqualInt(10, from_hex(e + 54, 8)); /* File size */
|
||||
assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */
|
||||
assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */
|
||||
assert(is_hex(e + 78, 8)); /* rdevmajor */
|
||||
assert(is_hex(e + 86, 8)); /* rdevminor */
|
||||
assertEqualMem(e + 94, "00000009", 8); /* Name size */
|
||||
assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
|
||||
assertEqualMem(e + 110, "hardlink\0\0", 10); /* Name contents */
|
||||
assertEqualMem(e + 120, "123456789\0\0\0", 12); /* File contents */
|
||||
e += 120 + from_hex(e + 54, 8) + (3 & -from_hex(e + 54, 8));
|
||||
|
||||
/* Last entry is end-of-archive marker. */
|
||||
assert(is_hex(e, 110));
|
||||
assertEqualMem(e + 0, "070701", 6); /* Magic */
|
||||
assertEqualMem(e + 8, "00000000", 8); /* ino */
|
||||
assertEqualMem(e + 14, "00000000", 8); /* mode */
|
||||
assertEqualMem(e + 22, "00000000", 8); /* uid */
|
||||
assertEqualMem(e + 30, "00000000", 8); /* gid */
|
||||
assertEqualMem(e + 38, "00000001", 8); /* nlink */
|
||||
assertEqualMem(e + 46, "00000000", 8); /* mtime */
|
||||
assertEqualMem(e + 54, "00000000", 8); /* size */
|
||||
assertEqualMem(e + 62, "00000000", 8); /* devmajor */
|
||||
assertEqualMem(e + 70, "00000000", 8); /* devminor */
|
||||
assertEqualMem(e + 78, "00000000", 8); /* rdevmajor */
|
||||
assertEqualMem(e + 86, "00000000", 8); /* rdevminor */
|
||||
assertEqualInt(11, from_hex(e + 94, 8)); /* name size */
|
||||
assertEqualMem(e + 102, "00000000", 8); /* check field */
|
||||
assertEqualMem(e + 110, "TRAILER!!!\0\0", 12); /* Name */
|
||||
|
||||
free(p);
|
||||
|
||||
umask(oldmask);
|
||||
}
|
127
usr.bin/cpio/test/test_gcpio_compat.c
Normal file
127
usr.bin/cpio/test/test_gcpio_compat.c
Normal file
@ -0,0 +1,127 @@
|
||||
/*-
|
||||
* 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
|
||||
unpack_test(const char *from, const char *options, const char *se)
|
||||
{
|
||||
struct stat st, st2;
|
||||
char buff[128];
|
||||
int r;
|
||||
|
||||
/* Create a work dir named after the file we're unpacking. */
|
||||
assertEqualInt(0, mkdir(from, 0775));
|
||||
chdir(from);
|
||||
|
||||
/*
|
||||
* Use cpio to unpack the sample archive
|
||||
*/
|
||||
extract_reference_file(from);
|
||||
r = systemf("%s -i %s < %s >unpack.out 2>unpack.err",
|
||||
testprog, options, from);
|
||||
failure("Error invoking %s -i %s < %s",
|
||||
testprog, options, from);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
/* Verify that nothing went to stderr. */
|
||||
assertFileContents(se, strlen(se), "unpack.err");
|
||||
|
||||
/*
|
||||
* Verify unpacked files.
|
||||
*/
|
||||
|
||||
/* Regular file with 2 links. */
|
||||
r = lstat("file", &st);
|
||||
failure("Failed to stat file %s/file, errno=%d", from, errno);
|
||||
assertEqualInt(r, 0);
|
||||
if (r == 0) {
|
||||
assert(S_ISREG(st.st_mode));
|
||||
assertEqualInt(0644, st.st_mode & 0777);
|
||||
failure("file %s/file", from);
|
||||
assertEqualInt(10, st.st_size);
|
||||
failure("file %s/file", from);
|
||||
assertEqualInt(2, st.st_nlink);
|
||||
}
|
||||
|
||||
/* Another name for the same file. */
|
||||
r = lstat("linkfile", &st2);
|
||||
failure("Failed to stat file %s/linkfile, errno=%d", from, errno);
|
||||
assertEqualInt(r, 0);
|
||||
if (r == 0) {
|
||||
assert(S_ISREG(st2.st_mode));
|
||||
assertEqualInt(0644, st2.st_mode & 0777);
|
||||
failure("file %s/file", from);
|
||||
assertEqualInt(10, st2.st_size);
|
||||
failure("file %s/file", from);
|
||||
assertEqualInt(2, st2.st_nlink);
|
||||
failure("file and linkfile should be hardlinked");
|
||||
assertEqualInt(st.st_dev, st2.st_dev);
|
||||
failure("file %s/file", from);
|
||||
assertEqualInt(st.st_ino, st2.st_ino);
|
||||
}
|
||||
|
||||
/* Symlink */
|
||||
r = lstat("symlink", &st);
|
||||
failure("Failed to stat file %s/symlink, errno=%d", from, 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_gcpio_compat)
|
||||
{
|
||||
int oldumask;
|
||||
|
||||
oldumask = umask(0);
|
||||
|
||||
/* Dearchive sample files with a variety of options. */
|
||||
unpack_test("test_gcpio_compat_ref.bin", "", "1 block\n");
|
||||
unpack_test("test_gcpio_compat_ref.crc", "", "2 blocks\n");
|
||||
unpack_test("test_gcpio_compat_ref.newc", "", "2 blocks\n");
|
||||
unpack_test("test_gcpio_compat_ref.ustar", "", "7 blocks\n");
|
||||
|
||||
umask(oldumask);
|
||||
}
|
16
usr.bin/cpio/test/test_gcpio_compat_ref.bin.uu
Normal file
16
usr.bin/cpio/test/test_gcpio_compat_ref.bin.uu
Normal file
@ -0,0 +1,16 @@
|
||||
$FreeBSD$
|
||||
begin 644 test_gcpio_compat_ref.bin
|
||||
MQW%9`*IWI('H`^@#`@````U'=YD%````"@!F:6QE```Q,C,T-38W.#D*QW%9
|
||||
M`*IWI('H`^@#`@````U'=YD)````"@!L:6YK9FEL90``,3(S-#4V-S@Y"L=Q
|
||||
M60"K=^VAZ`/H`P$````-1X29"`````0`<WEM;&EN:P!F:6QEQW%9`*YW_4'H
|
||||
M`^@#`@````U'A9D$``````!D:7(`QW$``````````````0`````````+````
|
||||
M``!44D%)3$52(2$A````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
1````````````````````````
|
||||
`
|
||||
end
|
27
usr.bin/cpio/test/test_gcpio_compat_ref.crc.uu
Normal file
27
usr.bin/cpio/test/test_gcpio_compat_ref.crc.uu
Normal file
@ -0,0 +1,27 @@
|
||||
$FreeBSD$
|
||||
begin 644 test_gcpio_compat_ref.crc
|
||||
M,#<P-S`R,#`S,S<W86$P,#`P.#%A-#`P,#`P,V4X,#`P,#`S93@P,#`P,#`P
|
||||
M,C0W,&0Y.3<W,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#4Y,#`P,#`P,#`P,#`P
|
||||
M,#`P,#`P,#`P,#`U,#`P,#`P,#!F:6QE```P-S`W,#(P,#,S-S=A83`P,#`X
|
||||
M,6$T,#`P,#`S93@P,#`P,#-E.#`P,#`P,#`R-#<P9#DY-S<P,#`P,#`P83`P
|
||||
M,#`P,#`P,#`P,#`P-3DP,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#DP,#`P,#%E
|
||||
M-VQI;FMF:6QE```Q,C,T-38W.#D*```P-S`W,#(P,#,S-S=A8C`P,#!A,65D
|
||||
M,#`P,#`S93@P,#`P,#-E.#`P,#`P,#`Q-#<P9#DY.#0P,#`P,#`P-#`P,#`P
|
||||
M,#`P,#`P,#`P-3DP,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#@P,#`P,#`P,'-Y
|
||||
M;6QI;FL```!F:6QE,#<P-S`R,#`S,S<W864P,#`P-#%F9#`P,#`P,V4X,#`P
|
||||
M,#`S93@P,#`P,#`P,C0W,&0Y.3@U,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#4Y
|
||||
M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`T,#`P,#`P,#!D:7(````P-S`W,#(P
|
||||
M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`Q,#`P,#`P
|
||||
M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P
|
||||
M,#`P,&(P,#`P,#`P,%1204E,15(A(2$`````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
B````````````````````````````````````````````````
|
||||
`
|
||||
end
|
27
usr.bin/cpio/test/test_gcpio_compat_ref.newc.uu
Normal file
27
usr.bin/cpio/test/test_gcpio_compat_ref.newc.uu
Normal file
@ -0,0 +1,27 @@
|
||||
$FreeBSD$
|
||||
begin 644 test_gcpio_compat_ref.newc
|
||||
M,#<P-S`Q,#`S,S<W86$P,#`P.#%A-#`P,#`P,V4X,#`P,#`S93@P,#`P,#`P
|
||||
M,C0W,&0Y.3<W,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#4Y,#`P,#`P,#`P,#`P
|
||||
M,#`P,#`P,#`P,#`U,#`P,#`P,#!F:6QE```P-S`W,#$P,#,S-S=A83`P,#`X
|
||||
M,6$T,#`P,#`S93@P,#`P,#-E.#`P,#`P,#`R-#<P9#DY-S<P,#`P,#`P83`P
|
||||
M,#`P,#`P,#`P,#`P-3DP,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#DP,#`P,#`P
|
||||
M,&QI;FMF:6QE```Q,C,T-38W.#D*```P-S`W,#$P,#,S-S=A8C`P,#!A,65D
|
||||
M,#`P,#`S93@P,#`P,#-E.#`P,#`P,#`Q-#<P9#DY.#0P,#`P,#`P-#`P,#`P
|
||||
M,#`P,#`P,#`P-3DP,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#@P,#`P,#`P,'-Y
|
||||
M;6QI;FL```!F:6QE,#<P-S`Q,#`S,S<W864P,#`P-#%F9#`P,#`P,V4X,#`P
|
||||
M,#`S93@P,#`P,#`P,C0W,&0Y.3@U,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#4Y
|
||||
M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`T,#`P,#`P,#!D:7(````P-S`W,#$P
|
||||
M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`Q,#`P,#`P
|
||||
M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P
|
||||
M,#`P,&(P,#`P,#`P,%1204E,15(A(2$`````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
B````````````````````````````````````````````````
|
||||
`
|
||||
end
|
84
usr.bin/cpio/test/test_gcpio_compat_ref.ustar.uu
Normal file
84
usr.bin/cpio/test/test_gcpio_compat_ref.ustar.uu
Normal file
@ -0,0 +1,84 @@
|
||||
$FreeBSD$
|
||||
begin 644 test_gcpio_compat_ref.ustar
|
||||
M9FEL90``````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M`````````````#`P,#`V-#0`,#`P,3<U,``P,#`Q-S4P`#`P,#`P,#`P,#$R
|
||||
M`#$P-S`S,S$T-38W`#`P,3$S-C,`,```````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M``````````````````````````````````````````!U<W1A<@`P,'1I;0``
|
||||
M````````````````````````````````````=&EM````````````````````
|
||||
M```````````````````P,#`P,#`P`#`P,#`P,#``````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M```````````````````````Q,C,T-38W.#D*````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M`````````````````````````````````````````````&QI;FMF:6QE````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M```````````````````````````````````````````````````````````P
|
||||
M,#`P-C0T`#`P,#$W-3``,#`P,3<U,``P,#`P,#`P,#`P,``Q,#<P,S,Q-#4V
|
||||
M-P`P,#$S,#<W`#%F:6QE````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````=7-T87(`,#!T:6T`````````````````
|
||||
M`````````````````````'1I;0``````````````````````````````````
|
||||
M````,#`P,#`P,``P,#`P,#`P````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````<WEM;&EN:P``````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M`````````````````````#`P,#`W-34`,#`P,3<U,``P,#`Q-S4P`#`P,#`P
|
||||
M,#`P,#`P`#$P-S`S,S$T-C`T`#`P,3(W-C0`,F9I;&4`````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M``````````````````````````````````````````````````!U<W1A<@`P
|
||||
M,'1I;0``````````````````````````````````````=&EM````````````
|
||||
M```````````````````````````P,#`P,#`P`#`P,#`P,#``````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M``````````````````````````````!D:7(O````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````,#`P,#<W-0`P,#`Q
|
||||
M-S4P`#`P,#$W-3``,#`P,#`P,#`P,#``,3`W,#,S,30V,#4`,#`Q,3,P,0`U
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M`````````````'5S=&%R`#`P=&EM````````````````````````````````
|
||||
M``````!T:6T``````````````````````````````````````#`P,#`P,#``
|
||||
M,#`P,#`P,```````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
=````````````````````````````````````````
|
||||
`
|
||||
end
|
54
usr.bin/cpio/test/test_option_B.c
Normal file
54
usr.bin/cpio/test/test_option_B.c
Normal file
@ -0,0 +1,54 @@
|
||||
/*-
|
||||
* 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_option_B)
|
||||
{
|
||||
struct stat st;
|
||||
int r, fd;
|
||||
|
||||
/*
|
||||
* Create a file on disk.
|
||||
*/
|
||||
fd = open("file", O_CREAT | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
close(fd);
|
||||
|
||||
/* Create an archive without -B; this should be 512 bytes. */
|
||||
r = systemf("echo file | %s -o > small.cpio 2>small.err", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertFileContents("1 block\n", 8, "small.err");
|
||||
assertEqualInt(0, stat("small.cpio", &st));
|
||||
assertEqualInt(512, st.st_size);
|
||||
|
||||
/* Create an archive with -B; this should be 5120 bytes. */
|
||||
r = systemf("echo file | %s -oB > large.cpio 2>large.err", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertFileContents("1 block\n", 8, "large.err");
|
||||
assertEqualInt(0, stat("large.cpio", &st));
|
||||
assertEqualInt(5120, st.st_size);
|
||||
}
|
84
usr.bin/cpio/test/test_option_L.c
Normal file
84
usr.bin/cpio/test/test_option_L.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*-
|
||||
* 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_option_L)
|
||||
{
|
||||
struct stat st;
|
||||
int fd, filelist;
|
||||
int r;
|
||||
|
||||
filelist = open("filelist", O_CREAT | O_WRONLY, 0644);
|
||||
|
||||
/* Create a file and a symlink to the file. */
|
||||
fd = open("file", O_CREAT | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
assertEqualInt(10, write(fd, "123456789", 10));
|
||||
close(fd);
|
||||
write(filelist, "file\n", 5);
|
||||
|
||||
/* Symlink to above file. */
|
||||
assertEqualInt(0, symlink("file", "symlink"));
|
||||
write(filelist, "symlink\n", 8);
|
||||
|
||||
close(filelist);
|
||||
|
||||
r = systemf("cat filelist | %s -pd copy >copy.out 2>copy.err", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertEqualInt(0, lstat("copy/symlink", &st));
|
||||
failure("Regular -p without -L should preserve symlinks.");
|
||||
assert(S_ISLNK(st.st_mode));
|
||||
|
||||
r = systemf("cat filelist | %s -pd -L copy-L >copy-L.out 2>copy-L.err", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertEmptyFile("copy-L.out");
|
||||
assertEmptyFile("copy-L.err");
|
||||
assertEqualInt(0, lstat("copy-L/symlink", &st));
|
||||
failure("-pdL should dereference symlinks and turn them into files.");
|
||||
assert(!S_ISLNK(st.st_mode));
|
||||
|
||||
r = systemf("cat filelist | %s -o >archive.out 2>archive.err", testprog);
|
||||
failure("Error invoking %s -o ", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
assertEqualInt(0, mkdir("unpack", 0755));
|
||||
r = systemf("cat archive.out | (cd unpack ; %s -i >unpack.out 2>unpack.err)", testprog);
|
||||
failure("Error invoking %s -i", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertEqualInt(0, lstat("unpack/symlink", &st));
|
||||
assert(S_ISLNK(st.st_mode));
|
||||
|
||||
r = systemf("cat filelist | %s -oL >archive-L.out 2>archive-L.err", testprog);
|
||||
failure("Error invoking %s -oL", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
assertEqualInt(0, mkdir("unpack-L", 0755));
|
||||
r = systemf("cat archive-L.out | (cd unpack-L ; %s -i >unpack-L.out 2>unpack-L.err)", testprog);
|
||||
failure("Error invoking %s -i < archive-L.out", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertEqualInt(0, lstat("unpack-L/symlink", &st));
|
||||
assert(!S_ISLNK(st.st_mode));
|
||||
}
|
159
usr.bin/cpio/test/test_option_a.c
Normal file
159
usr.bin/cpio/test/test_option_a.c
Normal file
@ -0,0 +1,159 @@
|
||||
/*-
|
||||
* Copyright (c) 2003-2008 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"
|
||||
#include <utime.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
time_t atime_sec;
|
||||
} files[] = {
|
||||
{ "f0", 0 },
|
||||
{ "f1", 0 },
|
||||
{ "f2", 0 },
|
||||
{ "f3", 0 },
|
||||
{ "f4", 0 },
|
||||
{ "f5", 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Create a bunch of test files and record their atimes.
|
||||
* For the atime preserve/change tests, the files must have
|
||||
* atimes in the past. We can accomplish this by explicitly invoking
|
||||
* utime() on platforms that support it or by simply sleeping
|
||||
* for a second after creating the files. (Creating all of the files
|
||||
* at once means we only need to sleep once.)
|
||||
*/
|
||||
static void
|
||||
test_create(void)
|
||||
{
|
||||
struct stat st;
|
||||
struct utimbuf times;
|
||||
static const int numfiles = sizeof(files) / sizeof(files[0]);
|
||||
int i;
|
||||
int fd;
|
||||
|
||||
for (i = 0; i < numfiles; ++i) {
|
||||
fd = open(files[i].name, O_CREAT | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
/*
|
||||
* Note: Have to write at least one byte to the file.
|
||||
* cpio doesn't bother reading the file if it's zero length,
|
||||
* so the atime never gets changed in that case, which
|
||||
* makes the tests below rather pointless.
|
||||
*/
|
||||
assertEqualInt(1, write(fd, "a", 1));
|
||||
close(fd);
|
||||
|
||||
/* If utime() isn't supported on your platform, just
|
||||
* #ifdef this section out. Most of the test below is
|
||||
* still valid. */
|
||||
memset(×, 0, sizeof(times));
|
||||
times.actime = 1;
|
||||
times.modtime = 3;
|
||||
assertEqualInt(0, utime(files[i].name, ×));
|
||||
|
||||
/* Record whatever atime the file ended up with. */
|
||||
/* If utime() is available, this should be 1, but there's
|
||||
* no harm in being careful. */
|
||||
assertEqualInt(0, stat(files[i].name, &st));
|
||||
files[i].atime_sec = st.st_atime;
|
||||
}
|
||||
|
||||
/* Wait until the atime on the last file is actually in the past. */
|
||||
/* If utime() is supported above, there's no sleep here which
|
||||
* makes the test faster. */
|
||||
while (files[numfiles - 1].atime_sec >= time(NULL))
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
DEFINE_TEST(test_option_a)
|
||||
{
|
||||
struct stat st;
|
||||
int r;
|
||||
int f;
|
||||
char buff[64];
|
||||
|
||||
/* Create all of the test files. */
|
||||
test_create();
|
||||
|
||||
/* Sanity check; verify that atimes really do get modified. */
|
||||
f = open(files[0].name, O_RDONLY);
|
||||
assertEqualInt(1, read(f,buff, 1));
|
||||
assertEqualInt(0, close(f));
|
||||
assertEqualInt(0, stat("f0", &st));
|
||||
if (st.st_atime == files[0].atime_sec) {
|
||||
skipping("Cannot verify -a option\n"
|
||||
" Your system appears to not support atime.");
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If this disk is mounted noatime, then we can't
|
||||
* verify correct operation without -a.
|
||||
*/
|
||||
|
||||
/* Copy the file without -a; should change the atime. */
|
||||
r = systemf("echo %s | %s -pd copy-no-a > copy-no-a.out 2>copy-no-a.err", files[1].name, testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertEmptyFile("copy-no-a.err");
|
||||
assertEmptyFile("copy-no-a.out");
|
||||
assertEqualInt(0, stat(files[1].name, &st));
|
||||
failure("Copying file without -a should have changed atime.");
|
||||
assert(st.st_atime != files[1].atime_sec);
|
||||
|
||||
/* Archive the file without -a; should change the atime. */
|
||||
r = systemf("echo %s | %s -o > archive-no-a.out 2>archive-no-a.err", files[2].name, testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertEmptyFile("copy-no-a.err");
|
||||
assertEqualInt(0, stat(files[2].name, &st));
|
||||
failure("Archiving file without -a should have changed atime.");
|
||||
assert(st.st_atime != files[2].atime_sec);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can, of course, still verify that the atime is unchanged
|
||||
* when using the -a option.
|
||||
*/
|
||||
|
||||
/* Copy the file with -a; should not change the atime. */
|
||||
r = systemf("echo %s | %s -pad copy-a > copy-a.out 2>copy-a.err",
|
||||
files[3].name, testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertEmptyFile("copy-a.err");
|
||||
assertEmptyFile("copy-a.out");
|
||||
assertEqualInt(0, stat(files[3].name, &st));
|
||||
failure("Copying file with -a should not have changed atime.");
|
||||
assertEqualInt(st.st_atime, files[3].atime_sec);
|
||||
|
||||
/* Archive the file with -a; should not change the atime. */
|
||||
r = systemf("echo %s | %s -oa > archive-a.out 2>archive-a.err",
|
||||
files[4].name, testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertEmptyFile("copy-a.err");
|
||||
assertEqualInt(0, stat(files[4].name, &st));
|
||||
failure("Archiving file with -a should not have changed atime.");
|
||||
assertEqualInt(st.st_atime, files[4].atime_sec);
|
||||
}
|
198
usr.bin/cpio/test/test_option_c.c
Normal file
198
usr.bin/cpio/test/test_option_c.c
Normal file
@ -0,0 +1,198 @@
|
||||
/*-
|
||||
* 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 int
|
||||
is_octal(const char *p, size_t l)
|
||||
{
|
||||
while (l > 0) {
|
||||
if (*p < '0' || *p > '7')
|
||||
return (0);
|
||||
--l;
|
||||
++p;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
from_octal(const char *p, size_t l)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
while (l > 0) {
|
||||
r *= 8;
|
||||
r += *p - '0';
|
||||
--l;
|
||||
++p;
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
DEFINE_TEST(test_option_c)
|
||||
{
|
||||
int fd, filelist;
|
||||
int r;
|
||||
int dev, ino, gid;
|
||||
time_t t, now;
|
||||
char *p, *e;
|
||||
size_t s;
|
||||
mode_t oldmask;
|
||||
|
||||
oldmask = umask(0);
|
||||
|
||||
/*
|
||||
* Create an assortment of files.
|
||||
* TODO: Extend this to cover more filetypes.
|
||||
*/
|
||||
filelist = open("filelist", O_CREAT | O_WRONLY, 0644);
|
||||
|
||||
/* "file" */
|
||||
fd = open("file", O_CREAT | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
assertEqualInt(10, write(fd, "123456789", 10));
|
||||
close(fd);
|
||||
assertEqualInt(5, write(filelist, "file\n", 5));
|
||||
|
||||
/* "symlink" */
|
||||
assertEqualInt(0, symlink("file", "symlink"));
|
||||
assertEqualInt(8, write(filelist, "symlink\n", 8));
|
||||
|
||||
/* "dir" */
|
||||
assertEqualInt(0, mkdir("dir", 0775));
|
||||
/* Record some facts about what we just created: */
|
||||
now = time(NULL); /* They were all created w/in last two seconds. */
|
||||
assertEqualInt(4, write(filelist, "dir\n", 4));
|
||||
|
||||
/* Use the cpio program to create an archive. */
|
||||
close(filelist);
|
||||
r = systemf("%s -oc <filelist >basic.out 2>basic.err", testprog);
|
||||
/* Verify that nothing went to stderr. */
|
||||
assertFileContents("1 block\n", 8, "basic.err");
|
||||
|
||||
/* Assert that the program finished. */
|
||||
failure("%s -oc crashed", testprog);
|
||||
if (!assertEqualInt(r, 0))
|
||||
return;
|
||||
|
||||
/* Verify that stdout is a well-formed cpio file in "odc" format. */
|
||||
p = slurpfile(&s, "basic.out");
|
||||
assertEqualInt(s, 512);
|
||||
e = p;
|
||||
|
||||
/*
|
||||
* Some of these assertions could be stronger, but it's
|
||||
* a little tricky because they depend on the local environment.
|
||||
*/
|
||||
|
||||
/* First entry is "file" */
|
||||
assert(is_octal(e, 76)); /* Entire header is octal digits. */
|
||||
assertEqualMem(e + 0, "070707", 6); /* Magic */
|
||||
assert(is_octal(e + 6, 6)); /* dev */
|
||||
dev = from_octal(e + 6, 6);
|
||||
assert(is_octal(e + 12, 6)); /* ino */
|
||||
ino = from_octal(e + 12, 6);
|
||||
assertEqualMem(e + 18, "100644", 6); /* Mode */
|
||||
assertEqualInt(from_octal(e + 24, 6), getuid()); /* uid */
|
||||
assert(is_octal(e + 30, 6)); /* gid */
|
||||
gid = from_octal(e + 30, 6);
|
||||
assertEqualMem(e + 36, "000001", 6); /* nlink */
|
||||
failure("file entries should not have rdev set (dev field was 0%o)",
|
||||
dev);
|
||||
assertEqualMem(e + 42, "000000", 6); /* rdev */
|
||||
t = from_octal(e + 48, 11); /* mtime */
|
||||
assert(t <= now); /* File wasn't created in future. */
|
||||
assert(t >= now - 2); /* File was created w/in last 2 secs. */
|
||||
assertEqualMem(e + 59, "000005", 6); /* Name size */
|
||||
assertEqualMem(e + 65, "00000000012", 11); /* File size */
|
||||
assertEqualMem(e + 76, "file\0", 5); /* Name contents */
|
||||
assertEqualMem(e + 81, "123456789\0", 10); /* File contents */
|
||||
e += 91;
|
||||
|
||||
/* Second entry is "symlink" pointing to "file" */
|
||||
assert(is_octal(e, 76)); /* Entire header is octal digits. */
|
||||
assertEqualMem(e + 0, "070707", 6); /* Magic */
|
||||
assertEqualInt(dev, from_octal(e + 6, 6)); /* dev */
|
||||
assert(dev != from_octal(e + 12, 6)); /* ino */
|
||||
assertEqualMem(e + 18, "120777", 6); /* Mode */
|
||||
assertEqualInt(from_octal(e + 24, 6), getuid()); /* uid */
|
||||
assertEqualInt(gid, from_octal(e + 30, 6)); /* gid */
|
||||
assertEqualMem(e + 36, "000001", 6); /* nlink */
|
||||
failure("file entries should have rdev == 0 (dev was 0%o)",
|
||||
from_octal(e + 6, 6));
|
||||
assertEqualMem(e + 42, "000000", 6); /* rdev */
|
||||
t = from_octal(e + 48, 11); /* mtime */
|
||||
assert(t <= now); /* File wasn't created in future. */
|
||||
assert(t >= now - 2); /* File was created w/in last 2 secs. */
|
||||
assertEqualMem(e + 59, "000010", 6); /* Name size */
|
||||
assertEqualMem(e + 65, "00000000004", 11); /* File size */
|
||||
assertEqualMem(e + 76, "symlink\0", 8); /* Name contents */
|
||||
assertEqualMem(e + 84, "file", 4); /* Symlink target. */
|
||||
e += 88;
|
||||
|
||||
/* Second entry is "dir" */
|
||||
assert(is_octal(e, 76));
|
||||
assertEqualMem(e + 0, "070707", 6); /* Magic */
|
||||
/* Dev should be same as first entry. */
|
||||
assert(is_octal(e + 6, 6)); /* dev */
|
||||
assertEqualInt(dev, from_octal(e + 6, 6));
|
||||
/* Ino must be different from first entry. */
|
||||
assert(is_octal(e + 12, 6)); /* ino */
|
||||
assert(dev != from_octal(e + 12, 6));
|
||||
assertEqualMem(e + 18, "040775", 6); /* Mode */
|
||||
assertEqualInt(from_octal(e + 24, 6), getuid()); /* uid */
|
||||
/* Gid should be same as first entry. */
|
||||
assert(is_octal(e + 30, 6)); /* gid */
|
||||
assertEqualInt(gid, from_octal(e + 30, 6));
|
||||
assertEqualMem(e + 36, "000002", 6); /* Nlink */
|
||||
t = from_octal(e + 48, 11); /* mtime */
|
||||
assert(t <= now); /* File wasn't created in future. */
|
||||
assert(t >= now - 2); /* File was created w/in last 2 secs. */
|
||||
assertEqualMem(e + 59, "000004", 6); /* Name size */
|
||||
assertEqualMem(e + 65, "00000000000", 11); /* File size */
|
||||
assertEqualMem(e + 76, "dir\0", 4); /* name */
|
||||
e += 80;
|
||||
|
||||
/* TODO: Verify other types of entries. */
|
||||
|
||||
/* Last entry is end-of-archive marker. */
|
||||
assert(is_octal(e, 76));
|
||||
assertEqualMem(e + 0, "070707", 6); /* Magic */
|
||||
assertEqualMem(e + 6, "000000", 6); /* dev */
|
||||
assertEqualMem(e + 12, "000000", 6); /* ino */
|
||||
assertEqualMem(e + 18, "000000", 6); /* Mode */
|
||||
assertEqualMem(e + 24, "000000", 6); /* uid */
|
||||
assertEqualMem(e + 30, "000000", 6); /* gid */
|
||||
assertEqualMem(e + 36, "000001", 6); /* Nlink */
|
||||
assertEqualMem(e + 42, "000000", 6); /* rdev */
|
||||
assertEqualMem(e + 48, "00000000000", 11); /* mtime */
|
||||
assertEqualMem(e + 59, "000013", 6); /* Name size */
|
||||
assertEqualMem(e + 65, "00000000000", 11); /* File size */
|
||||
assertEqualMem(e + 76, "TRAILER!!!\0", 11); /* Name */
|
||||
|
||||
free(p);
|
||||
|
||||
umask(oldmask);
|
||||
}
|
68
usr.bin/cpio/test/test_option_d.c
Normal file
68
usr.bin/cpio/test/test_option_d.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*-
|
||||
* 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_option_d)
|
||||
{
|
||||
struct stat st;
|
||||
int r, fd;
|
||||
|
||||
/*
|
||||
* Create a file in a directory.
|
||||
*/
|
||||
assertEqualInt(0, mkdir("dir", 0755));
|
||||
fd = open("dir/file", O_CREAT | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
close(fd);
|
||||
|
||||
/* Create an archive. */
|
||||
r = systemf("echo dir/file | %s -o > archive.cpio 2>archive.err", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertFileContents("1 block\n", 8, "archive.err");
|
||||
assertEqualInt(0, stat("archive.cpio", &st));
|
||||
assertEqualInt(512, st.st_size);
|
||||
|
||||
/* Dearchive without -d, this should fail. */
|
||||
assertEqualInt(0, mkdir("without-d", 0755));
|
||||
assertEqualInt(0, chdir("without-d"));
|
||||
r = systemf("%s -i < ../archive.cpio >out 2>err", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertEmptyFile("out");
|
||||
/* And the file should not be restored. */
|
||||
assert(0 != stat("dir/file", &st));
|
||||
|
||||
/* Dearchive with -d, this should succeed. */
|
||||
assertEqualInt(0, chdir(".."));
|
||||
assertEqualInt(0, mkdir("with-d", 0755));
|
||||
assertEqualInt(0, chdir("with-d"));
|
||||
r = systemf("%s -id < ../archive.cpio >out 2>err", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertEmptyFile("out");
|
||||
assertFileContents("1 block\n", 8, "err");
|
||||
/* And the file should be restored. */
|
||||
assertEqualInt(0, stat("dir/file", &st));
|
||||
}
|
66
usr.bin/cpio/test/test_option_ell.c
Normal file
66
usr.bin/cpio/test/test_option_ell.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*-
|
||||
* 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$");
|
||||
|
||||
/*
|
||||
* This is called "test_option_ell" instead of "test_option_l" to
|
||||
* avoid any conflicts with "test_option_L" on case-insensitive
|
||||
* filesystems.
|
||||
*/
|
||||
|
||||
DEFINE_TEST(test_option_ell)
|
||||
{
|
||||
struct stat st, st2;
|
||||
int fd;
|
||||
int r;
|
||||
|
||||
/* Create a file. */
|
||||
fd = open("f", O_CREAT | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
assertEqualInt(1, write(fd, "a", 1));
|
||||
close(fd);
|
||||
|
||||
/* Stat it. */
|
||||
assertEqualInt(0, stat("f", &st));
|
||||
|
||||
/* Copy the file to the "copy" dir. */
|
||||
r = systemf("echo f | %s -pd copy >copy.out 2>copy.err",
|
||||
testprog);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
/* Check that the copy is a true copy and not a link. */
|
||||
assertEqualInt(0, stat("copy/f", &st2));
|
||||
assert(st2.st_ino != st.st_ino);
|
||||
|
||||
/* Copy the file to the "link" dir with the -l option. */
|
||||
r = systemf("echo f | %s -pld link >link.out 2>link.err",
|
||||
testprog);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
/* Check that this is a link and not a copy. */
|
||||
assertEqualInt(0, stat("link/f", &st2));
|
||||
assert(st2.st_ino == st.st_ino);
|
||||
}
|
66
usr.bin/cpio/test/test_option_f.c
Normal file
66
usr.bin/cpio/test/test_option_f.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*-
|
||||
* 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$");
|
||||
|
||||
/*
|
||||
* Unpack the archive in a new dir.
|
||||
*/
|
||||
static void
|
||||
unpack(const char *dirname, const char *option)
|
||||
{
|
||||
int r;
|
||||
|
||||
assertEqualInt(0, mkdir(dirname, 0755));
|
||||
assertEqualInt(0, chdir(dirname));
|
||||
extract_reference_file("test_option_f.cpio");
|
||||
r = systemf("%s -i %s < test_option_f.cpio > copy-no-a.out 2>copy-no-a.err", testprog, option);
|
||||
assertEqualInt(0, r);
|
||||
assertEqualInt(0, chdir(".."));
|
||||
}
|
||||
|
||||
DEFINE_TEST(test_option_f)
|
||||
{
|
||||
/* Calibrate: No -f option, so everything should be extracted. */
|
||||
unpack("t0", "");
|
||||
assertEqualInt(0, access("t0/a123", F_OK));
|
||||
assertEqualInt(0, access("t0/a234", F_OK));
|
||||
assertEqualInt(0, access("t0/b123", F_OK));
|
||||
assertEqualInt(0, access("t0/b234", F_OK));
|
||||
|
||||
/* Don't extract 'a*' files. */
|
||||
unpack("t1", "-f 'a*'");
|
||||
assert(0 != access("t1/a123", F_OK));
|
||||
assert(0 != access("t1/a234", F_OK));
|
||||
assertEqualInt(0, access("t1/b123", F_OK));
|
||||
assertEqualInt(0, access("t1/b234", F_OK));
|
||||
|
||||
/* Don't extract 'b*' files. */
|
||||
unpack("t2", "-f 'b*'");
|
||||
assertEqualInt(0, access("t2/a123", F_OK));
|
||||
assertEqualInt(0, access("t2/a234", F_OK));
|
||||
assert(0 != access("t2/b123", F_OK));
|
||||
assert(0 != access("t2/b234", F_OK));
|
||||
}
|
16
usr.bin/cpio/test/test_option_f.cpio.uu
Normal file
16
usr.bin/cpio/test/test_option_f.cpio.uu
Normal file
@ -0,0 +1,16 @@
|
||||
$FreeBSD$
|
||||
begin 644 test_option_f.cpio
|
||||
M,#<P-S`W,#`P,3,Q-C(Q-38Q,3`P-C0T,#`Q-S4P,#`Q-S4P,#`P,#`Q,#`P
|
||||
M,#`P,3`W,S4Q,3(U,C8P,#`P,#4P,#`P,#`P,#`P,&$Q,C,`,#<P-S`W,#`P
|
||||
M,3,Q-C(Q-38S,3`P-C0T,#`Q-S4P,#`Q-S4P,#`P,#`Q,#`P,#`P,3`W,S4Q
|
||||
M,3(U-#`P,#`P,#4P,#`P,#`P,#`P,&$R,S0`,#<P-S`W,#`P,3,Q-C(Q-38R
|
||||
M,3`P-C0T,#`Q-S4P,#`Q-S4P,#`P,#`Q,#`P,#`P,3`W,S4Q,3(U,S0P,#`P
|
||||
M,#4P,#`P,#`P,#`P,&(Q,C,`,#<P-S`W,#`P,3,Q-C(Q-38T,3`P-C0T,#`Q
|
||||
M-S4P,#`Q-S4P,#`P,#`Q,#`P,#`P,3`W,S4Q,3(U-#,P,#`P,#4P,#`P,#`P
|
||||
M,#`P,&(R,S0`,#<P-S`W,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P
|
||||
M,#`P,#`Q,#`P,#`P,#`P,#`P,#`P,#`P,#`P,3,P,#`P,#`P,#`P,%1204E,
|
||||
M15(A(2$`````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
1````````````````````````
|
||||
`
|
||||
end
|
81
usr.bin/cpio/test/test_option_help.c
Normal file
81
usr.bin/cpio/test/test_option_help.c
Normal file
@ -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_option_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 >= 7);
|
||||
failure("First line of help output should contain string 'bsdcpio'");
|
||||
assert(in_first_line(p, "bsdcpio"));
|
||||
/*
|
||||
* 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");
|
||||
}
|
70
usr.bin/cpio/test/test_option_m.c
Normal file
70
usr.bin/cpio/test/test_option_m.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*-
|
||||
* 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_option_m)
|
||||
{
|
||||
struct stat st;
|
||||
int r;
|
||||
time_t now;
|
||||
|
||||
/*
|
||||
* The reference archive has one file with an mtime in 1970, 1
|
||||
* second after the start of the epoch.
|
||||
*/
|
||||
|
||||
/* Restored without -m, the result should have a current mtime. */
|
||||
assertEqualInt(0, mkdir("without-m", 0755));
|
||||
assertEqualInt(0, chdir("without-m"));
|
||||
extract_reference_file("test_option_m.cpio");
|
||||
r = systemf("%s -i < test_option_m.cpio >out 2>err", testprog);
|
||||
now = time(NULL);
|
||||
assertEqualInt(r, 0);
|
||||
assertEmptyFile("out");
|
||||
assertFileContents("1 block\n", 8, "err");
|
||||
assertEqualInt(0, stat("file", &st));
|
||||
/* Should have been created within the last few seconds. */
|
||||
assert(st.st_mtime <= now);
|
||||
assert(st.st_mtime > now - 5);
|
||||
|
||||
/* With -m, it should have an mtime in 1970. */
|
||||
assertEqualInt(0, chdir(".."));
|
||||
assertEqualInt(0, mkdir("with-m", 0755));
|
||||
assertEqualInt(0, chdir("with-m"));
|
||||
extract_reference_file("test_option_m.cpio");
|
||||
r = systemf("%s -im < test_option_m.cpio >out 2>err", testprog);
|
||||
now = time(NULL);
|
||||
assertEqualInt(r, 0);
|
||||
assertEmptyFile("out");
|
||||
assertFileContents("1 block\n", 8, "err");
|
||||
assertEqualInt(0, stat("file", &st));
|
||||
/*
|
||||
* mtime in reference archive is '1' == 1 second after
|
||||
* midnight Jan 1, 1970 UTC.
|
||||
*/
|
||||
assertEqualInt(1, st.st_mtime);
|
||||
}
|
16
usr.bin/cpio/test/test_option_m.cpio.uu
Normal file
16
usr.bin/cpio/test/test_option_m.cpio.uu
Normal file
@ -0,0 +1,16 @@
|
||||
$FreeBSD$
|
||||
begin 644 test_option_m.cpio
|
||||
M,#<P-S`W,#`P,3,Q-#4P,#8T,3`P-C0T,#`Q-S4P,#`Q-S4P,#`P,#`Q,#`P
|
||||
M,#`P,#`P,#`P,#`P,#$P,#`P,#4P,#`P,#`P,#`P,&9I;&4`,#<P-S`W,#`P
|
||||
M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`Q,#`P,#`P,#`P,#`P
|
||||
M,#`P,#`P,#`P,3,P,#`P,#`P,#`P,%1204E,15(A(2$`````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
1````````````````````````
|
||||
`
|
||||
end
|
47
usr.bin/cpio/test/test_option_t.c
Normal file
47
usr.bin/cpio/test/test_option_t.c
Normal file
@ -0,0 +1,47 @@
|
||||
/*-
|
||||
* 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_option_t)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* List reference archive, make sure the TOC is correct. */
|
||||
extract_reference_file("test_option_t.cpio");
|
||||
r = systemf("%s -it < test_option_t.cpio >t.out 2>t.err", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertFileContents("1 block\n", 8, "t.err");
|
||||
extract_reference_file("test_option_t.stdout");
|
||||
assertEqualFile("t.out", "test_option_t.stdout");
|
||||
|
||||
/* List reference archive verbosely, make sure the TOC is correct. */
|
||||
r = systemf("%s -itv < test_option_t.cpio >tv.out 2>tv.err", testprog);
|
||||
assertEqualInt(r, 0);
|
||||
assertFileContents("1 block\n", 8, "tv.err");
|
||||
extract_reference_file("test_option_tv.stdout");
|
||||
assertEqualFile("tv.out", "test_option_tv.stdout");
|
||||
}
|
16
usr.bin/cpio/test/test_option_t.cpio.uu
Normal file
16
usr.bin/cpio/test/test_option_t.cpio.uu
Normal file
@ -0,0 +1,16 @@
|
||||
$FreeBSD$
|
||||
begin 644 test_option_t.cpio
|
||||
M,#<P-S`W,#`P,3,Q-#4P,#8T,3`P-C0T,#`Q-S4P,#`Q-S4P,#`P,#`Q,#`P
|
||||
M,#`P,#`P,#`P,#`P,#$P,#`P,#4P,#`P,#`P,#`P,&9I;&4`,#<P-S`W,#`P
|
||||
M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`Q,#`P,#`P,#`P,#`P
|
||||
M,#`P,#`P,#`P,3,P,#`P,#`P,#`P,%1204E,15(A(2$`````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
M````````````````````````````````````````````````````````````
|
||||
1````````````````````````
|
||||
`
|
||||
end
|
5
usr.bin/cpio/test/test_option_t.stdout.uu
Normal file
5
usr.bin/cpio/test/test_option_t.stdout.uu
Normal file
@ -0,0 +1,5 @@
|
||||
$FreeBSD$
|
||||
begin 644 test_option_t.stdout
|
||||
%9FEL90H`
|
||||
`
|
||||
end
|
5
usr.bin/cpio/test/test_option_tv.stdout.uu
Normal file
5
usr.bin/cpio/test/test_option_tv.stdout.uu
Normal file
@ -0,0 +1,5 @@
|
||||
$FreeBSD$
|
||||
begin 644 test_option_tv.stdout
|
||||
G+7)W+7(M+7(M+2`@(#$@("`H;G5L;"D@("AN=6QL*2`P(&9I;&4*
|
||||
`
|
||||
end
|
84
usr.bin/cpio/test/test_option_u.c
Normal file
84
usr.bin/cpio/test/test_option_u.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*-
|
||||
* 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"
|
||||
#include <utime.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
DEFINE_TEST(test_option_u)
|
||||
{
|
||||
struct utimbuf times;
|
||||
char *p;
|
||||
size_t s;
|
||||
int fd;
|
||||
int r;
|
||||
|
||||
/* Create a file. */
|
||||
fd = open("f", O_CREAT | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
assertEqualInt(1, write(fd, "a", 1));
|
||||
close(fd);
|
||||
|
||||
/* Copy the file to the "copy" dir. */
|
||||
r = systemf("echo f | %s -pd copy >copy.out 2>copy.err",
|
||||
testprog);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
/* Check that the file contains only a single "a" */
|
||||
p = slurpfile(&s, "copy/f");
|
||||
assertEqualInt(s, 1);
|
||||
assertEqualMem(p, "a", 1);
|
||||
|
||||
/* Recreate the file with a single "b" */
|
||||
fd = open("f", O_CREAT | O_TRUNC | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
assertEqualInt(1, write(fd, "b", 1));
|
||||
close(fd);
|
||||
|
||||
/* Set the mtime to the distant past. */
|
||||
memset(×, 0, sizeof(times));
|
||||
times.actime = 1;
|
||||
times.modtime = 3;
|
||||
assertEqualInt(0, utime("f", ×));
|
||||
|
||||
/* Copy the file to the "copy" dir. */
|
||||
r = systemf("echo f | %s -pd copy >copy.out 2>copy.err",
|
||||
testprog);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
/* Verify that the file hasn't changed (it wasn't overwritten) */
|
||||
p = slurpfile(&s, "copy/f");
|
||||
assertEqualInt(s, 1);
|
||||
assertEqualMem(p, "a", 1);
|
||||
|
||||
/* Copy the file to the "copy" dir with -u (force) */
|
||||
r = systemf("echo f | %s -pud copy >copy.out 2>copy.err",
|
||||
testprog);
|
||||
assertEqualInt(r, 0);
|
||||
|
||||
/* Verify that the file has changed (it was overwritten) */
|
||||
p = slurpfile(&s, "copy/f");
|
||||
assertEqualInt(s, 1);
|
||||
assertEqualMem(p, "b", 1);
|
||||
}
|
105
usr.bin/cpio/test/test_option_version.c
Normal file
105
usr.bin/cpio/test/test_option_version.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static void
|
||||
verify(const char *p, size_t s)
|
||||
{
|
||||
const char *q = p;
|
||||
|
||||
/* Version message should start with name of program, then space. */
|
||||
failure("version message too short:", p);
|
||||
if (!assert(s > 6))
|
||||
return;
|
||||
failure("Version message should begin with 'bsdcpio': %s", p);
|
||||
if (!assertEqualMem(q, "bsdcpio ", 8))
|
||||
/* If we're not testing bsdcpio, don't keep going. */
|
||||
return;
|
||||
q += 8; s -= 8;
|
||||
/* Version number is a series of digits and periods. */
|
||||
while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {
|
||||
++q;
|
||||
--s;
|
||||
}
|
||||
/* Version number terminated by space. */
|
||||
failure("Version: %s", p);
|
||||
assert(s > 1);
|
||||
/* Skip a single trailing a,b,c, or d. */
|
||||
if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
|
||||
++q;
|
||||
failure("Version: %s", p);
|
||||
assert(*q == ' ');
|
||||
++q; --s;
|
||||
/* Separator. */
|
||||
failure("Version: %s", p);
|
||||
assertEqualMem(q, "-- ", 3);
|
||||
q += 3; s -= 3;
|
||||
/* libarchive name and version number */
|
||||
assert(s > 11);
|
||||
failure("Version: %s", p);
|
||||
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;
|
||||
}
|
||||
/* Skip a single trailing a,b,c, or d. */
|
||||
if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
|
||||
++q;
|
||||
/* All terminated by a newline. */
|
||||
assert(s >= 1);
|
||||
failure("Version: %s", p);
|
||||
assertEqualMem(q, "\n", 1);
|
||||
}
|
||||
|
||||
|
||||
DEFINE_TEST(test_option_version)
|
||||
{
|
||||
int r;
|
||||
char *p;
|
||||
size_t s;
|
||||
|
||||
r = systemf("%s --version >version.stdout 2>version.stderr", testprog);
|
||||
if (r != 0)
|
||||
r = systemf("%s -W version >version.stdout 2>version.stderr",
|
||||
testprog);
|
||||
failure("Unable to run either %s --version or %s -W version",
|
||||
testprog, testprog);
|
||||
if (!assert(r == 0))
|
||||
return;
|
||||
|
||||
/* --version should generate nothing to stderr. */
|
||||
assertEmptyFile("version.stderr");
|
||||
/* Verify format of version message. */
|
||||
p = slurpfile(&s, "version.stdout");
|
||||
verify(p, s);
|
||||
free(p);
|
||||
}
|
52
usr.bin/cpio/test/test_option_y.c
Normal file
52
usr.bin/cpio/test/test_option_y.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*-
|
||||
* 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_option_y)
|
||||
{
|
||||
char *p;
|
||||
int fd;
|
||||
int r;
|
||||
size_t s;
|
||||
|
||||
/* Create a file. */
|
||||
fd = open("f", O_CREAT | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
assertEqualInt(1, write(fd, "a", 1));
|
||||
close(fd);
|
||||
|
||||
/* Archive it with bzip2 compression. */
|
||||
r = systemf("echo f | %s -oy >archive.out 2>archive.err",
|
||||
testprog);
|
||||
assertFileContents("1 block\n", 8, "archive.err");
|
||||
failure("-y (bzip) option seems to be broken");
|
||||
if (assertEqualInt(r, 0)) {
|
||||
/* Check that the archive file has a bzip2 signature. */
|
||||
p = slurpfile(&s, "archive.out");
|
||||
assert(s > 2);
|
||||
assertEqualMem(p, "BZh9", 4);
|
||||
}
|
||||
}
|
52
usr.bin/cpio/test/test_option_z.c
Normal file
52
usr.bin/cpio/test/test_option_z.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*-
|
||||
* 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_option_z)
|
||||
{
|
||||
char *p;
|
||||
int fd;
|
||||
int r;
|
||||
size_t s;
|
||||
|
||||
/* Create a file. */
|
||||
fd = open("f", O_CREAT | O_WRONLY, 0644);
|
||||
assert(fd >= 0);
|
||||
assertEqualInt(1, write(fd, "a", 1));
|
||||
close(fd);
|
||||
|
||||
/* Archive it with gzip compression. */
|
||||
r = systemf("echo f | %s -oz >archive.out 2>archive.err",
|
||||
testprog);
|
||||
failure("-z option seems to be broken");
|
||||
assertEqualInt(r, 0);
|
||||
if (r == 0) {
|
||||
/* Check that the archive file has a gzip signature. */
|
||||
p = slurpfile(&s, "archive.out");
|
||||
assert(s > 2);
|
||||
assertEqualMem(p, "\x1f\x8b\x08\x00", 4);
|
||||
}
|
||||
}
|
68
usr.bin/cpio/test/test_owner_parse.c
Normal file
68
usr.bin/cpio/test/test_owner_parse.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*-
|
||||
* 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$");
|
||||
|
||||
#include "../cpio.h"
|
||||
|
||||
DEFINE_TEST(test_owner_parse)
|
||||
{
|
||||
int uid, gid;
|
||||
|
||||
cpio_progname = "Ignore this message";
|
||||
|
||||
assertEqualInt(0, owner_parse("root", &uid, &gid));
|
||||
assertEqualInt(0, uid);
|
||||
assertEqualInt(-1, gid);
|
||||
|
||||
|
||||
assertEqualInt(0, owner_parse("root:", &uid, &gid));
|
||||
assertEqualInt(0, uid);
|
||||
assertEqualInt(0, gid);
|
||||
|
||||
assertEqualInt(0, owner_parse("root.", &uid, &gid));
|
||||
assertEqualInt(0, uid);
|
||||
assertEqualInt(0, gid);
|
||||
|
||||
/*
|
||||
* TODO: Lookup current user/group name, build strings and
|
||||
* use those to verify username/groupname lookups for ordinary
|
||||
* users.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: Rework owner_parse to either return a char * pointing
|
||||
* to an error message or accept a function pointer to an
|
||||
* error-reporting routine so that the following tests don't
|
||||
* generate any output.
|
||||
*
|
||||
* Alternatively, redirect stderr temporarily to suppress the output.
|
||||
*/
|
||||
|
||||
assertEqualInt(1, owner_parse(":nonexistentgroup", &uid, &gid));
|
||||
assertEqualInt(1, owner_parse("root:nonexistentgroup", &uid, &gid));
|
||||
assertEqualInt(1,
|
||||
owner_parse("nonexistentuser:nonexistentgroup", &uid, &gid));
|
||||
}
|
165
usr.bin/cpio/test/test_pathmatch.c
Normal file
165
usr.bin/cpio/test/test_pathmatch.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*-
|
||||
* 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$");
|
||||
|
||||
#include "../pathmatch.h"
|
||||
|
||||
/*
|
||||
* Verify that the pattern matcher implements the wildcard logic specified
|
||||
* in SUSv2 for the cpio command. This is essentially the
|
||||
* shell glob syntax:
|
||||
* * - matches any sequence of chars, including '/'
|
||||
* ? - matches any single char, including '/'
|
||||
* [...] - matches any of a set of chars, '-' specifies a range,
|
||||
* initial '!' is undefined
|
||||
*
|
||||
* The specification in SUSv2 is a bit incomplete, I assume the following:
|
||||
* Trailing '-' in [...] is not special.
|
||||
*/
|
||||
|
||||
DEFINE_TEST(test_pathmatch)
|
||||
{
|
||||
assertEqualInt(1, pathmatch("*","", 0));
|
||||
assertEqualInt(1, pathmatch("*","a", 0));
|
||||
assertEqualInt(1, pathmatch("*","abcd", 0));
|
||||
/* SUSv2: * matches / */
|
||||
assertEqualInt(1, pathmatch("*","abcd/efgh/ijkl", 0));
|
||||
assertEqualInt(1, pathmatch("abcd*efgh/ijkl","abcd/efgh/ijkl", 0));
|
||||
assertEqualInt(1, pathmatch("abcd***efgh/ijkl","abcd/efgh/ijkl", 0));
|
||||
assertEqualInt(1, pathmatch("abcd***/efgh/ijkl","abcd/efgh/ijkl", 0));
|
||||
assertEqualInt(0, pathmatch("?", "", 0));
|
||||
assertEqualInt(0, pathmatch("?", "\0", 0));
|
||||
assertEqualInt(1, pathmatch("?", "a", 0));
|
||||
assertEqualInt(0, pathmatch("?", "ab", 0));
|
||||
assertEqualInt(1, pathmatch("?", ".", 0));
|
||||
assertEqualInt(1, pathmatch("?", "?", 0));
|
||||
assertEqualInt(1, pathmatch("a", "a", 0));
|
||||
assertEqualInt(0, pathmatch("a", "ab", 0));
|
||||
assertEqualInt(0, pathmatch("a", "ab", 0));
|
||||
assertEqualInt(1, pathmatch("a?c", "abc", 0));
|
||||
/* SUSv2: ? matches / */
|
||||
assertEqualInt(1, pathmatch("a?c", "a/c", 0));
|
||||
assertEqualInt(1, pathmatch("a?*c*", "a/c", 0));
|
||||
assertEqualInt(1, pathmatch("*a*", "a/c", 0));
|
||||
assertEqualInt(1, pathmatch("*a*", "/a/c", 0));
|
||||
assertEqualInt(1, pathmatch("*a*", "defaaaaaaa", 0));
|
||||
assertEqualInt(0, pathmatch("a*", "defghi", 0));
|
||||
assertEqualInt(0, pathmatch("*a*", "defghi", 0));
|
||||
assertEqualInt(1, pathmatch("abc[def", "abc[def", 0));
|
||||
assertEqualInt(0, pathmatch("abc[def]", "abc[def", 0));
|
||||
assertEqualInt(0, pathmatch("abc[def", "abcd", 0));
|
||||
assertEqualInt(1, pathmatch("abc[def]", "abcd", 0));
|
||||
assertEqualInt(1, pathmatch("abc[def]", "abce", 0));
|
||||
assertEqualInt(1, pathmatch("abc[def]", "abcf", 0));
|
||||
assertEqualInt(0, pathmatch("abc[def]", "abcg", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d*f]", "abcd", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d*f]", "abc*", 0));
|
||||
assertEqualInt(0, pathmatch("abc[d*f]", "abcdefghi", 0));
|
||||
assertEqualInt(0, pathmatch("abc[d*", "abcdefghi", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d*", "abc[defghi", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-f]", "abcd", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-f]", "abce", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-f]", "abcf", 0));
|
||||
assertEqualInt(0, pathmatch("abc[d-f]", "abcg", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-fh-k]", "abcd", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-fh-k]", "abce", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-fh-k]", "abcf", 0));
|
||||
assertEqualInt(0, pathmatch("abc[d-fh-k]", "abcg", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-fh-k]", "abch", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-fh-k]", "abci", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-fh-k]", "abcj", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-fh-k]", "abck", 0));
|
||||
assertEqualInt(0, pathmatch("abc[d-fh-k]", "abcl", 0));
|
||||
assertEqualInt(0, pathmatch("abc[d-fh-k]", "abc-", 0));
|
||||
|
||||
/* I assume: Trailing '-' is non-special. */
|
||||
assertEqualInt(0, pathmatch("abc[d-fh-]", "abcl", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-fh-]", "abch", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-fh-]", "abc-", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-fh-]", "abc-", 0));
|
||||
|
||||
/* ']' can be backslash-quoted within a character class. */
|
||||
assertEqualInt(1, pathmatch("abc[\\]]", "abc]", 0));
|
||||
assertEqualInt(1, pathmatch("abc[\\]d]", "abc]", 0));
|
||||
assertEqualInt(1, pathmatch("abc[\\]d]", "abcd", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d\\]]", "abc]", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d\\]]", "abcd", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d]e]", "abcde]", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d\\]e]", "abc]", 0));
|
||||
assertEqualInt(0, pathmatch("abc[d\\]e]", "abcd]e", 0));
|
||||
assertEqualInt(0, pathmatch("abc[d]e]", "abc]", 0));
|
||||
|
||||
/* backslash-quoted chars can appear as either end of a range. */
|
||||
assertEqualInt(1, pathmatch("abc[\\d-f]gh", "abcegh", 0));
|
||||
assertEqualInt(0, pathmatch("abc[\\d-f]gh", "abcggh", 0));
|
||||
assertEqualInt(0, pathmatch("abc[\\d-f]gh", "abc\\gh", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d-\\f]gh", "abcegh", 0));
|
||||
assertEqualInt(1, pathmatch("abc[\\d-\\f]gh", "abcegh", 0));
|
||||
assertEqualInt(1, pathmatch("abc[\\d-\\f]gh", "abcegh", 0));
|
||||
/* backslash-quoted '-' isn't special. */
|
||||
assertEqualInt(0, pathmatch("abc[d\\-f]gh", "abcegh", 0));
|
||||
assertEqualInt(1, pathmatch("abc[d\\-f]gh", "abc-gh", 0));
|
||||
|
||||
/* Leading '!' negates a character class. */
|
||||
assertEqualInt(0, pathmatch("abc[!d]", "abcd", 0));
|
||||
assertEqualInt(1, pathmatch("abc[!d]", "abce", 0));
|
||||
assertEqualInt(1, pathmatch("abc[!d]", "abcc", 0));
|
||||
assertEqualInt(0, pathmatch("abc[!d-z]", "abcq", 0));
|
||||
assertEqualInt(1, pathmatch("abc[!d-gi-z]", "abch", 0));
|
||||
assertEqualInt(1, pathmatch("abc[!fgijkl]", "abch", 0));
|
||||
assertEqualInt(0, pathmatch("abc[!fghijkl]", "abch", 0));
|
||||
|
||||
/* Backslash quotes next character. */
|
||||
assertEqualInt(0, pathmatch("abc\\[def]", "abc\\d", 0));
|
||||
assertEqualInt(1, pathmatch("abc\\[def]", "abc[def]", 0));
|
||||
assertEqualInt(0, pathmatch("abc\\\\[def]", "abc[def]", 0));
|
||||
assertEqualInt(0, pathmatch("abc\\\\[def]", "abc\\[def]", 0));
|
||||
assertEqualInt(1, pathmatch("abc\\\\[def]", "abc\\d", 0));
|
||||
|
||||
/*
|
||||
* Because '.' and '/' have special meanings, we can
|
||||
* identify many equivalent paths even if they're expressed
|
||||
* differently.
|
||||
*/
|
||||
assertEqualInt(1, pathmatch("./abc/./def/", "abc/def/", 0));
|
||||
assertEqualInt(1, pathmatch("abc/def", "./././abc/./def", 0));
|
||||
assertEqualInt(1, pathmatch("abc/def/././//", "./././abc/./def/", 0));
|
||||
assertEqualInt(1, pathmatch(".////abc/.//def", "./././abc/./def", 0));
|
||||
assertEqualInt(1, pathmatch("./abc?def/", "abc/def/", 0));
|
||||
failure("\"?./\" is not the same as \"/./\"");
|
||||
assertEqualInt(0, pathmatch("./abc?./def/", "abc/def/", 0));
|
||||
failure("Trailing '/' should match no trailing '/'");
|
||||
assertEqualInt(1, pathmatch("./abc/./def/", "abc/def", 0));
|
||||
failure("Trailing '/./' is still the same directory.");
|
||||
assertEqualInt(1, pathmatch("./abc/./def/./", "abc/def", 0));
|
||||
failure("Trailing '/.' is still the same directory.");
|
||||
assertEqualInt(1, pathmatch("./abc/./def/.", "abc/def", 0));
|
||||
assertEqualInt(1, pathmatch("./abc/./def", "abc/def/", 0));
|
||||
failure("Trailing '/./' is still the same directory.");
|
||||
assertEqualInt(1, pathmatch("./abc/./def", "abc/def/./", 0));
|
||||
failure("Trailing '/.' is still the same directory.");
|
||||
assertEqualInt(1, pathmatch("./abc*/./def", "abc/def/.", 0));
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user