From cb3baab306e5951dc3a176fd9061f596a05b4729 Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sun, 15 Nov 2009 18:32:03 +0100 Subject: Rebase libarchive to 2.7.1 --- libarchive/libarchive-2.7.1/cpio/CMakeLists.txt | 46 + libarchive/libarchive-2.7.1/cpio/bsdcpio.1 | 376 ++++++ libarchive/libarchive-2.7.1/cpio/cmdline.c | 342 +++++ libarchive/libarchive-2.7.1/cpio/config_freebsd.h | 107 ++ libarchive/libarchive-2.7.1/cpio/cpio.c | 1356 ++++++++++++++++++++ libarchive/libarchive-2.7.1/cpio/cpio.h | 119 ++ libarchive/libarchive-2.7.1/cpio/cpio_cygwin.c | 139 ++ libarchive/libarchive-2.7.1/cpio/cpio_cygwin.h | 41 + libarchive/libarchive-2.7.1/cpio/cpio_platform.h | 98 ++ libarchive/libarchive-2.7.1/cpio/cpio_windows.c | 994 ++++++++++++++ libarchive/libarchive-2.7.1/cpio/cpio_windows.h | 61 + libarchive/libarchive-2.7.1/cpio/err.c | 73 ++ libarchive/libarchive-2.7.1/cpio/matching.c | 259 ++++ libarchive/libarchive-2.7.1/cpio/matching.h | 40 + libarchive/libarchive-2.7.1/cpio/pathmatch.c | 249 ++++ libarchive/libarchive-2.7.1/cpio/pathmatch.h | 42 + .../libarchive-2.7.1/cpio/test/CMakeLists.txt | 66 + libarchive/libarchive-2.7.1/cpio/test/list.h | 25 + libarchive/libarchive-2.7.1/cpio/test/main.c | 1191 +++++++++++++++++ libarchive/libarchive-2.7.1/cpio/test/test.h | 171 +++ libarchive/libarchive-2.7.1/cpio/test/test_0.c | 67 + libarchive/libarchive-2.7.1/cpio/test/test_basic.c | 260 ++++ .../libarchive-2.7.1/cpio/test/test_cmdline.c | 107 ++ .../libarchive-2.7.1/cpio/test/test_format_newc.c | 289 +++++ .../libarchive-2.7.1/cpio/test/test_gcpio_compat.c | 144 +++ .../cpio/test/test_gcpio_compat_ref.bin.uu | 16 + .../cpio/test/test_gcpio_compat_ref.crc.uu | 27 + .../cpio/test/test_gcpio_compat_ref.newc.uu | 27 + .../cpio/test/test_gcpio_compat_ref.ustar.uu | 84 ++ .../cpio/test/test_option_B_upper.c | 54 + .../cpio/test/test_option_C_upper.c | 68 + .../cpio/test/test_option_L_upper.c | 106 ++ .../cpio/test/test_option_Z_upper.c | 59 + .../libarchive-2.7.1/cpio/test/test_option_a.c | 163 +++ .../libarchive-2.7.1/cpio/test/test_option_c.c | 227 ++++ .../libarchive-2.7.1/cpio/test/test_option_d.c | 68 + .../libarchive-2.7.1/cpio/test/test_option_f.c | 76 ++ .../cpio/test/test_option_f.cpio.uu | 16 + .../libarchive-2.7.1/cpio/test/test_option_help.c | 81 ++ .../libarchive-2.7.1/cpio/test/test_option_l.c | 60 + .../libarchive-2.7.1/cpio/test/test_option_m.c | 70 + .../cpio/test/test_option_m.cpio.uu | 16 + .../libarchive-2.7.1/cpio/test/test_option_t.c | 85 ++ .../cpio/test/test_option_t.cpio.uu | 16 + .../cpio/test/test_option_t.stdout.uu | 5 + .../cpio/test/test_option_tnv.stdout.uu | 5 + .../cpio/test/test_option_tv.stdout.uu | 6 + .../libarchive-2.7.1/cpio/test/test_option_u.c | 88 ++ .../cpio/test/test_option_version.c | 109 ++ .../libarchive-2.7.1/cpio/test/test_option_y.c | 59 + .../libarchive-2.7.1/cpio/test/test_option_z.c | 59 + .../libarchive-2.7.1/cpio/test/test_owner_parse.c | 112 ++ .../cpio/test/test_passthrough_dotdot.c | 93 ++ .../cpio/test/test_passthrough_reverse.c | 112 ++ .../libarchive-2.7.1/cpio/test/test_pathmatch.c | 243 ++++ 55 files changed, 8872 insertions(+) create mode 100644 libarchive/libarchive-2.7.1/cpio/CMakeLists.txt create mode 100644 libarchive/libarchive-2.7.1/cpio/bsdcpio.1 create mode 100644 libarchive/libarchive-2.7.1/cpio/cmdline.c create mode 100644 libarchive/libarchive-2.7.1/cpio/config_freebsd.h create mode 100644 libarchive/libarchive-2.7.1/cpio/cpio.c create mode 100644 libarchive/libarchive-2.7.1/cpio/cpio.h create mode 100644 libarchive/libarchive-2.7.1/cpio/cpio_cygwin.c create mode 100644 libarchive/libarchive-2.7.1/cpio/cpio_cygwin.h create mode 100644 libarchive/libarchive-2.7.1/cpio/cpio_platform.h create mode 100644 libarchive/libarchive-2.7.1/cpio/cpio_windows.c create mode 100644 libarchive/libarchive-2.7.1/cpio/cpio_windows.h create mode 100644 libarchive/libarchive-2.7.1/cpio/err.c create mode 100644 libarchive/libarchive-2.7.1/cpio/matching.c create mode 100644 libarchive/libarchive-2.7.1/cpio/matching.h create mode 100644 libarchive/libarchive-2.7.1/cpio/pathmatch.c create mode 100644 libarchive/libarchive-2.7.1/cpio/pathmatch.h create mode 100644 libarchive/libarchive-2.7.1/cpio/test/CMakeLists.txt create mode 100644 libarchive/libarchive-2.7.1/cpio/test/list.h create mode 100644 libarchive/libarchive-2.7.1/cpio/test/main.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test.h create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_0.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_basic.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_cmdline.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_format_newc.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat_ref.bin.uu create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat_ref.crc.uu create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat_ref.newc.uu create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat_ref.ustar.uu create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_B_upper.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_C_upper.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_L_upper.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_Z_upper.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_a.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_c.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_d.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_f.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_f.cpio.uu create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_help.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_l.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_m.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_m.cpio.uu create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_t.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_t.cpio.uu create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_t.stdout.uu create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_tnv.stdout.uu create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_tv.stdout.uu create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_u.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_version.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_y.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_option_z.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_owner_parse.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_passthrough_dotdot.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_passthrough_reverse.c create mode 100644 libarchive/libarchive-2.7.1/cpio/test/test_pathmatch.c (limited to 'libarchive/libarchive-2.7.1/cpio') diff --git a/libarchive/libarchive-2.7.1/cpio/CMakeLists.txt b/libarchive/libarchive-2.7.1/cpio/CMakeLists.txt new file mode 100644 index 0000000..4744ba1 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/CMakeLists.txt @@ -0,0 +1,46 @@ +############################################ +# +# How to build bsdcpio +# +############################################ +IF(ENABLE_CPIO) + SET(bsdcpio_SOURCES + cmdline.c + cpio.c + cpio.h + cpio_platform.h + err.c + matching.c + matching.h + pathmatch.c + pathmatch.h + ) + IF(WIN32 AND NOT CYGWIN) + LIST(APPEND bsdcpio_SOURCES cpio_windows.c) + LIST(APPEND bsdcpio_SOURCES cpio_windows.h) + ENDIF(WIN32 AND NOT CYGWIN) + + SET(bsdcpio_MANS bsdcpio.1) + + # + # Register target + # + ADD_EXECUTABLE(bsdcpio ${bsdcpio_SOURCES}) + IF(ENABLE_CPIO_SHARED) + TARGET_LINK_LIBRARIES(bsdcpio archive ${ADDITIONAL_LIBS}) + ELSE(ENABLE_CPIO_SHARED) + TARGET_LINK_LIBRARIES(bsdcpio archive_static ${ADDITIONAL_LIBS}) + ENDIF(ENABLE_CPIO_SHARED) + IF(WIN32 AND NOT CYGWIN) + SET_TARGET_PROPERTIES(bsdcpio PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + SET(BSDCPIO ${CMAKE_BINARY_DIR}/debug/bsdcpio.exe) + ELSE(WIN32 AND NOT CYGWIN) + SET(BSDCPIO ${CMAKE_CURRENT_BINARY_DIR}/bsdcpio) + ENDIF(WIN32 AND NOT CYGWIN) + # + INSTALL(TARGETS bsdcpio RUNTIME DESTINATION bin) + INSTALL_MAN(${bsdcpio_MANS}) +ENDIF(ENABLE_CPIO) + +add_subdirectory(test) diff --git a/libarchive/libarchive-2.7.1/cpio/bsdcpio.1 b/libarchive/libarchive-2.7.1/cpio/bsdcpio.1 new file mode 100644 index 0000000..81b3462 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/bsdcpio.1 @@ -0,0 +1,376 @@ +.\" 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 n +(i mode, only with +.Fl t ) +Display numeric uid and gid. +By default, +.Nm +displays the user and group names when they are provided in the +archive, or looks up the user and group names in the system +password database. +.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. diff --git a/libarchive/libarchive-2.7.1/cpio/cmdline.c b/libarchive/libarchive-2.7.1/cpio/cmdline.c new file mode 100644 index 0000000..edcd8ba --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/cmdline.c @@ -0,0 +1,342 @@ +/*- + * 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: src/usr.bin/cpio/cmdline.c,v 1.5 2008/12/06 07:30:40 kientzle Exp $"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "cpio.h" + +/* + * Short options for cpio. Please keep this sorted. + */ +static const char *short_options = "0AaBC:F:O:cdE:f:H:hI:ijLlmnopR:rtuvW:yZz"; + +/* + * Long options for cpio. Please keep this sorted. + */ +static const struct option { + const char *name; + int required; /* 1 if this option requires an argument */ + int equivalent; /* Equivalent short option. */ +} cpio_longopts[] = { + { "create", 0, 'o' }, + { "extract", 0, 'i' }, + { "file", 1, 'F' }, + { "format", 1, 'H' }, + { "help", 0, 'h' }, + { "insecure", 0, OPTION_INSECURE }, + { "link", 0, 'l' }, + { "list", 0, 't' }, + { "make-directories", 0, 'd' }, + { "no-preserve-owner", 0, OPTION_NO_PRESERVE_OWNER }, + { "null", 0, '0' }, + { "numeric-uid-gid", 0, 'n' }, + { "owner", 1, 'R' }, + { "pass-through", 0, 'p' }, + { "preserve-modification-time", 0, 'm' }, + { "quiet", 0, OPTION_QUIET }, + { "unconditional", 0, 'u' }, + { "verbose", 0, 'v' }, + { "version", 0, OPTION_VERSION }, + { NULL, 0, 0 } +}; + +/* + * I used to try to select platform-provided getopt() or + * getopt_long(), but that caused a lot of headaches. In particular, + * I couldn't consistently use long options in the test harness + * because not all platforms have getopt_long(). That in turn led to + * overuse of the -W hack in the test harness, which made it rough to + * run the test harness against GNU cpio. (I periodically run the + * test harness here against GNU cpio as a sanity-check. Yes, + * I've found a couple of bugs in GNU cpio that way.) + */ +int +cpio_getopt(struct cpio *cpio) +{ + enum { state_start = 0, state_next_word, state_short, state_long }; + static int state = state_start; + static char *opt_word; + + const struct option *popt, *match = NULL, *match2 = NULL; + const char *p, *long_prefix = "--"; + size_t optlength; + int opt = '?'; + int required = 0; + + cpio->optarg = NULL; + + /* First time through, initialize everything. */ + if (state == state_start) { + /* Skip program name. */ + ++cpio->argv; + --cpio->argc; + state = state_next_word; + } + + /* + * We're ready to look at the next word in argv. + */ + if (state == state_next_word) { + /* No more arguments, so no more options. */ + if (cpio->argv[0] == NULL) + return (-1); + /* Doesn't start with '-', so no more options. */ + if (cpio->argv[0][0] != '-') + return (-1); + /* "--" marks end of options; consume it and return. */ + if (strcmp(cpio->argv[0], "--") == 0) { + ++cpio->argv; + --cpio->argc; + return (-1); + } + /* Get next word for parsing. */ + opt_word = *cpio->argv++; + --cpio->argc; + if (opt_word[1] == '-') { + /* Set up long option parser. */ + state = state_long; + opt_word += 2; /* Skip leading '--' */ + } else { + /* Set up short option parser. */ + state = state_short; + ++opt_word; /* Skip leading '-' */ + } + } + + /* + * We're parsing a group of POSIX-style single-character options. + */ + if (state == state_short) { + /* Peel next option off of a group of short options. */ + opt = *opt_word++; + if (opt == '\0') { + /* End of this group; recurse to get next option. */ + state = state_next_word; + return cpio_getopt(cpio); + } + + /* Does this option take an argument? */ + p = strchr(short_options, opt); + if (p == NULL) + return ('?'); + if (p[1] == ':') + required = 1; + + /* If it takes an argument, parse that. */ + if (required) { + /* If arg is run-in, opt_word already points to it. */ + if (opt_word[0] == '\0') { + /* Otherwise, pick up the next word. */ + opt_word = *cpio->argv; + if (opt_word == NULL) { + cpio_warnc(0, + "Option -%c requires an argument", + opt); + return ('?'); + } + ++cpio->argv; + --cpio->argc; + } + if (opt == 'W') { + state = state_long; + long_prefix = "-W "; /* For clearer errors. */ + } else { + state = state_next_word; + cpio->optarg = opt_word; + } + } + } + + /* We're reading a long option, including -W long=arg convention. */ + if (state == state_long) { + /* After this long option, we'll be starting a new word. */ + state = state_next_word; + + /* Option name ends at '=' if there is one. */ + p = strchr(opt_word, '='); + if (p != NULL) { + optlength = (size_t)(p - opt_word); + cpio->optarg = (char *)(uintptr_t)(p + 1); + } else { + optlength = strlen(opt_word); + } + + /* Search the table for an unambiguous match. */ + for (popt = cpio_longopts; popt->name != NULL; popt++) { + /* Short-circuit if first chars don't match. */ + if (popt->name[0] != opt_word[0]) + continue; + /* If option is a prefix of name in table, record it.*/ + if (strncmp(opt_word, popt->name, optlength) == 0) { + match2 = match; /* Record up to two matches. */ + match = popt; + /* If it's an exact match, we're done. */ + if (strlen(popt->name) == optlength) { + match2 = NULL; /* Forget the others. */ + break; + } + } + } + + /* Fail if there wasn't a unique match. */ + if (match == NULL) { + cpio_warnc(0, + "Option %s%s is not supported", + long_prefix, opt_word); + return ('?'); + } + if (match2 != NULL) { + cpio_warnc(0, + "Ambiguous option %s%s (matches --%s and --%s)", + long_prefix, opt_word, match->name, match2->name); + return ('?'); + } + + /* We've found a unique match; does it need an argument? */ + if (match->required) { + /* Argument required: get next word if necessary. */ + if (cpio->optarg == NULL) { + cpio->optarg = *cpio->argv; + if (cpio->optarg == NULL) { + cpio_warnc(0, + "Option %s%s requires an argument", + long_prefix, match->name); + return ('?'); + } + ++cpio->argv; + --cpio->argc; + } + } else { + /* Argument forbidden: fail if there is one. */ + if (cpio->optarg != NULL) { + cpio_warnc(0, + "Option %s%s does not allow an argument", + long_prefix, match->name); + return ('?'); + } + } + return (match->equivalent); + } + + return (opt); +} + + +/* + * Parse the argument to the -R or --owner flag. + * + * The format is one of the following: + * - Override user but not group + * : - Override both, group is user's default group + * : - Override both + * : - 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); +} diff --git a/libarchive/libarchive-2.7.1/cpio/config_freebsd.h b/libarchive/libarchive-2.7.1/cpio/config_freebsd.h new file mode 100644 index 0000000..2add4af --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/config_freebsd.h @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/usr.bin/cpio/config_freebsd.h,v 1.3 2008/12/06 07:30:40 kientzle Exp $ + */ + +/* A default configuration for FreeBSD, used if there is no config.h. */ + +#include /* __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 +#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_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 + diff --git a/libarchive/libarchive-2.7.1/cpio/cpio.c b/libarchive/libarchive-2.7.1/cpio/cpio.c new file mode 100644 index 0000000..e5b40c9 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/cpio.c @@ -0,0 +1,1356 @@ +/*- + * 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: src/usr.bin/cpio/cpio.c,v 1.15 2008/12/06 07:30:40 kientzle Exp $"); + +#include +#include +#include + +#ifdef HAVE_SYS_MKDEV_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_STDARG_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif + +#include "cpio.h" +#include "matching.h" + +/* Fixed size of uname/gname caches. */ +#define name_cache_size 101 + +struct name_cache { + int probes; + int hits; + size_t size; + struct { + id_t id; + char *name; + } cache[name_cache_size]; +}; + +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 free_cache(struct name_cache *cache); +static void list_item_verbose(struct cpio *, struct archive_entry *); +static void long_help(void); +static const char *lookup_gname(struct cpio *, gid_t gid); +static int lookup_gname_helper(struct cpio *, + const char **name, id_t gid); +static const char *lookup_uname(struct cpio *, uid_t uid); +static int lookup_uname_helper(struct cpio *, + const char **name, id_t uid); +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 int 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); +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Make sure open() function will be used with a binary mode. */ + /* on cygwin, we need something similar, but instead link against */ + /* a special startup object, binmode.o */ + _set_fmode(_O_BINARY); +#endif + + /* Need cpio_progname before calling cpio_warnc. */ + if (*argv == NULL) + cpio_progname = "bsdcpio"; + else { +#if defined(_WIN32) && !defined(__CYGWIN__) + cpio_progname = strrchr(*argv, '\\'); +#else + cpio_progname = strrchr(*argv, '/'); +#endif + 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->line_separator = '\n'; + cpio->mode = '\0'; + cpio->verbose = 0; + cpio->compress = '\0'; + 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; + cpio->extract_flags |= ARCHIVE_EXTRACT_PERM; + cpio->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; + cpio->extract_flags |= ARCHIVE_EXTRACT_ACL; +#if defined(_WIN32) || defined(__CYGWIN__) + if (bsdcpio_is_privileged()) +#else + if (geteuid() == 0) +#endif + cpio->extract_flags |= ARCHIVE_EXTRACT_OWNER; + cpio->bytes_per_block = 512; + cpio->filename = NULL; + + while ((opt = cpio_getopt(cpio)) != -1) { + switch (opt) { + case '0': /* GNU convention: --null, -0 */ + cpio->line_separator = '\0'; + break; + 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(cpio->optarg); + if (cpio->bytes_per_block <= 0) + cpio_errc(1, 0, "Invalid blocksize %s", cpio->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, cpio->optarg); + break; + case 'F': /* NetBSD/OpenBSD/GNU cpio */ + cpio->filename = cpio->optarg; + break; + case 'f': /* POSIX 1997 */ + exclude(cpio, cpio->optarg); + break; + case 'H': /* GNU cpio (also --format) */ + cpio->format = cpio->optarg; + break; + case 'h': + long_help(); + break; + case 'I': /* NetBSD/OpenBSD */ + cpio->filename = cpio->optarg; + break; + case 'i': /* POSIX 1997 */ + if (cpio->mode != '\0') + cpio_errc(1, 0, + "Cannot use both -i and -%c", cpio->mode); + 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 'n': /* GNU cpio */ + cpio->option_numeric_uid_gid = 1; + break; + case OPTION_NO_PRESERVE_OWNER: /* GNU cpio */ + cpio->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; + break; + case 'O': /* GNU cpio */ + cpio->filename = cpio->optarg; + break; + case 'o': /* POSIX 1997 */ + if (cpio->mode != '\0') + cpio_errc(1, 0, + "Cannot use both -o and -%c", cpio->mode); + cpio->mode = opt; + break; + case 'p': /* POSIX 1997 */ + if (cpio->mode != '\0') + cpio_errc(1, 0, + "Cannot use both -p and -%c", cpio->mode); + cpio->mode = opt; + cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; + break; + case OPTION_QUIET: /* GNU cpio */ + cpio->quiet = 1; + break; + case 'R': /* GNU cpio, also --owner */ + if (owner_parse(cpio->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 */ +#if HAVE_LIBBZ2 + cpio->compress = opt; +#else + cpio_warnc(0, "bzip2 compression not supported by " + "this version of bsdcpio"); +#endif + break; + case 'Z': /* tar convention */ + cpio->compress = opt; + break; + case 'z': /* tar convention */ +#if HAVE_LIBZ + cpio->compress = opt; +#else + cpio_warnc(0, "gzip compression not supported by " + "this version of bsdcpio"); +#endif + break; + default: + usage(); + } + } + + /* + * Sanity-check args, error out on nonsensical combinations. + */ + /* -t implies -i if no mode was specified. */ + if (cpio->option_list && cpio->mode == '\0') + cpio->mode = 'i'; + /* -t requires -i */ + if (cpio->option_list && cpio->mode != 'i') + cpio_errc(1, 0, "Option -t requires -i", cpio->mode); + /* -n requires -it */ + if (cpio->option_numeric_uid_gid && !cpio->option_list) + cpio_errc(1, 0, "Option -n requires -it"); + /* Can only specify format when writing */ + if (cpio->format != NULL && cpio->mode != 'o') + cpio_errc(1, 0, "Option --format requires -o"); + /* -l requires -p */ + if (cpio->option_link && cpio->mode != 'p') + cpio_errc(1, 0, "Option -l requires -p"); + /* TODO: Flag other nonsensical combinations. */ + + switch (cpio->mode) { + case 'o': + /* TODO: Implement old binary format in libarchive, + use that here. */ + if (cpio->format == NULL) + cpio->format = "odc"; /* Default format */ + + 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"); + } + + free_cache(cpio->gname_cache); + free_cache(cpio->uname_cache); + 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); + fprintf(stderr, " Help: %s --help\n", p); + 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" +#ifdef HAVE_BZLIB_H + " -y Compress archive with bzip2\n" +#endif +#ifdef HAVE_ZLIB_H + " -z Compress archive with gzip\n" +#endif + " --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) +{ + unsigned long blocks; + struct archive_entry *entry, *spare; + struct line_reader *lr; + const char *p; + 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) { +#ifdef HAVE_BZLIB_H + case 'j': case 'y': + archive_write_set_compression_bzip2(cpio->archive); + break; +#endif +#ifdef HAVE_ZLIB_H + case 'z': + archive_write_set_compression_gzip(cpio->archive); + break; +#endif + 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)); + lr = process_lines_init("-", cpio->line_separator); + while ((p = process_lines_next(lr)) != NULL) + file_to_archive(cpio, p); + process_lines_free(lr); + + /* + * 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; +#if !defined(_WIN32) || defined(__CYGWIN__) + int lnklen; +#endif + int r; + + /* + * Create an archive_entry describing the source file. + * + * XXX TODO: rework to use archive_read_disk_entry_from_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 !defined(_WIN32) || defined(__CYGWIN__) + /* 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); + } +#endif + + /* + * 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); + + /* + * Option_link only makes sense in pass mode and for + * regular files. Also note: if a link operation fails + * because of cross-device restrictions, we'll fall back + * to copy mode for that entry. + * + * TODO: Test other cpio implementations to see if they + * hard-link anything other than regular files here. + */ + if (cpio->option_link + && archive_entry_filetype(entry) == AE_IFREG) + { + struct archive_entry *t; + /* Save the original entry in case we need it later. */ + t = archive_entry_clone(entry); + if (t == NULL) + cpio_errc(1, ENOMEM, "Can't create link"); + /* Note: link(2) doesn't create parent directories, + * so we use archive_write_header() instead as a + * convenience. */ + archive_entry_set_hardlink(t, srcpath); + /* This is a straight link that carries no data. */ + archive_entry_set_size(t, 0); + r = archive_write_header(cpio->archive, t); + archive_entry_free(t); + if (r != ARCHIVE_OK) + cpio_warnc(archive_errno(cpio->archive), + archive_error_string(cpio->archive)); + if (r == ARCHIVE_FATAL) + exit(1); +#ifdef EXDEV + if (r != ARCHIVE_OK && archive_errno(cpio->archive) == EXDEV) { + /* Cross-device link: Just fall through and use + * the original entry to copy the file over. */ + cpio_warnc(0, "Copying file instead"); + } else +#endif + 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", + srcpath, + 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); + } + } + + fd = restore_time(cpio, entry, srcpath, fd); + +cleanup: + if (cpio->verbose) + fprintf(stderr,"\n"); + if (fd >= 0) + close(fd); + return (0); +} + +static int +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 */ + + if (!warned) + cpio_warnc(0, "Can't restore access times on this platform"); + warned = 1; + return (fd); +#else +#if defined(_WIN32) && !defined(__CYGWIN__) + struct __timeval times[2]; +#else + struct timeval times[2]; +#endif + + if (!cpio->option_atime_restore) + return (fd); + + 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 (fd); +#endif + /* + * Some platform cannot restore access times if the file descriptor + * is still opened. + */ + if (fd >= 0) { + close(fd); + fd = -1; + } + +#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 + return (fd); +} + + +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) + list_item_verbose(cpio, 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); +} + +/* + * Display information about the current file. + * + * The format here roughly duplicates the output of 'ls -l'. + * This is based on SUSv2, where 'tar tv' is documented as + * listing additional information in an "unspecified format," + * and 'pax -l' is documented as using the same format as 'ls -l'. + */ +static void +list_item_verbose(struct cpio *cpio, struct archive_entry *entry) +{ + char size[32]; + char date[32]; + char uids[16], gids[16]; + const char *uname, *gname; + FILE *out = stdout; + const struct stat *st; + const char *fmt; + time_t tim; + static time_t now; + + st = archive_entry_stat(entry); + + if (!now) + time(&now); + + if (cpio->option_numeric_uid_gid) { + /* Format numeric uid/gid for display. */ + snprintf(uids, sizeof(uids), "%d", + (int)archive_entry_uid(entry)); + uname = uids; + snprintf(gids, sizeof(gids), "%d", + (int)archive_entry_gid(entry)); + gname = gids; + } else { + /* Use uname if it's present, else lookup name from uid. */ + uname = archive_entry_uname(entry); + if (uname == NULL) + uname = lookup_uname(cpio, archive_entry_uid(entry)); + /* Use gname if it's present, else lookup name from gid. */ + gname = archive_entry_gname(entry); + if (gname == NULL) + gname = lookup_gname(cpio, archive_entry_gid(entry)); + } + + /* Print device number or file size. */ + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { + snprintf(size, sizeof(size), "%lu,%lu", + (unsigned long)major(st->st_rdev), + (unsigned long)minor(st->st_rdev)); /* ls(1) also casts here. */ + } else { + snprintf(size, sizeof(size), CPIO_FILESIZE_PRINTF, + (CPIO_FILESIZE_TYPE)st->st_size); + } + + /* Format the time using 'ls -l' conventions. */ + tim = (time_t)st->st_mtime; +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Windows' strftime function does not support %e format. */ + if (abs(tim - now) > (365/2)*86400) + fmt = cpio->day_first ? "%d %b %Y" : "%b %d %Y"; + else + fmt = cpio->day_first ? "%d %b %H:%M" : "%b %d %H:%M"; +#else + if (abs(tim - now) > (365/2)*86400) + fmt = cpio->day_first ? "%e %b %Y" : "%b %e %Y"; + else + fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M"; +#endif + strftime(date, sizeof(date), fmt, localtime(&tim)); + + fprintf(out, "%s%3d %-8s %-8s %8s %12s %s", + archive_entry_strmode(entry), + archive_entry_nlink(entry), + uname, gname, size, date, + archive_entry_pathname(entry)); + + /* Extra information for links. */ + if (archive_entry_hardlink(entry)) /* Hard link */ + fprintf(out, " link to %s", archive_entry_hardlink(entry)); + else if (archive_entry_symlink(entry)) /* Symbolic link */ + fprintf(out, " -> %s", archive_entry_symlink(entry)); + fprintf(out, "\n"); +} + +static void +mode_pass(struct cpio *cpio, const char *destdir) +{ + unsigned long blocks; + struct line_reader *lr; + const char *p; + 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); + lr = process_lines_init("-", cpio->line_separator); + while ((p = process_lines_next(lr)) != NULL) + file_to_archive(cpio, p); + process_lines_free(lr); + + 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)); + + 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); +} + +/* + * 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. + */ +struct line_reader { + FILE *f; + char *buff, *buff_end, *line_start, *line_end, *p; + char *pathname; + size_t buff_length; + int separator; + int ret; +}; + +struct line_reader * +process_lines_init(const char *pathname, char separator) +{ + struct line_reader *lr; + + lr = calloc(1, sizeof(*lr)); + if (lr == NULL) + cpio_errc(1, ENOMEM, "Can't open %s", pathname); + + lr->separator = separator; + lr->pathname = strdup(pathname); + + if (strcmp(pathname, "-") == 0) + lr->f = stdin; + else + lr->f = fopen(pathname, "r"); + if (lr->f == NULL) + cpio_errc(1, errno, "Couldn't open %s", pathname); + lr->buff_length = 8192; + lr->buff = malloc(lr->buff_length); + if (lr->buff == NULL) + cpio_errc(1, ENOMEM, "Can't read %s", pathname); + lr->line_start = lr->line_end = lr->buff_end = lr->buff; + + return (lr); +} + +const char * +process_lines_next(struct line_reader *lr) +{ + size_t bytes_wanted, bytes_read, new_buff_size; + char *line_start, *p; + + for (;;) { + /* If there's a line in the buffer, return it immediately. */ + while (lr->line_end < lr->buff_end) { + if (*lr->line_end == lr->separator) { + *lr->line_end = '\0'; + line_start = lr->line_start; + lr->line_start = lr->line_end + 1; + lr->line_end = lr->line_start; + return (line_start); + } else + lr->line_end++; + } + + /* If we're at end-of-file, process the final data. */ + if (lr->f == NULL) { + /* If there's more text, return one last line. */ + if (lr->line_end > lr->line_start) { + *lr->line_end = '\0'; + line_start = lr->line_start; + lr->line_start = lr->line_end + 1; + lr->line_end = lr->line_start; + return (line_start); + } + /* Otherwise, we're done. */ + return (NULL); + } + + /* Buffer only has part of a line. */ + if (lr->line_start > lr->buff) { + /* Move a leftover fractional line to the beginning. */ + memmove(lr->buff, lr->line_start, + lr->buff_end - lr->line_start); + lr->buff_end -= lr->line_start - lr->buff; + lr->line_end -= lr->line_start - lr->buff; + lr->line_start = lr->buff; + } else { + /* Line is too big; enlarge the buffer. */ + new_buff_size = lr->buff_length * 2; + if (new_buff_size <= lr->buff_length) + cpio_errc(1, ENOMEM, + "Line too long in %s", lr->pathname); + lr->buff_length = new_buff_size; + p = realloc(lr->buff, new_buff_size); + if (p == NULL) + cpio_errc(1, ENOMEM, + "Line too long in %s", lr->pathname); + lr->buff_end = p + (lr->buff_end - lr->buff); + lr->line_end = p + (lr->line_end - lr->buff); + lr->line_start = lr->buff = p; + } + + /* Get some more data into the buffer. */ + bytes_wanted = lr->buff + lr->buff_length - lr->buff_end; + bytes_read = fread(lr->buff_end, 1, bytes_wanted, lr->f); + lr->buff_end += bytes_read; + + if (ferror(lr->f)) + cpio_errc(1, errno, "Can't read %s", lr->pathname); + if (feof(lr->f)) { + if (lr->f != stdin) + fclose(lr->f); + lr->f = NULL; + } + } +} + +void +process_lines_free(struct line_reader *lr) +{ + free(lr->buff); + free(lr->pathname); + free(lr); +} + +static void +free_cache(struct name_cache *cache) +{ + size_t i; + + if (cache != NULL) { + for (i = 0; i < cache->size; i++) + free(cache->cache[i].name); + free(cache); + } +} + +/* + * Lookup uname/gname from uid/gid, return NULL if no match. + */ +static const char * +lookup_name(struct cpio *cpio, struct name_cache **name_cache_variable, + int (*lookup_fn)(struct cpio *, const char **, id_t), id_t id) +{ + char asnum[16]; + struct name_cache *cache; + const char *name; + int slot; + + + if (*name_cache_variable == NULL) { + *name_cache_variable = malloc(sizeof(struct name_cache)); + if (*name_cache_variable == NULL) + cpio_errc(1, ENOMEM, "No more memory"); + memset(*name_cache_variable, 0, sizeof(struct name_cache)); + (*name_cache_variable)->size = name_cache_size; + } + + cache = *name_cache_variable; + cache->probes++; + + slot = id % cache->size; + if (cache->cache[slot].name != NULL) { + if (cache->cache[slot].id == id) { + cache->hits++; + return (cache->cache[slot].name); + } + free(cache->cache[slot].name); + cache->cache[slot].name = NULL; + } + + if (lookup_fn(cpio, &name, id) == 0) { + if (name == NULL || name[0] == '\0') { + /* If lookup failed, format it as a number. */ + snprintf(asnum, sizeof(asnum), "%u", (unsigned)id); + name = asnum; + } + cache->cache[slot].name = strdup(name); + if (cache->cache[slot].name != NULL) { + cache->cache[slot].id = id; + return (cache->cache[slot].name); + } + /* + * Conveniently, NULL marks an empty slot, so + * if the strdup() fails, we've just failed to + * cache it. No recovery necessary. + */ + } + return (NULL); +} + +static const char * +lookup_uname(struct cpio *cpio, uid_t uid) +{ + return (lookup_name(cpio, &cpio->uname_cache, + &lookup_uname_helper, (id_t)uid)); +} + +static int +lookup_uname_helper(struct cpio *cpio, const char **name, id_t id) +{ + struct passwd *pwent; + + (void)cpio; /* UNUSED */ + + errno = 0; + pwent = getpwuid((uid_t)id); + if (pwent == NULL) { + *name = NULL; + if (errno != 0) + cpio_warnc(errno, "getpwuid(%d) failed", id); + return (errno); + } + + *name = pwent->pw_name; + return (0); +} + +static const char * +lookup_gname(struct cpio *cpio, gid_t gid) +{ + return (lookup_name(cpio, &cpio->gname_cache, + &lookup_gname_helper, (id_t)gid)); +} + +static int +lookup_gname_helper(struct cpio *cpio, const char **name, id_t id) +{ + struct group *grent; + + (void)cpio; /* UNUSED */ + + errno = 0; + grent = getgrgid((gid_t)id); + if (grent == NULL) { + *name = NULL; + if (errno != 0) + cpio_warnc(errno, "getgrgid(%d) failed", id); + return (errno); + } + + *name = grent->gr_name; + return (0); +} diff --git a/libarchive/libarchive-2.7.1/cpio/cpio.h b/libarchive/libarchive-2.7.1/cpio/cpio.h new file mode 100644 index 0000000..79b2223 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/cpio.h @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/usr.bin/cpio/cpio.h,v 1.7 2008/12/06 07:30:40 kientzle Exp $ + */ + +#ifndef CPIO_H_INCLUDED +#define CPIO_H_INCLUDED + +#include "cpio_platform.h" +#include + +#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 { + /* Option parsing */ + const char *optarg; + + /* Options */ + const 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; + char line_separator; /* --null ? '\0' : '\n' */ + 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_numeric_uid_gid; /* -n */ + int option_rename; /* -r */ + char *destdir; + size_t pass_destpath_alloc; + char *pass_destpath; + int uid_override; + int gid_override; + int day_first; /* true if locale prefers day/mon */ + + /* 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; + + struct name_cache *uname_cache; + struct name_cache *gname_cache; + + /* 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, ...) __LA_DEAD; +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_NO_PRESERVE_OWNER, + OPTION_QUIET, + OPTION_VERSION +}; + +struct line_reader; + +struct line_reader *process_lines_init(const char *, char separator); +const char *process_lines_next(struct line_reader *); +void process_lines_free(struct line_reader *); + +int cpio_getopt(struct cpio *cpio); +int include_from_file(struct cpio *, const char *); + +#endif diff --git a/libarchive/libarchive-2.7.1/cpio/cpio_cygwin.c b/libarchive/libarchive-2.7.1/cpio/cpio_cygwin.c new file mode 100644 index 0000000..f2157c5 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/cpio_cygwin.c @@ -0,0 +1,139 @@ +/*- + * Copyright (c) 2009 Michihiro NAKAJIMA + * 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$ + */ + +#if defined(__CYGWIN__) +#define _WIN32_WINNT 0x0500 +#define WINVER 0x0500 + +#include "cpio_platform.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpio.h" + +#ifndef LIST_H +static int +_is_privileged(HANDLE thandle, const char *sidlist[]) +{ + TOKEN_USER *tuser; + TOKEN_GROUPS *tgrp; + DWORD bytes; + PSID psid; + DWORD i, g; + int member; + + psid = NULL; + tuser = NULL; + tgrp = NULL; + member = 0; + for (i = 0; sidlist[i] != NULL && member == 0; i++) { + if (psid != NULL) + LocalFree(psid); + /* mingw/cygwin: incorrectly prototypes arg 1 as LPSTR + * instead of LPCSTR. Work around it here + */ + if (ConvertStringSidToSidA((char *)sidlist[i], &psid) == 0) { + errno = EPERM; + return (-1); + } + if (tuser == NULL) { + GetTokenInformation(thandle, TokenUser, NULL, 0, &bytes); + tuser = malloc(bytes); + if (tuser == NULL) { + errno = ENOMEM; + member = -1; + break; + } + if (GetTokenInformation(thandle, TokenUser, tuser, bytes, &bytes) == 0) { + errno = EPERM; + member = -1; + break; + } + } + member = EqualSid(tuser->User.Sid, psid); + if (member) + break; + if (tgrp == NULL) { + GetTokenInformation(thandle, TokenGroups, NULL, 0, &bytes); + tgrp = malloc(bytes); + if (tgrp == NULL) { + errno = ENOMEM; + member = -1; + break; + } + if (GetTokenInformation(thandle, TokenGroups, tgrp, bytes, &bytes) == 0) { + errno = EPERM; + member = -1; + break; + } + } + for (g = 0; g < tgrp->GroupCount; g++) { + member = EqualSid(tgrp->Groups[g].Sid, psid); + if (member) + break; + } + } + LocalFree(psid); + free(tuser); + free(tgrp); + + return (member); +} + +int +bsdcpio_is_privileged() +{ + HANDLE thandle; + int ret; + const char *sidlist[] = { + "S-1-5-32-544", /* Administrators */ + "S-1-5-32-551", /* Backup Operators */ + NULL + }; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &thandle) == 0) { + cpio_warnc(EPERM, "Failed to check privilege"); + return (0); + } + ret = _is_privileged(thandle, sidlist); + if (ret < 0) { + cpio_warnc(errno, "Failed to check privilege"); + return (0); + } + return (ret); +} + +#endif /* LIST_H */ + +#endif diff --git a/libarchive/libarchive-2.7.1/cpio/cpio_cygwin.h b/libarchive/libarchive-2.7.1/cpio/cpio_cygwin.h new file mode 100644 index 0000000..9ee41b4 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/cpio_cygwin.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2009 Michihiro NAKAJIMA + * 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_CYGWIN_H +#define CPIO_CYGWIN_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +extern int bsdcpio_is_privileged(); + +#ifdef __cplusplus +} +#endif + +#endif /* CPIO_CYGWIN_H */ diff --git a/libarchive/libarchive-2.7.1/cpio/cpio_platform.h b/libarchive/libarchive-2.7.1/cpio/cpio_platform.h new file mode 100644 index 0000000..8ade731 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/cpio_platform.h @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/usr.bin/cpio/cpio_platform.h,v 1.2 2008/12/06 07:15:42 kientzle Exp $ + */ + +/* + * 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 /* For __FBSDID */ +#elif !defined(__FBSDID) +/* 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 +#include +#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 + +/* How to mark functions that don't return. */ +#if defined(__GNUC__) && (__GNUC__ > 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)) +#define __LA_DEAD __attribute__((__noreturn__)) +#else +#define __LA_DEAD +#endif + +#if defined(__CYGWIN__) +#include "cpio_cygwin.h" +#elif defined(_WIN32) /* && !__CYGWIN__ */ +#include "cpio_windows.h" +#endif + +#endif /* !CPIO_PLATFORM_H_INCLUDED */ diff --git a/libarchive/libarchive-2.7.1/cpio/cpio_windows.c b/libarchive/libarchive-2.7.1/cpio/cpio_windows.c new file mode 100644 index 0000000..ea67d98 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/cpio_windows.c @@ -0,0 +1,994 @@ +/*- + * Copyright (c) 2009 Michihiro NAKAJIMA + * 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$ + */ + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define _WIN32_WINNT 0x0500 +#define WINVER 0x0500 + +#include "cpio_platform.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpio.h" + +#define EPOC_TIME (116444736000000000ULL) + +struct ustat { + int64_t st_atime; + uint32_t st_atime_nsec; + int64_t st_ctime; + uint32_t st_ctime_nsec; + int64_t st_mtime; + uint32_t st_mtime_nsec; + gid_t st_gid; + /* 64bits ino */ + int64_t st_ino; + mode_t st_mode; + uint32_t st_nlink; + uint64_t st_size; + uid_t st_uid; + dev_t st_dev; + dev_t st_rdev; +}; + +/* Transform 64-bits ino into 32-bits by hashing. + * You do not forget that really unique number size is 64-bits. + */ +#define INOSIZE (8*sizeof(ino_t)) /* 32 */ +static __inline ino_t +getino(struct ustat *ub) +{ + ULARGE_INTEGER ino64; + + ino64.QuadPart = ub->st_ino; + /* I don't know this hashing is correct way */ + return (ino64.LowPart ^ (ino64.LowPart >> INOSIZE)); +} + +/* + * Prepend "\\?\" to the path name and convert it to unicode to permit + * an extended-length path for a maximum total path length of 32767 + * characters. + * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx + */ +static wchar_t * +permissive_name(const char *name) +{ + wchar_t *wn, *wnp; + wchar_t *ws, *wsp; + size_t l, len, slen; + int unc; + + len = strlen(name); + wn = malloc((len + 1) * sizeof(wchar_t)); + if (wn == NULL) + return (NULL); + l = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len); + if (l == 0) { + free(wn); + return (NULL); + } + wn[l] = L'\0'; + + /* Get a full path names */ + l = GetFullPathNameW(wn, 0, NULL, NULL); + if (l == 0) { + free(wn); + return (NULL); + } + wnp = malloc(l * sizeof(wchar_t)); + if (wnp == NULL) { + free(wn); + return (NULL); + } + len = GetFullPathNameW(wn, l, wnp, NULL); + free(wn); + wn = wnp; + + if (wnp[0] == L'\\' && wnp[1] == L'\\' && + wnp[2] == L'?' && wnp[3] == L'\\') + /* We have already permissive names. */ + return (wn); + + if (wnp[0] == L'\\' && wnp[1] == L'\\' && + wnp[2] == L'.' && wnp[3] == L'\\') { + /* Device names */ + if (((wnp[4] >= L'a' && wnp[4] <= L'z') || + (wnp[4] >= L'A' && wnp[4] <= L'Z')) && + wnp[5] == L':' && wnp[6] == L'\\') + wnp[2] = L'?';/* Not device names. */ + return (wn); + } + + unc = 0; + if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') { + wchar_t *p = &wnp[2]; + + /* Skip server-name letters. */ + while (*p != L'\\' && *p != L'\0') + ++p; + if (*p == L'\\') { + wchar_t *rp = ++p; + /* Skip share-name letters. */ + while (*p != L'\\' && *p != L'\0') + ++p; + if (*p == L'\\' && p != rp) { + /* Now, match patterns such as + * "\\server-name\share-name\" */ + wnp += 2; + len -= 2; + unc = 1; + } + } + } + + slen = 4 + (unc * 4) + len + 1; + ws = wsp = malloc(slen * sizeof(wchar_t)); + if (ws == NULL) { + free(wn); + return (NULL); + } + /* prepend "\\?\" */ + wcsncpy(wsp, L"\\\\?\\", 4); + wsp += 4; + slen -= 4; + if (unc) { + /* append "UNC\" ---> "\\?\UNC\" */ + wcsncpy(wsp, L"UNC\\", 4); + wsp += 4; + slen -= 4; + } + wcsncpy_s(wsp, slen, wnp, _TRUNCATE); + free(wn); + return (ws); +} + +static HANDLE +la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) +{ + wchar_t *wpath; + HANDLE handle; + + handle = CreateFileA(path, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile); + if (handle != INVALID_HANDLE_VALUE) + return (handle); + if (GetLastError() != ERROR_PATH_NOT_FOUND) + return (handle); + wpath = permissive_name(path); + if (wpath == NULL) + return (handle); + handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile); + free(wpath); + return (handle); +} + +static size_t +wequallen(const wchar_t *s1, const wchar_t *s2) +{ + size_t i = 0; + + while (*s1 != L'\0' && *s2 != L'\0' && *s1 == *s2) { + ++s1; ++s2; ++i; + } + return (i); +} + +/* Check that path1 and path2 can be hard-linked by each other. + * Both arguments must be made by permissive_name function. + */ +static int +canHardLinkW(const wchar_t *path1, const wchar_t *path2) +{ + wchar_t root[MAX_PATH]; + wchar_t fs[32]; + const wchar_t *s; + int r; + + r = wequallen(path1, path2); + /* Is volume-name the same? */ + if (r < 7) + return (0); + if (wcsncmp(path1, L"\\\\?\\UNC\\", 8) == 0) { + int len; + + s = path1 + 8; + if (*s == L'\\') + return (0); + /* 012345678 + * Name : "\\?\UNC\Server\Share\" + * ^ search + */ + s = wcschr(++s, L'\\'); + if (s == NULL) + return (0); + if (*++s == L'\\') + return (0); + /* 012345678 + * Name : "\\?\UNC\Server\Share\" + * ^ search + */ + s = wcschr(++s, L'\\'); + if (s == NULL) + return (0); + s++; + /* 012345678 + * Name : "\\?\UNC\Server\Share\xxxx" + * ^--- len ----^ + */ + len = (int)(s - path1 - 8); + /* Is volume-name the same? */ + if (r < len + 8) + return (0); + /* Is volume-name too long? */ + if (sizeof(root) -3 < len) + return (0); + root[0] = root[1] = L'\\'; + wcsncpy(root + 2, path1 + 8 , len); + /* root : "\\Server\Share\" */ + root[2 + len] = L'\0'; + } else if (wcsncmp(path1, L"\\\\?\\", 4) == 0) { + s = path1 + 4; + if ((!iswalpha(*s)) || s[1] != L':' || s[2] != L'\\') + return (0); + wcsncpy(root, path1 + 4, 3); + root[3] = L'\0'; + } else + return (0); + if (!GetVolumeInformationW(root, NULL, 0, NULL, NULL, NULL, fs, sizeof(fs))) + return (0); + if (wcscmp(fs, L"NTFS") == 0) + return (1); + else + return (0); +} + +/* Make a link to src called dst. */ +static int +__link(const char *src, const char *dst, int sym) +{ + wchar_t *wsrc, *wdst; + int res, retval; + DWORD attr; + + if (src == NULL || dst == NULL) { + set_errno (EINVAL); + return -1; + } + + wsrc = permissive_name(src); + wdst = permissive_name(dst); + if (wsrc == NULL || wdst == NULL) { + if (wsrc != NULL) + free(wsrc); + if (wdst != NULL) + free(wdst); + set_errno (EINVAL); + return -1; + } + + if ((attr = GetFileAttributesW(wsrc)) != -1) { + if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + errno = EPERM; + retval = -1; + goto exit; + } + if (!sym && canHardLinkW(wsrc, wdst)) + res = CreateHardLinkW(wdst, wsrc, NULL); + else + res = CopyFileW(wsrc, wdst, FALSE); + } else { + /* wsrc does not exist; try src prepend it with the dirname of wdst */ + wchar_t *wnewsrc, *slash; + int i, n, slen, wlen; + + if (strlen(src) >= 3 && isalpha((unsigned char )src[0]) && + src[1] == ':' && src[2] == '\\') { + /* Original src name is already full-path */ + retval = -1; + goto exit; + } + if (src[0] == '\\') { + /* Original src name is almost full-path + * (maybe src name is without drive) */ + retval = -1; + goto exit; + } + + wnewsrc = malloc ((wcslen(wsrc) + wcslen(wdst) + 1) * sizeof(wchar_t)); + if (wnewsrc == NULL) { + errno = ENOMEM; + retval = -1; + goto exit; + } + /* Copying a dirname of wdst */ + wcscpy(wnewsrc, wdst); + slash = wcsrchr(wnewsrc, L'\\'); + if (slash != NULL) + *++slash = L'\0'; + else + wcscat(wnewsrc, L"\\"); + /* Converting multi-byte src to wide-char src */ + wlen = wcslen(wsrc); + slen = strlen(src); + n = MultiByteToWideChar(CP_ACP, 0, src, slen, wsrc, slen); + if (n == 0) { + free (wnewsrc); + retval = -1; + goto exit; + } + for (i = 0; i < n; i++) + if (wsrc[i] == L'/') + wsrc[i] = L'\\'; + wcsncat(wnewsrc, wsrc, n); + /* Check again */ + attr = GetFileAttributesW(wnewsrc); + if (attr == -1 || (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + if (attr == -1) + _dosmaperr(GetLastError()); + else + errno = EPERM; + free (wnewsrc); + retval = -1; + goto exit; + } + if (!sym && canHardLinkW(wnewsrc, wdst)) + res = CreateHardLinkW(wdst, wnewsrc, NULL); + else + res = CopyFileW(wnewsrc, wdst, FALSE); + free (wnewsrc); + } + if (res == 0) { + _dosmaperr(GetLastError()); + retval = -1; + } else + retval = 0; +exit: + free(wsrc); + free(wdst); + return (retval); +} + +/* Make a hard link to src called dst. */ +int +link(const char *src, const char *dst) +{ + return __link (src, dst, 0); +} + +/* Make a symbolic link to FROM called TO. */ +int symlink (from, to) + const char *from; + const char *to; +{ + return __link (from, to, 1); +} + +unsigned int +sleep(unsigned int seconds) +{ + Sleep(seconds * 1000); + return (0); +} + +#define WINTIME(sec, usec) ((Int32x32To64(sec, 10000000) + EPOC_TIME) + (usec * 10)) +static int +__hutimes(HANDLE handle, const struct __timeval *times) +{ + ULARGE_INTEGER wintm; + FILETIME fatime, fmtime; + + wintm.QuadPart = WINTIME(times[0].tv_sec, times[0].tv_usec); + fatime.dwLowDateTime = wintm.LowPart; + fatime.dwHighDateTime = wintm.HighPart; + wintm.QuadPart = WINTIME(times[1].tv_sec, times[1].tv_usec); + fmtime.dwLowDateTime = wintm.LowPart; + fmtime.dwHighDateTime = wintm.HighPart; + if (SetFileTime(handle, NULL, &fatime, &fmtime) == 0) { + errno = EINVAL; + return (-1); + } + return (0); +} + +int +futimes(int fd, const struct __timeval *times) +{ + + return (__hutimes((HANDLE)_get_osfhandle(fd), times)); +} + +int +utimes(const char *name, const struct __timeval *times) +{ + int ret; + HANDLE handle; + + handle = la_CreateFile(name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (handle == INVALID_HANDLE_VALUE) { + _dosmaperr(GetLastError()); + return (-1); + } + ret = __hutimes(handle, times); + CloseHandle(handle); + return (ret); +} + +int +la_chdir(const char *path) +{ + wchar_t *ws; + int r; + + r = SetCurrentDirectoryA(path); + if (r == 0) { + if (GetLastError() != ERROR_FILE_NOT_FOUND) { + _dosmaperr(GetLastError()); + return (-1); + } + } else + return (0); + ws = permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + r = SetCurrentDirectoryW(ws); + free(ws); + if (r == 0) { + _dosmaperr(GetLastError()); + return (-1); + } + return (0); +} + +int +la_mkdir(const char *path, mode_t mode) +{ + wchar_t *ws; + int r; + + (void)mode;/* UNUSED */ + r = CreateDirectoryA(path, NULL); + if (r == 0) { + DWORD lasterr = GetLastError(); + if (lasterr != ERROR_FILENAME_EXCED_RANGE && + lasterr != ERROR_PATH_NOT_FOUND) { + _dosmaperr(GetLastError()); + return (-1); + } + } else + return (0); + ws = permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + r = CreateDirectoryW(ws, NULL); + free(ws); + if (r == 0) { + _dosmaperr(GetLastError()); + return (-1); + } + return (0); +} + +int +la_open(const char *path, int flags, ...) +{ + va_list ap; + wchar_t *ws; + int r, pmode; + DWORD attr; + + va_start(ap, flags); + pmode = va_arg(ap, int); + va_end(ap); + ws = NULL; + if ((flags & ~O_BINARY) == O_RDONLY) { + /* + * When we open a directory, _open function returns + * "Permission denied" error. + */ + attr = GetFileAttributesA(path); + if (attr == -1 && GetLastError() == ERROR_PATH_NOT_FOUND) { + ws = permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + attr = GetFileAttributesW(ws); + } + if (attr == -1) { + _dosmaperr(GetLastError()); + free(ws); + return (-1); + } + if (attr & FILE_ATTRIBUTE_DIRECTORY) { + HANDLE handle; + + if (ws != NULL) + handle = CreateFileW(ws, 0, 0, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_ATTRIBUTE_READONLY, + NULL); + else + handle = CreateFileA(path, 0, 0, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_ATTRIBUTE_READONLY, + NULL); + free(ws); + if (handle == INVALID_HANDLE_VALUE) { + _dosmaperr(GetLastError()); + return (-1); + } + r = _open_osfhandle((intptr_t)handle, _O_RDONLY); + return (r); + } + } + if (ws == NULL) { + r = _open(path, flags, pmode); + if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { + /* simular other POSIX system action to pass a test */ + attr = GetFileAttributesA(path); + if (attr == -1) + _dosmaperr(GetLastError()); + else if (attr & FILE_ATTRIBUTE_DIRECTORY) + errno = EISDIR; + else + errno = EACCES; + return (-1); + } + if (r >= 0 || errno != ENOENT) + return (r); + ws = permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + } + r = _wopen(ws, flags, pmode); + if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { + /* simular other POSIX system action to pass a test */ + attr = GetFileAttributesW(ws); + if (attr == -1) + _dosmaperr(GetLastError()); + else if (attr & FILE_ATTRIBUTE_DIRECTORY) + errno = EISDIR; + else + errno = EACCES; + } + free(ws); + return (r); +} + +ssize_t +la_read(int fd, void *buf, size_t nbytes) +{ + HANDLE handle; + DWORD bytes_read, lasterr; + int r; + +#ifdef _WIN64 + if (nbytes > UINT32_MAX) + nbytes = UINT32_MAX; +#endif + if (fd < 0) { + errno = EBADF; + return (-1); + } + handle = (HANDLE)_get_osfhandle(fd); + if (GetFileType(handle) == FILE_TYPE_PIPE) { + DWORD sta; + if (GetNamedPipeHandleState( + handle, &sta, NULL, NULL, NULL, NULL, 0) != 0 && + (sta & PIPE_NOWAIT) == 0) { + DWORD avail = -1; + int cnt = 3; + + while (PeekNamedPipe( + handle, NULL, 0, NULL, &avail, NULL) != 0 && + avail == 0 && --cnt) + Sleep(100); + if (avail == 0) + return (0); + } + } + r = ReadFile(handle, buf, (uint32_t)nbytes, + &bytes_read, NULL); + if (r == 0) { + lasterr = GetLastError(); + if (lasterr == ERROR_NO_DATA) { + errno = EAGAIN; + return (-1); + } + if (lasterr == ERROR_BROKEN_PIPE) + return (0); + if (lasterr == ERROR_ACCESS_DENIED) + errno = EBADF; + else + _dosmaperr(lasterr); + return (-1); + } + return ((ssize_t)bytes_read); +} + +/* Remove directory */ +int +la_rmdir(const char *path) +{ + wchar_t *ws; + int r; + + r = _rmdir(path); + if (r >= 0 || errno != ENOENT) + return (r); + ws = permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + r = _wrmdir(ws); + free(ws); + return (r); +} + +/* Convert Windows FILETIME to UTC */ +__inline static void +fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns) +{ + ULARGE_INTEGER utc; + + utc.HighPart = filetime->dwHighDateTime; + utc.LowPart = filetime->dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + *time = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */ + *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */ + } else { + *time = 0; + *ns = 0; + } +} + +/* Stat by handle + * Windows' stat() does not accept path which is added "\\?\" especially "?" + * character. + * It means we cannot access a long name path(which is longer than MAX_PATH). + * So I've implemented simular Windows' stat() to access the long name path. + * And I've added some feature. + * 1. set st_ino by nFileIndexHigh and nFileIndexLow of + * BY_HANDLE_FILE_INFORMATION. + * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION. + * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION. + */ +static int +__hstat(HANDLE handle, struct ustat *st) +{ + BY_HANDLE_FILE_INFORMATION info; + ULARGE_INTEGER ino64; + DWORD ftype; + mode_t mode; + time_t time; + long ns; + + switch (ftype = GetFileType(handle)) { + case FILE_TYPE_UNKNOWN: + errno = EBADF; + return (-1); + case FILE_TYPE_CHAR: + case FILE_TYPE_PIPE: + if (ftype == FILE_TYPE_CHAR) { + st->st_mode = S_IFCHR; + st->st_size = 0; + } else { + DWORD avail; + + st->st_mode = S_IFIFO; + if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL)) + st->st_size = avail; + else + st->st_size = 0; + } + st->st_atime = 0; + st->st_atime_nsec = 0; + st->st_mtime = 0; + st->st_mtime_nsec = 0; + st->st_ctime = 0; + st->st_ctime_nsec = 0; + st->st_ino = 0; + st->st_nlink = 1; + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + st->st_dev = 0; + return (0); + case FILE_TYPE_DISK: + break; + default: + /* This ftype is undocumented type. */ + _dosmaperr(GetLastError()); + return (-1); + } + + ZeroMemory(&info, sizeof(info)); + if (!GetFileInformationByHandle (handle, &info)) { + _dosmaperr(GetLastError()); + return (-1); + } + + mode = S_IRUSR | S_IRGRP | S_IROTH; + if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + else + mode |= S_IFREG; + st->st_mode = mode; + + fileTimeToUTC(&info.ftLastAccessTime, &time, &ns); + st->st_atime = time; + st->st_atime_nsec = ns; + fileTimeToUTC(&info.ftLastWriteTime, &time, &ns); + st->st_mtime = time; + st->st_mtime_nsec = ns; + fileTimeToUTC(&info.ftCreationTime, &time, &ns); + st->st_ctime = time; + st->st_ctime_nsec = ns; + st->st_size = + ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1)) + + (int64_t)(info.nFileSizeLow); +#ifdef SIMULATE_WIN_STAT + st->st_ino = 0; + st->st_nlink = 1; + st->st_dev = 0; +#else + /* Getting FileIndex as i-node. We have to remove a sequence which + * is high-16-bits of nFileIndexHigh. */ + ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL; + ino64.LowPart = info.nFileIndexLow; + st->st_ino = ino64.QuadPart; + st->st_nlink = info.nNumberOfLinks; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ++st->st_nlink;/* Add parent directory. */ + st->st_dev = info.dwVolumeSerialNumber; +#endif + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + return (0); +} + +static void +copy_stat(struct stat *st, struct ustat *us) +{ + st->st_atime = us->st_atime; + st->st_ctime = us->st_ctime; + st->st_mtime = us->st_mtime; + st->st_gid = us->st_gid; + st->st_ino = getino(us); + st->st_mode = us->st_mode; + st->st_nlink = us->st_nlink; + st->st_size = us->st_size; + st->st_uid = us->st_uid; + st->st_dev = us->st_dev; + st->st_rdev = us->st_rdev; +} + +int +la_fstat(int fd, struct stat *st) +{ + struct ustat u; + int ret; + + if (fd < 0) { + errno = EBADF; + return (-1); + } + ret = __hstat((HANDLE)_get_osfhandle(fd), &u); + if (ret >= 0) { + copy_stat(st, &u); + if (u.st_mode & (S_IFCHR | S_IFIFO)) { + st->st_dev = fd; + st->st_rdev = fd; + } + } + return (ret); +} + +int +la_stat(const char *path, struct stat *st) +{ + HANDLE handle; + struct ustat u; + int ret; + + handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + _dosmaperr(GetLastError()); + return (-1); + } + ret = __hstat(handle, &u); + CloseHandle(handle); + if (ret >= 0) { + char *p; + + copy_stat(st, &u); + p = strrchr(path, '.'); + if (p != NULL && strlen(p) == 4) { + char exttype[4]; + + ++ p; + exttype[0] = toupper(*p++); + exttype[1] = toupper(*p++); + exttype[2] = toupper(*p++); + exttype[3] = '\0'; + if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") || + !strcmp(exttype, "BAT") || !strcmp(exttype, "COM")) + st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + } + } + return (ret); +} + +ssize_t +la_write(int fd, const void *buf, size_t nbytes) +{ + uint32_t bytes_written; + +#ifdef _WIN64 + if (nbytes > UINT32_MAX) + nbytes = UINT32_MAX; +#endif + if (fd < 0) { + errno = EBADF; + return (-1); + } + if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes, + &bytes_written, NULL)) { + DWORD lasterr; + + lasterr = GetLastError(); + if (lasterr == ERROR_ACCESS_DENIED) + errno = EBADF; + else + _dosmaperr(lasterr); + return (-1); + } + return (bytes_written); +} + +#ifndef LIST_H +static int +_is_privileged(HANDLE thandle, const char *sidlist[]) +{ + TOKEN_USER *tuser; + TOKEN_GROUPS *tgrp; + DWORD bytes; + PSID psid; + DWORD i, g; + int member; + + psid = NULL; + tuser = NULL; + tgrp = NULL; + member = 0; + for (i = 0; sidlist[i] != NULL && member == 0; i++) { + if (psid != NULL) + LocalFree(psid); + if (ConvertStringSidToSidA(sidlist[i], &psid) == 0) { + errno = EPERM; + return (-1); + } + if (tuser == NULL) { + GetTokenInformation(thandle, TokenUser, NULL, 0, &bytes); + tuser = malloc(bytes); + if (tuser == NULL) { + errno = ENOMEM; + member = -1; + break; + } + if (GetTokenInformation(thandle, TokenUser, tuser, bytes, &bytes) == 0) { + errno = EPERM; + member = -1; + break; + } + } + member = EqualSid(tuser->User.Sid, psid); + if (member) + break; + if (tgrp == NULL) { + GetTokenInformation(thandle, TokenGroups, NULL, 0, &bytes); + tgrp = malloc(bytes); + if (tgrp == NULL) { + errno = ENOMEM; + member = -1; + break; + } + if (GetTokenInformation(thandle, TokenGroups, tgrp, bytes, &bytes) == 0) { + errno = EPERM; + member = -1; + break; + } + } + for (g = 0; g < tgrp->GroupCount; g++) { + member = EqualSid(tgrp->Groups[g].Sid, psid); + if (member) + break; + } + } + LocalFree(psid); + free(tuser); + free(tgrp); + + return (member); +} + +int +bsdcpio_is_privileged() +{ + HANDLE thandle; + int ret; + const char *sidlist[] = { + "S-1-5-32-544", /* Administrators */ + "S-1-5-32-551", /* Backup Operators */ + NULL + }; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &thandle) == 0) { + cpio_warnc(EPERM, "Failed to check privilege"); + return (0); + } + ret = _is_privileged(thandle, sidlist); + if (ret < 0) { + cpio_warnc(errno, "Failed to check privilege"); + return (0); + } + return (ret); +} + +#endif /* LIST_H */ + +#endif diff --git a/libarchive/libarchive-2.7.1/cpio/cpio_windows.h b/libarchive/libarchive-2.7.1/cpio/cpio_windows.h new file mode 100644 index 0000000..5527dbc --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/cpio_windows.h @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2009 Michihiro NAKAJIMA + * 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_WINDOWS_H +#define CPIO_WINDOWS_H 1 + +#define geteuid() 0 +#define getgrgid(id) NULL +#define getgrnam(name) NULL +#define getpwnam(name) NULL +#define getpwuid(id) NULL +#define getuid() 0 +#define snprintf sprintf_s + +struct passwd { + char *pw_name; + uid_t pw_uid; + gid_t pw_gid; +}; + +struct group { + char *gr_name; + gid_t gr_gid; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned int sleep(unsigned int seconds); +extern int bsdcpio_is_privileged(); + +#ifdef __cplusplus +} +#endif + +#endif /* CPIO_WINDOWS_H */ diff --git a/libarchive/libarchive-2.7.1/cpio/err.c b/libarchive/libarchive-2.7.1/cpio/err.c new file mode 100644 index 0000000..ad9c0e1 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/err.c @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * 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 +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#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); +} diff --git a/libarchive/libarchive-2.7.1/cpio/matching.c b/libarchive/libarchive-2.7.1/cpio/matching.c new file mode 100644 index 0000000..3e4ddc3 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/matching.c @@ -0,0 +1,259 @@ +/*- + * 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: src/usr.bin/cpio/matching.c,v 1.2 2008/06/21 02:20:20 kientzle Exp $"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#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) +{ + struct line_reader *lr; + const char *p; + int ret = 0; + + lr = process_lines_init(pathname, '\n'); + while ((p = process_lines_next(lr)) != NULL) + if (include(cpio, p) != 0) + ret = -1; + process_lines_free(lr); + return (ret); +} + +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); +} diff --git a/libarchive/libarchive-2.7.1/cpio/matching.h b/libarchive/libarchive-2.7.1/cpio/matching.h new file mode 100644 index 0000000..a66bc86 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/matching.h @@ -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 diff --git a/libarchive/libarchive-2.7.1/cpio/pathmatch.c b/libarchive/libarchive-2.7.1/cpio/pathmatch.c new file mode 100644 index 0000000..40fa836 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/pathmatch.c @@ -0,0 +1,249 @@ +/*- + * 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 +#endif + +#include "pathmatch.h" + +/* + * Check whether a character 'c' is matched by a list specification [...]: + * * Leading '!' negates the class. + * * - is a range of characters + * * \ removes any special meaning for + * + * 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[0] == '.' && s[1] == '/') + || (s[0] == '.' && s[1] == '\0')) + ++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); + } + 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; + case '\\': + /* Trailing '\\' matches itself. */ + if (p[1] == '\0') { + if (*s != '\\') + return (0); + } else { + ++p; + if (*p != *s) + return (0); + } + break; + case '/': + if (*s != '/' && *s != '\0') + return (0); + /* Note: pattern "/\./" won't match "/"; + * pm_slashskip() correctly stops at backslash. */ + p = pm_slashskip(p); + s = pm_slashskip(s); + if (*p == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)) + return (1); + --p; /* Counteract the increment below. */ + --s; + break; + case '$': + /* '$' is special only at end of pattern and only + * if PATHMATCH_NO_ANCHOR_END is specified. */ + if (p[1] == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)){ + /* "dir" == "dir/" == "dir/." */ + return (*pm_slashskip(s) == '\0'); + } + /* Otherwise, '$' is not special. */ + /* FALL THROUGH */ + default: + if (*p != *s) + return (0); + break; + } + ++p; + ++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 ( ; s != NULL; s = strchr(s, '/')) { + if (*s == '/') + s++; + if (pm(p, s, flags)) + return (1); + } + return (0); + } + + /* Default: Match from beginning. */ + return (pm(p, s, flags)); +} diff --git a/libarchive/libarchive-2.7.1/cpio/pathmatch.h b/libarchive/libarchive-2.7.1/cpio/pathmatch.h new file mode 100644 index 0000000..fd2c257 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/pathmatch.h @@ -0,0 +1,42 @@ +/*- + * 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 + +/* Don't anchor at beginning unless the pattern starts with "^" */ +#define PATHMATCH_NO_ANCHOR_START 1 +/* Don't anchor at end unless the pattern ends with "$" */ +#define PATHMATCH_NO_ANCHOR_END 2 + +/* Note that "^" and "$" are not special unless you set the corresponding + * flag above. */ + +int pathmatch(const char *p, const char *s, int flags); + +#endif diff --git a/libarchive/libarchive-2.7.1/cpio/test/CMakeLists.txt b/libarchive/libarchive-2.7.1/cpio/test/CMakeLists.txt new file mode 100644 index 0000000..4f9522e --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/CMakeLists.txt @@ -0,0 +1,66 @@ +############################################ +# +# How to build bsdcpio_test +# +############################################ +IF(ENABLE_CPIO AND ENABLE_TEST) + SET(bsdcpio_test_SOURCES + ../cmdline.c + ../err.c + ../pathmatch.c + main.c + test.h + test_0.c + test_basic.c + test_cmdline.c + test_format_newc.c + test_gcpio_compat.c + test_option_B_upper.c + test_option_C_upper.c + test_option_L_upper.c + test_option_Z_upper.c + test_option_a.c + test_option_c.c + test_option_d.c + test_option_f.c + test_option_help.c + test_option_l.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_passthrough_dotdot.c + test_passthrough_reverse.c + test_pathmatch.c + ) + IF(WIN32 AND NOT CYGWIN) + LIST(APPEND bsdcpio_test_SOURCES ../cpio_windows.c) + LIST(APPEND bsdcpio_test_SOURCES ../cpio_windows.h) + ENDIF(WIN32 AND NOT CYGWIN) + + # + # Generate the list.h + # + GENERATE_LIST_H(${CMAKE_CURRENT_BINARY_DIR}/list.h + ${CMAKE_CURRENT_LIST_FILE} ${bsdcpio_test_SOURCES}) + SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES + ${CMAKE_CURRENT_BINARY_DIR}) + # + # Register target + # + ADD_EXECUTABLE(bsdcpio_test ${bsdcpio_test_SOURCES}) + SET_PROPERTY(TARGET bsdcpio_test PROPERTY COMPILE_DEFINITIONS LIST_H) + SET(num 0) + FOREACH(test ${bsdcpio_test_SOURCES}) + IF(test MATCHES "^test_[^/]+[.]c$") + STRING(REGEX REPLACE "^(test_[^/]+)[.]c$" "\\1" testname ${test}) + ADD_TEST("bsdcpio_${testname}" bsdcpio_test + -q -v -p ${BSDCPIO} -r ${CMAKE_CURRENT_SOURCE_DIR} ${num}) + MATH(EXPR num "${num} + 1") + ENDIF(test MATCHES "^test_[^/]+[.]c$") + ENDFOREACH(test) +ENDIF(ENABLE_CPIO AND ENABLE_TEST) + diff --git a/libarchive/libarchive-2.7.1/cpio/test/list.h b/libarchive/libarchive-2.7.1/cpio/test/list.h new file mode 100644 index 0000000..01b11df --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/list.h @@ -0,0 +1,25 @@ +DEFINE_TEST(test_0) +DEFINE_TEST(test_basic) +DEFINE_TEST(test_cmdline) +DEFINE_TEST(test_format_newc) +DEFINE_TEST(test_gcpio_compat) +DEFINE_TEST(test_option_B_upper) +DEFINE_TEST(test_option_C_upper) +DEFINE_TEST(test_option_L_upper) +DEFINE_TEST(test_option_Z_upper) +DEFINE_TEST(test_option_a) +DEFINE_TEST(test_option_c) +DEFINE_TEST(test_option_d) +DEFINE_TEST(test_option_f) +DEFINE_TEST(test_option_help) +DEFINE_TEST(test_option_l) +DEFINE_TEST(test_option_m) +DEFINE_TEST(test_option_t) +DEFINE_TEST(test_option_u) +DEFINE_TEST(test_option_version) +DEFINE_TEST(test_option_y) +DEFINE_TEST(test_option_z) +DEFINE_TEST(test_owner_parse) +DEFINE_TEST(test_passthrough_dotdot) +DEFINE_TEST(test_passthrough_reverse) +DEFINE_TEST(test_pathmatch) diff --git a/libarchive/libarchive-2.7.1/cpio/test/main.c b/libarchive/libarchive-2.7.1/cpio/test/main.c new file mode 100644 index 0000000..9e35481 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/main.c @@ -0,0 +1,1191 @@ +/* + * 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 "test.h" + +#include +#include +#include +#include + +/* + * 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) ? "" : "") +#define KNOWNREF "test_option_f.cpio.uu" +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/main.c,v 1.3 2008/08/24 04:58:22 kientzle Exp $"); + +/* + * "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 const 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 : (int)strlen(v1)); + fprintf(stderr, " %s = ", e2); + strdump(v2); + fprintf(stderr, " (length %d)\n", v2 == NULL ? 0 : (int)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", (unsigned)(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); + close(fd); + } + 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) { + close(fd1); + close(fd2); + return (1); + } + if (memcmp(buff1, buff2, n1) != 0) + break; + } + close(fd1); + close(fd2); + 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); +} + +int +test_assert_file_exists(const char *fpattern, ...) +{ + char f[1024]; + va_list ap; + + va_start(ap, fpattern); + vsprintf(f, fpattern, ap); + va_end(ap); + + if (!access(f, F_OK)) + return (1); + if (!previous_failures(test_filename, test_line)) { + fprintf(stderr, "%s:%d: File doesn't exist\n", + test_filename, test_line); + fprintf(stderr, " file=\"%s\"\n", f); + report_failure(test_extra); + } + return (0); +} + +int +test_assert_file_not_exists(const char *fpattern, ...) +{ + char f[1024]; + va_list ap; + + va_start(ap, fpattern); + vsprintf(f, fpattern, ap); + va_end(ap); + + if (access(f, F_OK)) + return (1); + if (!previous_failures(test_filename, test_line)) { + fprintf(stderr, "%s:%d: File exists and shouldn't\n", + test_filename, test_line); + fprintf(stderr, " file=\"%s\"\n", f); + 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 + 128); + n = read(fd, contents, s * 2 + 128); + close(fd); + 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); +} + +/* assertTextFileContents() asserts the contents of a text file. */ +int +test_assert_text_file_contents(const char *buff, const char *f) +{ + char *contents; + const char *btxt, *ftxt; + int fd; + int n, s; + + fd = open(f, O_RDONLY); + s = strlen(buff); + contents = malloc(s * 2 + 128); + n = read(fd, contents, s * 2 + 128 -1); + if (n >= 0) + contents[n] = '\0'; + close(fd); + /* Compare texts. */ + btxt = buff; + ftxt = (const char *)contents; + while (*btxt != '\0' && *ftxt != '\0') { + if (*btxt == *ftxt) { + ++btxt; + ++ftxt; + continue; + } + if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') { + /* Pass over different new line characters. */ + ++btxt; + ftxt += 2; + continue; + } + break; + } + if (*btxt == '\0' && *ftxt == '\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); + fflush(stdout); + } + + /* + * 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) { +#if defined(_WIN32) && !defined(__CYGWIN__) + systemf("rmdir /S /Q %s", tests[i].name); +#else + systemf("rm -rf %s", tests[i].name); +#endif + } + } + /* 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] ...\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 to executable to be tested.\n"); + printf(" Default: path taken from " ENVBASE " environment variable.\n"); +#endif + printf(" -q Quiet.\n"); + printf(" -r 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); +} + + +static char * +get_refdir(void) +{ + char tried[512] = { '\0' }; + char buff[128]; + char *pwd, *p; + + /* Get the current dir. */ + pwd = getcwd(NULL, 0); + while (pwd[strlen(pwd) - 1] == '\n') + pwd[strlen(pwd) - 1] = '\0'; + printf("PWD: %s\n", pwd); + + /* Look for a known file. */ + snprintf(buff, sizeof(buff), "%s", pwd); + p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); + if (p != NULL) goto success; + strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); + strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); + + snprintf(buff, sizeof(buff), "%s/test", pwd); + p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); + if (p != NULL) goto success; + strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); + strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); + + snprintf(buff, sizeof(buff), "%s/%s/test", pwd, PROGRAM); + p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); + if (p != NULL) goto success; + strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); + strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); + + if (memcmp(pwd, "/usr/obj", 8) == 0) { + snprintf(buff, sizeof(buff), "%s", pwd + 8); + p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); + if (p != NULL) goto success; + strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); + strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); + + snprintf(buff, sizeof(buff), "%s/test", pwd + 8); + p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); + if (p != NULL) goto success; + strncat(tried, buff, sizeof(tried) - strlen(tried) - 1); + strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1); + } + +#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) + DebugBreak(); +#endif + printf("Unable to locate known reference file %s\n", KNOWNREF); + printf(" Checked following directories:\n%s\n", tried); + exit(1); + +success: + free(p); + free(pwd); + return strdup(buff); +} + +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; +#if defined(_WIN32) && !defined(__CYGWIN__) + char *testprg; +#endif + const char *tmp, *opt_arg, *progname, *p; + char tmpdir[256]; + char tmpdir_timestamp[256]; + + (void)argc; /* UNUSED */ + +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Make sure open() function will be used with a binary mode. */ + /* on cygwin, we need something similar, but instead link against */ + /* a special startup object, binmode.o */ + _set_fmode(_O_BINARY); +#endif + /* + * Name of this program, used to build root of our temp directory + * tree. + */ + progname = p = argv[0]; + while (*p != '\0') { + /* Support \ or / dir separators for Windows compat. */ + if (*p == '/' || *p == '\\') + progname = p + 1; + ++p; + } + +#ifdef PROGRAM + /* Get the target program from environment, if available. */ + testprog = getenv(ENVBASE); +#endif + + if (getenv("TMPDIR") != NULL) + tmp = getenv("TMPDIR"); + else if (getenv("TMP") != NULL) + tmp = getenv("TMP"); + else if (getenv("TEMP") != NULL) + tmp = getenv("TEMP"); + else if (getenv("TEMPDIR") != NULL) + tmp = getenv("TEMPDIR"); + else + tmp = "/tmp"; + + /* 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, without using getopt(), which isn't available + * on all platforms. + */ + ++argv; /* Skip program name */ + while (*argv != NULL) { + if (**argv != '-') + break; + p = *argv++; + ++p; /* Skip '-' */ + while (*p != '\0') { + opt = *p++; + opt_arg = NULL; + /* If 'opt' takes an argument, parse that. */ + if (opt == 'p' || opt == 'r') { + if (*p != '\0') + opt_arg = p; + else if (*argv == NULL) { + fprintf(stderr, + "Option -%c requires argument.\n", + opt); + usage(progname); + } else + opt_arg = *argv++; + p = ""; /* End of this option word. */ + } + + switch (opt) { + case 'd': + dump_on_failure = 1; + break; + case 'k': + keep_temp_files = 1; + break; + case 'p': +#ifdef PROGRAM + testprog = opt_arg; +#else + usage(progname); +#endif + break; + case 'q': + quiet_flag++; + break; + case 'r': + refdir = opt_arg; + break; + case 'v': + verbose = 1; + break; + case '?': + default: + usage(progname); + } + } + } + + /* + * Sanity-check that our options make sense. + */ +#ifdef PROGRAM + if (testprog == NULL) + usage(progname); +#endif +#if defined(_WIN32) && !defined(__CYGWIN__) + /* + * Command.exe cannot accept the command used '/' with drive + * name such as c:/xxx/command.exe when use '|' pipe handling. + */ + testprg = strdup(testprog); + for (i = 0; testprg[i] != '\0'; i++) { + if (testprg[i] == '/') + testprg[i] = '\\'; + } + testprog = testprg; +#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, "%s/%s.%s-%03d", tmp, 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) + refdir = refdir_alloc = get_refdir(); + + /* + * 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 (*argv == NULL) { + /* 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. */ + chdir(".."); + rmdir(tmpdir); + + return (tests_failed); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test.h b/libarchive/libarchive-2.7.1/cpio/test/test.h new file mode 100644 index 0000000..327668f --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2003-2006 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/usr.bin/cpio/test/test.h,v 1.2 2008/06/21 02:17:18 kientzle Exp $ + */ + +/* Every test program should #include "test.h" as the first thing. */ + +/* + * The goal of this file (and the matching test.c) is to + * simplify the very repetitive test-*.c test programs. + */ +#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) && !defined(__CYGWIN__) +/* 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 + +#if !defined(_WIN32) || defined(__CYGWIN__) +#include +#else +#include "../cpio_windows.h" +#endif +#if defined(__CYGWIN__) +/* In cygwin-1.7.x, the .nlinks field of directories is + * deliberately inaccurate, because to populate it requires + * stat'ing every file in the directory, which is slow. + * So, as an optimization cygwin doesn't do that in newer + * releases; all correct applications on any platform should + * never rely on it being > 1, so this optimization doesn't + * impact the operation of correctly coded applications. + * Therefore, the cpio test should not check its accuracy + */ +# define NLINKS_INACCURATE_FOR_DIRS +#endif +#include +#include +#include +#include +#include +#include +#if !defined(_WIN32) || defined(__CYGWIN__) +#include +#endif +#include +#include + +#ifdef USE_DMALLOC +#include +#endif + +/* No non-FreeBSD platform will have __FBSDID, so just define it here. */ +#ifdef __FreeBSD__ +#include /* For __FBSDID */ +#else +#undef __FBSDID +#define __FBSDID(a) struct _undefined_hack +#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 a file exists; supports printf-style arguments. */ +#define assertFileExists \ + test_setup(__FILE__, __LINE__);test_assert_file_exists +/* Assert that a file exists; supports printf-style arguments. */ +#define assertFileNotExists \ + test_setup(__FILE__, __LINE__);test_assert_file_not_exists +/* Assert that file contents match a string; supports printf-style arguments. */ +#define assertFileContents \ + test_setup(__FILE__, __LINE__);test_assert_file_contents +#define assertTextFileContents \ + test_setup(__FILE__, __LINE__);test_assert_text_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 *, ...); +int test_assert_text_file_contents(const char *buff, const char *f); +int test_assert_file_exists(const char *, ...); +int test_assert_file_not_exists(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. */ +const char *testprog; diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_0.c b/libarchive/libarchive-2.7.1/cpio/test/test_0.c new file mode 100644 index 0000000..d224daa --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_0.c @@ -0,0 +1,67 @@ +/*- + * 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. + */ +#if !defined(_WIN32) || defined(__CYGWIN__) +#define DEV_NULL "/dev/null" +#else +#define DEV_NULL "NUL" +#endif + +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. */ +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_basic.c b/libarchive/libarchive-2.7.1/cpio/test/test_basic.c new file mode 100644 index 0000000..9613723 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_basic.c @@ -0,0 +1,260 @@ +/*- + * 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: src/usr.bin/cpio/test/test_basic.c,v 1.4 2008/08/25 06:39:29 kientzle Exp $"); + +static void +verify_files(const char *target) +{ + struct stat st, st2; +#if !defined(_WIN32) || defined(__CYGWIN__) + char buff[128]; +#endif + 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)); +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Group members bits and others bits do not work. */ + assertEqualInt(0600, st.st_mode & 0700); +#else + assertEqualInt(0644, st.st_mode & 0777); +#endif + 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)); +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Group members bits and others bits do not work. */ + assertEqualInt(0600, st2.st_mode & 0700); +#else + assertEqualInt(0644, st2.st_mode & 0777); +#endif + 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 !defined(_WIN32) || defined(__CYGWIN__) + 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"); + } + } +#endif + + /* Another file with 1 link and different permissions. */ + r = lstat("file2", &st); + failure("Failed to stat file %s/file2, errno=%d", target, errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st.st_mode)); + failure("%s/file2: st.st_mode = %o", target, st.st_mode); +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Execution bit and group members bits and others + * bits do not work. */ + assertEqualInt(0600, st.st_mode & 0700); +#else + assertEqualInt(0777, st.st_mode & 0777); +#endif + assertEqualInt(10, st.st_size); + failure("file %s/file2 should have 1 link", target); + assertEqualInt(1, st.st_nlink); + } + + /* dir */ + r = lstat("dir", &st); + if (r == 0) { + assertEqualInt(r, 0); + assert(S_ISDIR(st.st_mode)); + failure("%s/dir: st.st_mode = %o", target, st.st_mode); +#if defined(_WIN32) && !defined(__CYGWIN__) + assertEqualInt(0700, st.st_mode & 0700); +#else + assertEqualInt(0775, st.st_mode & 0777); +#endif + } +} + +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); + assertTextFileContents(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); + assertTextFileContents(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 %s %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); + assertTextFileContents("1 block\n", "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); + + /* Another file with different permissions. */ + fd = open("file2", O_CREAT | O_WRONLY, 0777); + assert(fd >= 0); + assertEqualInt(10, write(fd, "123456789", 10)); + close(fd); + write(filelist, "file2\n", 6); + + /* Directory. */ + assertEqualInt(0, mkdir("dir", 0775)); + write(filelist, "dir\n", 4); + /* All done. */ + close(filelist); + + umask(022); + + /* Archive/dearchive with a variety of options. */ + basic_cpio("copy", "", "", "2 blocks\n"); + basic_cpio("copy_odc", "--format=odc", "", "2 blocks\n"); + basic_cpio("copy_newc", "-H newc", "", "2 blocks\n"); + basic_cpio("copy_cpio", "-H odc", "", "2 blocks\n"); +#if defined(_WIN32) && !defined(__CYGWIN__) + /* + * On Windows, symbolic link does not work. + * Currentry copying file instead. therefore block size is + * different. + */ + basic_cpio("copy_ustar", "-H ustar", "", "10 blocks\n"); +#else + basic_cpio("copy_ustar", "-H ustar", "", "9 blocks\n"); +#endif + /* Copy in one step using -p */ + passthrough("passthrough"); + + umask(oldumask); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_cmdline.c b/libarchive/libarchive-2.7.1/cpio/test/test_cmdline.c new file mode 100644 index 0000000..594cd34 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_cmdline.c @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 2003-2009 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 the command-line parsing. + */ + +DEFINE_TEST(test_cmdline) +{ + int fd; + + /* Create an empty file. */ + fd = open("empty", O_WRONLY | O_CREAT, 0555); + assert(fd >= 0); + close(fd); + + failure("-Q is an invalid option on every cpio program I know of"); + assert(0 != systemf("%s -i -Q 1.out 2>1.err", testprog)); + assertEmptyFile("1.out"); + + failure("-f requires an argument"); + assert(0 != systemf("%s -if 2.out 2>2.err", testprog)); + assertEmptyFile("2.out"); + + failure("-f requires an argument"); + assert(0 != systemf("%s -i -f 3.out 2>3.err", testprog)); + assertEmptyFile("3.out"); + + failure("--format requires an argument"); + assert(0 != systemf("%s -i --format 4.out 2>4.err", testprog)); + assertEmptyFile("4.out"); + + failure("--badopt is an invalid option"); + assert(0 != systemf("%s -i --badop 5.out 2>5.err", testprog)); + assertEmptyFile("5.out"); + + failure("--badopt is an invalid option"); + assert(0 != systemf("%s -i --badopt 6.out 2>6.err", testprog)); + assertEmptyFile("6.out"); + + failure("--n is ambiguous"); + assert(0 != systemf("%s -i --n 7.out 2>7.err", testprog)); + assertEmptyFile("7.out"); + + failure("--create forbids an argument"); + assert(0 != systemf("%s --create=arg 8.out 2>8.err", testprog)); + assertEmptyFile("8.out"); + + failure("-i with empty input should succeed"); + assert(0 == systemf("%s -i 9.out 2>9.err", testprog)); + assertEmptyFile("9.out"); + + failure("-o with empty input should succeed"); + assert(0 == systemf("%s -o 10.out 2>10.err", testprog)); + + failure("-i -p is nonsense"); + assert(0 != systemf("%s -i -p 11.out 2>11.err", testprog)); + assertEmptyFile("11.out"); + + failure("-p -i is nonsense"); + assert(0 != systemf("%s -p -i 12.out 2>12.err", testprog)); + assertEmptyFile("12.out"); + + failure("-i -o is nonsense"); + assert(0 != systemf("%s -i -o 13.out 2>13.err", testprog)); + assertEmptyFile("13.out"); + + failure("-o -i is nonsense"); + assert(0 != systemf("%s -o -i 14.out 2>14.err", testprog)); + assertEmptyFile("14.out"); + + failure("-o -p is nonsense"); + assert(0 != systemf("%s -o -p 15.out 2>15.err", testprog)); + assertEmptyFile("15.out"); + + failure("-p -o is nonsense"); + assert(0 != systemf("%s -p -o 16.out 2>16.err", testprog)); + assertEmptyFile("16.out"); + + failure("-p with empty input should fail"); + assert(0 != systemf("%s -p 17.out 2>17.err", testprog)); + assertEmptyFile("17.out"); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_format_newc.c b/libarchive/libarchive-2.7.1/cpio/test/test_format_newc.c new file mode 100644 index 0000000..0533364 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_format_newc.c @@ -0,0 +1,289 @@ +/*- + * 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: src/usr.bin/cpio/test/test_format_newc.c,v 1.2 2008/08/22 02:09:10 kientzle Exp $"); + +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, fs, ns; + 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 newc.out 2>newc.err", + testprog); + if (!assertEqualInt(r, 0)) + return; + + /* Verify that nothing went to stderr. */ + assertTextFileContents("2 blocks\n", "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 */ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Group members bits and others bits do not work. */ + assertEqualInt(0x8180, from_hex(e + 14, 8) & 0xffc0); /* Mode */ +#else + assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */ +#endif + 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 */ + fs = from_hex(e + 54, 8); + fs += 3 & -fs; + 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 */ + ns = from_hex(e + 94, 8); + ns += 3 & (-ns - 2); + 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 += 110 + fs + ns; + + /* "symlink" pointing to "file1" */ + assert(is_hex(e, 110)); + assertEqualMem(e + 0, "070701", 6); /* Magic */ + assert(is_hex(e + 6, 8)); /* ino */ +#if !defined(_WIN32) || defined(__CYGWIN__) + /* On Windows, symbolic link and group members bits and + * others bits do not work. */ + assertEqualInt(0xa1ff, from_hex(e + 14, 8)); /* Mode */ +#endif + 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. */ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Symbolic link does not work. */ + assertEqualMem(e + 54, "0000000a", 8); /* File size */ +#else + assertEqualMem(e + 54, "00000005", 8); /* File size */ +#endif + fs = from_hex(e + 54, 8); + fs += 3 & -fs; + 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 */ + ns = from_hex(e + 94, 8); + ns += 3 & (-ns - 2); + assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ + assertEqualMem(e + 110, "symlink\0\0\0", 10); /* Name contents */ +#if !defined(_WIN32) || defined(__CYGWIN__) + assertEqualMem(e + 110 + ns, "file1\0\0\0", 8); /* symlink target */ +#endif + e += 110 + fs + ns; + + /* "dir" */ + assert(is_hex(e, 110)); + assertEqualMem(e + 0, "070701", 6); /* Magic */ + assert(is_hex(e + 6, 8)); /* ino */ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Group members bits and others bits do not work. */ + assertEqualInt(0x41c0, from_hex(e + 14, 8) & 0xffc0); /* Mode */ +#else + /* Mode: sgid bit sometimes propagates from parent dirs, ignore it. */ + assertEqualInt(040775, from_hex(e + 14, 8) & ~02000); +#endif + assertEqualInt(from_hex(e + 22, 8), getuid()); /* uid */ + assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */ +#ifndef NLINKS_INACCURATE_FOR_DIRS + assertEqualMem(e + 38, "00000002", 8); /* nlink */ +#endif + 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 */ + fs = from_hex(e + 54, 8); + fs += 3 & -fs; + 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 */ + ns = from_hex(e + 94, 8); + ns += 3 & (-ns - 2); + assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ + assertEqualMem(e + 110, "dir\0\0\0", 6); /* Name contents */ + e += 110 + fs + ns; + + /* 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 */ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Group members bits and others bits do not work. */ + assertEqualInt(0x8180, from_hex(e + 14, 8) & 0xffc0); /* Mode */ +#else + assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */ +#endif + 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 */ + fs = from_hex(e + 54, 8); + fs += 3 & -fs; + 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 */ + ns = from_hex(e + 94, 8); + ns += 3 & (-ns - 2); + assertEqualInt(0, from_hex(e + 102, 8)); /* check field */ + assertEqualMem(e + 110, "hardlink\0\0", 10); /* Name contents */ + assertEqualMem(e + 110 + ns, "123456789\0\0\0", 12); /* File contents */ + e += 110 + ns + fs; + + /* 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); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat.c b/libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat.c new file mode 100644 index 0000000..f9604b9 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat.c @@ -0,0 +1,144 @@ +/*- + * 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: src/usr.bin/cpio/test/test_gcpio_compat.c,v 1.2 2008/08/22 02:27:06 kientzle Exp $"); + +static void +unpack_test(const char *from, const char *options, const char *se) +{ + struct stat st, st2; +#if !defined(_WIN32) || defined(__CYGWIN__) + char buff[128]; +#endif + 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. */ + failure("Error invoking %s -i %s < %s", testprog, options, from); + assertTextFileContents(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)); +#if defined(_WIN32) && !defined(__CYGWIN__) + assertEqualInt(0600, st.st_mode & 0700); +#else + assertEqualInt(0644, st.st_mode & 0777); +#endif + 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)); +#if defined(_WIN32) && !defined(__CYGWIN__) + assertEqualInt(0600, st2.st_mode & 0700); +#else + assertEqualInt(0644, st2.st_mode & 0777); +#endif + 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 !defined(_WIN32) || defined(__CYGWIN__) + 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"); + } + } +#endif + + /* dir */ + r = lstat("dir", &st); + if (r == 0) { + assertEqualInt(r, 0); + assert(S_ISDIR(st.st_mode)); +#if defined(_WIN32) && !defined(__CYGWIN__) + assertEqualInt(0700, st.st_mode & 0700); +#else + assertEqualInt(0775, st.st_mode & 0777); +#endif + } + + 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", "--no-preserve-owner", "1 block\n"); + unpack_test("test_gcpio_compat_ref.crc", "--no-preserve-owner", "2 blocks\n"); + unpack_test("test_gcpio_compat_ref.newc", "--no-preserve-owner", "2 blocks\n"); + /* gcpio-2.9 only reads 6 blocks here */ + unpack_test("test_gcpio_compat_ref.ustar", "--no-preserve-owner", "7 blocks\n"); + + umask(oldumask); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat_ref.bin.uu b/libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat_ref.bin.uu new file mode 100644 index 0000000..745d8ab --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_gcpio_compat_ref.bin.uu @@ -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`= 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); + assertTextFileContents("1 block\n", "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); + assertTextFileContents("1 block\n", "large.err"); + assertEqualInt(0, stat("large.cpio", &st)); + assertEqualInt(5120, st.st_size); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_C_upper.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_C_upper.c new file mode 100644 index 0000000..b15f887 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_C_upper.c @@ -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_C_upper) +{ + 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 -C; this should be 512 bytes. */ + r = systemf("echo file | %s -o > small.cpio 2>small.err", testprog); + assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "small.err"); + assertEqualInt(0, stat("small.cpio", &st)); + assertEqualInt(512, st.st_size); + + /* Create an archive with -C 513; this should be 513 bytes. */ + r = systemf("echo file | %s -o -C 513 > 513.cpio 2>513.err", + testprog); + assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "513.err"); + assertEqualInt(0, stat("513.cpio", &st)); + assertEqualInt(513, st.st_size); + + /* Create an archive with -C 12345; this should be 12345 bytes. */ + r = systemf("echo file | %s -o -C12345 > 12345.cpio 2>12345.err", + testprog); + assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "12345.err"); + assertEqualInt(0, stat("12345.cpio", &st)); + assertEqualInt(12345, st.st_size); + + /* Create an archive with invalid -C request */ + assert(0 != systemf("echo file | %s -o -C > bad.cpio 2>bad.err", + testprog)); + assertEmptyFile("bad.cpio"); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_L_upper.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_L_upper.c new file mode 100644 index 0000000..db5f642 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_L_upper.c @@ -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. + */ +#include "test.h" +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/test_option_L.c,v 1.2 2008/08/24 06:21:00 kientzle Exp $"); + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define CAT "type" +#else +#define CAT "cat" +#endif + +DEFINE_TEST(test_option_L_upper) +{ + 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)); +#if !defined(_WIN32) || defined(__CYGWIN__) + failure("Regular -p without -L should preserve symlinks."); + assert(S_ISLNK(st.st_mode)); +#endif + + r = systemf(CAT " filelist | %s -pd -L copy-L >copy-L.out 2>copy-L.err", testprog); + assertEqualInt(r, 0); + assertEmptyFile("copy-L.out"); + assertTextFileContents("1 block\n", "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)); +#if defined(_WIN32) && !defined(__CYGWIN__) + assertEqualInt(0, chdir("unpack")); + r = systemf("type ..\\archive.out | %s -i >unpack.out 2>unpack.err", testprog); + assertEqualInt(0, chdir("..")); +#else + r = systemf("cat archive.out | (cd unpack ; %s -i >unpack.out 2>unpack.err)", testprog); +#endif + failure("Error invoking %s -i", testprog); + assertEqualInt(r, 0); + assertEqualInt(0, lstat("unpack/symlink", &st)); +#if !defined(_WIN32) || defined(__CYGWIN__) + assert(S_ISLNK(st.st_mode)); +#endif + + 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)); +#if defined(_WIN32) && !defined(__CYGWIN__) + assertEqualInt(0, chdir("unpack-L")); + r = systemf("type ..\\archive-L.out | %s -i >unpack-L.out 2>unpack-L.err", testprog); + assertEqualInt(0, chdir("..")); +#else + r = systemf("cat archive-L.out | (cd unpack-L ; %s -i >unpack-L.out 2>unpack-L.err)", testprog); +#endif + 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)); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_Z_upper.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_Z_upper.c new file mode 100644 index 0000000..8117fee --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_Z_upper.c @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2003-2009 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_upper) +{ + 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) { + p = slurpfile(&s, "archive.err"); + p[s] = '\0'; + if (strstr(p, "not supported") != NULL) { + skipping("This version of bsdcpio was compiled " + "without compress support"); + } else { + /* Check that the archive file has a compress signature. */ + p = slurpfile(&s, "archive.out"); + assert(s > 2); + assertEqualMem(p, "\x1f\x9d", 2); + } + } +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_a.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_a.c new file mode 100644 index 0000000..d1fe5ff --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_a.c @@ -0,0 +1,163 @@ +/*- + * 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" +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#else +#include +#endif +__FBSDID("$FreeBSD: src/usr.bin/cpio/test/test_option_a.c,v 1.3 2008/08/24 06:21:00 kientzle Exp $"); + +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); + assertTextFileContents("1 block\n", "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); + assertTextFileContents("1 block\n", "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); + assertTextFileContents("1 block\n", "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); + assertTextFileContents("1 block\n", "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); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_c.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_c.c new file mode 100644 index 0000000..23eabff --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_c.c @@ -0,0 +1,227 @@ +/*- + * 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 basic.out 2>basic.err", testprog); + /* Verify that nothing went to stderr. */ + assertTextFileContents("1 block\n", "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); +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Group members bits and others bits do not work. */ + assertEqualMem(e + 18, "100666", 6); /* Mode */ +#else + assertEqualMem(e + 18, "100644", 6); /* Mode */ +#endif + 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 */ +#if !defined(_WIN32) || defined(__CYGWIN__) + /* On Windows, symbolic link and group members bits and + * others bits do not work. */ + assertEqualMem(e + 18, "120777", 6); /* Mode */ +#endif + 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 */ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* On Windows, symbolic link does not work. */ + assertEqualMem(e + 65, "00000000012", 11); /* File size */ +#else + assertEqualMem(e + 65, "00000000004", 11); /* File size */ +#endif + assertEqualMem(e + 76, "symlink\0", 8); /* Name contents */ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* On Windows, symbolic link does not work. */ + assertEqualMem(e + 84, "123456789\0", 10); /* File contents. */ + e += 94; +#else + assertEqualMem(e + 84, "file", 4); /* Symlink target. */ + e += 88; +#endif + + /* 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)); +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Group members bits and others bits do not work. */ + assertEqualMem(e + 18, "040777", 6); /* Mode */ +#else + /* Accept 042775 to accomodate systems where sgid bit propagates. */ + if (memcmp(e + 18, "042775", 6) != 0) + assertEqualMem(e + 18, "040775", 6); /* Mode */ +#endif + 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)); +#ifndef NLINKS_INACCURATE_FOR_DIRS + assertEqualMem(e + 36, "000002", 6); /* Nlink */ +#endif + 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); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_d.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_d.c new file mode 100644 index 0000000..cb422ae --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_d.c @@ -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); + assertTextFileContents("1 block\n", "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"); + assertTextFileContents("1 block\n", "err"); + /* And the file should be restored. */ + assertEqualInt(0, stat("dir/file", &st)); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_f.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_f.c new file mode 100644 index 0000000..9d6b24c --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_f.c @@ -0,0 +1,76 @@ +/*- + * 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", "--no-preserve-owner"); + 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. */ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Single quotes isn't used by command.exe. */ + unpack("t1", "--no-preserve-owner -f a*"); +#else + unpack("t1", "--no-preserve-owner -f 'a*'"); +#endif + 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. */ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Single quotes isn't used by command.exe. */ + unpack("t2", "--no-preserve-owner -f b*"); +#else + unpack("t2", "--no-preserve-owner -f 'b*'"); +#endif + 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)); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_f.cpio.uu b/libarchive/libarchive-2.7.1/cpio/test/test_option_f.cpio.uu new file mode 100644 index 0000000..42c63c3 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_f.cpio.uu @@ -0,0 +1,16 @@ +$FreeBSD$ +begin 644 test_option_f.cpio +M,#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"); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_l.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_l.c new file mode 100644 index 0000000..c6110fa --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_l.c @@ -0,0 +1,60 @@ +/*- + * 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, 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); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_m.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_m.c new file mode 100644 index 0000000..fc02d2e --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_m.c @@ -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 --no-preserve-owner -i < test_option_m.cpio >out 2>err", testprog); + now = time(NULL); + assertEqualInt(r, 0); + assertEmptyFile("out"); + assertTextFileContents("1 block\n", "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 --no-preserve-owner -im < test_option_m.cpio >out 2>err", testprog); + now = time(NULL); + assertEqualInt(r, 0); + assertEmptyFile("out"); + assertTextFileContents("1 block\n", "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); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_m.cpio.uu b/libarchive/libarchive-2.7.1/cpio/test/test_option_m.cpio.uu new file mode 100644 index 0000000..3d20023 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_m.cpio.uu @@ -0,0 +1,16 @@ +$FreeBSD$ +begin 644 test_option_m.cpio +M,#it.out 2>it.err", testprog); + assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "it.err"); + extract_reference_file("test_option_t.stdout"); + p = slurpfile(NULL, "test_option_t.stdout"); + assertTextFileContents(p, "it.out"); + free(p); + + /* We accept plain "-t" as a synonym for "-it" */ + r = systemf("%s -t < test_option_t.cpio >t.out 2>t.err", testprog); + assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "t.err"); + extract_reference_file("test_option_t.stdout"); + p = slurpfile(NULL, "test_option_t.stdout"); + assertTextFileContents(p, "t.out"); + free(p); + + /* But "-ot" is an error. */ + assert(0 != systemf("%s -ot < test_option_t.cpio >ot.out 2>ot.err", + testprog)); + assertEmptyFile("ot.out"); + + /* 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); + assertTextFileContents("1 block\n", "tv.err"); + extract_reference_file("test_option_tv.stdout"); + + /* This doesn't work because the usernames on different systems + * are different and cpio now looks up numeric UIDs on + * the local system. */ + /* assertEqualFile("tv.out", "test_option_tv.stdout"); */ + + /* List reference archive with numeric IDs, verify TOC is correct. */ + r = systemf("%s -itnv < test_option_t.cpio >itnv.out 2>itnv.err", + testprog); + assertEqualInt(r, 0); + assertTextFileContents("1 block\n", "itnv.err"); + extract_reference_file("test_option_tnv.stdout"); + /* This does work because numeric IDs come from archive. */ + /* Unfortunately, the timestamp still gets localized, so + * we can't just compare against a fixed result. */ + /* TODO: Fix this. */ + /* assertEqualFile("itnv.out", "test_option_tnv.stdout"); */ + + /* But "-n" without "-t" is an error. */ + assert(0 != systemf("%s -in < test_option_t.cpio >in.out 2>in.err", + testprog)); + assertEmptyFile("in.out"); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_t.cpio.uu b/libarchive/libarchive-2.7.1/cpio/test/test_option_t.cpio.uu new file mode 100644 index 0000000..055fe74 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_t.cpio.uu @@ -0,0 +1,16 @@ +$FreeBSD$ +begin 644 test_option_t.cpio +M,# +#else +#include +#endif +__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); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_version.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_version.c new file mode 100644 index 0000000..8a25248 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_version.c @@ -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. + */ +#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); +#if defined(_WIN32) && !defined(__CYGWIN__) + assertEqualMem(q, "\r\n", 2); +#else + assertEqualMem(q, "\n", 1); +#endif +} + + +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); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_y.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_y.c new file mode 100644 index 0000000..92280be --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_y.c @@ -0,0 +1,59 @@ +/*- + * 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: src/usr.bin/cpio/test/test_option_y.c,v 1.2 2008/08/24 06:21:00 kientzle Exp $"); + +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); + failure("-y (bzip) option seems to be broken"); + if (assertEqualInt(r, 0)) { + p = slurpfile(&s, "archive.err"); + p[s] = '\0'; + if (strstr(p, "bzip2 compression not supported") != NULL) { + skipping("This version of bsdcpio was compiled " + "without bzip2 support"); + } else { + assertTextFileContents("1 block\n", "archive.err"); + /* Check that the archive file has a bzip2 signature. */ + p = slurpfile(&s, "archive.out"); + assert(s > 2); + assertEqualMem(p, "BZh9", 4); + } + } +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_option_z.c b/libarchive/libarchive-2.7.1/cpio/test/test_option_z.c new file mode 100644 index 0000000..2057912 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_option_z.c @@ -0,0 +1,59 @@ +/*- + * 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) { + p = slurpfile(&s, "archive.err"); + p[s] = '\0'; + if (strstr(p, "gzip compression not supported") != NULL) { + skipping("This version of bsdcpio was compiled " + "without gzip support"); + } else { + /* Check that the archive file has a gzip signature. */ + p = slurpfile(&s, "archive.out"); + assert(s > 2); + assertEqualMem(p, "\x1f\x8b\x08\x00", 4); + } + } +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_owner_parse.c b/libarchive/libarchive-2.7.1/cpio/test/test_owner_parse.c new file mode 100644 index 0000000..1e9434f --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_owner_parse.c @@ -0,0 +1,112 @@ +/*- + * 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" + +#if defined(__CYGWIN__) +/* On cygwin, the Administrator user most likely exists (unless + * it has been renamed or is in a non-English localization), but + * its primary group membership depends on how the user set up + * their /etc/passwd. Likely values are 513 (None), 545 (Users), + * or 544 (Administrators). Just check for one of those... + * TODO: Handle non-English localizations...e.g. French 'Administrateur' + * Use CreateWellKnownSID() and LookupAccountName()? + */ +#define ROOT "Administrator" +#define ROOT_UID 500 +#define ROOT_GID1 513 +#define ROOT_GID2 545 +#define ROOT_GID3 544 +#else +#define ROOT "root" +#define ROOT_UID 0 +#define ROOT_GID 0 +#endif + + +DEFINE_TEST(test_owner_parse) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* TODO: Does this need cygwin style handling of uid/gid ? */ + skipping("Windows cannot handle uid/gid as UNIX like system"); +#else + int uid, gid; + + cpio_progname = "Ignore this message"; + + assertEqualInt(0, owner_parse(ROOT, &uid, &gid)); + assertEqualInt(ROOT_UID, uid); + assertEqualInt(-1, gid); + + + assertEqualInt(0, owner_parse(ROOT ":", &uid, &gid)); + assertEqualInt(ROOT_UID, uid); +#if defined(__CYGWIN__) + { + int gidIsOneOf = (ROOT_GID1 == gid) + || (ROOT_GID2 == gid) + || (ROOT_GID3 == gid); + assertEqualInt(1, gidIsOneOf); + } +#else + assertEqualInt(ROOT_GID, gid); +#endif + + assertEqualInt(0, owner_parse(ROOT ".", &uid, &gid)); + assertEqualInt(ROOT_UID, uid); +#if defined(__CYGWIN__) + { + int gidIsOneOf = (ROOT_GID1 == gid) + || (ROOT_GID2 == gid) + || (ROOT_GID3 == gid); + assertEqualInt(1, gidIsOneOf); + } +#else + assertEqualInt(ROOT_GID, gid); +#endif + + /* + * 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)); +#endif +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_passthrough_dotdot.c b/libarchive/libarchive-2.7.1/cpio/test/test_passthrough_dotdot.c new file mode 100644 index 0000000..d8d3fe1 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_passthrough_dotdot.c @@ -0,0 +1,93 @@ +/*- + * 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: src/usr.bin/cpio/test/test_passthrough_dotdot.c,v 1.4 2008/08/24 06:21:00 kientzle Exp $"); + +/* + * Verify that "cpio -p .." works. + */ + +DEFINE_TEST(test_passthrough_dotdot) +{ + struct stat st; + int fd, r; + int filelist; + int oldumask; + + oldumask = umask(0); + + /* + * Create an assortment of files on disk. + */ + filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + + /* Directory. */ + assertEqualInt(0, mkdir("dir", 0755)); + assertEqualInt(0, chdir("dir")); + + write(filelist, ".\n", 2); + + /* File with 10 bytes content. */ + fd = open("file", O_CREAT | O_WRONLY, 0642); + assert(fd >= 0); + assertEqualInt(10, write(fd, "123456789", 10)); + close(fd); + write(filelist, "file\n", 5); + + /* All done. */ + close(filelist); + + + /* + * Use cpio passthrough mode to copy files to another directory. + */ + r = systemf("%s -pdvm .. <../filelist >../stdout 2>../stderr", + testprog); + failure("Error invoking %s -pd ..", testprog); + assertEqualInt(r, 0); + + assertEqualInt(0, chdir("..")); + + /* Verify stderr and stdout. */ + assertTextFileContents("../.\n../file\n1 block\n", "stderr"); + assertEmptyFile("stdout"); + + /* Regular file. */ + r = lstat("file", &st); + failure("Failed to stat file, errno=%d", errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st.st_mode)); +#if defined(_WIN32) && !defined(__CYGWIN__) + assertEqualInt(0600, st.st_mode & 0700); +#else + assertEqualInt(0642, st.st_mode & 0777); +#endif + assertEqualInt(10, st.st_size); + assertEqualInt(1, st.st_nlink); + } + + umask(oldumask); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_passthrough_reverse.c b/libarchive/libarchive-2.7.1/cpio/test/test_passthrough_reverse.c new file mode 100644 index 0000000..37e2086 --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_passthrough_reverse.c @@ -0,0 +1,112 @@ +/*- + * 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: src/usr.bin/cpio/test/test_passthrough_reverse.c,v 1.2 2008/08/24 06:21:00 kientzle Exp $"); + +/* + * As reported by Bernd Walter: Some people are in the habit of + * using "find -d" to generate a list for cpio -p because that + * copies the top-level dir last, which preserves owner and mode + * information. That's not necessary for bsdcpio (libarchive defers + * restoring directory information), but bsdcpio should still generate + * the correct results with this usage. + */ + +DEFINE_TEST(test_passthrough_reverse) +{ + struct stat st; + int fd, r; + int filelist; + int oldumask; + + oldumask = umask(0); + + /* + * Create an assortment of files on disk. + */ + filelist = open("filelist", O_CREAT | O_WRONLY, 0644); + + /* Directory. */ + assertEqualInt(0, mkdir("dir", 0743)); + + /* File with 10 bytes content. */ + fd = open("dir/file", O_CREAT | O_WRONLY, 0644); + assert(fd >= 0); + assertEqualInt(10, write(fd, "123456789", 10)); + close(fd); + write(filelist, "dir/file\n", 9); + + /* Write dir last. */ + write(filelist, "dir\n", 4); + + /* All done. */ + close(filelist); + + + /* + * Use cpio passthrough mode to copy files to another directory. + */ + r = systemf("%s -pdvm out stdout 2>stderr", testprog); + failure("Error invoking %s -pd out", testprog); + assertEqualInt(r, 0); + + assertEqualInt(0, chdir("out")); + + /* Verify stderr and stdout. */ + assertTextFileContents("out/dir/file\nout/dir\n1 block\n", + "../stderr"); + assertEmptyFile("../stdout"); + + /* dir */ + r = lstat("dir", &st); + if (r == 0) { + assertEqualInt(r, 0); + assert(S_ISDIR(st.st_mode)); + failure("st.st_mode=0%o", st.st_mode); +#if defined(_WIN32) && !defined(__CYGWIN__) + assertEqualInt(0700, st.st_mode & 0700); +#else + assertEqualInt(0743, st.st_mode & 0777); +#endif + } + + + /* Regular file. */ + r = lstat("dir/file", &st); + failure("Failed to stat dir/file, errno=%d", errno); + assertEqualInt(r, 0); + if (r == 0) { + assert(S_ISREG(st.st_mode)); +#if defined(_WIN32) && !defined(__CYGWIN__) + assertEqualInt(0600, st.st_mode & 0700); +#else + assertEqualInt(0644, st.st_mode & 0777); +#endif + assertEqualInt(10, st.st_size); + assertEqualInt(1, st.st_nlink); + } + + umask(oldumask); +} diff --git a/libarchive/libarchive-2.7.1/cpio/test/test_pathmatch.c b/libarchive/libarchive-2.7.1/cpio/test/test_pathmatch.c new file mode 100644 index 0000000..a596eda --- /dev/null +++ b/libarchive/libarchive-2.7.1/cpio/test/test_pathmatch.c @@ -0,0 +1,243 @@ +/*- + * 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. + * + * TODO: Figure out if there's a good way to extend this to handle + * Windows paths that use '\' as a path separator. + */ + +DEFINE_TEST(test_pathmatch) +{ + assertEqualInt(1, pathmatch("a/b/c", "a/b/c", 0)); + assertEqualInt(0, pathmatch("a/b/", "a/b/c", 0)); + assertEqualInt(0, pathmatch("a/b", "a/b/c", 0)); + assertEqualInt(0, pathmatch("a/b/c", "a/b/", 0)); + assertEqualInt(0, pathmatch("a/b/c", "a/b", 0)); + + /* Empty pattern only matches empty string. */ + assertEqualInt(1, pathmatch("","", 0)); + assertEqualInt(0, pathmatch("","a", 0)); + 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)); + + /* Character classes */ + 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(0, pathmatch("abc[d-fh-k]", "abca", 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)); + + /* [] matches nothing, [!] is the same as ? */ + assertEqualInt(0, pathmatch("abc[]efg", "abcdefg", 0)); + assertEqualInt(0, pathmatch("abc[]efg", "abcqefg", 0)); + assertEqualInt(0, pathmatch("abc[]efg", "abcefg", 0)); + assertEqualInt(1, pathmatch("abc[!]efg", "abcdefg", 0)); + assertEqualInt(1, pathmatch("abc[!]efg", "abcqefg", 0)); + assertEqualInt(0, pathmatch("abc[!]efg", "abcefg", 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)); + assertEqualInt(1, pathmatch("abcd\\", "abcd\\", 0)); + assertEqualInt(0, pathmatch("abcd\\", "abcd\\[", 0)); + assertEqualInt(0, pathmatch("abcd\\", "abcde", 0)); + assertEqualInt(0, pathmatch("abcd\\[", "abcd\\", 0)); + + /* + * Because '.' and '/' have special meanings, we can + * identify many equivalent paths even if they're expressed + * differently. (But quoting a character with '\\' suppresses + * special meanings!) + */ + assertEqualInt(0, pathmatch("a/b/", "a/bc", 0)); + assertEqualInt(1, pathmatch("a/./b", "a/b", 0)); + assertEqualInt(0, pathmatch("a\\/./b", "a/b", 0)); + assertEqualInt(0, pathmatch("a/\\./b", "a/b", 0)); + assertEqualInt(0, pathmatch("a/.\\/b", "a/b", 0)); + assertEqualInt(0, pathmatch("a\\/\\.\\/b", "a/b", 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)); + 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)); + + /* Matches not anchored at beginning. */ + assertEqualInt(0, + pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_START)); + assertEqualInt(1, + pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_START)); + assertEqualInt(0, + pathmatch("^bcd", "abcd", PATHMATCH_NO_ANCHOR_START)); + assertEqualInt(1, + pathmatch("b/c/d", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); + assertEqualInt(0, + pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); + assertEqualInt(0, + pathmatch("^b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_START)); + + /* Matches not anchored at end. */ + assertEqualInt(0, + pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + pathmatch("abcd", "abcd", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + pathmatch("abcd", "abcd/", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + pathmatch("abcd", "abcd/.", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(0, + pathmatch("abc", "abcd", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + pathmatch("a/b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(0, + pathmatch("a/b/c$", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + pathmatch("a/b/c$", "a/b/c", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + pathmatch("a/b/c$", "a/b/c/", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + pathmatch("a/b/c/", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(0, + pathmatch("a/b/c/$", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + pathmatch("a/b/c/$", "a/b/c/", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(1, + pathmatch("a/b/c/$", "a/b/c", PATHMATCH_NO_ANCHOR_END)); + assertEqualInt(0, + pathmatch("b/c", "a/b/c/d", PATHMATCH_NO_ANCHOR_END)); +} -- cgit v1.2.3