libarchive/archive_write_open_filename.c \
libarchive/archive_write_open_memory.c \
libarchive/archive_write_private.h \
- libarchive/archive_write_set_compression_bzip2.c \
- libarchive/archive_write_set_compression_compress.c \
- libarchive/archive_write_set_compression_gzip.c \
- libarchive/archive_write_set_compression_none.c \
- libarchive/archive_write_set_compression_program.c \
- libarchive/archive_write_set_compression_xz.c \
+ libarchive/archive_write_add_filter_bzip2.c \
+ libarchive/archive_write_add_filter_compress.c \
+ libarchive/archive_write_add_filter_gzip.c \
+ libarchive/archive_write_add_filter_none.c \
+ libarchive/archive_write_add_filter_program.c \
+ libarchive/archive_write_add_filter_xz.c \
libarchive/archive_write_set_format.c \
libarchive/archive_write_set_format_ar.c \
libarchive/archive_write_set_format_by_name.c \
# Clean up the source dir as much as we can.
/bin/sh build/clean.sh
-# Substitute the integer version into Libarchive's archive.h
+# Substitute the versions into Libarchive's archive.h and archive_entry.h
perl -p -i -e "s/^(#define\tARCHIVE_VERSION_NUMBER).*/\$1 $VN/" libarchive/archive.h
+perl -p -i -e "s/^(#define\tARCHIVE_VERSION_NUMBER).*/\$1 $VN/" libarchive/archive_entry.h
perl -p -i -e "s/^(#define\tARCHIVE_VERSION_STRING).*/\$1 \"libarchive $VS\"/" libarchive/archive.h
# Substitute versions into configure.ac as well
perl -p -i -e 's/(m4_define\(\[LIBARCHIVE_VERSION_S\]),.*\)/$1,['"$VS"'])/' configure.ac
archive_write_open_file.c
archive_write_open_filename.c
archive_write_open_memory.c
- archive_write_set_compression_bzip2.c
- archive_write_set_compression_compress.c
- archive_write_set_compression_gzip.c
- archive_write_set_compression_none.c
- archive_write_set_compression_program.c
- archive_write_set_compression_xz.c
+ archive_write_add_filter_bzip2.c
+ archive_write_add_filter_compress.c
+ archive_write_add_filter_gzip.c
+ archive_write_add_filter_none.c
+ archive_write_add_filter_program.c
+ archive_write_add_filter_xz.c
archive_write_set_format.c
archive_write_set_format_ar.c
archive_write_set_format_by_name.c
/*-
- * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2003-2010 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
* #endif
*/
-#define ARCHIVE_VERSION_NUMBER 2007902
+#define ARCHIVE_VERSION_NUMBER 3000000
__LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
-#define ARCHIVE_VERSION_STRING "libarchive 2.7.902a"
+#define ARCHIVE_VERSION_STRING "libarchive 3.0.0a"
__LA_DECL const char * archive_version_string(void);
#if ARCHIVE_VERSION_NUMBER < 3000000
void *_client_data,
const void *_buffer, size_t _length);
-#if ARCHIVE_VERSION_NUMBER < 3000000
-/* Open callback is actually never needed; remove it in libarchive 3.0. */
typedef int archive_open_callback(struct archive *, void *_client_data);
-#endif
typedef int archive_close_callback(struct archive *, void *_client_data);
/*
- * Codes for archive_compression.
+ * Codes to identify various stream filters.
*/
-#define ARCHIVE_COMPRESSION_NONE 0
-#define ARCHIVE_COMPRESSION_GZIP 1
-#define ARCHIVE_COMPRESSION_BZIP2 2
-#define ARCHIVE_COMPRESSION_COMPRESS 3
-#define ARCHIVE_COMPRESSION_PROGRAM 4
-#define ARCHIVE_COMPRESSION_LZMA 5
-#define ARCHIVE_COMPRESSION_XZ 6
-#define ARCHIVE_COMPRESSION_UU 7
-#define ARCHIVE_COMPRESSION_RPM 8
+#define ARCHIVE_FILTER_NONE 0
+#define ARCHIVE_FILTER_GZIP 1
+#define ARCHIVE_FILTER_BZIP2 2
+#define ARCHIVE_FILTER_COMPRESS 3
+#define ARCHIVE_FILTER_PROGRAM 4
+#define ARCHIVE_FILTER_LZMA 5
+#define ARCHIVE_FILTER_XZ 6
+#define ARCHIVE_FILTER_UU 7
+#define ARCHIVE_FILTER_RPM 8
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+#define ARCHIVE_COMPRESSION_NONE ARCHIVE_FILTER_NONE
+#define ARCHIVE_COMPRESSION_GZIP ARCHIVE_FILTER_GZIP
+#define ARCHIVE_COMPRESSION_BZIP2 ARCHIVE_FILTER_BZIP2
+#define ARCHIVE_COMPRESSION_COMPRESS ARCHIVE_FILTER_COMPRESS
+#define ARCHIVE_COMPRESSION_PROGRAM ARCHIVE_FILTER_PROGRAM
+#define ARCHIVE_COMPRESSION_LZMA ARCHIVE_FILTER_LZMA
+#define ARCHIVE_COMPRESSION_XZ ARCHIVE_FILTER_XZ
+#define ARCHIVE_COMPRESSION_UU ARCHIVE_FILTER_UU
+#define ARCHIVE_COMPRESSION_RPM ARCHIVE_FILTER_RPM
+#endif
/*
* Codes returned by archive_format.
* support_compression_bzip2(). The "all" functions provide the
* obvious shorthand.
*/
-__LA_DECL int archive_read_support_compression_all(struct archive *);
-__LA_DECL int archive_read_support_compression_bzip2(struct archive *);
-__LA_DECL int archive_read_support_compression_compress(struct archive *);
-__LA_DECL int archive_read_support_compression_gzip(struct archive *);
-__LA_DECL int archive_read_support_compression_lzma(struct archive *);
-__LA_DECL int archive_read_support_compression_none(struct archive *);
-__LA_DECL int archive_read_support_compression_program(struct archive *,
+/* TODO: Rename 'compression' here to 'filter' for libarchive 3.0, deprecate
+ * the old names. */
+
+__LA_DECL int archive_read_support_compression_all(struct archive *);
+__LA_DECL int archive_read_support_compression_bzip2(struct archive *);
+__LA_DECL int archive_read_support_compression_compress(struct archive *);
+__LA_DECL int archive_read_support_compression_gzip(struct archive *);
+__LA_DECL int archive_read_support_compression_lzma(struct archive *);
+__LA_DECL int archive_read_support_compression_none(struct archive *);
+__LA_DECL int archive_read_support_compression_program(struct archive *,
const char *command);
-__LA_DECL int archive_read_support_compression_program_signature
- (struct archive *, const char *,
+__LA_DECL int archive_read_support_compression_program_signature
+ (struct archive *, const char *,
const void * /* match */, size_t);
-__LA_DECL int archive_read_support_compression_rpm(struct archive *);
-__LA_DECL int archive_read_support_compression_uu(struct archive *);
-__LA_DECL int archive_read_support_compression_xz(struct archive *);
+__LA_DECL int archive_read_support_compression_rpm(struct archive *);
+__LA_DECL int archive_read_support_compression_uu(struct archive *);
+__LA_DECL int archive_read_support_compression_xz(struct archive *);
-__LA_DECL int archive_read_support_format_all(struct archive *);
-__LA_DECL int archive_read_support_format_ar(struct archive *);
-__LA_DECL int archive_read_support_format_cpio(struct archive *);
-__LA_DECL int archive_read_support_format_empty(struct archive *);
-__LA_DECL int archive_read_support_format_gnutar(struct archive *);
-__LA_DECL int archive_read_support_format_iso9660(struct archive *);
-__LA_DECL int archive_read_support_format_mtree(struct archive *);
-__LA_DECL int archive_read_support_format_raw(struct archive *);
-__LA_DECL int archive_read_support_format_tar(struct archive *);
-__LA_DECL int archive_read_support_format_xar(struct archive *);
-__LA_DECL int archive_read_support_format_zip(struct archive *);
+__LA_DECL int archive_read_support_format_all(struct archive *);
+__LA_DECL int archive_read_support_format_ar(struct archive *);
+__LA_DECL int archive_read_support_format_cpio(struct archive *);
+__LA_DECL int archive_read_support_format_empty(struct archive *);
+__LA_DECL int archive_read_support_format_gnutar(struct archive *);
+__LA_DECL int archive_read_support_format_iso9660(struct archive *);
+__LA_DECL int archive_read_support_format_mtree(struct archive *);
+__LA_DECL int archive_read_support_format_raw(struct archive *);
+__LA_DECL int archive_read_support_format_tar(struct archive *);
+__LA_DECL int archive_read_support_format_xar(struct archive *);
+__LA_DECL int archive_read_support_format_zip(struct archive *);
/* Open the archive using callbacks for archive I/O. */
-__LA_DECL int archive_read_open(struct archive *, void *_client_data,
+__LA_DECL int archive_read_open(struct archive *, void *_client_data,
archive_open_callback *, archive_read_callback *,
archive_close_callback *);
-__LA_DECL int archive_read_open2(struct archive *, void *_client_data,
+__LA_DECL int archive_read_open2(struct archive *, void *_client_data,
archive_open_callback *, archive_read_callback *,
archive_skip_callback *, archive_close_callback *);
* accept a block size handle tape blocking correctly.
*/
/* Use this if you know the filename. Note: NULL indicates stdin. */
-__LA_DECL int archive_read_open_filename(struct archive *,
+__LA_DECL int archive_read_open_filename(struct archive *,
const char *_filename, size_t _block_size);
/* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
-__LA_DECL int archive_read_open_file(struct archive *,
+__LA_DECL int archive_read_open_file(struct archive *,
const char *_filename, size_t _block_size);
/* Read an archive that's stored in memory. */
-__LA_DECL int archive_read_open_memory(struct archive *,
+__LA_DECL int archive_read_open_memory(struct archive *,
void * buff, size_t size);
/* A more involved version that is only used for internal testing. */
-__LA_DECL int archive_read_open_memory2(struct archive *a, void *buff,
+__LA_DECL int archive_read_open_memory2(struct archive *a, void *buff,
size_t size, size_t read_size);
/* Read an archive that's already open, using the file descriptor. */
-__LA_DECL int archive_read_open_fd(struct archive *, int _fd,
+__LA_DECL int archive_read_open_fd(struct archive *, int _fd,
size_t _block_size);
/* Read an archive that's already open, using a FILE *. */
/* Note: DO NOT use this with tape drives. */
-__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file);
+__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file);
/* Parses and returns next entry header. */
-__LA_DECL int archive_read_next_header(struct archive *,
+__LA_DECL int archive_read_next_header(struct archive *,
struct archive_entry **);
/* Parses and returns next entry header using the archive_entry passed in */
-__LA_DECL int archive_read_next_header2(struct archive *,
+__LA_DECL int archive_read_next_header2(struct archive *,
struct archive_entry *);
/*
* be strictly increasing and that returned blocks will not overlap.
*/
#if ARCHIVE_VERSION_NUMBER < 3000000
-__LA_DECL int archive_read_data_block(struct archive *a,
- const void **buff, size_t *size, off_t *offset);
+__LA_DECL int archive_read_data_block(struct archive *a,
+ const void **buff, size_t *size, off_t *offset);
#else
-__LA_DECL int archive_read_data_block(struct archive *a,
- const void **buff, size_t *size,
- __LA_INT64_T *offset);
+__LA_DECL int archive_read_data_block(struct archive *a,
+ const void **buff, size_t *size, __LA_INT64_T *offset);
#endif
/*-
* 'into_buffer': writes data into memory buffer that you provide
* 'into_fd': writes data to specified filedes
*/
-__LA_DECL int archive_read_data_skip(struct archive *);
-__LA_DECL int archive_read_data_into_buffer(struct archive *,
+__LA_DECL int archive_read_data_skip(struct archive *);
+__LA_DECL int archive_read_data_into_buffer(struct archive *,
void *buffer, __LA_SSIZE_T len);
-__LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
+__LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
/*
* Set read options.
*/
/* Apply option string to the format only. */
-__LA_DECL int archive_read_set_format_options(struct archive *_a,
+__LA_DECL int archive_read_set_format_options(struct archive *_a,
const char *s);
/* Apply option string to the filter only. */
-__LA_DECL int archive_read_set_filter_options(struct archive *_a,
+__LA_DECL int archive_read_set_filter_options(struct archive *_a,
const char *s);
/* Apply option string to both the format and the filter. */
-__LA_DECL int archive_read_set_options(struct archive *_a,
+__LA_DECL int archive_read_set_options(struct archive *_a,
const char *s);
/*-
/* Detect blocks of 0 and write holes instead. */
#define ARCHIVE_EXTRACT_SPARSE (0x1000)
-__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
+__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
int flags);
-__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *,
+__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *,
struct archive * /* dest */);
__LA_DECL void archive_read_extract_set_progress_callback(struct archive *,
void (*_progress_func)(void *), void *_user_data);
* 6) archive_write_free to cleanup the writer and release resources
*/
__LA_DECL struct archive *archive_write_new(void);
-__LA_DECL int archive_write_set_bytes_per_block(struct archive *,
+__LA_DECL int archive_write_set_bytes_per_block(struct archive *,
int bytes_per_block);
-__LA_DECL int archive_write_get_bytes_per_block(struct archive *);
+__LA_DECL int archive_write_get_bytes_per_block(struct archive *);
/* XXX This is badly misnamed; suggestions appreciated. XXX */
-__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
+__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
int bytes_in_last_block);
-__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *);
+__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *);
/* The dev/ino of a file that won't be archived. This is used
* to avoid recursively adding an archive to itself. */
-__LA_DECL int archive_write_set_skip_file(struct archive *, dev_t, ino_t);
-
-__LA_DECL int archive_write_set_compression_bzip2(struct archive *);
-__LA_DECL int archive_write_set_compression_compress(struct archive *);
-__LA_DECL int archive_write_set_compression_gzip(struct archive *);
-__LA_DECL int archive_write_set_compression_lzma(struct archive *);
-__LA_DECL int archive_write_set_compression_none(struct archive *);
-__LA_DECL int archive_write_set_compression_program(struct archive *,
+__LA_DECL int archive_write_set_skip_file(struct archive *, dev_t, ino_t);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+__LA_DECL int archive_write_set_compression_bzip2(struct archive *);
+__LA_DECL int archive_write_set_compression_compress(struct archive *);
+__LA_DECL int archive_write_set_compression_gzip(struct archive *);
+__LA_DECL int archive_write_set_compression_lzma(struct archive *);
+__LA_DECL int archive_write_set_compression_none(struct archive *);
+__LA_DECL int archive_write_set_compression_program(struct archive *,
+ const char *cmd);
+__LA_DECL int archive_write_set_compression_xz(struct archive *);
+#endif
+
+__LA_DECL int archive_write_add_filter_bzip2(struct archive *);
+__LA_DECL int archive_write_add_filter_compress(struct archive *);
+__LA_DECL int archive_write_add_filter_gzip(struct archive *);
+__LA_DECL int archive_write_add_filter_lzma(struct archive *);
+__LA_DECL int archive_write_add_filter_none(struct archive *);
+__LA_DECL int archive_write_add_filter_program(struct archive *,
const char *cmd);
-__LA_DECL int archive_write_set_compression_xz(struct archive *);
+__LA_DECL int archive_write_add_filter_xz(struct archive *);
+
+
/* A convenience function to set the format based on the code or name. */
-__LA_DECL int archive_write_set_format(struct archive *, int format_code);
-__LA_DECL int archive_write_set_format_by_name(struct archive *,
+__LA_DECL int archive_write_set_format(struct archive *, int format_code);
+__LA_DECL int archive_write_set_format_by_name(struct archive *,
const char *name);
/* To minimize link pollution, use one or more of the following. */
-__LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
-__LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
-__LA_DECL int archive_write_set_format_cpio(struct archive *);
-__LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
-__LA_DECL int archive_write_set_format_mtree(struct archive *);
+__LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
+__LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
+__LA_DECL int archive_write_set_format_cpio(struct archive *);
+__LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
+__LA_DECL int archive_write_set_format_mtree(struct archive *);
/* TODO: int archive_write_set_format_old_tar(struct archive *); */
-__LA_DECL int archive_write_set_format_pax(struct archive *);
-__LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
-__LA_DECL int archive_write_set_format_shar(struct archive *);
-__LA_DECL int archive_write_set_format_shar_dump(struct archive *);
-__LA_DECL int archive_write_set_format_ustar(struct archive *);
-__LA_DECL int archive_write_set_format_zip(struct archive *);
-__LA_DECL int archive_write_open(struct archive *, void *,
+__LA_DECL int archive_write_set_format_pax(struct archive *);
+__LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
+__LA_DECL int archive_write_set_format_shar(struct archive *);
+__LA_DECL int archive_write_set_format_shar_dump(struct archive *);
+__LA_DECL int archive_write_set_format_ustar(struct archive *);
+__LA_DECL int archive_write_set_format_zip(struct archive *);
+__LA_DECL int archive_write_open(struct archive *, void *,
archive_open_callback *, archive_write_callback *,
archive_close_callback *);
-__LA_DECL int archive_write_open_fd(struct archive *, int _fd);
-__LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
+__LA_DECL int archive_write_open_fd(struct archive *, int _fd);
+__LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
/* A deprecated synonym for archive_write_open_filename() */
-__LA_DECL int archive_write_open_file(struct archive *, const char *_file);
-__LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
+__LA_DECL int archive_write_open_file(struct archive *, const char *_file);
+__LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
/* _buffSize is the size of the buffer, _used refers to a variable that
* will be updated after each write into the buffer. */
-__LA_DECL int archive_write_open_memory(struct archive *,
+__LA_DECL int archive_write_open_memory(struct archive *,
void *_buffer, size_t _buffSize, size_t *_used);
/*
* Note that the library will truncate writes beyond the size provided
* to archive_write_header or pad if the provided data is short.
*/
-__LA_DECL int archive_write_header(struct archive *,
+__LA_DECL int archive_write_header(struct archive *,
struct archive_entry *);
-/* Libarchive 2.0 and later return ssize_t here. */
-__LA_DECL __LA_SSIZE_T archive_write_data(struct archive *,
+__LA_DECL __LA_SSIZE_T archive_write_data(struct archive *,
const void *, size_t);
#if ARCHIVE_VERSION_NUMBER < 3000000
__LA_DECL int archive_write_set_options(struct archive *_a,
const char *s);
-
/*-
* ARCHIVE_WRITE_DISK API
*
* Accessor functions to read/set various information in
* the struct archive object:
*/
-/* Bytes written after compression or read before decompression. */
+
+/* Number of filters in the current filter pipeline. */
+/* Filter #0 is the one closest to the format, -1 is a synonym for the
+ * last filter, which is always the pseudo-filter that wraps the
+ * client callbacks. */
+__LA_DECL int archive_filter_count(struct archive *);
+__LA_DECL __LA_INT64_T archive_filter_bytes(struct archive *, int);
+__LA_DECL int archive_filter_code(struct archive *, int);
+__LA_DECL const char * archive_filter_name(struct archive *, int);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* These don't properly handle multiple filters, so are deprecated and
+ * will eventually be removed. */
+/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */
__LA_DECL __LA_INT64_T archive_position_compressed(struct archive *);
-/* Bytes written to compressor or read from decompressor. */
+/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */
__LA_DECL __LA_INT64_T archive_position_uncompressed(struct archive *);
-
+/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
__LA_DECL const char *archive_compression_name(struct archive *);
+/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */
__LA_DECL int archive_compression(struct archive *);
+#endif
+
__LA_DECL int archive_errno(struct archive *);
__LA_DECL const char *archive_error_string(struct archive *);
__LA_DECL const char *archive_format_name(struct archive *);
#ifndef ARCHIVE_ENTRY_H_INCLUDED
#define ARCHIVE_ENTRY_H_INCLUDED
+/* Needed if archive_entry.h is used without archive.h */
+#ifndef ARCHIVE_VERSION_NUMBER
+#define ARCHIVE_VERSION_NUMBER 3000000
+#endif
+
/*
* Note: archive_entry.h is for use outside of libarchive; the
* configuration headers (config.h, archive_platform.h, etc.) are
__LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_hardlink_utf8(struct archive_entry *, const char *);
-#if ARCHIVE_VERSION_NUMBER >= 3000000
-/* Starting with libarchive 3.0, this will be synonym for ino64. */
-__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INT64_T);
-#else
+#if ARCHIVE_VERSION_NUMBER < 3000000
__LA_DECL void archive_entry_set_ino(struct archive_entry *, unsigned long);
+#else
+__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INT64_T);
#endif
__LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INT64_T);
__LA_DECL void archive_entry_set_link(struct archive_entry *, const char *);
#include <sys/stat.h>
#endif
+#include "archive.h"
#include "archive_entry.h"
void
#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
const void *, size_t);
ssize_t (*archive_write_data_block)(struct archive *,
const void *, size_t, off_t);
+
+ int (*archive_filter_count)(struct archive *);
+ int64_t (*archive_filter_bytes)(struct archive *, int);
+ int (*archive_filter_code)(struct archive *, int);
+ const char * (*archive_filter_name)(struct archive *, int);
};
struct archive {
int compression_code; /* Currently active compression. */
const char *compression_name;
- /* Position in UNCOMPRESSED data stream. */
- int64_t file_position;
- /* Position in COMPRESSED data stream. */
- int64_t raw_position;
/* Number of file entries processed. */
int file_count;
static int build_stream(struct archive_read *);
static int choose_format(struct archive_read *);
-static int cleanup_filters(struct archive_read *);
+static void free_filters(struct archive_read *);
+static int close_filters(struct archive_read *);
static struct archive_vtable *archive_read_vtable(void);
+static int64_t _archive_filter_bytes(struct archive *, int);
+static int _archive_filter_code(struct archive *, int);
+static const char *_archive_filter_name(struct archive *, int);
static int _archive_read_close(struct archive *);
static int _archive_read_free(struct archive *);
static int inited = 0;
if (!inited) {
+ av.archive_filter_bytes = _archive_filter_bytes;
+ av.archive_filter_code = _archive_filter_code;
+ av.archive_filter_name = _archive_filter_name;
av.archive_free = _archive_read_free;
av.archive_close = _archive_read_close;
}
ssize_t r;
r = (self->archive->client.reader)(&self->archive->archive,
self->data, buff);
- self->archive->archive.raw_position += r;
return (r);
}
if (get == 0)
return (total);
request -= get;
- self->archive->archive.raw_position += get;
total += get;
}
}
/* Verify the filter by asking it for some data. */
__archive_read_filter_ahead(filter, 1, &avail);
if (avail < 0) {
- cleanup_filters(a);
+ close_filters(a);
+ free_filters(a);
return (ARCHIVE_FATAL);
}
}
return (ret);
}
- /* Record start-of-header. */
- a->header_position = a->archive.file_position;
+ /* Record start-of-header offset in uncompressed stream. */
+ a->header_position = a->filter->bytes_consumed;
ret = (a->format->read_header)(a, entry);
return (a->format->read_data)(a, buff, size, offset);
}
+static int
+close_filters(struct archive_read *a)
+{
+ struct archive_read_filter *f = a->filter;
+ int r = ARCHIVE_OK;
+ /* Close each filter in the pipeline. */
+ while (f != NULL) {
+ struct archive_read_filter *t = f->upstream;
+ if (f->close != NULL) {
+ int r1 = (f->close)(f);
+ if (r1 < r)
+ r = r1;
+ }
+ free(f->buffer);
+ f->buffer = NULL;
+ f = t;
+ }
+ return r;
+}
+
+static void
+free_filters(struct archive_read *a)
+{
+ while (a->filter != NULL) {
+ struct archive_read_filter *t = a->filter->upstream;
+ free(a->filter);
+ a->filter = t;
+ }
+}
+
/*
- * Close the file and release most resources.
- *
- * Be careful: client might just call read_new and then read_finish.
- * Don't assume we actually read anything or performed any non-trivial
- * initialization.
+ * Close the file and all I/O.
*/
static int
_archive_read_close(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
- size_t i, n;
__archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_close");
archive_clear_error(&a->archive);
a->archive.state = ARCHIVE_STATE_CLOSED;
-
- /* Call cleanup functions registered by optional components. */
- if (a->cleanup_archive_extract != NULL)
- r = (a->cleanup_archive_extract)(a);
-
/* TODO: Clean up the formatters. */
/* Release the filter objects. */
- r1 = cleanup_filters(a);
+ r1 = close_filters(a);
if (r1 < r)
r = r1;
- /* Release the bidder objects. */
- n = sizeof(a->bidders)/sizeof(a->bidders[0]);
- for (i = 0; i < n; i++) {
- if (a->bidders[i].free != NULL) {
- r1 = (a->bidders[i].free)(&a->bidders[i]);
- if (r1 < r)
- r = r1;
- }
- }
-
return (r);
}
-static int
-cleanup_filters(struct archive_read *a)
-{
- int r = ARCHIVE_OK;
- /* Clean up the filter pipeline. */
- while (a->filter != NULL) {
- struct archive_read_filter *t = a->filter->upstream;
- if (a->filter->close != NULL) {
- int r1 = (a->filter->close)(a->filter);
- if (r1 < r)
- r = r1;
- }
- free(a->filter->buffer);
- free(a->filter);
- a->filter = t;
- }
- return r;
-}
-
/*
* Release memory and other resources.
*/
_archive_read_free(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
- int i;
+ int i, n;
int slots;
int r = ARCHIVE_OK;
if (a->archive.state != ARCHIVE_STATE_CLOSED)
r = archive_read_close(&a->archive);
+ /* Call cleanup functions registered by optional components. */
+ if (a->cleanup_archive_extract != NULL)
+ r = (a->cleanup_archive_extract)(a);
+
/* Cleanup format-specific data. */
slots = sizeof(a->formats) / sizeof(a->formats[0]);
for (i = 0; i < slots; i++) {
(a->formats[i].cleanup)(a);
}
+ /* Free the filters */
+ free_filters(a);
+
+ /* Release the bidder objects. */
+ n = sizeof(a->bidders)/sizeof(a->bidders[0]);
+ for (i = 0; i < n; i++) {
+ if (a->bidders[i].free != NULL) {
+ int r1 = (a->bidders[i].free)(&a->bidders[i]);
+ if (r1 < r)
+ r = r1;
+ }
+ }
+
archive_string_free(&a->archive.error_string);
if (a->entry)
archive_entry_free(a->entry);
return (r);
}
+static struct archive_read_filter *
+get_filter(struct archive *_a, int n)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter *f = a->filter;
+ /* XXX handle n == -1 */
+ if (n < 0)
+ return NULL;
+ while (n > 0 && f != NULL) {
+ f = f->upstream;
+ --n;
+ }
+ return (f);
+}
+
+static int
+_archive_filter_code(struct archive *_a, int n)
+{
+ struct archive_read_filter *f = get_filter(_a, n);
+ return f == NULL ? -1 : f->code;
+}
+
+static const char *
+_archive_filter_name(struct archive *_a, int n)
+{
+ struct archive_read_filter *f = get_filter(_a, n);
+ return f == NULL ? NULL : f->name;
+}
+
+static int64_t
+_archive_filter_bytes(struct archive *_a, int n)
+{
+ struct archive_read_filter *f = get_filter(_a, n);
+ return f == NULL ? -1 : f->bytes_consumed;
+}
+
/*
* Used internally by read format handlers to register their bid and
* initialization functions.
ssize_t
__archive_read_consume(struct archive_read *a, size_t request)
{
- ssize_t r;
- r = __archive_read_filter_consume(a->filter, request);
- a->archive.file_position += r;
- return (r);
+ return (__archive_read_filter_consume(a->filter, request));
}
ssize_t
filter->client_next += request;
filter->client_avail -= request;
}
+ filter->bytes_consumed += request;
return (request);
}
int64_t
__archive_read_skip_lenient(struct archive_read *a, int64_t request)
{
- int64_t skipped = __archive_read_filter_skip(a->filter, request);
- if (skipped > 0)
- a->archive.file_position += skipped;
- return (skipped);
+ return (__archive_read_filter_skip(a->filter, request));
}
int64_t
}
if (request == 0)
return (total_bytes_skipped);
+
/*
* If a client_skipper was provided, try that first.
*/
filter->fatal = 1;
return (bytes_skipped);
}
+ filter->bytes_consumed += bytes_skipped;
total_bytes_skipped += bytes_skipped;
request -= bytes_skipped;
filter->client_next = filter->client_buff;
/*
* How bidding works for filters:
- * * The bid manager reads the first block from the current source.
- * * It shows that block to each registered bidder.
+ * * The bid manager initializes the client-provided reader as the
+ * first filter.
+ * * It invokes the bidder for each registered filter with the
+ * current head filter.
+ * * The bidders can use archive_read_filter_ahead() to peek ahead
+ * at the incoming data to compose their bids.
* * The bid manager creates a new filter structure for the winning
* bidder and gives the winning bidder a chance to initialize it.
- * * The new filter becomes the top filter in the archive_read structure
- * and we repeat the process.
- * This ends only when no bidder provides a non-zero bid.
+ * * The new filter becomes the new top filter and we repeat the
+ * process.
+ * This ends only when no bidder provides a non-zero bid. Then
+ * we perform a similar dance with the registered format handlers.
*/
struct archive_read_filter_bidder {
/* Configuration data for the bidder. */
* corresponding bidder above.
*/
struct archive_read_filter {
+ int64_t bytes_consumed;
/* Essentially all filters will need these values, so
* just declare them here. */
struct archive_read_filter_bidder *bidder; /* My bidder. */
"Failed to clean up decompressor");
ret = ARCHIVE_FATAL;
}
+ state->valid = 0;
}
free(state->out_block);
off_t entry_padding;
char *strtab;
size_t strtab_size;
+ char read_global_header;
};
/*
ar = (struct ar*)(a->format->data);
- if (a->archive.file_position == 0) {
+ if (!ar->read_global_header) {
/*
* We are now at the beginning of the archive,
* so we need first consume the ar global header.
*/
__archive_read_consume(a, 8);
+ ar->read_global_header = 1;
/* Set a default format code for now. */
a->archive.archive_format = ARCHIVE_FORMAT_AR;
}
.Nm archive_errno ,
.Nm archive_error_string ,
.Nm archive_file_count ,
+.Nm archive_filter_code ,
+.Nm archive_filter_count ,
+.Nm archive_filter_name ,
.Nm archive_format ,
.Nm archive_format_name ,
+.Nm archive_position ,
.Nm archive_set_error
.Nd libarchive utility functions
.Sh SYNOPSIS
.Ft int
.Fn archive_file_count "struct archive *"
.Ft int
+.Fn archive_filter_code "struct archive *" "int"
+.Ft int
+.Fn archive_filter_count "struct archive *" "int"
+.Ft const char *
+.Fn archive_filter_name "struct archive *" "int"
+.Ft int
.Fn archive_format "struct archive *"
.Ft const char *
.Fn archive_format_name "struct archive *"
+.Ft int64_t
+.Fn archive_position "struct archive *" "int"
.Ft void
.Fo archive_set_error
.Fa "struct archive *"
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
-.Fn archive_read_open .
+Synonym for
+.Fn archive_filter_code(a, 0) .
.It Fn archive_compression_name
-Returns a text description of the current compression suitable for display.
+Synonym for
+.Fn archive_filter_name(a, 0) .
.It Fn archive_copy_error
Copies error information from one archive to another.
.It Fn archive_errno
.Xr archive_write_header
or
.Xr archive_read_next_header .
+.It Fn archive_filter_code
+Returns a numeric code identifying the indicated filter.
+See
+.Fn archive_filter_count
+for details of the numbering.
+.It Fn archive_filter_count
+Returns the number of filters in the current pipeline.
+For read archive handles, these filters are added automatically
+by the automatic format detection.
+For write archive handles, these filters are added by calls to the various
+.Fn archive_write_add_filter_XXX
+functions.
+Filters in the resulting pipeline are numbered so that filter 0
+is the filter closest to the format handler.
+As a convenience, functions that expect a filter number will
+accept -1 as a synonym for the highest-numbered filter.
+.Pp
+For example, when reading a uuencoded gzipped tar archive, there
+are three filters:
+filter 0 is the gunzip filter,
+filter 1 is the uudecode filter,
+and filter 2 is the pseudo-filter that wraps the archive read functions.
+In this case, requesting
+.Fn archive_position(a, -1)
+would be a synonym for
+.Fn archive_position(a, 2)
+which would return the number of bytes currently read from the archive, while
+.Fn archive_position(a, 1)
+would return the number of bytes after uudecoding, and
+.Fn archive_position(a, 0)
+would return the number of bytes after decompression.
+.It Fn archive_filter_name
+Returns a textual name identifying the indicated filter.
+See
+.Fn archive_filter_count
+for details of the numbering.
.It Fn archive_format
Returns a numeric code indicating the format of the current
archive entry.
These entries will have different format codes.
.It Fn archive_format_name
A textual description of the format of the current entry.
+.It Fn archive_position
+Returns the number of bytes read from or written to the indicated filter.
+In particular,
+.Fn archive_position(a, 0)
+returns the number of bytes read or written by the format handler, while
+.Fn archive_position(a, -1)
+returns the number of bytes read or written to the archive.
+See
+.Fn archive_filter_count
+for details of the numbering here.
.It Fn archive_set_error
Sets the numeric error code and error description that will be returned
by
int
archive_compression(struct archive *a)
{
- return (a->compression_code);
+ return archive_filter_code(a, 0);
}
const char *
archive_compression_name(struct archive *a)
{
- return (a->compression_name);
+ return archive_filter_name(a, 0);
}
int64_t
archive_position_compressed(struct archive *a)
{
- return (a->raw_position);
+ return archive_filter_bytes(a, -1);
}
/*
int64_t
archive_position_uncompressed(struct archive *a)
{
- return (a->file_position);
+ return archive_filter_bytes(a, 0);
}
void
#include "archive_entry.h"
#include "archive_private.h"
+int
+archive_filter_code(struct archive *a, int n)
+{
+ return ((a->vtable->archive_filter_code)(a, n));
+}
+
+int
+archive_filter_count(struct archive *a)
+{
+ return ((a->vtable->archive_filter_count)(a));
+}
+
+const char *
+archive_filter_name(struct archive *a, int n)
+{
+ return ((a->vtable->archive_filter_name)(a, n));
+}
+
+int64_t
+archive_filter_bytes(struct archive *a, int n)
+{
+ return ((a->vtable->archive_filter_bytes)(a, n));
+}
+
int
archive_write_close(struct archive *a)
{
/*-
- * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2003-2010 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
static struct archive_vtable *archive_write_vtable(void);
+static int _archive_filter_code(struct archive *, int);
+static const char *_archive_filter_name(struct archive *, int);
+static int64_t _archive_filter_bytes(struct archive *, int);
static int _archive_write_close(struct archive *);
static int _archive_write_free(struct archive *);
static int _archive_write_header(struct archive *, struct archive_entry *);
if (!inited) {
av.archive_close = _archive_write_close;
+ av.archive_filter_bytes = _archive_filter_bytes;
+ av.archive_filter_code = _archive_filter_code;
+ av.archive_filter_name = _archive_filter_name;
av.archive_free = _archive_write_free;
av.archive_write_header = _archive_write_header;
av.archive_write_finish_entry = _archive_write_finish_entry;
}
memset(nulls, 0, a->null_length);
a->nulls = nulls;
- /*
- * Set default compression, but don't set a default format.
- * Were we to set a default format here, we would force every
- * client to link in support for that format, even if they didn't
- * ever use it.
- */
- archive_write_set_compression_none(&a->archive);
return (&a->archive);
}
archive_write_set_compressor_options(struct archive *_a, const char *s)
{
struct archive_write *a = (struct archive_write *)_a;
+ struct archive_write_filter *filter;
char key[64], val[64];
int len, r;
int ret = ARCHIVE_OK;
if (s == NULL || *s == '\0')
return (ARCHIVE_OK);
- if (a->compressor.options == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Unsupported option ``%s''", s);
- /* This compressor does not support option. */
- return (ARCHIVE_WARN);
- }
-
- while ((len = __archive_parse_options(s, a->archive.compression_name,
- sizeof(key), key, sizeof(val), val)) > 0) {
- if (val[0] == '\0')
- r = a->compressor.options(a, key, NULL);
- else
- r = a->compressor.options(a, key, val);
- if (r == ARCHIVE_FATAL)
- return (r);
- if (r < ARCHIVE_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Unsupported option ``%s''", key);
- ret = ARCHIVE_WARN;
+ for (filter = a->filter_first; filter != NULL; filter = filter->next_filter) {
+ if (filter->options == NULL)
+ /* This filter does not have any options */
+ continue;
+ while ((len = __archive_parse_options(s,
+ a->archive.compression_name,
+ sizeof(key), key, sizeof(val), val)) > 0) {
+ if (val[0] == '\0')
+ r = filter->options(filter, key, NULL);
+ else
+ r = filter->options(filter, key, val);
+ if (r == ARCHIVE_FATAL)
+ return (r);
+ if (r < ARCHIVE_OK) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Unsupported option ``%s''", key);
+ ret = ARCHIVE_WARN;
+ }
+ s += len;
}
- s += len;
}
if (len < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
return (ARCHIVE_OK);
}
+/*
+ * Allocate and return the next filter structure.
+ */
+struct archive_write_filter *
+__archive_write_allocate_filter(struct archive *_a)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+ struct archive_write_filter *f;
+ __archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_allocate_filter");
+ f = calloc(1, sizeof(*f));
+ f->archive = _a;
+ if (a->filter_first == NULL)
+ a->filter_first = f;
+ else
+ a->filter_last->next_filter = f;
+ a->filter_last = f;
+ return f;
+}
+
+/*
+ * Write data to a particular filter.
+ */
+int
+__archive_write_filter(struct archive_write_filter *f,
+ const void *buff, size_t length)
+{
+ int r;
+ r = (f->write)(f, buff, length);
+ f->bytes_written += length;
+// fprintf(stdout, "__archive_write_filter(%s, %d) = %d\n", f->name, (int)length, r);
+ return (r);
+}
+
+/*
+ * Open a filter.
+ */
+int
+__archive_write_open_filter(struct archive_write_filter *f)
+{
+ if (f->open == NULL)
+ return (ARCHIVE_OK);
+ return (f->open)(f);
+}
+
+/*
+ * Close a filter.
+ */
+int
+__archive_write_close_filter(struct archive_write_filter *f)
+{
+ if (f->close == NULL)
+ return (ARCHIVE_OK);
+ return (f->close)(f);
+}
+
+int
+__archive_write_output(struct archive_write *a, const void *buff, size_t length)
+{
+// fprintf(stdout, "__archive_write_output(%d)\n", (int)length);
+ return (__archive_write_filter(a->filter_first, buff, length));
+}
+
+static int
+archive_write_client_open(struct archive_write_filter *f)
+{
+ struct archive_write *a = (struct archive_write *)f->archive;
+ if (a->client_opener == NULL)
+ return (ARCHIVE_OK);
+ return (a->client_opener(f->archive, f->data));
+}
+
+static int
+archive_write_client_write(struct archive_write_filter *f,
+ const void *_buff, size_t length)
+{
+ struct archive_write *a = (struct archive_write *)f->archive;
+ const char *buff = _buff;
+
+ while (length > 0) {
+ ssize_t written
+ = (a->client_writer(f->archive, f->data, buff, length));
+// fprintf(stdout, "__archive_write_client_write(%d): written=%d\n", (int)length, (int)written);
+ if (written < 0)
+ return ((int)written);
+ if (written == 0)
+ return (ARCHIVE_FATAL);
+ buff += written;
+ length -= written;
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_write_client_close(struct archive_write_filter *f)
+{
+ struct archive_write *a = (struct archive_write *)f->archive;
+ if (a->client_closer == NULL)
+ return (ARCHIVE_OK);
+ return (a->client_closer(f->archive, f->data));
+}
/*
* Open the archive using the current settings.
archive_close_callback *closer)
{
struct archive_write *a = (struct archive_write *)_a;
+ struct archive_write_filter *client_filter;
int ret;
__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;
+
+ if (a->filter_first == NULL)
+ archive_write_set_compression_none(_a);
+
a->client_writer = writer;
a->client_opener = opener;
a->client_closer = closer;
- ret = (a->compressor.init)(a);
+
+ client_filter = __archive_write_allocate_filter(_a);
+ client_filter->data = client_data;
+ client_filter->open = archive_write_client_open;
+ client_filter->write = archive_write_client_write;
+ client_filter->close = archive_write_client_close;
+
+ ret = __archive_write_open_filter(a->filter_first);
+
+ a->archive.state = ARCHIVE_STATE_HEADER;
+
if (a->format_init && ret == ARCHIVE_OK)
ret = (a->format_init)(a);
return (ret);
}
-
/*
* Close out the archive.
- *
- * Be careful: user might just call write_new and then write_finish.
- * Don't assume we actually wrote anything or performed any non-trivial
- * initialization.
*/
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, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_ANY, "archive_write_close");
+ /*
+ * It's perfectly reasonable to call close() as part of
+ * routine cleanup, even after an error, so we're a little
+ * tolerant of being called in odd states.
+ */
+ if (a->archive.state & ARCHIVE_STATE_FATAL)
+ return (ARCHIVE_FATAL);
+ archive_clear_error(&a->archive);
+ if (a->archive.state & (ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED))
+ return (ARCHIVE_OK);
+
+ __archive_check_magic(&a->archive,
+ ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+ "archive_write_close");
/* Finish the last entry. */
if (a->archive.state & ARCHIVE_STATE_DATA)
r = ((a->format_finish_entry)(a));
/* Finish off the archive. */
+ /* TODO: Rename format_finish to format_close, have
+ * format closers invoke compression close. */
if (a->format_finish != NULL) {
r1 = (a->format_finish)(a);
if (r1 < r)
r = r1;
}
- /* Release format 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->compressor.finish != NULL) {
- r1 = (a->compressor.finish)(a);
- if (r1 < r)
- r = r1;
- }
-
- /* Close out the client stream. */
- if (a->client_closer != NULL) {
- r1 = (a->client_closer)(&a->archive, a->client_data);
- if (r1 < r)
- r = r1;
- }
+ r1 = __archive_write_close_filter(a->filter_first);
+ if (r1 < r)
+ r = r1;
a->archive.state = ARCHIVE_STATE_CLOSED;
return (r);
}
+void
+__archive_write_filters_free(struct archive *_a)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+ int r = ARCHIVE_OK, r1;
+
+ while (a->filter_first != NULL) {
+ struct archive_write_filter *next
+ = a->filter_first->next_filter;
+ if (a->filter_first->free != NULL) {
+ r1 = (*a->filter_first->free)(a->filter_first);
+ if (r > r1)
+ r = r1;
+ }
+ free(a->filter_first);
+ a->filter_first = next;
+ }
+ a->filter_last = NULL;
+}
+
/*
* Destroy the archive structure.
+ *
+ * Be careful: user might just call write_new and then write_free.
+ * Don't assume we actually wrote anything or performed any non-trivial
+ * initialization.
*/
static int
_archive_write_free(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
- int r = ARCHIVE_OK;
+ int r = ARCHIVE_OK, r1;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_ANY, "archive_write_free");
- if (a->archive.state != ARCHIVE_STATE_CLOSED)
+ if (a->archive.state != ARCHIVE_STATE_CLOSED
+ && a->archive.state != ARCHIVE_STATE_FATAL)
r = archive_write_close(&a->archive);
+ /* Release format resources. */
+ /* TODO: Rename format_destroy to format_free */
+ if (a->format_destroy != NULL) {
+ r1 = (a->format_destroy)(a);
+ if (r1 < r)
+ r = r1;
+ }
+
+ __archive_write_filters_free(_a);
+
/* Release various dynamic buffers. */
free((void *)(uintptr_t)(const void *)a->nulls);
archive_string_free(&a->archive.error_string);
/* In particular, "retry" and "fatal" get returned immediately. */
ret = archive_write_finish_entry(&a->archive);
+ if (ret == ARCHIVE_FATAL) {
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+ }
if (ret < ARCHIVE_OK && ret != ARCHIVE_WARN)
return (ret);
/* Format and write header. */
r2 = ((a->format_write_header)(a, entry));
+ if (r2 == ARCHIVE_FATAL) {
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+ }
if (r2 < ret)
ret = r2;
archive_clear_error(&a->archive);
return ((a->format_write_data)(a, buff, s));
}
+
+static struct archive_write_filter *
+filter_lookup(struct archive *_a, int n)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+ struct archive_write_filter *f = a->filter_first;
+ if (n == -1)
+ return a->filter_last;
+ if (n < 0)
+ return NULL;
+ while (n > 0 && f != NULL) {
+ f = f->next_filter;
+ --n;
+ }
+ return f;
+}
+
+static int
+_archive_filter_code(struct archive *_a, int n)
+{
+ struct archive_write_filter *f = filter_lookup(_a, n);
+ return f == NULL ? -1 : f->code;
+}
+
+static const char *
+_archive_filter_name(struct archive *_a, int n)
+{
+ struct archive_write_filter *f = filter_lookup(_a, n);
+ return f == NULL ? NULL : f->name;
+}
+
+static int64_t
+_archive_filter_bytes(struct archive *_a, int n)
+{
+ struct archive_write_filter *f = filter_lookup(_a, n);
+ return f == NULL ? -1 : f->bytes_written;
+}
--- /dev/null
+/*-
+ * 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: head/lib/libarchive/archive_write_set_compression_bzip2.c 201091 2009-12-28 02:22:41Z kientzle $");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_bzip2(struct archive *a)
+{
+ __archive_write_filters_free(a);
+ return (archive_write_add_filter_bzip2(a));
+}
+#endif
+
+#ifndef HAVE_BZLIB_H
+int
+archive_write_add_filter_bzip2(struct archive *a)
+{
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "bzip2 compression not supported on this platform");
+ return (ARCHIVE_FATAL);
+}
+#else
+/* Don't compile this if we don't have bzlib. */
+
+struct private_data {
+ int compression_level;
+ bz_stream stream;
+ int64_t total_in;
+ char *compressed;
+ size_t compressed_buffer_size;
+};
+
+/*
+ * Yuck. bzlib.h is not const-correct, so I need this one bit
+ * of ugly hackery to convert a const * pointer to a non-const pointer.
+ */
+#define SET_NEXT_IN(st,src) \
+ (st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
+
+static int archive_compressor_bzip2_close(struct archive_write_filter *);
+static int archive_compressor_bzip2_free(struct archive_write_filter *);
+static int archive_compressor_bzip2_open(struct archive_write_filter *);
+static int archive_compressor_bzip2_options(struct archive_write_filter *,
+ const char *, const char *);
+static int archive_compressor_bzip2_write(struct archive_write_filter *,
+ const void *, size_t);
+static int drive_compressor(struct archive_write_filter *,
+ struct private_data *, int finishing);
+
+/*
+ * Add a bzip2 compression filter to this write handle.
+ */
+int
+archive_write_add_filter_bzip2(struct archive *_a)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+ struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+ struct private_data *data;
+
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
+
+ data = calloc(1, sizeof(*data));
+ if (data == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ data->compression_level = 9; /* default */
+
+ f->data = data;
+ f->options = &archive_compressor_bzip2_options;
+ f->close = &archive_compressor_bzip2_close;
+ f->free = &archive_compressor_bzip2_free;
+ f->open = &archive_compressor_bzip2_open;
+ f->code = ARCHIVE_COMPRESSION_BZIP2;
+ f->name = "bzip2";
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_bzip2_open(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret;
+
+ ret = __archive_write_open_filter(f->next_filter);
+ if (ret != 0)
+ return (ret);
+
+ // TODO: Find a better way to size this. (Maybe look at the
+ // block size expected by the following filter?)
+ if (data->compressed == NULL) {
+ data->compressed_buffer_size = 65536;
+ data->compressed
+ = (char *)malloc(data->compressed_buffer_size);
+ if (data->compressed == NULL) {
+ archive_set_error(f->archive, ENOMEM,
+ "Can't allocate data for compression buffer");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ memset(&data->stream, 0, sizeof(data->stream));
+ data->stream.next_out = data->compressed;
+ data->stream.avail_out = data->compressed_buffer_size;
+ f->write = archive_compressor_bzip2_write;
+
+ /* Initialize compression library */
+ ret = BZ2_bzCompressInit(&(data->stream),
+ data->compression_level, 0, 30);
+ if (ret == BZ_OK) {
+ f->data = data;
+ return (ARCHIVE_OK);
+ }
+
+ /* Library setup failed: clean up. */
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library");
+
+ /* Override the error message if we know what really went wrong. */
+ switch (ret) {
+ case BZ_PARAM_ERROR:
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "invalid setup parameter");
+ break;
+ case BZ_MEM_ERROR:
+ archive_set_error(f->archive, ENOMEM,
+ "Internal error initializing compression library: "
+ "out of memory");
+ break;
+ case BZ_CONFIG_ERROR:
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "mis-compiled library");
+ break;
+ }
+
+ return (ARCHIVE_FATAL);
+
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_compressor_bzip2_options(struct archive_write_filter *f,
+ const char *key, const char *value)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ if (strcmp(key, "compression-level") == 0) {
+ if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+ value[1] != '\0')
+ return (ARCHIVE_WARN);
+ data->compression_level = value[0] - '0';
+ /* Make '0' be a synonym for '1'. */
+ /* This way, bzip2 compressor supports the same 0..9
+ * range of levels as gzip. */
+ if (data->compression_level < 1)
+ data->compression_level = 1;
+ return (ARCHIVE_OK);
+ }
+
+ return (ARCHIVE_WARN);
+}
+
+/*
+ * Write data to the compressed stream.
+ *
+ * Returns ARCHIVE_OK if all data written, error otherwise.
+ */
+static int
+archive_compressor_bzip2_write(struct archive_write_filter *f,
+ const void *buff, size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ /* Update statistics */
+ data->total_in += length;
+
+ /* Compress input data to output buffer */
+ SET_NEXT_IN(data, buff);
+ data->stream.avail_in = length;
+ if (drive_compressor(f, data, 0))
+ return (ARCHIVE_FATAL);
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression.
+ */
+static int
+archive_compressor_bzip2_close(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ ssize_t bytes_written;
+ int ret;
+
+ if (data == NULL)
+ return (ARCHIVE_OK);
+
+ /* Finish compression cycle. */
+ ret = drive_compressor(f, data, 1);
+ if (ret == ARCHIVE_OK) {
+ /* Write the last block */
+ bytes_written = __archive_write_filter(f->next_filter,
+ data->compressed,
+ data->compressed_buffer_size - data->stream.avail_out);
+ if (bytes_written <= 0)
+ ret = ARCHIVE_FATAL;
+ }
+
+ switch (BZ2_bzCompressEnd(&(data->stream))) {
+ case BZ_OK:
+ break;
+ default:
+ archive_set_error(f->archive, ARCHIVE_ERRNO_PROGRAMMER,
+ "Failed to clean up compressor");
+ ret = ARCHIVE_FATAL;
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_compressor_bzip2_free(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ free(data->compressed);
+ free(data);
+ f->data = NULL;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Utility function to push input data through compressor, writing
+ * full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive_write_filter *f,
+ struct private_data *data, int finishing)
+{
+ ssize_t bytes_written;
+ int ret;
+
+ for (;;) {
+ if (data->stream.avail_out == 0) {
+ bytes_written = __archive_write_filter(f->next_filter,
+ data->compressed,
+ data->compressed_buffer_size);
+ if (bytes_written <= 0) {
+ /* TODO: Handle this write failure */
+ return (ARCHIVE_FATAL);
+ } else if ((size_t)bytes_written < data->compressed_buffer_size) {
+ /* Short write: Move remainder to
+ * front and keep filling */
+ memmove(data->compressed,
+ data->compressed + bytes_written,
+ data->compressed_buffer_size - bytes_written);
+ }
+
+ data->stream.next_out = data->compressed +
+ data->compressed_buffer_size - bytes_written;
+ data->stream.avail_out = bytes_written;
+ }
+
+ /* If there's nothing to do, we're done. */
+ if (!finishing && data->stream.avail_in == 0)
+ return (ARCHIVE_OK);
+
+ ret = BZ2_bzCompress(&(data->stream),
+ finishing ? BZ_FINISH : BZ_RUN);
+
+ switch (ret) {
+ case BZ_RUN_OK:
+ /* In non-finishing case, did compressor
+ * consume everything? */
+ if (!finishing && data->stream.avail_in == 0)
+ return (ARCHIVE_OK);
+ break;
+ case BZ_FINISH_OK: /* Finishing: There's more work to do */
+ break;
+ case BZ_STREAM_END: /* Finishing: all done */
+ /* Only occurs in finishing case */
+ return (ARCHIVE_OK);
+ default:
+ /* Any other return value indicates an error */
+ archive_set_error(f->archive,
+ ARCHIVE_ERRNO_PROGRAMMER,
+ "Bzip2 compression failed;"
+ " BZ2_bzCompress() returned %d",
+ ret);
+ return (ARCHIVE_FATAL);
+ }
+ }
+}
+
+#endif /* HAVE_BZLIB_H */
size_t compressed_offset;
};
-static int archive_compressor_compress_finish(struct archive_write *);
-static int archive_compressor_compress_init(struct archive_write *);
-static int archive_compressor_compress_write(struct archive_write *,
+static int archive_compressor_compress_open(struct archive_write_filter *);
+static int archive_compressor_compress_write(struct archive_write_filter *,
const void *, size_t);
+static int archive_compressor_compress_close(struct archive_write_filter *);
+static int archive_compressor_compress_free(struct archive_write_filter *);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_compress(struct archive *a)
+{
+ __archive_write_filters_free(a);
+ return (archive_write_add_filter_compress(a));
+}
+#endif
/*
- * Allocate, initialize and return a archive object.
+ * Add a compress filter to this write handle.
*/
int
-archive_write_set_compression_compress(struct archive *_a)
+archive_write_add_filter_compress(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
+ struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_compress");
- a->compressor.init = &archive_compressor_compress_init;
- a->archive.compression_code = ARCHIVE_COMPRESSION_COMPRESS;
- a->archive.compression_name = "compress";
+ f->open = &archive_compressor_compress_open;
+ f->code = ARCHIVE_COMPRESSION_COMPRESS;
+ f->name = "compress";
return (ARCHIVE_OK);
}
* Setup callback.
*/
static int
-archive_compressor_compress_init(struct archive_write *a)
+archive_compressor_compress_open(struct archive_write_filter *f)
{
int ret;
struct private_data *state;
- a->archive.compression_code = ARCHIVE_COMPRESSION_COMPRESS;
- a->archive.compression_name = "compress";
-
- if (a->bytes_per_block < 4) {
- archive_set_error(&a->archive, EINVAL,
- "Can't write Compress header as single block");
- return (ARCHIVE_FATAL);
- }
+ f->code = ARCHIVE_COMPRESSION_COMPRESS;
+ f->name = "compress";
- if (a->client_opener != NULL) {
- ret = (a->client_opener)(&a->archive, a->client_data);
- if (ret != ARCHIVE_OK)
- return (ret);
- }
+ ret = __archive_write_open_filter(f->next_filter);
+ if (ret != ARCHIVE_OK)
+ return (ret);
- state = (struct private_data *)malloc(sizeof(*state));
+ state = (struct private_data *)calloc(1, sizeof(*state));
if (state == NULL) {
- archive_set_error(&a->archive, ENOMEM,
+ archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression");
return (ARCHIVE_FATAL);
}
- memset(state, 0, sizeof(*state));
- state->compressed_buffer_size = a->bytes_per_block;
+ state->compressed_buffer_size = 65536;
state->compressed = malloc(state->compressed_buffer_size);
if (state->compressed == NULL) {
- archive_set_error(&a->archive, ENOMEM,
+ archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression buffer");
free(state);
return (ARCHIVE_FATAL);
}
- a->compressor.write = archive_compressor_compress_write;
- a->compressor.finish = archive_compressor_compress_finish;
+ f->write = archive_compressor_compress_write;
+ f->close = archive_compressor_compress_close;
+ f->free = archive_compressor_compress_free;
state->max_maxcode = 0x10000; /* Should NEVER generate this code. */
state->in_count = 0; /* Length of input. */
state->compressed[2] = 0x90; /* Block mode, 16bit max */
state->compressed_offset = 3;
- a->compressor.data = state;
+ f->data = state;
return (0);
}
{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
static int
-output_byte(struct archive_write *a, unsigned char c)
+output_byte(struct archive_write_filter *f, unsigned char c)
{
- struct private_data *state = a->compressor.data;
+ struct private_data *state = f->data;
ssize_t bytes_written;
state->compressed[state->compressed_offset++] = c;
++state->out_count;
if (state->compressed_buffer_size == state->compressed_offset) {
- bytes_written = (a->client_writer)(&a->archive,
- a->client_data,
+ bytes_written = __archive_write_filter(f->next_filter,
state->compressed, state->compressed_buffer_size);
if (bytes_written <= 0)
return ARCHIVE_FATAL;
- a->archive.raw_position += bytes_written;
state->compressed_offset = 0;
}
}
static int
-output_code(struct archive_write *a, int ocode)
+output_code(struct archive_write_filter *f, int ocode)
{
- struct private_data *state = a->compressor.data;
+ struct private_data *state = f->data;
int bits, ret, clear_flg, bit_offset;
clear_flg = ocode == CLEAR;
*/
bit_offset = state->bit_offset % 8;
state->bit_buf |= (ocode << bit_offset) & 0xff;
- output_byte(a, state->bit_buf);
+ output_byte(f, state->bit_buf);
bits = state->code_len - (8 - bit_offset);
ocode >>= 8 - bit_offset;
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
if (bits >= 8) {
- output_byte(a, ocode & 0xff);
+ output_byte(f, ocode & 0xff);
ocode >>= 8;
bits -= 8;
}
*/
if (state->bit_offset > 0) {
while (state->bit_offset < state->code_len * 8) {
- ret = output_byte(a, state->bit_buf);
+ ret = output_byte(f, state->bit_buf);
if (ret != ARCHIVE_OK)
return ret;
state->bit_offset += 8;
}
static int
-output_flush(struct archive_write *a)
+output_flush(struct archive_write_filter *f)
{
- struct private_data *state = a->compressor.data;
+ struct private_data *state = f->data;
int ret;
/* At EOF, write the rest of the buffer. */
if (state->bit_offset % 8) {
state->code_len = (state->bit_offset % 8 + 7) / 8;
- ret = output_byte(a, state->bit_buf);
+ ret = output_byte(f, state->bit_buf);
if (ret != ARCHIVE_OK)
return ret;
}
* Write data to the compressed stream.
*/
static int
-archive_compressor_compress_write(struct archive_write *a, const void *buff,
- size_t length)
+archive_compressor_compress_write(struct archive_write_filter *f,
+ const void *buff, size_t length)
{
- struct private_data *state;
+ struct private_data *state = (struct private_data *)f->data;
int i;
int ratio;
int c, disp, ret;
const unsigned char *bp;
- state = (struct private_data *)a->compressor.data;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- return (ARCHIVE_FATAL);
- }
-
if (length == 0)
return ARCHIVE_OK;
disp = 1;
else
disp = HSIZE - i;
- probe:
+ probe:
if ((i -= disp) < 0)
i += HSIZE;
}
if (state->hashtab[i] >= 0)
goto probe;
- nomatch:
- ret = output_code(a, state->cur_code);
+ nomatch:
+ ret = output_code(f, state->cur_code);
if (ret != ARCHIVE_OK)
return ret;
state->cur_code = c;
state->compress_ratio = 0;
memset(state->hashtab, 0xff, sizeof(state->hashtab));
state->first_free = FIRST;
- ret = output_code(a, CLEAR);
+ ret = output_code(f, CLEAR);
if (ret != ARCHIVE_OK)
return ret;
}
* Finish the compression...
*/
static int
-archive_compressor_compress_finish(struct archive_write *a)
+archive_compressor_compress_close(struct archive_write_filter *f)
{
- ssize_t block_length, target_block_length, bytes_written;
+ struct private_data *state = (struct private_data *)f->data;
int ret;
- struct private_data *state;
- size_t tocopy;
-
- state = (struct private_data *)a->compressor.data;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
-
- /* By default, always pad the uncompressed data. */
- if (a->pad_uncompressed) {
- while (state->in_count % a->bytes_per_block != 0) {
- tocopy = a->bytes_per_block -
- (state->in_count % a->bytes_per_block);
- if (tocopy > a->null_length)
- tocopy = a->null_length;
- ret = archive_compressor_compress_write(a, a->nulls,
- tocopy);
- if (ret != ARCHIVE_OK)
- goto cleanup;
- }
- }
- ret = output_code(a, state->cur_code);
+ ret = output_code(f, state->cur_code);
if (ret != ARCHIVE_OK)
goto cleanup;
- ret = output_flush(a);
+ ret = output_flush(f);
if (ret != ARCHIVE_OK)
goto cleanup;
- /* Optionally, pad the final compressed block. */
- block_length = state->compressed_offset;
-
- /* Tricky calculation to determine size of last block. */
- if (a->bytes_in_last_block <= 0)
- /* Default or Zero: pad to full block */
- target_block_length = a->bytes_per_block;
- else
- /* Round length to next multiple of bytes_in_last_block. */
- target_block_length = a->bytes_in_last_block *
- ( (block_length + a->bytes_in_last_block - 1) /
- a->bytes_in_last_block);
- if (target_block_length > a->bytes_per_block)
- target_block_length = a->bytes_per_block;
- if (block_length < target_block_length) {
- memset(state->compressed + state->compressed_offset, 0,
- target_block_length - block_length);
- block_length = target_block_length;
- }
-
/* Write the last block */
- bytes_written = (a->client_writer)(&a->archive, a->client_data,
- state->compressed, block_length);
- if (bytes_written <= 0)
- ret = ARCHIVE_FATAL;
- else
- a->archive.raw_position += bytes_written;
-
+ ret = __archive_write_filter(f->next_filter,
+ state->compressed, state->compressed_offset);
cleanup:
free(state->compressed);
free(state);
return (ret);
}
+
+static int
+archive_compressor_compress_free(struct archive_write_filter *f)
+{
+ (void)f; /* UNUSED */
+ return (ARCHIVE_OK);
+}
--- /dev/null
+/*-
+ * 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: head/lib/libarchive/archive_write_set_compression_gzip.c 201081 2009-12-28 02:04:42Z kientzle $");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <time.h>
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_gzip(struct archive *a)
+{
+ __archive_write_filters_free(a);
+ return (archive_write_add_filter_gzip(a));
+}
+#endif
+
+#ifndef HAVE_ZLIB_H
+int
+archive_write_add_filter_gzip(struct archive *a)
+{
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "gzip compression not supported on this platform");
+ return (ARCHIVE_FATAL);
+}
+#else
+/* Don't compile this if we don't have zlib. */
+
+struct private_data {
+ int compression_level;
+ z_stream stream;
+ int64_t total_in;
+ unsigned char *compressed;
+ size_t compressed_buffer_size;
+ unsigned long crc;
+};
+
+/*
+ * Yuck. zlib.h is not const-correct, so I need this one bit
+ * of ugly hackery to convert a const * pointer to a non-const pointer.
+ */
+#define SET_NEXT_IN(st,src) \
+ (st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src)
+
+static int archive_compressor_gzip_options(struct archive_write_filter *,
+ const char *, const char *);
+static int archive_compressor_gzip_open(struct archive_write_filter *);
+static int archive_compressor_gzip_write(struct archive_write_filter *,
+ const void *, size_t);
+static int archive_compressor_gzip_close(struct archive_write_filter *);
+static int archive_compressor_gzip_free(struct archive_write_filter *);
+static int drive_compressor(struct archive_write_filter *,
+ struct private_data *, int finishing);
+
+
+/*
+ * Add a gzip compression filter to this write handle.
+ */
+int
+archive_write_add_filter_gzip(struct archive *_a)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+ struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+ struct private_data *data;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
+
+ data = calloc(1, sizeof(*data));
+ if (data == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ f->data = data;
+ data->compression_level = Z_DEFAULT_COMPRESSION;
+ f->open = &archive_compressor_gzip_open;
+ f->options = &archive_compressor_gzip_options;
+ f->close = &archive_compressor_gzip_close;
+ f->free = &archive_compressor_gzip_free;
+ f->code = ARCHIVE_COMPRESSION_GZIP;
+ f->name = "gzip";
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_gzip_open(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret;
+ time_t t;
+
+ ret = __archive_write_open_filter(f->next_filter);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+
+ if (data->compressed == NULL) {
+ data->compressed_buffer_size = 65536;
+ data->compressed
+ = (unsigned char *)malloc(data->compressed_buffer_size);
+ if (data->compressed == NULL) {
+ archive_set_error(f->archive, ENOMEM,
+ "Can't allocate data for compression buffer");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ data->crc = crc32(0L, NULL, 0);
+ data->stream.next_out = data->compressed;
+ data->stream.avail_out = data->compressed_buffer_size;
+
+ /* Prime output buffer with a gzip header. */
+ t = time(NULL);
+ data->compressed[0] = 0x1f; /* GZip signature bytes */
+ data->compressed[1] = 0x8b;
+ data->compressed[2] = 0x08; /* "Deflate" compression */
+ data->compressed[3] = 0; /* No options */
+ data->compressed[4] = (t)&0xff; /* Timestamp */
+ data->compressed[5] = (t>>8)&0xff;
+ data->compressed[6] = (t>>16)&0xff;
+ data->compressed[7] = (t>>24)&0xff;
+ data->compressed[8] = 0; /* No deflate options */
+ data->compressed[9] = 3; /* OS=Unix */
+ data->stream.next_out += 10;
+ data->stream.avail_out -= 10;
+
+ f->write = archive_compressor_gzip_write;
+
+ /* Initialize compression library. */
+ ret = deflateInit2(&(data->stream),
+ data->compression_level,
+ Z_DEFLATED,
+ -15 /* < 0 to suppress zlib header */,
+ 8,
+ Z_DEFAULT_STRATEGY);
+
+ if (ret == Z_OK) {
+ f->data = data;
+ return (ARCHIVE_OK);
+ }
+
+ /* Library setup failed: clean up. */
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Internal error "
+ "initializing compression library");
+
+ /* Override the error message if we know what really went wrong. */
+ switch (ret) {
+ case Z_STREAM_ERROR:
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing "
+ "compression library: invalid setup parameter");
+ break;
+ case Z_MEM_ERROR:
+ archive_set_error(f->archive, ENOMEM, "Internal error initializing "
+ "compression library");
+ break;
+ case Z_VERSION_ERROR:
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing "
+ "compression library: invalid library version");
+ break;
+ }
+
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
+ const char *value)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ if (strcmp(key, "compression-level") == 0) {
+ if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+ value[1] != '\0')
+ return (ARCHIVE_WARN);
+ data->compression_level = value[0] - '0';
+ return (ARCHIVE_OK);
+ }
+ return (ARCHIVE_WARN);
+}
+
+/*
+ * Write data to the compressed stream.
+ */
+static int
+archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
+ size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret;
+
+ /* Update statistics */
+ data->crc = crc32(data->crc, (const Bytef *)buff, length);
+ data->total_in += length;
+
+ /* Compress input data to output buffer */
+ SET_NEXT_IN(data, buff);
+ data->stream.avail_in = length;
+ if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)
+ return (ret);
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_compressor_gzip_close(struct archive_write_filter *f)
+{
+ unsigned char trailer[8];
+ struct private_data *data = (struct private_data *)f->data;
+ int ret;
+
+ ret = 0;
+ if (data != NULL) {
+ /* Finish compression cycle */
+ ret = drive_compressor(f, data, 1);
+ if (ret != ARCHIVE_OK)
+ goto cleanup;
+
+ /* Write the last compressed data. */
+ ret = __archive_write_filter(f->next_filter,
+ data->compressed,
+ data->compressed_buffer_size - data->stream.avail_out);
+ if (ret != ARCHIVE_OK) {
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+
+ /* Build and write out 8-byte trailer. */
+ trailer[0] = (data->crc)&0xff;
+ trailer[1] = (data->crc >> 8)&0xff;
+ trailer[2] = (data->crc >> 16)&0xff;
+ trailer[3] = (data->crc >> 24)&0xff;
+ trailer[4] = (data->total_in)&0xff;
+ trailer[5] = (data->total_in >> 8)&0xff;
+ trailer[6] = (data->total_in >> 16)&0xff;
+ trailer[7] = (data->total_in >> 24)&0xff;
+ ret = __archive_write_filter(f->next_filter, trailer, 8);
+ if (ret != ARCHIVE_OK)
+ ret = ARCHIVE_FATAL;
+
+ cleanup:
+ switch (deflateEnd(&(data->stream))) {
+ case Z_OK:
+ break;
+ default:
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "Failed to clean up compressor");
+ ret = ARCHIVE_FATAL;
+ }
+ }
+ return (ret);
+}
+
+static int
+archive_compressor_gzip_free(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ free(data->compressed);
+ free(data);
+ f->data = NULL;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Utility function to push input data through compressor,
+ * writing full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive_write_filter *f,
+ struct private_data *data, int finishing)
+{
+ int ret;
+
+ for (;;) {
+ if (data->stream.avail_out == 0) {
+ ret = __archive_write_filter(f->next_filter,
+ data->compressed,
+ data->compressed_buffer_size);
+ if (ret != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ data->stream.next_out = data->compressed;
+ data->stream.avail_out = data->compressed_buffer_size;
+ }
+
+ /* If there's nothing to do, we're done. */
+ if (!finishing && data->stream.avail_in == 0)
+ return (ARCHIVE_OK);
+
+ ret = deflate(&(data->stream),
+ finishing ? Z_FINISH : Z_NO_FLUSH );
+
+ switch (ret) {
+ case Z_OK:
+ /* In non-finishing case, check if compressor
+ * consumed everything */
+ if (!finishing && data->stream.avail_in == 0)
+ return (ARCHIVE_OK);
+ /* In finishing case, this return always means
+ * there's more work */
+ break;
+ case Z_STREAM_END:
+ /* This return can only occur in finishing case. */
+ return (ARCHIVE_OK);
+ default:
+ /* Any other return value indicates an error. */
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "GZip compression failed:"
+ " deflate() call returned status %d",
+ ret);
+ return (ARCHIVE_FATAL);
+ }
+ }
+}
+
+#endif /* HAVE_ZLIB_H */
#include "archive_private.h"
#include "archive_write_private.h"
-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 *,
+
+int
+archive_write_set_compression_none(struct archive *a)
+{
+ __archive_write_filters_free(a);
+ return (archive_write_add_filter_none(a));
+}
+
+
+static int archive_compressor_none_open(struct archive_write_filter *);
+static int archive_compressor_none_write(struct archive_write_filter *,
const void *, size_t);
+static int archive_compressor_none_close(struct archive_write_filter *);
+static int archive_compressor_none_free(struct archive_write_filter *);
struct archive_none {
char *buffer;
ssize_t avail; /* Free space left in buffer */
};
+/*
+ * TODO: A little refactoring will turn this into a true no-op.
+ */
int
-archive_write_set_compression_none(struct archive *_a)
+archive_write_add_filter_none(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
+ struct archive_write_filter *f = __archive_write_allocate_filter(_a);
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_none");
- a->compressor.init = &archive_compressor_none_init;
- return (0);
+ f->open = &archive_compressor_none_open;
+ f->code = ARCHIVE_COMPRESSION_NONE;
+ f->name = "none";
+
+ return (ARCHIVE_OK);
}
/*
* Setup callback.
*/
static int
-archive_compressor_none_init(struct archive_write *a)
+archive_compressor_none_open(struct archive_write_filter *f)
{
int ret;
struct archive_none *state;
- a->archive.compression_code = ARCHIVE_COMPRESSION_NONE;
- a->archive.compression_name = "none";
+ ret = __archive_write_open_filter(f->next_filter);
+ if (ret != 0)
+ return (ret);
- if (a->client_opener != NULL) {
- ret = (a->client_opener)(&a->archive, a->client_data);
- if (ret != 0)
- return (ret);
- }
+ f->bytes_per_block = archive_write_get_bytes_per_block(f->archive);
+ f->bytes_in_last_block = archive_write_get_bytes_in_last_block(f->archive);
- state = (struct archive_none *)malloc(sizeof(*state));
+ state = (struct archive_none *)calloc(1, sizeof(*state));
if (state == NULL) {
- archive_set_error(&a->archive, ENOMEM,
+ archive_set_error(f->archive, ENOMEM,
"Can't allocate data for output buffering");
return (ARCHIVE_FATAL);
}
- memset(state, 0, sizeof(*state));
- state->buffer_size = a->bytes_per_block;
+ state->buffer_size = f->bytes_per_block;
if (state->buffer_size != 0) {
state->buffer = (char *)malloc(state->buffer_size);
if (state->buffer == NULL) {
- archive_set_error(&a->archive, ENOMEM,
+ archive_set_error(f->archive, ENOMEM,
"Can't allocate output buffer");
free(state);
return (ARCHIVE_FATAL);
state->next = state->buffer;
state->avail = state->buffer_size;
- a->compressor.data = state;
- a->compressor.write = archive_compressor_none_write;
- a->compressor.finish = archive_compressor_none_finish;
+ f->data = state;
+ f->write = archive_compressor_none_write;
+ f->close = archive_compressor_none_close;
+ f->free = archive_compressor_none_free;
return (ARCHIVE_OK);
}
* Write data to the stream.
*/
static int
-archive_compressor_none_write(struct archive_write *a, const void *vbuff,
- size_t length)
+archive_compressor_none_write(struct archive_write_filter *f,
+ const void *vbuff, size_t length)
{
+ struct archive_none *state = (struct archive_none *)f->data;
const char *buff;
ssize_t remaining, to_copy;
- ssize_t bytes_written;
- struct archive_none *state;
-
- state = (struct archive_none *)a->compressor.data;
- buff = (const char *)vbuff;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- return (ARCHIVE_FATAL);
- }
-
- remaining = length;
+ int ret;
/*
* If there is no buffer for blocking, just pass the data
* particular, this supports "no write delay" operation for
* special applications. Just set the block size to zero.
*/
- if (state->buffer_size == 0) {
- while (remaining > 0) {
- bytes_written = (a->client_writer)(&a->archive,
- a->client_data, buff, remaining);
- if (bytes_written <= 0)
- return (ARCHIVE_FATAL);
- a->archive.raw_position += bytes_written;
- remaining -= bytes_written;
- buff += bytes_written;
- }
- a->archive.file_position += length;
- return (ARCHIVE_OK);
- }
+ if (state->buffer_size == 0)
+ return (__archive_write_filter(f->next_filter,
+ vbuff, length));
+
+ buff = (const char *)vbuff;
+ remaining = length;
/* If the copy buffer isn't empty, try to fill it. */
if (state->avail < state->buffer_size) {
remaining -= to_copy;
/* ... if it's full, write it out. */
if (state->avail == 0) {
- bytes_written = (a->client_writer)(&a->archive,
- a->client_data, state->buffer, state->buffer_size);
- if (bytes_written <= 0)
+ ret = __archive_write_filter(f->next_filter,
+ state->buffer, state->buffer_size);
+ if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- /* XXX TODO: if bytes_written < state->buffer_size */
- a->archive.raw_position += bytes_written;
state->next = state->buffer;
state->avail = state->buffer_size;
}
}
+ /* Write out full blocks directly to client. */
while (remaining > state->buffer_size) {
- /* Write out full blocks directly to client. */
- bytes_written = (a->client_writer)(&a->archive,
- a->client_data, buff, state->buffer_size);
- if (bytes_written <= 0)
+ ret = __archive_write_filter(f->next_filter,
+ buff, state->buffer_size);
+ if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- a->archive.raw_position += bytes_written;
- buff += bytes_written;
- remaining -= bytes_written;
+ buff += state->buffer_size;
+ remaining -= state->buffer_size;
}
if (remaining > 0) {
state->avail -= remaining;
}
- a->archive.file_position += length;
return (ARCHIVE_OK);
}
* Finish the compression.
*/
static int
-archive_compressor_none_finish(struct archive_write *a)
+archive_compressor_none_close(struct archive_write_filter *f)
{
+ struct archive_none *state = (struct archive_none *)f->data;
ssize_t block_length;
ssize_t target_block_length;
- ssize_t bytes_written;
int ret;
- struct archive_none *state;
- state = (struct archive_none *)a->compressor.data;
ret = ARCHIVE_OK;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- return (ARCHIVE_FATAL);
- }
/* If there's pending data, pad and write the last block */
if (state->next != state->buffer) {
block_length = state->buffer_size - state->avail;
/* Tricky calculation to determine size of last block */
- if (a->bytes_in_last_block <= 0)
+ if (f->bytes_in_last_block <= 0)
/* Default or Zero: pad to full block */
- target_block_length = a->bytes_per_block;
+ target_block_length = f->bytes_per_block;
else
/* Round to next multiple of bytes_in_last_block. */
- target_block_length = a->bytes_in_last_block *
- ( (block_length + a->bytes_in_last_block - 1) /
- a->bytes_in_last_block);
- if (target_block_length > a->bytes_per_block)
- target_block_length = a->bytes_per_block;
+ target_block_length = f->bytes_in_last_block *
+ ( (block_length + f->bytes_in_last_block - 1) /
+ f->bytes_in_last_block);
+ if (target_block_length > f->bytes_per_block)
+ target_block_length = f->bytes_per_block;
if (block_length < target_block_length) {
memset(state->next, 0,
target_block_length - block_length);
block_length = target_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->archive.raw_position += bytes_written;
- ret = ARCHIVE_OK;
- }
+ ret = __archive_write_filter(f->next_filter,
+ state->buffer, block_length);
}
if (state->buffer)
free(state->buffer);
free(state);
- a->compressor.data = NULL;
+ f->data = NULL;
return (ret);
}
+
+static int
+archive_compressor_none_free(struct archive_write_filter *f)
+{
+ (void)f; /* UNUSED */
+ return (ARCHIVE_OK);
+}
--- /dev/null
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger
+ * 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: head/lib/libarchive/archive_write_set_compression_program.c 201104 2009-12-28 03:14:30Z kientzle $");
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_program(struct archive *a, const char *cmd)
+{
+ __archive_write_filters_free(a);
+ return (archive_write_add_filter_program(a, cmd));
+}
+#endif
+
+/* This capability is only available on POSIX systems. */
+#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
+ !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && (!defined(_WIN32) || defined(__CYGWIN__))
+
+/*
+ * On non-Posix systems, allow the program to build, but choke if
+ * this function is actually invoked.
+ */
+int
+archive_write_add_filter_program(struct archive *_a, const char *cmd)
+{
+ archive_set_error(_a, -1,
+ "External compression programs not supported on this platform");
+ return (ARCHIVE_FATAL);
+}
+
+#else
+
+#include "filter_fork.h"
+
+struct private_data {
+ char *cmd;
+ char *description;
+ pid_t child;
+ int child_stdin, child_stdout;
+
+ char *child_buf;
+ size_t child_buf_len, child_buf_avail;
+};
+
+static int archive_compressor_program_open(struct archive_write_filter *);
+static int archive_compressor_program_write(struct archive_write_filter *,
+ const void *, size_t);
+static int archive_compressor_program_close(struct archive_write_filter *);
+static int archive_compressor_program_free(struct archive_write_filter *);
+
+/*
+ * Add a filter to this write handle that passes all data through an
+ * external program.
+ */
+int
+archive_write_add_filter_program(struct archive *_a, const char *cmd)
+{
+ struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+ struct archive_write *a = (struct archive_write *)_a;
+ struct private_data *data;
+ static const char *prefix = "Program: ";
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_compression_program");
+ data = calloc(1, sizeof(*data));
+ if (data == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ data->cmd = strdup(cmd);
+ data->description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
+ strcpy(data->description, prefix);
+ strcat(data->description, cmd);
+
+ f->name = data->description;
+ f->data = data;
+ f->open = &archive_compressor_program_open;
+ f->code = ARCHIVE_COMPRESSION_PROGRAM;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_program_open(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret;
+
+ ret = __archive_write_open_filter(f->next_filter);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+
+ if (data->child_buf == NULL) {
+ data->child_buf_len = 65536;
+ data->child_buf_avail = 0;
+ data->child_buf = malloc(data->child_buf_len);
+
+ if (data->child_buf == NULL) {
+ archive_set_error(f->archive, ENOMEM,
+ "Can't allocate compression buffer");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ if ((data->child = __archive_create_child(data->cmd,
+ &data->child_stdin, &data->child_stdout)) == -1) {
+ archive_set_error(f->archive, EINVAL,
+ "Can't initialise filter");
+ return (ARCHIVE_FATAL);
+ }
+
+ f->write = archive_compressor_program_write;
+ f->close = archive_compressor_program_close;
+ f->free = archive_compressor_program_free;
+ return (0);
+}
+
+static ssize_t
+child_write(struct archive_write_filter *f, const char *buf, size_t buf_len)
+{
+ struct private_data *data = f->data;
+ ssize_t ret;
+
+ if (data->child_stdin == -1)
+ return (-1);
+
+ if (buf_len == 0)
+ return (-1);
+
+restart_write:
+ do {
+ ret = write(data->child_stdin, buf, buf_len);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret > 0)
+ return (ret);
+ if (ret == 0) {
+ close(data->child_stdin);
+ data->child_stdin = -1;
+ fcntl(data->child_stdout, F_SETFL, 0);
+ return (0);
+ }
+ if (ret == -1 && errno != EAGAIN)
+ return (-1);
+
+ if (data->child_stdout == -1) {
+ fcntl(data->child_stdin, F_SETFL, 0);
+ __archive_check_child(data->child_stdin, data->child_stdout);
+ goto restart_write;
+ }
+
+ do {
+ ret = read(data->child_stdout,
+ data->child_buf + data->child_buf_avail,
+ data->child_buf_len - data->child_buf_avail);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == 0 || (ret == -1 && errno == EPIPE)) {
+ close(data->child_stdout);
+ data->child_stdout = -1;
+ fcntl(data->child_stdin, F_SETFL, 0);
+ goto restart_write;
+ }
+ if (ret == -1 && errno == EAGAIN) {
+ __archive_check_child(data->child_stdin, data->child_stdout);
+ goto restart_write;
+ }
+ if (ret == -1)
+ return (-1);
+
+ data->child_buf_avail += ret;
+
+ ret = __archive_write_filter(f->next_filter,
+ data->child_buf, data->child_buf_avail);
+ if (ret <= 0)
+ return (-1);
+
+ if ((size_t)ret < data->child_buf_avail) {
+ memmove(data->child_buf, data->child_buf + ret,
+ data->child_buf_avail - ret);
+ }
+ data->child_buf_avail -= ret;
+ goto restart_write;
+}
+
+/*
+ * Write data to the compressed stream.
+ */
+static int
+archive_compressor_program_write(struct archive_write_filter *f,
+ const void *buff, size_t length)
+{
+ ssize_t ret;
+ const char *buf;
+
+ buf = buff;
+ while (length > 0) {
+ ret = child_write(f, buf, length);
+ if (ret == -1 || ret == 0) {
+ archive_set_error(f->archive, EIO,
+ "Can't write to filter");
+ return (ARCHIVE_FATAL);
+ }
+ length -= ret;
+ buf += ret;
+ }
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_compressor_program_close(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret, status;
+ ssize_t bytes_read;
+
+ ret = 0;
+ close(data->child_stdin);
+ data->child_stdin = -1;
+ fcntl(data->child_stdout, F_SETFL, 0);
+
+ for (;;) {
+ do {
+ bytes_read = read(data->child_stdout,
+ data->child_buf + data->child_buf_avail,
+ data->child_buf_len - data->child_buf_avail);
+ } while (bytes_read == -1 && errno == EINTR);
+
+ if (bytes_read == 0 || (bytes_read == -1 && errno == EPIPE))
+ break;
+
+ if (bytes_read == -1) {
+ archive_set_error(f->archive, errno,
+ "Read from filter failed unexpectedly.");
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+ data->child_buf_avail += bytes_read;
+
+ ret = __archive_write_filter(f->next_filter,
+ data->child_buf, data->child_buf_avail);
+ if (ret != ARCHIVE_OK) {
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+ data->child_buf_avail = 0;
+ }
+
+cleanup:
+ /* Shut down the child. */
+ if (data->child_stdin != -1)
+ close(data->child_stdin);
+ if (data->child_stdout != -1)
+ close(data->child_stdout);
+ while (waitpid(data->child, &status, 0) == -1 && errno == EINTR)
+ continue;
+
+ if (status != 0) {
+ archive_set_error(f->archive, EIO,
+ "Filter exited with failure.");
+ ret = ARCHIVE_FATAL;
+ }
+ return (ret);
+}
+
+static int
+archive_compressor_program_free(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ free(data->cmd);
+ free(data->description);
+ free(data->child_buf);
+ free(data);
+ f->data = NULL;
+ return (ARCHIVE_OK);
+}
+
+#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */
--- /dev/null
+/*-
+ * Copyright (c) 2009 Michihiro NAKAJIMA
+ * Copyright (c) 2003-2010 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: head/lib/libarchive/archive_write_set_compression_xz.c 201108 2009-12-28 03:28:21Z kientzle $");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <time.h>
+#ifdef HAVE_LZMA_H
+#include <lzma.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_lzma(struct archive *a)
+{
+ __archive_write_filters_free(a);
+ return (archive_write_add_filter_lzma(a));
+}
+
+int
+archive_write_set_compression_xz(struct archive *a)
+{
+ __archive_write_filters_free(a);
+ return (archive_write_add_filter_xz(a));
+}
+#endif
+
+#ifndef HAVE_LZMA_H
+int
+archive_write_add_filter_xz(struct archive *a)
+{
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "xz compression not supported on this platform");
+ return (ARCHIVE_FATAL);
+}
+
+int
+archive_write_add_filter_lzma(struct archive *a)
+{
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "lzma compression not supported on this platform");
+ return (ARCHIVE_FATAL);
+}
+#else
+/* Don't compile this if we don't have liblzma. */
+
+struct private_data {
+ int compression_level;
+ lzma_stream stream;
+ lzma_filter lzmafilters[2];
+ lzma_options_lzma lzma_opt;
+ int64_t total_in;
+ unsigned char *compressed;
+ size_t compressed_buffer_size;
+};
+
+static int archive_compressor_xz_options(struct archive_write_filter *,
+ const char *, const char *);
+static int archive_compressor_xz_open(struct archive_write_filter *);
+static int archive_compressor_xz_write(struct archive_write_filter *,
+ const void *, size_t);
+static int archive_compressor_xz_close(struct archive_write_filter *);
+static int archive_compressor_xz_free(struct archive_write_filter *);
+static int drive_compressor(struct archive_write_filter *,
+ struct private_data *, int finishing);
+
+
+static int
+common_setup(struct archive_write_filter *f)
+{
+ struct private_data *data;
+ struct archive_write *a = (struct archive_write *)f->archive;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_add_filter_xz");
+ data = calloc(1, sizeof(*data));
+ if (data == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ f->data = data;
+ data->compression_level = LZMA_PRESET_DEFAULT;
+ f->open = &archive_compressor_xz_open;
+ f->close = archive_compressor_xz_close;
+ f->free = archive_compressor_xz_free;
+ f->options = &archive_compressor_xz_options;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Add an xz compression filter to this write handle.
+ */
+int
+archive_write_add_filter_xz(struct archive *_a)
+{
+ struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+ int r = common_setup(f);
+ if (r == ARCHIVE_OK) {
+ f->code = ARCHIVE_COMPRESSION_XZ;
+ f->name = "xz";
+ }
+ return (r);
+}
+
+/* LZMA is handled identically, we just need a different compression
+ * code set. (The liblzma setup looks at the code to determine
+ * the one place that XZ and LZMA require different handling.) */
+int
+archive_write_add_filter_lzma(struct archive *_a)
+{
+ struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+ int r = common_setup(f);
+ if (r == ARCHIVE_OK) {
+ f->code = ARCHIVE_COMPRESSION_LZMA;
+ f->name = "lzma";
+ }
+ return (r);
+}
+
+static int
+archive_compressor_xz_init_stream(struct archive_write_filter *f,
+ struct private_data *data)
+{
+ int ret;
+
+ data->stream = (lzma_stream)LZMA_STREAM_INIT;
+ data->stream.next_out = data->compressed;
+ data->stream.avail_out = data->compressed_buffer_size;
+ if (f->code == ARCHIVE_COMPRESSION_XZ)
+ ret = lzma_stream_encoder(&(data->stream),
+ data->lzmafilters, LZMA_CHECK_CRC64);
+ else
+ ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt);
+ if (ret == LZMA_OK)
+ return (ARCHIVE_OK);
+
+ switch (ret) {
+ case LZMA_MEM_ERROR:
+ archive_set_error(f->archive, ENOMEM,
+ "Internal error initializing compression library: "
+ "Cannot allocate memory");
+ break;
+ default:
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "It's a bug in liblzma");
+ break;
+ }
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_xz_open(struct archive_write_filter *f)
+{
+ struct private_data *data = f->data;
+ int ret;
+
+ ret = __archive_write_open_filter(f->next_filter);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+
+ if (data->compressed == NULL) {
+ data->compressed_buffer_size = 65536;
+ data->compressed
+ = (unsigned char *)malloc(data->compressed_buffer_size);
+ if (data->compressed == NULL) {
+ archive_set_error(f->archive, ENOMEM,
+ "Can't allocate data for compression buffer");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ f->write = archive_compressor_xz_write;
+
+ /* Initialize compression library. */
+ if (lzma_lzma_preset(&data->lzma_opt, data->compression_level)) {
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library");
+ }
+ data->lzmafilters[0].id = LZMA_FILTER_LZMA2;
+ data->lzmafilters[0].options = &data->lzma_opt;
+ data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
+ ret = archive_compressor_xz_init_stream(f, data);
+ if (ret == LZMA_OK) {
+ f->data = data;
+ return (0);
+ }
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_compressor_xz_options(struct archive_write_filter *f,
+ const char *key, const char *value)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ if (strcmp(key, "compression-level") == 0) {
+ if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+ value[1] != '\0')
+ return (ARCHIVE_WARN);
+ data->compression_level = value[0] - '0';
+ if (data->compression_level > 6)
+ data->compression_level = 6;
+ return (ARCHIVE_OK);
+ }
+
+ return (ARCHIVE_WARN);
+}
+
+/*
+ * Write data to the compressed stream.
+ */
+static int
+archive_compressor_xz_write(struct archive_write_filter *f,
+ const void *buff, size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret;
+
+ /* Update statistics */
+ data->total_in += length;
+
+ /* Compress input data to output buffer */
+ data->stream.next_in = buff;
+ data->stream.avail_in = length;
+ if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)
+ return (ret);
+
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_compressor_xz_close(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret;
+
+ if (data == NULL)
+ return (ARCHIVE_OK);
+ ret = drive_compressor(f, data, 1);
+ if (ret == ARCHIVE_OK) {
+ ret = __archive_write_filter(f->next_filter,
+ data->compressed,
+ data->compressed_buffer_size - data->stream.avail_out);
+ }
+ lzma_end(&(data->stream));
+ return (ret);
+}
+
+static int
+archive_compressor_xz_free(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ free(data->compressed);
+ free(data);
+ f->data = NULL;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Utility function to push input data through compressor,
+ * writing full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive_write_filter *f,
+ struct private_data *data, int finishing)
+{
+ int ret;
+
+ for (;;) {
+ if (data->stream.avail_out == 0) {
+ ret = __archive_write_filter(f->next_filter,
+ data->compressed,
+ data->compressed_buffer_size);
+ if (ret != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ data->stream.next_out = data->compressed;
+ data->stream.avail_out = data->compressed_buffer_size;
+ }
+
+ /* If there's nothing to do, we're done. */
+ if (!finishing && data->stream.avail_in == 0)
+ return (ARCHIVE_OK);
+
+ ret = lzma_code(&(data->stream),
+ finishing ? LZMA_FINISH : LZMA_RUN );
+
+ switch (ret) {
+ case LZMA_OK:
+ /* In non-finishing case, check if compressor
+ * consumed everything */
+ if (!finishing && data->stream.avail_in == 0)
+ return (ARCHIVE_OK);
+ /* In finishing case, this return always means
+ * there's more work */
+ break;
+ case LZMA_STREAM_END:
+ /* This return can only occur in finishing case. */
+ if (finishing)
+ return (ARCHIVE_OK);
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "lzma compression data error");
+ return (ARCHIVE_FATAL);
+ case LZMA_MEMLIMIT_ERROR:
+ archive_set_error(f->archive, ENOMEM,
+ "lzma compression error: "
+ "%ju MiB would have been needed",
+ (lzma_memusage(&(data->stream)) + 1024 * 1024 -1)
+ / (1024 * 1024));
+ return (ARCHIVE_FATAL);
+ default:
+ /* Any other return value indicates an error. */
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "lzma compression failed:"
+ " lzma_code() call returned status %d",
+ ret);
+ return (ARCHIVE_FATAL);
+ }
+ }
+}
+
+#endif /* HAVE_LZMA_H */
/* Handle for the file we're restoring. */
int fd;
/* Current offset for writing data to the file. */
- off_t offset;
+ int64_t offset;
/* Last offset actually written to disk. */
- off_t fd_offset;
+ int64_t fd_offset;
+ /* Total bytes actually written to files. */
+ int64_t total_bytes_written;
/* Maximum size of file, -1 if unknown. */
- off_t filesize;
+ int64_t filesize;
/* Dir we were in before this restore; only for deep paths. */
int restore_pwd;
/* Mode we should use for this entry; affected by _PERM and umask. */
static struct archive_vtable *archive_write_disk_vtable(void);
-static int _archive_write_close(struct archive *);
-static int _archive_write_free(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 ssize_t _archive_write_data_block(struct archive *, const void *, size_t, off_t);
+static int _archive_write_disk_close(struct archive *);
+static int _archive_write_disk_free(struct archive *);
+static int _archive_write_disk_header(struct archive *, struct archive_entry *);
+static int64_t _archive_write_disk_filter_bytes(struct archive *, int);
+static int _archive_write_disk_finish_entry(struct archive *);
+static ssize_t _archive_write_disk_data(struct archive *, const void *, size_t);
+static ssize_t _archive_write_disk_data_block(struct archive *, const void *, size_t, off_t);
static int
-_archive_write_disk_lazy_stat(struct archive_write_disk *a)
+lazy_stat(struct archive_write_disk *a)
{
if (a->pst != NULL) {
/* Already have stat() data available. */
static int inited = 0;
if (!inited) {
- av.archive_close = _archive_write_close;
- av.archive_free = _archive_write_free;
- av.archive_write_header = _archive_write_header;
- av.archive_write_finish_entry = _archive_write_finish_entry;
- av.archive_write_data = _archive_write_data;
- av.archive_write_data_block = _archive_write_data_block;
+ av.archive_close = _archive_write_disk_close;
+ av.archive_filter_bytes = _archive_write_disk_filter_bytes;
+ av.archive_free = _archive_write_disk_free;
+ av.archive_write_header = _archive_write_disk_header;
+ av.archive_write_finish_entry
+ = _archive_write_disk_finish_entry;
+ av.archive_write_data = _archive_write_disk_data;
+ av.archive_write_data_block = _archive_write_disk_data_block;
}
return (&av);
}
+static int64_t
+_archive_write_disk_filter_bytes(struct archive *_a, int n)
+{
+ (void)n; /* UNUSED */
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+// fprintf(stderr, "archive_write_disk_filter_bytes(%d)=%d\n", n, (int)a->fd_offset);
+ if (n == -1 || n == 0)
+ return (a->total_bytes_written);
+ return (-1);
+}
+
int
archive_write_disk_set_options(struct archive *_a, int flags)
*
*/
static int
-_archive_write_header(struct archive *_a, struct archive_entry *entry)
+_archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
struct fixup_entry *fe;
"archive_write_disk_header");
archive_clear_error(&a->archive);
if (a->archive.state & ARCHIVE_STATE_DATA) {
- r = _archive_write_finish_entry(&a->archive);
+ r = _archive_write_disk_finish_entry(&a->archive);
if (r == ARCHIVE_FATAL)
return (r);
}
if (a->flags & ARCHIVE_EXTRACT_SPARSE) {
#if HAVE_STRUCT_STAT_ST_BLKSIZE
int r;
- if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK)
+ if ((r = lazy_stat(a)) != ARCHIVE_OK)
return (r);
block_size = a->pst->st_blksize;
#else
}
/* If this write would run beyond the file size, truncate it. */
- if (a->filesize >= 0 && (off_t)(a->offset + size) > a->filesize)
+ if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
start_size = size = (size_t)(a->filesize - a->offset);
/* Write the data. */
} else {
/* We're sparsifying the file. */
const char *p, *end;
- off_t block_end;
+ int64_t block_end;
/* Skip leading zero bytes. */
for (p = buff, end = buff + size; p < end; ++p) {
return (ARCHIVE_FATAL);
}
a->fd_offset = a->offset;
- a->archive.file_position = a->offset;
- a->archive.raw_position = a->offset;
}
bytes_written = write(a->fd, buff, bytes_to_write);
if (bytes_written < 0) {
}
buff += bytes_written;
size -= bytes_written;
+ a->total_bytes_written += bytes_written;
a->offset += bytes_written;
- a->archive.file_position += bytes_written;
- a->archive.raw_position += bytes_written;
a->fd_offset = a->offset;
}
return (start_size - size);
}
static ssize_t
-_archive_write_data_block(struct archive *_a,
+_archive_write_disk_data_block(struct archive *_a,
const void *buff, size_t size, off_t offset)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
ssize_t r;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
- ARCHIVE_STATE_DATA, "archive_write_disk_block");
+ ARCHIVE_STATE_DATA, "archive_write_data_block");
a->offset = offset;
r = write_data_block(a, buff, size);
}
static ssize_t
-_archive_write_data(struct archive *_a, const void *buff, size_t size)
+_archive_write_disk_data(struct archive *_a, const void *buff, size_t size)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
}
static int
-_archive_write_finish_entry(struct archive *_a)
+_archive_write_disk_finish_entry(struct archive *_a)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
int ret = ARCHIVE_OK;
* to see what happened.
*/
a->pst = NULL;
- if ((ret = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK)
+ if ((ret = lazy_stat(a)) != ARCHIVE_OK)
return (ret);
/* We can use lseek()/write() to extend the file if
* ftruncate didn't work or isn't available. */
* reason we set directory perms here. XXX
*/
static int
-_archive_write_close(struct archive *_a)
+_archive_write_disk_close(struct archive *_a)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
struct fixup_entry *next, *p;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_write_disk_close");
- ret = _archive_write_finish_entry(&a->archive);
+ ret = _archive_write_disk_finish_entry(&a->archive);
/* Sort dir list so directories are fixed up in depth-first order. */
p = sort_dir_list(a->fixup_list);
}
static int
-_archive_write_free(struct archive *_a)
+_archive_write_disk_free(struct archive *_a)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
int ret;
- ret = _archive_write_close(&a->archive);
+ ret = _archive_write_disk_close(&a->archive);
if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL)
(a->cleanup_gid)(a->lookup_gid_data);
if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL)
* process, since systems sometimes set GID from
* the enclosing dir or based on ACLs.
*/
- if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK)
+ if ((r = lazy_stat(a)) != ARCHIVE_OK)
return (r);
if (a->pst->st_gid != a->gid) {
mode &= ~ S_ISGID;
* about the correct approach if we're overwriting an existing
* file that already has flags on it. XXX
*/
- if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK)
+ if ((r = lazy_stat(a)) != ARCHIVE_OK)
return (r);
a->st.st_flags &= ~clear;
#include "archive_string.h"
#include "archive_private.h"
+struct archive_write;
+
+struct archive_write_filter {
+ int64_t bytes_written;
+ struct archive *archive; /* Associated archive. */
+ struct archive_write_filter *next_filter; /* Who I write to. */
+ int (*options)(struct archive_write_filter *,
+ const char *key, const char *value);
+ int (*open)(struct archive_write_filter *);
+ int (*write)(struct archive_write_filter *, const void *, size_t);
+ int (*close)(struct archive_write_filter *);
+ int (*free)(struct archive_write_filter *);
+ void *data;
+ const char *name;
+ int code;
+ int bytes_per_block;
+ int bytes_in_last_block;
+};
+
+#if ARCHIVE_VERSION < 4000000
+void __archive_write_filters_free(struct archive *);
+#endif
+
+struct archive_write_filter *__archive_write_allocate_filter(struct archive *);
+
+int __archive_write_output(struct archive_write *, const void *, size_t);
+int __archive_write_filter(struct archive_write_filter *, const void *, size_t);
+int __archive_write_open_filter(struct archive_write_filter *);
+int __archive_write_close_filter(struct archive_write_filter *);
+
struct archive_write {
struct archive archive;
* 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.
+ * First and last write filters in the pipeline.
*/
- struct {
- void *data;
- void *config;
- int (*init)(struct archive_write *);
- int (*options)(struct archive_write *,
- const char *key, const char *value);
- int (*finish)(struct archive_write *);
- int (*write)(struct archive_write *, const void *, size_t);
- } compressor;
+ struct archive_write_filter *filter_first;
+ struct archive_write_filter *filter_last;
/*
* Pointers to format-specific functions for writing. They're
+++ /dev/null
-/*-
- * 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: head/lib/libarchive/archive_write_set_compression_bzip2.c 201091 2009-12-28 02:22:41Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_BZLIB_H
-#include <bzlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-#ifndef HAVE_BZLIB_H
-int
-archive_write_set_compression_bzip2(struct archive *a)
-{
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "bzip2 compression not supported on this platform");
- return (ARCHIVE_FATAL);
-}
-#else
-/* Don't compile this if we don't have bzlib. */
-
-struct private_data {
- bz_stream stream;
- int64_t total_in;
- char *compressed;
- size_t compressed_buffer_size;
-};
-
-struct private_config {
- int compression_level;
-};
-
-/*
- * Yuck. bzlib.h is not const-correct, so I need this one bit
- * of ugly hackery to convert a const * pointer to a non-const pointer.
- */
-#define SET_NEXT_IN(st,src) \
- (st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
-
-static int archive_compressor_bzip2_finish(struct archive_write *);
-static int archive_compressor_bzip2_init(struct archive_write *);
-static int archive_compressor_bzip2_options(struct archive_write *,
- const char *, const char *);
-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)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct private_config *config;
- __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
- config = malloc(sizeof(*config));
- if (config == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- a->compressor.config = config;
- a->compressor.finish = archive_compressor_bzip2_finish;
- config->compression_level = 9; /* default */
- a->compressor.init = &archive_compressor_bzip2_init;
- a->compressor.options = &archive_compressor_bzip2_options;
- a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
- a->archive.compression_name = "bzip2";
- return (ARCHIVE_OK);
-}
-
-/*
- * Setup callback.
- */
-static int
-archive_compressor_bzip2_init(struct archive_write *a)
-{
- int ret;
- struct private_data *state;
- struct private_config *config;
-
- config = (struct private_config *)a->compressor.config;
- if (a->client_opener != NULL) {
- 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->archive, ENOMEM,
- "Can't allocate data for compression");
- return (ARCHIVE_FATAL);
- }
- memset(state, 0, sizeof(*state));
-
- state->compressed_buffer_size = a->bytes_per_block;
- state->compressed = (char *)malloc(state->compressed_buffer_size);
-
- if (state->compressed == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data for compression buffer");
- free(state);
- return (ARCHIVE_FATAL);
- }
-
- state->stream.next_out = state->compressed;
- state->stream.avail_out = state->compressed_buffer_size;
- a->compressor.write = archive_compressor_bzip2_write;
-
- /* Initialize compression library */
- ret = BZ2_bzCompressInit(&(state->stream),
- config->compression_level, 0, 30);
- if (ret == BZ_OK) {
- a->compressor.data = state;
- return (ARCHIVE_OK);
- }
-
- /* Library setup failed: clean up. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library");
- free(state->compressed);
- free(state);
-
- /* Override the error message if we know what really went wrong. */
- switch (ret) {
- case BZ_PARAM_ERROR:
- 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, ENOMEM,
- "Internal error initializing compression library: "
- "out of memory");
- break;
- case BZ_CONFIG_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "mis-compiled library");
- break;
- }
-
- return (ARCHIVE_FATAL);
-
-}
-
-/*
- * Set write options.
- */
-static int
-archive_compressor_bzip2_options(struct archive_write *a, const char *key,
- const char *value)
-{
- struct private_config *config;
-
- config = (struct private_config *)a->compressor.config;
- if (strcmp(key, "compression-level") == 0) {
- if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
- value[1] != '\0')
- return (ARCHIVE_WARN);
- config->compression_level = value[0] - '0';
- /* Make '0' be a synonym for '1'. */
- /* This way, bzip2 compressor supports the same 0..9
- * range of levels as gzip. */
- if (config->compression_level < 1)
- config->compression_level = 1;
- return (ARCHIVE_OK);
- }
-
- return (ARCHIVE_WARN);
-}
-
-/*
- * Write data to the compressed stream.
- *
- * Returns ARCHIVE_OK if all data written, error otherwise.
- */
-static int
-archive_compressor_bzip2_write(struct archive_write *a, const void *buff,
- size_t length)
-{
- struct private_data *state;
-
- state = (struct private_data *)a->compressor.data;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- return (ARCHIVE_FATAL);
- }
-
- /* Update statistics */
- state->total_in += length;
-
- /* Compress input data to output buffer */
- SET_NEXT_IN(state, buff);
- state->stream.avail_in = length;
- if (drive_compressor(a, state, 0))
- return (ARCHIVE_FATAL);
- a->archive.file_position += length;
- return (ARCHIVE_OK);
-}
-
-
-/*
- * Finish the compression.
- */
-static int
-archive_compressor_bzip2_finish(struct archive_write *a)
-{
- ssize_t block_length;
- int ret;
- struct private_data *state;
- ssize_t target_block_length;
- ssize_t bytes_written;
- unsigned tocopy;
-
- ret = ARCHIVE_OK;
- state = (struct private_data *)a->compressor.data;
- if (state != NULL) {
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered?\n"
- "This is probably an internal programming error.");
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
-
- /* By default, always pad the uncompressed data. */
- if (a->pad_uncompressed) {
- tocopy = a->bytes_per_block -
- (state->total_in % a->bytes_per_block);
- while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
- SET_NEXT_IN(state, a->nulls);
- state->stream.avail_in = tocopy < a->null_length ?
- tocopy : a->null_length;
- state->total_in += state->stream.avail_in;
- tocopy -= state->stream.avail_in;
- ret = drive_compressor(a, state, 0);
- if (ret != ARCHIVE_OK)
- goto cleanup;
- }
- }
-
- /* Finish compression cycle. */
- if ((ret = drive_compressor(a, state, 1)))
- goto cleanup;
-
- /* Optionally, pad the final compressed block. */
- block_length = state->stream.next_out - state->compressed;
-
- /* Tricky calculation to determine size of last block. */
- if (a->bytes_in_last_block <= 0)
- /* Default or Zero: pad to full block */
- target_block_length = a->bytes_per_block;
- else
- /* Round length to next multiple of bytes_in_last_block. */
- target_block_length = a->bytes_in_last_block *
- ( (block_length + a->bytes_in_last_block - 1) /
- a->bytes_in_last_block);
- if (target_block_length > a->bytes_per_block)
- target_block_length = a->bytes_per_block;
- if (block_length < target_block_length) {
- memset(state->stream.next_out, 0,
- target_block_length - block_length);
- block_length = target_block_length;
- }
-
- /* Write the last block */
- 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->archive.raw_position += ret;
- ret = ARCHIVE_OK;
- }
-
- /* Cleanup: shut down compressor, release memory, etc. */
-cleanup:
- switch (BZ2_bzCompressEnd(&(state->stream))) {
- case BZ_OK:
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "Failed to clean up compressor");
- ret = ARCHIVE_FATAL;
- }
-
- free(state->compressed);
- free(state);
- }
- /* Free configuration data even if we were never fully initialized. */
- free(a->compressor.config);
- a->compressor.config = NULL;
- return (ret);
-}
-
-/*
- * Utility function to push input data through compressor, writing
- * full output blocks as necessary.
- *
- * Note that this handles both the regular write case (finishing ==
- * false) and the end-of-archive case (finishing == true).
- */
-static int
-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->archive,
- a->client_data, state->compressed,
- state->compressed_buffer_size);
- if (bytes_written <= 0) {
- /* TODO: Handle this write failure */
- return (ARCHIVE_FATAL);
- } else if ((size_t)bytes_written < state->compressed_buffer_size) {
- /* Short write: Move remainder to
- * front and keep filling */
- memmove(state->compressed,
- state->compressed + bytes_written,
- state->compressed_buffer_size - 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;
- }
-
- /* If there's nothing to do, we're done. */
- if (!finishing && state->stream.avail_in == 0)
- return (ARCHIVE_OK);
-
- ret = BZ2_bzCompress(&(state->stream),
- finishing ? BZ_FINISH : BZ_RUN);
-
- switch (ret) {
- case BZ_RUN_OK:
- /* In non-finishing case, did compressor
- * consume everything? */
- if (!finishing && state->stream.avail_in == 0)
- return (ARCHIVE_OK);
- break;
- case BZ_FINISH_OK: /* Finishing: There's more work to do */
- break;
- case BZ_STREAM_END: /* Finishing: all done */
- /* Only occurs in finishing case */
- return (ARCHIVE_OK);
- default:
- /* Any other return value indicates an error */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_PROGRAMMER,
- "Bzip2 compression failed;"
- " BZ2_bzCompress() returned %d",
- ret);
- return (ARCHIVE_FATAL);
- }
- }
-}
-
-#endif /* HAVE_BZLIB_H */
+++ /dev/null
-/*-
- * 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: head/lib/libarchive/archive_write_set_compression_gzip.c 201081 2009-12-28 02:04:42Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#include <time.h>
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-#ifndef HAVE_ZLIB_H
-int
-archive_write_set_compression_gzip(struct archive *a)
-{
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "gzip compression not supported on this platform");
- return (ARCHIVE_FATAL);
-}
-#else
-/* Don't compile this if we don't have zlib. */
-
-struct private_data {
- z_stream stream;
- int64_t total_in;
- unsigned char *compressed;
- size_t compressed_buffer_size;
- unsigned long crc;
-};
-
-struct private_config {
- int compression_level;
-};
-
-
-/*
- * Yuck. zlib.h is not const-correct, so I need this one bit
- * of ugly hackery to convert a const * pointer to a non-const pointer.
- */
-#define SET_NEXT_IN(st,src) \
- (st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src)
-
-static int archive_compressor_gzip_finish(struct archive_write *);
-static int archive_compressor_gzip_init(struct archive_write *);
-static int archive_compressor_gzip_options(struct archive_write *,
- const char *, const char *);
-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);
-
-
-/*
- * Allocate, initialize and return a archive object.
- */
-int
-archive_write_set_compression_gzip(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct private_config *config;
- __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
- config = malloc(sizeof(*config));
- if (config == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- a->compressor.config = config;
- a->compressor.finish = &archive_compressor_gzip_finish;
- config->compression_level = Z_DEFAULT_COMPRESSION;
- a->compressor.init = &archive_compressor_gzip_init;
- a->compressor.options = &archive_compressor_gzip_options;
- a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
- a->archive.compression_name = "gzip";
- return (ARCHIVE_OK);
-}
-
-/*
- * Setup callback.
- */
-static int
-archive_compressor_gzip_init(struct archive_write *a)
-{
- int ret;
- struct private_data *state;
- struct private_config *config;
- time_t t;
-
- config = (struct private_config *)a->compressor.config;
-
- if (a->client_opener != NULL) {
- ret = (a->client_opener)(&a->archive, a->client_data);
- if (ret != ARCHIVE_OK)
- return (ret);
- }
-
- /*
- * The next check is a temporary workaround until the gzip
- * code can be overhauled some. The code should not require
- * that compressed_buffer_size == bytes_per_block. Removing
- * this assumption will allow us to compress larger chunks at
- * a time, which should improve overall performance
- * marginally. As a minor side-effect, such a cleanup would
- * allow us to support truly arbitrary block sizes.
- */
- if (a->bytes_per_block < 10) {
- archive_set_error(&a->archive, EINVAL,
- "GZip compressor requires a minimum 10 byte block size");
- return (ARCHIVE_FATAL);
- }
-
- state = (struct private_data *)malloc(sizeof(*state));
- if (state == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data for compression");
- return (ARCHIVE_FATAL);
- }
- memset(state, 0, sizeof(*state));
-
- /*
- * See comment above. We should set compressed_buffer_size to
- * max(bytes_per_block, 65536), but the code can't handle that yet.
- */
- state->compressed_buffer_size = a->bytes_per_block;
- state->compressed = (unsigned char *)malloc(state->compressed_buffer_size);
- state->crc = crc32(0L, NULL, 0);
-
- if (state->compressed == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data for compression buffer");
- free(state);
- return (ARCHIVE_FATAL);
- }
-
- state->stream.next_out = state->compressed;
- state->stream.avail_out = state->compressed_buffer_size;
-
- /* Prime output buffer with a gzip header. */
- t = time(NULL);
- state->compressed[0] = 0x1f; /* GZip signature bytes */
- state->compressed[1] = 0x8b;
- state->compressed[2] = 0x08; /* "Deflate" compression */
- state->compressed[3] = 0; /* No options */
- state->compressed[4] = (t)&0xff; /* Timestamp */
- state->compressed[5] = (t>>8)&0xff;
- state->compressed[6] = (t>>16)&0xff;
- state->compressed[7] = (t>>24)&0xff;
- state->compressed[8] = 0; /* No deflate options */
- state->compressed[9] = 3; /* OS=Unix */
- state->stream.next_out += 10;
- state->stream.avail_out -= 10;
-
- a->compressor.write = archive_compressor_gzip_write;
-
- /* Initialize compression library. */
- ret = deflateInit2(&(state->stream),
- config->compression_level,
- Z_DEFLATED,
- -15 /* < 0 to suppress zlib header */,
- 8,
- Z_DEFAULT_STRATEGY);
-
- if (ret == Z_OK) {
- a->compressor.data = state;
- return (0);
- }
-
- /* Library setup failed: clean up. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal error "
- "initializing compression library");
- free(state->compressed);
- free(state);
-
- /* Override the error message if we know what really went wrong. */
- switch (ret) {
- case Z_STREAM_ERROR:
- 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->archive, ENOMEM, "Internal error initializing "
- "compression library");
- break;
- case Z_VERSION_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing "
- "compression library: invalid library version");
- break;
- }
-
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Set write options.
- */
-static int
-archive_compressor_gzip_options(struct archive_write *a, const char *key,
- const char *value)
-{
- struct private_config *config;
-
- config = (struct private_config *)a->compressor.config;
- if (strcmp(key, "compression-level") == 0) {
- if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
- value[1] != '\0')
- return (ARCHIVE_WARN);
- config->compression_level = value[0] - '0';
- return (ARCHIVE_OK);
- }
-
- return (ARCHIVE_WARN);
-}
-
-/*
- * Write data to the compressed stream.
- */
-static int
-archive_compressor_gzip_write(struct archive_write *a, const void *buff,
- size_t length)
-{
- struct private_data *state;
- int ret;
-
- state = (struct private_data *)a->compressor.data;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- return (ARCHIVE_FATAL);
- }
-
- /* Update statistics */
- state->crc = crc32(state->crc, (const Bytef *)buff, length);
- state->total_in += length;
-
- /* Compress input data to output buffer */
- SET_NEXT_IN(state, buff);
- state->stream.avail_in = length;
- if ((ret = drive_compressor(a, state, 0)) != ARCHIVE_OK)
- return (ret);
-
- a->archive.file_position += length;
- return (ARCHIVE_OK);
-}
-
-/*
- * Finish the compression...
- */
-static int
-archive_compressor_gzip_finish(struct archive_write *a)
-{
- ssize_t block_length, target_block_length, bytes_written;
- int ret;
- struct private_data *state;
- unsigned tocopy;
- unsigned char trailer[8];
-
- state = (struct private_data *)a->compressor.data;
- ret = 0;
- if (state != NULL) {
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
-
- /* By default, always pad the uncompressed data. */
- if (a->pad_uncompressed) {
- tocopy = a->bytes_per_block -
- (state->total_in % a->bytes_per_block);
- while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
- SET_NEXT_IN(state, a->nulls);
- state->stream.avail_in = tocopy < a->null_length ?
- tocopy : a->null_length;
- state->crc = crc32(state->crc, a->nulls,
- state->stream.avail_in);
- state->total_in += state->stream.avail_in;
- tocopy -= state->stream.avail_in;
- ret = drive_compressor(a, state, 0);
- if (ret != ARCHIVE_OK)
- goto cleanup;
- }
- }
-
- /* Finish compression cycle */
- if (((ret = drive_compressor(a, state, 1))) != ARCHIVE_OK)
- goto cleanup;
-
- /* Build trailer: 4-byte CRC and 4-byte length. */
- trailer[0] = (state->crc)&0xff;
- trailer[1] = (state->crc >> 8)&0xff;
- trailer[2] = (state->crc >> 16)&0xff;
- trailer[3] = (state->crc >> 24)&0xff;
- trailer[4] = (state->total_in)&0xff;
- trailer[5] = (state->total_in >> 8)&0xff;
- trailer[6] = (state->total_in >> 16)&0xff;
- trailer[7] = (state->total_in >> 24)&0xff;
-
- /* Add trailer to current block. */
- tocopy = 8;
- if (tocopy > state->stream.avail_out)
- tocopy = state->stream.avail_out;
- memcpy(state->stream.next_out, trailer, tocopy);
- state->stream.next_out += tocopy;
- state->stream.avail_out -= tocopy;
-
- /* If it overflowed, flush and start a new block. */
- if (tocopy < 8) {
- 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->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);
- state->stream.next_out += 8-tocopy;
- state->stream.avail_out -= 8-tocopy;
- }
-
- /* Optionally, pad the final compressed block. */
- block_length = state->stream.next_out - state->compressed;
-
- /* Tricky calculation to determine size of last block. */
- if (a->bytes_in_last_block <= 0)
- /* Default or Zero: pad to full block */
- target_block_length = a->bytes_per_block;
- else
- /* Round length to next multiple of bytes_in_last_block. */
- target_block_length = a->bytes_in_last_block *
- ( (block_length + a->bytes_in_last_block - 1) /
- a->bytes_in_last_block);
- if (target_block_length > a->bytes_per_block)
- target_block_length = a->bytes_per_block;
- if (block_length < target_block_length) {
- memset(state->stream.next_out, 0,
- target_block_length - block_length);
- block_length = target_block_length;
- }
-
- /* Write the last block */
- bytes_written = (a->client_writer)(&a->archive, a->client_data,
- state->compressed, block_length);
- if (bytes_written <= 0) {
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
- a->archive.raw_position += bytes_written;
-
- /* Cleanup: shut down compressor, release memory, etc. */
- cleanup:
- switch (deflateEnd(&(state->stream))) {
- case Z_OK:
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to clean up compressor");
- ret = ARCHIVE_FATAL;
- }
- free(state->compressed);
- free(state);
- }
- /* Clean up config area even if we never initialized. */
- free(a->compressor.config);
- a->compressor.config = NULL;
- return (ret);
-}
-
-/*
- * Utility function to push input data through compressor,
- * writing full output blocks as necessary.
- *
- * Note that this handles both the regular write case (finishing ==
- * false) and the end-of-archive case (finishing == true).
- */
-static int
-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->archive,
- a->client_data, state->compressed,
- state->compressed_buffer_size);
- if (bytes_written <= 0) {
- /* TODO: Handle this write failure */
- return (ARCHIVE_FATAL);
- } else if ((size_t)bytes_written < state->compressed_buffer_size) {
- /* Short write: Move remaining to
- * front of block and keep filling */
- memmove(state->compressed,
- state->compressed + bytes_written,
- state->compressed_buffer_size - 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;
- }
-
- /* If there's nothing to do, we're done. */
- if (!finishing && state->stream.avail_in == 0)
- return (ARCHIVE_OK);
-
- ret = deflate(&(state->stream),
- finishing ? Z_FINISH : Z_NO_FLUSH );
-
- switch (ret) {
- case Z_OK:
- /* In non-finishing case, check if compressor
- * consumed everything */
- if (!finishing && state->stream.avail_in == 0)
- return (ARCHIVE_OK);
- /* In finishing case, this return always means
- * there's more work */
- break;
- case Z_STREAM_END:
- /* This return can only occur in finishing case. */
- return (ARCHIVE_OK);
- default:
- /* Any other return value indicates an error. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "GZip compression failed:"
- " deflate() call returned status %d",
- ret);
- return (ARCHIVE_FATAL);
- }
- }
-}
-
-#endif /* HAVE_ZLIB_H */
+++ /dev/null
-/*-
- * Copyright (c) 2007 Joerg Sonnenberger
- * 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: head/lib/libarchive/archive_write_set_compression_program.c 201104 2009-12-28 03:14:30Z kientzle $");
-
-/* This capability is only available on POSIX systems. */
-#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
- !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && (!defined(_WIN32) || defined(__CYGWIN__))
-#include "archive.h"
-
-/*
- * On non-Posix systems, allow the program to build, but choke if
- * this function is actually invoked.
- */
-int
-archive_write_set_compression_program(struct archive *_a, const char *cmd)
-{
- archive_set_error(_a, -1,
- "External compression programs not supported on this platform");
- return (ARCHIVE_FATAL);
-}
-
-#else
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-#ifdef HAVE_ERRNO_H
-# include <errno.h>
-#endif
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-#endif
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-#include "filter_fork.h"
-
-struct private_data {
- char *description;
- pid_t child;
- int child_stdin, child_stdout;
-
- char *child_buf;
- size_t child_buf_len, child_buf_avail;
-};
-
-static int archive_compressor_program_finish(struct archive_write *);
-static int archive_compressor_program_init(struct archive_write *);
-static int archive_compressor_program_write(struct archive_write *,
- const void *, size_t);
-
-/*
- * Allocate, initialize and return a archive object.
- */
-int
-archive_write_set_compression_program(struct archive *_a, const char *cmd)
-{
- struct archive_write *a = (struct archive_write *)_a;
- __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_compression_program");
- a->compressor.init = &archive_compressor_program_init;
- a->compressor.config = strdup(cmd);
- return (ARCHIVE_OK);
-}
-
-/*
- * Setup callback.
- */
-static int
-archive_compressor_program_init(struct archive_write *a)
-{
- int ret;
- struct private_data *state;
- static const char *prefix = "Program: ";
- char *cmd = a->compressor.config;
-
- if (a->client_opener != NULL) {
- 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->archive, ENOMEM,
- "Can't allocate data for compression");
- return (ARCHIVE_FATAL);
- }
- memset(state, 0, sizeof(*state));
-
- a->archive.compression_code = ARCHIVE_COMPRESSION_PROGRAM;
- state->description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
- strcpy(state->description, prefix);
- strcat(state->description, cmd);
- a->archive.compression_name = state->description;
-
- state->child_buf_len = a->bytes_per_block;
- state->child_buf_avail = 0;
- state->child_buf = malloc(state->child_buf_len);
-
- if (state->child_buf == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data for compression buffer");
- free(state);
- return (ARCHIVE_FATAL);
- }
-
- if ((state->child = __archive_create_child(cmd,
- &state->child_stdin, &state->child_stdout)) == -1) {
- archive_set_error(&a->archive, EINVAL,
- "Can't initialise filter");
- free(state->child_buf);
- free(state);
- return (ARCHIVE_FATAL);
- }
-
- a->compressor.write = archive_compressor_program_write;
- a->compressor.finish = archive_compressor_program_finish;
-
- a->compressor.data = state;
- return (0);
-}
-
-static ssize_t
-child_write(struct archive_write *a, const char *buf, size_t buf_len)
-{
- struct private_data *state = a->compressor.data;
- ssize_t ret;
-
- if (state->child_stdin == -1)
- return (-1);
-
- if (buf_len == 0)
- return (-1);
-
-restart_write:
- do {
- ret = write(state->child_stdin, buf, buf_len);
- } while (ret == -1 && errno == EINTR);
-
- if (ret > 0)
- return (ret);
- if (ret == 0) {
- close(state->child_stdin);
- state->child_stdin = -1;
- fcntl(state->child_stdout, F_SETFL, 0);
- return (0);
- }
- if (ret == -1 && errno != EAGAIN)
- return (-1);
-
- if (state->child_stdout == -1) {
- fcntl(state->child_stdin, F_SETFL, 0);
- __archive_check_child(state->child_stdin, state->child_stdout);
- goto restart_write;
- }
-
- do {
- ret = read(state->child_stdout,
- state->child_buf + state->child_buf_avail,
- state->child_buf_len - state->child_buf_avail);
- } while (ret == -1 && errno == EINTR);
-
- if (ret == 0 || (ret == -1 && errno == EPIPE)) {
- close(state->child_stdout);
- state->child_stdout = -1;
- fcntl(state->child_stdin, F_SETFL, 0);
- goto restart_write;
- }
- if (ret == -1 && errno == EAGAIN) {
- __archive_check_child(state->child_stdin, state->child_stdout);
- goto restart_write;
- }
- if (ret == -1)
- return (-1);
-
- state->child_buf_avail += ret;
-
- ret = (a->client_writer)(&a->archive, a->client_data,
- state->child_buf, state->child_buf_avail);
- if (ret <= 0)
- return (-1);
-
- if ((size_t)ret < state->child_buf_avail) {
- memmove(state->child_buf, state->child_buf + ret,
- state->child_buf_avail - ret);
- }
- state->child_buf_avail -= ret;
- a->archive.raw_position += ret;
- goto restart_write;
-}
-
-/*
- * Write data to the compressed stream.
- */
-static int
-archive_compressor_program_write(struct archive_write *a, const void *buff,
- size_t length)
-{
- ssize_t ret;
- const char *buf;
-
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- return (ARCHIVE_FATAL);
- }
-
- buf = buff;
- while (length > 0) {
- ret = child_write(a, buf, length);
- if (ret == -1 || ret == 0) {
- archive_set_error(&a->archive, EIO,
- "Can't write to filter");
- return (ARCHIVE_FATAL);
- }
- length -= ret;
- buf += ret;
- }
-
- a->archive.file_position += length;
- return (ARCHIVE_OK);
-}
-
-
-/*
- * Finish the compression...
- */
-static int
-archive_compressor_program_finish(struct archive_write *a)
-{
- int ret, status;
- ssize_t bytes_read, bytes_written;
- struct private_data *state;
-
- state = (struct private_data *)a->compressor.data;
- ret = 0;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
-
- /* XXX pad compressed data. */
-
- close(state->child_stdin);
- state->child_stdin = -1;
- fcntl(state->child_stdout, F_SETFL, 0);
-
- for (;;) {
- do {
- bytes_read = read(state->child_stdout,
- state->child_buf + state->child_buf_avail,
- state->child_buf_len - state->child_buf_avail);
- } while (bytes_read == -1 && errno == EINTR);
-
- if (bytes_read == 0 || (bytes_read == -1 && errno == EPIPE))
- break;
-
- if (bytes_read == -1) {
- archive_set_error(&a->archive, errno,
- "Read from filter failed unexpectedly.");
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
- state->child_buf_avail += bytes_read;
-
- bytes_written = (a->client_writer)(&a->archive, a->client_data,
- state->child_buf, state->child_buf_avail);
- if (bytes_written <= 0) {
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
- if ((size_t)bytes_written < state->child_buf_avail) {
- memmove(state->child_buf,
- state->child_buf + bytes_written,
- state->child_buf_avail - bytes_written);
- }
- state->child_buf_avail -= bytes_written;
- a->archive.raw_position += bytes_written;
- }
-
- /* XXX pad final compressed block. */
-
-cleanup:
- /* Shut down the child. */
- if (state->child_stdin != -1)
- close(state->child_stdin);
- if (state->child_stdout != -1)
- close(state->child_stdout);
- while (waitpid(state->child, &status, 0) == -1 && errno == EINTR)
- continue;
-
- if (status != 0) {
- archive_set_error(&a->archive, EIO,
- "Filter exited with failure.");
- ret = ARCHIVE_FATAL;
- }
-
- /* Release our configuration data. */
- free(a->compressor.config);
- a->compressor.config = NULL;
-
- /* Release our private state data. */
- free(state->child_buf);
- free(state->description);
- free(state);
- return (ret);
-}
-
-#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */
+++ /dev/null
-/*-
- * Copyright (c) 2009 Michihiro NAKAJIMA
- * 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: head/lib/libarchive/archive_write_set_compression_xz.c 201108 2009-12-28 03:28:21Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#include <time.h>
-#ifdef HAVE_LZMA_H
-#include <lzma.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-#ifndef HAVE_LZMA_H
-int
-archive_write_set_compression_xz(struct archive *a)
-{
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "xz compression not supported on this platform");
- return (ARCHIVE_FATAL);
-}
-
-int
-archive_write_set_compression_lzma(struct archive *a)
-{
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "lzma compression not supported on this platform");
- return (ARCHIVE_FATAL);
-}
-#else
-/* Don't compile this if we don't have liblzma. */
-
-struct private_data {
- lzma_stream stream;
- lzma_filter lzmafilters[2];
- lzma_options_lzma lzma_opt;
- int64_t total_in;
- unsigned char *compressed;
- size_t compressed_buffer_size;
-};
-
-struct private_config {
- int compression_level;
-};
-
-static int archive_compressor_xz_init(struct archive_write *);
-static int archive_compressor_xz_options(struct archive_write *,
- const char *, const char *);
-static int archive_compressor_xz_finish(struct archive_write *);
-static int archive_compressor_xz_write(struct archive_write *,
- const void *, size_t);
-static int drive_compressor(struct archive_write *, struct private_data *,
- int finishing);
-
-
-/*
- * Allocate, initialize and return a archive object.
- */
-int
-archive_write_set_compression_xz(struct archive *_a)
-{
- struct private_config *config;
- struct archive_write *a = (struct archive_write *)_a;
- __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_compression_xz");
- config = calloc(1, sizeof(*config));
- if (config == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- a->compressor.config = config;
- a->compressor.finish = archive_compressor_xz_finish;
- config->compression_level = LZMA_PRESET_DEFAULT;
- a->compressor.init = &archive_compressor_xz_init;
- a->compressor.options = &archive_compressor_xz_options;
- a->archive.compression_code = ARCHIVE_COMPRESSION_XZ;
- a->archive.compression_name = "xz";
- return (ARCHIVE_OK);
-}
-
-/* LZMA is handled identically, we just need a different compression
- * code set. (The liblzma setup looks at the code to determine
- * the one place that XZ and LZMA require different handling.) */
-int
-archive_write_set_compression_lzma(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- int r = archive_write_set_compression_xz(_a);
- if (r != ARCHIVE_OK)
- return (r);
- a->archive.compression_code = ARCHIVE_COMPRESSION_LZMA;
- a->archive.compression_name = "lzma";
- return (ARCHIVE_OK);
-}
-
-static int
-archive_compressor_xz_init_stream(struct archive_write *a,
- struct private_data *state)
-{
- int ret;
-
- state->stream = (lzma_stream)LZMA_STREAM_INIT;
- state->stream.next_out = state->compressed;
- state->stream.avail_out = state->compressed_buffer_size;
- if (a->archive.compression_code == ARCHIVE_COMPRESSION_XZ)
- ret = lzma_stream_encoder(&(state->stream),
- state->lzmafilters, LZMA_CHECK_CRC64);
- else
- ret = lzma_alone_encoder(&(state->stream), &state->lzma_opt);
- if (ret == LZMA_OK)
- return (ARCHIVE_OK);
-
- switch (ret) {
- case LZMA_MEM_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Internal error initializing compression library: "
- "Cannot allocate memory");
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "It's a bug in liblzma");
- break;
- }
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Setup callback.
- */
-static int
-archive_compressor_xz_init(struct archive_write *a)
-{
- int ret;
- struct private_data *state;
- struct private_config *config;
-
- if (a->client_opener != NULL) {
- 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->archive, ENOMEM,
- "Can't allocate data for compression");
- return (ARCHIVE_FATAL);
- }
- memset(state, 0, sizeof(*state));
- config = a->compressor.config;
-
- /*
- * See comment above. We should set compressed_buffer_size to
- * max(bytes_per_block, 65536), but the code can't handle that yet.
- */
- state->compressed_buffer_size = a->bytes_per_block;
- state->compressed = (unsigned char *)malloc(state->compressed_buffer_size);
- if (state->compressed == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data for compression buffer");
- free(state);
- return (ARCHIVE_FATAL);
- }
- a->compressor.write = archive_compressor_xz_write;
-
- /* Initialize compression library. */
- if (lzma_lzma_preset(&state->lzma_opt, config->compression_level)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library");
- free(state->compressed);
- free(state);
- }
- state->lzmafilters[0].id = LZMA_FILTER_LZMA2;
- state->lzmafilters[0].options = &state->lzma_opt;
- state->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
- ret = archive_compressor_xz_init_stream(a, state);
- if (ret == LZMA_OK) {
- a->compressor.data = state;
- return (0);
- }
- /* Library setup failed: clean up. */
- free(state->compressed);
- free(state);
-
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Set write options.
- */
-static int
-archive_compressor_xz_options(struct archive_write *a, const char *key,
- const char *value)
-{
- struct private_config *config;
-
- config = (struct private_config *)a->compressor.config;
- if (strcmp(key, "compression-level") == 0) {
- if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
- value[1] != '\0')
- return (ARCHIVE_WARN);
- config->compression_level = value[0] - '0';
- if (config->compression_level > 6)
- config->compression_level = 6;
- return (ARCHIVE_OK);
- }
-
- return (ARCHIVE_WARN);
-}
-
-/*
- * Write data to the compressed stream.
- */
-static int
-archive_compressor_xz_write(struct archive_write *a, const void *buff,
- size_t length)
-{
- struct private_data *state;
- int ret;
-
- state = (struct private_data *)a->compressor.data;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- return (ARCHIVE_FATAL);
- }
-
- /* Update statistics */
- state->total_in += length;
-
- /* Compress input data to output buffer */
- state->stream.next_in = buff;
- state->stream.avail_in = length;
- if ((ret = drive_compressor(a, state, 0)) != ARCHIVE_OK)
- return (ret);
-
- a->archive.file_position += length;
- return (ARCHIVE_OK);
-}
-
-
-/*
- * Finish the compression...
- */
-static int
-archive_compressor_xz_finish(struct archive_write *a)
-{
- ssize_t block_length, target_block_length, bytes_written;
- int ret;
- struct private_data *state;
- unsigned tocopy;
-
- ret = ARCHIVE_OK;
- state = (struct private_data *)a->compressor.data;
- if (state != NULL) {
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered? "
- "This is probably an internal programming error.");
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
-
- /* By default, always pad the uncompressed data. */
- if (a->pad_uncompressed) {
- tocopy = a->bytes_per_block -
- (state->total_in % a->bytes_per_block);
- while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
- state->stream.next_in = a->nulls;
- state->stream.avail_in = tocopy < a->null_length ?
- tocopy : a->null_length;
- state->total_in += state->stream.avail_in;
- tocopy -= state->stream.avail_in;
- ret = drive_compressor(a, state, 0);
- if (ret != ARCHIVE_OK)
- goto cleanup;
- }
- }
-
- /* Finish compression cycle */
- if (((ret = drive_compressor(a, state, 1))) != ARCHIVE_OK)
- goto cleanup;
-
- /* Optionally, pad the final compressed block. */
- block_length = state->stream.next_out - state->compressed;
-
- /* Tricky calculation to determine size of last block. */
- if (a->bytes_in_last_block <= 0)
- /* Default or Zero: pad to full block */
- target_block_length = a->bytes_per_block;
- else
- /* Round length to next multiple of bytes_in_last_block. */
- target_block_length = a->bytes_in_last_block *
- ( (block_length + a->bytes_in_last_block - 1) /
- a->bytes_in_last_block);
- if (target_block_length > a->bytes_per_block)
- target_block_length = a->bytes_per_block;
- if (block_length < target_block_length) {
- memset(state->stream.next_out, 0,
- target_block_length - block_length);
- block_length = target_block_length;
- }
-
- /* Write the last block */
- bytes_written = (a->client_writer)(&a->archive, a->client_data,
- state->compressed, block_length);
- if (bytes_written <= 0) {
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
- a->archive.raw_position += bytes_written;
-
- /* Cleanup: shut down compressor, release memory, etc. */
- cleanup:
- lzma_end(&(state->stream));
- free(state->compressed);
- free(state);
- }
- free(a->compressor.config);
- a->compressor.config = NULL;
- return (ret);
-}
-
-/*
- * Utility function to push input data through compressor,
- * writing full output blocks as necessary.
- *
- * Note that this handles both the regular write case (finishing ==
- * false) and the end-of-archive case (finishing == true).
- */
-static int
-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->archive,
- a->client_data, state->compressed,
- state->compressed_buffer_size);
- if (bytes_written <= 0) {
- /* TODO: Handle this write failure */
- return (ARCHIVE_FATAL);
- } else if ((size_t)bytes_written < state->compressed_buffer_size) {
- /* Short write: Move remaining to
- * front of block and keep filling */
- memmove(state->compressed,
- state->compressed + bytes_written,
- state->compressed_buffer_size - 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;
- }
-
- /* If there's nothing to do, we're done. */
- if (!finishing && state->stream.avail_in == 0)
- return (ARCHIVE_OK);
-
- ret = lzma_code(&(state->stream),
- finishing ? LZMA_FINISH : LZMA_RUN );
-
- switch (ret) {
- case LZMA_OK:
- /* In non-finishing case, check if compressor
- * consumed everything */
- if (!finishing && state->stream.avail_in == 0)
- return (ARCHIVE_OK);
- /* In finishing case, this return always means
- * there's more work */
- break;
- case LZMA_STREAM_END:
- /* This return can only occur in finishing case. */
- if (finishing)
- return (ARCHIVE_OK);
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "lzma compression data error");
- return (ARCHIVE_FATAL);
- case LZMA_MEMLIMIT_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "lzma compression error: "
- "%ju MiB would have been needed",
- (lzma_memusage(&(state->stream)) + 1024 * 1024 -1)
- / (1024 * 1024));
- return (ARCHIVE_FATAL);
- default:
- /* Any other return value indicates an error. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "lzma compression failed:"
- " lzma_code() call returned status %d",
- ret);
- return (ARCHIVE_FATAL);
- }
- }
-}
-
-#endif /* HAVE_LZMA_H */
uint64_t entry_padding;
int is_strtab;
int has_strtab;
+ char wrote_global_header;
char *strtab;
};
* If we are now at the beginning of the archive,
* we need first write the ar global header.
*/
- if (a->archive.file_position == 0)
- (a->compressor.write)(a, "!<arch>\n", 8);
+ if (!ar->wrote_global_header) {
+ __archive_write_output(a, "!<arch>\n", 8);
+ ar->wrote_global_header = 1;
+ }
memset(buff, ' ', 60);
strncpy(&buff[AR_fmag_offset], "`\n", 2);
return (ARCHIVE_WARN);
}
- ret = (a->compressor.write)(a, buff, 60);
+ ret = __archive_write_output(a, buff, 60);
if (ret != ARCHIVE_OK)
return (ret);
ar->entry_padding = ar->entry_bytes_remaining % 2;
if (append_fn > 0) {
- ret = (a->compressor.write)(a, filename, strlen(filename));
+ ret = __archive_write_output(a, filename, strlen(filename));
if (ret != ARCHIVE_OK)
return (ret);
ar->entry_bytes_remaining -= strlen(filename);
ar->has_strtab = 1;
}
- ret = (a->compressor.write)(a, buff, s);
+ ret = __archive_write_output(a, buff, s);
if (ret != ARCHIVE_OK)
return (ret);
static int
archive_write_ar_finish(struct archive_write *a)
{
+ struct ar_w *ar;
int ret;
/*
* If we haven't written anything yet, we need to write
* the ar global header now to make it a valid ar archive.
*/
- if (a->archive.file_position == 0) {
- ret = (a->compressor.write)(a, "!<arch>\n", 8);
+ ar = (struct ar_w *)a->format_data;
+ if (!ar->wrote_global_header) {
+ ar->wrote_global_header = 1;
+ ret = __archive_write_output(a, "!<arch>\n", 8);
return (ret);
}
return (ARCHIVE_WARN);
}
- ret = (a->compressor.write)(a, "\n", 1);
+ ret = __archive_write_output(a, "\n", 1);
return (ret);
}
format_octal(archive_entry_size(entry),
&h.c_filesize, sizeof(h.c_filesize));
- ret = (a->compressor.write)(a, &h, sizeof(h));
+ ret = __archive_write_output(a, &h, sizeof(h));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- ret = (a->compressor.write)(a, path, pathlength);
+ ret = __archive_write_output(a, path, pathlength);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
/* Write the symlink now. */
if (p != NULL && *p != '\0')
- ret = (a->compressor.write)(a, p, strlen(p));
+ ret = __archive_write_output(a, p, strlen(p));
if (ret == ARCHIVE_OK)
ret = ret2;
if (s > cpio->entry_bytes_remaining)
s = cpio->entry_bytes_remaining;
- ret = (a->compressor.write)(a, buff, s);
+ ret = __archive_write_output(a, buff, s);
cpio->entry_bytes_remaining -= s;
if (ret >= 0)
return (s);
while (cpio->entry_bytes_remaining > 0) {
to_write = cpio->entry_bytes_remaining < a->null_length ?
cpio->entry_bytes_remaining : a->null_length;
- ret = (a->compressor.write)(a, a->nulls, to_write);
+ ret = __archive_write_output(a, a->nulls, to_write);
if (ret != ARCHIVE_OK)
return (ret);
cpio->entry_bytes_remaining -= to_write;
format_hex(archive_entry_size(entry),
&h.c_filesize, sizeof(h.c_filesize));
- ret = (a->compressor.write)(a, &h, sizeof(h));
+ ret = __archive_write_output(a, &h, sizeof(h));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
/* Pad pathname to even length. */
- ret = (a->compressor.write)(a, path, pathlength);
+ ret = __archive_write_output(a, path, pathlength);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
pad = PAD4(pathlength + sizeof(struct cpio_header_newc));
if (pad)
- ret = (a->compressor.write)(a, "\0\0\0", pad);
+ ret = __archive_write_output(a, "\0\0\0", pad);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
/* Write the symlink now. */
if (p != NULL && *p != '\0') {
- ret = (a->compressor.write)(a, p, strlen(p));
+ ret = __archive_write_output(a, p, strlen(p));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
pad = PAD4(strlen(p));
- ret = (a->compressor.write)(a, "\0\0\0", pad);
+ ret = __archive_write_output(a, "\0\0\0", pad);
}
if (ret == ARCHIVE_OK)
if (s > cpio->entry_bytes_remaining)
s = cpio->entry_bytes_remaining;
- ret = (a->compressor.write)(a, buff, s);
+ ret = __archive_write_output(a, buff, s);
cpio->entry_bytes_remaining -= s;
if (ret >= 0)
return (s);
while (cpio->entry_bytes_remaining > 0) {
to_write = cpio->entry_bytes_remaining < a->null_length ?
cpio->entry_bytes_remaining : a->null_length;
- ret = (a->compressor.write)(a, a->nulls, to_write);
+ ret = __archive_write_output(a, a->nulls, to_write);
if (ret != ARCHIVE_OK)
return (ret);
cpio->entry_bytes_remaining -= to_write;
}
- ret = (a->compressor.write)(a, a->nulls, cpio->padding);
+ ret = __archive_write_output(a, a->nulls, cpio->padding);
return (ret);
}
archive_entry_free(entry);
if (mtree->buf.length > 32768) {
- ret = (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
+ ret = __archive_write_output(a, mtree->buf.s, mtree->buf.length);
archive_string_empty(&mtree->buf);
} else
ret = ARCHIVE_OK;
archive_write_set_bytes_in_last_block(&a->archive, 1);
- return (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
+ return __archive_write_output(a, mtree->buf.s, mtree->buf.length);
}
static ssize_t
(void)u; /* UNUSED */
exit(1);
}
- r = (a->compressor.write)(a, paxbuff, 512);
+ r = __archive_write_output(a, paxbuff, 512);
if (r != ARCHIVE_OK) {
sparse_list_clear(pax);
pax->entry_bytes_remaining = 0;
pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header));
pax->entry_padding = 0x1ff & (-(int64_t)pax->entry_bytes_remaining);
- r = (a->compressor.write)(a, pax->pax_header.s,
+ r = __archive_write_output(a, pax->pax_header.s,
archive_strlen(&(pax->pax_header)));
if (r != ARCHIVE_OK) {
/* If a write fails, we're pretty much toast. */
}
/* Write the header for main entry. */
- r = (a->compressor.write)(a, ustarbuff, 512);
+ r = __archive_write_output(a, ustarbuff, 512);
if (r != ARCHIVE_OK)
return (r);
* <dir>/GNUSparseFile.<pid>/<original file name>
*
* This function is used for only Sparse file, a file type of which
- * is regular file.
+ * is regular file.
*/
static char *
build_gnu_sparse_name(char *dest, const char *src)
static int
archive_write_pax_finish(struct archive_write *a)
{
- int r;
-
- if (a->compressor.write == NULL)
- return (ARCHIVE_OK);
-
- r = write_nulls(a, 512 * 2);
- return (r);
+ return (write_nulls(a, 512 * 2));
}
static int
while (padding > 0) {
to_write = padding < a->null_length ? padding : a->null_length;
- ret = (a->compressor.write)(a, a->nulls, to_write);
+ ret = __archive_write_output(a, a->nulls, to_write);
if (ret != ARCHIVE_OK)
return (ret);
padding -= to_write;
/*
* According to GNU PAX format 1.0, write a sparse map
- * before the body.
+ * before the body.
*/
if (archive_strlen(&(pax->sparse_map))) {
- ret = (a->compressor.write)(a, pax->sparse_map.s,
+ ret = __archive_write_output(a, pax->sparse_map.s,
archive_strlen(&(pax->sparse_map)));
if (ret != ARCHIVE_OK)
return (ret);
continue;
}
- ret = (a->compressor.write)(a, p, ws);
+ ret = __archive_write_output(a, p, ws);
pax->sparse_list->remaining -= ws;
total += ws;
if (ret != ARCHIVE_OK)
__archive_errx(1, "Out of memory");
if (shar->work.length > ensured) {
- ret = (*a->compressor.write)(a, shar->work.s,
+ ret = __archive_write_output(a, shar->work.s,
shar->work.length);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
if (buf >= buf_end) {
shar->work.length = buf - shar->work.s;
- ret = (*a->compressor.write)(a, shar->work.s,
+ ret = __archive_write_output(a, shar->work.s,
shar->work.length);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
if (shar->work.length < 65536)
continue;
- ret = (*a->compressor.write)(a, shar->work.s,
+ ret = __archive_write_output(a, shar->work.s,
shar->work.length);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
if (shar->work.length < 65536)
return (ARCHIVE_OK);
- ret = (*a->compressor.write)(a, shar->work.s, shar->work.length);
+ ret = __archive_write_output(a, shar->work.s, shar->work.length);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
archive_string_empty(&shar->work);
archive_strcat(&shar->work, "exit\n");
- ret = (*a->compressor.write)(a, shar->work.s, shar->work.length);
+ ret = __archive_write_output(a, shar->work.s, shar->work.length);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1);
if (ret < ARCHIVE_WARN)
return (ret);
- ret2 = (a->compressor.write)(a, buff, 512);
+ ret2 = __archive_write_output(a, buff, 512);
if (ret2 < ARCHIVE_WARN)
return (ret2);
if (ret2 < ret)
static int
archive_write_ustar_finish(struct archive_write *a)
{
- int r;
-
- if (a->compressor.write == NULL)
- return (ARCHIVE_OK);
-
- r = write_nulls(a, 512*2);
- return (r);
+ return (write_nulls(a, 512*2));
}
static int
while (padding > 0) {
to_write = padding < a->null_length ? padding : a->null_length;
- ret = (a->compressor.write)(a, a->nulls, to_write);
+ ret = __archive_write_output(a, a->nulls, to_write);
if (ret != ARCHIVE_OK)
return (ret);
padding -= to_write;
ustar = (struct ustar *)a->format_data;
if (s > ustar->entry_bytes_remaining)
s = ustar->entry_bytes_remaining;
- ret = (a->compressor.write)(a, buff, s);
+ ret = __archive_write_output(a, buff, s);
ustar->entry_bytes_remaining -= s;
if (ret != ARCHIVE_OK)
return (ret);
archive_le32enc(&e.mtime, archive_entry_mtime(entry));
archive_le32enc(&e.atime, archive_entry_atime(entry));
archive_le32enc(&e.ctime, archive_entry_ctime(entry));
-
+
archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_UNIX);
archive_le16enc(&e.unix_size, sizeof(e.unix_uid) + sizeof(e.unix_gid));
archive_le16enc(&e.unix_uid, archive_entry_uid(entry));
archive_le32enc(&d->uncompressed_size, size);
- ret = (a->compressor.write)(a, &h, sizeof(h));
+ ret = __archive_write_output(a, &h, sizeof(h));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
zip->written_bytes += sizeof(h);
return (ARCHIVE_FATAL);
zip->written_bytes += ret;
- ret = (a->compressor.write)(a, &e, sizeof(e));
+ ret = __archive_write_output(a, &e, sizeof(e));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
zip->written_bytes += sizeof(e);
switch (zip->compression) {
case COMPRESSION_STORE:
- ret = (a->compressor.write)(a, buff, s);
+ ret = __archive_write_output(a, buff, s);
if (ret != ARCHIVE_OK) return (ret);
zip->written_bytes += s;
zip->remaining_data_bytes -= s;
if (ret == Z_STREAM_ERROR)
return (ARCHIVE_FATAL);
if (zip->stream.avail_out == 0) {
- ret = (a->compressor.write)(a, zip->buf, zip->len_buf);
+ ret = __archive_write_output(a, zip->buf, zip->len_buf);
if (ret != ARCHIVE_OK)
return (ret);
l->compressed_size += zip->len_buf;
if (ret == Z_STREAM_ERROR)
return (ARCHIVE_FATAL);
reminder = zip->len_buf - zip->stream.avail_out;
- ret = (a->compressor.write)(a, zip->buf, reminder);
+ ret = __archive_write_output(a, zip->buf, reminder);
if (ret != ARCHIVE_OK)
return (ret);
l->compressed_size += reminder;
archive_le32enc(&d->crc32, l->crc32);
archive_le32enc(&d->compressed_size, l->compressed_size);
- ret = (a->compressor.write)(a, d, sizeof(*d));
+ ret = __archive_write_output(a, d, sizeof(*d));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
zip->written_bytes += sizeof(*d);
archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_UNIX);
archive_le16enc(&e.unix_size, 0x0000);
- ret = (a->compressor.write)(a, &h, sizeof(h));
+ ret = __archive_write_output(a, &h, sizeof(h));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
zip->written_bytes += sizeof(h);
return (ARCHIVE_FATAL);
zip->written_bytes += ret;
- ret = (a->compressor.write)(a, &e, sizeof(e));
+ ret = __archive_write_output(a, &e, sizeof(e));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
zip->written_bytes += sizeof(e);
archive_le32enc(&end.offset, offset_start);
/* Writing end of central directory. */
- ret = (a->compressor.write)(a, &end, sizeof(end));
+ ret = __archive_write_output(a, &end, sizeof(end));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
zip->written_bytes += sizeof(end);
type = archive_entry_filetype(entry);
written_bytes = 0;
- ret = (archive->compressor.write)(archive, path, strlen(path));
+ ret = __archive_write_output(archive, path, strlen(path));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
written_bytes += strlen(path);
/* Folders are recognized by a traling slash. */
if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
- ret = (archive->compressor.write)(archive, "/", 1);
+ ret = __archive_write_output(archive, "/", 1);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
written_bytes += 1;