libarchive 2.0

* libarchive_test program exercises many of the core features
  * Refactored old "read_extract" into new "archive_write_disk", which
    uses archive_write methods to put entries onto disk.  In particular,
    you can now use archive_write_disk to create objects on disk
    without having an archive available.
  * Pushed some security checks from bsdtar down into libarchive, where
    they can be better optimized.
  * Rearchitected the logic for creating objects on disk to reduce
    the number of system calls.  Several common cases now use a
    minimum number of system calls.
  * Virtualized some internal interfaces to provide a clearer separation
    of read and write handling and make it simpler to override key
    methods.
  * New "empty" format reader.
  * Corrected return types (this ABI breakage required the "2.0" version bump)
  * Many bug fixes.
This commit is contained in:
Tim Kientzle 2007-03-03 07:37:37 +00:00
parent 4fce38ec78
commit f81da3e584
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=167186
72 changed files with 7230 additions and 2458 deletions

View File

@ -9,14 +9,14 @@ LDADD= -lbz2 -lz
# Major: Bumped ONLY when API/ABI breakage happens (see SHLIB_MAJOR)
# Minor: Bumped when significant new features are added
# Revision: Bumped on any notable change
VERSION= 1.3.1
VERSION= 2.0.20
ARCHIVE_API_MAJOR!= echo ${VERSION} | sed -e 's/[^0-9]/./g' -e 's/\..*//'
ARCHIVE_API_MINOR!= echo ${VERSION} | sed -e 's/[^0-9]/./g' -e 's/[0-9]*\.//' -e 's/\..*//'
# FreeBSD SHLIB_MAJOR value is managed as part of the FreeBSD system.
# It has no real relation to the version number above.
SHLIB_MAJOR= 3
SHLIB_MAJOR= 4
CFLAGS+= -DPACKAGE_NAME=\"lib${LIB}\"
CFLAGS+= -DPACKAGE_VERSION=\"${VERSION}\"
@ -67,7 +67,10 @@ SRCS= archive.h \
archive_string.c \
archive_string_sprintf.c \
archive_util.c \
archive_virtual.c \
archive_write.c \
archive_write_disk.c \
archive_write_disk_set_standard_lookup.c \
archive_write_open_fd.c \
archive_write_open_file.c \
archive_write_open_filename.c \
@ -87,6 +90,7 @@ MAN= archive_entry.3 \
archive_read.3 \
archive_util.3 \
archive_write.3 \
archive_write_disk.3 \
libarchive.3 \
libarchive-formats.5 \
tar.5
@ -173,6 +177,7 @@ MLINKS+= archive_read.3 archive_read_support_format_cpio.3
MLINKS+= archive_read.3 archive_read_support_format_iso9660.3
MLINKS+= archive_read.3 archive_read_support_format_tar.3
MLINKS+= archive_read.3 archive_read_support_format_zip.3
MLINKS+= archive_util.3 archive_clear_error.3
MLINKS+= archive_util.3 archive_compression.3
MLINKS+= archive_util.3 archive_compression_name.3
MLINKS+= archive_util.3 archive_errno.3
@ -201,6 +206,15 @@ MLINKS+= archive_write.3 archive_write_set_compression_gzip.3
MLINKS+= archive_write.3 archive_write_set_format_pax.3
MLINKS+= archive_write.3 archive_write_set_format_shar.3
MLINKS+= archive_write.3 archive_write_set_format_ustar.3
MLINKS+= archive_write_disk.3 archive_write_disk_new.3
MLINKS+= archive_write_disk.3 archive_write_disk_set_group_lookup.3
MLINKS+= archive_write_disk.3 archive_write_disk_set_options.3
MLINKS+= archive_write_disk.3 archive_write_disk_set_skip_file.3
MLINKS+= archive_write_disk.3 archive_write_disk_set_standard_lookup.3
MLINKS+= archive_write_disk.3 archive_write_disk_set_user_lookup.3
MLINKS+= libarchive.3 archive.3
test:
cd ${.CURDIR}/test && make test
.include <bsd.lib.mk>

View File

@ -6,16 +6,16 @@ This is all under a BSD license. Use, enjoy, but don't blame me if it breaks!
Documentation:
* libarchive.3 gives an overview of the library as a whole
* archive_read.3 and archive_write.3 provide detailed calling
sequences for the read and write APIs
* archive_read.3, archive_write.3, and archive_write_disk.3 provide
detailed calling sequences for the read and write APIs
* archive_entry.3 details the "struct archive_entry" utility class
* libarchive-formats.5 documents the file formats supported by the library
* tar.5 provides some detailed information about a variety of different
"tar" formats.
You should also read the copious comments in "archive.h" and the source
code for the sample "bsdtar" program for more details. Please let me know
about any errors or omissions you find.
code for the sample "bsdtar" and "minitar" programs for more details.
Please let me know about any errors or omissions you find.
Currently, the library automatically detects and reads the following:
* gzip compression
@ -84,8 +84,10 @@ Notes:
a block of data in memory and add it to a tar archive without
first writing a temporary file. You can also read an entry from
an archive and write the data directly to a socket. If you want
to read/write entries to disk, there are convenience functions to
make this especially easy.
to read/write entries to disk, the archive_write_disk interface
treats a directory as if it were an archive so you can copy
from archive->disk using the same code you use for archive->archive
transfers.
* Note: "pax interchange format" is really an extended tar format,
despite what the name says.

View File

@ -37,7 +37,14 @@
#include <sys/types.h> /* Linux requires this for off_t */
@ARCHIVE_H_INCLUDE_INTTYPES_H@
#include <stdio.h> /* For FILE * */
#ifndef _WIN32
#include <unistd.h> /* For ssize_t and size_t */
#else
typedef long ssize_t;
typedef unsigned int uid_t;
typedef unsigned int gid_t;
typedef unsigned short mode_t;
#endif
#ifdef __cplusplus
extern "C" {
@ -59,6 +66,7 @@ extern "C" {
* 1 - Version tests are available.
* 2 - archive_{read,write}_close available separately from _finish.
* 3 - open_memory, open_memory2, open_FILE, open_fd available
* 5 - archive_write_disk interface available
*/
#define ARCHIVE_API_VERSION @ARCHIVE_API_MAJOR@
int archive_api_version(void);
@ -138,8 +146,17 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
* Top 16 bits identifies the format family (e.g., "tar"); lower
* 16 bits indicate the variant. This is updated by read_next_header.
* Note that the lower 16 bits will often vary from entry to entry.
* In some cases, this variation occurs as libarchive learns more about
* the archive (for example, later entries might utilize extensions that
* weren't necessary earlier in the archive; in this case, libarchive
* will change the format code to indicate the extended format that
* was used). In other cases, it's because different tools have
* modified the archive and so different parts of the archive
* actually have slightly different formts. (Both tar and cpio store
* format codes in each entry, so it is quite possible for each
* entry to be in a different format.)
*/
#define ARCHIVE_FORMAT_BASE_MASK 0xff0000U
#define ARCHIVE_FORMAT_BASE_MASK 0xff0000
#define ARCHIVE_FORMAT_CPIO 0x10000
#define ARCHIVE_FORMAT_CPIO_POSIX (ARCHIVE_FORMAT_CPIO | 1)
#define ARCHIVE_FORMAT_CPIO_BIN_LE (ARCHIVE_FORMAT_CPIO | 2)
@ -274,15 +291,28 @@ int archive_read_data_into_fd(struct archive *, int fd);
*/
/* The "flags" argument selects optional behavior, 'OR' the flags you want. */
/* TODO: The 'Default' comments here are not quite correct; clean this up. */
#define ARCHIVE_EXTRACT_OWNER (1) /* Default: owner/group not restored */
#define ARCHIVE_EXTRACT_PERM (2) /* Default: restore perm only for reg file*/
#define ARCHIVE_EXTRACT_TIME (4) /* Default: mod time not restored */
#define ARCHIVE_EXTRACT_NO_OVERWRITE (8) /* Default: Replace files on disk */
#define ARCHIVE_EXTRACT_UNLINK (16) /* Default: don't unlink existing files */
#define ARCHIVE_EXTRACT_ACL (32) /* Default: don't restore ACLs */
#define ARCHIVE_EXTRACT_FFLAGS (64) /* Default: don't restore fflags */
#define ARCHIVE_EXTRACT_XATTR (128) /* Default: don't restore xattrs */
/* Default: Do not try to set owner/group. */
#define ARCHIVE_EXTRACT_OWNER (1)
/* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */
#define ARCHIVE_EXTRACT_PERM (2)
/* Default: Do not restore mtime/atime. */
#define ARCHIVE_EXTRACT_TIME (4)
/* Default: Replace existing files. */
#define ARCHIVE_EXTRACT_NO_OVERWRITE (8)
/* Default: Try create first, unlink only if create fails with EEXIST. */
#define ARCHIVE_EXTRACT_UNLINK (16)
/* Default: Do not restore ACLs. */
#define ARCHIVE_EXTRACT_ACL (32)
/* Default: Do not restore fflags. */
#define ARCHIVE_EXTRACT_FFLAGS (64)
/* Default: Do not restore xattrs. */
#define ARCHIVE_EXTRACT_XATTR (128)
/* Default: Do not try to guard against extracts redirected by symlinks. */
/* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */
#define ARCHIVE_EXTRACT_SECURE_SYMLINKS (256)
/* Default: Do not reject entries with '..' as path elements. */
#define ARCHIVE_EXTRACT_SECURE_NODOTDOT (512)
int archive_read_extract(struct archive *, struct archive_entry *,
int flags);
@ -298,7 +328,13 @@ void archive_read_extract_set_skip_file(struct archive *,
int archive_read_close(struct archive *);
/* Release all resources and destroy the object. */
/* Note that archive_read_finish will call archive_read_close for you. */
#if ARCHIVE_API_VERSION > 1
int archive_read_finish(struct archive *);
#else
/* Temporarily allow library to compile with either 1.x or 2.0 API. */
/* Erroneously declared to return void in libarchive 1.x */
void archive_read_finish(struct archive *);
#endif
/*-
* To create an archive:
@ -362,11 +398,76 @@ int archive_write_open_memory(struct archive *,
*/
int archive_write_header(struct archive *,
struct archive_entry *);
/* TODO: should be ssize_t, but that might require .so version bump? */
#if ARCHIVE_API_VERSION > 1
ssize_t archive_write_data(struct archive *, const void *, size_t);
#else
/* Temporarily allow library to compile with either 1.x or 2.0 API. */
/* This was erroneously declared to return "int" in libarchive 1.x. */
int archive_write_data(struct archive *, const void *, size_t);
#endif
ssize_t archive_write_data_block(struct archive *, const void *, size_t, off_t);
int archive_write_finish_entry(struct archive *);
int archive_write_close(struct archive *);
#if ARCHIVE_API_VERSION > 1
int archive_write_finish(struct archive *);
#else
/* Temporarily allow library to compile with either 1.x or 2.0 API. */
/* Return value was incorrect in libarchive 1.x. */
void archive_write_finish(struct archive *);
#endif
/*-
* To create objects on disk:
* 1) Ask archive_write_disk_new for a new archive_write_disk object.
* 2) Set any global properties. In particular, you should set
* the compression and format to use.
* 3) For each entry:
* - construct an appropriate struct archive_entry structure
* - archive_write_header to create the file/dir/etc on disk
* - archive_write_data to write the entry data
* 4) archive_write_finish to cleanup the writer and release resources
*
* In particular, you can use this in conjunction with archive_read()
* to pull entries out of an archive and create them on disk.
*/
struct archive *archive_write_disk_new(void);
/* This file will not be overwritten. */
int archive_write_disk_set_skip_file(struct archive *,
dev_t, ino_t);
/* Set flags to control how the next item gets created. */
int archive_write_disk_set_options(struct archive *,
int flags);
/*
* The lookup functions are given uname/uid (or gname/gid) pairs and
* return a uid (gid) suitable for this system. These are used for
* restoring ownership and for setting ACLs. The default functions
* are naive, they just return the uid/gid. These are small, so reasonable
* for applications that don't need to preserve ownership; they
* are probably also appropriate for applications that are doing
* same-system backup and restore.
*/
/*
* The "standard" lookup functions use common system calls to lookup
* the uname/gname, falling back to the uid/gid if the names can't be
* found. They cache lookups and are reasonably fast, but can be very
* large, so they are not used unless you ask for them. In
* particular, these match the specifications of POSIX "pax" and old
* POSIX "tar".
*/
int archive_write_disk_set_standard_lookup(struct archive *);
/*
* If neither the default (naive) nor the standard (big) functions suit
* your needs, you can write your own and register them. Be sure to
* include a cleanup function if you have allocated private data.
*/
int archive_write_disk_set_group_lookup(struct archive *,
void *private_data,
gid_t (*loookup)(void *, const char *gname, gid_t gid),
void (*cleanup)(void *));
int archive_write_disk_set_user_lookup(struct archive *,
void *private_data,
uid_t (*)(void *, const char *uname, uid_t uid),
void (*cleanup)(void *));
/*
* Accessor functions to read/set various information in
@ -383,6 +484,7 @@ int archive_errno(struct archive *);
const char *archive_error_string(struct archive *);
const char *archive_format_name(struct archive *);
int archive_format(struct archive *);
void archive_clear_error(struct archive *);
void archive_set_error(struct archive *, int _err, const char *fmt, ...);
#ifdef __cplusplus

View File

@ -46,6 +46,7 @@
.Nm archive_entry_copy_hardlink_w ,
.Nm archive_entry_copy_pathname_w ,
.Nm archive_entry_copy_stat ,
.Nm archive_entry_copy_symlink ,
.Nm archive_entry_copy_symlink_w ,
.Nm archive_entry_copy_uname_w ,
.Nm archive_entry_dev ,
@ -124,6 +125,8 @@
.Ft void
.Fn archive_entry_copy_stat "struct archive_entry *" "const struct stat *"
.Ft void
.Fn archive_entry_copy_symlink "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_copy_symlink_w "struct archive_entry *" "const wchar_t *"
.Ft void
.Fn archive_entry_copy_uname_w "struct archive_entry *" "const wchar_t *"

View File

@ -33,6 +33,28 @@
#define ARCHIVE_WRITE_MAGIC (0xb0c5c0deU)
#define ARCHIVE_READ_MAGIC (0xdeb0c5U)
#define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
#define ARCHIVE_STATE_ANY 0xFFFFU
#define ARCHIVE_STATE_NEW 1U
#define ARCHIVE_STATE_HEADER 2U
#define ARCHIVE_STATE_DATA 4U
#define ARCHIVE_STATE_DATA_END 8U
#define ARCHIVE_STATE_EOF 0x10U
#define ARCHIVE_STATE_CLOSED 0x20U
#define ARCHIVE_STATE_FATAL 0x8000U
struct archive_vtable {
int (*archive_write_close)(struct archive *);
int (*archive_write_finish)(struct archive *);
int (*archive_write_header)(struct archive *,
struct archive_entry *);
int (*archive_write_finish_entry)(struct archive *);
ssize_t (*archive_write_data)(struct archive *,
const void *, size_t);
ssize_t (*archive_write_data_block)(struct archive *,
const void *, size_t, off_t);
};
struct archive {
/*
@ -44,202 +66,34 @@ struct archive {
unsigned magic;
unsigned state;
struct archive_entry *entry;
uid_t user_uid; /* UID of current user. */
/* Dev/ino of the archive being read/written. */
dev_t skip_file_dev;
ino_t skip_file_ino;
/* Utility: Pointer to a block of nulls. */
const unsigned char *nulls;
size_t null_length;
/*
* Used by archive_read_data() to track blocks and copy
* data to client buffers, filling gaps with zero bytes.
* Some public API functions depend on the "real" type of the
* archive object.
*/
const char *read_data_block;
off_t read_data_offset;
off_t read_data_output_offset;
size_t read_data_remaining;
struct archive_vtable *vtable;
/* Callbacks to open/read/write/close archive stream. */
archive_open_callback *client_opener;
archive_read_callback *client_reader;
archive_skip_callback *client_skipper;
archive_write_callback *client_writer;
archive_close_callback *client_closer;
void *client_data;
int archive_format;
const char *archive_format_name;
/*
* Blocking information. Note that bytes_in_last_block is
* misleadingly named; I should find a better name. These
* control the final output from all compressors, including
* compression_none.
*/
int bytes_per_block;
int bytes_in_last_block;
/*
* These control whether data within a gzip/bzip2 compressed
* stream gets padded or not. If pad_uncompressed is set,
* the data will be padded to a full block before being
* compressed. The pad_uncompressed_byte determines the value
* that will be used for padding. Note that these have no
* effect on compression "none."
*/
int pad_uncompressed;
int pad_uncompressed_byte; /* TODO: Support this. */
int compression_code; /* Currently active compression. */
const char *compression_name;
/* Position in UNCOMPRESSED data stream. */
off_t file_position;
/* Position in COMPRESSED data stream. */
off_t raw_position;
/* File offset of beginning of most recently-read header. */
off_t header_position;
/*
* Detection functions for decompression: bid functions are
* given a block of data from the beginning of the stream and
* can bid on whether or not they support the data stream.
* General guideline: bid the number of bits that you actually
* test, e.g., 16 if you test a 2-byte magic value. The
* highest bidder will have their init function invoked, which
* can set up pointers to specific handlers.
*
* On write, the client just invokes an archive_write_set function
* which sets up the data here directly.
*/
int compression_code; /* Currently active compression. */
const char *compression_name;
struct {
int (*bid)(const void *buff, size_t);
int (*init)(struct archive *, const void *buff, size_t);
} decompressors[4];
/* Read/write data stream (with compression). */
void *compression_data; /* Data for (de)compressor. */
int (*compression_init)(struct archive *); /* Initialize. */
int (*compression_finish)(struct archive *);
int (*compression_write)(struct archive *, const void *, size_t);
/*
* Read uses a peek/consume I/O model: the decompression code
* returns a pointer to the requested block and advances the
* file position only when requested by a consume call. This
* reduces copying and also simplifies look-ahead for format
* detection.
*/
ssize_t (*compression_read_ahead)(struct archive *,
const void **, size_t request);
ssize_t (*compression_read_consume)(struct archive *, size_t);
off_t (*compression_skip)(struct archive *, off_t);
/*
* Format detection is mostly the same as compression
* detection, with two significant differences: The bidders
* use the read_ahead calls above to examine the stream rather
* than having the supervisor hand them a block of data to
* examine, and the auction is repeated for every header.
* Winning bidders should set the archive_format and
* archive_format_name appropriately. Bid routines should
* check archive_format and decline to bid if the format of
* the last header was incompatible.
*
* Again, write support is considerably simpler because there's
* no need for an auction.
*/
int archive_format;
const char *archive_format_name;
struct archive_format_descriptor {
int (*bid)(struct archive *);
int (*read_header)(struct archive *, struct archive_entry *);
int (*read_data)(struct archive *, const void **, size_t *, off_t *);
int (*read_data_skip)(struct archive *);
int (*cleanup)(struct archive *);
void *format_data; /* Format-specific data for readers. */
} formats[8];
struct archive_format_descriptor *format; /* Active format. */
/*
* Storage for format-specific data. Note that there can be
* multiple format readers active at one time, so we need to
* allow for multiple format readers to have their data
* available. The pformat_data slot here is the solution: on
* read, it is guaranteed to always point to a void* variable
* that the format can use.
*/
void **pformat_data; /* Pointer to current format_data. */
void *format_data; /* Used by writers. */
/*
* Pointers to format-specific functions for writing. They're
* initialized by archive_write_set_format_XXX() calls.
*/
int (*format_init)(struct archive *); /* Only used on write. */
int (*format_finish)(struct archive *);
int (*format_finish_entry)(struct archive *);
int (*format_write_header)(struct archive *,
struct archive_entry *);
ssize_t (*format_write_data)(struct archive *,
const void *buff, size_t);
/*
* Various information needed by archive_extract.
*/
struct extract *extract;
void (*extract_progress)(void *);
void *extract_progress_user_data;
int (*cleanup_archive_extract)(struct archive *);
int archive_error_number;
const char *error;
struct archive_string error_string;
};
#define ARCHIVE_STATE_ANY 0xFFFFU
#define ARCHIVE_STATE_NEW 1U
#define ARCHIVE_STATE_HEADER 2U
#define ARCHIVE_STATE_DATA 4U
#define ARCHIVE_STATE_EOF 8U
#define ARCHIVE_STATE_CLOSED 0x10U
#define ARCHIVE_STATE_FATAL 0x8000U
/* Check magic value and state; exit if it isn't valid. */
void __archive_check_magic(struct archive *, unsigned magic,
unsigned state, const char *func);
int __archive_read_register_format(struct archive *a,
void *format_data,
int (*bid)(struct archive *),
int (*read_header)(struct archive *, struct archive_entry *),
int (*read_data)(struct archive *, const void **, size_t *, off_t *),
int (*read_data_skip)(struct archive *),
int (*cleanup)(struct archive *));
int __archive_read_register_compression(struct archive *a,
int (*bid)(const void *, size_t),
int (*init)(struct archive *, const void *, size_t));
void __archive_errx(int retvalue, const char *msg);
#define err_combine(a,b) ((a) < (b) ? (a) : (b))
/*
* Utility function to format a USTAR header into a buffer. If
* "strict" is set, this tries to create the absolutely most portable
* version of a ustar header. If "strict" is set to 0, then it will
* relax certain requirements.
*
* Generally, format-specific declarations don't belong in this
* header; this is a rare example of a function that is shared by
* two very similar formats (ustar and pax).
*/
int
__archive_write_format_header_ustar(struct archive *, char buff[512],
struct archive_entry *, int tartype, int strict);
#endif

View File

@ -113,7 +113,7 @@
.Fn archive_read_extract_set_progress_callback "struct archive *" "void (*func)(void *)" "void *user_data"
.Ft int
.Fn archive_read_close "struct archive *"
.Ft void
.Ft int
.Fn archive_read_finish "struct archive *"
.Sh DESCRIPTION
These functions provide a complete API for reading streaming archives.
@ -148,7 +148,7 @@ ustar, pax interchange format, and many common variants.
For convenience,
.Fn archive_read_support_format_all
enables support for all available formats.
Note that there is no default.
Only empty archives are supported by default.
.It Fn archive_read_open
The same as
.Fn archive_read_open2 ,
@ -233,58 +233,27 @@ Note that the client is responsible for sizing the buffer appropriately.
A convenience function that repeatedly calls
.Fn archive_read_data_block
to copy the entire entry to the provided file descriptor.
.It Fn archive_read_extract_set_skip_file
This function records the device and inode numbers
of a file that should not be restored.
This is a convenience that prevents
.It Fn archive_read_extract , Fn archive_read_extract_set_skip_file
A convenience function that wraps the corresponding
.Xr archive_write_disk 3
interfaces.
The first call to
.Fn archive_read_extract
from restoring a file over the archive itself.
.It Fn archive_read_extract
A convenience function that recreates the specified object on
disk and reads the entry data into that object.
The filename, permissions, and other critical information
are taken from the provided
.Va archive_entry
object.
creates a restore object using
.Xr archive_write_disk_new 3
and
.Xr archive_write_disk_set_standard_lookup 3 ,
then transparently invokes
.Xr archive_write_disk_set_options 3 ,
.Xr archive_write_header 3 ,
.Xr archive_write_data 3 ,
and
.Xr archive_write_finish_entry 3
to create the entry on disk and copy data into it.
The
.Va flags
argument modifies how the object is recreated.
It consists of a bitwise OR of one or more of the following values:
.Bl -tag -compact -width "indent"
.It Cm ARCHIVE_EXTRACT_OWNER
The user and group IDs should be set on the restored file.
By default, the user and group IDs are not restored.
.It Cm ARCHIVE_EXTRACT_PERM
The permissions (mode bits) should be restored for all objects.
By default, permissions are only restored for regular files.
.It Cm ARCHIVE_EXTRACT_TIME
The timestamps (mtime, ctime, and atime) should be restored.
By default, they are ignored.
Note that restoring of atime is not currently supported.
.It Cm ARCHIVE_EXTRACT_NO_OVERWRITE
Existing files on disk will not be overwritten.
By default, existing regular files are truncated and overwritten;
existing directories will have their permissions updated;
other pre-existing objects are unlinked and recreated from scratch.
.It Cm ARCHIVE_EXTRACT_UNLINK
Existing files on disk will be unlinked and recreated from scratch.
By default, existing files are truncated and rewritten, but
the file is not recreated.
In particular, the default behavior does not break existing hard links.
.It Cm ARCHIVE_EXTRACT_ACL
Attempt to restore ACLs.
By default, extended ACLs are ignored.
.It Cm ARCHIVE_EXTRACT_FFLAGS
Attempt to restore extended file flags.
By default, file flags are ignored.
.El
Note that not all attributes are set immediately;
some attributes are cached in memory and written to disk only
when the archive is closed.
(For example, read-only directories are initially created
writable so that files within those directories can be
restored.
The final permissions are set when the archive is closed.)
argument is passed unmodified to
.Xr archiv_write_disk_set_options 3 .
.It Fn archive_read_extract_set_progress_callback
Sets a pointer to a user-defined callback that can be used
for updating progress displays during extraction.
@ -300,6 +269,12 @@ Complete the archive and invoke the close callback.
Invokes
.Fn archive_read_close
if it was not invoked manually, then release all resources.
Note: In libarchive 1.x, this function was declared to return
.Ft void ,
which made it impossible to detect certain errors when
.Fn archive_read_close
was invoked implicitly from this function.
The declaration is corrected beginning with libarchive 2.0.
.El
.Pp
Note that the library determines most of the relevant information about
@ -523,26 +498,6 @@ The
library was written by
.An Tim Kientzle Aq kientzle@acm.org .
.Sh BUGS
Directories are actually extracted in two distinct phases.
Directories are created during
.Fn archive_read_extract ,
but final permissions are not set until
.Fn archive_read_close .
This separation is necessary to correctly handle borderline
cases such as a non-writable directory containing
files, but can cause unexpected results.
In particular, directory permissions are not fully
restored until the archive is closed.
If you use
.Xr chdir 2
to change the current directory between calls to
.Fn archive_read_extract
or before calling
.Fn archive_read_close ,
you may confuse the permission-setting logic with
the result that directory permissions are restored
incorrectly.
.Pp
Many traditional archiver programs treat
empty files as valid empty archives.
For example, many implementations of

View File

@ -51,9 +51,10 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_read_private.h"
static int choose_decompressor(struct archive *, const void*, size_t);
static int choose_format(struct archive *);
static int choose_decompressor(struct archive_read *, const void*, size_t);
static int choose_format(struct archive_read *);
/*
* Allocate, initialize and return a struct archive object.
@ -61,44 +62,45 @@ static int choose_format(struct archive *);
struct archive *
archive_read_new(void)
{
struct archive *a;
struct archive_read *a;
unsigned char *nulls;
a = (struct archive *)malloc(sizeof(*a));
a = (struct archive_read *)malloc(sizeof(*a));
if (a == NULL)
return (NULL);
memset(a, 0, sizeof(*a));
a->user_uid = geteuid();
a->magic = ARCHIVE_READ_MAGIC;
a->archive.magic = ARCHIVE_READ_MAGIC;
a->bytes_per_block = ARCHIVE_DEFAULT_BYTES_PER_BLOCK;
a->null_length = 1024;
nulls = (unsigned char *)malloc(a->null_length);
if (nulls == NULL) {
archive_set_error(a, ENOMEM, "Can't allocate archive object 'nulls' element");
archive_set_error(&a->archive, ENOMEM,
"Can't allocate archive object 'nulls' element");
free(a);
return (NULL);
}
memset(nulls, 0, a->null_length);
a->nulls = nulls;
a->state = ARCHIVE_STATE_NEW;
a->archive.state = ARCHIVE_STATE_NEW;
a->entry = archive_entry_new();
/* We always support uncompressed archives. */
archive_read_support_compression_none((struct archive*)a);
archive_read_support_compression_none(&a->archive);
return (a);
return (&a->archive);
}
/*
* Record the do-not-extract-to file. This belongs in archive_read_extract.c.
*/
void
archive_read_extract_set_skip_file(struct archive *a, dev_t d, ino_t i)
archive_read_extract_set_skip_file(struct archive *_a, dev_t d, ino_t i)
{
__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_extract_set_skip_file");
struct archive_read *a = (struct archive_read *)_a;
__archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY,
"archive_read_extract_set_skip_file");
a->skip_file_dev = d;
a->skip_file_ino = i;
}
@ -119,18 +121,19 @@ archive_read_open(struct archive *a, void *client_data,
}
int
archive_read_open2(struct archive *a, void *client_data,
archive_read_open2(struct archive *_a, void *client_data,
archive_open_callback *client_opener,
archive_read_callback *client_reader,
archive_skip_callback *client_skipper,
archive_close_callback *client_closer)
{
struct archive_read *a = (struct archive_read *)_a;
const void *buffer;
ssize_t bytes_read;
int high_bidder;
int e;
__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_open");
__archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_open");
if (client_reader == NULL)
__archive_errx(1,
@ -150,22 +153,22 @@ archive_read_open2(struct archive *a, void *client_data,
/* Open data source. */
if (client_opener != NULL) {
e =(client_opener)(a, client_data);
e =(client_opener)(&a->archive, client_data);
if (e != 0) {
/* If the open failed, call the closer to clean up. */
if (client_closer)
(client_closer)(a, client_data);
(client_closer)(&a->archive, client_data);
return (e);
}
}
/* Read first block now for format detection. */
bytes_read = (client_reader)(a, client_data, &buffer);
bytes_read = (client_reader)(&a->archive, client_data, &buffer);
if (bytes_read < 0) {
/* If the first read fails, close before returning error. */
if (client_closer)
(client_closer)(a, client_data);
(client_closer)(&a->archive, client_data);
/* client_reader should have already set error information. */
return (ARCHIVE_FATAL);
}
@ -186,7 +189,7 @@ archive_read_open2(struct archive *a, void *client_data,
e = (a->decompressors[high_bidder].init)(a, buffer, bytes_read);
if (e == ARCHIVE_OK)
a->state = ARCHIVE_STATE_HEADER;
a->archive.state = ARCHIVE_STATE_HEADER;
return (e);
}
@ -196,7 +199,8 @@ archive_read_open2(struct archive *a, void *client_data,
* wants to handle this stream. Return index of winning bidder.
*/
static int
choose_decompressor(struct archive *a, const void *buffer, size_t bytes_read)
choose_decompressor(struct archive_read *a,
const void *buffer, size_t bytes_read)
{
int decompression_slots, i, bid, best_bid, best_bid_slot;
@ -231,7 +235,7 @@ choose_decompressor(struct archive *a, const void *buffer, size_t bytes_read)
* support this stream.
*/
if (best_bid < 1) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized archive format");
return (ARCHIVE_FATAL);
}
@ -243,28 +247,30 @@ choose_decompressor(struct archive *a, const void *buffer, size_t bytes_read)
* Read header of next entry.
*/
int
archive_read_next_header(struct archive *a, struct archive_entry **entryp)
archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_entry *entry;
int slot, ret;
__archive_check_magic(a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_read_next_header");
__archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_read_next_header");
*entryp = NULL;
entry = a->entry;
archive_entry_clear(entry);
archive_string_empty(&a->error_string);
archive_clear_error(&a->archive);
/*
* If client didn't consume entire data, skip any remainder
* (This is especially important for GNU incremental directories.)
*/
if (a->state == ARCHIVE_STATE_DATA) {
ret = archive_read_data_skip(a);
if (a->archive.state == ARCHIVE_STATE_DATA) {
ret = archive_read_data_skip(&a->archive);
if (ret == ARCHIVE_EOF) {
archive_set_error(a, EIO, "Premature end-of-file.");
a->state = ARCHIVE_STATE_FATAL;
archive_set_error(&a->archive, EIO, "Premature end-of-file.");
a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
if (ret != ARCHIVE_OK)
@ -272,11 +278,11 @@ archive_read_next_header(struct archive *a, struct archive_entry **entryp)
}
/* Record start-of-header. */
a->header_position = a->file_position;
a->header_position = a->archive.file_position;
slot = choose_format(a);
if (slot < 0) {
a->state = ARCHIVE_STATE_FATAL;
a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
a->format = &(a->formats[slot]);
@ -290,18 +296,18 @@ archive_read_next_header(struct archive *a, struct archive_entry **entryp)
*/
switch (ret) {
case ARCHIVE_EOF:
a->state = ARCHIVE_STATE_EOF;
a->archive.state = ARCHIVE_STATE_EOF;
break;
case ARCHIVE_OK:
a->state = ARCHIVE_STATE_DATA;
a->archive.state = ARCHIVE_STATE_DATA;
break;
case ARCHIVE_WARN:
a->state = ARCHIVE_STATE_DATA;
a->archive.state = ARCHIVE_STATE_DATA;
break;
case ARCHIVE_RETRY:
break;
case ARCHIVE_FATAL:
a->state = ARCHIVE_STATE_FATAL;
a->archive.state = ARCHIVE_STATE_FATAL;
break;
}
@ -316,7 +322,7 @@ archive_read_next_header(struct archive *a, struct archive_entry **entryp)
* the next entry. Return index of winning bidder.
*/
static int
choose_format(struct archive *a)
choose_format(struct archive_read *a)
{
int slots;
int i;
@ -356,7 +362,7 @@ choose_format(struct archive *a)
* can't support this stream.
*/
if (best_bid < 1) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized archive format");
return (ARCHIVE_FATAL);
}
@ -369,8 +375,11 @@ choose_format(struct archive *a)
* the last header started.
*/
int64_t
archive_read_header_position(struct archive *a)
archive_read_header_position(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
__archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_header_position");
return (a->header_position);
}
@ -386,8 +395,9 @@ archive_read_header_position(struct archive *a)
* to read a single entry body.
*/
ssize_t
archive_read_data(struct archive *a, void *buff, size_t s)
archive_read_data(struct archive *_a, void *buff, size_t s)
{
struct archive_read *a = (struct archive_read *)_a;
char *dest;
size_t bytes_read;
size_t len;
@ -398,7 +408,7 @@ archive_read_data(struct archive *a, void *buff, size_t s)
while (s > 0) {
if (a->read_data_remaining <= 0) {
r = archive_read_data_block(a,
r = archive_read_data_block(&a->archive,
(const void **)&a->read_data_block,
&a->read_data_remaining,
&a->read_data_offset);
@ -414,7 +424,7 @@ archive_read_data(struct archive *a, void *buff, size_t s)
}
if (a->read_data_offset < a->read_data_output_offset) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Encountered out-of-order sparse blocks");
return (ARCHIVE_RETRY);
}
@ -459,19 +469,22 @@ archive_read_data(struct archive *a, void *buff, size_t s)
* Skip over all remaining data in this entry.
*/
int
archive_read_data_skip(struct archive *a)
archive_read_data_skip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
int r;
const void *buff;
size_t size;
off_t offset;
__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_skip");
__archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
"archive_read_data_skip");
if (a->format->read_data_skip != NULL)
r = (a->format->read_data_skip)(a);
else {
while ((r = archive_read_data_block(a, &buff, &size, &offset))
while ((r = archive_read_data_block(&a->archive,
&buff, &size, &offset))
== ARCHIVE_OK)
;
}
@ -479,7 +492,7 @@ archive_read_data_skip(struct archive *a)
if (r == ARCHIVE_EOF)
r = ARCHIVE_OK;
a->state = ARCHIVE_STATE_HEADER;
a->archive.state = ARCHIVE_STATE_HEADER;
return (r);
}
@ -492,13 +505,15 @@ archive_read_data_skip(struct archive *a)
* the end of entry is encountered.
*/
int
archive_read_data_block(struct archive *a,
archive_read_data_block(struct archive *_a,
const void **buff, size_t *size, off_t *offset)
{
__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_block");
struct archive_read *a = (struct archive_read *)_a;
__archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
"archive_read_data_block");
if (a->format->read_data == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: "
"No format_read_data_block function registered");
return (ARCHIVE_FATAL);
@ -515,12 +530,14 @@ archive_read_data_block(struct archive *a,
* initialization.
*/
int
archive_read_close(struct archive *a)
archive_read_close(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_close");
a->state = ARCHIVE_STATE_CLOSED;
__archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_close");
a->archive.state = ARCHIVE_STATE_CLOSED;
/* Call cleanup functions registered by optional components. */
if (a->cleanup_archive_extract != NULL)
@ -541,15 +558,23 @@ archive_read_close(struct archive *a)
/*
* Release memory and other resources.
*/
#if ARCHIVE_API_VERSION > 1
int
#else
/* Temporarily allow library to compile with either 1.x or 2.0 API. */
void
archive_read_finish(struct archive *a)
#endif
archive_read_finish(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
int i;
int slots;
int r = ARCHIVE_OK;
__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_finish");
if (a->state != ARCHIVE_STATE_CLOSED)
archive_read_close(a);
__archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY,
"archive_read_finish");
if (a->archive.state != ARCHIVE_STATE_CLOSED)
r = archive_read_close(&a->archive);
/* Cleanup format-specific data. */
slots = sizeof(a->formats) / sizeof(a->formats[0]);
@ -561,11 +586,14 @@ archive_read_finish(struct archive *a)
/* Casting a pointer to int allows us to remove 'const.' */
free((void *)(uintptr_t)(const void *)a->nulls);
archive_string_free(&a->error_string);
archive_string_free(&a->archive.error_string);
if (a->entry)
archive_entry_free(a->entry);
a->magic = 0;
a->archive.magic = 0;
free(a);
#if ARCHIVE_API_VERSION > 1
return (r);
#endif
}
/*
@ -573,17 +601,19 @@ archive_read_finish(struct archive *a)
* initialization functions.
*/
int
__archive_read_register_format(struct archive *a,
__archive_read_register_format(struct archive_read *a,
void *format_data,
int (*bid)(struct archive *),
int (*read_header)(struct archive *, struct archive_entry *),
int (*read_data)(struct archive *, const void **, size_t *, off_t *),
int (*read_data_skip)(struct archive *),
int (*cleanup)(struct archive *))
int (*bid)(struct archive_read *),
int (*read_header)(struct archive_read *, struct archive_entry *),
int (*read_data)(struct archive_read *, const void **, size_t *, off_t *),
int (*read_data_skip)(struct archive_read *),
int (*cleanup)(struct archive_read *))
{
int i, number_slots;
__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_register_format");
__archive_check_magic(&a->archive,
ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
"__archive_read_register_format");
number_slots = sizeof(a->formats) / sizeof(a->formats[0]);
@ -610,13 +640,15 @@ __archive_read_register_format(struct archive *a,
* initialization functions.
*/
int
__archive_read_register_compression(struct archive *a,
__archive_read_register_compression(struct archive_read *a,
int (*bid)(const void *, size_t),
int (*init)(struct archive *, const void *, size_t))
int (*init)(struct archive_read *, const void *, size_t))
{
int i, number_slots;
__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_register_compression");
__archive_check_magic(&a->archive,
ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
"__archive_read_register_compression");
number_slots = sizeof(a->decompressors) / sizeof(a->decompressors[0]);

View File

@ -80,8 +80,6 @@ archive_read_data_into_fd(struct archive *a, int fd)
total_written += bytes_written;
p += bytes_written;
size -= bytes_written;
if (a->extract_progress != NULL)
(*a->extract_progress)(a->extract_progress_user_data);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,188 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED
#define ARCHIVE_READ_PRIVATE_H_INCLUDED
#include "archive.h"
#include "archive_string.h"
#include "archive_private.h"
struct archive_read {
struct archive archive;
struct archive_entry *entry;
/* Dev/ino of the archive being read/written. */
dev_t skip_file_dev;
ino_t skip_file_ino;
/* Utility: Pointer to a block of nulls. */
const unsigned char *nulls;
size_t null_length;
/*
* Used by archive_read_data() to track blocks and copy
* data to client buffers, filling gaps with zero bytes.
*/
const char *read_data_block;
off_t read_data_offset;
off_t read_data_output_offset;
size_t read_data_remaining;
/* Callbacks to open/read/write/close archive stream. */
archive_open_callback *client_opener;
archive_read_callback *client_reader;
archive_skip_callback *client_skipper;
archive_write_callback *client_writer;
archive_close_callback *client_closer;
void *client_data;
/*
* Blocking information. Note that bytes_in_last_block is
* misleadingly named; I should find a better name. These
* control the final output from all compressors, including
* compression_none.
*/
int bytes_per_block;
int bytes_in_last_block;
/*
* These control whether data within a gzip/bzip2 compressed
* stream gets padded or not. If pad_uncompressed is set,
* the data will be padded to a full block before being
* compressed. The pad_uncompressed_byte determines the value
* that will be used for padding. Note that these have no
* effect on compression "none."
*/
int pad_uncompressed;
int pad_uncompressed_byte; /* TODO: Support this. */
/* File offset of beginning of most recently-read header. */
off_t header_position;
/*
* Detection functions for decompression: bid functions are
* given a block of data from the beginning of the stream and
* can bid on whether or not they support the data stream.
* General guideline: bid the number of bits that you actually
* test, e.g., 16 if you test a 2-byte magic value. The
* highest bidder will have their init function invoked, which
* can set up pointers to specific handlers.
*
* On write, the client just invokes an archive_write_set function
* which sets up the data here directly.
*/
struct {
int (*bid)(const void *buff, size_t);
int (*init)(struct archive_read *, const void *buff, size_t);
} decompressors[4];
/* Read/write data stream (with compression). */
void *compression_data; /* Data for (de)compressor. */
int (*compression_init)(struct archive_read *); /* Initialize. */
int (*compression_finish)(struct archive_read *);
int (*compression_write)(struct archive_read *, const void *, size_t);
/*
* Read uses a peek/consume I/O model: the decompression code
* returns a pointer to the requested block and advances the
* file position only when requested by a consume call. This
* reduces copying and also simplifies look-ahead for format
* detection.
*/
ssize_t (*compression_read_ahead)(struct archive_read *,
const void **, size_t request);
ssize_t (*compression_read_consume)(struct archive_read *, size_t);
off_t (*compression_skip)(struct archive_read *, off_t);
/*
* Format detection is mostly the same as compression
* detection, with two significant differences: The bidders
* use the read_ahead calls above to examine the stream rather
* than having the supervisor hand them a block of data to
* examine, and the auction is repeated for every header.
* Winning bidders should set the archive_format and
* archive_format_name appropriately. Bid routines should
* check archive_format and decline to bid if the format of
* the last header was incompatible.
*
* Again, write support is considerably simpler because there's
* no need for an auction.
*/
struct archive_format_descriptor {
int (*bid)(struct archive_read *);
int (*read_header)(struct archive_read *, struct archive_entry *);
int (*read_data)(struct archive_read *, const void **, size_t *, off_t *);
int (*read_data_skip)(struct archive_read *);
int (*cleanup)(struct archive_read *);
void *format_data; /* Format-specific data for readers. */
} formats[8];
struct archive_format_descriptor *format; /* Active format. */
/*
* Storage for format-specific data. Note that there can be
* multiple format readers active at one time, so we need to
* allow for multiple format readers to have their data
* available. The pformat_data slot here is the solution: on
* read, it is guaranteed to always point to a void* variable
* that the format can use.
*/
void **pformat_data; /* Pointer to current format_data. */
void *format_data; /* Used by writers. */
/*
* Pointers to format-specific functions for writing. They're
* initialized by archive_write_set_format_XXX() calls.
*/
int (*format_init)(struct archive *); /* Only used on write. */
int (*format_finish)(struct archive *);
int (*format_finish_entry)(struct archive *);
int (*format_write_header)(struct archive *,
struct archive_entry *);
ssize_t (*format_write_data)(struct archive *,
const void *buff, size_t);
/*
* Various information needed by archive_extract.
*/
struct extract *extract;
int (*cleanup_archive_extract)(struct archive_read *);
};
int __archive_read_register_format(struct archive_read *a,
void *format_data,
int (*bid)(struct archive_read *),
int (*read_header)(struct archive_read *, struct archive_entry *),
int (*read_data)(struct archive_read *, const void **, size_t *, off_t *),
int (*read_data_skip)(struct archive_read *),
int (*cleanup)(struct archive_read *));
int __archive_read_register_compression(struct archive_read *a,
int (*bid)(const void *, size_t),
int (*init)(struct archive_read *, const void *, size_t));
#endif

View File

@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
#include "archive_read_private.h"
#if HAVE_BZLIB_H
struct private_data {
@ -56,19 +57,20 @@ struct private_data {
int64_t total_out;
};
static int finish(struct archive *);
static ssize_t read_ahead(struct archive *, const void **, size_t);
static ssize_t read_consume(struct archive *, size_t);
static int drive_decompressor(struct archive *a, struct private_data *);
static int finish(struct archive_read *);
static ssize_t read_ahead(struct archive_read *, const void **, size_t);
static ssize_t read_consume(struct archive_read *, size_t);
static int drive_decompressor(struct archive_read *a, struct private_data *);
#endif
/* These two functions are defined even if we lack bzlib. See below. */
static int bid(const void *, size_t);
static int init(struct archive *, const void *, size_t);
static int init(struct archive_read *, const void *, size_t);
int
archive_read_support_compression_bzip2(struct archive *a)
archive_read_support_compression_bzip2(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
return (__archive_read_register_compression(a, bid, init));
}
@ -152,19 +154,19 @@ init(struct archive *a, const void *buff, size_t n)
* Setup the callbacks.
*/
static int
init(struct archive *a, const void *buff, size_t n)
init(struct archive_read *a, const void *buff, size_t n)
{
struct private_data *state;
int ret;
a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
a->compression_name = "bzip2";
a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
a->archive.compression_name = "bzip2";
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for %s decompression",
a->compression_name);
a->archive.compression_name);
return (ARCHIVE_FATAL);
}
memset(state, 0, sizeof(*state));
@ -176,9 +178,9 @@ init(struct archive *a, const void *buff, size_t n)
state->stream.avail_out = state->uncompressed_buffer_size;
if (state->uncompressed_buffer == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate %s decompression buffers",
a->compression_name);
a->archive.compression_name);
free(state);
return (ARCHIVE_FATAL);
}
@ -215,25 +217,26 @@ init(struct archive *a, const void *buff, size_t n)
}
/* Library setup failed: Clean up. */
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Internal error initializing %s library", a->compression_name);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing %s library",
a->archive.compression_name);
free(state->uncompressed_buffer);
free(state);
/* Override the error message if we know what really went wrong. */
switch (ret) {
case BZ_PARAM_ERROR:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid setup parameter");
break;
case BZ_MEM_ERROR:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"out of memory");
break;
case BZ_CONFIG_ERROR:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"mis-compiled library");
break;
@ -247,7 +250,7 @@ init(struct archive *a, const void *buff, size_t n)
* as necessary.
*/
static ssize_t
read_ahead(struct archive *a, const void **p, size_t min)
read_ahead(struct archive_read *a, const void **p, size_t min)
{
struct private_data *state;
int read_avail, was_avail, ret;
@ -255,7 +258,7 @@ read_ahead(struct archive *a, const void **p, size_t min)
state = (struct private_data *)a->compression_data;
was_avail = -1;
if (!a->client_reader) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No read callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@ -289,12 +292,12 @@ read_ahead(struct archive *a, const void **p, size_t min)
* Mark a previously-returned block of data as read.
*/
static ssize_t
read_consume(struct archive *a, size_t n)
read_consume(struct archive_read *a, size_t n)
{
struct private_data *state;
state = (struct private_data *)a->compression_data;
a->file_position += n;
a->archive.file_position += n;
state->read_next += n;
if (state->read_next > state->stream.next_out)
__archive_errx(1, "Request to consume too many "
@ -306,7 +309,7 @@ read_consume(struct archive *a, size_t n)
* Clean up the decompressor.
*/
static int
finish(struct archive *a)
finish(struct archive_read *a)
{
struct private_data *state;
int ret;
@ -317,8 +320,9 @@ finish(struct archive *a)
case BZ_OK:
break;
default:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Failed to clean up %s compressor", a->compression_name);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Failed to clean up %s compressor",
a->archive.compression_name);
ret = ARCHIVE_FATAL;
}
@ -327,7 +331,7 @@ finish(struct archive *a)
a->compression_data = NULL;
if (a->client_closer != NULL)
(a->client_closer)(a, a->client_data);
(a->client_closer)(&a->archive, a->client_data);
return (ret);
}
@ -337,7 +341,7 @@ finish(struct archive *a)
* blocks as necessary.
*/
static int
drive_decompressor(struct archive *a, struct private_data *state)
drive_decompressor(struct archive_read *a, struct private_data *state)
{
ssize_t ret;
int decompressed, total_decompressed;
@ -346,7 +350,7 @@ drive_decompressor(struct archive *a, struct private_data *state)
total_decompressed = 0;
for (;;) {
if (state->stream.avail_in == 0) {
ret = (a->client_reader)(a, a->client_data,
ret = (a->client_reader)(&a->archive, a->client_data,
(const void **)&state->stream.next_in);
if (ret < 0) {
/*
@ -356,12 +360,12 @@ drive_decompressor(struct archive *a, struct private_data *state)
goto fatal;
}
if (ret == 0 && total_decompressed == 0) {
archive_set_error(a, EIO,
archive_set_error(&a->archive, EIO,
"Premature end of %s compressed data",
a->compression_name);
a->archive.compression_name);
return (ARCHIVE_FATAL);
}
a->raw_position += ret;
a->archive.raw_position += ret;
state->stream.avail_in = ret;
}
@ -393,8 +397,8 @@ drive_decompressor(struct archive *a, struct private_data *state)
/* Return a fatal error. */
fatal:
archive_set_error(a, ARCHIVE_ERRNO_MISC, "%s decompression failed",
a->compression_name);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"%s decompression failed", a->archive.compression_name);
return (ARCHIVE_FATAL);
}

View File

@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
#include "archive_read_private.h"
/*
* Because LZW decompression is pretty simple, I've just implemented
@ -133,16 +134,17 @@ struct private_data {
};
static int bid(const void *, size_t);
static int finish(struct archive *);
static int init(struct archive *, const void *, size_t);
static ssize_t read_ahead(struct archive *, const void **, size_t);
static ssize_t read_consume(struct archive *, size_t);
static int getbits(struct archive *, struct private_data *, int n);
static int next_code(struct archive *a, struct private_data *state);
static int finish(struct archive_read *);
static int init(struct archive_read *, const void *, size_t);
static ssize_t read_ahead(struct archive_read *, const void **, size_t);
static ssize_t read_consume(struct archive_read *, size_t);
static int getbits(struct archive_read *, struct private_data *, int n);
static int next_code(struct archive_read *a, struct private_data *state);
int
archive_read_support_compression_compress(struct archive *a)
archive_read_support_compression_compress(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
return (__archive_read_register_compression(a, bid, init));
}
@ -187,13 +189,13 @@ bid(const void *buff, size_t len)
* Setup the callbacks.
*/
static int
init(struct archive *a, const void *buff, size_t n)
init(struct archive_read *a, const void *buff, size_t n)
{
struct private_data *state;
int code;
a->compression_code = ARCHIVE_COMPRESSION_COMPRESS;
a->compression_name = "compress (.Z)";
a->archive.compression_code = ARCHIVE_COMPRESSION_COMPRESS;
a->archive.compression_name = "compress (.Z)";
a->compression_read_ahead = read_ahead;
a->compression_read_consume = read_consume;
@ -202,9 +204,9 @@ init(struct archive *a, const void *buff, size_t n)
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for %s decompression",
a->compression_name);
a->archive.compression_name);
return (ARCHIVE_FATAL);
}
memset(state, 0, sizeof(*state));
@ -214,9 +216,9 @@ init(struct archive *a, const void *buff, size_t n)
state->uncompressed_buffer = malloc(state->uncompressed_buffer_size);
if (state->uncompressed_buffer == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate %s decompression buffers",
a->compression_name);
a->archive.compression_name);
goto fatal;
}
@ -235,7 +237,7 @@ init(struct archive *a, const void *buff, size_t n)
* blocks and gzip and compress are both enabled.
* You can't distinguish gzip and compress only from
* the first byte. */
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Compress signature did not match.");
goto fatal;
}
@ -270,7 +272,7 @@ init(struct archive *a, const void *buff, size_t n)
* as necessary.
*/
static ssize_t
read_ahead(struct archive *a, const void **p, size_t min)
read_ahead(struct archive_read *a, const void **p, size_t min)
{
struct private_data *state;
int read_avail, was_avail, ret;
@ -278,7 +280,7 @@ read_ahead(struct archive *a, const void **p, size_t min)
state = (struct private_data *)a->compression_data;
was_avail = -1;
if (!a->client_reader) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No read callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@ -325,12 +327,12 @@ read_ahead(struct archive *a, const void **p, size_t min)
* Mark a previously-returned block of data as read.
*/
static ssize_t
read_consume(struct archive *a, size_t n)
read_consume(struct archive_read *a, size_t n)
{
struct private_data *state;
state = (struct private_data *)a->compression_data;
a->file_position += n;
a->archive.file_position += n;
state->read_next += n;
if (state->read_next > state->next_out)
__archive_errx(1, "Request to consume too many "
@ -342,7 +344,7 @@ read_consume(struct archive *a, size_t n)
* Clean up the decompressor.
*/
static int
finish(struct archive *a)
finish(struct archive_read *a)
{
struct private_data *state;
int ret = ARCHIVE_OK;
@ -357,7 +359,7 @@ finish(struct archive *a)
a->compression_data = NULL;
if (a->client_closer != NULL)
ret = (a->client_closer)(a, a->client_data);
ret = (a->client_closer)(&a->archive, a->client_data);
return (ret);
}
@ -368,7 +370,7 @@ finish(struct archive *a)
* format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.
*/
static int
next_code(struct archive *a, struct private_data *state)
next_code(struct archive_read *a, struct private_data *state)
{
int code, newcode;
@ -412,7 +414,7 @@ next_code(struct archive *a, struct private_data *state)
if (code > state->free_ent) {
/* An invalid code is a fatal error. */
archive_set_error(a, -1, "Invalid compressed data");
archive_set_error(&a->archive, -1, "Invalid compressed data");
return (ARCHIVE_FATAL);
}
@ -456,7 +458,7 @@ next_code(struct archive *a, struct private_data *state)
* -1 indicates end of available data.
*/
static int
getbits(struct archive *a, struct private_data *state, int n)
getbits(struct archive_read *a, struct private_data *state, int n)
{
int code, ret;
static const int mask[] = {
@ -467,13 +469,13 @@ getbits(struct archive *a, struct private_data *state, int n)
while (state->bits_avail < n) {
if (state->avail_in <= 0) {
ret = (a->client_reader)(a, a->client_data,
ret = (a->client_reader)(&a->archive, a->client_data,
(const void **)&state->next_in);
if (ret < 0)
return (ARCHIVE_FATAL);
if (ret == 0)
return (ARCHIVE_EOF);
a->raw_position += ret;
a->archive.raw_position += ret;
state->avail_in = ret;
}
state->bit_buffer |= *state->next_in++ << state->bits_avail;

View File

@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
#include "archive_read_private.h"
#ifdef HAVE_ZLIB_H
struct private_data {
@ -58,19 +59,20 @@ struct private_data {
char header_done;
};
static int finish(struct archive *);
static ssize_t read_ahead(struct archive *, const void **, size_t);
static ssize_t read_consume(struct archive *, size_t);
static int drive_decompressor(struct archive *a, struct private_data *);
static int finish(struct archive_read *);
static ssize_t read_ahead(struct archive_read *, const void **, size_t);
static ssize_t read_consume(struct archive_read *, size_t);
static int drive_decompressor(struct archive_read *a, struct private_data *);
#endif
/* These two functions are defined even if we lack zlib. See below. */
static int bid(const void *, size_t);
static int init(struct archive *, const void *, size_t);
static int init(struct archive_read *, const void *, size_t);
int
archive_read_support_compression_gzip(struct archive *a)
archive_read_support_compression_gzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
return (__archive_read_register_compression(a, bid, init));
}
@ -135,7 +137,7 @@ bid(const void *buff, size_t len)
* archives and emit a useful message.
*/
static int
init(struct archive *a, const void *buff, size_t n)
init(struct archive_read *a, const void *buff, size_t n)
{
(void)a; /* UNUSED */
(void)buff; /* UNUSED */
@ -153,19 +155,19 @@ init(struct archive *a, const void *buff, size_t n)
* Setup the callbacks.
*/
static int
init(struct archive *a, const void *buff, size_t n)
init(struct archive_read *a, const void *buff, size_t n)
{
struct private_data *state;
int ret;
a->compression_code = ARCHIVE_COMPRESSION_GZIP;
a->compression_name = "gzip";
a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
a->archive.compression_name = "gzip";
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for %s decompression",
a->compression_name);
a->archive.compression_name);
return (ARCHIVE_FATAL);
}
memset(state, 0, sizeof(*state));
@ -180,9 +182,9 @@ init(struct archive *a, const void *buff, size_t n)
state->stream.avail_out = state->uncompressed_buffer_size;
if (state->uncompressed_buffer == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate %s decompression buffers",
a->compression_name);
a->archive.compression_name);
free(state);
return (ARCHIVE_FATAL);
}
@ -220,25 +222,26 @@ init(struct archive *a, const void *buff, size_t n)
}
/* Library setup failed: Clean up. */
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Internal error initializing %s library", a->compression_name);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing %s library",
a->archive.compression_name);
free(state->uncompressed_buffer);
free(state);
/* Override the error message if we know what really went wrong. */
switch (ret) {
case Z_STREAM_ERROR:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid setup parameter");
break;
case Z_MEM_ERROR:
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Internal error initializing compression library: "
"out of memory");
break;
case Z_VERSION_ERROR:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid library version");
break;
@ -252,7 +255,7 @@ init(struct archive *a, const void *buff, size_t n)
* as necessary.
*/
static ssize_t
read_ahead(struct archive *a, const void **p, size_t min)
read_ahead(struct archive_read *a, const void **p, size_t min)
{
struct private_data *state;
int read_avail, was_avail, ret;
@ -260,7 +263,7 @@ read_ahead(struct archive *a, const void **p, size_t min)
state = (struct private_data *)a->compression_data;
was_avail = -1;
if (!a->client_reader) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No read callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@ -294,12 +297,12 @@ read_ahead(struct archive *a, const void **p, size_t min)
* Mark a previously-returned block of data as read.
*/
static ssize_t
read_consume(struct archive *a, size_t n)
read_consume(struct archive_read *a, size_t n)
{
struct private_data *state;
state = (struct private_data *)a->compression_data;
a->file_position += n;
a->archive.file_position += n;
state->read_next += n;
if (state->read_next > state->stream.next_out)
__archive_errx(1, "Request to consume too many "
@ -311,7 +314,7 @@ read_consume(struct archive *a, size_t n)
* Clean up the decompressor.
*/
static int
finish(struct archive *a)
finish(struct archive_read *a)
{
struct private_data *state;
int ret;
@ -322,8 +325,9 @@ finish(struct archive *a)
case Z_OK:
break;
default:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Failed to clean up %s compressor", a->compression_name);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Failed to clean up %s compressor",
a->archive.compression_name);
ret = ARCHIVE_FATAL;
}
@ -332,7 +336,7 @@ finish(struct archive *a)
a->compression_data = NULL;
if (a->client_closer != NULL)
(a->client_closer)(a, a->client_data);
(a->client_closer)(&a->archive, a->client_data);
return (ret);
}
@ -342,7 +346,7 @@ finish(struct archive *a)
* blocks as necessary.
*/
static int
drive_decompressor(struct archive *a, struct private_data *state)
drive_decompressor(struct archive_read *a, struct private_data *state)
{
ssize_t ret;
int decompressed, total_decompressed;
@ -356,7 +360,7 @@ drive_decompressor(struct archive *a, struct private_data *state)
total_decompressed = 0;
for (;;) {
if (state->stream.avail_in == 0) {
ret = (a->client_reader)(a, a->client_data,
ret = (a->client_reader)(&a->archive, a->client_data,
(const void **)&state->stream.next_in);
if (ret < 0) {
/*
@ -366,12 +370,12 @@ drive_decompressor(struct archive *a, struct private_data *state)
goto fatal;
}
if (ret == 0 && total_decompressed == 0) {
archive_set_error(a, EIO,
archive_set_error(&a->archive, EIO,
"Premature end of %s compressed data",
a->compression_name);
a->archive.compression_name);
return (ARCHIVE_FATAL);
}
a->raw_position += ret;
a->archive.raw_position += ret;
state->stream.avail_in = ret;
}
@ -520,7 +524,7 @@ drive_decompressor(struct archive *a, struct private_data *state)
return (ARCHIVE_OK);
default:
/* Any other return value is an error. */
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"gzip decompression failed (%s)",
state->stream.msg);
goto fatal;
@ -531,8 +535,8 @@ drive_decompressor(struct archive *a, struct private_data *state)
/* Return a fatal error. */
fatal:
archive_set_error(a, ARCHIVE_ERRNO_MISC, "%s decompression failed",
a->compression_name);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"%s decompression failed", a->archive.compression_name);
return (ARCHIVE_FATAL);
}

View File

@ -26,7 +26,6 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
#include <assert.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@ -45,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
#include "archive_read_private.h"
struct archive_decompress_none {
char *buffer;
@ -75,18 +75,19 @@ struct archive_decompress_none {
#define minimum(a, b) (a < b ? a : b)
static int archive_decompressor_none_bid(const void *, size_t);
static int archive_decompressor_none_finish(struct archive *);
static int archive_decompressor_none_init(struct archive *,
static int archive_decompressor_none_finish(struct archive_read *);
static int archive_decompressor_none_init(struct archive_read *,
const void *, size_t);
static ssize_t archive_decompressor_none_read_ahead(struct archive *,
static ssize_t archive_decompressor_none_read_ahead(struct archive_read *,
const void **, size_t);
static ssize_t archive_decompressor_none_read_consume(struct archive *,
static ssize_t archive_decompressor_none_read_consume(struct archive_read *,
size_t);
static off_t archive_decompressor_none_skip(struct archive *, off_t);
static off_t archive_decompressor_none_skip(struct archive_read *, off_t);
int
archive_read_support_compression_none(struct archive *a)
archive_read_support_compression_none(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
return (__archive_read_register_compression(a,
archive_decompressor_none_bid,
archive_decompressor_none_init));
@ -105,16 +106,16 @@ archive_decompressor_none_bid(const void *buff, size_t len)
}
static int
archive_decompressor_none_init(struct archive *a, const void *buff, size_t n)
archive_decompressor_none_init(struct archive_read *a, const void *buff, size_t n)
{
struct archive_decompress_none *state;
a->compression_code = ARCHIVE_COMPRESSION_NONE;
a->compression_name = "none";
a->archive.compression_code = ARCHIVE_COMPRESSION_NONE;
a->archive.compression_name = "none";
state = (struct archive_decompress_none *)malloc(sizeof(*state));
if (!state) {
archive_set_error(a, ENOMEM, "Can't allocate input data");
archive_set_error(&a->archive, ENOMEM, "Can't allocate input data");
return (ARCHIVE_FATAL);
}
memset(state, 0, sizeof(*state));
@ -124,7 +125,7 @@ archive_decompressor_none_init(struct archive *a, const void *buff, size_t n)
state->next = state->buffer;
if (state->buffer == NULL) {
free(state);
archive_set_error(a, ENOMEM, "Can't allocate input buffer");
archive_set_error(&a->archive, ENOMEM, "Can't allocate input buffer");
return (ARCHIVE_FATAL);
}
@ -149,7 +150,7 @@ archive_decompressor_none_init(struct archive *a, const void *buff, size_t n)
* buffer to combine reads.
*/
static ssize_t
archive_decompressor_none_read_ahead(struct archive *a, const void **buff,
archive_decompressor_none_read_ahead(struct archive_read *a, const void **buff,
size_t min)
{
struct archive_decompress_none *state;
@ -217,7 +218,8 @@ archive_decompressor_none_read_ahead(struct archive *a, const void **buff,
* char ** should be compatible, but they
* aren't, hence the cast.
*/
bytes_read = (a->client_reader)(a, a->client_data,
bytes_read = (a->client_reader)(&a->archive,
a->client_data,
(const void **)&state->client_buff);
if (bytes_read < 0) { /* Read error. */
state->client_total = state->client_avail = 0;
@ -231,7 +233,7 @@ archive_decompressor_none_read_ahead(struct archive *a, const void **buff,
state->end_of_file = 1;
break;
}
a->raw_position += bytes_read;
a->archive.raw_position += bytes_read;
state->client_total = bytes_read;
state->client_avail = state->client_total;
state->client_next = state->client_buff;
@ -248,7 +250,7 @@ archive_decompressor_none_read_ahead(struct archive *a, const void **buff,
* request.
*/
static ssize_t
archive_decompressor_none_read_consume(struct archive *a, size_t request)
archive_decompressor_none_read_consume(struct archive_read *a, size_t request)
{
struct archive_decompress_none *state;
@ -262,7 +264,7 @@ archive_decompressor_none_read_consume(struct archive *a, size_t request)
state->client_next += request;
state->client_avail -= request;
}
a->file_position += request;
a->archive.file_position += request;
return (request);
}
@ -272,7 +274,7 @@ archive_decompressor_none_read_consume(struct archive *a, size_t request)
* read_ahead, which does not guarantee a minimum count.
*/
static off_t
archive_decompressor_none_skip(struct archive *a, off_t request)
archive_decompressor_none_skip(struct archive_read *a, off_t request)
{
struct archive_decompress_none *state;
off_t bytes_skipped, total_bytes_skipped = 0;
@ -306,8 +308,8 @@ archive_decompressor_none_skip(struct archive *a, off_t request)
#else
if (a->client_skipper != NULL) {
#endif
bytes_skipped = (a->client_skipper)(a, a->client_data,
request);
bytes_skipped = (a->client_skipper)(&a->archive,
a->client_data, request);
if (bytes_skipped < 0) { /* error */
state->client_total = state->client_avail = 0;
state->client_next = state->client_buff = NULL;
@ -315,10 +317,10 @@ archive_decompressor_none_skip(struct archive *a, off_t request)
return (bytes_skipped);
}
total_bytes_skipped += bytes_skipped;
a->file_position += bytes_skipped;
a->archive.file_position += bytes_skipped;
request -= bytes_skipped;
state->client_next = state->client_buff;
a->raw_position += bytes_skipped;
a->archive.raw_position += bytes_skipped;
state->client_avail = state->client_total = 0;
}
/*
@ -336,23 +338,21 @@ archive_decompressor_none_skip(struct archive *a, off_t request)
return (bytes_read);
if (bytes_read == 0) {
/* We hit EOF before we satisfied the skip request. */
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated input file (need to skip %jd bytes)",
(intmax_t)request);
return (ARCHIVE_FATAL);
}
assert(bytes_read >= 0); /* precondition for cast below */
min = (size_t)(minimum(bytes_read, request));
bytes_read = archive_decompressor_none_read_consume(a, min);
total_bytes_skipped += bytes_read;
request -= bytes_read;
}
assert(request == 0);
return (total_bytes_skipped);
}
static int
archive_decompressor_none_finish(struct archive *a)
archive_decompressor_none_finish(struct archive_read *a)
{
struct archive_decompress_none *state;
@ -361,6 +361,6 @@ archive_decompressor_none_finish(struct archive *a)
free(state);
a->compression_data = NULL;
if (a->client_closer != NULL)
return ((a->client_closer)(a, a->client_data));
return ((a->client_closer)(&a->archive, a->client_data));
return (ARCHIVE_OK);
}

View File

@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_read_private.h"
struct cpio_bin_header {
unsigned char c_magic[2];
@ -108,7 +109,7 @@ struct links_entry {
#define CPIO_MAGIC 0x13141516
struct cpio {
int magic;
int (*read_header)(struct archive *, struct cpio *,
int (*read_header)(struct archive_read *, struct cpio *,
struct stat *, size_t *, size_t *);
struct links_entry *links_head;
struct archive_string entry_name;
@ -120,34 +121,35 @@ struct cpio {
static int64_t atol16(const char *, unsigned);
static int64_t atol8(const char *, unsigned);
static int archive_read_format_cpio_bid(struct archive *);
static int archive_read_format_cpio_cleanup(struct archive *);
static int archive_read_format_cpio_read_data(struct archive *,
static int archive_read_format_cpio_bid(struct archive_read *);
static int archive_read_format_cpio_cleanup(struct archive_read *);
static int archive_read_format_cpio_read_data(struct archive_read *,
const void **, size_t *, off_t *);
static int archive_read_format_cpio_read_header(struct archive *,
static int archive_read_format_cpio_read_header(struct archive_read *,
struct archive_entry *);
static int be4(const unsigned char *);
static int header_bin_be(struct archive *, struct cpio *, struct stat *,
static int header_bin_be(struct archive_read *, struct cpio *, struct stat *,
size_t *, size_t *);
static int header_bin_le(struct archive *, struct cpio *, struct stat *,
static int header_bin_le(struct archive_read *, struct cpio *, struct stat *,
size_t *, size_t *);
static int header_newc(struct archive *, struct cpio *, struct stat *,
static int header_newc(struct archive_read *, struct cpio *, struct stat *,
size_t *, size_t *);
static int header_odc(struct archive *, struct cpio *, struct stat *,
static int header_odc(struct archive_read *, struct cpio *, struct stat *,
size_t *, size_t *);
static int le4(const unsigned char *);
static void record_hardlink(struct cpio *cpio, struct archive_entry *entry,
const struct stat *st);
int
archive_read_support_format_cpio(struct archive *a)
archive_read_support_format_cpio(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct cpio *cpio;
int r;
cpio = (struct cpio *)malloc(sizeof(*cpio));
if (cpio == NULL) {
archive_set_error(a, ENOMEM, "Can't allocate cpio data");
archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
return (ARCHIVE_FATAL);
}
memset(cpio, 0, sizeof(*cpio));
@ -168,7 +170,7 @@ archive_read_support_format_cpio(struct archive *a)
static int
archive_read_format_cpio_bid(struct archive *a)
archive_read_format_cpio_bid(struct archive_read *a)
{
int bid, bytes_read;
const void *h;
@ -227,7 +229,7 @@ archive_read_format_cpio_bid(struct archive *a)
}
static int
archive_read_format_cpio_read_header(struct archive *a,
archive_read_format_cpio_read_header(struct archive_read *a,
struct archive_entry *entry)
{
struct stat st;
@ -274,7 +276,7 @@ archive_read_format_cpio_read_header(struct archive *a,
/* Compare name to "TRAILER!!!" to test for end-of-archive. */
if (namelength == 11 && strcmp((const char *)h, "TRAILER!!!") == 0) {
/* TODO: Store file location of start of block. */
archive_set_error(a, 0, NULL);
archive_set_error(&a->archive, 0, NULL);
return (ARCHIVE_EOF);
}
@ -285,7 +287,7 @@ archive_read_format_cpio_read_header(struct archive *a,
}
static int
archive_read_format_cpio_read_data(struct archive *a,
archive_read_format_cpio_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset)
{
ssize_t bytes_read;
@ -322,7 +324,7 @@ archive_read_format_cpio_read_data(struct archive *a,
}
static int
header_newc(struct archive *a, struct cpio *cpio, struct stat *st,
header_newc(struct archive_read *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
@ -339,11 +341,11 @@ header_newc(struct archive *a, struct cpio *cpio, struct stat *st,
header = (const struct cpio_newc_header *)h;
if (memcmp(header->c_magic, "070701", 6) == 0) {
a->archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
a->archive_format_name = "ASCII cpio (SVR4 with no CRC)";
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)";
} else if (memcmp(header->c_magic, "070702", 6) == 0) {
a->archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC;
a->archive_format_name = "ASCII cpio (SVR4 with CRC)";
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC;
a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)";
} else {
/* TODO: Abort here? */
}
@ -379,15 +381,15 @@ header_newc(struct archive *a, struct cpio *cpio, struct stat *st,
}
static int
header_odc(struct archive *a, struct cpio *cpio, struct stat *st,
header_odc(struct archive_read *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
const struct cpio_odc_header *header;
size_t bytes;
a->archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
a->archive_format_name = "POSIX octet-oriented cpio";
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
a->archive.archive_format_name = "POSIX octet-oriented cpio";
/* Read fixed-size portion of header. */
bytes = (a->compression_read_ahead)(a, &h, sizeof(struct cpio_odc_header));
@ -423,15 +425,15 @@ header_odc(struct archive *a, struct cpio *cpio, struct stat *st,
}
static int
header_bin_le(struct archive *a, struct cpio *cpio, struct stat *st,
header_bin_le(struct archive_read *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
const struct cpio_bin_header *header;
size_t bytes;
a->archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;
a->archive_format_name = "cpio (little-endian binary)";
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;
a->archive.archive_format_name = "cpio (little-endian binary)";
/* Read fixed-size portion of header. */
bytes = (a->compression_read_ahead)(a, &h, sizeof(struct cpio_bin_header));
@ -460,15 +462,15 @@ header_bin_le(struct archive *a, struct cpio *cpio, struct stat *st,
}
static int
header_bin_be(struct archive *a, struct cpio *cpio, struct stat *st,
header_bin_be(struct archive_read *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
const struct cpio_bin_header *header;
size_t bytes;
a->archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
a->archive_format_name = "cpio (big-endian binary)";
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
a->archive.archive_format_name = "cpio (big-endian binary)";
/* Read fixed-size portion of header. */
bytes = (a->compression_read_ahead)(a, &h,
@ -497,7 +499,7 @@ header_bin_be(struct archive *a, struct cpio *cpio, struct stat *st,
}
static int
archive_read_format_cpio_cleanup(struct archive *a)
archive_read_format_cpio_cleanup(struct archive_read *a)
{
struct cpio *cpio;

View File

@ -29,15 +29,17 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_read_private.h"
static int archive_read_format_empty_bid(struct archive *);
static int archive_read_format_empty_read_data(struct archive *,
static int archive_read_format_empty_bid(struct archive_read *);
static int archive_read_format_empty_read_data(struct archive_read *,
const void **, size_t *, off_t *);
static int archive_read_format_empty_read_header(struct archive *,
static int archive_read_format_empty_read_header(struct archive_read *,
struct archive_entry *);
int
archive_read_support_format_empty(struct archive *a)
archive_read_support_format_empty(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
int r;
r = __archive_read_register_format(a,
@ -53,7 +55,7 @@ archive_read_support_format_empty(struct archive *a)
static int
archive_read_format_empty_bid(struct archive *a)
archive_read_format_empty_bid(struct archive_read *a)
{
int bytes_read;
const void *h;
@ -65,20 +67,20 @@ archive_read_format_empty_bid(struct archive *a)
}
static int
archive_read_format_empty_read_header(struct archive *a,
archive_read_format_empty_read_header(struct archive_read *a,
struct archive_entry *entry)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
a->archive_format = ARCHIVE_FORMAT_EMPTY;
a->archive_format_name = "Empty file";
a->archive.archive_format = ARCHIVE_FORMAT_EMPTY;
a->archive.archive_format_name = "Empty file";
return (ARCHIVE_EOF);
}
static int
archive_read_format_empty_read_data(struct archive *a,
archive_read_format_empty_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset)
{
(void)a; /* UNUSED */

View File

@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_string.h"
/*
@ -222,12 +223,12 @@ struct iso9660 {
};
static void add_entry(struct iso9660 *iso9660, struct file_info *file);
static int archive_read_format_iso9660_bid(struct archive *);
static int archive_read_format_iso9660_cleanup(struct archive *);
static int archive_read_format_iso9660_read_data(struct archive *,
static int archive_read_format_iso9660_bid(struct archive_read *);
static int archive_read_format_iso9660_cleanup(struct archive_read *);
static int archive_read_format_iso9660_read_data(struct archive_read *,
const void **, size_t *, off_t *);
static int archive_read_format_iso9660_read_data_skip(struct archive *);
static int archive_read_format_iso9660_read_header(struct archive *,
static int archive_read_format_iso9660_read_data_skip(struct archive_read *);
static int archive_read_format_iso9660_read_header(struct archive_read *,
struct archive_entry *);
static const char *build_pathname(struct archive_string *, struct file_info *);
static void dump_isodirrec(FILE *, const unsigned char *isodirrec);
@ -236,7 +237,7 @@ static time_t isodate17(const unsigned char *);
static time_t isodate7(const unsigned char *);
static int isPVD(struct iso9660 *, const unsigned char *);
static struct file_info *next_entry(struct iso9660 *);
static int next_entry_seek(struct archive *a, struct iso9660 *iso9660,
static int next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
struct file_info **pfile);
static struct file_info *
parse_file_info(struct iso9660 *iso9660,
@ -248,14 +249,15 @@ static void release_file(struct iso9660 *, struct file_info *);
static unsigned toi(const void *p, int n);
int
archive_read_support_format_iso9660(struct archive *a)
archive_read_support_format_iso9660(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct iso9660 *iso9660;
int r;
iso9660 = (struct iso9660 *)malloc(sizeof(*iso9660));
if (iso9660 == NULL) {
archive_set_error(a, ENOMEM, "Can't allocate iso9660 data");
archive_set_error(&a->archive, ENOMEM, "Can't allocate iso9660 data");
return (ARCHIVE_FATAL);
}
memset(iso9660, 0, sizeof(*iso9660));
@ -279,7 +281,7 @@ archive_read_support_format_iso9660(struct archive *a)
static int
archive_read_format_iso9660_bid(struct archive *a)
archive_read_format_iso9660_bid(struct archive_read *a)
{
struct iso9660 *iso9660;
ssize_t bytes_read;
@ -338,7 +340,7 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
}
static int
archive_read_format_iso9660_read_header(struct archive *a,
archive_read_format_iso9660_read_header(struct archive_read *a,
struct archive_entry *entry)
{
struct stat st;
@ -349,9 +351,9 @@ archive_read_format_iso9660_read_header(struct archive *a,
iso9660 = (struct iso9660 *)*(a->pformat_data);
if (!a->archive_format) {
a->archive_format = ARCHIVE_FORMAT_ISO9660;
a->archive_format_name = "ISO9660";
if (!a->archive.archive_format) {
a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
a->archive.archive_format_name = "ISO9660";
}
/* Get the next entry that appears after the current offset. */
@ -397,7 +399,7 @@ archive_read_format_iso9660_read_header(struct archive *a,
/* If the offset is before our current position, we can't
* seek backwards to extract it, so issue a warning. */
if (file->offset < iso9660->current_position) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Ignoring out-of-order file");
iso9660->entry_bytes_remaining = 0;
iso9660->entry_sparse_offset = 0;
@ -419,7 +421,7 @@ archive_read_format_iso9660_read_header(struct archive *a,
step = iso9660->entry_bytes_remaining;
bytes_read = (a->compression_read_ahead)(a, &block, step);
if (bytes_read < step) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Failed to read full block when scanning ISO9660 directory list");
release_file(iso9660, file);
return (ARCHIVE_FATAL);
@ -445,9 +447,9 @@ archive_read_format_iso9660_read_header(struct archive *a,
child = parse_file_info(iso9660, file, p);
add_entry(iso9660, child);
if (iso9660->seenRockridge) {
a->archive_format =
a->archive.archive_format =
ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
a->archive_format_name =
a->archive.archive_format_name =
"ISO9660 with Rockridge extensions";
}
}
@ -459,7 +461,7 @@ archive_read_format_iso9660_read_header(struct archive *a,
}
static int
archive_read_format_iso9660_read_data_skip(struct archive *a)
archive_read_format_iso9660_read_data_skip(struct archive_read *a)
{
/* Because read_next_header always does an explicit skip
* to the next entry, we don't need to do anything here. */
@ -468,7 +470,7 @@ archive_read_format_iso9660_read_data_skip(struct archive *a)
}
static int
archive_read_format_iso9660_read_data(struct archive *a,
archive_read_format_iso9660_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset)
{
ssize_t bytes_read;
@ -484,7 +486,7 @@ archive_read_format_iso9660_read_data(struct archive *a,
bytes_read = (a->compression_read_ahead)(a, buff, 1);
if (bytes_read == 0)
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated input file");
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
@ -500,7 +502,7 @@ archive_read_format_iso9660_read_data(struct archive *a,
}
static int
archive_read_format_iso9660_cleanup(struct archive *a)
archive_read_format_iso9660_cleanup(struct archive_read *a)
{
struct iso9660 *iso9660;
struct file_info *file;
@ -889,7 +891,7 @@ release_file(struct iso9660 *iso9660, struct file_info *file)
}
static int
next_entry_seek(struct archive *a, struct iso9660 *iso9660,
next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
struct file_info **pfile)
{
struct file_info *file;

View File

@ -83,6 +83,7 @@ static size_t wcslen(const wchar_t *s)
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_read_private.h"
/*
* Layout of POSIX 'ustar' tar header.
@ -174,50 +175,50 @@ struct tar {
static size_t UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n);
static int archive_block_is_null(const unsigned char *p);
static char *base64_decode(const wchar_t *, size_t, size_t *);
static int gnu_read_sparse_data(struct archive *, struct tar *,
static int gnu_read_sparse_data(struct archive_read *, struct tar *,
const struct archive_entry_header_gnutar *header);
static void gnu_parse_sparse_data(struct archive *, struct tar *,
static void gnu_parse_sparse_data(struct archive_read *, struct tar *,
const struct gnu_sparse *sparse, int length);
static int header_Solaris_ACL(struct archive *, struct tar *,
static int header_Solaris_ACL(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *);
static int header_common(struct archive *, struct tar *,
static int header_common(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *);
static int header_old_tar(struct archive *, struct tar *,
static int header_old_tar(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *);
static int header_pax_extensions(struct archive *, struct tar *,
static int header_pax_extensions(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *);
static int header_pax_global(struct archive *, struct tar *,
static int header_pax_global(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
static int header_longlink(struct archive *, struct tar *,
static int header_longlink(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
static int header_longname(struct archive *, struct tar *,
static int header_longname(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
static int header_volume(struct archive *, struct tar *,
static int header_volume(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
static int header_ustar(struct archive *, struct tar *,
static int header_ustar(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
static int header_gnutar(struct archive *, struct tar *,
static int header_gnutar(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
static int archive_read_format_tar_bid(struct archive *);
static int archive_read_format_tar_cleanup(struct archive *);
static int archive_read_format_tar_read_data(struct archive *a,
static int archive_read_format_tar_bid(struct archive_read *);
static int archive_read_format_tar_cleanup(struct archive_read *);
static int archive_read_format_tar_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset);
static int archive_read_format_tar_skip(struct archive *a);
static int archive_read_format_tar_read_header(struct archive *,
static int archive_read_format_tar_skip(struct archive_read *a);
static int archive_read_format_tar_read_header(struct archive_read *,
struct archive_entry *);
static int checksum(struct archive *, const void *);
static int checksum(struct archive_read *, const void *);
static int pax_attribute(struct archive_entry *, struct stat *,
wchar_t *key, wchar_t *value);
static int pax_header(struct archive *, struct tar *,
static int pax_header(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, char *attr);
static void pax_time(const wchar_t *, int64_t *sec, long *nanos);
static int read_body_to_string(struct archive *, struct tar *,
static int read_body_to_string(struct archive_read *, struct tar *,
struct archive_string *, const void *h);
static int64_t tar_atol(const char *, unsigned);
static int64_t tar_atol10(const wchar_t *, unsigned);
static int64_t tar_atol256(const char *, unsigned);
static int64_t tar_atol8(const char *, unsigned);
static int tar_read_header(struct archive *, struct tar *,
static int tar_read_header(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *);
static int tohex(int c);
static char *url_decode(const char *);
@ -254,14 +255,16 @@ archive_read_support_format_gnutar(struct archive *a)
int
archive_read_support_format_tar(struct archive *a)
archive_read_support_format_tar(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct tar *tar;
int r;
tar = (struct tar *)malloc(sizeof(*tar));
if (tar == NULL) {
archive_set_error(a, ENOMEM, "Can't allocate tar data");
archive_set_error(&a->archive, ENOMEM,
"Can't allocate tar data");
return (ARCHIVE_FATAL);
}
memset(tar, 0, sizeof(*tar));
@ -279,7 +282,7 @@ archive_read_support_format_tar(struct archive *a)
}
static int
archive_read_format_tar_cleanup(struct archive *a)
archive_read_format_tar_cleanup(struct archive_read *a)
{
struct tar *tar;
@ -300,7 +303,7 @@ archive_read_format_tar_cleanup(struct archive *a)
static int
archive_read_format_tar_bid(struct archive *a)
archive_read_format_tar_bid(struct archive_read *a)
{
int bid;
ssize_t bytes_read;
@ -311,8 +314,8 @@ archive_read_format_tar_bid(struct archive *a)
* If we're already reading a non-tar file, don't
* bother to bid.
*/
if (a->archive_format != 0 &&
(a->archive_format & ARCHIVE_FORMAT_BASE_MASK) !=
if (a->archive.archive_format != 0 &&
(a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) !=
ARCHIVE_FORMAT_TAR)
return (0);
bid = 0;
@ -321,7 +324,7 @@ archive_read_format_tar_bid(struct archive *a)
* If we're already reading a tar format, start the bid at 1 as
* a failsafe.
*/
if ((a->archive_format & ARCHIVE_FORMAT_BASE_MASK) ==
if ((a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) ==
ARCHIVE_FORMAT_TAR)
bid++;
@ -345,7 +348,7 @@ archive_read_format_tar_bid(struct archive *a)
* If we already know this is a tar archive,
* then we have a problem.
*/
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated tar archive");
return (ARCHIVE_FATAL);
}
@ -353,7 +356,7 @@ archive_read_format_tar_bid(struct archive *a)
/* If it's an end-of-archive mark, we can handle it. */
if ((*(const char *)h) == 0 && archive_block_is_null((const unsigned char *)h)) {
/* If it's a known tar file, end-of-archive is definite. */
if ((a->archive_format & ARCHIVE_FORMAT_BASE_MASK) ==
if ((a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) ==
ARCHIVE_FORMAT_TAR)
return (512);
/* Empty archive? */
@ -412,7 +415,7 @@ archive_read_format_tar_bid(struct archive *a)
* tar_read_header() function below.
*/
static int
archive_read_format_tar_read_header(struct archive *a,
archive_read_format_tar_read_header(struct archive_read *a,
struct archive_entry *entry)
{
/*
@ -472,7 +475,7 @@ archive_read_format_tar_read_header(struct archive *a,
}
static int
archive_read_format_tar_read_data(struct archive *a,
archive_read_format_tar_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset)
{
ssize_t bytes_read;
@ -497,7 +500,7 @@ archive_read_format_tar_read_data(struct archive *a,
if (tar->entry_bytes_remaining > 0) {
bytes_read = (a->compression_read_ahead)(a, buff, 1);
if (bytes_read == 0) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated tar archive");
return (ARCHIVE_FATAL);
}
@ -538,7 +541,7 @@ archive_read_format_tar_read_data(struct archive *a,
}
static int
archive_read_format_tar_skip(struct archive *a)
archive_read_format_tar_skip(struct archive_read *a)
{
off_t bytes_skipped;
struct tar* tar;
@ -584,7 +587,7 @@ archive_read_format_tar_skip(struct archive *a)
* with a single entry.
*/
static int
tar_read_header(struct archive *a, struct tar *tar,
tar_read_header(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st)
{
ssize_t bytes;
@ -610,7 +613,7 @@ tar_read_header(struct archive *a, struct tar *tar,
bytes = (a->compression_read_ahead)(a, &h, 512);
if (bytes > 0)
(a->compression_read_consume)(a, bytes);
archive_set_error(a, 0, NULL);
archive_set_error(&a->archive, 0, NULL);
return (ARCHIVE_EOF);
}
@ -622,12 +625,12 @@ tar_read_header(struct archive *a, struct tar *tar,
* TODO: Improve this by implementing a real header scan.
*/
if (!checksum(a, h)) {
archive_set_error(a, EINVAL, "Damaged tar archive");
archive_set_error(&a->archive, EINVAL, "Damaged tar archive");
return (ARCHIVE_RETRY); /* Retryable: Invalid header */
}
if (++tar->header_recursion_depth > 32) {
archive_set_error(a, EINVAL, "Too many special headers");
archive_set_error(&a->archive, EINVAL, "Too many special headers");
return (ARCHIVE_WARN);
}
@ -635,13 +638,13 @@ tar_read_header(struct archive *a, struct tar *tar,
header = (const struct archive_entry_header_ustar *)h;
switch(header->typeflag[0]) {
case 'A': /* Solaris tar ACL */
a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive_format_name = "Solaris tar";
a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive.archive_format_name = "Solaris tar";
err = header_Solaris_ACL(a, tar, entry, st, h);
break;
case 'g': /* POSIX-standard 'g' header. */
a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive_format_name = "POSIX pax interchange format";
a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive.archive_format_name = "POSIX pax interchange format";
err = header_pax_global(a, tar, entry, st, h);
break;
case 'K': /* Long link name (GNU tar, others) */
@ -654,30 +657,30 @@ tar_read_header(struct archive *a, struct tar *tar,
err = header_volume(a, tar, entry, st, h);
break;
case 'X': /* Used by SUN tar; same as 'x'. */
a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive_format_name =
a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive.archive_format_name =
"POSIX pax interchange format (Sun variant)";
err = header_pax_extensions(a, tar, entry, st, h);
break;
case 'x': /* POSIX-standard 'x' header. */
a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive_format_name = "POSIX pax interchange format";
a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive.archive_format_name = "POSIX pax interchange format";
err = header_pax_extensions(a, tar, entry, st, h);
break;
default:
if (memcmp(header->magic, "ustar \0", 8) == 0) {
a->archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
a->archive_format_name = "GNU tar format";
a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
a->archive.archive_format_name = "GNU tar format";
err = header_gnutar(a, tar, entry, st, h);
} else if (memcmp(header->magic, "ustar", 5) == 0) {
if (a->archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) {
a->archive_format = ARCHIVE_FORMAT_TAR_USTAR;
a->archive_format_name = "POSIX ustar format";
if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) {
a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR;
a->archive.archive_format_name = "POSIX ustar format";
}
err = header_ustar(a, tar, entry, st, h);
} else {
a->archive_format = ARCHIVE_FORMAT_TAR;
a->archive_format_name = "tar (non-POSIX)";
a->archive.archive_format = ARCHIVE_FORMAT_TAR;
a->archive.archive_format_name = "tar (non-POSIX)";
err = header_old_tar(a, tar, entry, st, h);
}
}
@ -689,7 +692,7 @@ tar_read_header(struct archive *a, struct tar *tar,
* Return true if block checksum is correct.
*/
static int
checksum(struct archive *a, const void *h)
checksum(struct archive_read *a, const void *h)
{
const unsigned char *bytes;
const struct archive_entry_header_ustar *header;
@ -750,7 +753,7 @@ archive_block_is_null(const unsigned char *p)
* Interpret 'A' Solaris ACL header
*/
static int
header_Solaris_ACL(struct archive *a, struct tar *tar,
header_Solaris_ACL(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
int err, err2;
@ -786,7 +789,7 @@ header_Solaris_ACL(struct archive *a, struct tar *tar,
* Interpret 'K' long linkname header.
*/
static int
header_longlink(struct archive *a, struct tar *tar,
header_longlink(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
int err, err2;
@ -804,7 +807,7 @@ header_longlink(struct archive *a, struct tar *tar,
* Interpret 'L' long filename header.
*/
static int
header_longname(struct archive *a, struct tar *tar,
header_longname(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
int err, err2;
@ -822,7 +825,7 @@ header_longname(struct archive *a, struct tar *tar,
* Interpret 'V' GNU tar volume header.
*/
static int
header_volume(struct archive *a, struct tar *tar,
header_volume(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
(void)h;
@ -835,7 +838,7 @@ header_volume(struct archive *a, struct tar *tar,
* Read body of an archive entry into an archive_string object.
*/
static int
read_body_to_string(struct archive *a, struct tar *tar,
read_body_to_string(struct archive_read *a, struct tar *tar,
struct archive_string *as, const void *h)
{
off_t size, padded_size;
@ -882,7 +885,7 @@ read_body_to_string(struct archive *a, struct tar *tar,
* common parsing into one place.
*/
static int
header_common(struct archive *a, struct tar *tar, struct archive_entry *entry,
header_common(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
struct stat *st, const void *h)
{
const struct archive_entry_header_ustar *header;
@ -946,7 +949,7 @@ header_common(struct archive *a, struct tar *tar, struct archive_entry *entry,
* itself an uncompressed tar archive.
*/
if (st->st_size > 0 &&
a->archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&
a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&
archive_read_format_tar_bid(a) > 50)
st->st_size = 0;
break;
@ -1014,7 +1017,7 @@ header_common(struct archive *a, struct tar *tar, struct archive_entry *entry,
* Parse out header elements for "old-style" tar archives.
*/
static int
header_old_tar(struct archive *a, struct tar *tar, struct archive_entry *entry,
header_old_tar(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
struct stat *st, const void *h)
{
const struct archive_entry_header_ustar *header;
@ -1036,7 +1039,7 @@ header_old_tar(struct archive *a, struct tar *tar, struct archive_entry *entry,
* Parse a file header for a pax extended archive entry.
*/
static int
header_pax_global(struct archive *a, struct tar *tar,
header_pax_global(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
int err, err2;
@ -1047,7 +1050,7 @@ header_pax_global(struct archive *a, struct tar *tar,
}
static int
header_pax_extensions(struct archive *a, struct tar *tar,
header_pax_extensions(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
int err, err2;
@ -1080,7 +1083,7 @@ header_pax_extensions(struct archive *a, struct tar *tar,
* handles "pax" or "extended ustar" entries.
*/
static int
header_ustar(struct archive *a, struct tar *tar, struct archive_entry *entry,
header_ustar(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
struct stat *st, const void *h)
{
const struct archive_entry_header_ustar *header;
@ -1132,7 +1135,7 @@ header_ustar(struct archive *a, struct tar *tar, struct archive_entry *entry,
* Returns non-zero if there's an error in the data.
*/
static int
pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
pax_header(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
struct stat *st, char *attr)
{
size_t attr_length, l, line_length;
@ -1158,7 +1161,7 @@ pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
line_length *= 10;
line_length += *p - '0';
if (line_length > 999999) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Rejecting pax extended attribute > 1MB");
return (ARCHIVE_WARN);
}
@ -1183,7 +1186,7 @@ pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
tar->pax_entry_length * sizeof(wchar_t));
if (tar->pax_entry == NULL) {
free(old_entry);
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"No memory");
return (ARCHIVE_FATAL);
}
@ -1192,7 +1195,7 @@ pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
/* Decode UTF-8 to wchar_t, null-terminate result. */
if (utf8_decode(tar->pax_entry, p,
line_length - (p - attr) - 1)) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Invalid UTF8 character in pax extended attribute");
err = err_combine(err, ARCHIVE_WARN);
}
@ -1204,7 +1207,7 @@ pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
while (*wp && *wp != L'=')
++wp;
if (*wp == L'\0' || wp == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Invalid pax extended attributes");
return (ARCHIVE_WARN);
}
@ -1430,7 +1433,7 @@ pax_time(const wchar_t *p, int64_t *ps, long *pn)
* Parse GNU tar header
*/
static int
header_gnutar(struct archive *a, struct tar *tar, struct archive_entry *entry,
header_gnutar(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
struct stat *st, const void *h)
{
const struct archive_entry_header_gnutar *header;
@ -1495,7 +1498,7 @@ header_gnutar(struct archive *a, struct tar *tar, struct archive_entry *entry,
}
static int
gnu_read_sparse_data(struct archive *a, struct tar *tar,
gnu_read_sparse_data(struct archive_read *a, struct tar *tar,
const struct archive_entry_header_gnutar *header)
{
ssize_t bytes_read;
@ -1516,7 +1519,7 @@ gnu_read_sparse_data(struct archive *a, struct tar *tar,
if (bytes_read < 0)
return (ARCHIVE_FATAL);
if (bytes_read < 512) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated tar archive "
"detected while reading sparse file data");
return (ARCHIVE_FATAL);
@ -1531,7 +1534,7 @@ gnu_read_sparse_data(struct archive *a, struct tar *tar,
}
static void
gnu_parse_sparse_data(struct archive *a, struct tar *tar,
gnu_parse_sparse_data(struct archive_read *a, struct tar *tar,
const struct gnu_sparse *sparse, int length)
{
struct sparse_block *last;

View File

@ -44,15 +44,16 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_read_private.h"
struct zip {
/* entry_bytes_remaining is the number of bytes we expect. */
off_t entry_bytes_remaining;
off_t entry_offset;
int64_t entry_bytes_remaining;
int64_t entry_offset;
/* These count the number of bytes actually read for the entry. */
off_t entry_compressed_bytes_read;
off_t entry_uncompressed_bytes_read;
int64_t entry_compressed_bytes_read;
int64_t entry_uncompressed_bytes_read;
unsigned version;
unsigned system;
@ -74,8 +75,8 @@ struct zip {
long crc32;
ssize_t filename_length;
ssize_t extra_length;
off_t uncompressed_size;
off_t compressed_size;
int64_t uncompressed_size;
int64_t compressed_size;
unsigned char *uncompressed_buffer;
size_t uncompressed_buffer_size;
@ -115,36 +116,40 @@ static const char *compression_names[] = {
"deflation"
};
static int archive_read_format_zip_bid(struct archive *);
static int archive_read_format_zip_cleanup(struct archive *);
static int archive_read_format_zip_read_data(struct archive *,
static int archive_read_format_zip_bid(struct archive_read *);
static int archive_read_format_zip_cleanup(struct archive_read *);
static int archive_read_format_zip_read_data(struct archive_read *,
const void **, size_t *, off_t *);
static int archive_read_format_zip_read_data_skip(struct archive *a);
static int archive_read_format_zip_read_header(struct archive *,
static int archive_read_format_zip_read_data_skip(struct archive_read *a);
static int archive_read_format_zip_read_header(struct archive_read *,
struct archive_entry *);
static int i2(const char *);
static int i4(const char *);
static unsigned int u2(const char *);
static unsigned int u4(const char *);
static uint64_t u8(const char *);
static int zip_read_data_deflate(struct archive *a, const void **buff,
static int zip_read_data_deflate(struct archive_read *a, const void **buff,
size_t *size, off_t *offset);
static int zip_read_data_none(struct archive *a, const void **buff,
static int zip_read_data_none(struct archive_read *a, const void **buff,
size_t *size, off_t *offset);
static int zip_read_file_header(struct archive *a,
static int zip_read_file_header(struct archive_read *a,
struct archive_entry *entry, struct zip *zip);
static time_t zip_time(const char *);
static void process_extra(const void* extra, struct zip* zip);
/* Largest 32-bit unsigned value, stored in a 64-bit constant. */
static const uint64_t max_uint32 = (((uint64_t)1) << 32) - 1;
int
archive_read_support_format_zip(struct archive *a)
archive_read_support_format_zip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct zip *zip;
int r;
zip = (struct zip *)malloc(sizeof(*zip));
if (zip == NULL) {
archive_set_error(a, ENOMEM, "Can't allocate zip data");
archive_set_error(&a->archive, ENOMEM, "Can't allocate zip data");
return (ARCHIVE_FATAL);
}
memset(zip, 0, sizeof(*zip));
@ -164,14 +169,14 @@ archive_read_support_format_zip(struct archive *a)
static int
archive_read_format_zip_bid(struct archive *a)
archive_read_format_zip_bid(struct archive_read *a)
{
int bytes_read;
int bid = 0;
const void *h;
const char *p;
if (a->archive_format == ARCHIVE_FORMAT_ZIP)
if (a->archive.archive_format == ARCHIVE_FORMAT_ZIP)
bid += 1;
bytes_read = (a->compression_read_ahead)(a, &h, 4);
@ -194,7 +199,7 @@ archive_read_format_zip_bid(struct archive *a)
}
static int
archive_read_format_zip_read_header(struct archive *a,
archive_read_format_zip_read_header(struct archive_read *a,
struct archive_entry *entry)
{
int bytes_read;
@ -202,9 +207,9 @@ archive_read_format_zip_read_header(struct archive *a,
const char *signature;
struct zip *zip;
a->archive_format = ARCHIVE_FORMAT_ZIP;
if (a->archive_format_name == NULL)
a->archive_format_name = "ZIP";
a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
if (a->archive.archive_format_name == NULL)
a->archive.archive_format_name = "ZIP";
zip = (struct zip *)*(a->pformat_data);
zip->decompress_init = 0;
@ -218,7 +223,7 @@ archive_read_format_zip_read_header(struct archive *a,
signature = (const char *)h;
if (signature[0] != 'P' || signature[1] != 'K') {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad ZIP file");
return (ARCHIVE_FATAL);
}
@ -243,19 +248,19 @@ archive_read_format_zip_read_header(struct archive *a,
* We should never encounter this record here;
* see ZIP_LENGTH_AT_END handling below for details.
*/
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Bad ZIP file: Unexpected end-of-entry record");
return (ARCHIVE_FATAL);
}
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Damaged ZIP file or unsupported format variant (%d,%d)",
signature[2], signature[3]);
return (ARCHIVE_FATAL);
}
int
zip_read_file_header(struct archive *a, struct archive_entry *entry,
zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
struct zip *zip)
{
const struct zip_file_header *p;
@ -266,7 +271,7 @@ zip_read_file_header(struct archive *a, struct archive_entry *entry,
bytes_read =
(a->compression_read_ahead)(a, &h, sizeof(struct zip_file_header));
if (bytes_read < (int)sizeof(struct zip_file_header)) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
}
@ -299,7 +304,7 @@ zip_read_file_header(struct archive *a, struct archive_entry *entry,
/* Read the filename. */
bytes_read = (a->compression_read_ahead)(a, &h, zip->filename_length);
if (bytes_read < zip->filename_length) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
}
@ -316,7 +321,7 @@ zip_read_file_header(struct archive *a, struct archive_entry *entry,
/* Read the extra data. */
bytes_read = (a->compression_read_ahead)(a, &h, zip->extra_length);
if (bytes_read < zip->extra_length) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
}
@ -341,7 +346,7 @@ zip_read_file_header(struct archive *a, struct archive_entry *entry,
sprintf(zip->format_name, "ZIP %d.%d (%s)",
zip->version / 10, zip->version % 10,
zip->compression_name);
a->archive_format_name = zip->format_name;
a->archive.archive_format_name = zip->format_name;
return (ARCHIVE_OK);
}
@ -368,7 +373,7 @@ zip_time(const char *p)
}
static int
archive_read_format_zip_read_data(struct archive *a,
archive_read_format_zip_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset)
{
int r;
@ -388,7 +393,7 @@ archive_read_format_zip_read_data(struct archive *a,
int bytes_read =
(a->compression_read_ahead)(a, &h, 16);
if (bytes_read < 16) {
archive_set_error(a,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP end-of-file record");
return (ARCHIVE_FATAL);
@ -402,19 +407,21 @@ archive_read_format_zip_read_data(struct archive *a,
/* Check file size, CRC against these values. */
if (zip->compressed_size != zip->entry_compressed_bytes_read) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"ZIP compressed data is wrong size");
return (ARCHIVE_WARN);
}
if (zip->uncompressed_size != zip->entry_uncompressed_bytes_read) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
/* Size field only stores the lower 32 bits of the actual size. */
if ((zip->uncompressed_size & max_uint32)
!= (zip->entry_uncompressed_bytes_read & max_uint32)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"ZIP uncompressed data is wrong size");
return (ARCHIVE_WARN);
}
/* TODO: Compute CRC. */
/*
if (zip->crc32 != zip->entry_crc32_calculated) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"ZIP data CRC error");
return (ARCHIVE_WARN);
}
@ -437,7 +444,7 @@ archive_read_format_zip_read_data(struct archive *a,
*size = 0;
*offset = 0;
/* Return a warning. */
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported ZIP compression method (%s)",
zip->compression_name);
if (zip->flags & ZIP_LENGTH_AT_END) {
@ -472,7 +479,7 @@ archive_read_format_zip_read_data(struct archive *a,
* zip->end_of_entry if it consumes all of the data.
*/
static int
zip_read_data_none(struct archive *a, const void **buff,
zip_read_data_none(struct archive_read *a, const void **buff,
size_t *size, off_t *offset)
{
struct zip *zip;
@ -495,7 +502,7 @@ zip_read_data_none(struct archive *a, const void **buff,
*/
bytes_avail = (a->compression_read_ahead)(a, buff, 1);
if (bytes_avail <= 0) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file data");
return (ARCHIVE_FATAL);
}
@ -513,7 +520,7 @@ zip_read_data_none(struct archive *a, const void **buff,
#ifdef HAVE_ZLIB_H
static int
zip_read_data_deflate(struct archive *a, const void **buff,
zip_read_data_deflate(struct archive_read *a, const void **buff,
size_t *size, off_t *offset)
{
struct zip *zip;
@ -529,7 +536,7 @@ zip_read_data_deflate(struct archive *a, const void **buff,
zip->uncompressed_buffer
= (unsigned char *)malloc(zip->uncompressed_buffer_size);
if (zip->uncompressed_buffer == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"No memory for ZIP decompression");
return (ARCHIVE_FATAL);
}
@ -540,7 +547,7 @@ zip_read_data_deflate(struct archive *a, const void **buff,
r = inflateInit2(&zip->stream,
-15 /* Don't check for zlib header */);
if (r != Z_OK) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Can't initialize ZIP decompression.");
return (ARCHIVE_FATAL);
}
@ -555,7 +562,7 @@ zip_read_data_deflate(struct archive *a, const void **buff,
*/
bytes_avail = (a->compression_read_ahead)(a, &compressed_buff, 1);
if (bytes_avail <= 0) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file body");
return (ARCHIVE_FATAL);
}
@ -581,11 +588,11 @@ zip_read_data_deflate(struct archive *a, const void **buff,
zip->end_of_entry = 1;
break;
case Z_MEM_ERROR:
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Out of memory for ZIP decompression");
return (ARCHIVE_FATAL);
default:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"ZIP decompression failed (%d)", r);
return (ARCHIVE_FATAL);
}
@ -605,20 +612,20 @@ zip_read_data_deflate(struct archive *a, const void **buff,
}
#else
static int
zip_read_data_deflate(struct archive *a, const void **buff,
zip_read_data_deflate(struct archive_read *a, const void **buff,
size_t *size, off_t *offset)
{
*buff = NULL;
*size = 0;
*offset = 0;
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"libarchive compiled without deflate support (no libz)");
return (ARCHIVE_FATAL);
}
#endif
static int
archive_read_format_zip_read_data_skip(struct archive *a)
archive_read_format_zip_read_data_skip(struct archive_read *a)
{
struct zip *zip;
const void *buff = NULL;
@ -648,7 +655,8 @@ archive_read_format_zip_read_data_skip(struct archive *a)
while (zip->entry_bytes_remaining > 0) {
bytes_avail = (a->compression_read_ahead)(a, &buff, 1);
if (bytes_avail <= 0) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file body");
return (ARCHIVE_FATAL);
}
@ -663,7 +671,7 @@ archive_read_format_zip_read_data_skip(struct archive *a)
}
static int
archive_read_format_zip_cleanup(struct archive *a)
archive_read_format_zip_cleanup(struct archive_read *a)
{
struct zip *zip;

View File

@ -28,6 +28,7 @@
.Dt archive_util 3
.Os
.Sh NAME
.Nm archive_clear_error ,
.Nm archive_compression ,
.Nm archive_compression_name ,
.Nm archive_errno ,
@ -38,6 +39,8 @@
.Nd libarchive utility functions
.Sh SYNOPSIS
.In archive.h
.Ft void
.Fn archive_clear_error "struct archive *"
.Ft int
.Fn archive_compression "struct archive *"
.Ft const char *
@ -59,6 +62,9 @@ object used in the
.Xr libarchive 3
library.
.Bl -tag -compact -width indent
.It Fn archive_clear_error
Clears any error information left over from a previous call.
Not generally used in client code.
.It Fn archive_compression
Returns a numeric code indicating the current compression.
This value is set by

View File

@ -118,6 +118,12 @@ archive_position_uncompressed(struct archive *a)
return (a->file_position);
}
void
archive_clear_error(struct archive *a)
{
archive_string_empty(&a->error_string);
a->error = NULL;
}
void
archive_set_error(struct archive *a, int error_number, const char *fmt, ...)

View File

@ -0,0 +1,81 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
int
archive_write_close(struct archive *a)
{
return ((a->vtable->archive_write_close)(a));
}
#if ARCHIVE_API_VERSION > 1
int
archive_write_finish(struct archive *a)
{
return ((a->vtable->archive_write_finish)(a));
}
#else
/* Temporarily allow library to compile with either 1.x or 2.0 API. */
void
archive_write_finish(struct archive *a)
{
(void)(a->vtable->archive_write_finish)(a);
}
#endif
int
archive_write_header(struct archive *a, struct archive_entry *entry)
{
return ((a->vtable->archive_write_header)(a, entry));
}
int
archive_write_finish_entry(struct archive *a)
{
return ((a->vtable->archive_write_finish_entry)(a));
}
#if ARCHIVE_API_VERSION > 1
ssize_t
#else
/* Temporarily allow library to compile with either 1.x or 2.0 API. */
int
#endif
archive_write_data(struct archive *a, const void *buff, size_t s)
{
return ((a->vtable->archive_write_data)(a, buff, s));
}
ssize_t
archive_write_data_block(struct archive *a, const void *buff, size_t s, off_t o)
{
return ((a->vtable->archive_write_data_block)(a, buff, s, o));
}

View File

@ -89,13 +89,13 @@
.Fn archive_write_open_memory "struct archive *" "void *buffer" "size_t bufferSize" "size_t *outUsed"
.Ft int
.Fn archive_write_header "struct archive *" "struct archive_entry *"
.Ft int
.Ft ssize_t
.Fn archive_write_data "struct archive *" "const void *" "size_t"
.Ft int
.Fn archive_write_finish_entry "struct archive *"
.Ft int
.Fn archive_write_close "struct archive *"
.Ft void
.Ft int
.Fn archive_write_finish "struct archive *"
.Sh DESCRIPTION
These functions provide a complete API for creating streaming
@ -260,6 +260,12 @@ Complete the archive and invoke the close callback.
Invokes
.Fn archive_write_close
if it was not invoked manually, then releases all resources.
Note that this function was declared to return
.Ft void
in libarchive 1.x, which made it impossible to detect errors when
.Fn archive_write_close
was invoked implicitly from this function.
This is corrected beginning with libarchive 2.0.
.El
More information about the
.Va struct archive
@ -457,8 +463,9 @@ through whatever API function resulted in that call, which
may include
.Fn archive_write_header ,
.Fn archive_write_data ,
.Fn archive_write_close ,
or
.Fn archive_write_close .
.Fn archive_write_finish .
The client callback can call
.Fn archive_set_error
to provide values that can then be retrieved by

View File

@ -55,6 +55,31 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_write_private.h"
static struct archive_vtable *archive_write_vtable(void);
static int _archive_write_close(struct archive *);
static int _archive_write_finish(struct archive *);
static int _archive_write_header(struct archive *, struct archive_entry *);
static int _archive_write_finish_entry(struct archive *);
static ssize_t _archive_write_data(struct archive *, const void *, size_t);
static struct archive_vtable *
archive_write_vtable(void)
{
static struct archive_vtable av;
static int inited = 0;
if (!inited) {
av.archive_write_close = _archive_write_close;
av.archive_write_finish = _archive_write_finish;
av.archive_write_header = _archive_write_header;
av.archive_write_finish_entry = _archive_write_finish_entry;
av.archive_write_data = _archive_write_data;
}
return (&av);
}
/*
* Allocate, initialize and return an archive object.
@ -62,18 +87,18 @@ __FBSDID("$FreeBSD$");
struct archive *
archive_write_new(void)
{
struct archive *a;
struct archive_write *a;
unsigned char *nulls;
a = (struct archive *)malloc(sizeof(*a));
a = (struct archive_write *)malloc(sizeof(*a));
if (a == NULL)
return (NULL);
memset(a, 0, sizeof(*a));
a->magic = ARCHIVE_WRITE_MAGIC;
a->user_uid = geteuid();
a->archive.magic = ARCHIVE_WRITE_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = archive_write_vtable();
a->bytes_per_block = ARCHIVE_DEFAULT_BYTES_PER_BLOCK;
a->bytes_in_last_block = -1; /* Default */
a->state = ARCHIVE_STATE_NEW;
a->pformat_data = &(a->format_data);
/* Initialize a block of nulls for padding purposes. */
@ -91,17 +116,19 @@ archive_write_new(void)
* client to link in support for that format, even if they didn't
* ever use it.
*/
archive_write_set_compression_none(a);
return (a);
archive_write_set_compression_none(&a->archive);
return (&a->archive);
}
/*
* Set the block size. Returns 0 if successful.
*/
int
archive_write_set_bytes_per_block(struct archive *a, int bytes_per_block)
archive_write_set_bytes_per_block(struct archive *_a, int bytes_per_block)
{
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_bytes_per_block");
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_bytes_per_block");
a->bytes_per_block = bytes_per_block;
return (ARCHIVE_OK);
}
@ -110,9 +137,11 @@ archive_write_set_bytes_per_block(struct archive *a, int bytes_per_block)
* Get the current block size. -1 if it has never been set.
*/
int
archive_write_get_bytes_per_block(struct archive *a)
archive_write_get_bytes_per_block(struct archive *_a)
{
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_get_bytes_per_block");
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_ANY, "archive_write_get_bytes_per_block");
return (a->bytes_per_block);
}
@ -121,9 +150,11 @@ archive_write_get_bytes_per_block(struct archive *a)
* Returns 0 if successful.
*/
int
archive_write_set_bytes_in_last_block(struct archive *a, int bytes)
archive_write_set_bytes_in_last_block(struct archive *_a, int bytes)
{
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_set_bytes_in_last_block");
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_ANY, "archive_write_set_bytes_in_last_block");
a->bytes_in_last_block = bytes;
return (ARCHIVE_OK);
}
@ -132,9 +163,11 @@ archive_write_set_bytes_in_last_block(struct archive *a, int bytes)
* Return the value set above. -1 indicates it has not been set.
*/
int
archive_write_get_bytes_in_last_block(struct archive *a)
archive_write_get_bytes_in_last_block(struct archive *_a)
{
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_get_bytes_in_last_block");
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_ANY, "archive_write_get_bytes_in_last_block");
return (a->bytes_in_last_block);
}
@ -144,9 +177,11 @@ archive_write_get_bytes_in_last_block(struct archive *a)
* an archive to itself recursively.
*/
int
archive_write_set_skip_file(struct archive *a, dev_t d, ino_t i)
archive_write_set_skip_file(struct archive *_a, dev_t d, ino_t i)
{
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_set_skip_file");
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_ANY, "archive_write_set_skip_file");
a->skip_file_dev = d;
a->skip_file_ino = i;
return (ARCHIVE_OK);
@ -157,16 +192,18 @@ archive_write_set_skip_file(struct archive *a, dev_t d, ino_t i)
* Open the archive using the current settings.
*/
int
archive_write_open(struct archive *a, void *client_data,
archive_write_open(struct archive *_a, void *client_data,
archive_open_callback *opener, archive_write_callback *writer,
archive_close_callback *closer)
{
struct archive_write *a = (struct archive_write *)_a;
int ret;
ret = ARCHIVE_OK;
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_open");
archive_string_empty(&a->error_string);
a->state = ARCHIVE_STATE_HEADER;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_open");
archive_clear_error(&a->archive);
a->archive.state = ARCHIVE_STATE_HEADER;
a->client_data = client_data;
a->client_writer = writer;
a->client_opener = opener;
@ -185,15 +222,17 @@ archive_write_open(struct archive *a, void *client_data,
* Don't assume we actually wrote anything or performed any non-trivial
* initialization.
*/
int
archive_write_close(struct archive *a)
static int
_archive_write_close(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_close");
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_ANY, "archive_write_close");
/* Finish the last entry. */
if (a->state & ARCHIVE_STATE_DATA)
if (a->archive.state & ARCHIVE_STATE_DATA)
r = ((a->format_finish_entry)(a));
/* Finish off the archive. */
@ -203,6 +242,13 @@ archive_write_close(struct archive *a)
r = r1;
}
/* Release resources. */
if (a->format_destroy != NULL) {
r1 = (a->format_destroy)(a);
if (r1 < r)
r = r1;
}
/* Finish the compression and close the stream. */
if (a->compression_finish != NULL) {
r1 = (a->compression_finish)(a);
@ -210,41 +256,47 @@ archive_write_close(struct archive *a)
r = r1;
}
a->state = ARCHIVE_STATE_CLOSED;
a->archive.state = ARCHIVE_STATE_CLOSED;
return (r);
}
/*
* Destroy the archive structure.
*/
void
archive_write_finish(struct archive *a)
static int
_archive_write_finish(struct archive *_a)
{
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_finish");
if (a->state != ARCHIVE_STATE_CLOSED)
archive_write_close(a);
struct archive_write *a = (struct archive_write *)_a;
int r = ARCHIVE_OK;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_ANY, "archive_write_finish");
if (a->archive.state != ARCHIVE_STATE_CLOSED)
r = archive_write_close(&a->archive);
/* Release various dynamic buffers. */
free((void *)(uintptr_t)(const void *)a->nulls);
archive_string_free(&a->error_string);
a->magic = 0;
archive_string_free(&a->archive.error_string);
a->archive.magic = 0;
free(a);
return (r);
}
/*
* Write the appropriate header.
*/
int
archive_write_header(struct archive *a, struct archive_entry *entry)
static int
_archive_write_header(struct archive *_a, struct archive_entry *entry)
{
struct archive_write *a = (struct archive_write *)_a;
int ret, r2;
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_DATA | ARCHIVE_STATE_HEADER, "archive_write_header");
archive_string_empty(&a->error_string);
archive_clear_error(&a->archive);
/* In particular, "retry" and "fatal" get returned immediately. */
ret = archive_write_finish_entry(a);
ret = archive_write_finish_entry(&a->archive);
if (ret < ARCHIVE_OK && ret != ARCHIVE_WARN)
return (ret);
@ -252,7 +304,8 @@ archive_write_header(struct archive *a, struct archive_entry *entry)
archive_entry_dev(entry) == a->skip_file_dev &&
a->skip_file_ino != 0 &&
archive_entry_ino(entry) == a->skip_file_ino) {
archive_set_error(a, 0, "Can't add archive to itself");
archive_set_error(&a->archive, 0,
"Can't add archive to itself");
return (ARCHIVE_WARN);
}
@ -261,33 +314,34 @@ archive_write_header(struct archive *a, struct archive_entry *entry)
if (r2 < ret)
ret = r2;
a->state = ARCHIVE_STATE_DATA;
a->archive.state = ARCHIVE_STATE_DATA;
return (ret);
}
int
archive_write_finish_entry(struct archive * a)
static int
_archive_write_finish_entry(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
int ret = ARCHIVE_OK;
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_write_finish_entry");
if (a->state & ARCHIVE_STATE_DATA)
if (a->archive.state & ARCHIVE_STATE_DATA)
ret = (a->format_finish_entry)(a);
a->state = ARCHIVE_STATE_HEADER;
a->archive.state = ARCHIVE_STATE_HEADER;
return (ret);
}
/*
* Note that the compressor is responsible for blocking.
*/
/* Should be "ssize_t", but that breaks the ABI. <sigh> */
int
archive_write_data(struct archive *a, const void *buff, size_t s)
static ssize_t
_archive_write_data(struct archive *_a, const void *buff, size_t s)
{
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_DATA, "archive_write_data");
archive_string_empty(&a->error_string);
archive_clear_error(&a->archive);
return ((a->format_write_data)(a, buff, s));
}

View File

@ -0,0 +1,358 @@
.\" Copyright (c) 2003-2007 Tim Kientzle
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 March 2, 2007
.Dt archive_write_disk 3
.Os
.Sh NAME
.Nm archive_write_disk_new ,
.Nm archive_write_disk_set_options ,
.Nm archive_write_disk_set_skip_file ,
.Nm archive_write_disk_set_group_lookup ,
.Nm archive_write_disk_set_standard_lookup ,
.Nm archive_write_disk_set_user_lookup ,
.Nm archive_write_header ,
.Nm archive_write_data ,
.Nm archive_write_finish_entry ,
.Nm archive_write_close ,
.Nm archive_write_finish
.Nd functions for creating objects on disk
.Sh SYNOPSIS
.In archive.h
.Ft struct archive *
.Fn archive_write_disk_new "void"
.Ft int
.Fn archive_write_disk_set_options "struct archive *" "int flags"
.Ft int
.Fn archive_write_disk_set_skip_file "struct archive *" "dev_t" "ino_t"
.Ft int
.Fn archive_write_disk_set_group_lookup "struct archive *" "void *" "gid_t (*)(void *, const char *gname, gid_t gid)" "void (*cleanup)(void *)"
.Ft int
.Fn archive_write_disk_set_standard_lookup "struct archive *"
.Ft int
.Fn archive_write_disk_set_user_lookup "struct archive *" "void *" "uid_t (*)(void *, const char *uname, uid_t uid)" "void (*cleanup)(void *)"
.Ft int
.Fn archive_write_header "struct archive *" "struct archive_entry *"
.Ft ssize_t
.Fn archive_write_data "struct archive *" "const void *" "size_t"
.Ft int
.Fn archive_write_finish_entry "struct archive *"
.Ft int
.Fn archive_write_close "struct archive *"
.Ft int
.Fn archive_write_finish "struct archive *"
.Sh DESCRIPTION
These functions provide a complete API for creating objects on
disk from
.Tn struct archive_entry
descriptions.
They are most naturally used when extracting objects from an archive
using the
.Fn archive_read
interface.
The general process is to read
.Tn struct archive_entry
objects from an archive, then write those objects to a
.Tn struct archive
object created using the
.Fn archive_write_disk
family functions.
This interface is deliberately very similar to the
.Fn archive_write
interface used to write objects to a streaming archive.
.Bl -tag -width indent
.It Fn archive_write_disk_new
Allocates and initializes a
.Tn struct archive
object suitable for writing objects to disk.
.It Fn archive_write_disk_set_skip_file
Records the device and inode numbers of a file that should not be
overwritten.
This is typically used to ensure that an extraction process does not
overwrite the archive from which objects are being read.
This capability is technically unnecessary but can be a significant
performance optimization in practice.
.It Fn archive_write_disk_set_options
The options field consists of a bitwise OR of one or more of the
following values:
.Bl -tag -compact -width "indent"
.It Cm ARCHIVE_EXTRACT_OWNER
The user and group IDs should be set on the restored file.
By default, the user and group IDs are not restored.
.It Cm ARCHIVE_EXTRACT_PERM
Full permissions (including SGID, SUID, and sticky bits) should
be restored exactly as specified, without obeying the
current umask.
Note that SUID and SGID bits can only be restored if the
user and group ID of the object on disk are correct.
If
.Cm ARCHIVE_EXTRACT_OWNER
is not specified, then SUID and SGID bits will only be restored
if the default user and group IDs of newly-created objects on disk
happen to match those specified in the archive entry.
By default, only basic permissions are restored, and umask is obeyed.
.It Cm ARCHIVE_EXTRACT_TIME
The timestamps (mtime, ctime, and atime) should be restored.
By default, they are ignored.
Note that restoring of atime is not currently supported.
.It Cm ARCHIVE_EXTRACT_NO_OVERWRITE
Existing files on disk will not be overwritten.
By default, existing regular files are truncated and overwritten;
existing directories will have their permissions updated;
other pre-existing objects are unlinked and recreated from scratch.
.It Cm ARCHIVE_EXTRACT_UNLINK
Existing files on disk will be unlinked before any attempt to
create them.
In some cases, this can prove to be a significant performance improvement.
By default, existing files are truncated and rewritten, but
the file is not recreated.
In particular, the default behavior does not break existing hard links.
.It Cm ARCHIVE_EXTRACT_ACL
Attempt to restore ACLs.
By default, extended ACLs are ignored.
.It Cm ARCHIVE_EXTRACT_FFLAGS
Attempt to restore extended file flags.
By default, file flags are ignored.
.It Cm ARCHIVE_EXTRACT_XATTR
Attempt to restore POSIX.1e extended attributes.
By default, they are ignored.
.It Cm ARCHIVE_EXTRACT_SECURE_SYMLINKS
Refuse to extract any object whose final location would be altered
by a symlink on disk.
This is intended to help guard against a variety of mischief
caused by archives that (deliberately or otherwise) extract
files outside of the current directory.
The default is not to perform this check.
If
.Cm ARCHIVE_EXTRACT_UNLINK
is specified together with this option, the library will
remove any intermediate symlinks it finds and return an
error only if such symlink could not be removed.
.It Cm ARCHIVE_EXTRACT_SECURE_NODOTDOT
Refuse to extract a path that contains a
.Pa ..
element anywhere within it.
The default is to not refuse such paths.
Note that paths ending in
.Pa ..
always cause an error, regardless of this flag.
.El
.It Fn archive_write_disk_set_group_lookup , Fn archive_write_disk_set_user_lookup
The
.Tn struct archive_entry
objects contain both names and ids that can be used to identify users
and groups.
These names and ids describe the ownership of the file itself and
also appear in ACL lists.
By default, the library uses the ids and ignores the names, but
this can be overridden by registering user and group lookup functions.
To register, you must provide a lookup function which
accepts both a name and id and returns a suitable id.
You may also provide a
.Tn void *
pointer to a private data structure and a cleanup function for
that data.
The cleanup function will be invoked when the
.Tn struct archive
object is destroyed.
.It Fn archive_write_disk_set_standard_lookup
This convenience function installs a standard set of user
and group lookup functions.
These functions use
.Xr getpwnam 3
and
.Xr getgrnam 3
to convert names to ids, defaulting to the ids if the names cannot
be looked up.
These functions also implement a simple memory cache to reduce
the number of calls to
.Xr getpwnam 3
and
.Xr getgrnam 3 .
.It Fn archive_write_header
Build and write a header using the data in the provided
.Tn struct archive_entry
structure.
See
.Xr archive_entry 3
for information on creating and populating
.Tn struct archive_entry
objects.
.It Fn archive_write_data
Write data corresponding to the header just written.
Returns number of bytes written or -1 on error.
.It Fn archive_write_finish_entry
Close out the entry just written.
Ordinarily, clients never need to call this, as it
is called automatically by
.Fn archive_write_next_header
and
.Fn archive_write_close
as needed.
.It Fn archive_write_close
Set any attributes that could not be set during the initial restore.
For example, directory timestamps are not restored initially because
restoring a subsequent file would alter that timestamp.
Similarly, non-writable directories are initially created with
write permissions (so that their contents can be restored).
The
.Nm
library maintains a list of all such deferred attributes and
sets them when this function is invoked.
.It Fn archive_write_finish
Invokes
.Fn archive_write_close
if it was not invoked manually, then releases all resources.
.El
More information about the
.Va struct archive
object and the overall design of the library can be found in the
.Xr libarchive 3
overview.
Many of these functions are also documented under
.Xr archive_write 3 .
.Sh RETURN VALUES
Most functions return
.Cm ARCHIVE_OK
(zero) on success, or one of several non-zero
error codes for errors.
Specific error codes include:
.Cm ARCHIVE_RETRY
for operations that might succeed if retried,
.Cm ARCHIVE_WARN
for unusual conditions that do not prevent further operations, and
.Cm ARCHIVE_FATAL
for serious errors that make remaining operations impossible.
The
.Fn archive_errno
and
.Fn archive_error_string
functions can be used to retrieve an appropriate error code and a
textual error message.
.Pp
.Fn archive_write_disk_new
returns a pointer to a newly-allocated
.Tn struct archive
object.
.Pp
.Fn archive_write_data
returns a count of the number of bytes actually written.
On error, -1 is returned and the
.Fn archive_errno
and
.Fn archive_error_string
functions will return appropriate values.
.Sh SEE ALSO
.Xr archive_read 3 ,
.Xr archive_write 3 ,
.Xr tar 1 ,
.Xr libarchive 3
.Sh HISTORY
The
.Nm libarchive
library first appeared in
.Fx 5.3 .
The
.Nm archive_write_disk
interface was added to
.Nm libarchive 2.0
and first appeared in
.Fx 6.3 .
.Sh AUTHORS
.An -nosplit
The
.Nm libarchive
library was written by
.An Tim Kientzle Aq kientzle@acm.org .
.Sh BUGS
Directories are actually extracted in two distinct phases.
Directories are created during
.Fn archive_write_header ,
but final permissions are not set until
.Fn archive_write_close .
This separation is necessary to correctly handle borderline
cases such as a non-writable directory containing
files, but can cause unexpected results.
In particular, directory permissions are not fully
restored until the archive is closed.
If you use
.Xr chdir 2
to change the current directory between calls to
.Fn archive_read_extract
or before calling
.Fn archive_read_close ,
you may confuse the permission-setting logic with
the result that directory permissions are restored
incorrectly.
.Pp
The library attempts to create objects with filenames longer than
.Cm PATH_MAX
by creating prefixes of the full path and changing the current directory.
Currently, this logic is limited in scope; the fixup pass does
not work correctly for such objects and the symlink security check
option disables the support for very long pathnames.
.Pp
Restoring the path
.Pa aa/../bb
does create each intermediate directory.
In particular, the directory
.Pa aa
is created as well as the final object
.Pa bb .
In theory, this can be exploited to create an entire directory heirarchy
with a single request.
Of course, this does not work if the
.Cm ARCHIVE_EXTRACT_NODOTDOT
option is specified.
.Pp
Implicit directories are always created obeying the current umask.
Explicit objects are created obeying the current umask unless
.Cm ARCHIVE_EXTRACT_PERM
is specified, in which case they current umask is ignored.
.Pp
SGID and SUID bits are restored only if the correct user and
group could be set.
If
.Cm ARCHIVE_EXTRACT_OWNER
is not specified, then no attempt is made to set the ownership.
In this case, SGID and SUID bits are restored only if the
user and group of the final object happen to match those specified
in the entry.
.Pp
The
.Dq standard
user-id and group-id lookup functions are not the defaults because
.Xr getgrnam 3
and
.Xr getpwnam 3
are sometimes too large for particular applications.
The current design allows the application author to use a more
compact implementation when appropriate.
.Pp
There should be a corresponding
.Nm archive_read_disk
interface that walks a directory heirarchy and returns archive
entry objects.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
/*-
* 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 ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
#define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
struct archive_write_disk;
#endif

View File

@ -0,0 +1,212 @@
/*-
* 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 "archive_platform.h"
__FBSDID("$FreeBSD$");
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_ACL_H
#include <sys/acl.h>
#endif
#ifdef HAVE_ATTR_XATTR_H
#include <attr/xattr.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "archive.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_write_disk_private.h"
struct bucket {
char *name;
int hash;
id_t id;
};
static unsigned int hash(const char *);
static gid_t lookup_gid(void *, const char *uname, gid_t);
static uid_t lookup_uid(void *, const char *uname, uid_t);
static void cleanup(void *);
/*
* Installs functions that use getpwnam()/getgrnam()---along with
* a simple cache to accelerate such lookups---into the archive_write_disk
* object. This is in a separate file because getpwnam()/getgrnam()
* can pull in a LOT of library code (including NIS/LDAP functions, which
* pull in DNS resolveers, etc). This can easily top 500kB, which makes
* it inappropriate for some space-constrained applications.
*
* Applications that are size-sensitive may want to just use the
* real default functions (defined in archive_write_disk.c) that just
* use the uid/gid without the lookup. Or define your own custom functions
* if you prefer.
*
* TODO: Replace these hash tables with simpler move-to-front LRU
* lists with a bounded size (128 items?). The hash is a bit faster,
* but has a bad pathology in which it thrashes a single bucket. Even
* walking a list of 128 items is a lot faster than calling
* getpwnam()!
*/
int
archive_write_disk_set_standard_lookup(struct archive *a)
{
struct bucket *ucache = malloc(sizeof(struct bucket[127]));
struct bucket *gcache = malloc(sizeof(struct bucket[127]));
memset(ucache, 0, sizeof(struct bucket[127]));
memset(gcache, 0, sizeof(struct bucket[127]));
archive_write_disk_set_group_lookup(a, gcache, lookup_gid, cleanup);
archive_write_disk_set_user_lookup(a, ucache, lookup_uid, cleanup);
return (ARCHIVE_OK);
}
static gid_t
lookup_gid(void *private_data, const char *gname, gid_t gid)
{
int h;
struct bucket *b;
int cache_size;
struct bucket *gcache = (struct bucket *)private_data;
cache_size = 127;
/* If no gname, just use the gid provided. */
if (gname == NULL || *gname == '\0')
return (gid);
/* Try to find gname in the cache. */
h = hash(gname);
b = &gcache[h % cache_size ];
if (b->name != NULL && b->hash == h && strcmp(gname, b->name) == 0)
return ((gid_t)b->id);
/* Free the cache slot for a new entry. */
if (b->name != NULL)
free(b->name);
b->name = strdup(gname);
/* Note: If strdup fails, that's okay; we just won't cache. */
b->hash = h;
#if HAVE_GRP_H
{
struct group *grent = getgrnam(gname);
if (grent != NULL)
gid = grent->gr_gid;
}
#elif _WIN32
/* TODO: do a gname->gid lookup for Windows. */
#endif
b->id = gid;
return (gid);
}
static uid_t
lookup_uid(void *private_data, const char *uname, uid_t uid)
{
int h;
struct bucket *b;
int cache_size;
struct bucket *ucache = (struct bucket *)private_data;
cache_size = 127;
/* If no uname, just use the uid provided. */
if (uname == NULL || *uname == '\0')
return (uid);
/* Try to find uname in the cache. */
h = hash(uname);
b = &ucache[h % cache_size ];
if (b->name != NULL && b->hash == h && strcmp(uname, b->name) == 0)
return ((uid_t)b->id);
/* Free the cache slot for a new entry. */
if (b->name != NULL)
free(b->name);
b->name = strdup(uname);
/* Note: If strdup fails, that's okay; we just won't cache. */
b->hash = h;
#if HAVE_PWD_H
{
struct passwd *pwent = getpwnam(uname);
if (pwent != NULL)
uid = pwent->pw_uid;
}
#elif _WIN32
/* TODO: do a uname->uid lookup for Windows. */
#endif
b->id = uid;
return (uid);
}
static void
cleanup(void *private)
{
free(private);
}
static unsigned int
hash(const char *p)
{
/* A 32-bit version of Peter Weinberger's (PJW) hash algorithm,
as used by ELF for hashing function names. */
unsigned g, h = 0;
while (*p != '\0') {
h = ( h << 4 ) + *p++;
if (( g = h & 0xF0000000 )) {
h ^= g >> 24;
h &= 0x0FFFFFFF;
}
}
return h;
}

View File

@ -0,0 +1,177 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef ARCHIVE_WRITE_PRIVATE_H_INCLUDED
#define ARCHIVE_WRITE_PRIVATE_H_INCLUDED
#include "archive.h"
#include "archive_string.h"
#include "archive_private.h"
struct archive_write {
struct archive archive;
struct archive_entry *entry;
/* Dev/ino of the archive being read/written. */
dev_t skip_file_dev;
ino_t skip_file_ino;
/* Utility: Pointer to a block of nulls. */
const unsigned char *nulls;
size_t null_length;
/*
* Used by archive_read_data() to track blocks and copy
* data to client buffers, filling gaps with zero bytes.
*/
const char *read_data_block;
off_t read_data_offset;
off_t read_data_output_offset;
size_t read_data_remaining;
/* Callbacks to open/read/write/close archive stream. */
archive_open_callback *client_opener;
archive_read_callback *client_reader;
archive_skip_callback *client_skipper;
archive_write_callback *client_writer;
archive_close_callback *client_closer;
void *client_data;
/*
* Blocking information. Note that bytes_in_last_block is
* misleadingly named; I should find a better name. These
* control the final output from all compressors, including
* compression_none.
*/
int bytes_per_block;
int bytes_in_last_block;
/*
* These control whether data within a gzip/bzip2 compressed
* stream gets padded or not. If pad_uncompressed is set,
* the data will be padded to a full block before being
* compressed. The pad_uncompressed_byte determines the value
* that will be used for padding. Note that these have no
* effect on compression "none."
*/
int pad_uncompressed;
int pad_uncompressed_byte; /* TODO: Support this. */
/*
* On write, the client just invokes an archive_write_set function
* which sets up the data here directly.
*/
void *compression_data; /* Data for (de)compressor. */
int (*compression_init)(struct archive_write *); /* Initialize. */
int (*compression_finish)(struct archive_write *);
int (*compression_write)(struct archive_write *, const void *, size_t);
/*
* Read uses a peek/consume I/O model: the decompression code
* returns a pointer to the requested block and advances the
* file position only when requested by a consume call. This
* reduces copying and also simplifies look-ahead for format
* detection.
*/
ssize_t (*compression_read_ahead)(struct archive *,
const void **, size_t request);
ssize_t (*compression_read_consume)(struct archive *, size_t);
off_t (*compression_skip)(struct archive *, off_t);
/*
* Format detection is mostly the same as compression
* detection, with two significant differences: The bidders
* use the read_ahead calls above to examine the stream rather
* than having the supervisor hand them a block of data to
* examine, and the auction is repeated for every header.
* Winning bidders should set the archive_format and
* archive_format_name appropriately. Bid routines should
* check archive_format and decline to bid if the format of
* the last header was incompatible.
*
* Again, write support is considerably simpler because there's
* no need for an auction.
*/
int archive_format;
const char *archive_format_name;
struct archive_format_descriptor {
int (*bid)(struct archive *);
int (*read_header)(struct archive *, struct archive_entry *);
int (*read_data)(struct archive *, const void **, size_t *, off_t *);
int (*read_data_skip)(struct archive *);
int (*cleanup)(struct archive *);
void *format_data; /* Format-specific data for readers. */
} formats[8];
struct archive_format_descriptor *format; /* Active format. */
/*
* Storage for format-specific data. Note that there can be
* multiple format readers active at one time, so we need to
* allow for multiple format readers to have their data
* available. The pformat_data slot here is the solution: on
* read, it is guaranteed to always point to a void* variable
* that the format can use.
*/
void **pformat_data; /* Pointer to current format_data. */
void *format_data; /* Used by writers. */
/*
* Pointers to format-specific functions for writing. They're
* initialized by archive_write_set_format_XXX() calls.
*/
int (*format_init)(struct archive_write *);
int (*format_finish)(struct archive_write *);
int (*format_destroy)(struct archive_write *);
int (*format_finish_entry)(struct archive_write *);
int (*format_write_header)(struct archive_write *,
struct archive_entry *);
ssize_t (*format_write_data)(struct archive_write *,
const void *buff, size_t);
/*
* Various information needed by archive_extract.
*/
struct extract *extract;
int (*cleanup_archive_extract)(struct archive *);
};
/*
* Utility function to format a USTAR header into a buffer. If
* "strict" is set, this tries to create the absolutely most portable
* version of a ustar header. If "strict" is set to 0, then it will
* relax certain requirements.
*
* Generally, format-specific declarations don't belong in this
* header; this is a rare example of a function that is shared by
* two very similar formats (ustar and pax).
*/
int
__archive_write_format_header_ustar(struct archive_write *, char buff[512],
struct archive_entry *, int tartype, int strict);
#endif

View File

@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
#include "archive_write_private.h"
struct private_data {
bz_stream stream;
@ -62,23 +63,23 @@ struct private_data {
#define SET_NEXT_IN(st,src) \
(st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
static int archive_compressor_bzip2_finish(struct archive *);
static int archive_compressor_bzip2_init(struct archive *);
static int archive_compressor_bzip2_write(struct archive *, const void *,
size_t);
static int drive_compressor(struct archive *, struct private_data *,
static int archive_compressor_bzip2_finish(struct archive_write *);
static int archive_compressor_bzip2_init(struct archive_write *);
static int archive_compressor_bzip2_write(struct archive_write *,
const void *, size_t);
static int drive_compressor(struct archive_write *, struct private_data *,
int finishing);
/*
* Allocate, initialize and return an archive object.
*/
int
archive_write_set_compression_bzip2(struct archive *a)
archive_write_set_compression_bzip2(struct archive *_a)
{
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
a->compression_init = &archive_compressor_bzip2_init;
a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
a->compression_name = "bzip2";
return (ARCHIVE_OK);
}
@ -86,23 +87,23 @@ archive_write_set_compression_bzip2(struct archive *a)
* Setup callback.
*/
static int
archive_compressor_bzip2_init(struct archive *a)
archive_compressor_bzip2_init(struct archive_write *a)
{
int ret;
struct private_data *state;
a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
a->compression_name = "bzip2";
a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
a->archive.compression_name = "bzip2";
if (a->client_opener != NULL) {
ret = (a->client_opener)(a, a->client_data);
ret = (a->client_opener)(&a->archive, a->client_data);
if (ret != 0)
return (ret);
}
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for compression");
return (ARCHIVE_FATAL);
}
@ -112,7 +113,7 @@ archive_compressor_bzip2_init(struct archive *a)
state->compressed = (char *)malloc(state->compressed_buffer_size);
if (state->compressed == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for compression buffer");
free(state);
return (ARCHIVE_FATAL);
@ -131,7 +132,7 @@ archive_compressor_bzip2_init(struct archive *a)
}
/* Library setup failed: clean up. */
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library");
free(state->compressed);
free(state);
@ -139,17 +140,17 @@ archive_compressor_bzip2_init(struct archive *a)
/* Override the error message if we know what really went wrong. */
switch (ret) {
case BZ_PARAM_ERROR:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid setup parameter");
break;
case BZ_MEM_ERROR:
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Internal error initializing compression library: "
"out of memory");
break;
case BZ_CONFIG_ERROR:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"mis-compiled library");
break;
@ -165,14 +166,14 @@ archive_compressor_bzip2_init(struct archive *a)
* Returns ARCHIVE_OK if all data written, error otherwise.
*/
static int
archive_compressor_bzip2_write(struct archive *a, const void *buff,
archive_compressor_bzip2_write(struct archive_write *a, const void *buff,
size_t length)
{
struct private_data *state;
state = (struct private_data *)a->compression_data;
if (a->client_writer == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@ -186,7 +187,7 @@ archive_compressor_bzip2_write(struct archive *a, const void *buff,
state->stream.avail_in = length;
if (drive_compressor(a, state, 0))
return (ARCHIVE_FATAL);
a->file_position += length;
a->archive.file_position += length;
return (ARCHIVE_OK);
}
@ -195,7 +196,7 @@ archive_compressor_bzip2_write(struct archive *a, const void *buff,
* Finish the compression.
*/
static int
archive_compressor_bzip2_finish(struct archive *a)
archive_compressor_bzip2_finish(struct archive_write *a)
{
ssize_t block_length;
int ret;
@ -207,7 +208,7 @@ archive_compressor_bzip2_finish(struct archive *a)
state = (struct private_data *)a->compression_data;
ret = ARCHIVE_OK;
if (a->client_writer == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered?\n"
"This is probably an internal programming error.");
ret = ARCHIVE_FATAL;
@ -257,14 +258,14 @@ archive_compressor_bzip2_finish(struct archive *a)
}
/* Write the last block */
bytes_written = (a->client_writer)(a, a->client_data,
bytes_written = (a->client_writer)(&a->archive, a->client_data,
state->compressed, block_length);
/* TODO: Handle short write of final block. */
if (bytes_written <= 0)
ret = ARCHIVE_FATAL;
else {
a->raw_position += ret;
a->archive.raw_position += ret;
ret = ARCHIVE_OK;
}
@ -274,7 +275,7 @@ archive_compressor_bzip2_finish(struct archive *a)
case BZ_OK:
break;
default:
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Failed to clean up compressor");
ret = ARCHIVE_FATAL;
}
@ -284,7 +285,7 @@ archive_compressor_bzip2_finish(struct archive *a)
/* Close the output */
if (a->client_closer != NULL)
(a->client_closer)(a, a->client_data);
(a->client_closer)(&a->archive, a->client_data);
return (ret);
}
@ -297,15 +298,16 @@ archive_compressor_bzip2_finish(struct archive *a)
* false) and the end-of-archive case (finishing == true).
*/
static int
drive_compressor(struct archive *a, struct private_data *state, int finishing)
drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
{
ssize_t bytes_written;
int ret;
for (;;) {
if (state->stream.avail_out == 0) {
bytes_written = (a->client_writer)(a, a->client_data,
state->compressed, state->compressed_buffer_size);
bytes_written = (a->client_writer)(&a->archive,
a->client_data, state->compressed,
state->compressed_buffer_size);
if (bytes_written <= 0) {
/* TODO: Handle this write failure */
return (ARCHIVE_FATAL);
@ -317,7 +319,7 @@ drive_compressor(struct archive *a, struct private_data *state, int finishing)
state->compressed_buffer_size - bytes_written);
}
a->raw_position += bytes_written;
a->archive.raw_position += bytes_written;
state->stream.next_out = state->compressed +
state->compressed_buffer_size - bytes_written;
state->stream.avail_out = bytes_written;
@ -340,7 +342,8 @@ drive_compressor(struct archive *a, struct private_data *state, int finishing)
return (ARCHIVE_OK);
default:
/* Any other return value indicates an error */
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_PROGRAMMER,
"Bzip2 compression failed");
return (ARCHIVE_FATAL);
}

View File

@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
#include "archive_write_private.h"
struct private_data {
z_stream stream;
@ -63,11 +64,11 @@ struct private_data {
#define SET_NEXT_IN(st,src) \
(st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src)
static int archive_compressor_gzip_finish(struct archive *);
static int archive_compressor_gzip_init(struct archive *);
static int archive_compressor_gzip_write(struct archive *, const void *,
size_t);
static int drive_compressor(struct archive *, struct private_data *,
static int archive_compressor_gzip_finish(struct archive_write *);
static int archive_compressor_gzip_init(struct archive_write *);
static int archive_compressor_gzip_write(struct archive_write *,
const void *, size_t);
static int drive_compressor(struct archive_write *, struct private_data *,
int finishing);
@ -75,12 +76,14 @@ static int drive_compressor(struct archive *, struct private_data *,
* Allocate, initialize and return a archive object.
*/
int
archive_write_set_compression_gzip(struct archive *a)
archive_write_set_compression_gzip(struct archive *_a)
{
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
a->compression_init = &archive_compressor_gzip_init;
a->compression_code = ARCHIVE_COMPRESSION_GZIP;
a->compression_name = "gzip";
a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
a->archive.compression_name = "gzip";
return (ARCHIVE_OK);
}
@ -88,24 +91,24 @@ archive_write_set_compression_gzip(struct archive *a)
* Setup callback.
*/
static int
archive_compressor_gzip_init(struct archive *a)
archive_compressor_gzip_init(struct archive_write *a)
{
int ret;
struct private_data *state;
time_t t;
a->compression_code = ARCHIVE_COMPRESSION_GZIP;
a->compression_name = "gzip";
a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
a->archive.compression_name = "gzip";
if (a->client_opener != NULL) {
ret = (a->client_opener)(a, a->client_data);
ret = (a->client_opener)(&a->archive, a->client_data);
if (ret != ARCHIVE_OK)
return (ret);
}
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for compression");
return (ARCHIVE_FATAL);
}
@ -116,7 +119,7 @@ archive_compressor_gzip_init(struct archive *a)
state->crc = crc32(0L, NULL, 0);
if (state->compressed == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for compression buffer");
free(state);
return (ARCHIVE_FATAL);
@ -157,7 +160,7 @@ archive_compressor_gzip_init(struct archive *a)
}
/* Library setup failed: clean up. */
archive_set_error(a, ARCHIVE_ERRNO_MISC, "Internal error "
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal error "
"initializing compression library");
free(state->compressed);
free(state);
@ -165,16 +168,16 @@ archive_compressor_gzip_init(struct archive *a)
/* Override the error message if we know what really went wrong. */
switch (ret) {
case Z_STREAM_ERROR:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing "
"compression library: invalid setup parameter");
break;
case Z_MEM_ERROR:
archive_set_error(a, ENOMEM, "Internal error initializing "
archive_set_error(&a->archive, ENOMEM, "Internal error initializing "
"compression library");
break;
case Z_VERSION_ERROR:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing "
"compression library: invalid library version");
break;
@ -187,7 +190,7 @@ archive_compressor_gzip_init(struct archive *a)
* Write data to the compressed stream.
*/
static int
archive_compressor_gzip_write(struct archive *a, const void *buff,
archive_compressor_gzip_write(struct archive_write *a, const void *buff,
size_t length)
{
struct private_data *state;
@ -195,7 +198,7 @@ archive_compressor_gzip_write(struct archive *a, const void *buff,
state = (struct private_data *)a->compression_data;
if (a->client_writer == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@ -211,7 +214,7 @@ archive_compressor_gzip_write(struct archive *a, const void *buff,
if ((ret = drive_compressor(a, state, 0)) != ARCHIVE_OK)
return (ret);
a->file_position += length;
a->archive.file_position += length;
return (ARCHIVE_OK);
}
@ -220,7 +223,7 @@ archive_compressor_gzip_write(struct archive *a, const void *buff,
* Finish the compression...
*/
static int
archive_compressor_gzip_finish(struct archive *a)
archive_compressor_gzip_finish(struct archive_write *a)
{
ssize_t block_length, target_block_length, bytes_written;
int ret;
@ -231,7 +234,7 @@ archive_compressor_gzip_finish(struct archive *a)
state = (struct private_data *)a->compression_data;
ret = 0;
if (a->client_writer == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
"This is probably an internal programming error.");
ret = ARCHIVE_FATAL;
@ -280,13 +283,13 @@ archive_compressor_gzip_finish(struct archive *a)
/* If it overflowed, flush and start a new block. */
if (tocopy < 8) {
bytes_written = (a->client_writer)(a, a->client_data,
bytes_written = (a->client_writer)(&a->archive, a->client_data,
state->compressed, state->compressed_buffer_size);
if (bytes_written <= 0) {
ret = ARCHIVE_FATAL;
goto cleanup;
}
a->raw_position += bytes_written;
a->archive.raw_position += bytes_written;
state->stream.next_out = state->compressed;
state->stream.avail_out = state->compressed_buffer_size;
memcpy(state->stream.next_out, trailer + tocopy, 8-tocopy);
@ -317,13 +320,13 @@ archive_compressor_gzip_finish(struct archive *a)
}
/* Write the last block */
bytes_written = (a->client_writer)(a, a->client_data,
bytes_written = (a->client_writer)(&a->archive, a->client_data,
state->compressed, block_length);
if (bytes_written <= 0) {
ret = ARCHIVE_FATAL;
goto cleanup;
}
a->raw_position += bytes_written;
a->archive.raw_position += bytes_written;
/* Cleanup: shut down compressor, release memory, etc. */
cleanup:
@ -331,7 +334,7 @@ archive_compressor_gzip_finish(struct archive *a)
case Z_OK:
break;
default:
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Failed to clean up compressor");
ret = ARCHIVE_FATAL;
}
@ -340,7 +343,7 @@ archive_compressor_gzip_finish(struct archive *a)
/* Close the output */
if (a->client_closer != NULL)
(a->client_closer)(a, a->client_data);
(a->client_closer)(&a->archive, a->client_data);
return (ret);
}
@ -353,15 +356,16 @@ archive_compressor_gzip_finish(struct archive *a)
* false) and the end-of-archive case (finishing == true).
*/
static int
drive_compressor(struct archive *a, struct private_data *state, int finishing)
drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
{
ssize_t bytes_written;
int ret;
for (;;) {
if (state->stream.avail_out == 0) {
bytes_written = (a->client_writer)(a, a->client_data,
state->compressed, state->compressed_buffer_size);
bytes_written = (a->client_writer)(&a->archive,
a->client_data, state->compressed,
state->compressed_buffer_size);
if (bytes_written <= 0) {
/* TODO: Handle this write failure */
return (ARCHIVE_FATAL);
@ -372,7 +376,7 @@ drive_compressor(struct archive *a, struct private_data *state, int finishing)
state->compressed + bytes_written,
state->compressed_buffer_size - bytes_written);
}
a->raw_position += bytes_written;
a->archive.raw_position += bytes_written;
state->stream.next_out
= state->compressed +
state->compressed_buffer_size - bytes_written;
@ -396,7 +400,7 @@ drive_compressor(struct archive *a, struct private_data *state, int finishing)
return (ARCHIVE_OK);
default:
/* Any other return value indicates an error. */
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"GZip compression failed");
return (ARCHIVE_FATAL);
}

View File

@ -38,11 +38,12 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
#include "archive_write_private.h"
static int archive_compressor_none_finish(struct archive *a);
static int archive_compressor_none_init(struct archive *);
static int archive_compressor_none_write(struct archive *, const void *,
size_t);
static int archive_compressor_none_finish(struct archive_write *a);
static int archive_compressor_none_init(struct archive_write *);
static int archive_compressor_none_write(struct archive_write *,
const void *, size_t);
struct archive_none {
char *buffer;
@ -52,12 +53,12 @@ struct archive_none {
};
int
archive_write_set_compression_none(struct archive *a)
archive_write_set_compression_none(struct archive *_a)
{
__archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_none");
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_none");
a->compression_init = &archive_compressor_none_init;
a->compression_code = ARCHIVE_COMPRESSION_NONE;
a->compression_name = "none";
return (0);
}
@ -65,23 +66,23 @@ archive_write_set_compression_none(struct archive *a)
* Setup callback.
*/
static int
archive_compressor_none_init(struct archive *a)
archive_compressor_none_init(struct archive_write *a)
{
int ret;
struct archive_none *state;
a->compression_code = ARCHIVE_COMPRESSION_NONE;
a->compression_name = "none";
a->archive.compression_code = ARCHIVE_COMPRESSION_NONE;
a->archive.compression_name = "none";
if (a->client_opener != NULL) {
ret = (a->client_opener)(a, a->client_data);
ret = (a->client_opener)(&a->archive, a->client_data);
if (ret != 0)
return (ret);
}
state = (struct archive_none *)malloc(sizeof(*state));
if (state == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for output buffering");
return (ARCHIVE_FATAL);
}
@ -91,7 +92,7 @@ archive_compressor_none_init(struct archive *a)
if (state->buffer_size != 0) {
state->buffer = (char *)malloc(state->buffer_size);
if (state->buffer == NULL) {
archive_set_error(a, ENOMEM,
archive_set_error(&a->archive, ENOMEM,
"Can't allocate output buffer");
free(state);
return (ARCHIVE_FATAL);
@ -111,7 +112,7 @@ archive_compressor_none_init(struct archive *a)
* Write data to the stream.
*/
static int
archive_compressor_none_write(struct archive *a, const void *vbuff,
archive_compressor_none_write(struct archive_write *a, const void *vbuff,
size_t length)
{
const char *buff;
@ -122,7 +123,7 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
state = (struct archive_none *)a->compression_data;
buff = (const char *)vbuff;
if (a->client_writer == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@ -138,14 +139,14 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
*/
if (state->buffer_size == 0) {
while (remaining > 0) {
bytes_written = (a->client_writer)(a, a->client_data,
buff, remaining);
bytes_written = (a->client_writer)(&a->archive,
a->client_data, buff, remaining);
if (bytes_written <= 0)
return (ARCHIVE_FATAL);
remaining -= bytes_written;
buff += bytes_written;
}
a->file_position += length;
a->archive.file_position += length;
return (ARCHIVE_OK);
}
@ -155,12 +156,12 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
* output buffer.
*/
if (state->avail == 0) {
bytes_written = (a->client_writer)(a, a->client_data,
state->buffer, state->buffer_size);
bytes_written = (a->client_writer)(&a->archive,
a->client_data, state->buffer, state->buffer_size);
if (bytes_written <= 0)
return (ARCHIVE_FATAL);
/* XXX TODO: if bytes_written < state->buffer_size */
a->raw_position += bytes_written;
a->archive.raw_position += bytes_written;
state->next = state->buffer;
state->avail = state->buffer_size;
}
@ -174,7 +175,7 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
buff += to_copy;
remaining -= to_copy;
}
a->file_position += length;
a->archive.file_position += length;
return (ARCHIVE_OK);
}
@ -183,7 +184,7 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
* Finish the compression.
*/
static int
archive_compressor_none_finish(struct archive *a)
archive_compressor_none_finish(struct archive_write *a)
{
ssize_t block_length;
ssize_t target_block_length;
@ -195,7 +196,7 @@ archive_compressor_none_finish(struct archive *a)
state = (struct archive_none *)a->compression_data;
ret = ret2 = ARCHIVE_OK;
if (a->client_writer == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@ -222,19 +223,19 @@ archive_compressor_none_finish(struct archive *a)
target_block_length - block_length);
block_length = target_block_length;
}
bytes_written = (a->client_writer)(a, a->client_data,
state->buffer, block_length);
bytes_written = (a->client_writer)(&a->archive,
a->client_data, state->buffer, block_length);
if (bytes_written <= 0)
ret = ARCHIVE_FATAL;
else {
a->raw_position += bytes_written;
a->archive.raw_position += bytes_written;
ret = ARCHIVE_OK;
}
}
/* Close the output */
if (a->client_closer != NULL)
ret2 = (a->client_closer)(a, a->client_data);
ret2 = (a->client_closer)(&a->archive, a->client_data);
free(state->buffer);
free(state);

View File

@ -43,12 +43,14 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_write_private.h"
static ssize_t archive_write_cpio_data(struct archive *, const void *buff,
size_t s);
static int archive_write_cpio_finish(struct archive *);
static int archive_write_cpio_finish_entry(struct archive *);
static int archive_write_cpio_header(struct archive *,
static ssize_t archive_write_cpio_data(struct archive_write *,
const void *buff, size_t s);
static int archive_write_cpio_finish(struct archive_write *);
static int archive_write_cpio_destroy(struct archive_write *);
static int archive_write_cpio_finish_entry(struct archive_write *);
static int archive_write_cpio_header(struct archive_write *,
struct archive_entry *);
static int format_octal(int64_t, void *, int);
static int64_t format_octal_recursive(int64_t, char *, int);
@ -75,17 +77,18 @@ struct cpio_header {
* Set output format to 'cpio' format.
*/
int
archive_write_set_format_cpio(struct archive *a)
archive_write_set_format_cpio(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
struct cpio *cpio;
/* If someone else was already registered, unregister them. */
if (a->format_finish != NULL)
(a->format_finish)(a);
if (a->format_destroy != NULL)
(a->format_destroy)(a);
cpio = (struct cpio *)malloc(sizeof(*cpio));
if (cpio == NULL) {
archive_set_error(a, ENOMEM, "Can't allocate cpio data");
archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
return (ARCHIVE_FATAL);
}
memset(cpio, 0, sizeof(*cpio));
@ -96,13 +99,14 @@ archive_write_set_format_cpio(struct archive *a)
a->format_write_data = archive_write_cpio_data;
a->format_finish_entry = archive_write_cpio_finish_entry;
a->format_finish = archive_write_cpio_finish;
a->format_destroy = archive_write_cpio_destroy;
a->archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
a->archive_format_name = "POSIX cpio";
return (ARCHIVE_OK);
}
static int
archive_write_cpio_header(struct archive *a, struct archive_entry *entry)
archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
{
struct cpio *cpio;
const char *p, *path;
@ -126,7 +130,7 @@ archive_write_cpio_header(struct archive *a, struct archive_entry *entry)
* field only limits the number of files in the archive.
*/
if (st->st_ino > 0777777) {
archive_set_error(a, ERANGE, "large inode number truncated");
archive_set_error(&a->archive, ERANGE, "large inode number truncated");
ret = ARCHIVE_WARN;
}
@ -167,7 +171,7 @@ archive_write_cpio_header(struct archive *a, struct archive_entry *entry)
}
static ssize_t
archive_write_cpio_data(struct archive *a, const void *buff, size_t s)
archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s)
{
struct cpio *cpio;
int ret;
@ -215,7 +219,7 @@ format_octal_recursive(int64_t v, char *p, int s)
}
static int
archive_write_cpio_finish(struct archive *a)
archive_write_cpio_finish(struct archive_write *a)
{
struct cpio *cpio;
struct stat st;
@ -230,14 +234,22 @@ archive_write_cpio_finish(struct archive *a)
archive_entry_set_pathname(trailer, "TRAILER!!!");
er = archive_write_cpio_header(a, trailer);
archive_entry_free(trailer);
free(cpio);
a->format_data = NULL;
return (er);
}
static int
archive_write_cpio_finish_entry(struct archive *a)
archive_write_cpio_destroy(struct archive_write *a)
{
struct cpio *cpio;
cpio = (struct cpio *)a->format_data;
free(cpio);
a->format_data = NULL;
return (ARCHIVE_OK);
}
static int
archive_write_cpio_finish_entry(struct archive_write *a)
{
struct cpio *cpio;
int to_write, ret;

View File

@ -52,12 +52,12 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_write_private.h"
struct pax {
uint64_t entry_bytes_remaining;
uint64_t entry_padding;
struct archive_string pax_header;
char written;
};
static void add_pax_attr(struct archive_string *, const char *key,
@ -69,11 +69,12 @@ static void add_pax_attr_time(struct archive_string *,
unsigned long nanos);
static void add_pax_attr_w(struct archive_string *,
const char *key, const wchar_t *wvalue);
static ssize_t archive_write_pax_data(struct archive *,
static ssize_t archive_write_pax_data(struct archive_write *,
const void *, size_t);
static int archive_write_pax_finish(struct archive *);
static int archive_write_pax_finish_entry(struct archive *);
static int archive_write_pax_header(struct archive *,
static int archive_write_pax_finish(struct archive_write *);
static int archive_write_pax_destroy(struct archive_write *);
static int archive_write_pax_finish_entry(struct archive_write *);
static int archive_write_pax_header(struct archive_write *,
struct archive_entry *);
static char *base64_encode(const char *src, size_t len);
static char *build_pax_attribute_name(char *dest, const char *src);
@ -82,7 +83,7 @@ static char *build_ustar_entry_name(char *dest, const char *src,
static char *format_int(char *dest, int64_t);
static int has_non_ASCII(const wchar_t *);
static char *url_encode(const char *in);
static int write_nulls(struct archive *, size_t);
static int write_nulls(struct archive_write *, size_t);
/*
* Set output format to 'restricted pax' format.
@ -92,10 +93,11 @@ static int write_nulls(struct archive *, size_t);
* bsdtar, for instance.
*/
int
archive_write_set_format_pax_restricted(struct archive *a)
archive_write_set_format_pax_restricted(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
int r;
r = archive_write_set_format_pax(a);
r = archive_write_set_format_pax(&a->archive);
a->archive_format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED;
a->archive_format_name = "restricted POSIX pax interchange";
return (r);
@ -105,16 +107,17 @@ archive_write_set_format_pax_restricted(struct archive *a)
* Set output format to 'pax' format.
*/
int
archive_write_set_format_pax(struct archive *a)
archive_write_set_format_pax(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
struct pax *pax;
if (a->format_finish != NULL)
(a->format_finish)(a);
if (a->format_destroy != NULL)
(a->format_destroy)(a);
pax = (struct pax *)malloc(sizeof(*pax));
if (pax == NULL) {
archive_set_error(a, ENOMEM, "Can't allocate pax data");
archive_set_error(&a->archive, ENOMEM, "Can't allocate pax data");
return (ARCHIVE_FATAL);
}
memset(pax, 0, sizeof(*pax));
@ -124,6 +127,7 @@ archive_write_set_format_pax(struct archive *a)
a->format_write_header = archive_write_pax_header;
a->format_write_data = archive_write_pax_data;
a->format_finish = archive_write_pax_finish;
a->format_destroy = archive_write_pax_destroy;
a->format_finish_entry = archive_write_pax_finish_entry;
a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive_format_name = "POSIX pax interchange";
@ -388,7 +392,7 @@ archive_write_pax_header_xattrs(struct pax *pax, struct archive_entry *entry)
* key/value data.
*/
static int
archive_write_pax_header(struct archive *a,
archive_write_pax_header(struct archive_write *a,
struct archive_entry *entry_original)
{
struct archive_entry *entry_main;
@ -407,7 +411,6 @@ archive_write_pax_header(struct archive *a,
need_extension = 0;
pax = (struct pax *)a->format_data;
pax->written = 1;
st_original = archive_entry_stat(entry_original);
@ -424,11 +427,11 @@ archive_write_pax_header(struct archive *a,
case S_IFIFO:
break;
case S_IFSOCK:
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"tar format cannot archive socket");
return (ARCHIVE_WARN);
default:
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"tar format cannot archive this (mode=0%lo)",
(unsigned long)st_original->st_mode);
return (ARCHIVE_WARN);
@ -1038,23 +1041,33 @@ build_pax_attribute_name(char *dest, const char *src)
/* Write two null blocks for the end of archive */
static int
archive_write_pax_finish(struct archive *a)
archive_write_pax_finish(struct archive_write *a)
{
struct pax *pax;
int r;
r = ARCHIVE_OK;
if (a->compression_write == NULL)
return (ARCHIVE_OK);
pax = (struct pax *)a->format_data;
if (pax->written && a->compression_write != NULL)
r = write_nulls(a, 512 * 2);
archive_string_free(&pax->pax_header);
free(pax);
a->format_data = NULL;
r = write_nulls(a, 512 * 2);
return (r);
}
static int
archive_write_pax_finish_entry(struct archive *a)
archive_write_pax_destroy(struct archive_write *a)
{
struct pax *pax;
pax = (struct pax *)a->format_data;
archive_string_free(&pax->pax_header);
free(pax);
a->format_data = NULL;
return (ARCHIVE_OK);
}
static int
archive_write_pax_finish_entry(struct archive_write *a)
{
struct pax *pax;
int ret;
@ -1066,7 +1079,7 @@ archive_write_pax_finish_entry(struct archive *a)
}
static int
write_nulls(struct archive *a, size_t padding)
write_nulls(struct archive_write *a, size_t padding)
{
int ret, to_write;
@ -1081,13 +1094,12 @@ write_nulls(struct archive *a, size_t padding)
}
static ssize_t
archive_write_pax_data(struct archive *a, const void *buff, size_t s)
archive_write_pax_data(struct archive_write *a, const void *buff, size_t s)
{
struct pax *pax;
int ret;
pax = (struct pax *)a->format_data;
pax->written = 1;
if (s > pax->entry_bytes_remaining)
s = pax->entry_bytes_remaining;

View File

@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_write_private.h"
struct shar {
int dump;
@ -60,19 +61,20 @@ struct shar {
struct archive_string work;
};
static int archive_write_shar_finish(struct archive *);
static int archive_write_shar_header(struct archive *,
static int archive_write_shar_finish(struct archive_write *);
static int archive_write_shar_destroy(struct archive_write *);
static int archive_write_shar_header(struct archive_write *,
struct archive_entry *);
static ssize_t archive_write_shar_data_sed(struct archive *,
static ssize_t archive_write_shar_data_sed(struct archive_write *,
const void * buff, size_t);
static ssize_t archive_write_shar_data_uuencode(struct archive *,
static ssize_t archive_write_shar_data_uuencode(struct archive_write *,
const void * buff, size_t);
static int archive_write_shar_finish_entry(struct archive *);
static int shar_printf(struct archive *, const char *fmt, ...);
static int archive_write_shar_finish_entry(struct archive_write *);
static int shar_printf(struct archive_write *, const char *fmt, ...);
static void uuencode_group(struct shar *);
static int
shar_printf(struct archive *a, const char *fmt, ...)
shar_printf(struct archive_write *a, const char *fmt, ...)
{
struct shar *shar;
va_list ap;
@ -91,17 +93,18 @@ shar_printf(struct archive *a, const char *fmt, ...)
* Set output format to 'shar' format.
*/
int
archive_write_set_format_shar(struct archive *a)
archive_write_set_format_shar(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
struct shar *shar;
/* If someone else was already registered, unregister them. */
if (a->format_finish != NULL)
(a->format_finish)(a);
if (a->format_destroy != NULL)
(a->format_destroy)(a);
shar = (struct shar *)malloc(sizeof(*shar));
if (shar == NULL) {
archive_set_error(a, ENOMEM, "Can't allocate shar data");
archive_set_error(&a->archive, ENOMEM, "Can't allocate shar data");
return (ARCHIVE_FATAL);
}
memset(shar, 0, sizeof(*shar));
@ -110,6 +113,7 @@ archive_write_set_format_shar(struct archive *a)
a->pad_uncompressed = 0;
a->format_write_header = archive_write_shar_header;
a->format_finish = archive_write_shar_finish;
a->format_destroy = archive_write_shar_destroy;
a->format_write_data = archive_write_shar_data_sed;
a->format_finish_entry = archive_write_shar_finish_entry;
a->archive_format = ARCHIVE_FORMAT_SHAR_BASE;
@ -124,11 +128,12 @@ archive_write_set_format_shar(struct archive *a)
* and other extended file information.
*/
int
archive_write_set_format_shar_dump(struct archive *a)
archive_write_set_format_shar_dump(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
struct shar *shar;
archive_write_set_format_shar(a);
archive_write_set_format_shar(&a->archive);
shar = (struct shar *)a->format_data;
shar->dump = 1;
a->format_write_data = archive_write_shar_data_uuencode;
@ -138,7 +143,7 @@ archive_write_set_format_shar_dump(struct archive *a)
}
static int
archive_write_shar_header(struct archive *a, struct archive_entry *entry)
archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
{
const char *linkname;
const char *name;
@ -186,7 +191,7 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
archive_entry_set_size(entry, 0);
if (archive_entry_hardlink(entry) == NULL &&
archive_entry_symlink(entry) == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"shar format cannot archive this");
return (ARCHIVE_WARN);
}
@ -323,7 +328,7 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
/* XXX TODO: This could be more efficient XXX */
static ssize_t
archive_write_shar_data_sed(struct archive *a, const void *buff, size_t n)
archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n)
{
struct shar *shar;
const char *src;
@ -387,7 +392,7 @@ uuencode_group(struct shar *shar)
}
static ssize_t
archive_write_shar_data_uuencode(struct archive *a, const void *buff,
archive_write_shar_data_uuencode(struct archive_write *a, const void *buff,
size_t length)
{
struct shar *shar;
@ -419,7 +424,7 @@ archive_write_shar_data_uuencode(struct archive *a, const void *buff,
}
static int
archive_write_shar_finish_entry(struct archive *a)
archive_write_shar_finish_entry(struct archive_write *a)
{
const char *g, *p, *u;
struct shar *shar;
@ -504,7 +509,7 @@ archive_write_shar_finish_entry(struct archive *a)
}
static int
archive_write_shar_finish(struct archive *a)
archive_write_shar_finish(struct archive_write *a)
{
struct shar *shar;
int ret;
@ -527,12 +532,21 @@ archive_write_shar_finish(struct archive *a)
if (ret != ARCHIVE_OK)
return (ret);
/* Shar output is never padded. */
archive_write_set_bytes_in_last_block(a, 1);
archive_write_set_bytes_in_last_block(&a->archive, 1);
/*
* TODO: shar should also suppress padding of
* uncompressed data within gzip/bzip2 streams.
*/
}
return (ARCHIVE_OK);
}
static int
archive_write_shar_destroy(struct archive_write *a)
{
struct shar *shar;
shar = (struct shar *)a->format_data;
if (shar->entry != NULL)
archive_entry_free(shar->entry);
if (shar->last_dir != NULL)

View File

@ -50,11 +50,11 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_write_private.h"
struct ustar {
uint64_t entry_bytes_remaining;
uint64_t entry_padding;
char written;
};
/*
@ -150,38 +150,40 @@ static const char template_header[] = {
0,0,0,0,0,0,0,0, 0,0,0,0
};
static ssize_t archive_write_ustar_data(struct archive *a, const void *buff,
static ssize_t archive_write_ustar_data(struct archive_write *a, const void *buff,
size_t s);
static int archive_write_ustar_finish(struct archive *);
static int archive_write_ustar_finish_entry(struct archive *);
static int archive_write_ustar_header(struct archive *,
static int archive_write_ustar_destroy(struct archive_write *);
static int archive_write_ustar_finish(struct archive_write *);
static int archive_write_ustar_finish_entry(struct archive_write *);
static int archive_write_ustar_header(struct archive_write *,
struct archive_entry *entry);
static int format_256(int64_t, char *, int);
static int format_number(int64_t, char *, int size, int max, int strict);
static int format_octal(int64_t, char *, int);
static int write_nulls(struct archive *a, size_t);
static int write_nulls(struct archive_write *a, size_t);
/*
* Set output format to 'ustar' format.
*/
int
archive_write_set_format_ustar(struct archive *a)
archive_write_set_format_ustar(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
struct ustar *ustar;
/* If someone else was already registered, unregister them. */
if (a->format_finish != NULL)
(a->format_finish)(a);
if (a->format_destroy != NULL)
(a->format_destroy)(a);
/* Basic internal sanity test. */
if (sizeof(template_header) != 512) {
archive_set_error(a, ARCHIVE_ERRNO_MISC, "Internal: template_header wrong size: %d should be 512", sizeof(template_header));
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal: template_header wrong size: %d should be 512", sizeof(template_header));
return (ARCHIVE_FATAL);
}
ustar = (struct ustar *)malloc(sizeof(*ustar));
if (ustar == NULL) {
archive_set_error(a, ENOMEM, "Can't allocate ustar data");
archive_set_error(&a->archive, ENOMEM, "Can't allocate ustar data");
return (ARCHIVE_FATAL);
}
memset(ustar, 0, sizeof(*ustar));
@ -191,6 +193,7 @@ archive_write_set_format_ustar(struct archive *a)
a->format_write_header = archive_write_ustar_header;
a->format_write_data = archive_write_ustar_data;
a->format_finish = archive_write_ustar_finish;
a->format_destroy = archive_write_ustar_destroy;
a->format_finish_entry = archive_write_ustar_finish_entry;
a->archive_format = ARCHIVE_FORMAT_TAR_USTAR;
a->archive_format_name = "POSIX ustar";
@ -198,14 +201,13 @@ archive_write_set_format_ustar(struct archive *a)
}
static int
archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
{
char buff[512];
int ret;
struct ustar *ustar;
ustar = (struct ustar *)a->format_data;
ustar->written = 1;
/* Only regular files (not hardlinks) have data. */
if (archive_entry_hardlink(entry) != NULL ||
@ -236,7 +238,7 @@ archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
* This is exported so that other 'tar' formats can use it.
*/
int
__archive_write_format_header_ustar(struct archive *a, char h[512],
__archive_write_format_header_ustar(struct archive_write *a, char h[512],
struct archive_entry *entry, int tartype, int strict)
{
unsigned int checksum;
@ -272,11 +274,11 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
* remaining name are too large, return an error.
*/
if (!p) {
archive_set_error(a, ENAMETOOLONG,
archive_set_error(&a->archive, ENAMETOOLONG,
"Pathname too long");
ret = ARCHIVE_WARN;
} else if (p > pp + USTAR_prefix_size) {
archive_set_error(a, ENAMETOOLONG,
archive_set_error(&a->archive, ENAMETOOLONG,
"Pathname too long");
ret = ARCHIVE_WARN;
} else {
@ -294,7 +296,7 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
if (p != NULL && p[0] != '\0') {
copy_length = strlen(p);
if (copy_length > USTAR_linkname_size) {
archive_set_error(a, ENAMETOOLONG,
archive_set_error(&a->archive, ENAMETOOLONG,
"Link contents too long");
ret = ARCHIVE_WARN;
copy_length = USTAR_linkname_size;
@ -306,7 +308,7 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
if (p != NULL && p[0] != '\0') {
copy_length = strlen(p);
if (copy_length > USTAR_uname_size) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Username too long");
ret = ARCHIVE_WARN;
copy_length = USTAR_uname_size;
@ -318,7 +320,7 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
if (p != NULL && p[0] != '\0') {
copy_length = strlen(p);
if (strlen(p) > USTAR_gname_size) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Group name too long");
ret = ARCHIVE_WARN;
copy_length = USTAR_gname_size;
@ -329,27 +331,27 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
st = archive_entry_stat(entry);
if (format_number(st->st_mode & 07777, h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {
archive_set_error(a, ERANGE, "Numeric mode too large");
archive_set_error(&a->archive, ERANGE, "Numeric mode too large");
ret = ARCHIVE_WARN;
}
if (format_number(st->st_uid, h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {
archive_set_error(a, ERANGE, "Numeric user ID too large");
archive_set_error(&a->archive, ERANGE, "Numeric user ID too large");
ret = ARCHIVE_WARN;
}
if (format_number(st->st_gid, h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {
archive_set_error(a, ERANGE, "Numeric group ID too large");
archive_set_error(&a->archive, ERANGE, "Numeric group ID too large");
ret = ARCHIVE_WARN;
}
if (format_number(st->st_size, h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {
archive_set_error(a, ERANGE, "File size out of range");
archive_set_error(&a->archive, ERANGE, "File size out of range");
ret = ARCHIVE_WARN;
}
if (format_number(st->st_mtime, h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {
archive_set_error(a, ERANGE,
archive_set_error(&a->archive, ERANGE,
"File modification time too large");
ret = ARCHIVE_WARN;
}
@ -357,14 +359,14 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
if (format_number(major(st->st_rdev), h + USTAR_rdevmajor_offset,
USTAR_rdevmajor_size, USTAR_rdevmajor_max_size, strict)) {
archive_set_error(a, ERANGE,
archive_set_error(&a->archive, ERANGE,
"Major device number too large");
ret = ARCHIVE_WARN;
}
if (format_number(minor(st->st_rdev), h + USTAR_rdevminor_offset,
USTAR_rdevminor_size, USTAR_rdevminor_max_size, strict)) {
archive_set_error(a, ERANGE,
archive_set_error(&a->archive, ERANGE,
"Minor device number too large");
ret = ARCHIVE_WARN;
}
@ -383,12 +385,12 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
case S_IFDIR: h[USTAR_typeflag_offset] = '5' ; break;
case S_IFIFO: h[USTAR_typeflag_offset] = '6' ; break;
case S_IFSOCK:
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"tar format cannot archive socket");
ret = ARCHIVE_WARN;
break;
default:
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"tar format cannot archive this (mode=0%lo)",
(unsigned long)st->st_mode);
ret = ARCHIVE_WARN;
@ -486,27 +488,32 @@ format_octal(int64_t v, char *p, int s)
}
static int
archive_write_ustar_finish(struct archive *a)
archive_write_ustar_finish(struct archive_write *a)
{
struct ustar *ustar;
int r;
r = ARCHIVE_OK;
if (a->compression_write == NULL)
return (ARCHIVE_OK);
ustar = (struct ustar *)a->format_data;
/*
* Suppress end-of-archive if nothing else was ever written.
* This fixes a problem where setting one format, then another
* ends up writing a gratuitous end-of-archive marker.
*/
if (ustar->written && a->compression_write != NULL)
r = write_nulls(a, 512*2);
free(ustar);
a->format_data = NULL;
r = write_nulls(a, 512*2);
return (r);
}
static int
archive_write_ustar_finish_entry(struct archive *a)
archive_write_ustar_destroy(struct archive_write *a)
{
struct ustar *ustar;
ustar = (struct ustar *)a->format_data;
free(ustar);
a->format_data = NULL;
return (ARCHIVE_OK);
}
static int
archive_write_ustar_finish_entry(struct archive_write *a)
{
struct ustar *ustar;
int ret;
@ -519,7 +526,7 @@ archive_write_ustar_finish_entry(struct archive *a)
}
static int
write_nulls(struct archive *a, size_t padding)
write_nulls(struct archive_write *a, size_t padding)
{
int ret, to_write;
@ -534,7 +541,7 @@ write_nulls(struct archive *a, size_t padding)
}
static ssize_t
archive_write_ustar_data(struct archive *a, const void *buff, size_t s)
archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
{
struct ustar *ustar;
int ret;

View File

@ -0,0 +1,67 @@
# $FreeBSD$
TESTS= \
test_archive_api_feature.c \
test_bad_fd.c \
test_read_data_large.c \
test_read_extract.c \
test_read_format_cpio_bin.c \
test_read_format_cpio_bin_Z.c \
test_read_format_cpio_bin_bz2.c \
test_read_format_cpio_bin_gz.c \
test_read_format_cpio_odc.c \
test_read_format_cpio_svr4_gzip.c \
test_read_format_cpio_svr4c_Z.c \
test_read_format_empty.c \
test_read_format_gtar_gz.c \
test_read_format_iso_gz.c \
test_read_format_isorr_bz2.c \
test_read_format_pax_bz2.c \
test_read_format_tar.c \
test_read_format_tbz.c \
test_read_format_tgz.c \
test_read_format_tz.c \
test_read_format_zip.c \
test_read_large.c \
test_read_position.c \
test_read_truncated.c \
test_write_disk.c \
test_write_disk_perms.c \
test_write_disk_secure.c \
test_write_format_cpio_empty.c \
test_write_format_shar_empty.c \
test_write_format_tar.c \
test_write_format_tar_empty.c \
test_write_open_memory.c
SRCS= ${TESTS} \
list.h \
main.c
CLEANFILES+= list.h
MK_MAN=no
NO_MAN=yes
PROG=libarchive_test
DPADD=${LIBARCHIVE} ${LIBBZ2} ${LIBZ}
LDADD= -larchive -lz -lbz2
CFLAGS+= -static -g
CFLAGS+= -I${.OBJDIR}
test: libarchive_test
./libarchive_test
list.h: ${TESTS} Makefile
(cd ${.CURDIR}; cat ${TESTS}) | grep DEFINE_TEST > list.h
clean:
rm -f *.out
rm -f *.o
rm -f *.core
rm -f *~
rm -f list.h
-chmod -R +w /tmp/libarchive_test.*
rm -rf /tmp/libarchive_test.*
.include <bsd.prog.mk>

View File

@ -0,0 +1,46 @@
$FreeBSD$
This is the test harness for libarchive.
It compiles into a single program "libarchive_test" that is intended
to exercise as much of the library as possible. It is, of course,
very much a work in progress.
Each test is a function named test_foo in a file named test_foo.c.
Note that the file name is the same as the function name.
Each file must start with this line:
#include "test.h"
The test function must be declared with a line of this form
DEFINE_TEST(test_foo)
Nothing else should appear on that line.
When you add a test, please update the Makefile to add your
file to the list of tests. The Makefile and main.c use various
macro trickery to automatically collect a list of test functions
to be invoked.
Each test function can rely on the following:
* The current directory will be a freshly-created empty directory
suitable for that test. (The top-level main() creates a
directory for each separate test and chdir()s to that directory
before running the test.)
* The test function should use assert(), assertA() and similar macros
defined in test.h. If you need to add new macros of this form, feel
free to do so.
* You are encouraged to document each assertion with a failure() call
just before the assert. The failure() function is a printf-like
function whose text is displayed only if the assertion fails. It
can be used to display additional information relevant to the failure:
failure("The data read from file %s did not match the data written to that file.", filename);
assert(strcmp(buff1, buff2) == 0);
* Tests are encouraged to be economical with their memory and disk usage,
though this is not essential.

168
lib/libarchive/test/main.c Normal file
View File

@ -0,0 +1,168 @@
/*
* 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.
*/
/*
* Various utility routines useful for test programs.
* Each test program is linked against this file.
*/
#include <stdarg.h>
#include <time.h>
#include "test.h"
__FBSDID("$FreeBSD$");
/*
* 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
* libarchive test harnesses:
* failure(fmt, args) -- Stores a text string that gets
* printed if the following assertion fails, good for
* explaining subtle tests.
* assertA(a, cond) -- If the test fails, also prints out any error
* message stored in archive object 'a'.
*/
static char msg[4096];
void
failure(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsprintf(msg, fmt, ap);
va_end(ap);
}
void
test_assert(const char *file, int line, int value, const char *condition, struct archive *a)
{
if (value) {
msg[0] = '\0';
return;
}
fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
fprintf(stderr, " Condition: %s\n", condition);
if (msg[0] != '\0') {
fprintf(stderr, " Description: %s\n", msg);
msg[0] = '\0';
}
if (a != NULL) {
fprintf(stderr, " archive error: %s\n", archive_error_string(a));
}
*(char *)(NULL) = 0;
exit(1);
}
void
test_assert_equal_int(const char *file, int line,
int v1, const char *e1, int v2, const char *e2, struct archive *a)
{
if (v1 == v2) {
msg[0] = '\0';
return;
}
fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
fprintf(stderr, " Condition: %s==%s\n", e1, e2);
fprintf(stderr, " %s=%d\n", e1, v1);
fprintf(stderr, " %s=%d\n", e2, v2);
if (msg[0] != '\0') {
fprintf(stderr, " Description: %s\n", msg);
msg[0] = '\0';
}
if (a != NULL) {
fprintf(stderr, " archive error: %s\n", archive_error_string(a));
}
*(char *)(NULL) = 0;
exit(1);
}
/*
* "list.h" is automatically generated; it just has a lot of lines like:
* DEFINE_TEST(function_name)
* The common "test.h" includes it to declare all of the test functions.
* We reuse it here to define a list of all tests to run.
*/
#undef DEFINE_TEST
#define DEFINE_TEST(n) n, #n,
struct { void (*func)(void); char *name; } tests[] = {
#include "list.h"
};
int main(int argc, char **argv)
{
void (*f)(void);
int limit = sizeof(tests) / sizeof(tests[0]);
int i;
time_t now;
char tmpdir[256];
int tmpdirHandle;
/*
* 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);
strftime(tmpdir, sizeof(tmpdir),
"/tmp/libarchive_test.%Y-%m-%dT%H.%M.%S.XXXXXX",
localtime(&now));
if (mkdtemp(tmpdir) == NULL) {
fprintf(stderr, "ERROR: Unable to create temp directory %s\n",
tmpdir);
exit(1);
}
printf("Running libarchive tests in: %s\n", tmpdir);
for (i = 0; i < limit; i++) {
printf("%d: %s\n", i, tests[i].name);
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);
}
if (chdir(tests[i].name)) {
fprintf(stderr,
"ERROR: Couldn't chdir to temp dir ``%s''\n",
tests[i].name);
exit(1);
}
(*tests[i].func)();
}
printf("%d tests succeeded.\n", limit);
return (0);
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2003-2006 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
/* Every test program should #include "test.h" as the first thing. */
/*
* The goal of this file (and the matching test.c) is to
* simplify the very repetitive test-*.c test programs.
*/
#include <archive.h>
#include <archive_entry.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#if defined(HAVE_CONFIG_H)
/* Most POSIX platforms use the 'configure' script to build config.h */
#include "../../config.h"
#elif defined(__FreeBSD__)
/* Building as part of FreeBSD system requires a pre-built config.h. */
#include "../config_freebsd.h"
#elif defined(_WIN32)
/* Win32 can't run the 'configure' script. */
#include "../config_windows.h"
#else
/* Warn if the library hasn't been (automatically or manually) configured. */
#error Oops: No config.h and no pre-built configuration in test.h.
#endif
/*
* "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.
*/
#define DEFINE_TEST(name) void name(void);
#include "list.h"
/*
* Redefine DEFINE_TEST for use in defining the test functions.
*/
#undef DEFINE_TEST
#define DEFINE_TEST(name) void name(void)
/* An implementation of the standard assert() macro */
#define assert(e) test_assert(__FILE__, __LINE__, (e), #e, NULL)
/* As above, but reports any archive_error found in variable 'a' */
#define assertA(e) test_assert(__FILE__, __LINE__, (e), #e, (a))
/* Asserts that two values are the same. Reports value of each one if not. */
#define assertEqualIntA(a,v1,v2) \
test_assert_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a))
/* Asserts that two values 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)
/* Function declarations. These are defined in test_utility.c. */
void failure(const char *fmt, ...);
void test_assert(const char *, int, int, const char *, struct archive *);
void test_assert_equal_int(const char *, int, int, const char *, int, const char *, struct archive *);

View File

@ -0,0 +1,33 @@
/*-
* 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_archive_api_feature)
{
assert(ARCHIVE_API_FEATURE == archive_api_feature());
assert(ARCHIVE_API_VERSION == archive_api_version());
assert(0 == (strcmp(ARCHIVE_LIBRARY_VERSION, archive_version())));
}

View File

@ -0,0 +1,41 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
/* Verify that attempting to open an invalid fd returns correct error. */
DEFINE_TEST(test_bad_fd)
{
struct archive *a;
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_compression_all(a));
assertA(ARCHIVE_FATAL == archive_read_open_fd(a, -1, 1024));
assertA(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,116 @@
/*-
* 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 read/write of a 10M block of data in a single operation.
* Uses an in-memory archive with a single 10M entry. Exercises
* archive_read_data() to ensure it can handle large blocks like
* this and also exercises archive_read_data_into_fd() (which
* had a bug relating to this, fixed in Nov 2006).
*/
char buff1[11000000];
char buff2[10000000];
char buff3[10000000];
DEFINE_TEST(test_read_data_large)
{
struct archive_entry *ae;
struct archive *a;
char tmpfilename[] = "largefile";
int tmpfile;
int i;
size_t used;
/* Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_ustar(a));
assertA(0 == archive_write_set_compression_none(a));
assertA(0 == archive_write_open_memory(a, buff1, sizeof(buff1), &used));
/*
* Write a file (with random contents) to it.
*/
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0755);
for (i = 0; i < sizeof(buff2); i++)
buff2[i] = (unsigned char)rand();
archive_entry_set_size(ae, sizeof(buff2));
assertA(0 == archive_write_header(a, ae));
assertA(sizeof(buff2) == archive_write_data(a, buff2, sizeof(buff2)));
/* Close out the archive. */
assertA(0 == archive_write_close(a));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
/* Check that archive_read_data can handle 10*10^6 at a pop. */
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff1, sizeof(buff1)));
assertA(0 == archive_read_next_header(a, &ae));
failure("Wrote 10MB, but didn't read the same amount");
assertEqualIntA(a, sizeof(buff2),archive_read_data(a, buff3, sizeof(buff3)));
failure("Read expected 10MB, but data read didn't match what was written");
assert(0 == memcmp(buff2, buff3, sizeof(buff3)));
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
/* Check archive_read_data_into_fd */
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff1, sizeof(buff1)));
assertA(0 == archive_read_next_header(a, &ae));
tmpfile = open(tmpfilename, O_WRONLY | O_CREAT, 0777);
assert(tmpfile != 0);
assertEqualIntA(a, 0, archive_read_data_into_fd(a, tmpfile));
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
close(tmpfile);
tmpfile = open(tmpfilename, O_RDONLY);
assert(tmpfile != 0);
assertEqualIntA(NULL, sizeof(buff3), read(tmpfile, buff3, sizeof(buff3)));
close(tmpfile);
assert(0 == memcmp(buff2, buff3, sizeof(buff3)));
unlink(tmpfilename);
}

View File

@ -0,0 +1,177 @@
/*-
* 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 BUFF_SIZE 1000000
#define FILE_BUFF_SIZE 100000
DEFINE_TEST(test_read_extract)
{
struct archive_entry *ae;
struct archive *a;
struct stat st;
ssize_t used;
int i;
char *buff, *file_buff;
int fd;
ssize_t bytes_read;
buff = malloc(BUFF_SIZE);
file_buff = malloc(FILE_BUFF_SIZE);
/* Force the umask to something predictable. */
umask(022);
/* Create a new archive in memory containing various types of entries. */
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_ustar(a));
assertA(0 == archive_write_set_compression_none(a));
assertA(0 == archive_write_open_memory(a, buff, BUFF_SIZE, &used));
/* A directory to be restored with EXTRACT_PERM. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir_0775");
archive_entry_set_mode(ae, S_IFDIR | 0775);
assertA(0 == archive_write_header(a, ae));
/* A regular file. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0755);
for (i = 0; i < FILE_BUFF_SIZE; i++)
file_buff[i] = (unsigned char)rand();
archive_entry_set_size(ae, FILE_BUFF_SIZE);
assertA(0 == archive_write_header(a, ae));
assertA(FILE_BUFF_SIZE == archive_write_data(a, file_buff, FILE_BUFF_SIZE));
archive_entry_free(ae);
/* A directory that should obey umask when restored. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir");
archive_entry_set_mode(ae, S_IFDIR | 0777);
assertA(0 == archive_write_header(a, ae));
/* A file in the directory. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir/file");
archive_entry_set_mode(ae, S_IFREG | 0700);
assertA(0 == archive_write_header(a, ae));
/* A file in a dir that is not already in the archive. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir2/file");
archive_entry_set_mode(ae, S_IFREG | 0000);
assertA(0 == archive_write_header(a, ae));
/* A dir with a trailing /. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir3/.");
archive_entry_set_mode(ae, S_IFDIR | 0710);
assertA(0 == archive_write_header(a, ae));
/* Multiple dirs with a single entry. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir4/a/../b/../c/");
archive_entry_set_mode(ae, S_IFDIR | 0711);
assertA(0 == archive_write_header(a, ae));
/* A symlink. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "symlink");
archive_entry_set_mode(ae, S_IFLNK | 0755);
archive_entry_set_symlink(ae, "file");
assertA(0 == archive_write_header(a, ae));
/* Close out the archive. */
assertA(0 == archive_write_close(a));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
/* Extract the entries to disk. */
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff, BUFF_SIZE));
/* Restore first entry with _EXTRACT_PERM. */
failure("Error reading first entry", i);
assertA(0 == archive_read_next_header(a, &ae));
assertA(0 == archive_read_extract(a, ae, ARCHIVE_EXTRACT_PERM));
/* Rest of entries get restored with no flags. */
for (i = 0; i < 7; i++) {
failure("Error reading entry %d", i+1);
assertA(0 == archive_read_next_header(a, &ae));
assertA(0 == archive_read_extract(a, ae, 0));
}
assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
/* Test the entries on disk. */
assert(0 == stat("dir_0775", &st));
failure("This was 0775 in archive, and should be 0775 on disk");
assert(st.st_mode == (S_IFDIR | 0775));
assert(0 == stat("file", &st));
failure("st.st_mode=%o should be %o", st.st_mode, S_IFREG | 0755);
assert(st.st_mode == (S_IFREG | 0755));
failure("The file extracted to disk is the wrong size.");
assert(st.st_size == FILE_BUFF_SIZE);
fd = open("file", O_RDONLY);
failure("The file on disk could not be opened.");
assert(fd != 0);
bytes_read = read(fd, buff, FILE_BUFF_SIZE);
failure("The file contents read from disk are the wrong size");
assert(bytes_read == FILE_BUFF_SIZE);
failure("The file contents on disk do not match the file contents that were put into the archive.");
assert(memcmp(buff, file_buff, FILE_BUFF_SIZE) == 0);
assert(0 == stat("dir", &st));
failure("This was 0777 in archive, but umask should make it 0755");
assert(st.st_mode == (S_IFDIR | 0755));
assert(0 == stat("dir/file", &st));
assert(st.st_mode == (S_IFREG | 0700));
assert(0 == stat("dir2", &st));
assert(st.st_mode == (S_IFDIR | 0755));
assert(0 == stat("dir2/file", &st));
assert(st.st_mode == (S_IFREG | 0000));
assert(0 == stat("dir3", &st));
assert(st.st_mode == (S_IFDIR | 0710));
assert(0 == stat("dir4", &st));
assert(st.st_mode == (S_IFDIR | 0755));
assert(0 == stat("dir4/a", &st));
assert(st.st_mode == (S_IFDIR | 0755));
assert(0 == stat("dir4/b", &st));
assert(st.st_mode == (S_IFDIR | 0755));
assert(0 == stat("dir4/c", &st));
assert(st.st_mode == (S_IFDIR | 0711));
assert(0 == lstat("symlink", &st));
assert(S_ISLNK(st.st_mode));
#if HAVE_LCHMOD
/* Systems that lack lchmod() can't set symlink perms, so skip this. */
assert((st.st_mode & 07777) == 0755);
#endif
assert(0 == stat("symlink", &st));
assert(st.st_mode == (S_IFREG | 0755));
free(buff);
free(file_buff);
}

View File

@ -0,0 +1,64 @@
/*-
* 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 unsigned char archive[] = {
199,'q',21,4,177,'y',237,'A',232,3,232,3,2,0,0,0,'p','C',244,'M',2,0,0,0,
0,0,'.',0,199,'q',0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,11,0,0,0,0,0,'T','R',
'A','I','L','E','R','!','!','!',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
DEFINE_TEST(test_read_format_cpio_bin)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assertA(0 == archive_read_next_header(a, &ae));
assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
assertA(archive_format(a) == ARCHIVE_FORMAT_CPIO_BIN_LE);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,53 @@
/*-
* 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 unsigned char archive[] = {
31,157,144,199,226,'T',' ',16,'+','O',187,' ',232,6,'$',20,0,160,'!',156,
'!',244,154,'0','l',216,208,5,128,128,20,'3','R',12,160,177,225,2,141,'T',
164,4,'I',194,164,136,148,16,'(',';',170,'\\',201,178,165,203,151,'0','c',
202,156,'I',179,166,205,155,'8','s',234,220,201,179,167,207,159,'@',127,2};
DEFINE_TEST(test_read_format_cpio_bin_Z)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assertA(0 == archive_read_next_header(a, &ae));
assertA(archive_compression(a) == ARCHIVE_COMPRESSION_COMPRESS);
assertA(archive_format(a) == ARCHIVE_FORMAT_CPIO_BIN_LE);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
static unsigned char archive[] = {
'B','Z','h','9','1','A','Y','&','S','Y',134,'J',208,'4',0,0,30,246,141,253,
8,2,0,' ',1,'*','&',20,0,'`',' ',' ',2,0,128,0,'B',4,8,' ',0,'T','P',0,'4',
0,13,6,137,168,245,27,'Q',160,'a',25,169,5,'I',187,'(',10,'d','E',177,177,
142,218,232,'r',130,'4','D',247,'<','Z',190,'U',237,236,'d',227,31,' ','z',
192,'E','_',23,'r','E','8','P',144,134,'J',208,'4'};
DEFINE_TEST(test_read_format_cpio_bin_bz2)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assert(0 == archive_read_support_compression_all(a));
assert(0 == archive_read_support_format_all(a));
assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assert(0 == archive_read_next_header(a, &ae));
assert(archive_compression(a) == ARCHIVE_COMPRESSION_BZIP2);
assert(archive_format(a) == ARCHIVE_FORMAT_CPIO_BIN_LE);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,53 @@
/*-
* 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 unsigned char archive[] = {
31,139,8,0,244,'M','p','C',0,3,';','^','(',202,178,177,242,173,227,11,230,
23,204,'L',12,12,12,5,206,'_','|','A','4',3,131,30,195,241,'B',6,'8','`',
132,210,220,'`','2','$',200,209,211,199,'5','H','Q','Q',145,'a',20,12,'i',
0,0,170,199,228,195,0,2,0,0};
DEFINE_TEST(test_read_format_cpio_bin_gz)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assert(0 == archive_read_support_compression_all(a));
assert(0 == archive_read_support_format_all(a));
assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assert(0 == archive_read_next_header(a, &ae));
assert(archive_compression(a) == ARCHIVE_COMPRESSION_GZIP);
assert(archive_format(a) == ARCHIVE_FORMAT_CPIO_BIN_LE);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,68 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
static unsigned char archive[] = {
'0','7','0','7','0','7','0','0','2','0','2','5','0','7','4','6','6','1','0',
'4','0','7','5','5','0','0','1','7','5','0','0','0','1','7','5','0','0','0',
'0','0','0','2','0','0','0','0','0','0','1','0','3','3','4','0','5','0','0',
'5','3','0','0','0','0','0','2','0','0','0','0','0','0','0','0','0','0','0',
'.',0,'0','7','0','7','0','7','0','0','0','0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0',
'0','0','0','0','0','1','0','0','0','0','0','0','0','0','0','0','0','0','0',
'0','0','0','0','0','0','0','0','1','3','0','0','0','0','0','0','0','0','0',
'0','0','T','R','A','I','L','E','R','!','!','!',0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0};
DEFINE_TEST(test_read_format_cpio_odc)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assertA(0 == archive_read_next_header(a, &ae));
assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
assertA(archive_format(a) == ARCHIVE_FORMAT_CPIO_POSIX);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
static unsigned char archive[] = {
31,139,8,0,236,'c',217,'D',0,3,'3','0','7','0','7','0','4','0','0',181,'0',
183,'L',2,210,6,6,'&',134,169,')',' ',218,192,'8',213,2,133,'6','0','0','2',
'1','6','7','0','5','0','N','6','@',5,'&',16,202,208,212,0,';','0',130,'1',
244,24,12,160,246,17,5,136,'U',135,14,146,'`',140,144,' ','G','O',31,215,
' ','E','E','E',134,'Q',128,21,0,0,'%',215,202,221,0,2,0,0};
DEFINE_TEST(test_read_format_cpio_svr4_gzip)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assert(0 == archive_read_support_compression_all(a));
assert(0 == archive_read_support_format_all(a));
assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assert(0 == archive_read_next_header(a, &ae));
assert(archive_compression(a) == ARCHIVE_COMPRESSION_GZIP);
assert(archive_format(a) == ARCHIVE_FORMAT_CPIO_SVR4_NOCRC);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,56 @@
/*-
* 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 unsigned char archive[] = {
31,157,144,'0','n',4,132,'!',3,6,140,26,'8','n',228,16,19,195,160,'A',26,
'1',202,144,'q','h','p','F',25,28,20,'a','X',196,152,145,' ',141,25,2,'k',
192,160,'A',163,163,201,135,29,'c',136,'<',201,'2','c','A',147,'.',0,12,20,
248,178,165,205,155,20,27,226,220,201,243,166,152,147,'T',164,4,'I',194,164,
136,148,16,'H',1,'(',']',202,180,169,211,167,'P',163,'J',157,'J',181,170,
213,171,'X',179,'j',221,202,181,171,215,175,'L',1};
DEFINE_TEST(test_read_format_cpio_svr4c_Z)
{
struct archive_entry *ae;
struct archive *a;
/* printf("Archive address: start=%X, end=%X\n", archive, archive+sizeof(archive)); */
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assertA(0 == archive_read_next_header(a, &ae));
assertA(archive_compression(a) == ARCHIVE_COMPRESSION_COMPRESS);
assertA(archive_format(a) == ARCHIVE_FORMAT_CPIO_SVR4_CRC);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,49 @@
/*-
* 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 unsigned char archive[] = { };
DEFINE_TEST(test_read_format_empty)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
assertA(archive_format(a) == ARCHIVE_FORMAT_EMPTY);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
static unsigned char archive[] = {
31,139,8,0,'+','e',217,'D',0,3,211,211,'g',160,'9','0',0,2,'s','S','S',16,
'm','h','n','j',128,'L',195,0,131,161,129,177,177,137,129,137,185,185,161,
'!',131,129,161,129,153,161,'9',131,130,')',237,157,198,192,'P','Z','\\',
146,'X',164,160,192,'P',146,153,139,'W',29,'!','y',152,'G','`',244,'(',24,
5,163,'`',20,12,'r',0,0,226,234,'6',162,0,6,0,0};
DEFINE_TEST(test_read_format_gtar_gz)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assert(0 == archive_read_support_compression_all(a));
assert(0 == archive_read_support_format_all(a));
assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assert(0 == archive_read_next_header(a, &ae));
assert(archive_compression(a) == ARCHIVE_COMPRESSION_GZIP);
assert(archive_format(a) == ARCHIVE_FORMAT_TAR_GNUTAR);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,73 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 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 unsigned char archive[] = {
31,139,8,8,201,'R','p','C',0,3,'t','e','s','t','-','r','e','a','d','_','f',
'o','r','m','a','t','.','i','s','o',0,237,219,223,'k',211,'@',28,0,240,212,
23,'K','}',20,169,143,135,15,162,224,218,180,']','W',186,183,173,'I',183,
206,254,144,'d',19,246,'$',5,';',24,'2',11,235,240,239,221,127,162,233,'f',
17,29,219,24,12,'\'',243,243,'!',185,187,220,']',146,';',8,9,223,131,'D',
17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'P',234,
'%','q',220,'(','E',253,211,217,'l',';','O',194,'u','z','I','6',25,']',219,
26,194,234,'z',241,'o',217,13,247,'-',182,229,30,149,203,'Q',229,178,170,
242,252,'W',243,139,'e',242,'*',170,'^',30,'U',163,242,'2','+','G',199,207,
158,'V','_',190,';',127,178,':',255,134,1,241,23,140,222,15,242,'I','?',15,
'E',26,186,27,27,'q','}',183,'8',232,15,134,'i','~',152,239,167,163,176,'}',
'0',24,'&','i',22,'^','/',159,159,180,'7',201,146,162,176,150,213,147,143,
'E','!','K',183,246,'\'','Y','x',211,'{',27,26,221,'n','+',164,181,195,201,
193,'x','\'',217,26,166,171,202,'N',216,171,'}','H',183,178,'|','2',174,239,
213,242,222,238,'`','8',28,140,'w',30,'j',186,205,'8','n','7',26,'q',167,
217,'j',174,183,';','q','|','~',165,'"',254,'C','t',165,'G',')','z',168,209,
243,'o',184,143,215,'6',220,139,239,'?',191,255,0,192,255,163,136,224,194,
'h',254,'5',140,231,223,'B',232,132,'f','k',179,185,190,217,238,'\\',132,
':',149,147,'/',199,139,249,209,'"','4','k','q',173,21,214,230,225,'l',182,
'8','[',';',157,'M','?',127,':',154,159,158,'L',207,'j','E','{',152,'>',244,
28,0,128,187,')',']',172,177,139,255,1,0,0,224,'1',187,136,252,171,22,0,0,
0,0,224,'1',187,253,31,187,'[','{','X',';',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,206,
'~',0,137,'#',195,182,0,128,1,0};
DEFINE_TEST(test_read_format_iso_gz)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assert(0 == archive_read_support_compression_all(a));
assert(0 == archive_read_support_format_all(a));
assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assert(0 == archive_read_next_header(a, &ae));
assert(archive_compression(a) == ARCHIVE_COMPRESSION_GZIP);
assert(archive_format(a) == ARCHIVE_FORMAT_ISO9660);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,180 @@
/*-
* 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$");
/*
Execute the following to rebuild the data for this program:
tail -n +5 test-read_format-isorr_bz2.c | /bin/sh
rm -rf /tmp/iso
mkdir /tmp/iso
mkdir /tmp/iso/dir
echo "hello" >/tmp/iso/file
ln /tmp/iso/file /tmp/iso/hardlink
(cd /tmp/iso; ln -s file symlink)
TZ=utc touch -afhm -t 197001010000.01 /tmp/iso /tmp/iso/file /tmp/iso/dir
TZ=utc touch -afhm -t 196912312359.58 /tmp/iso/symlink
mkhybrid -R -uid 1 -gid 2 /tmp/iso | bzip2 > data.iso.bz2
cat data.iso.bz2 | ./maketest.pl > data.c
exit 1
*/
static unsigned char archive[] = {
'B','Z','h','9','1','A','Y','&','S','Y','G',11,4,'c',0,0,199,255,221,255,
255,203,252,221,'c',251,248,'?',255,223,224,167,255,222,'&','!',234,'$',0,
'0',1,' ',0,'D',2,129,8,192,3,14,'2','3','$',19,184,'J',' ','F',168,244,201,
149,'6','Q',226,155,'S',212,209,160,'h','4','i',160,26,13,0,244,134,212,0,
218,'O',212,153,1,144,244,128,148,' ',147,13,' ',213,'=','1','\'',169,166,
128,'=','!',233,0,208,0,26,0,0,30,160,'h',0,'4','z',130,180,163,'@',0,0,4,
211,0,0,0,2,'b','`',0,0,0,0,0,8,146,133,'F',154,'y','A',163,'A',161,163,'@',
'z',134,'C','C','F',131,'F','@',0,0,0,0,6,154,26,'Q',24,234,180,'P',172,251,
'=',2,'P','H','&','Y','o',130,28,'"',229,210,247,227,248,200,'?','6',161,
'?',170,'H',172,'"','H','I',16,'2','"','&',148,'G',133,'T','z',224,1,215,
' ',0,191,184,10,160,24,248,180,183,244,156,'K',202,133,208,'U',5,'6','C',
26,144,'H',168,'H','H','(','"',151,'@','m',223,'(','P',169,'e',145,148,'6',
237,235,7,227,204,']','k','{',241,187,227,244,251,':','a','L',138,'#','R',
'"',221,'_',239,')',140,'*','*',172,'Q',16,1,16,207,166,251,233,'Z',169,'4',
'_',195,'a',14,18,231,'}',14,139,137,'e',213,185,'T',194,'D','`',25,'$',187,
208,'%','c',162,'~',181,'@',204,'2',238,'P',161,213,127,'I',169,3,' ','o',
6,161,16,128,'F',214,'S','m',6,244,11,229,'Z','y','.',176,'q',' ',248,167,
204,26,193,'q',211,241,214,133,221,212,'I','`',28,244,'N','N','f','H','9',
'w',245,209,'*',20,26,208,'h','(',194,156,192,'l',';',192,'X','T',151,177,
209,'0',156,16,'=',20,'k',184,144,'z',26,'j',133,194,'9',227,'<','[','^',
17,'w','p',225,220,248,'>',205,'>','[',19,'5',155,17,175,28,28,168,175,'n',
'\'','c','w',27,222,204,'k','n','x','I',23,237,'c',145,11,184,'A','(',1,169,
'0',180,189,134,'\\','Y','x',187,'C',151,'d','k','y','-','L',218,138,'s',
'*','(',12,'h',242,'*',17,'E','L',202,146,138,'l','0',217,160,'9','.','S',
214,198,143,'3','&',237,'=','t','P',168,214,210,'`','p','J',181,'H',138,149,
'1','B',206,22,164,'[','O','A',172,134,224,179,219,166,184,'X',185,'W',154,
219,19,161,'Y',184,220,237,147,'9',191,237,'&','i','_',226,146,205,160,'@',
'b',182,';',3,'!',183,'J','t',161,160,178,173,'S',235,':','2',159,':',245,
'{','U',174,'P',142,'G','(',')',9,168,185,'A','U',231,193,'g',213,'e',12,
'X',223,22,249,')',152,237,'G',150,156,3,201,245,212,'2',218,209,177,196,
235,'_','~',137,24,31,196,232,'B',172,'w',159,24,'n',156,150,225,'1','y',
22,'#',138,193,227,232,169,170,166,179,1,11,182,'i',')',160,180,198,175,128,
249,167,5,194,142,183,'f',134,206,180,'&','E','!','[',31,195,':',192,'s',
232,187,'N',131,'Y',137,243,15,'y',12,'J',163,'-',242,'5',197,151,130,163,
240,220,'T',161,'L',159,141,159,152,'4',18,128,'.','^',250,168,200,163,'P',
231,'Y','w','F','U',186,'x',190,16,'0',228,22,'9','F','t',168,157,'i',190,
'+',246,141,142,18,' ','M',174,197,'O',165,'m',224,27,'b',150,'|','W','H',
196,'.','*','Q','$',225,'I','-',148,169,'F',7,197,'m','-',130,153,0,158,21,
'(',221,221,226,206,'g',13,159,163,'y',176,'~',158,'k','4','q','d','s',177,
'7',14,217,'1',173,206,228,'t',250,200,170,162,'d','2','Z','$','e',168,224,
223,129,174,229,165,187,252,203,'-',28,'`',207,183,'-','/',127,196,230,131,
'B',30,237,' ',8,26,194,'O',132,'L','K','\\',144,'L','c',1,10,176,192,'c',
0,244,2,168,3,0,'+',233,186,16,17,'P',17,129,252,'2',0,2,154,247,255,166,
'.',228,138,'p',161,' ',142,22,8,198};
DEFINE_TEST(test_read_format_isorr_bz2)
{
struct archive_entry *ae;
struct archive *a;
const void *p;
size_t size;
off_t offset;
assert((a = archive_read_new()) != NULL);
assert(0 == archive_read_support_compression_all(a));
assert(0 == archive_read_support_format_all(a));
assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
/* First entry is '.' root directory. */
assert(0 == archive_read_next_header(a, &ae));
assert(0 == strcmp(".", archive_entry_pathname(ae)));
assert(S_ISDIR(archive_entry_stat(ae)->st_mode));
assert(2048 == archive_entry_size(ae));
assert(1 == archive_entry_mtime(ae));
assert(0 == archive_entry_mtime_nsec(ae));
assert(1 == archive_entry_ctime(ae));
assert(0 == archive_entry_stat(ae)->st_nlink);
assert(0 == archive_entry_uid(ae));
/* A directory. */
assert(0 == archive_read_next_header(a, &ae));
assert(0 == strcmp("dir", archive_entry_pathname(ae)));
assert(S_ISDIR(archive_entry_stat(ae)->st_mode));
assert(2048 == archive_entry_size(ae));
assert(1 == archive_entry_mtime(ae));
assert(1 == archive_entry_atime(ae));
assert(2 == archive_entry_stat(ae)->st_nlink);
assert(1 == archive_entry_uid(ae));
assert(2 == archive_entry_gid(ae));
/* A regular file. */
assert(0 == archive_read_next_header(a, &ae));
assert(0 == strcmp("file", archive_entry_pathname(ae)));
assert(S_ISREG(archive_entry_stat(ae)->st_mode));
assert(6 == archive_entry_size(ae));
assert(0 == archive_read_data_block(a, &p, &size, &offset));
assert(6 == size);
assert(0 == offset);
assert(0 == memcmp(p, "hello\n", 6));
assert(1 == archive_entry_mtime(ae));
assert(1 == archive_entry_atime(ae));
assert(2 == archive_entry_stat(ae)->st_nlink);
assert(1 == archive_entry_uid(ae));
assert(2 == archive_entry_gid(ae));
/* A hardlink to the regular file. */
assert(0 == archive_read_next_header(a, &ae));
assert(0 == strcmp("hardlink", archive_entry_pathname(ae)));
assert(S_ISREG(archive_entry_stat(ae)->st_mode));
assert(0 == strcmp("file", archive_entry_hardlink(ae)));
assert(6 == archive_entry_size(ae));
assert(1 == archive_entry_mtime(ae));
assert(1 == archive_entry_atime(ae));
assert(2 == archive_entry_stat(ae)->st_nlink);
assert(1 == archive_entry_uid(ae));
assert(2 == archive_entry_gid(ae));
/* A symlink to the regular file. */
assert(0 == archive_read_next_header(a, &ae));
assert(0 == strcmp("symlink", archive_entry_pathname(ae)));
assert(S_ISLNK(archive_entry_stat(ae)->st_mode));
assert(0 == strcmp("file", archive_entry_symlink(ae)));
assert(0 == archive_entry_size(ae));
assert(-2 == archive_entry_mtime(ae));
assert(-2 == archive_entry_atime(ae));
assert(1 == archive_entry_stat(ae)->st_nlink);
assert(1 == archive_entry_uid(ae));
assert(2 == archive_entry_gid(ae));
/* End of archive. */
assert(ARCHIVE_EOF == archive_read_next_header(a, &ae));
/* Verify archive format. */
assert(archive_compression(a) == ARCHIVE_COMPRESSION_BZIP2);
assert(archive_format(a) == ARCHIVE_FORMAT_ISO9660_ROCKRIDGE);
/* Close the archive. */
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,62 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
static unsigned char archive[] = {
'B','Z','h','9','1','A','Y','&','S','Y',152,180,30,185,0,0,140,127,176,212,
144,0,' ','@',1,255,226,8,'d','H',' ',238,'/',159,'@',0,16,4,'@',0,8,'0',
0,216,'A',164,167,147,'Q',147,'!',180,'#',0,'L',153,162,'i',181,'?','P',192,
26,'h','h',209,136,200,6,128,13,12,18,132,202,'5','O',209,'5','=',26,'2',
154,7,168,12,2,'d',252,13,254,29,'4',247,181,'l','T','i',130,5,195,1,'2',
'@',146,18,251,245,'c','J',130,224,172,'$','l','4',235,170,186,'c','1',255,
179,'K',188,136,18,208,152,192,149,153,10,'{','|','0','8',166,3,6,9,128,172,
'(',164,220,244,149,6,' ',243,212,'B',25,17,'6',237,13,'I',152,'L',129,209,
'G','J','<',137,'Y',16,'b',21,18,'a','Y','l','t','r',160,128,147,'l','f',
'~',219,206,'=','?','S',233,'3',251,'L','~',17,176,169,'%',23,'_',225,'M',
'C','u','k',218,8,'q',216,'(',22,235,'K',131,136,146,136,147,202,0,158,134,
'F',23,160,184,'s','0','a',246,'*','P',7,2,238,'H',167,10,18,19,22,131,215,
' '};
DEFINE_TEST(test_read_format_pax_bz2)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assert(0 == archive_read_support_compression_all(a));
assert(0 == archive_read_support_format_all(a));
assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assert(0 == archive_read_next_header(a, &ae));
assert(archive_compression(a) == ARCHIVE_COMPRESSION_BZIP2);
assert(archive_format(a) == ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -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$");
static unsigned char archive[] = {
'.',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'0','0','0','7','5',
'5',' ',0,'0','0','1','7','5','0',' ',0,'0','0','1','7','5','0',' ',0,'0',
'0','0','0','0','0','0','0','0','0','0',' ','1','0','3','3','4','0','4','1',
'7','3','6',' ','0','1','0','5','6','1',0,' ','5',0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,'u','s','t','a','r',0,'0','0','t','i','m',0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'t','i','m',0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'0','0','0','0','0','0',
' ',0,'0','0','0','0','0','0',' ',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
DEFINE_TEST(test_read_format_tar)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assertA(0 == archive_read_next_header(a, &ae));
assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
assertA(archive_format(a) == ARCHIVE_FORMAT_TAR_USTAR);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,55 @@
/*-
* 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 unsigned char archive[] = {
'B','Z','h','9','1','A','Y','&','S','Y',237,7,140,'W',0,0,27,251,144,208,
128,0,' ','@',1,'o',128,0,0,224,'"',30,0,0,'@',0,8,' ',0,'T','2',26,163,'&',
129,160,211,212,18,'I',169,234,13,168,26,6,150,'1',155,134,'p',8,173,3,183,
'J','S',26,20,'2',222,'b',240,160,'a','>',205,'f',29,170,227,'[',179,139,
'\'','L','o',211,':',178,'0',162,134,'*','>','8',24,153,230,147,'R','?',23,
'r','E','8','P',144,237,7,140,'W'};
DEFINE_TEST(test_read_format_tbz)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assert(0 == archive_read_support_compression_all(a));
assert(0 == archive_read_support_format_all(a));
assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assert(0 == archive_read_next_header(a, &ae));
assert(archive_compression(a) == ARCHIVE_COMPRESSION_BZIP2);
assert(archive_format(a) == ARCHIVE_FORMAT_TAR_USTAR);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
static unsigned char archive[] = {
31,139,8,0,222,'C','p','C',0,3,211,'c',160,'=','0','0','0','0','7','5','U',
0,210,134,230,166,6,200,'4',28,'(',24,26,24,27,155,24,152,24,154,27,155,')',
24,24,26,152,154,25,'2','(',152,210,193,'m',12,165,197,'%',137,'E','@',167,
148,'d',230,226,'U','G','H',30,234,15,'8','=',10,'F',193,'(',24,5,131,28,
0,0,29,172,5,240,0,6,0,0};
DEFINE_TEST(test_read_format_tgz)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assert(0 == archive_read_support_compression_all(a));
assert(0 == archive_read_support_format_all(a));
assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assert(0 == archive_read_next_header(a, &ae));
assert(archive_compression(a) == ARCHIVE_COMPRESSION_GZIP);
assert(archive_format(a) == ARCHIVE_FORMAT_TAR_USTAR);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,56 @@
/*-
* 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 unsigned char archive[] = {
31,157,144,'.',0,8,28,'H',176,160,193,131,8,19,'*','\\',200,176,'!','B',24,
16,'o',212,168,1,2,0,196,24,18,'a','T',188,152,'q','#',196,143,' ','5',198,
128,'1','c',6,13,24,'4','0',206,176,1,2,198,200,26,'6','b',0,0,'Q',195,161,
205,155,'8','s',234,4,'P','g',14,157,'0','r',',',194,160,147,166,205,206,
132,'D',141,30,'=',24,'R',163,'P',144,21,151,'J',157,'J',181,170,213,171,
'X',179,'j',221,202,181,171,215,175,'`',195,138,29,'K',182,172,217,179,'h',
211,170,']',203,182,173,219,183,'g',1};
DEFINE_TEST(test_read_format_tz)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assertA(0 == archive_read_next_header(a, &ae));
assertA(archive_compression(a) == ARCHIVE_COMPRESSION_COMPRESS);
assertA(archive_format(a) == ARCHIVE_FORMAT_TAR_USTAR);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
static unsigned char archive[] = {
'P','K',3,4,10,0,0,0,0,0,162,186,'g','3',0,0,0,0,0,0,0,0,0,0,0,0,1,0,21,0,
'a','U','T',9,0,3,224,'Q','p','C',224,'Q','p','C','U','x',4,0,232,3,232,3,
'P','K',1,2,23,3,10,0,0,0,0,0,162,186,'g','3',0,0,0,0,0,0,0,0,0,0,0,0,1,0,
13,0,0,0,0,0,0,0,0,0,164,129,0,0,0,0,'a','U','T',5,0,3,224,'Q','p','C','U',
'x',0,0,'P','K',5,6,0,0,0,0,1,0,1,0,'<',0,0,0,'4',0,0,0,0,0};
DEFINE_TEST(test_read_format_zip)
{
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_open_memory(a, archive, sizeof(archive)));
assertA(0 == archive_read_next_header(a, &ae));
assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
assertA(archive_format(a) == ARCHIVE_FORMAT_ZIP);
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}

View File

@ -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$");
static unsigned char testdata[10 * 1024 * 1024];
static unsigned char testdatacopy[10 * 1024 * 1024];
static unsigned char buff[11 * 1024 * 1024];
/* Check correct behavior on large reads. */
DEFINE_TEST(test_read_large)
{
int i;
int tmpfile;
char tmpfilename[] = "/tmp/test-read_large.XXXXXX";
size_t used;
struct archive *a;
struct archive_entry *entry;
for (i = 0; i < sizeof(testdata); i++)
testdata[i] = (unsigned char)(rand());
assert(NULL != (a = archive_write_new()));
assertA(0 == archive_write_set_format_ustar(a));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
assert(NULL != (entry = archive_entry_new()));
archive_entry_set_size(entry, sizeof(testdata));
archive_entry_set_mode(entry, S_IFREG | 0777);
archive_entry_set_pathname(entry, "test");
assertA(0 == archive_write_header(a, entry));
assertA(sizeof(testdata) == archive_write_data(a, testdata, sizeof(testdata)));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
assert(NULL != (a = archive_read_new()));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff, sizeof(buff)));
assertA(0 == archive_read_next_header(a, &entry));
assertA(0 == archive_read_data_into_buffer(a, testdatacopy, sizeof(testdatacopy)));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
assert(0 == memcmp(testdata, testdatacopy, sizeof(testdata)));
assert(NULL != (a = archive_read_new()));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff, sizeof(buff)));
assertA(0 == archive_read_next_header(a, &entry));
assert(0 < (tmpfile = mkstemp(tmpfilename)));
assertA(0 == archive_read_data_into_fd(a, tmpfile));
close(tmpfile);
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
tmpfile = open(tmpfilename, O_RDONLY);
read(tmpfile, testdatacopy, sizeof(testdatacopy));
close(tmpfile);
assert(0 == memcmp(testdata, testdatacopy, sizeof(testdata)));
unlink(tmpfilename);
}

View File

@ -0,0 +1,74 @@
/*-
* 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 unsigned char nulls[10000000];
static unsigned char buff[10000000];
/* Check that header_position tracks correctly on read. */
DEFINE_TEST(test_read_position)
{
struct archive *a;
struct archive_entry *ae;
size_t write_pos;
const size_t data_size = 1000000;
/* Create a simple archive_entry. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_set_pathname(ae, "testfile");
archive_entry_set_mode(ae, S_IFREG);
archive_entry_set_size(ae, data_size);
assert(NULL != (a = archive_write_new()));
assertA(0 == archive_write_set_format_pax_restricted(a));
assertA(0 == archive_write_set_bytes_per_block(a, 512));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &write_pos));
assertA(0 == archive_write_header(a, ae));
assertA(data_size == archive_write_data(a, nulls, sizeof(nulls)));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
assertA(0 == archive_write_close(a));
archive_write_finish(a);
#endif
/* 512-byte header + data_size (rounded up) + 1024 end-of-archive */
assert(write_pos == ((512 + data_size + 1024 + 511)/512)*512);
/* Read the archive back. */
assert(NULL != (a = archive_read_new()));
assertA(0 == archive_read_support_format_tar(a));
assertA(0 == archive_read_open_memory2(a, buff, sizeof(buff), 512));
assert((intmax_t)0 == (intmax_t)archive_read_header_position(a));
assertA(0 == archive_read_next_header(a, &ae));
assert((intmax_t)0 == (intmax_t)archive_read_header_position(a));
assertA(0 == archive_read_data_skip(a));
assert((intmax_t)0 == (intmax_t)archive_read_header_position(a));
assertA(1 == archive_read_next_header(a, &ae));
assert((intmax_t)((data_size + 511 + 512)/512)*512 == (intmax_t)archive_read_header_position(a));
assertA(0 == archive_read_close(a));
assert((intmax_t)((data_size + 511 + 512)/512)*512 == (intmax_t)archive_read_header_position(a));
archive_read_finish(a);
}

View File

@ -0,0 +1,148 @@
/*-
* 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$");
char buff[1000000];
char buff2[100000];
DEFINE_TEST(test_read_truncated)
{
struct archive_entry *ae;
struct archive *a;
int i;
size_t used;
/* Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_ustar(a));
assertA(0 == archive_write_set_compression_none(a));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
/*
* Write a file to it.
*/
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0755);
for (i = 0; i < sizeof(buff2); i++)
buff2[i] = (unsigned char)rand();
archive_entry_set_size(ae, sizeof(buff2));
assertA(0 == archive_write_header(a, ae));
assertA(sizeof(buff2) == archive_write_data(a, buff2, sizeof(buff2)));
/* Close out the archive. */
assertA(0 == archive_write_close(a));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
/* Now, read back a truncated version of the archive and
* verify that we get an appropriate error. */
for (i = 1; i < used + 100; i += 100) {
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff, i));
if (i < 512) {
assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
goto wrap_up;
} else {
assertA(0 == archive_read_next_header(a, &ae));
}
if (i < 512 + sizeof(buff2)) {
assertA(ARCHIVE_FATAL == archive_read_data(a, buff2, sizeof(buff2)));
goto wrap_up;
} else {
assertA(sizeof(buff2) == archive_read_data(a, buff2, sizeof(buff2)));
}
/* Verify the end of the archive. */
/* Archive must be long enough to capture a 512-byte
* block of zeroes after the entry. (POSIX requires a
* second block of zeros to be written but libarchive
* does not return an error if it can't consume
* it.) */
if (i < 512 + 512*((sizeof(buff2) + 511)/512) + 512) {
assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
} else {
assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
}
wrap_up:
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}
/* Same as above, except skip the body instead of reading it. */
for (i = 1; i < used + 100; i += 100) {
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff, i));
if (i < 512) {
assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
goto wrap_up2;
} else {
assertA(0 == archive_read_next_header(a, &ae));
}
if (i < 512 + 512*((sizeof(buff2)+511)/512)) {
assertA(ARCHIVE_FATAL == archive_read_data_skip(a));
goto wrap_up2;
} else {
assertA(ARCHIVE_OK == archive_read_data_skip(a));
}
/* Verify the end of the archive. */
/* Archive must be long enough to capture a 512-byte
* block of zeroes after the entry. (POSIX requires a
* second block of zeros to be written but libarchive
* does not return an error if it can't consume
* it.) */
if (i < 512 + 512*((sizeof(buff2) + 511)/512) + 512) {
assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
} else {
assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
}
wrap_up2:
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}
}

View File

@ -0,0 +1,92 @@
/*-
* 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 UMASK 022
static void create(struct archive_entry *ae)
{
struct archive *ad;
struct stat st;
/* Write the entry to disk. */
assert((ad = archive_write_disk_new()) != NULL);
assert(0 == archive_write_header(ad, ae));
assert(0 == archive_write_finish_entry(ad));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_write_finish(ad));
#else
archive_write_finish(ad);
#endif
/* Test the entries on disk. */
assert(0 == stat(archive_entry_pathname(ae), &st));
failure("st.st_mode=%o archive_entry_mode(ae)=%o",
st.st_mode, archive_entry_mode(ae));
assert(st.st_mode == (archive_entry_mode(ae) & ~UMASK));
}
DEFINE_TEST(test_write_disk)
{
struct archive_entry *ae;
/* Force the umask to something predictable. */
umask(UMASK);
/* A regular file. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0755);
create(ae);
archive_entry_free(ae);
/* A regular file over an existing file */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0724);
create(ae);
archive_entry_free(ae);
/* A directory. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir");
archive_entry_set_mode(ae, S_IFDIR | 0555);
create(ae);
archive_entry_free(ae);
/* A directory over an existing file. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFDIR | 0742);
create(ae);
archive_entry_free(ae);
/* A file over an existing dir. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0744);
create(ae);
archive_entry_free(ae);
}

View File

@ -0,0 +1,324 @@
/*-
* 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 UMASK 022
static gid_t _default_gid = 0;
static gid_t _invalid_gid = 0;
static gid_t _alt_gid = 0;
/*
* To fully test SGID restores, we need three distinct GIDs to work
* with:
* * the GID that files are created with by default (for the
* current user in the current directory)
* * An "alt gid" that this user can create files with
* * An "invalid gid" that this user is not permitted to create
* files with.
* The second fails if this user doesn't belong to at least two groups;
* the third fails if the current user is root.
*/
static int
searchgid(void)
{
static int _searched = 0;
uid_t uid = getuid();
gid_t gid = 0;
int n;
struct stat st;
int fd;
/* If we've already looked this up, we're done. */
if (_searched)
return;
_searched = 1;
/* Create a file on disk. */
fd = open("test_gid", O_CREAT, 0664);
failure("Couldn't create a file for gid testing.");
assert(fd > 0);
/* See what GID it ended up with. This is our "valid" GID. */
assert(fstat(fd, &st) == 0);
_default_gid = st.st_gid;
/* Find a GID for which fchown() fails. This is our "invalid" GID. */
_invalid_gid = 0;
/* This loop stops when we wrap the gid or examine 10,000 gids. */
for (gid = 1, n = 1; gid == n && n < 10000 ; n++, gid++) {
if (fchown(fd, uid, gid) != 0) {
_invalid_gid = gid;
break;
}
}
/*
* Find a GID for which fchown() succeeds, but which isn't the
* default. This is the "alternate" gid.
*/
_alt_gid = 0;
for (gid = 1, n = 1; gid == n && n < 10000 ; n++, gid++) {
/* _alt_gid must be different than _default_gid */
if (gid == _default_gid)
continue;
if (fchown(fd, uid, gid) == 0) {
_alt_gid = gid;
break;
}
}
close(fd);
}
static int
altgid(void)
{
searchgid();
return (_alt_gid);
}
static int
invalidgid(void)
{
searchgid();
return (_invalid_gid);
}
static int
defaultgid(void)
{
searchgid();
return (_default_gid);
}
/*
* Exercise permission and ownership restores.
* In particular, try to exercise a bunch of border cases related
* to files/dirs that already exist, SUID/SGID bits, etc.
*/
DEFINE_TEST(test_write_disk_perms)
{
struct archive *a;
struct archive_entry *ae;
struct stat st;
/* Create an archive_write_disk object. */
assert((a = archive_write_disk_new()) != NULL);
/* Write a regular file to it. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file_0755");
archive_entry_set_mode(ae, S_IFREG | 0777);
assert(0 == archive_write_header(a, ae));
assert(0 == archive_write_finish_entry(a));
/* Write a regular file with SUID bit, but don't use _EXTRACT_PERM. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file_no_suid");
archive_entry_set_mode(ae, S_IFREG | S_ISUID | 0777);
archive_write_disk_set_options(a, 0);
assert(0 == archive_write_header(a, ae));
assert(0 == archive_write_finish_entry(a));
/* Write a regular file with ARCHIVE_EXTRACT_PERM. */
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "file_0777");
archive_entry_set_mode(ae, S_IFREG | 0777);
archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
assert(0 == archive_write_header(a, ae));
assert(0 == archive_write_finish_entry(a));
/* Write a regular file with ARCHIVE_EXTRACT_PERM & SUID bit */
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "file_4742");
archive_entry_set_mode(ae, S_IFREG | S_ISUID | 0742);
archive_entry_set_uid(ae, getuid());
archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
assert(0 == archive_write_header(a, ae));
assert(0 == archive_write_finish_entry(a));
/*
* Write a regular file with ARCHIVE_EXTRACT_PERM & SUID bit,
* but wrong uid. POSIX says you shouldn't restore SUID bit
* unless the UID could be restored.
*/
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "file_bad_suid");
archive_entry_set_mode(ae, S_IFREG | S_ISUID | 0742);
archive_entry_set_uid(ae, getuid() + 1);
archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
assertA(0 == archive_write_header(a, ae));
assertA(ARCHIVE_WARN == archive_write_finish_entry(a));
/* Write a regular file with ARCHIVE_EXTRACT_PERM & SGID bit */
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "file_perm_sgid");
archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
archive_entry_set_gid(ae, defaultgid());
archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
assert(0 == archive_write_header(a, ae));
failure("Setting SGID bit should succeed here.");
assertEqualIntA(a, 0, archive_write_finish_entry(a));
if (altgid() == 0) {
/*
* Current user must belong to at least two groups or
* else we can't test setting the GID to another group.
*/
printf("Current user can't test gid restore: must belong to more than one group.\n");
} else {
/* Write a regular file with ARCHIVE_EXTRACT_PERM & SGID bit */
/*
* This is a weird case: The user has asked for permissions to
* be restored but not asked for ownership to be restored. As
* a result, the default file creation will create a file with
* the wrong group. There are two reasonable behaviors: warn
* and drop the SGID bit (the current libarchive behavior) or
* try to set the group. It is completely wrong to set the
* SGID bit with the wrong group (which is, incidentally,
* exactly what gtar 1.15 does).
*/
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "file_alt_sgid");
archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
archive_entry_set_uid(ae, getuid());
archive_entry_set_gid(ae, altgid());
archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
assert(0 == archive_write_header(a, ae));
failure("Setting SGID bit should not succeed here.");
assertEqualIntA(a, ARCHIVE_WARN, archive_write_finish_entry(a));
/* As above, but add _EXTRACT_OWNER. */
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "file_alt_sgid_owner");
archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
archive_entry_set_uid(ae, getuid());
archive_entry_set_gid(ae, altgid());
archive_write_disk_set_options(a,
ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_OWNER);
assert(0 == archive_write_header(a, ae));
failure("Setting SGID bit should succeed here.");
assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
}
/*
* Write a regular file with ARCHIVE_EXTRACT_PERM & SGID bit,
* but wrong GID. POSIX says you shouldn't restore SGID bit
* unless the GID could be restored.
*/
if (invalidgid() == 0) {
/* This test always fails for root. */
printf("Running as root: Can't test SGID failures.\n");
} else {
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "file_bad_sgid");
archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
archive_entry_set_gid(ae, invalidgid());
archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
assertA(0 == archive_write_header(a, ae));
failure("This SGID restore should fail.");
assertEqualIntA(a, ARCHIVE_WARN, archive_write_finish_entry(a));
}
/* Set ownership should fail if we're not root. */
if (getuid() == 0) {
printf("Running as root: Can't test setuid failures.\n");
} else {
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "file_bad_owner");
archive_entry_set_mode(ae, S_IFREG | 0744);
archive_entry_set_uid(ae, getuid() + 1);
archive_write_disk_set_options(a, ARCHIVE_EXTRACT_OWNER);
assertA(0 == archive_write_header(a, ae));
assertEqualIntA(a,ARCHIVE_WARN,archive_write_finish_entry(a));
}
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
/* Test the entries on disk. */
assert(0 == stat("file_0755", &st));
failure("file_0755: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == 0755);
assert(0 == stat("file_no_suid", &st));
failure("file_0755: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == 0755);
assert(0 == stat("file_0777", &st));
failure("file_0777: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == 0777);
/* SUID bit should get set here. */
assert(0 == stat("file_4742", &st));
failure("file_4742: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == (S_ISUID | 0742));
/* SUID bit should NOT have been set here. */
assert(0 == stat("file_bad_suid", &st));
failure("file_bad_suid: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == (0742));
/* SGID should be set here. */
assert(0 == stat("file_perm_sgid", &st));
failure("file_perm_sgid: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == (S_ISGID | 0742));
if (altgid() != 0) {
/* SGID should not be set here. */
assert(0 == stat("file_alt_sgid", &st));
failure("file_alt_sgid: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == (0742));
/* SGID should be set here. */
assert(0 == stat("file_alt_sgid_owner", &st));
failure("file_alt_sgid: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == (S_ISGID | 0742));
}
if (invalidgid() != 0) {
/* SGID should NOT be set here. */
assert(0 == stat("file_bad_sgid", &st));
failure("file_bad_sgid: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == (0742));
}
if (getuid() != 0) {
assert(0 == stat("file_bad_owner", &st));
failure("file_bad_owner: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == (0744));
failure("file_bad_owner: st.st_uid=%d getuid()=%d",
st.st_uid, getuid());
/* The entry had getuid()+1, but because we're
* not root, we should not have been able to set that. */
assert(st.st_uid == getuid());
}
}

View File

@ -0,0 +1,140 @@
/*-
* 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 UMASK 022
/*
* Exercise security checks that should prevent certain
* writes.
*/
DEFINE_TEST(test_write_disk_secure)
{
struct archive *a;
struct archive_entry *ae;
struct stat st;
/* Start with a known umask. */
umask(UMASK);
/* Create an archive_write_disk object. */
assert((a = archive_write_disk_new()) != NULL);
/* Write a regular dir to it. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "dir");
archive_entry_set_mode(ae, S_IFDIR | 0777);
assert(0 == archive_write_header(a, ae));
assert(0 == archive_write_finish_entry(a));
/* Write a symlink to the dir above. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "link_to_dir");
archive_entry_set_mode(ae, S_IFLNK | 0777);
archive_entry_set_symlink(ae, "dir");
archive_write_disk_set_options(a, 0);
assert(0 == archive_write_header(a, ae));
assert(0 == archive_write_finish_entry(a));
/*
* Without security checks, we should be able to
* extract a file through the link.
*/
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "link_to_dir/filea");
archive_entry_set_mode(ae, S_IFREG | 0777);
assert(0 == archive_write_header(a, ae));
assert(0 == archive_write_finish_entry(a));
/* But with security checks enabled, this should fail. */
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "link_to_dir/fileb");
archive_entry_set_mode(ae, S_IFREG | 0777);
archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS);
failure("Extracting a file through a symlink should fail here.");
assertEqualInt(ARCHIVE_WARN, archive_write_header(a, ae));
assert(0 == archive_write_finish_entry(a));
/* Create another link. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "link_to_dir2");
archive_entry_set_mode(ae, S_IFLNK | 0777);
archive_entry_set_symlink(ae, "dir");
archive_write_disk_set_options(a, 0);
assert(0 == archive_write_header(a, ae));
assert(0 == archive_write_finish_entry(a));
/*
* With symlink check and unlink option, it should remove
* the link and create the dir.
*/
assert(archive_entry_clear(ae) != NULL);
archive_entry_copy_pathname(ae, "link_to_dir2/filec");
archive_entry_set_mode(ae, S_IFREG | 0777);
archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_UNLINK);
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
assert(0 == archive_write_finish_entry(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
/* Test the entries on disk. */
assert(0 == lstat("dir", &st));
failure("dir: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == 0755);
assert(0 == lstat("link_to_dir", &st));
failure("link_to_dir: st.st_mode=%o", st.st_mode);
assert(S_ISLNK(st.st_mode));
#if HAVE_LCHMOD
/* Systems that lack lchmod() can't set symlink perms, so skip this. */
failure("link_to_dir: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == 0755);
#endif
assert(0 == lstat("dir/filea", &st));
failure("dir/filea: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == 0755);
failure("dir/fileb: This file should not have been created");
assert(0 != lstat("dir/fileb", &st));
assert(0 == lstat("link_to_dir2", &st));
failure("link_to_dir2 should have been re-created as a true dir");
assert(S_ISDIR(st.st_mode));
failure("link_to_dir2: Implicit dir creation should obey umask, but st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == 0755);
assert(0 == lstat("link_to_dir2/filec", &st));
assert(S_ISREG(st.st_mode));
failure("link_to_dir2/filec: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == 0755);
}

View File

@ -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$");
/*
* Check that an "empty" cpio archive is correctly created.
*/
/* Here's what an empty cpio archive should look like. */
static char ref[] =
"070707" /* Magic number */
"000000" /* Dev = 0 */
"000000" /* ino = 0 */
"000000" /* mode = 0 */
"000000" /* uid = 0 */
"000000" /* gid = 0 */
"000001" /* nlink = 1 */
"000000" /* rdev = 0 */
"00000000000" /* mtime = 0 */
"000013" /* Namesize = 11 */
"00000000000" /* filesize = 0 */
"TRAILER!!!\0"; /* Name */
DEFINE_TEST(test_write_format_cpio_empty)
{
struct archive *a;
char buff[2048];
size_t used;
int i;
/* Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_cpio(a));
assertA(0 == archive_write_set_compression_none(a));
/* 1-byte block size ensures we see only the required bytes. */
/* We're not testing the padding here. */
assertA(0 == archive_write_set_bytes_per_block(a, 1));
assertA(0 == archive_write_set_bytes_in_last_block(a, 1));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
/* Close out the archive. */
assertA(0 == archive_write_close(a));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
failure("Empty cpio archive should be exactly 87 bytes, was %d.", used);
assert(used == 87);
failure("Empty cpio archive is incorrectly formatted.");
assert(memcmp(buff, ref, 87) == 0);
}

View File

@ -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$");
/*
* Check that an "empty" shar archive is correctly created as an empty file.
*/
DEFINE_TEST(test_write_format_shar_empty)
{
struct archive *a;
char buff[2048];
size_t used;
int i;
/* Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_shar(a));
assertA(0 == archive_write_set_compression_none(a));
/* 1-byte block size ensures we see only the required bytes. */
/* We're not testing the padding here. */
assertA(0 == archive_write_set_bytes_per_block(a, 1));
assertA(0 == archive_write_set_bytes_in_last_block(a, 1));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
/* Close out the archive. */
assertA(0 == archive_write_close(a));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
failure("Empty shar archive should be exactly 0 bytes, was %d.", used);
assert(used == 0);
}

View File

@ -0,0 +1,111 @@
/*-
* 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$");
char buff[1000000];
char buff2[64];
DEFINE_TEST(test_write_format_tar)
{
struct archive_entry *ae;
struct archive *a;
char *p;
size_t used;
int blocksize;
/* Repeat the following for a variety of odd blocksizes. */
for (blocksize = 1; blocksize < 100000; blocksize += blocksize + 3) {
/* Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_ustar(a));
assertA(0 == archive_write_set_compression_none(a));
assertA(0 == archive_write_set_bytes_per_block(a, blocksize));
assertA(0 == archive_write_set_bytes_in_last_block(a, blocksize));
assertA(blocksize == archive_write_get_bytes_in_last_block(a));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
assertA(blocksize == archive_write_get_bytes_in_last_block(a));
/*
* Write a file to it.
*/
assert((ae = archive_entry_new()) != NULL);
archive_entry_set_mtime(ae, 1, 10);
assert(1 == archive_entry_mtime(ae));
assert(10 == archive_entry_mtime_nsec(ae));
p = strdup("file");
archive_entry_copy_pathname(ae, p);
strcpy(p, "XXXX");
free(p);
assert(0 == strcmp("file", archive_entry_pathname(ae)));
archive_entry_set_mode(ae, S_IFREG | 0755);
assert((S_IFREG | 0755) == archive_entry_mode(ae));
archive_entry_set_size(ae, 8);
assertA(0 == archive_write_header(a, ae));
assertA(8 == archive_write_data(a, "12345678", 9));
/* Close out the archive. */
assertA(0 == archive_write_close(a));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
/* This calculation gives "the smallest multiple of
* the block size that is at least 2048 bytes". */
assert(((2048 - 1)/blocksize+1)*blocksize == used);
/*
* Now, read the data back.
*/
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff, used));
assertA(0 == archive_read_next_header(a, &ae));
assert(1 == archive_entry_mtime(ae));
/* Not the same as above: ustar doesn't store hi-res timestamps. */
assert(0 == archive_entry_mtime_nsec(ae));
assert(0 == archive_entry_atime(ae));
assert(0 == archive_entry_ctime(ae));
assert(0 == strcmp("file", archive_entry_pathname(ae)));
assert((S_IFREG | 0755) == archive_entry_mode(ae));
assert(8 == archive_entry_size(ae));
assertA(8 == archive_read_data(a, buff2, 10));
assert(0 == memcmp(buff2, "12345678", 8));
/* Verify the end of the archive. */
assert(1 == archive_read_next_header(a, &ae));
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
#else
archive_read_finish(a);
#endif
}
}

View File

@ -0,0 +1,84 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
/*
* Check that an "empty" tar archive is correctly created.
*/
DEFINE_TEST(test_write_format_tar_empty)
{
struct archive *a;
char buff[2048];
size_t used;
int i;
/* USTAR format: Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_ustar(a));
assertA(0 == archive_write_set_compression_none(a));
assertA(0 == archive_write_set_bytes_per_block(a, 512));
assertA(0 == archive_write_set_bytes_in_last_block(a, 512));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
/* Close out the archive. */
assertA(0 == archive_write_close(a));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
failure("Empty tar archive should be exactly 1024 bytes, was %d.", used);
assert(used == 1024);
for (i = 0; i < used; i++) {
failure("Empty tar archive should be all nulls.");
assert(buff[i] == 0);
}
/* PAX format: Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_pax(a));
assertA(0 == archive_write_set_compression_none(a));
assertA(0 == archive_write_set_bytes_per_block(a, 512));
assertA(0 == archive_write_set_bytes_in_last_block(a, 512));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
/* Close out the archive. */
assertA(0 == archive_write_close(a));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
failure("Empty tar archive should be exactly 1024 bytes, was %d.", used);
assert(used == 1024);
for (i = 0; i < used; i++) {
failure("Empty tar archive should be all nulls.");
assert(buff[i] == 0);
}
}

View File

@ -0,0 +1,75 @@
/*-
* 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$");
/* Try to force archive_write_open_memory.c to write past the end of an array. */
static unsigned char buff[16384];
DEFINE_TEST(test_write_open_memory)
{
int i;
struct archive *a;
struct archive_entry *ae;
const char *name="/tmp/test";
/* Create a simple archive_entry. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_set_pathname(ae, name);
archive_entry_set_mode(ae, S_IFREG);
assert(0 == strcmp(archive_entry_pathname(ae), name));
/* Try writing with different buffer sizes. */
/* Make sure that we get failure on too-small buffers, success on
* large enough ones. */
for (i = 100; i < 1600; i++) {
size_t s;
size_t blocksize = 94;
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_ustar(a));
assertA(0 == archive_write_set_bytes_in_last_block(a, 1));
assertA(0 == archive_write_set_bytes_per_block(a, blocksize));
buff[i] = 0xAE;
assertA(0 == archive_write_open_memory(a, buff, i, &s));
/* If buffer is smaller than a tar header, this should fail. */
if (i < (511/blocksize)*blocksize)
assertA(ARCHIVE_FATAL == archive_write_header(a,ae));
else
assertA(0 == archive_write_header(a, ae));
/* If buffer is smaller than a tar header plus 1024 byte
* end-of-archive marker, then this should fail. */
if (i < 1536)
assertA(ARCHIVE_FATAL == archive_write_close(a));
else
assertA(0 == archive_write_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_write_finish(a));
#else
archive_write_finish(a);
#endif
assert(buff[i] == 0xAE);
assert(s <= i);
}
}