libarchive 3.0.4.2 → 3.0.5.0
raw patch · 200 files changed
+61/−147099 lines, 200 filesdep +hspec-coredep +libarchive-clibdep −unbuildabledep ~tardep ~zlibnew-uploader
Dependencies added: hspec-core, libarchive-clib
Dependencies removed: unbuildable
Dependency ranges changed: tar, zlib
Files
- CHANGELOG.md +4/−0
- bench/Bench.hs +1/−2
- c/archive.h +0/−1212
- c/archive_acl.c +0/−2097
- c/archive_acl_private.h +0/−83
- c/archive_blake2.h +0/−197
- c/archive_blake2_impl.h +0/−161
- c/archive_blake2s_ref.c +0/−369
- c/archive_blake2sp_ref.c +0/−361
- c/archive_check_magic.c +0/−175
- c/archive_cmdline.c +0/−227
- c/archive_cmdline_private.h +0/−47
- c/archive_crc32.h +0/−83
- c/archive_cryptor.c +0/−534
- c/archive_cryptor_private.h +0/−188
- c/archive_digest.c +0/−1565
- c/archive_digest_private.h +0/−426
- c/archive_disk_acl_darwin.c +0/−559
- c/archive_disk_acl_freebsd.c +0/−712
- c/archive_disk_acl_linux.c +0/−760
- c/archive_disk_acl_sunos.c +0/−824
- c/archive_endian.h +0/−195
- c/archive_entry.c +0/−2149
- c/archive_entry.h +0/−723
- c/archive_entry_copy_bhfi.c +0/−75
- c/archive_entry_copy_stat.c +0/−83
- c/archive_entry_link_resolver.c +0/−447
- c/archive_entry_locale.h +0/−92
- c/archive_entry_private.h +0/−200
- c/archive_entry_sparse.c +0/−156
- c/archive_entry_stat.c +0/−118
- c/archive_entry_strmode.c +0/−87
- c/archive_entry_xattr.c +0/−156
- c/archive_getdate.c +0/−1104
- c/archive_getdate.h +0/−39
- c/archive_hmac.c +0/−339
- c/archive_hmac_private.h +0/−119
- c/archive_match.c +0/−1875
- c/archive_openssl_evp_private.h +0/−54
- c/archive_openssl_hmac_private.h +0/−54
- c/archive_options.c +0/−218
- c/archive_options_private.h +0/−51
- c/archive_pack_dev.c +0/−337
- c/archive_pack_dev.h +0/−49
- c/archive_pathmatch.c +0/−463
- c/archive_pathmatch.h +0/−52
- c/archive_platform.h +0/−233
- c/archive_platform_acl.h +0/−55
- c/archive_platform_xattr.h +0/−47
- c/archive_ppmd7.c +0/−1168
- c/archive_ppmd7_private.h +0/−119
- c/archive_ppmd8.c +0/−1287
- c/archive_ppmd8_private.h +0/−148
- c/archive_ppmd_private.h +0/−151
- c/archive_private.h +0/−180
- c/archive_random.c +0/−301
- c/archive_random_private.h +0/−36
- c/archive_rb.c +0/−709
- c/archive_rb.h +0/−113
- c/archive_read.c +0/−1756
- c/archive_read_add_passphrase.c +0/−190
- c/archive_read_append_filter.c +0/−204
- c/archive_read_data_into_fd.c +0/−144
- c/archive_read_disk_entry_from_file.c +0/−1086
- c/archive_read_disk_posix.c +0/−2760
- c/archive_read_disk_private.h +0/−98
- c/archive_read_disk_set_standard_lookup.c +0/−313
- c/archive_read_disk_windows.c +0/−2547
- c/archive_read_extract.c +0/−60
- c/archive_read_extract2.c +0/−155
- c/archive_read_open_fd.c +0/−211
- c/archive_read_open_file.c +0/−180
- c/archive_read_open_filename.c +0/−586
- c/archive_read_open_memory.c +0/−186
- c/archive_read_private.h +0/−267
- c/archive_read_set_format.c +0/−117
- c/archive_read_set_options.c +0/−133
- c/archive_read_support_filter_all.c +0/−85
- c/archive_read_support_filter_by_code.c +0/−83
- c/archive_read_support_filter_bzip2.c +0/−365
- c/archive_read_support_filter_compress.c +0/−452
- c/archive_read_support_filter_grzip.c +0/−112
- c/archive_read_support_filter_gzip.c +0/−536
- c/archive_read_support_filter_lrzip.c +0/−122
- c/archive_read_support_filter_lz4.c +0/−742
- c/archive_read_support_filter_lzop.c +0/−499
- c/archive_read_support_filter_none.c +0/−52
- c/archive_read_support_filter_program.c +0/−496
- c/archive_read_support_filter_rpm.c +0/−287
- c/archive_read_support_filter_uu.c +0/−683
- c/archive_read_support_filter_xz.c +0/−793
- c/archive_read_support_filter_zstd.c +0/−297
- c/archive_read_support_format_7zip.c +0/−4074
- c/archive_read_support_format_all.c +0/−89
- c/archive_read_support_format_ar.c +0/−638
- c/archive_read_support_format_by_code.c +0/−92
- c/archive_read_support_format_cab.c +0/−3228
- c/archive_read_support_format_cpio.c +0/−1104
- c/archive_read_support_format_empty.c +0/−96
- c/archive_read_support_format_iso9660.c +0/−3279
- c/archive_read_support_format_lha.c +0/−2919
- c/archive_read_support_format_mtree.c +0/−2156
- c/archive_read_support_format_rar.c +0/−3788
- c/archive_read_support_format_rar5.c +0/−4251
- c/archive_read_support_format_raw.c +0/−192
- c/archive_read_support_format_tar.c +0/−2946
- c/archive_read_support_format_warc.c +0/−848
- c/archive_read_support_format_xar.c +0/−3332
- c/archive_read_support_format_zip.c +0/−4270
- c/archive_string.c +0/−4244
- c/archive_string.h +0/−243
- c/archive_string_composition.h +0/−2292
- c/archive_string_sprintf.c +0/−192
- c/archive_util.c +0/−704
- c/archive_version_details.c +0/−151
- c/archive_virtual.c +0/−163
- c/archive_windows.c +0/−938
- c/archive_windows.h +0/−315
- c/archive_write.c +0/−859
- c/archive_write_add_filter.c +0/−72
- c/archive_write_add_filter_b64encode.c +0/−304
- c/archive_write_add_filter_by_name.c +0/−77
- c/archive_write_add_filter_bzip2.c +0/−401
- c/archive_write_add_filter_compress.c +0/−447
- c/archive_write_add_filter_grzip.c +0/−135
- c/archive_write_add_filter_gzip.c +0/−442
- c/archive_write_add_filter_lrzip.c +0/−197
- c/archive_write_add_filter_lz4.c +0/−700
- c/archive_write_add_filter_lzop.c +0/−478
- c/archive_write_add_filter_none.c +0/−43
- c/archive_write_add_filter_program.c +0/−391
- c/archive_write_add_filter_uuencode.c +0/−295
- c/archive_write_add_filter_xz.c +0/−545
- c/archive_write_add_filter_zstd.c +0/−467
- c/archive_write_disk_posix.c +0/−4759
- c/archive_write_disk_private.h +0/−45
- c/archive_write_disk_set_standard_lookup.c +0/−263
- c/archive_write_disk_windows.c +0/−2911
- c/archive_write_open_fd.c +0/−146
- c/archive_write_open_file.c +0/−111
- c/archive_write_open_filename.c +0/−270
- c/archive_write_open_memory.c +0/−115
- c/archive_write_private.h +0/−166
- c/archive_write_set_format.c +0/−125
- c/archive_write_set_format_7zip.c +0/−2322
- c/archive_write_set_format_ar.c +0/−570
- c/archive_write_set_format_by_name.c +0/−94
- c/archive_write_set_format_cpio.c +0/−11
- c/archive_write_set_format_cpio_binary.c +0/−610
- c/archive_write_set_format_cpio_newc.c +0/−457
- c/archive_write_set_format_cpio_odc.c +0/−500
- c/archive_write_set_format_filter_by_ext.c +0/−142
- c/archive_write_set_format_gnutar.c +0/−755
- c/archive_write_set_format_iso9660.c +0/−8161
- c/archive_write_set_format_mtree.c +0/−2217
- c/archive_write_set_format_pax.c +0/−2063
- c/archive_write_set_format_private.h +0/−42
- c/archive_write_set_format_raw.c +0/−125
- c/archive_write_set_format_shar.c +0/−641
- c/archive_write_set_format_ustar.c +0/−758
- c/archive_write_set_format_v7tar.c +0/−638
- c/archive_write_set_format_warc.c +0/−444
- c/archive_write_set_format_xar.c +0/−3255
- c/archive_write_set_format_zip.c +0/−1693
- c/archive_write_set_options.c +0/−130
- c/archive_write_set_passphrase.c +0/−95
- c/archive_xxhash.h +0/−48
- c/autoconf-darwin/config.h +0/−1520
- c/autoconf-freebsd/config.h +0/−1509
- c/autoconf-linux/config.h +0/−1520
- c/autoconf-windows/config.h +0/−1521
- c/config_freebsd.h +0/−276
- c/filter_fork.h +0/−46
- c/filter_fork_posix.c +0/−240
- c/filter_fork_windows.c +0/−245
- c/xxhash.c +0/−529
- c/zlib/adler32.c +0/−186
- c/zlib/compress.c +0/−86
- c/zlib/crc32.c +0/−442
- c/zlib/crc32.h +0/−441
- c/zlib/deflate.c +0/−2163
- c/zlib/deflate.h +0/−349
- c/zlib/gzguts.h +0/−218
- c/zlib/infback.c +0/−640
- c/zlib/inffast.c +0/−323
- c/zlib/inffast.h +0/−11
- c/zlib/inffixed.h +0/−94
- c/zlib/inflate.c +0/−1561
- c/zlib/inflate.h +0/−125
- c/zlib/inftrees.c +0/−304
- c/zlib/inftrees.h +0/−62
- c/zlib/trees.c +0/−1203
- c/zlib/trees.h +0/−128
- c/zlib/uncompr.c +0/−93
- c/zlib/zconf.h +0/−534
- c/zlib/zlib.h +0/−1912
- c/zlib/zutil.c +0/−325
- c/zlib/zutil.h +0/−271
- libarchive.cabal +14/−182
- src/Codec/Archive/Foreign/Archive.chs +42/−0
CHANGELOG.md view
@@ -1,5 +1,9 @@ # libarchive +# 3.0.5.0++ * use libarchive-clib package+ # 3.0.4.2 * Package bounds for Hackage
bench/Bench.hs view
@@ -1,9 +1,8 @@ module Main (main) where import Codec.Archive-import Codec.Archive.Tar (Entries (..), FormatError)+import Codec.Archive.Tar (Entries, FormatError, GenEntries (..)) import qualified Codec.Archive.Tar as Tar-import Control.Monad (void) import Control.Monad.IO.Class (liftIO) import Criterion.Main import qualified Data.ByteString.Lazy as BSL
− c/archive.h
@@ -1,1212 +0,0 @@-/*-- * 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.- *- * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.50 2008/05/26 17:00:22 kientzle Exp $- */--#ifndef ARCHIVE_H_INCLUDED-#define ARCHIVE_H_INCLUDED--/*- * The version number is expressed as a single integer that makes it- * easy to compare versions at build time: for version a.b.c, the- * version number is printf("%d%03d%03d",a,b,c). For example, if you- * know your application requires version 2.12.108 or later, you can- * assert that ARCHIVE_VERSION_NUMBER >= 2012108.- */-/* Note: Compiler will complain if this does not match archive_entry.h! */-#define ARCHIVE_VERSION_NUMBER 3007001--#include <sys/stat.h>-#include <stddef.h> /* for wchar_t */-#include <stdio.h> /* For FILE * */-#include <time.h> /* For time_t */--/*- * Note: archive.h is for use outside of libarchive; the configuration- * headers (config.h, archive_platform.h, etc.) are purely internal.- * Do NOT use HAVE_XXX configuration macros to control the behavior of- * this header! If you must conditionalize, use predefined compiler and/or- * platform macros.- */-#if defined(__BORLANDC__) && __BORLANDC__ >= 0x560-# include <stdint.h>-#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) && !defined(_SCO_DS) && !defined(__osf__) && !defined(__CLANG_INTTYPES_H)-# include <inttypes.h>-#endif--/* Get appropriate definitions of 64-bit integer */-#if !defined(__LA_INT64_T_DEFINED)-/* Older code relied on the __LA_INT64_T macro; after 4.0 we'll switch to the typedef exclusively. */-# if ARCHIVE_VERSION_NUMBER < 4000000-#define __LA_INT64_T la_int64_t-# endif-#define __LA_INT64_T_DEFINED-# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)-typedef __int64 la_int64_t;-# else-# include <unistd.h> /* ssize_t */-# if defined(_SCO_DS) || defined(__osf__)-typedef long long la_int64_t;-# else-typedef int64_t la_int64_t;-# endif-# endif-#endif--/* The la_ssize_t should match the type used in 'struct stat' */-#if !defined(__LA_SSIZE_T_DEFINED)-/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */-# if ARCHIVE_VERSION_NUMBER < 4000000-#define __LA_SSIZE_T la_ssize_t-# endif-#define __LA_SSIZE_T_DEFINED-# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)-# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)-typedef ssize_t la_ssize_t;-# elif defined(_WIN64)-typedef __int64 la_ssize_t;-# else-typedef long la_ssize_t;-# endif-# else-# include <unistd.h> /* ssize_t */-typedef ssize_t la_ssize_t;-# endif-#endif--/* Large file support for Android */-#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__)-#include "android_lf.h"-#endif--/*- * On Windows, define LIBARCHIVE_STATIC if you're building or using a- * .lib. The default here assumes you're building a DLL. Only- * libarchive source should ever define __LIBARCHIVE_BUILD.- */-#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC)-# ifdef __LIBARCHIVE_BUILD-# ifdef __GNUC__-# define __LA_DECL __attribute__((dllexport)) extern-# else-# define __LA_DECL __declspec(dllexport)-# endif-# else-# ifdef __GNUC__-# define __LA_DECL-# else-# define __LA_DECL __declspec(dllimport)-# endif-# endif-#elif defined __LIBARCHIVE_ENABLE_VISIBILITY-# define __LA_DECL __attribute__((visibility("default")))-#else-/* Static libraries or non-Windows needs no special declaration. */-# define __LA_DECL-#endif--#if defined(__GNUC__) && __GNUC__ >= 3 && !defined(__MINGW32__)-#define __LA_PRINTF(fmtarg, firstvararg) \- __attribute__((__format__ (__printf__, fmtarg, firstvararg)))-#else-#define __LA_PRINTF(fmtarg, firstvararg) /* nothing */-#endif--#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1-# define __LA_DEPRECATED __attribute__((deprecated))-#else-# define __LA_DEPRECATED-#endif--#ifdef __cplusplus-extern "C" {-#endif--/*- * The version number is provided as both a macro and a function.- * The macro identifies the installed header; the function identifies- * the library version (which may not be the same if you're using a- * dynamically-linked version of the library). Of course, if the- * header and library are very different, you should expect some- * strangeness. Don't do that.- */-__LA_DECL int archive_version_number(void);--/*- * Textual name/version of the library, useful for version displays.- */-#define ARCHIVE_VERSION_ONLY_STRING "3.7.1"-#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING-__LA_DECL const char * archive_version_string(void);--/*- * Detailed textual name/version of the library and its dependencies.- * This has the form:- * "libarchive x.y.z zlib/a.b.c liblzma/d.e.f ... etc ..."- * the list of libraries described here will vary depending on how- * libarchive was compiled.- */-__LA_DECL const char * archive_version_details(void);--/*- * Returns NULL if libarchive was compiled without the associated library.- * Otherwise, returns the version number that libarchive was compiled- * against.- */-__LA_DECL const char * archive_zlib_version(void);-__LA_DECL const char * archive_liblzma_version(void);-__LA_DECL const char * archive_bzlib_version(void);-__LA_DECL const char * archive_liblz4_version(void);-__LA_DECL const char * archive_libzstd_version(void);--/* Declare our basic types. */-struct archive;-struct archive_entry;--/*- * Error codes: Use archive_errno() and archive_error_string()- * to retrieve details. Unless specified otherwise, all functions- * that return 'int' use these codes.- */-#define ARCHIVE_EOF 1 /* Found end of archive. */-#define ARCHIVE_OK 0 /* Operation was successful. */-#define ARCHIVE_RETRY (-10) /* Retry might succeed. */-#define ARCHIVE_WARN (-20) /* Partial success. */-/* For example, if write_header "fails", then you can't push data. */-#define ARCHIVE_FAILED (-25) /* Current operation cannot complete. */-/* But if write_header is "fatal," then this archive is dead and useless. */-#define ARCHIVE_FATAL (-30) /* No more operations are possible. */--/*- * As far as possible, archive_errno returns standard platform errno codes.- * Of course, the details vary by platform, so the actual definitions- * here are stored in "archive_platform.h". The symbols are listed here- * for reference; as a rule, clients should not need to know the exact- * platform-dependent error code.- */-/* Unrecognized or invalid file format. */-/* #define ARCHIVE_ERRNO_FILE_FORMAT */-/* Illegal usage of the library. */-/* #define ARCHIVE_ERRNO_PROGRAMMER_ERROR */-/* Unknown or unclassified error. */-/* #define ARCHIVE_ERRNO_MISC */--/*- * Callbacks are invoked to automatically read/skip/write/open/close the- * archive. You can provide your own for complex tasks (like breaking- * archives across multiple tapes) or use standard ones built into the- * library.- */--/* Returns pointer and size of next block of data from archive. */-typedef la_ssize_t archive_read_callback(struct archive *,- void *_client_data, const void **_buffer);--/* Skips at most request bytes from archive and returns the skipped amount.- * This may skip fewer bytes than requested; it may even skip zero bytes.- * If you do skip fewer bytes than requested, libarchive will invoke your- * read callback and discard data as necessary to make up the full skip.- */-typedef la_int64_t archive_skip_callback(struct archive *,- void *_client_data, la_int64_t request);--/* Seeks to specified location in the file and returns the position.- * Whence values are SEEK_SET, SEEK_CUR, SEEK_END from stdio.h.- * Return ARCHIVE_FATAL if the seek fails for any reason.- */-typedef la_int64_t archive_seek_callback(struct archive *,- void *_client_data, la_int64_t offset, int whence);--/* Returns size actually written, zero on EOF, -1 on error. */-typedef la_ssize_t archive_write_callback(struct archive *,- void *_client_data,- const void *_buffer, size_t _length);--typedef int archive_open_callback(struct archive *, void *_client_data);--typedef int archive_close_callback(struct archive *, void *_client_data);--typedef int archive_free_callback(struct archive *, void *_client_data);--/* Switches from one client data object to the next/prev client data object.- * This is useful for reading from different data blocks such as a set of files- * that make up one large file.- */-typedef int archive_switch_callback(struct archive *, void *_client_data1,- void *_client_data2);--/*- * Returns a passphrase used for encryption or decryption, NULL on nothing- * to do and give it up.- */-typedef const char *archive_passphrase_callback(struct archive *,- void *_client_data);--/*- * Codes to identify various stream filters.- */-#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-#define ARCHIVE_FILTER_LZIP 9-#define ARCHIVE_FILTER_LRZIP 10-#define ARCHIVE_FILTER_LZOP 11-#define ARCHIVE_FILTER_GRZIP 12-#define ARCHIVE_FILTER_LZ4 13-#define ARCHIVE_FILTER_ZSTD 14--#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-#define ARCHIVE_COMPRESSION_LZIP ARCHIVE_FILTER_LZIP-#define ARCHIVE_COMPRESSION_LRZIP ARCHIVE_FILTER_LRZIP-#endif--/*- * Codes returned by archive_format.- *- * Top 16 bits identifies the format family (e.g., "tar"); lower- * 16 bits indicate the variant. This is updated by read_next_header.- * Note that the lower 16 bits will often vary from entry to entry.- * In some cases, this variation occurs as libarchive learns more about- * the archive (for example, later entries might utilize extensions that- * weren't necessary earlier in the archive; in this case, libarchive- * will change the format code to indicate the extended format that- * was used). In other cases, it's because different tools have- * modified the archive and so different parts of the archive- * actually have slightly different formats. (Both tar and cpio store- * format codes in each entry, so it is quite possible for each- * entry to be in a different format.)- */-#define ARCHIVE_FORMAT_BASE_MASK 0xff0000-#define ARCHIVE_FORMAT_CPIO 0x10000-#define ARCHIVE_FORMAT_CPIO_POSIX (ARCHIVE_FORMAT_CPIO | 1)-#define ARCHIVE_FORMAT_CPIO_BIN_LE (ARCHIVE_FORMAT_CPIO | 2)-#define ARCHIVE_FORMAT_CPIO_BIN_BE (ARCHIVE_FORMAT_CPIO | 3)-#define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4)-#define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5)-#define ARCHIVE_FORMAT_CPIO_AFIO_LARGE (ARCHIVE_FORMAT_CPIO | 6)-#define ARCHIVE_FORMAT_CPIO_PWB (ARCHIVE_FORMAT_CPIO | 7)-#define ARCHIVE_FORMAT_SHAR 0x20000-#define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1)-#define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2)-#define ARCHIVE_FORMAT_TAR 0x30000-#define ARCHIVE_FORMAT_TAR_USTAR (ARCHIVE_FORMAT_TAR | 1)-#define ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE (ARCHIVE_FORMAT_TAR | 2)-#define ARCHIVE_FORMAT_TAR_PAX_RESTRICTED (ARCHIVE_FORMAT_TAR | 3)-#define ARCHIVE_FORMAT_TAR_GNUTAR (ARCHIVE_FORMAT_TAR | 4)-#define ARCHIVE_FORMAT_ISO9660 0x40000-#define ARCHIVE_FORMAT_ISO9660_ROCKRIDGE (ARCHIVE_FORMAT_ISO9660 | 1)-#define ARCHIVE_FORMAT_ZIP 0x50000-#define ARCHIVE_FORMAT_EMPTY 0x60000-#define ARCHIVE_FORMAT_AR 0x70000-#define ARCHIVE_FORMAT_AR_GNU (ARCHIVE_FORMAT_AR | 1)-#define ARCHIVE_FORMAT_AR_BSD (ARCHIVE_FORMAT_AR | 2)-#define ARCHIVE_FORMAT_MTREE 0x80000-#define ARCHIVE_FORMAT_RAW 0x90000-#define ARCHIVE_FORMAT_XAR 0xA0000-#define ARCHIVE_FORMAT_LHA 0xB0000-#define ARCHIVE_FORMAT_CAB 0xC0000-#define ARCHIVE_FORMAT_RAR 0xD0000-#define ARCHIVE_FORMAT_7ZIP 0xE0000-#define ARCHIVE_FORMAT_WARC 0xF0000-#define ARCHIVE_FORMAT_RAR_V5 0x100000--/*- * Codes returned by archive_read_format_capabilities().- *- * This list can be extended with values between 0 and 0xffff.- * The original purpose of this list was to let different archive- * format readers expose their general capabilities in terms of- * encryption.- */-#define ARCHIVE_READ_FORMAT_CAPS_NONE (0) /* no special capabilities */-#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA (1<<0) /* reader can detect encrypted data */-#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA (1<<1) /* reader can detect encryptable metadata (pathname, mtime, etc.) */--/*- * Codes returned by archive_read_has_encrypted_entries().- *- * In case the archive does not support encryption detection at all- * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. If the reader- * for some other reason (e.g. not enough bytes read) cannot say if- * there are encrypted entries, ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW- * is returned.- */-#define ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED -2-#define ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW -1--/*-- * Basic outline for reading an archive:- * 1) Ask archive_read_new for an archive reader object.- * 2) Update any global properties as appropriate.- * In particular, you'll certainly want to call appropriate- * archive_read_support_XXX functions.- * 3) Call archive_read_open_XXX to open the archive- * 4) Repeatedly call archive_read_next_header to get information about- * successive archive entries. Call archive_read_data to extract- * data for entries of interest.- * 5) Call archive_read_free to end processing.- */-__LA_DECL struct archive *archive_read_new(void);--/*- * The archive_read_support_XXX calls enable auto-detect for this- * archive handle. They also link in the necessary support code.- * For example, if you don't want bzlib linked in, don't invoke- * support_compression_bzip2(). The "all" functions provide the- * obvious shorthand.- */--#if ARCHIVE_VERSION_NUMBER < 4000000-__LA_DECL int archive_read_support_compression_all(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_read_support_compression_bzip2(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_read_support_compression_compress(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_read_support_compression_gzip(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_read_support_compression_lzip(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_read_support_compression_lzma(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_read_support_compression_none(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_read_support_compression_program(struct archive *,- const char *command) __LA_DEPRECATED;-__LA_DECL int archive_read_support_compression_program_signature- (struct archive *, const char *,- const void * /* match */, size_t) __LA_DEPRECATED;--__LA_DECL int archive_read_support_compression_rpm(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_read_support_compression_uu(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_read_support_compression_xz(struct archive *)- __LA_DEPRECATED;-#endif--__LA_DECL int archive_read_support_filter_all(struct archive *);-__LA_DECL int archive_read_support_filter_by_code(struct archive *, int);-__LA_DECL int archive_read_support_filter_bzip2(struct archive *);-__LA_DECL int archive_read_support_filter_compress(struct archive *);-__LA_DECL int archive_read_support_filter_gzip(struct archive *);-__LA_DECL int archive_read_support_filter_grzip(struct archive *);-__LA_DECL int archive_read_support_filter_lrzip(struct archive *);-__LA_DECL int archive_read_support_filter_lz4(struct archive *);-__LA_DECL int archive_read_support_filter_lzip(struct archive *);-__LA_DECL int archive_read_support_filter_lzma(struct archive *);-__LA_DECL int archive_read_support_filter_lzop(struct archive *);-__LA_DECL int archive_read_support_filter_none(struct archive *);-__LA_DECL int archive_read_support_filter_program(struct archive *,- const char *command);-__LA_DECL int archive_read_support_filter_program_signature- (struct archive *, const char * /* cmd */,- const void * /* match */, size_t);-__LA_DECL int archive_read_support_filter_rpm(struct archive *);-__LA_DECL int archive_read_support_filter_uu(struct archive *);-__LA_DECL int archive_read_support_filter_xz(struct archive *);-__LA_DECL int archive_read_support_filter_zstd(struct archive *);--__LA_DECL int archive_read_support_format_7zip(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_by_code(struct archive *, int);-__LA_DECL int archive_read_support_format_cab(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_lha(struct archive *);-__LA_DECL int archive_read_support_format_mtree(struct archive *);-__LA_DECL int archive_read_support_format_rar(struct archive *);-__LA_DECL int archive_read_support_format_rar5(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_warc(struct archive *);-__LA_DECL int archive_read_support_format_xar(struct archive *);-/* archive_read_support_format_zip() enables both streamable and seekable- * zip readers. */-__LA_DECL int archive_read_support_format_zip(struct archive *);-/* Reads Zip archives as stream from beginning to end. Doesn't- * correctly handle SFX ZIP files or ZIP archives that have been modified- * in-place. */-__LA_DECL int archive_read_support_format_zip_streamable(struct archive *);-/* Reads starting from central directory; requires seekable input. */-__LA_DECL int archive_read_support_format_zip_seekable(struct archive *);--/* Functions to manually set the format and filters to be used. This is- * useful to bypass the bidding process when the format and filters to use- * is known in advance.- */-__LA_DECL int archive_read_set_format(struct archive *, int);-__LA_DECL int archive_read_append_filter(struct archive *, int);-__LA_DECL int archive_read_append_filter_program(struct archive *,- const char *);-__LA_DECL int archive_read_append_filter_program_signature- (struct archive *, const char *, const void * /* match */, size_t);--/* Set various callbacks. */-__LA_DECL int archive_read_set_open_callback(struct archive *,- archive_open_callback *);-__LA_DECL int archive_read_set_read_callback(struct archive *,- archive_read_callback *);-__LA_DECL int archive_read_set_seek_callback(struct archive *,- archive_seek_callback *);-__LA_DECL int archive_read_set_skip_callback(struct archive *,- archive_skip_callback *);-__LA_DECL int archive_read_set_close_callback(struct archive *,- archive_close_callback *);-/* Callback used to switch between one data object to the next */-__LA_DECL int archive_read_set_switch_callback(struct archive *,- archive_switch_callback *);--/* This sets the first data object. */-__LA_DECL int archive_read_set_callback_data(struct archive *, void *);-/* This sets data object at specified index */-__LA_DECL int archive_read_set_callback_data2(struct archive *, void *,- unsigned int);-/* This adds a data object at the specified index. */-__LA_DECL int archive_read_add_callback_data(struct archive *, void *,- unsigned int);-/* This appends a data object to the end of list */-__LA_DECL int archive_read_append_callback_data(struct archive *, void *);-/* This prepends a data object to the beginning of list */-__LA_DECL int archive_read_prepend_callback_data(struct archive *, void *);--/* Opening freezes the callbacks. */-__LA_DECL int archive_read_open1(struct archive *);--/* Convenience wrappers around the above. */-__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,- archive_open_callback *, archive_read_callback *,- archive_skip_callback *, archive_close_callback *);--/*- * A variety of shortcuts that invoke archive_read_open() with- * canned callbacks suitable for common situations. The ones that- * 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 *,- const char *_filename, size_t _block_size);-/* Use this for reading multivolume files by filenames.- * NOTE: Must be NULL terminated. Sorting is NOT done. */-__LA_DECL int archive_read_open_filenames(struct archive *,- const char **_filenames, size_t _block_size);-__LA_DECL int archive_read_open_filename_w(struct archive *,- const wchar_t *_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 *,- const char *_filename, size_t _block_size) __LA_DEPRECATED;-/* Read an archive that's stored in memory. */-__LA_DECL int archive_read_open_memory(struct archive *,- const 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, const 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,- 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);--/* Parses and returns next entry header. */-__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 *,- struct archive_entry *);--/*- * Retrieve the byte offset in UNCOMPRESSED data where last-read- * header started.- */-__LA_DECL la_int64_t archive_read_header_position(struct archive *);--/*- * Returns 1 if the archive contains at least one encrypted entry.- * If the archive format not support encryption at all- * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned.- * If for any other reason (e.g. not enough data read so far)- * we cannot say whether there are encrypted entries, then- * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned.- * In general, this function will return values below zero when the- * reader is uncertain or totally incapable of encryption support.- * When this function returns 0 you can be sure that the reader- * supports encryption detection but no encrypted entries have- * been found yet.- *- * NOTE: If the metadata/header of an archive is also encrypted, you- * cannot rely on the number of encrypted entries. That is why this- * function does not return the number of encrypted entries but#- * just shows that there are some.- */-__LA_DECL int archive_read_has_encrypted_entries(struct archive *);--/*- * Returns a bitmask of capabilities that are supported by the archive format reader.- * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned.- */-__LA_DECL int archive_read_format_capabilities(struct archive *);--/* Read data from the body of an entry. Similar to read(2). */-__LA_DECL la_ssize_t archive_read_data(struct archive *,- void *, size_t);--/* Seek within the body of an entry. Similar to lseek(2). */-__LA_DECL la_int64_t archive_seek_data(struct archive *, la_int64_t, int);--/*- * A zero-copy version of archive_read_data that also exposes the file offset- * of each returned block. Note that the client has no way to specify- * the desired size of the block. The API does guarantee that offsets will- * be strictly increasing and that returned blocks will not overlap.- */-__LA_DECL int archive_read_data_block(struct archive *a,- const void **buff, size_t *size, la_int64_t *offset);--/*-- * Some convenience functions that are built on archive_read_data:- * 'skip': skips entire entry- * '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_fd(struct archive *, int fd);--/*- * Set read options.- */-/* Apply option to the format only. */-__LA_DECL int archive_read_set_format_option(struct archive *_a,- const char *m, const char *o,- const char *v);-/* Apply option to the filter only. */-__LA_DECL int archive_read_set_filter_option(struct archive *_a,- const char *m, const char *o,- const char *v);-/* Apply option to both the format and the filter. */-__LA_DECL int archive_read_set_option(struct archive *_a,- const char *m, const char *o,- const char *v);-/* Apply option string to both the format and the filter. */-__LA_DECL int archive_read_set_options(struct archive *_a,- const char *opts);--/*- * Add a decryption passphrase.- */-__LA_DECL int archive_read_add_passphrase(struct archive *, const char *);-__LA_DECL int archive_read_set_passphrase_callback(struct archive *,- void *client_data, archive_passphrase_callback *);---/*-- * Convenience function to recreate the current entry (whose header- * has just been read) on disk.- *- * This does quite a bit more than just copy data to disk. It also:- * - Creates intermediate directories as required.- * - Manages directory permissions: non-writable directories will- * be initially created with write permission enabled; when the- * archive is closed, dir permissions are edited to the values specified- * in the archive.- * - Checks hardlinks: hardlinks will not be extracted unless the- * linked-to file was also extracted within the same session. (TODO)- */--/* The "flags" argument selects optional behavior, 'OR' the flags you want. */--/* Default: Do not try to set owner/group. */-#define ARCHIVE_EXTRACT_OWNER (0x0001)-/* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */-#define ARCHIVE_EXTRACT_PERM (0x0002)-/* Default: Do not restore mtime/atime. */-#define ARCHIVE_EXTRACT_TIME (0x0004)-/* Default: Replace existing files. */-#define ARCHIVE_EXTRACT_NO_OVERWRITE (0x0008)-/* Default: Try create first, unlink only if create fails with EEXIST. */-#define ARCHIVE_EXTRACT_UNLINK (0x0010)-/* Default: Do not restore ACLs. */-#define ARCHIVE_EXTRACT_ACL (0x0020)-/* Default: Do not restore fflags. */-#define ARCHIVE_EXTRACT_FFLAGS (0x0040)-/* Default: Do not restore xattrs. */-#define ARCHIVE_EXTRACT_XATTR (0x0080)-/* Default: Do not try to guard against extracts redirected by symlinks. */-/* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */-#define ARCHIVE_EXTRACT_SECURE_SYMLINKS (0x0100)-/* Default: Do not reject entries with '..' as path elements. */-#define ARCHIVE_EXTRACT_SECURE_NODOTDOT (0x0200)-/* Default: Create parent directories as needed. */-#define ARCHIVE_EXTRACT_NO_AUTODIR (0x0400)-/* Default: Overwrite files, even if one on disk is newer. */-#define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (0x0800)-/* Detect blocks of 0 and write holes instead. */-#define ARCHIVE_EXTRACT_SPARSE (0x1000)-/* Default: Do not restore Mac extended metadata. */-/* This has no effect except on Mac OS. */-#define ARCHIVE_EXTRACT_MAC_METADATA (0x2000)-/* Default: Use HFS+ compression if it was compressed. */-/* This has no effect except on Mac OS v10.6 or later. */-#define ARCHIVE_EXTRACT_NO_HFS_COMPRESSION (0x4000)-/* Default: Do not use HFS+ compression if it was not compressed. */-/* This has no effect except on Mac OS v10.6 or later. */-#define ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED (0x8000)-/* Default: Do not reject entries with absolute paths */-#define ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS (0x10000)-/* Default: Do not clear no-change flags when unlinking object */-#define ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS (0x20000)-/* Default: Do not extract atomically (using rename) */-#define ARCHIVE_EXTRACT_SAFE_WRITES (0x40000)--__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,- int flags);-__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);--/* Record the dev/ino of a file that will not be written. This is- * generally set to the dev/ino of the archive being read. */-__LA_DECL void archive_read_extract_set_skip_file(struct archive *,- la_int64_t, la_int64_t);--/* Close the file and release most resources. */-__LA_DECL int archive_read_close(struct archive *);-/* Release all resources and destroy the object. */-/* Note that archive_read_free will call archive_read_close for you. */-__LA_DECL int archive_read_free(struct archive *);-#if ARCHIVE_VERSION_NUMBER < 4000000-/* Synonym for archive_read_free() for backwards compatibility. */-__LA_DECL int archive_read_finish(struct archive *) __LA_DEPRECATED;-#endif--/*-- * To create an archive:- * 1) Ask archive_write_new for an archive writer object.- * 2) Set any global properties. In particular, you should set- * the compression and format to use.- * 3) Call archive_write_open to open the file (most people- * will use archive_write_open_file or archive_write_open_fd,- * which provide convenient canned I/O callbacks for you).- * 4) For each entry:- * - construct an appropriate struct archive_entry structure- * - archive_write_header to write the header- * - archive_write_data to write the entry data- * 5) archive_write_close to close the output- * 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 *,- int bytes_per_block);-__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 *,- int bytes_in_last_block);-__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 *,- la_int64_t, la_int64_t);--#if ARCHIVE_VERSION_NUMBER < 4000000-__LA_DECL int archive_write_set_compression_bzip2(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_write_set_compression_compress(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_write_set_compression_gzip(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_write_set_compression_lzip(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_write_set_compression_lzma(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_write_set_compression_none(struct archive *)- __LA_DEPRECATED;-__LA_DECL int archive_write_set_compression_program(struct archive *,- const char *cmd) __LA_DEPRECATED;-__LA_DECL int archive_write_set_compression_xz(struct archive *)- __LA_DEPRECATED;-#endif--/* A convenience function to set the filter based on the code. */-__LA_DECL int archive_write_add_filter(struct archive *, int filter_code);-__LA_DECL int archive_write_add_filter_by_name(struct archive *,- const char *name);-__LA_DECL int archive_write_add_filter_b64encode(struct archive *);-__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_grzip(struct archive *);-__LA_DECL int archive_write_add_filter_gzip(struct archive *);-__LA_DECL int archive_write_add_filter_lrzip(struct archive *);-__LA_DECL int archive_write_add_filter_lz4(struct archive *);-__LA_DECL int archive_write_add_filter_lzip(struct archive *);-__LA_DECL int archive_write_add_filter_lzma(struct archive *);-__LA_DECL int archive_write_add_filter_lzop(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_add_filter_uuencode(struct archive *);-__LA_DECL int archive_write_add_filter_xz(struct archive *);-__LA_DECL int archive_write_add_filter_zstd(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 *,- const char *name);-/* To minimize link pollution, use one or more of the following. */-__LA_DECL int archive_write_set_format_7zip(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_bin(struct archive *);-__LA_DECL int archive_write_set_format_cpio_newc(struct archive *);-__LA_DECL int archive_write_set_format_cpio_odc(struct archive *);-__LA_DECL int archive_write_set_format_cpio_pwb(struct archive *);-__LA_DECL int archive_write_set_format_gnutar(struct archive *);-__LA_DECL int archive_write_set_format_iso9660(struct archive *);-__LA_DECL int archive_write_set_format_mtree(struct archive *);-__LA_DECL int archive_write_set_format_mtree_classic(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_raw(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_v7tar(struct archive *);-__LA_DECL int archive_write_set_format_warc(struct archive *);-__LA_DECL int archive_write_set_format_xar(struct archive *);-__LA_DECL int archive_write_set_format_zip(struct archive *);-__LA_DECL int archive_write_set_format_filter_by_ext(struct archive *a, const char *filename);-__LA_DECL int archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext);-__LA_DECL int archive_write_zip_set_compression_deflate(struct archive *);-__LA_DECL int archive_write_zip_set_compression_store(struct archive *);-/* Deprecated; use archive_write_open2 instead */-__LA_DECL int archive_write_open(struct archive *, void *,- archive_open_callback *, archive_write_callback *,- archive_close_callback *);-__LA_DECL int archive_write_open2(struct archive *, void *,- archive_open_callback *, archive_write_callback *,- archive_close_callback *, archive_free_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_filename_w(struct archive *,- const wchar_t *_file);-/* A deprecated synonym for archive_write_open_filename() */-__LA_DECL int archive_write_open_file(struct archive *, const char *_file)- __LA_DEPRECATED;-__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 *,- 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 *,- struct archive_entry *);-__LA_DECL la_ssize_t archive_write_data(struct archive *,- const void *, size_t);--/* This interface is currently only available for archive_write_disk handles. */-__LA_DECL la_ssize_t archive_write_data_block(struct archive *,- const void *, size_t, la_int64_t);--__LA_DECL int archive_write_finish_entry(struct archive *);-__LA_DECL int archive_write_close(struct archive *);-/* Marks the archive as FATAL so that a subsequent free() operation- * won't try to close() cleanly. Provides a fast abort capability- * when the client discovers that things have gone wrong. */-__LA_DECL int archive_write_fail(struct archive *);-/* This can fail if the archive wasn't already closed, in which case- * archive_write_free() will implicitly call archive_write_close(). */-__LA_DECL int archive_write_free(struct archive *);-#if ARCHIVE_VERSION_NUMBER < 4000000-/* Synonym for archive_write_free() for backwards compatibility. */-__LA_DECL int archive_write_finish(struct archive *) __LA_DEPRECATED;-#endif--/*- * Set write options.- */-/* Apply option to the format only. */-__LA_DECL int archive_write_set_format_option(struct archive *_a,- const char *m, const char *o,- const char *v);-/* Apply option to the filter only. */-__LA_DECL int archive_write_set_filter_option(struct archive *_a,- const char *m, const char *o,- const char *v);-/* Apply option to both the format and the filter. */-__LA_DECL int archive_write_set_option(struct archive *_a,- const char *m, const char *o,- const char *v);-/* Apply option string to both the format and the filter. */-__LA_DECL int archive_write_set_options(struct archive *_a,- const char *opts);--/*- * Set a encryption passphrase.- */-__LA_DECL int archive_write_set_passphrase(struct archive *_a, const char *p);-__LA_DECL int archive_write_set_passphrase_callback(struct archive *,- void *client_data, archive_passphrase_callback *);--/*-- * ARCHIVE_WRITE_DISK API- *- * To create objects on disk:- * 1) Ask archive_write_disk_new for a new archive_write_disk object.- * 2) Set any global properties. In particular, you probably- * want to set the options.- * 3) For each entry:- * - construct an appropriate struct archive_entry structure- * - archive_write_header to create the file/dir/etc on disk- * - archive_write_data to write the entry data- * 4) archive_write_free to cleanup the writer and release resources- *- * In particular, you can use this in conjunction with archive_read()- * to pull entries out of an archive and create them on disk.- */-__LA_DECL struct archive *archive_write_disk_new(void);-/* This file will not be overwritten. */-__LA_DECL int archive_write_disk_set_skip_file(struct archive *,- la_int64_t, la_int64_t);-/* Set flags to control how the next item gets created.- * This accepts a bitmask of ARCHIVE_EXTRACT_XXX flags defined above. */-__LA_DECL int archive_write_disk_set_options(struct archive *,- int flags);-/*- * The lookup functions are given uname/uid (or gname/gid) pairs and- * return a uid (gid) suitable for this system. These are used for- * restoring ownership and for setting ACLs. The default functions- * are naive, they just return the uid/gid. These are small, so reasonable- * for applications that don't need to preserve ownership; they- * are probably also appropriate for applications that are doing- * same-system backup and restore.- */-/*- * The "standard" lookup functions use common system calls to lookup- * the uname/gname, falling back to the uid/gid if the names can't be- * found. They cache lookups and are reasonably fast, but can be very- * large, so they are not used unless you ask for them. In- * particular, these match the specifications of POSIX "pax" and old- * POSIX "tar".- */-__LA_DECL int archive_write_disk_set_standard_lookup(struct archive *);-/*- * If neither the default (naive) nor the standard (big) functions suit- * your needs, you can write your own and register them. Be sure to- * include a cleanup function if you have allocated private data.- */-__LA_DECL int archive_write_disk_set_group_lookup(struct archive *,- void * /* private_data */,- la_int64_t (*)(void *, const char *, la_int64_t),- void (* /* cleanup */)(void *));-__LA_DECL int archive_write_disk_set_user_lookup(struct archive *,- void * /* private_data */,- la_int64_t (*)(void *, const char *, la_int64_t),- void (* /* cleanup */)(void *));-__LA_DECL la_int64_t archive_write_disk_gid(struct archive *, const char *, la_int64_t);-__LA_DECL la_int64_t archive_write_disk_uid(struct archive *, const char *, la_int64_t);--/*- * ARCHIVE_READ_DISK API- *- * This is still evolving and somewhat experimental.- */-__LA_DECL struct archive *archive_read_disk_new(void);-/* The names for symlink modes here correspond to an old BSD- * command-line argument convention: -L, -P, -H */-/* Follow all symlinks. */-__LA_DECL int archive_read_disk_set_symlink_logical(struct archive *);-/* Follow no symlinks. */-__LA_DECL int archive_read_disk_set_symlink_physical(struct archive *);-/* Follow symlink initially, then not. */-__LA_DECL int archive_read_disk_set_symlink_hybrid(struct archive *);-/* TODO: Handle Linux stat32/stat64 ugliness. <sigh> */-__LA_DECL int archive_read_disk_entry_from_file(struct archive *,- struct archive_entry *, int /* fd */, const struct stat *);-/* Look up gname for gid or uname for uid. */-/* Default implementations are very, very stupid. */-__LA_DECL const char *archive_read_disk_gname(struct archive *, la_int64_t);-__LA_DECL const char *archive_read_disk_uname(struct archive *, la_int64_t);-/* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the- * results for performance. */-__LA_DECL int archive_read_disk_set_standard_lookup(struct archive *);-/* You can install your own lookups if you like. */-__LA_DECL int archive_read_disk_set_gname_lookup(struct archive *,- void * /* private_data */,- const char *(* /* lookup_fn */)(void *, la_int64_t),- void (* /* cleanup_fn */)(void *));-__LA_DECL int archive_read_disk_set_uname_lookup(struct archive *,- void * /* private_data */,- const char *(* /* lookup_fn */)(void *, la_int64_t),- void (* /* cleanup_fn */)(void *));-/* Start traversal. */-__LA_DECL int archive_read_disk_open(struct archive *, const char *);-__LA_DECL int archive_read_disk_open_w(struct archive *, const wchar_t *);-/*- * Request that current entry be visited. If you invoke it on every- * directory, you'll get a physical traversal. This is ignored if the- * current entry isn't a directory or a link to a directory. So, if- * you invoke this on every returned path, you'll get a full logical- * traversal.- */-__LA_DECL int archive_read_disk_descend(struct archive *);-__LA_DECL int archive_read_disk_can_descend(struct archive *);-__LA_DECL int archive_read_disk_current_filesystem(struct archive *);-__LA_DECL int archive_read_disk_current_filesystem_is_synthetic(struct archive *);-__LA_DECL int archive_read_disk_current_filesystem_is_remote(struct archive *);-/* Request that the access time of the entry visited by traversal be restored. */-__LA_DECL int archive_read_disk_set_atime_restored(struct archive *);-/*- * Set behavior. The "flags" argument selects optional behavior.- */-/* Request that the access time of the entry visited by traversal be restored.- * This is the same as archive_read_disk_set_atime_restored. */-#define ARCHIVE_READDISK_RESTORE_ATIME (0x0001)-/* Default: Do not skip an entry which has nodump flags. */-#define ARCHIVE_READDISK_HONOR_NODUMP (0x0002)-/* Default: Skip a mac resource fork file whose prefix is "._" because of- * using copyfile. */-#define ARCHIVE_READDISK_MAC_COPYFILE (0x0004)-/* Default: Traverse mount points. */-#define ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS (0x0008)-/* Default: Xattrs are read from disk. */-#define ARCHIVE_READDISK_NO_XATTR (0x0010)-/* Default: ACLs are read from disk. */-#define ARCHIVE_READDISK_NO_ACL (0x0020)-/* Default: File flags are read from disk. */-#define ARCHIVE_READDISK_NO_FFLAGS (0x0040)-/* Default: Sparse file information is read from disk. */-#define ARCHIVE_READDISK_NO_SPARSE (0x0080)--__LA_DECL int archive_read_disk_set_behavior(struct archive *,- int flags);--/*- * Set archive_match object that will be used in archive_read_disk to- * know whether an entry should be skipped. The callback function- * _excluded_func will be invoked when an entry is skipped by the result- * of archive_match.- */-__LA_DECL int archive_read_disk_set_matching(struct archive *,- struct archive *_matching, void (*_excluded_func)- (struct archive *, void *, struct archive_entry *),- void *_client_data);-__LA_DECL int archive_read_disk_set_metadata_filter_callback(struct archive *,- int (*_metadata_filter_func)(struct archive *, void *,- struct archive_entry *), void *_client_data);--/* Simplified cleanup interface;- * This calls archive_read_free() or archive_write_free() as needed. */-__LA_DECL int archive_free(struct archive *);--/*- * Accessor functions to read/set various information in- * the struct archive object:- */--/* 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 *)- __LA_DEPRECATED;-/* 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 *)- __LA_DEPRECATED;-/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */-__LA_DECL const char *archive_compression_name(struct archive *)- __LA_DEPRECATED;-/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */-__LA_DECL int archive_compression(struct archive *)- __LA_DEPRECATED;-#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 *);-__LA_DECL int archive_format(struct archive *);-__LA_DECL void archive_clear_error(struct archive *);-__LA_DECL void archive_set_error(struct archive *, int _err,- const char *fmt, ...) __LA_PRINTF(3, 4);-__LA_DECL void archive_copy_error(struct archive *dest,- struct archive *src);-__LA_DECL int archive_file_count(struct archive *);--/*- * ARCHIVE_MATCH API- */-__LA_DECL struct archive *archive_match_new(void);-__LA_DECL int archive_match_free(struct archive *);--/*- * Test if archive_entry is excluded.- * This is a convenience function. This is the same as calling all- * archive_match_path_excluded, archive_match_time_excluded- * and archive_match_owner_excluded.- */-__LA_DECL int archive_match_excluded(struct archive *,- struct archive_entry *);--/*- * Test if pathname is excluded. The conditions are set by following functions.- */-__LA_DECL int archive_match_path_excluded(struct archive *,- struct archive_entry *);-/* Control recursive inclusion of directory content when directory is included. Default on. */-__LA_DECL int archive_match_set_inclusion_recursion(struct archive *, int);-/* Add exclusion pathname pattern. */-__LA_DECL int archive_match_exclude_pattern(struct archive *, const char *);-__LA_DECL int archive_match_exclude_pattern_w(struct archive *,- const wchar_t *);-/* Add exclusion pathname pattern from file. */-__LA_DECL int archive_match_exclude_pattern_from_file(struct archive *,- const char *, int _nullSeparator);-__LA_DECL int archive_match_exclude_pattern_from_file_w(struct archive *,- const wchar_t *, int _nullSeparator);-/* Add inclusion pathname pattern. */-__LA_DECL int archive_match_include_pattern(struct archive *, const char *);-__LA_DECL int archive_match_include_pattern_w(struct archive *,- const wchar_t *);-/* Add inclusion pathname pattern from file. */-__LA_DECL int archive_match_include_pattern_from_file(struct archive *,- const char *, int _nullSeparator);-__LA_DECL int archive_match_include_pattern_from_file_w(struct archive *,- const wchar_t *, int _nullSeparator);-/*- * How to get statistic information for inclusion patterns.- */-/* Return the amount number of unmatched inclusion patterns. */-__LA_DECL int archive_match_path_unmatched_inclusions(struct archive *);-/* Return the pattern of unmatched inclusion with ARCHIVE_OK.- * Return ARCHIVE_EOF if there is no inclusion pattern. */-__LA_DECL int archive_match_path_unmatched_inclusions_next(- struct archive *, const char **);-__LA_DECL int archive_match_path_unmatched_inclusions_next_w(- struct archive *, const wchar_t **);--/*- * Test if a file is excluded by its time stamp.- * The conditions are set by following functions.- */-__LA_DECL int archive_match_time_excluded(struct archive *,- struct archive_entry *);--/*- * Flags to tell a matching type of time stamps. These are used for- * following functions.- */-/* Time flag: mtime to be tested. */-#define ARCHIVE_MATCH_MTIME (0x0100)-/* Time flag: ctime to be tested. */-#define ARCHIVE_MATCH_CTIME (0x0200)-/* Comparison flag: Match the time if it is newer than. */-#define ARCHIVE_MATCH_NEWER (0x0001)-/* Comparison flag: Match the time if it is older than. */-#define ARCHIVE_MATCH_OLDER (0x0002)-/* Comparison flag: Match the time if it is equal to. */-#define ARCHIVE_MATCH_EQUAL (0x0010)-/* Set inclusion time. */-__LA_DECL int archive_match_include_time(struct archive *, int _flag,- time_t _sec, long _nsec);-/* Set inclusion time by a date string. */-__LA_DECL int archive_match_include_date(struct archive *, int _flag,- const char *_datestr);-__LA_DECL int archive_match_include_date_w(struct archive *, int _flag,- const wchar_t *_datestr);-/* Set inclusion time by a particular file. */-__LA_DECL int archive_match_include_file_time(struct archive *,- int _flag, const char *_pathname);-__LA_DECL int archive_match_include_file_time_w(struct archive *,- int _flag, const wchar_t *_pathname);-/* Add exclusion entry. */-__LA_DECL int archive_match_exclude_entry(struct archive *,- int _flag, struct archive_entry *);--/*- * Test if a file is excluded by its uid ,gid, uname or gname.- * The conditions are set by following functions.- */-__LA_DECL int archive_match_owner_excluded(struct archive *,- struct archive_entry *);-/* Add inclusion uid, gid, uname and gname. */-__LA_DECL int archive_match_include_uid(struct archive *, la_int64_t);-__LA_DECL int archive_match_include_gid(struct archive *, la_int64_t);-__LA_DECL int archive_match_include_uname(struct archive *, const char *);-__LA_DECL int archive_match_include_uname_w(struct archive *,- const wchar_t *);-__LA_DECL int archive_match_include_gname(struct archive *, const char *);-__LA_DECL int archive_match_include_gname_w(struct archive *,- const wchar_t *);--/* Utility functions */-/* Convenience function to sort a NULL terminated list of strings */-__LA_DECL int archive_utility_string_sort(char **);--#ifdef __cplusplus-}-#endif--/* These are meaningless outside of this header. */-#undef __LA_DECL--#endif /* !ARCHIVE_H_INCLUDED */
− c/archive_acl.c
@@ -1,2097 +0,0 @@-/*-- * Copyright (c) 2003-2010 Tim Kientzle- * Copyright (c) 2016 Martin Matuska- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_WCHAR_H-#include <wchar.h>-#endif--#include "archive_acl_private.h"-#include "archive_entry.h"-#include "archive_private.h"--#undef max-#define max(a, b) ((a)>(b)?(a):(b))--#ifndef HAVE_WMEMCMP-/* Good enough for simple equality testing, but not for sorting. */-#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t))-#endif--static int acl_special(struct archive_acl *acl,- int type, int permset, int tag);-static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl,- int type, int permset, int tag, int id);-static int archive_acl_add_entry_len_l(struct archive_acl *acl,- int type, int permset, int tag, int id, const char *name,- size_t len, struct archive_string_conv *sc);-static int archive_acl_text_want_type(struct archive_acl *acl, int flags);-static ssize_t archive_acl_text_len(struct archive_acl *acl, int want_type,- int flags, int wide, struct archive *a,- struct archive_string_conv *sc);-static int isint_w(const wchar_t *start, const wchar_t *end, int *result);-static int ismode_w(const wchar_t *start, const wchar_t *end, int *result);-static int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end,- int *result);-static int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end,- int *result);-static void next_field_w(const wchar_t **wp, const wchar_t **start,- const wchar_t **end, wchar_t *sep);-static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,- int tag, int flags, const wchar_t *wname, int perm, int id);-static void append_id_w(wchar_t **wp, int id);-static int isint(const char *start, const char *end, int *result);-static int ismode(const char *start, const char *end, int *result);-static int is_nfs4_flags(const char *start, const char *end,- int *result);-static int is_nfs4_perms(const char *start, const char *end,- int *result);-static void next_field(const char **p, const char **start,- const char **end, char *sep);-static void append_entry(char **p, const char *prefix, int type,- int tag, int flags, const char *name, int perm, int id);-static void append_id(char **p, int id);--static const struct {- const int perm;- const char c;- const wchar_t wc;-} nfsv4_acl_perm_map[] = {- { ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 'r',- L'r' },- { ARCHIVE_ENTRY_ACL_WRITE_DATA | ARCHIVE_ENTRY_ACL_ADD_FILE, 'w',- L'w' },- { ARCHIVE_ENTRY_ACL_EXECUTE, 'x', L'x' },- { ARCHIVE_ENTRY_ACL_APPEND_DATA | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY,- 'p', L'p' },- { ARCHIVE_ENTRY_ACL_DELETE, 'd', L'd' },- { ARCHIVE_ENTRY_ACL_DELETE_CHILD, 'D', L'D' },- { ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 'a', L'a' },- { ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 'A', L'A' },- { ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 'R', L'R' },- { ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 'W', L'W' },- { ARCHIVE_ENTRY_ACL_READ_ACL, 'c', L'c' },- { ARCHIVE_ENTRY_ACL_WRITE_ACL, 'C', L'C' },- { ARCHIVE_ENTRY_ACL_WRITE_OWNER, 'o', L'o' },- { ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 's', L's' }-};--static const int nfsv4_acl_perm_map_size = (int)(sizeof(nfsv4_acl_perm_map) /- sizeof(nfsv4_acl_perm_map[0]));--static const struct {- const int perm;- const char c;- const wchar_t wc;-} nfsv4_acl_flag_map[] = {- { ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 'f', L'f' },- { ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 'd', L'd' },- { ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 'i', L'i' },- { ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 'n', L'n' },- { ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 'S', L'S' },- { ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 'F', L'F' },- { ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, 'I', L'I' }-};--static const int nfsv4_acl_flag_map_size = (int)(sizeof(nfsv4_acl_flag_map) /- sizeof(nfsv4_acl_flag_map[0]));--void-archive_acl_clear(struct archive_acl *acl)-{- struct archive_acl_entry *ap;-- while (acl->acl_head != NULL) {- ap = acl->acl_head->next;- archive_mstring_clean(&acl->acl_head->name);- free(acl->acl_head);- acl->acl_head = ap;- }- free(acl->acl_text_w);- acl->acl_text_w = NULL;- free(acl->acl_text);- acl->acl_text = NULL;- acl->acl_p = NULL;- acl->acl_types = 0;- acl->acl_state = 0; /* Not counting. */-}--void-archive_acl_copy(struct archive_acl *dest, struct archive_acl *src)-{- struct archive_acl_entry *ap, *ap2;-- archive_acl_clear(dest);-- dest->mode = src->mode;- ap = src->acl_head;- while (ap != NULL) {- ap2 = acl_new_entry(dest,- ap->type, ap->permset, ap->tag, ap->id);- if (ap2 != NULL)- archive_mstring_copy(&ap2->name, &ap->name);- ap = ap->next;- }-}--int-archive_acl_add_entry(struct archive_acl *acl,- int type, int permset, int tag, int id, const char *name)-{- struct archive_acl_entry *ap;-- if (acl_special(acl, type, permset, tag) == 0)- return ARCHIVE_OK;- ap = acl_new_entry(acl, type, permset, tag, id);- if (ap == NULL) {- /* XXX Error XXX */- return ARCHIVE_FAILED;- }- if (name != NULL && *name != '\0')- archive_mstring_copy_mbs(&ap->name, name);- else- archive_mstring_clean(&ap->name);- return ARCHIVE_OK;-}--int-archive_acl_add_entry_w_len(struct archive_acl *acl,- int type, int permset, int tag, int id, const wchar_t *name, size_t len)-{- struct archive_acl_entry *ap;-- if (acl_special(acl, type, permset, tag) == 0)- return ARCHIVE_OK;- ap = acl_new_entry(acl, type, permset, tag, id);- if (ap == NULL) {- /* XXX Error XXX */- return ARCHIVE_FAILED;- }- if (name != NULL && *name != L'\0' && len > 0)- archive_mstring_copy_wcs_len(&ap->name, name, len);- else- archive_mstring_clean(&ap->name);- return ARCHIVE_OK;-}--static int-archive_acl_add_entry_len_l(struct archive_acl *acl,- int type, int permset, int tag, int id, const char *name, size_t len,- struct archive_string_conv *sc)-{- struct archive_acl_entry *ap;- int r;-- if (acl_special(acl, type, permset, tag) == 0)- return ARCHIVE_OK;- ap = acl_new_entry(acl, type, permset, tag, id);- if (ap == NULL) {- /* XXX Error XXX */- return ARCHIVE_FAILED;- }- if (name != NULL && *name != '\0' && len > 0) {- r = archive_mstring_copy_mbs_len_l(&ap->name, name, len, sc);- } else {- r = 0;- archive_mstring_clean(&ap->name);- }- if (r == 0)- return (ARCHIVE_OK);- else if (errno == ENOMEM)- return (ARCHIVE_FATAL);- else- return (ARCHIVE_WARN);-}--/*- * If this ACL entry is part of the standard POSIX permissions set,- * store the permissions in the stat structure and return zero.- */-static int-acl_special(struct archive_acl *acl, int type, int permset, int tag)-{- if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS- && ((permset & ~007) == 0)) {- switch (tag) {- case ARCHIVE_ENTRY_ACL_USER_OBJ:- acl->mode &= ~0700;- acl->mode |= (permset & 7) << 6;- return (0);- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- acl->mode &= ~0070;- acl->mode |= (permset & 7) << 3;- return (0);- case ARCHIVE_ENTRY_ACL_OTHER:- acl->mode &= ~0007;- acl->mode |= permset & 7;- return (0);- }- }- return (1);-}--/*- * Allocate and populate a new ACL entry with everything but the- * name.- */-static struct archive_acl_entry *-acl_new_entry(struct archive_acl *acl,- int type, int permset, int tag, int id)-{- struct archive_acl_entry *ap, *aq;-- /* Type argument must be a valid NFS4 or POSIX.1e type.- * The type must agree with anything already set and- * the permset must be compatible. */- if (type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- return (NULL);- }- if (permset &- ~(ARCHIVE_ENTRY_ACL_PERMS_NFS4- | ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4)) {- return (NULL);- }- } else if (type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) {- if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) {- return (NULL);- }- if (permset & ~ARCHIVE_ENTRY_ACL_PERMS_POSIX1E) {- return (NULL);- }- } else {- return (NULL);- }-- /* Verify the tag is valid and compatible with NFS4 or POSIX.1e. */- switch (tag) {- case ARCHIVE_ENTRY_ACL_USER:- case ARCHIVE_ENTRY_ACL_USER_OBJ:- case ARCHIVE_ENTRY_ACL_GROUP:- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- /* Tags valid in both NFS4 and POSIX.1e */- break;- case ARCHIVE_ENTRY_ACL_MASK:- case ARCHIVE_ENTRY_ACL_OTHER:- /* Tags valid only in POSIX.1e. */- if (type & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) {- return (NULL);- }- break;- case ARCHIVE_ENTRY_ACL_EVERYONE:- /* Tags valid only in NFS4. */- if (type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- return (NULL);- }- break;- default:- /* No other values are valid. */- return (NULL);- }-- free(acl->acl_text_w);- acl->acl_text_w = NULL;- free(acl->acl_text);- acl->acl_text = NULL;-- /*- * If there's a matching entry already in the list, overwrite it.- * NFSv4 entries may be repeated and are not overwritten.- *- * TODO: compare names of no id is provided (needs more rework)- */- ap = acl->acl_head;- aq = NULL;- while (ap != NULL) {- if (((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) &&- ap->type == type && ap->tag == tag && ap->id == id) {- if (id != -1 || (tag != ARCHIVE_ENTRY_ACL_USER &&- tag != ARCHIVE_ENTRY_ACL_GROUP)) {- ap->permset = permset;- return (ap);- }- }- aq = ap;- ap = ap->next;- }-- /* Add a new entry to the end of the list. */- ap = (struct archive_acl_entry *)calloc(1, sizeof(*ap));- if (ap == NULL)- return (NULL);- if (aq == NULL)- acl->acl_head = ap;- else- aq->next = ap;- ap->type = type;- ap->tag = tag;- ap->id = id;- ap->permset = permset;- acl->acl_types |= type;- return (ap);-}--/*- * Return a count of entries matching "want_type".- */-int-archive_acl_count(struct archive_acl *acl, int want_type)-{- int count;- struct archive_acl_entry *ap;-- count = 0;- ap = acl->acl_head;- while (ap != NULL) {- if ((ap->type & want_type) != 0)- count++;- ap = ap->next;- }-- if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0))- count += 3;- return (count);-}--/*- * Return a bitmask of stored ACL types in an ACL list- */-int-archive_acl_types(struct archive_acl *acl)-{- return (acl->acl_types);-}--/*- * Prepare for reading entries from the ACL data. Returns a count- * of entries matching "want_type", or zero if there are no- * non-extended ACL entries of that type.- */-int-archive_acl_reset(struct archive_acl *acl, int want_type)-{- int count, cutoff;-- count = archive_acl_count(acl, want_type);-- /*- * If the only entries are the three standard ones,- * then don't return any ACL data. (In this case,- * client can just use chmod(2) to set permissions.)- */- if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)- cutoff = 3;- else- cutoff = 0;-- if (count > cutoff)- acl->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ;- else- acl->acl_state = 0;- acl->acl_p = acl->acl_head;- return (count);-}---/*- * Return the next ACL entry in the list. Fake entries for the- * standard permissions and include them in the returned list.- */-int-archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type,- int *type, int *permset, int *tag, int *id, const char **name)-{- *name = NULL;- *id = -1;-- /*- * The acl_state is either zero (no entries available), -1- * (reading from list), or an entry type (retrieve that type- * from ae_stat.aest_mode).- */- if (acl->acl_state == 0)- return (ARCHIVE_WARN);-- /* The first three access entries are special. */- if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {- switch (acl->acl_state) {- case ARCHIVE_ENTRY_ACL_USER_OBJ:- *permset = (acl->mode >> 6) & 7;- *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;- *tag = ARCHIVE_ENTRY_ACL_USER_OBJ;- acl->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- return (ARCHIVE_OK);- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- *permset = (acl->mode >> 3) & 7;- *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;- *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- acl->acl_state = ARCHIVE_ENTRY_ACL_OTHER;- return (ARCHIVE_OK);- case ARCHIVE_ENTRY_ACL_OTHER:- *permset = acl->mode & 7;- *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;- *tag = ARCHIVE_ENTRY_ACL_OTHER;- acl->acl_state = -1;- acl->acl_p = acl->acl_head;- return (ARCHIVE_OK);- default:- break;- }- }-- while (acl->acl_p != NULL && (acl->acl_p->type & want_type) == 0)- acl->acl_p = acl->acl_p->next;- if (acl->acl_p == NULL) {- acl->acl_state = 0;- *type = 0;- *permset = 0;- *tag = 0;- *id = -1;- *name = NULL;- return (ARCHIVE_EOF); /* End of ACL entries. */- }- *type = acl->acl_p->type;- *permset = acl->acl_p->permset;- *tag = acl->acl_p->tag;- *id = acl->acl_p->id;- if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) {- if (errno == ENOMEM)- return (ARCHIVE_FATAL);- *name = NULL;- }- acl->acl_p = acl->acl_p->next;- return (ARCHIVE_OK);-}--/*- * Determine what type of ACL do we want- */-static int-archive_acl_text_want_type(struct archive_acl *acl, int flags)-{- int want_type;-- /* Check if ACL is NFSv4 */- if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {- /* NFSv4 should never mix with POSIX.1e */- if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0)- return (0);- else- return (ARCHIVE_ENTRY_ACL_TYPE_NFS4);- }-- /* Now deal with POSIX.1e ACLs */-- want_type = 0;- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)- want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS;- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)- want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;-- /* By default we want both access and default ACLs */- if (want_type == 0)- return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E);-- return (want_type);-}--/*- * Calculate ACL text string length- */-static ssize_t-archive_acl_text_len(struct archive_acl *acl, int want_type, int flags,- int wide, struct archive *a, struct archive_string_conv *sc) {- struct archive_acl_entry *ap;- const char *name;- const wchar_t *wname;- int count, idlen, tmp, r;- ssize_t length;- size_t len;-- count = 0;- length = 0;- for (ap = acl->acl_head; ap != NULL; ap = ap->next) {- if ((ap->type & want_type) == 0)- continue;- /*- * Filemode-mapping ACL entries are stored exclusively in- * ap->mode so they should not be in the list- */- if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)- && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ- || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ- || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))- continue;- count++;- if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0- && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)- length += 8; /* "default:" */- switch (ap->tag) {- case ARCHIVE_ENTRY_ACL_USER_OBJ:- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- length += 6; /* "owner@" */- break;- }- /* FALLTHROUGH */- case ARCHIVE_ENTRY_ACL_USER:- case ARCHIVE_ENTRY_ACL_MASK:- length += 4; /* "user", "mask" */- break;- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- length += 6; /* "group@" */- break;- }- /* FALLTHROUGH */- case ARCHIVE_ENTRY_ACL_GROUP:- case ARCHIVE_ENTRY_ACL_OTHER:- length += 5; /* "group", "other" */- break;- case ARCHIVE_ENTRY_ACL_EVERYONE:- length += 9; /* "everyone@" */- break;- }- length += 1; /* colon after tag */- if (ap->tag == ARCHIVE_ENTRY_ACL_USER ||- ap->tag == ARCHIVE_ENTRY_ACL_GROUP) {- if (wide) {- r = archive_mstring_get_wcs(a, &ap->name,- &wname);- if (r == 0 && wname != NULL)- length += wcslen(wname);- else if (r < 0 && errno == ENOMEM)- return (0);- else- length += sizeof(uid_t) * 3 + 1;- } else {- r = archive_mstring_get_mbs_l(a, &ap->name, &name,- &len, sc);- if (r != 0)- return (0);- if (len > 0 && name != NULL)- length += len;- else- length += sizeof(uid_t) * 3 + 1;- }- length += 1; /* colon after user or group name */- } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4)- length += 1; /* 2nd colon empty user,group or other */-- if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0)- && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0)- && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER- || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) {- /* Solaris has no colon after other: and mask: */- length = length - 1;- }-- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- /* rwxpdDaARWcCos:fdinSFI:deny */- length += 27;- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0)- length += 1; /* allow, alarm, audit */- } else- length += 3; /* rwx */-- if ((ap->tag == ARCHIVE_ENTRY_ACL_USER ||- ap->tag == ARCHIVE_ENTRY_ACL_GROUP) &&- (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) {- length += 1; /* colon */- /* ID digit count */- idlen = 1;- tmp = ap->id;- while (tmp > 9) {- tmp = tmp / 10;- idlen++;- }- length += idlen;- }- length ++; /* entry separator */- }-- /* Add filemode-mapping access entries to the length */- if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {- if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) {- /* "user::rwx\ngroup::rwx\nother:rwx\n" */- length += 31;- } else {- /* "user::rwx\ngroup::rwx\nother::rwx\n" */- length += 32;- }- } else if (count == 0)- return (0);-- /* The terminating character is included in count */- return (length);-}--/*- * Generate a wide text version of the ACL. The flags parameter controls- * the type and style of the generated ACL.- */-wchar_t *-archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,- struct archive *a)-{- int count;- ssize_t length;- size_t len;- const wchar_t *wname;- const wchar_t *prefix;- wchar_t separator;- struct archive_acl_entry *ap;- int id, r, want_type;- wchar_t *wp, *ws;-- want_type = archive_acl_text_want_type(acl, flags);-- /* Both NFSv4 and POSIX.1 types found */- if (want_type == 0)- return (NULL);-- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)- flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;-- length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL);-- if (length == 0)- return (NULL);-- if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)- separator = L',';- else- separator = L'\n';-- /* Now, allocate the string and actually populate it. */- wp = ws = (wchar_t *)malloc(length * sizeof(wchar_t));- if (wp == NULL) {- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);- }- count = 0;-- if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,- ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,- acl->mode & 0700, -1);- *wp++ = separator;- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,- ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,- acl->mode & 0070, -1);- *wp++ = separator;- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,- ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,- acl->mode & 0007, -1);- count += 3;- }-- for (ap = acl->acl_head; ap != NULL; ap = ap->next) {- if ((ap->type & want_type) == 0)- continue;- /*- * Filemode-mapping ACL entries are stored exclusively in- * ap->mode so they should not be in the list- */- if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)- && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ- || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ- || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))- continue;- if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT &&- (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)- prefix = L"default:";- else- prefix = NULL;- r = archive_mstring_get_wcs(a, &ap->name, &wname);- if (r == 0) {- if (count > 0)- *wp++ = separator;- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)- id = ap->id;- else- id = -1;- append_entry_w(&wp, prefix, ap->type, ap->tag, flags,- wname, ap->permset, id);- count++;- } else if (r < 0 && errno == ENOMEM) {- free(ws);- return (NULL);- }- }-- /* Add terminating character */- *wp++ = L'\0';-- len = wcslen(ws);-- if ((ssize_t)len > (length - 1))- __archive_errx(1, "Buffer overrun");-- if (text_len != NULL)- *text_len = len;-- return (ws);-}--static void-append_id_w(wchar_t **wp, int id)-{- if (id < 0)- id = 0;- if (id > 9)- append_id_w(wp, id / 10);- *(*wp)++ = L"0123456789"[id % 10];-}--static void-append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,- int tag, int flags, const wchar_t *wname, int perm, int id)-{- int i;-- if (prefix != NULL) {- wcscpy(*wp, prefix);- *wp += wcslen(*wp);- }- switch (tag) {- case ARCHIVE_ENTRY_ACL_USER_OBJ:- wname = NULL;- id = -1;- if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {- wcscpy(*wp, L"owner@");- break;- }- /* FALLTHROUGH */- case ARCHIVE_ENTRY_ACL_USER:- wcscpy(*wp, L"user");- break;- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- wname = NULL;- id = -1;- if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {- wcscpy(*wp, L"group@");- break;- }- /* FALLTHROUGH */- case ARCHIVE_ENTRY_ACL_GROUP:- wcscpy(*wp, L"group");- break;- case ARCHIVE_ENTRY_ACL_MASK:- wcscpy(*wp, L"mask");- wname = NULL;- id = -1;- break;- case ARCHIVE_ENTRY_ACL_OTHER:- wcscpy(*wp, L"other");- wname = NULL;- id = -1;- break;- case ARCHIVE_ENTRY_ACL_EVERYONE:- wcscpy(*wp, L"everyone@");- wname = NULL;- id = -1;- break;- }- *wp += wcslen(*wp);- *(*wp)++ = L':';- if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||- tag == ARCHIVE_ENTRY_ACL_USER ||- tag == ARCHIVE_ENTRY_ACL_GROUP) {- if (wname != NULL) {- wcscpy(*wp, wname);- *wp += wcslen(*wp);- } else if (tag == ARCHIVE_ENTRY_ACL_USER- || tag == ARCHIVE_ENTRY_ACL_GROUP) {- append_id_w(wp, id);- if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0)- id = -1;- }- /* Solaris style has no second colon after other and mask */- if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)- || (tag != ARCHIVE_ENTRY_ACL_OTHER- && tag != ARCHIVE_ENTRY_ACL_MASK))- *(*wp)++ = L':';- }- if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {- /* POSIX.1e ACL perms */- *(*wp)++ = (perm & 0444) ? L'r' : L'-';- *(*wp)++ = (perm & 0222) ? L'w' : L'-';- *(*wp)++ = (perm & 0111) ? L'x' : L'-';- } else {- /* NFSv4 ACL perms */- for (i = 0; i < nfsv4_acl_perm_map_size; i++) {- if (perm & nfsv4_acl_perm_map[i].perm)- *(*wp)++ = nfsv4_acl_perm_map[i].wc;- else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)- *(*wp)++ = L'-';- }- *(*wp)++ = L':';- for (i = 0; i < nfsv4_acl_flag_map_size; i++) {- if (perm & nfsv4_acl_flag_map[i].perm)- *(*wp)++ = nfsv4_acl_flag_map[i].wc;- else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)- *(*wp)++ = L'-';- }- *(*wp)++ = L':';- switch (type) {- case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:- wcscpy(*wp, L"allow");- break;- case ARCHIVE_ENTRY_ACL_TYPE_DENY:- wcscpy(*wp, L"deny");- break;- case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:- wcscpy(*wp, L"audit");- break;- case ARCHIVE_ENTRY_ACL_TYPE_ALARM:- wcscpy(*wp, L"alarm");- break;- default:- break;- }- *wp += wcslen(*wp);- }- if (id != -1) {- *(*wp)++ = L':';- append_id_w(wp, id);- }-}--/*- * Generate a text version of the ACL. The flags parameter controls- * the type and style of the generated ACL.- */-char *-archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,- struct archive_string_conv *sc)-{- int count;- ssize_t length;- size_t len;- const char *name;- const char *prefix;- char separator;- struct archive_acl_entry *ap;- int id, r, want_type;- char *p, *s;-- want_type = archive_acl_text_want_type(acl, flags);-- /* Both NFSv4 and POSIX.1 types found */- if (want_type == 0)- return (NULL);-- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)- flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;-- length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc);-- if (length == 0)- return (NULL);-- if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)- separator = ',';- else- separator = '\n';-- /* Now, allocate the string and actually populate it. */- p = s = (char *)malloc(length * sizeof(char));- if (p == NULL) {- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);- }- count = 0;-- if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,- ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,- acl->mode & 0700, -1);- *p++ = separator;- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,- ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,- acl->mode & 0070, -1);- *p++ = separator;- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,- ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,- acl->mode & 0007, -1);- count += 3;- }-- for (ap = acl->acl_head; ap != NULL; ap = ap->next) {- if ((ap->type & want_type) == 0)- continue;- /*- * Filemode-mapping ACL entries are stored exclusively in- * ap->mode so they should not be in the list- */- if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)- && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ- || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ- || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))- continue;- if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT &&- (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)- prefix = "default:";- else- prefix = NULL;- r = archive_mstring_get_mbs_l(- NULL, &ap->name, &name, &len, sc);- if (r != 0) {- free(s);- return (NULL);- }- if (count > 0)- *p++ = separator;- if (name == NULL ||- (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) {- id = ap->id;- } else {- id = -1;- }- append_entry(&p, prefix, ap->type, ap->tag, flags, name,- ap->permset, id);- count++;- }-- /* Add terminating character */- *p++ = '\0';-- len = strlen(s);-- if ((ssize_t)len > (length - 1))- __archive_errx(1, "Buffer overrun");-- if (text_len != NULL)- *text_len = len;-- return (s);-}--static void-append_id(char **p, int id)-{- if (id < 0)- id = 0;- if (id > 9)- append_id(p, id / 10);- *(*p)++ = "0123456789"[id % 10];-}--static void-append_entry(char **p, const char *prefix, int type,- int tag, int flags, const char *name, int perm, int id)-{- int i;-- if (prefix != NULL) {- strcpy(*p, prefix);- *p += strlen(*p);- }- switch (tag) {- case ARCHIVE_ENTRY_ACL_USER_OBJ:- name = NULL;- id = -1;- if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {- strcpy(*p, "owner@");- break;- }- /* FALLTHROUGH */- case ARCHIVE_ENTRY_ACL_USER:- strcpy(*p, "user");- break;- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- name = NULL;- id = -1;- if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {- strcpy(*p, "group@");- break;- }- /* FALLTHROUGH */- case ARCHIVE_ENTRY_ACL_GROUP:- strcpy(*p, "group");- break;- case ARCHIVE_ENTRY_ACL_MASK:- strcpy(*p, "mask");- name = NULL;- id = -1;- break;- case ARCHIVE_ENTRY_ACL_OTHER:- strcpy(*p, "other");- name = NULL;- id = -1;- break;- case ARCHIVE_ENTRY_ACL_EVERYONE:- strcpy(*p, "everyone@");- name = NULL;- id = -1;- break;- }- *p += strlen(*p);- *(*p)++ = ':';- if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||- tag == ARCHIVE_ENTRY_ACL_USER ||- tag == ARCHIVE_ENTRY_ACL_GROUP) {- if (name != NULL) {- strcpy(*p, name);- *p += strlen(*p);- } else if (tag == ARCHIVE_ENTRY_ACL_USER- || tag == ARCHIVE_ENTRY_ACL_GROUP) {- append_id(p, id);- if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0)- id = -1;- }- /* Solaris style has no second colon after other and mask */- if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)- || (tag != ARCHIVE_ENTRY_ACL_OTHER- && tag != ARCHIVE_ENTRY_ACL_MASK))- *(*p)++ = ':';- }- if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {- /* POSIX.1e ACL perms */- *(*p)++ = (perm & 0444) ? 'r' : '-';- *(*p)++ = (perm & 0222) ? 'w' : '-';- *(*p)++ = (perm & 0111) ? 'x' : '-';- } else {- /* NFSv4 ACL perms */- for (i = 0; i < nfsv4_acl_perm_map_size; i++) {- if (perm & nfsv4_acl_perm_map[i].perm)- *(*p)++ = nfsv4_acl_perm_map[i].c;- else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)- *(*p)++ = '-';- }- *(*p)++ = ':';- for (i = 0; i < nfsv4_acl_flag_map_size; i++) {- if (perm & nfsv4_acl_flag_map[i].perm)- *(*p)++ = nfsv4_acl_flag_map[i].c;- else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)- *(*p)++ = '-';- }- *(*p)++ = ':';- switch (type) {- case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:- strcpy(*p, "allow");- break;- case ARCHIVE_ENTRY_ACL_TYPE_DENY:- strcpy(*p, "deny");- break;- case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:- strcpy(*p, "audit");- break;- case ARCHIVE_ENTRY_ACL_TYPE_ALARM:- strcpy(*p, "alarm");- break;- }- *p += strlen(*p);- }- if (id != -1) {- *(*p)++ = ':';- append_id(p, id);- }-}--/*- * Parse a wide ACL text string.- *- * The want_type argument may be one of the following:- * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS- * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT- * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL- *- * POSIX.1e ACL entries prefixed with "default:" are treated as- * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4- */-int-archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,- int want_type)-{- struct {- const wchar_t *start;- const wchar_t *end;- } field[6], name;-- const wchar_t *s, *st;-- int numfields, fields, n, r, sol, ret;- int type, types, tag, permset, id;- size_t len;- wchar_t sep;-- ret = ARCHIVE_OK;- types = 0;-- switch (want_type) {- case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:- want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;- __LA_FALLTHROUGH;- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:- numfields = 5;- break;- case ARCHIVE_ENTRY_ACL_TYPE_NFS4:- numfields = 6;- break;- default:- return (ARCHIVE_FATAL);- }-- while (text != NULL && *text != L'\0') {- /*- * Parse the fields out of the next entry,- * advance 'text' to start of next entry.- */- fields = 0;- do {- const wchar_t *start, *end;- next_field_w(&text, &start, &end, &sep);- if (fields < numfields) {- field[fields].start = start;- field[fields].end = end;- }- ++fields;- } while (sep == L':');-- /* Set remaining fields to blank. */- for (n = fields; n < numfields; ++n)- field[n].start = field[n].end = NULL;-- if (field[0].start != NULL && *(field[0].start) == L'#') {- /* Comment, skip entry */- continue;- }-- n = 0;- sol = 0;- id = -1;- permset = 0;- name.start = name.end = NULL;-- if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- /* POSIX.1e ACLs */- /*- * Default keyword "default:user::rwx"- * if found, we have one more field- *- * We also support old Solaris extension:- * "defaultuser::rwx" is the default ACL corresponding- * to "user::rwx", etc. valid only for first field- */- s = field[0].start;- len = field[0].end - field[0].start;- if (*s == L'd' && (len == 1 || (len >= 7- && wmemcmp((s + 1), L"efault", 6) == 0))) {- type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;- if (len > 7)- field[0].start += 7;- else- n = 1;- } else- type = want_type;-- /* Check for a numeric ID in field n+1 or n+3. */- isint_w(field[n + 1].start, field[n + 1].end, &id);- /* Field n+3 is optional. */- if (id == -1 && fields > n+3)- isint_w(field[n + 3].start, field[n + 3].end,- &id);-- tag = 0;- s = field[n].start;- st = field[n].start + 1;- len = field[n].end - field[n].start;-- switch (*s) {- case L'u':- if (len == 1 || (len == 4- && wmemcmp(st, L"ser", 3) == 0))- tag = ARCHIVE_ENTRY_ACL_USER_OBJ;- break;- case L'g':- if (len == 1 || (len == 5- && wmemcmp(st, L"roup", 4) == 0))- tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- break;- case L'o':- if (len == 1 || (len == 5- && wmemcmp(st, L"ther", 4) == 0))- tag = ARCHIVE_ENTRY_ACL_OTHER;- break;- case L'm':- if (len == 1 || (len == 4- && wmemcmp(st, L"ask", 3) == 0))- tag = ARCHIVE_ENTRY_ACL_MASK;- break;- default:- break;- }-- switch (tag) {- case ARCHIVE_ENTRY_ACL_OTHER:- case ARCHIVE_ENTRY_ACL_MASK:- if (fields == (n + 2)- && field[n + 1].start < field[n + 1].end- && ismode_w(field[n + 1].start,- field[n + 1].end, &permset)) {- /* This is Solaris-style "other:rwx" */- sol = 1;- } else if (fields == (n + 3) &&- field[n + 1].start < field[n + 1].end) {- /* Invalid mask or other field */- ret = ARCHIVE_WARN;- continue;- }- break;- case ARCHIVE_ENTRY_ACL_USER_OBJ:- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- if (id != -1 ||- field[n + 1].start < field[n + 1].end) {- name = field[n + 1];- if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)- tag = ARCHIVE_ENTRY_ACL_USER;- else- tag = ARCHIVE_ENTRY_ACL_GROUP;- }- break;- default:- /* Invalid tag, skip entry */- ret = ARCHIVE_WARN;- continue;- }-- /*- * Without "default:" we expect mode in field 2- * Exception: Solaris other and mask fields- */- if (permset == 0 && !ismode_w(field[n + 2 - sol].start,- field[n + 2 - sol].end, &permset)) {- /* Invalid mode, skip entry */- ret = ARCHIVE_WARN;- continue;- }- } else {- /* NFS4 ACLs */- s = field[0].start;- len = field[0].end - field[0].start;- tag = 0;-- switch (len) {- case 4:- if (wmemcmp(s, L"user", 4) == 0)- tag = ARCHIVE_ENTRY_ACL_USER;- break;- case 5:- if (wmemcmp(s, L"group", 5) == 0)- tag = ARCHIVE_ENTRY_ACL_GROUP;- break;- case 6:- if (wmemcmp(s, L"owner@", 6) == 0)- tag = ARCHIVE_ENTRY_ACL_USER_OBJ;- else if (wmemcmp(s, L"group@", len) == 0)- tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- break;- case 9:- if (wmemcmp(s, L"everyone@", 9) == 0)- tag = ARCHIVE_ENTRY_ACL_EVERYONE;- default:- break;- }-- if (tag == 0) {- /* Invalid tag, skip entry */- ret = ARCHIVE_WARN;- continue;- } else if (tag == ARCHIVE_ENTRY_ACL_USER ||- tag == ARCHIVE_ENTRY_ACL_GROUP) {- n = 1;- name = field[1];- isint_w(name.start, name.end, &id);- } else- n = 0;-- if (!is_nfs4_perms_w(field[1 + n].start,- field[1 + n].end, &permset)) {- /* Invalid NFSv4 perms, skip entry */- ret = ARCHIVE_WARN;- continue;- }- if (!is_nfs4_flags_w(field[2 + n].start,- field[2 + n].end, &permset)) {- /* Invalid NFSv4 flags, skip entry */- ret = ARCHIVE_WARN;- continue;- }- s = field[3 + n].start;- len = field[3 + n].end - field[3 + n].start;- type = 0;- if (len == 4) {- if (wmemcmp(s, L"deny", 4) == 0)- type = ARCHIVE_ENTRY_ACL_TYPE_DENY;- } else if (len == 5) {- if (wmemcmp(s, L"allow", 5) == 0)- type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;- else if (wmemcmp(s, L"audit", 5) == 0)- type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;- else if (wmemcmp(s, L"alarm", 5) == 0)- type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;- }- if (type == 0) {- /* Invalid entry type, skip entry */- ret = ARCHIVE_WARN;- continue;- }- isint_w(field[4 + n].start, field[4 + n].end, &id);- }-- /* Add entry to the internal list. */- r = archive_acl_add_entry_w_len(acl, type, permset,- tag, id, name.start, name.end - name.start);- if (r < ARCHIVE_WARN)- return (r);- if (r != ARCHIVE_OK)- ret = ARCHIVE_WARN;- types |= type;- }-- /* Reset ACL */- archive_acl_reset(acl, types);-- return (ret);-}--/*- * Parse a string to a positive decimal integer. Returns true if- * the string is non-empty and consists only of decimal digits,- * false otherwise.- */-static int-isint_w(const wchar_t *start, const wchar_t *end, int *result)-{- int n = 0;- if (start >= end)- return (0);- while (start < end) {- if (*start < L'0' || *start > L'9')- return (0);- if (n > (INT_MAX / 10) ||- (n == INT_MAX / 10 && (*start - L'0') > INT_MAX % 10)) {- n = INT_MAX;- } else {- n *= 10;- n += *start - L'0';- }- start++;- }- *result = n;- return (1);-}--/*- * Parse a string as a mode field. Returns true if- * the string is non-empty and consists only of mode characters,- * false otherwise.- */-static int-ismode_w(const wchar_t *start, const wchar_t *end, int *permset)-{- const wchar_t *p;-- if (start >= end)- return (0);- p = start;- *permset = 0;- while (p < end) {- switch (*p++) {- case L'r': case L'R':- *permset |= ARCHIVE_ENTRY_ACL_READ;- break;- case L'w': case L'W':- *permset |= ARCHIVE_ENTRY_ACL_WRITE;- break;- case L'x': case L'X':- *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;- break;- case L'-':- break;- default:- return (0);- }- }- return (1);-}--/*- * Parse a string as a NFS4 ACL permission field.- * Returns true if the string is non-empty and consists only of NFS4 ACL- * permission characters, false otherwise- */-static int-is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset)-{- const wchar_t *p = start;-- while (p < end) {- switch (*p++) {- case L'r':- *permset |= ARCHIVE_ENTRY_ACL_READ_DATA;- break;- case L'w':- *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA;- break;- case L'x':- *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;- break;- case L'p':- *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA;- break;- case L'D':- *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD;- break;- case L'd':- *permset |= ARCHIVE_ENTRY_ACL_DELETE;- break;- case L'a':- *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES;- break;- case L'A':- *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES;- break;- case L'R':- *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS;- break;- case L'W':- *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS;- break;- case L'c':- *permset |= ARCHIVE_ENTRY_ACL_READ_ACL;- break;- case L'C':- *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL;- break;- case L'o':- *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER;- break;- case L's':- *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;- break;- case L'-':- break;- default:- return(0);- }- }- return (1);-}--/*- * Parse a string as a NFS4 ACL flags field.- * Returns true if the string is non-empty and consists only of NFS4 ACL- * flag characters, false otherwise- */-static int-is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset)-{- const wchar_t *p = start;-- while (p < end) {- switch(*p++) {- case L'f':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT;- break;- case L'd':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT;- break;- case L'i':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY;- break;- case L'n':- *permset |=- ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT;- break;- case L'S':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS;- break;- case L'F':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS;- break;- case L'I':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED;- break;- case L'-':- break;- default:- return (0);- }- }- return (1);-}--/*- * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated- * to point to just after the separator. *start points to the first- * character of the matched text and *end just after the last- * character of the matched identifier. In particular *end - *start- * is the length of the field body, not including leading or trailing- * whitespace.- */-static void-next_field_w(const wchar_t **wp, const wchar_t **start,- const wchar_t **end, wchar_t *sep)-{- /* Skip leading whitespace to find start of field. */- while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') {- (*wp)++;- }- *start = *wp;-- /* Scan for the separator. */- while (**wp != L'\0' && **wp != L',' && **wp != L':' &&- **wp != L'\n' && **wp != L'#') {- (*wp)++;- }- *sep = **wp;-- /* Locate end of field, trim trailing whitespace if necessary */- if (*wp == *start) {- *end = *wp;- } else {- *end = *wp - 1;- while (**end == L' ' || **end == L'\t' || **end == L'\n') {- (*end)--;- }- (*end)++;- }-- /* Handle in-field comments */- if (*sep == L'#') {- while (**wp != L'\0' && **wp != L',' && **wp != L'\n') {- (*wp)++;- }- *sep = **wp;- }-- /* Adjust scanner location. */- if (**wp != L'\0')- (*wp)++;-}--/*- * Parse an ACL text string.- *- * The want_type argument may be one of the following:- * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS- * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT- * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL- *- * POSIX.1e ACL entries prefixed with "default:" are treated as- * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4- */-int-archive_acl_from_text_l(struct archive_acl *acl, const char *text,- int want_type, struct archive_string_conv *sc)-{- struct {- const char *start;- const char *end;- } field[6], name;-- const char *s, *st;- int numfields, fields, n, r, sol, ret;- int type, types, tag, permset, id;- size_t len;- char sep;-- switch (want_type) {- case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:- want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;- __LA_FALLTHROUGH;- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:- numfields = 5;- break;- case ARCHIVE_ENTRY_ACL_TYPE_NFS4:- numfields = 6;- break;- default:- return (ARCHIVE_FATAL);- }-- ret = ARCHIVE_OK;- types = 0;-- while (text != NULL && *text != '\0') {- /*- * Parse the fields out of the next entry,- * advance 'text' to start of next entry.- */- fields = 0;- do {- const char *start, *end;- next_field(&text, &start, &end, &sep);- if (fields < numfields) {- field[fields].start = start;- field[fields].end = end;- }- ++fields;- } while (sep == ':');-- /* Set remaining fields to blank. */- for (n = fields; n < numfields; ++n)- field[n].start = field[n].end = NULL;-- if (field[0].start != NULL && *(field[0].start) == '#') {- /* Comment, skip entry */- continue;- }-- n = 0;- sol = 0;- id = -1;- permset = 0;- name.start = name.end = NULL;-- if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- /* POSIX.1e ACLs */- /*- * Default keyword "default:user::rwx"- * if found, we have one more field- *- * We also support old Solaris extension:- * "defaultuser::rwx" is the default ACL corresponding- * to "user::rwx", etc. valid only for first field- */- s = field[0].start;- len = field[0].end - field[0].start;- if (*s == 'd' && (len == 1 || (len >= 7- && memcmp((s + 1), "efault", 6) == 0))) {- type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;- if (len > 7)- field[0].start += 7;- else- n = 1;- } else- type = want_type;-- /* Check for a numeric ID in field n+1 or n+3. */- isint(field[n + 1].start, field[n + 1].end, &id);- /* Field n+3 is optional. */- if (id == -1 && fields > (n + 3))- isint(field[n + 3].start, field[n + 3].end,- &id);-- tag = 0;- s = field[n].start;- st = field[n].start + 1;- len = field[n].end - field[n].start;-- if (len == 0) {- ret = ARCHIVE_WARN;- continue;- }-- switch (*s) {- case 'u':- if (len == 1 || (len == 4- && memcmp(st, "ser", 3) == 0))- tag = ARCHIVE_ENTRY_ACL_USER_OBJ;- break;- case 'g':- if (len == 1 || (len == 5- && memcmp(st, "roup", 4) == 0))- tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- break;- case 'o':- if (len == 1 || (len == 5- && memcmp(st, "ther", 4) == 0))- tag = ARCHIVE_ENTRY_ACL_OTHER;- break;- case 'm':- if (len == 1 || (len == 4- && memcmp(st, "ask", 3) == 0))- tag = ARCHIVE_ENTRY_ACL_MASK;- break;- default:- break;- }-- switch (tag) {- case ARCHIVE_ENTRY_ACL_OTHER:- case ARCHIVE_ENTRY_ACL_MASK:- if (fields == (n + 2)- && field[n + 1].start < field[n + 1].end- && ismode(field[n + 1].start,- field[n + 1].end, &permset)) {- /* This is Solaris-style "other:rwx" */- sol = 1;- } else if (fields == (n + 3) &&- field[n + 1].start < field[n + 1].end) {- /* Invalid mask or other field */- ret = ARCHIVE_WARN;- continue;- }- break;- case ARCHIVE_ENTRY_ACL_USER_OBJ:- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- if (id != -1 ||- field[n + 1].start < field[n + 1].end) {- name = field[n + 1];- if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)- tag = ARCHIVE_ENTRY_ACL_USER;- else- tag = ARCHIVE_ENTRY_ACL_GROUP;- }- break;- default:- /* Invalid tag, skip entry */- ret = ARCHIVE_WARN;- continue;- }-- /*- * Without "default:" we expect mode in field 3- * Exception: Solaris other and mask fields- */- if (permset == 0 && !ismode(field[n + 2 - sol].start,- field[n + 2 - sol].end, &permset)) {- /* Invalid mode, skip entry */- ret = ARCHIVE_WARN;- continue;- }- } else {- /* NFS4 ACLs */- s = field[0].start;- len = field[0].end - field[0].start;- tag = 0;-- switch (len) {- case 4:- if (memcmp(s, "user", 4) == 0)- tag = ARCHIVE_ENTRY_ACL_USER;- break;- case 5:- if (memcmp(s, "group", 5) == 0)- tag = ARCHIVE_ENTRY_ACL_GROUP;- break;- case 6:- if (memcmp(s, "owner@", 6) == 0)- tag = ARCHIVE_ENTRY_ACL_USER_OBJ;- else if (memcmp(s, "group@", 6) == 0)- tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- break;- case 9:- if (memcmp(s, "everyone@", 9) == 0)- tag = ARCHIVE_ENTRY_ACL_EVERYONE;- break;- default:- break;- }-- if (tag == 0) {- /* Invalid tag, skip entry */- ret = ARCHIVE_WARN;- continue;- } else if (tag == ARCHIVE_ENTRY_ACL_USER ||- tag == ARCHIVE_ENTRY_ACL_GROUP) {- n = 1;- name = field[1];- isint(name.start, name.end, &id);- } else- n = 0;-- if (!is_nfs4_perms(field[1 + n].start,- field[1 + n].end, &permset)) {- /* Invalid NFSv4 perms, skip entry */- ret = ARCHIVE_WARN;- continue;- }- if (!is_nfs4_flags(field[2 + n].start,- field[2 + n].end, &permset)) {- /* Invalid NFSv4 flags, skip entry */- ret = ARCHIVE_WARN;- continue;- }- s = field[3 + n].start;- len = field[3 + n].end - field[3 + n].start;- type = 0;- if (len == 4) {- if (memcmp(s, "deny", 4) == 0)- type = ARCHIVE_ENTRY_ACL_TYPE_DENY;- } else if (len == 5) {- if (memcmp(s, "allow", 5) == 0)- type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;- else if (memcmp(s, "audit", 5) == 0)- type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;- else if (memcmp(s, "alarm", 5) == 0)- type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;- }- if (type == 0) {- /* Invalid entry type, skip entry */- ret = ARCHIVE_WARN;- continue;- }- isint(field[4 + n].start, field[4 + n].end,- &id);- }-- /* Add entry to the internal list. */- r = archive_acl_add_entry_len_l(acl, type, permset,- tag, id, name.start, name.end - name.start, sc);- if (r < ARCHIVE_WARN)- return (r);- if (r != ARCHIVE_OK)- ret = ARCHIVE_WARN;- types |= type;- }-- /* Reset ACL */- archive_acl_reset(acl, types);-- return (ret);-}--/*- * Parse a string to a positive decimal integer. Returns true if- * the string is non-empty and consists only of decimal digits,- * false otherwise.- */-static int-isint(const char *start, const char *end, int *result)-{- int n = 0;- if (start >= end)- return (0);- while (start < end) {- if (*start < '0' || *start > '9')- return (0);- if (n > (INT_MAX / 10) ||- (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {- n = INT_MAX;- } else {- n *= 10;- n += *start - '0';- }- start++;- }- *result = n;- return (1);-}--/*- * Parse a string as a mode field. Returns true if- * the string is non-empty and consists only of mode characters,- * false otherwise.- */-static int-ismode(const char *start, const char *end, int *permset)-{- const char *p;-- if (start >= end)- return (0);- p = start;- *permset = 0;- while (p < end) {- switch (*p++) {- case 'r': case 'R':- *permset |= ARCHIVE_ENTRY_ACL_READ;- break;- case 'w': case 'W':- *permset |= ARCHIVE_ENTRY_ACL_WRITE;- break;- case 'x': case 'X':- *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;- break;- case '-':- break;- default:- return (0);- }- }- return (1);-}--/*- * Parse a string as a NFS4 ACL permission field.- * Returns true if the string is non-empty and consists only of NFS4 ACL- * permission characters, false otherwise- */-static int-is_nfs4_perms(const char *start, const char *end, int *permset)-{- const char *p = start;-- while (p < end) {- switch (*p++) {- case 'r':- *permset |= ARCHIVE_ENTRY_ACL_READ_DATA;- break;- case 'w':- *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA;- break;- case 'x':- *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;- break;- case 'p':- *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA;- break;- case 'D':- *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD;- break;- case 'd':- *permset |= ARCHIVE_ENTRY_ACL_DELETE;- break;- case 'a':- *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES;- break;- case 'A':- *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES;- break;- case 'R':- *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS;- break;- case 'W':- *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS;- break;- case 'c':- *permset |= ARCHIVE_ENTRY_ACL_READ_ACL;- break;- case 'C':- *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL;- break;- case 'o':- *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER;- break;- case 's':- *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;- break;- case '-':- break;- default:- return(0);- }- }- return (1);-}--/*- * Parse a string as a NFS4 ACL flags field.- * Returns true if the string is non-empty and consists only of NFS4 ACL- * flag characters, false otherwise- */-static int-is_nfs4_flags(const char *start, const char *end, int *permset)-{- const char *p = start;-- while (p < end) {- switch(*p++) {- case 'f':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT;- break;- case 'd':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT;- break;- case 'i':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY;- break;- case 'n':- *permset |=- ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT;- break;- case 'S':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS;- break;- case 'F':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS;- break;- case 'I':- *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED;- break;- case '-':- break;- default:- return (0);- }- }- return (1);-}--/*- * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated- * to point to just after the separator. *start points to the first- * character of the matched text and *end just after the last- * character of the matched identifier. In particular *end - *start- * is the length of the field body, not including leading or trailing- * whitespace.- */-static void-next_field(const char **p, const char **start,- const char **end, char *sep)-{- /* Skip leading whitespace to find start of field. */- while (**p == ' ' || **p == '\t' || **p == '\n') {- (*p)++;- }- *start = *p;-- /* Scan for the separator. */- while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n' &&- **p != '#') {- (*p)++;- }- *sep = **p;-- /* Locate end of field, trim trailing whitespace if necessary */- if (*p == *start) {- *end = *p;- } else {- *end = *p - 1;- while (**end == ' ' || **end == '\t' || **end == '\n') {- (*end)--;- }- (*end)++;- }-- /* Handle in-field comments */- if (*sep == '#') {- while (**p != '\0' && **p != ',' && **p != '\n') {- (*p)++;- }- *sep = **p;- }-- /* Adjust scanner location. */- if (**p != '\0')- (*p)++;-}
− c/archive_acl_private.h
@@ -1,83 +0,0 @@-/*-- * 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.- *- * $FreeBSD$- */--#ifndef ARCHIVE_ACL_PRIVATE_H_INCLUDED-#define ARCHIVE_ACL_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--#include "archive_string.h"--struct archive_acl_entry {- struct archive_acl_entry *next;- int type; /* E.g., access or default */- int tag; /* E.g., user/group/other/mask */- int permset; /* r/w/x bits */- int id; /* uid/gid for user/group */- struct archive_mstring name; /* uname/gname */-};--struct archive_acl {- mode_t mode;- struct archive_acl_entry *acl_head;- struct archive_acl_entry *acl_p;- int acl_state; /* See acl_next for details. */- wchar_t *acl_text_w;- char *acl_text;- int acl_types;-};--void archive_acl_clear(struct archive_acl *);-void archive_acl_copy(struct archive_acl *, struct archive_acl *);-int archive_acl_count(struct archive_acl *, int);-int archive_acl_types(struct archive_acl *);-int archive_acl_reset(struct archive_acl *, int);-int archive_acl_next(struct archive *, struct archive_acl *, int,- int *, int *, int *, int *, const char **);--int archive_acl_add_entry(struct archive_acl *, int, int, int, int, const char *);-int archive_acl_add_entry_w_len(struct archive_acl *,- int, int, int, int, const wchar_t *, size_t);-int archive_acl_add_entry_len(struct archive_acl *,- int, int, int, int, const char *, size_t);--wchar_t *archive_acl_to_text_w(struct archive_acl *, ssize_t *, int,- struct archive *);-char *archive_acl_to_text_l(struct archive_acl *, ssize_t *, int,- struct archive_string_conv *);--/*- * ACL text parser.- */-int archive_acl_from_text_w(struct archive_acl *, const wchar_t * /* wtext */,- int /* type */);-int archive_acl_from_text_l(struct archive_acl *, const char * /* text */,- int /* type */, struct archive_string_conv *);--#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
− c/archive_blake2.h
@@ -1,197 +0,0 @@-/*- BLAKE2 reference source code package - reference C implementations-- Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the- terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at- your option. The terms of these licenses can be found at:-- - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0- - OpenSSL license : https://www.openssl.org/source/license.html- - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0-- More information about the BLAKE2 hash function can be found at- https://blake2.net.-*/--#ifndef ARCHIVE_BLAKE2_H-#define ARCHIVE_BLAKE2_H--#include <stddef.h>-#include <stdint.h>--#if defined(_MSC_VER)-#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))-#elif defined(__GNUC__)-#define BLAKE2_PACKED(x) x __attribute__((packed))-#else-#define BLAKE2_PACKED(x) _Pragma("pack 1") x _Pragma("pack 0")-#endif--#if defined(__cplusplus)-extern "C" {-#endif-- enum blake2s_constant- {- BLAKE2S_BLOCKBYTES = 64,- BLAKE2S_OUTBYTES = 32,- BLAKE2S_KEYBYTES = 32,- BLAKE2S_SALTBYTES = 8,- BLAKE2S_PERSONALBYTES = 8- };-- enum blake2b_constant- {- BLAKE2B_BLOCKBYTES = 128,- BLAKE2B_OUTBYTES = 64,- BLAKE2B_KEYBYTES = 64,- BLAKE2B_SALTBYTES = 16,- BLAKE2B_PERSONALBYTES = 16- };-- typedef struct blake2s_state__- {- uint32_t h[8];- uint32_t t[2];- uint32_t f[2];- uint8_t buf[BLAKE2S_BLOCKBYTES];- size_t buflen;- size_t outlen;- uint8_t last_node;- } blake2s_state;-- typedef struct blake2b_state__- {- uint64_t h[8];- uint64_t t[2];- uint64_t f[2];- uint8_t buf[BLAKE2B_BLOCKBYTES];- size_t buflen;- size_t outlen;- uint8_t last_node;- } blake2b_state;-- typedef struct blake2sp_state__- {- blake2s_state S[8][1];- blake2s_state R[1];- uint8_t buf[8 * BLAKE2S_BLOCKBYTES];- size_t buflen;- size_t outlen;- } blake2sp_state;-- typedef struct blake2bp_state__- {- blake2b_state S[4][1];- blake2b_state R[1];- uint8_t buf[4 * BLAKE2B_BLOCKBYTES];- size_t buflen;- size_t outlen;- } blake2bp_state;-- BLAKE2_PACKED(struct blake2s_param__- {- uint8_t digest_length; /* 1 */- uint8_t key_length; /* 2 */- uint8_t fanout; /* 3 */- uint8_t depth; /* 4 */- uint32_t leaf_length; /* 8 */- uint32_t node_offset; /* 12 */- uint16_t xof_length; /* 14 */- uint8_t node_depth; /* 15 */- uint8_t inner_length; /* 16 */- /* uint8_t reserved[0]; */- uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */- uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */- });-- typedef struct blake2s_param__ blake2s_param;-- BLAKE2_PACKED(struct blake2b_param__- {- uint8_t digest_length; /* 1 */- uint8_t key_length; /* 2 */- uint8_t fanout; /* 3 */- uint8_t depth; /* 4 */- uint32_t leaf_length; /* 8 */- uint32_t node_offset; /* 12 */- uint32_t xof_length; /* 16 */- uint8_t node_depth; /* 17 */- uint8_t inner_length; /* 18 */- uint8_t reserved[14]; /* 32 */- uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */- uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */- });-- typedef struct blake2b_param__ blake2b_param;-- typedef struct blake2xs_state__- {- blake2s_state S[1];- blake2s_param P[1];- } blake2xs_state;-- typedef struct blake2xb_state__- {- blake2b_state S[1];- blake2b_param P[1];- } blake2xb_state;-- /* Padded structs result in a compile-time error */- enum {- BLAKE2_DUMMY_1 = 1/(sizeof(blake2s_param) == BLAKE2S_OUTBYTES),- BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES)- };-- /* Streaming API */- int blake2s_init( blake2s_state *S, size_t outlen );- int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen );- int blake2s_init_param( blake2s_state *S, const blake2s_param *P );- int blake2s_update( blake2s_state *S, const void *in, size_t inlen );- int blake2s_final( blake2s_state *S, void *out, size_t outlen );-- int blake2b_init( blake2b_state *S, size_t outlen );- int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen );- int blake2b_init_param( blake2b_state *S, const blake2b_param *P );- int blake2b_update( blake2b_state *S, const void *in, size_t inlen );- int blake2b_final( blake2b_state *S, void *out, size_t outlen );-- int blake2sp_init( blake2sp_state *S, size_t outlen );- int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen );- int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen );- int blake2sp_final( blake2sp_state *S, void *out, size_t outlen );-- int blake2bp_init( blake2bp_state *S, size_t outlen );- int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen );- int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen );- int blake2bp_final( blake2bp_state *S, void *out, size_t outlen );-- /* Variable output length API */- int blake2xs_init( blake2xs_state *S, const size_t outlen );- int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen );- int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen );- int blake2xs_final(blake2xs_state *S, void *out, size_t outlen);-- int blake2xb_init( blake2xb_state *S, const size_t outlen );- int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen );- int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen );- int blake2xb_final(blake2xb_state *S, void *out, size_t outlen);-- /* Simple API */- int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );- int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );-- int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );- int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );-- int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );- int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );-- /* This is simply an alias for blake2b */- int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );--#if defined(__cplusplus)-}-#endif--#endif
− c/archive_blake2_impl.h
@@ -1,161 +0,0 @@-/*- BLAKE2 reference source code package - reference C implementations-- Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the- terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at- your option. The terms of these licenses can be found at:-- - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0- - OpenSSL license : https://www.openssl.org/source/license.html- - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0-- More information about the BLAKE2 hash function can be found at- https://blake2.net.-*/--#ifndef ARCHIVE_BLAKE2_IMPL_H-#define ARCHIVE_BLAKE2_IMPL_H--#include <stdint.h>-#include <string.h>--#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)- #if defined(_MSC_VER)- #define BLAKE2_INLINE __inline- #elif defined(__GNUC__)- #define BLAKE2_INLINE __inline__- #else- #define BLAKE2_INLINE- #endif-#else- #define BLAKE2_INLINE inline-#endif--static BLAKE2_INLINE uint32_t load32( const void *src )-{-#if defined(NATIVE_LITTLE_ENDIAN)- uint32_t w;- memcpy(&w, src, sizeof w);- return w;-#else- const uint8_t *p = ( const uint8_t * )src;- return (( uint32_t )( p[0] ) << 0) |- (( uint32_t )( p[1] ) << 8) |- (( uint32_t )( p[2] ) << 16) |- (( uint32_t )( p[3] ) << 24) ;-#endif-}--static BLAKE2_INLINE uint64_t load64( const void *src )-{-#if defined(NATIVE_LITTLE_ENDIAN)- uint64_t w;- memcpy(&w, src, sizeof w);- return w;-#else- const uint8_t *p = ( const uint8_t * )src;- return (( uint64_t )( p[0] ) << 0) |- (( uint64_t )( p[1] ) << 8) |- (( uint64_t )( p[2] ) << 16) |- (( uint64_t )( p[3] ) << 24) |- (( uint64_t )( p[4] ) << 32) |- (( uint64_t )( p[5] ) << 40) |- (( uint64_t )( p[6] ) << 48) |- (( uint64_t )( p[7] ) << 56) ;-#endif-}--static BLAKE2_INLINE uint16_t load16( const void *src )-{-#if defined(NATIVE_LITTLE_ENDIAN)- uint16_t w;- memcpy(&w, src, sizeof w);- return w;-#else- const uint8_t *p = ( const uint8_t * )src;- return ( uint16_t )((( uint32_t )( p[0] ) << 0) |- (( uint32_t )( p[1] ) << 8));-#endif-}--static BLAKE2_INLINE void store16( void *dst, uint16_t w )-{-#if defined(NATIVE_LITTLE_ENDIAN)- memcpy(dst, &w, sizeof w);-#else- uint8_t *p = ( uint8_t * )dst;- *p++ = ( uint8_t )w; w >>= 8;- *p++ = ( uint8_t )w;-#endif-}--static BLAKE2_INLINE void store32( void *dst, uint32_t w )-{-#if defined(NATIVE_LITTLE_ENDIAN)- memcpy(dst, &w, sizeof w);-#else- uint8_t *p = ( uint8_t * )dst;- p[0] = (uint8_t)(w >> 0);- p[1] = (uint8_t)(w >> 8);- p[2] = (uint8_t)(w >> 16);- p[3] = (uint8_t)(w >> 24);-#endif-}--static BLAKE2_INLINE void store64( void *dst, uint64_t w )-{-#if defined(NATIVE_LITTLE_ENDIAN)- memcpy(dst, &w, sizeof w);-#else- uint8_t *p = ( uint8_t * )dst;- p[0] = (uint8_t)(w >> 0);- p[1] = (uint8_t)(w >> 8);- p[2] = (uint8_t)(w >> 16);- p[3] = (uint8_t)(w >> 24);- p[4] = (uint8_t)(w >> 32);- p[5] = (uint8_t)(w >> 40);- p[6] = (uint8_t)(w >> 48);- p[7] = (uint8_t)(w >> 56);-#endif-}--static BLAKE2_INLINE uint64_t load48( const void *src )-{- const uint8_t *p = ( const uint8_t * )src;- return (( uint64_t )( p[0] ) << 0) |- (( uint64_t )( p[1] ) << 8) |- (( uint64_t )( p[2] ) << 16) |- (( uint64_t )( p[3] ) << 24) |- (( uint64_t )( p[4] ) << 32) |- (( uint64_t )( p[5] ) << 40) ;-}--static BLAKE2_INLINE void store48( void *dst, uint64_t w )-{- uint8_t *p = ( uint8_t * )dst;- p[0] = (uint8_t)(w >> 0);- p[1] = (uint8_t)(w >> 8);- p[2] = (uint8_t)(w >> 16);- p[3] = (uint8_t)(w >> 24);- p[4] = (uint8_t)(w >> 32);- p[5] = (uint8_t)(w >> 40);-}--static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )-{- return ( w >> c ) | ( w << ( 32 - c ) );-}--static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )-{- return ( w >> c ) | ( w << ( 64 - c ) );-}--/* prevents compiler optimizing out memset() */-static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n)-{- static void *(__LA_LIBC_CC *const volatile memset_v)(void *, int, size_t) = &memset;- memset_v(v, 0, n);-}--#endif
− c/archive_blake2s_ref.c
@@ -1,369 +0,0 @@-/*- BLAKE2 reference source code package - reference C implementations-- Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the- terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at- your option. The terms of these licenses can be found at:-- - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0- - OpenSSL license : https://www.openssl.org/source/license.html- - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0-- More information about the BLAKE2 hash function can be found at- https://blake2.net.-*/--#include "archive_platform.h"--#include <stdint.h>-#include <string.h>-#include <stdio.h>--#include "archive_blake2.h"-#include "archive_blake2_impl.h"--static const uint32_t blake2s_IV[8] =-{- 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,- 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL-};--static const uint8_t blake2s_sigma[10][16] =-{- { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,- { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,- { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,- { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,- { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,- { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,- { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,- { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,- { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,- { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,-};--static void blake2s_set_lastnode( blake2s_state *S )-{- S->f[1] = (uint32_t)-1;-}--/* Some helper functions, not necessarily useful */-static int blake2s_is_lastblock( const blake2s_state *S )-{- return S->f[0] != 0;-}--static void blake2s_set_lastblock( blake2s_state *S )-{- if( S->last_node ) blake2s_set_lastnode( S );-- S->f[0] = (uint32_t)-1;-}--static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc )-{- S->t[0] += inc;- S->t[1] += ( S->t[0] < inc );-}--static void blake2s_init0( blake2s_state *S )-{- size_t i;- memset( S, 0, sizeof( blake2s_state ) );-- for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i];-}--/* init2 xors IV with input parameter block */-int blake2s_init_param( blake2s_state *S, const blake2s_param *P )-{- const unsigned char *p = ( const unsigned char * )( P );- size_t i;-- blake2s_init0( S );-- /* IV XOR ParamBlock */- for( i = 0; i < 8; ++i )- S->h[i] ^= load32( &p[i * 4] );-- S->outlen = P->digest_length;- return 0;-}---/* Sequential blake2s initialization */-int blake2s_init( blake2s_state *S, size_t outlen )-{- blake2s_param P[1];-- /* Move interval verification here? */- if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;-- P->digest_length = (uint8_t)outlen;- P->key_length = 0;- P->fanout = 1;- P->depth = 1;- store32( &P->leaf_length, 0 );- store32( &P->node_offset, 0 );- store16( &P->xof_length, 0 );- P->node_depth = 0;- P->inner_length = 0;- /* memset(P->reserved, 0, sizeof(P->reserved) ); */- memset( P->salt, 0, sizeof( P->salt ) );- memset( P->personal, 0, sizeof( P->personal ) );- return blake2s_init_param( S, P );-}--int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen )-{- blake2s_param P[1];-- if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;-- if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;-- P->digest_length = (uint8_t)outlen;- P->key_length = (uint8_t)keylen;- P->fanout = 1;- P->depth = 1;- store32( &P->leaf_length, 0 );- store32( &P->node_offset, 0 );- store16( &P->xof_length, 0 );- P->node_depth = 0;- P->inner_length = 0;- /* memset(P->reserved, 0, sizeof(P->reserved) ); */- memset( P->salt, 0, sizeof( P->salt ) );- memset( P->personal, 0, sizeof( P->personal ) );-- if( blake2s_init_param( S, P ) < 0 ) return -1;-- {- uint8_t block[BLAKE2S_BLOCKBYTES];- memset( block, 0, BLAKE2S_BLOCKBYTES );- memcpy( block, key, keylen );- blake2s_update( S, block, BLAKE2S_BLOCKBYTES );- secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */- }- return 0;-}--#define G(r,i,a,b,c,d) \- do { \- a = a + b + m[blake2s_sigma[r][2*i+0]]; \- d = rotr32(d ^ a, 16); \- c = c + d; \- b = rotr32(b ^ c, 12); \- a = a + b + m[blake2s_sigma[r][2*i+1]]; \- d = rotr32(d ^ a, 8); \- c = c + d; \- b = rotr32(b ^ c, 7); \- } while(0)--#define ROUND(r) \- do { \- G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \- G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \- G(r,2,v[ 2],v[ 6],v[10],v[14]); \- G(r,3,v[ 3],v[ 7],v[11],v[15]); \- G(r,4,v[ 0],v[ 5],v[10],v[15]); \- G(r,5,v[ 1],v[ 6],v[11],v[12]); \- G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \- G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \- } while(0)--static void blake2s_compress( blake2s_state *S, const uint8_t in[BLAKE2S_BLOCKBYTES] )-{- uint32_t m[16];- uint32_t v[16];- size_t i;-- for( i = 0; i < 16; ++i ) {- m[i] = load32( in + i * sizeof( m[i] ) );- }-- for( i = 0; i < 8; ++i ) {- v[i] = S->h[i];- }-- v[ 8] = blake2s_IV[0];- v[ 9] = blake2s_IV[1];- v[10] = blake2s_IV[2];- v[11] = blake2s_IV[3];- v[12] = S->t[0] ^ blake2s_IV[4];- v[13] = S->t[1] ^ blake2s_IV[5];- v[14] = S->f[0] ^ blake2s_IV[6];- v[15] = S->f[1] ^ blake2s_IV[7];-- ROUND( 0 );- ROUND( 1 );- ROUND( 2 );- ROUND( 3 );- ROUND( 4 );- ROUND( 5 );- ROUND( 6 );- ROUND( 7 );- ROUND( 8 );- ROUND( 9 );-- for( i = 0; i < 8; ++i ) {- S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];- }-}--#undef G-#undef ROUND--int blake2s_update( blake2s_state *S, const void *pin, size_t inlen )-{- const unsigned char * in = (const unsigned char *)pin;- if( inlen > 0 )- {- size_t left = S->buflen;- size_t fill = BLAKE2S_BLOCKBYTES - left;- if( inlen > fill )- {- S->buflen = 0;- memcpy( S->buf + left, in, fill ); /* Fill buffer */- blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );- blake2s_compress( S, S->buf ); /* Compress */- in += fill; inlen -= fill;- while(inlen > BLAKE2S_BLOCKBYTES) {- blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES);- blake2s_compress( S, in );- in += BLAKE2S_BLOCKBYTES;- inlen -= BLAKE2S_BLOCKBYTES;- }- }- memcpy( S->buf + S->buflen, in, inlen );- S->buflen += inlen;- }- return 0;-}--int blake2s_final( blake2s_state *S, void *out, size_t outlen )-{- uint8_t buffer[BLAKE2S_OUTBYTES] = {0};- size_t i;-- if( out == NULL || outlen < S->outlen )- return -1;-- if( blake2s_is_lastblock( S ) )- return -1;-- blake2s_increment_counter( S, ( uint32_t )S->buflen );- blake2s_set_lastblock( S );- memset( S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */- blake2s_compress( S, S->buf );-- for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */- store32( buffer + sizeof( S->h[i] ) * i, S->h[i] );-- memcpy( out, buffer, outlen );- secure_zero_memory(buffer, sizeof(buffer));- return 0;-}--int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )-{- blake2s_state S[1];-- /* Verify parameters */- if ( NULL == in && inlen > 0 ) return -1;-- if ( NULL == out ) return -1;-- if ( NULL == key && keylen > 0) return -1;-- if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;-- if( keylen > BLAKE2S_KEYBYTES ) return -1;-- if( keylen > 0 )- {- if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1;- }- else- {- if( blake2s_init( S, outlen ) < 0 ) return -1;- }-- blake2s_update( S, ( const uint8_t * )in, inlen );- blake2s_final( S, out, outlen );- return 0;-}--#if defined(SUPERCOP)-int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )-{- return blake2s( out, BLAKE2S_OUTBYTES, in, inlen, NULL, 0 );-}-#endif--#if defined(BLAKE2S_SELFTEST)-#include <string.h>-#include "blake2-kat.h"-int main( void )-{- uint8_t key[BLAKE2S_KEYBYTES];- uint8_t buf[BLAKE2_KAT_LENGTH];- size_t i, step;-- for( i = 0; i < BLAKE2S_KEYBYTES; ++i )- key[i] = ( uint8_t )i;-- for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )- buf[i] = ( uint8_t )i;-- /* Test simple API */- for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )- {- uint8_t hash[BLAKE2S_OUTBYTES];- blake2s( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES );-- if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) )- {- goto fail;- }- }-- /* Test streaming API */- for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {- for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {- uint8_t hash[BLAKE2S_OUTBYTES];- blake2s_state S;- uint8_t * p = buf;- size_t mlen = i;- int err = 0;-- if( (err = blake2s_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) {- goto fail;- }-- while (mlen >= step) {- if ( (err = blake2s_update(&S, p, step)) < 0 ) {- goto fail;- }- mlen -= step;- p += step;- }- if ( (err = blake2s_update(&S, p, mlen)) < 0) {- goto fail;- }- if ( (err = blake2s_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {- goto fail;- }-- if (0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) {- goto fail;- }- }- }-- puts( "ok" );- return 0;-fail:- puts("error");- return -1;-}-#endif
− c/archive_blake2sp_ref.c
@@ -1,361 +0,0 @@-/*- BLAKE2 reference source code package - reference C implementations-- Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the- terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at- your option. The terms of these licenses can be found at:-- - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0- - OpenSSL license : https://www.openssl.org/source/license.html- - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0-- More information about the BLAKE2 hash function can be found at- https://blake2.net.-*/--#include "archive_platform.h"--#include <stdlib.h>-#include <string.h>-#include <stdio.h>--#if defined(_OPENMP)-#include <omp.h>-#endif--#include "archive_blake2.h"-#include "archive_blake2_impl.h"--#define PARALLELISM_DEGREE 8--/*- blake2sp_init_param defaults to setting the expecting output length- from the digest_length parameter block field.-- In some cases, however, we do not want this, as the output length- of these instances is given by inner_length instead.-*/-static int blake2sp_init_leaf_param( blake2s_state *S, const blake2s_param *P )-{- int err = blake2s_init_param(S, P);- S->outlen = P->inner_length;- return err;-}--static int blake2sp_init_leaf( blake2s_state *S, size_t outlen, size_t keylen, uint32_t offset )-{- blake2s_param P[1];- P->digest_length = (uint8_t)outlen;- P->key_length = (uint8_t)keylen;- P->fanout = PARALLELISM_DEGREE;- P->depth = 2;- store32( &P->leaf_length, 0 );- store32( &P->node_offset, offset );- store16( &P->xof_length, 0 );- P->node_depth = 0;- P->inner_length = BLAKE2S_OUTBYTES;- memset( P->salt, 0, sizeof( P->salt ) );- memset( P->personal, 0, sizeof( P->personal ) );- return blake2sp_init_leaf_param( S, P );-}--static int blake2sp_init_root( blake2s_state *S, size_t outlen, size_t keylen )-{- blake2s_param P[1];- P->digest_length = (uint8_t)outlen;- P->key_length = (uint8_t)keylen;- P->fanout = PARALLELISM_DEGREE;- P->depth = 2;- store32( &P->leaf_length, 0 );- store32( &P->node_offset, 0 );- store16( &P->xof_length, 0 );- P->node_depth = 1;- P->inner_length = BLAKE2S_OUTBYTES;- memset( P->salt, 0, sizeof( P->salt ) );- memset( P->personal, 0, sizeof( P->personal ) );- return blake2s_init_param( S, P );-}---int blake2sp_init( blake2sp_state *S, size_t outlen )-{- size_t i;-- if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;-- memset( S->buf, 0, sizeof( S->buf ) );- S->buflen = 0;- S->outlen = outlen;-- if( blake2sp_init_root( S->R, outlen, 0 ) < 0 )- return -1;-- for( i = 0; i < PARALLELISM_DEGREE; ++i )- if( blake2sp_init_leaf( S->S[i], outlen, 0, (uint32_t)i ) < 0 ) return -1;-- S->R->last_node = 1;- S->S[PARALLELISM_DEGREE - 1]->last_node = 1;- return 0;-}--int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen )-{- size_t i;-- if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;-- if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;-- memset( S->buf, 0, sizeof( S->buf ) );- S->buflen = 0;- S->outlen = outlen;-- if( blake2sp_init_root( S->R, outlen, keylen ) < 0 )- return -1;-- for( i = 0; i < PARALLELISM_DEGREE; ++i )- if( blake2sp_init_leaf( S->S[i], outlen, keylen, (uint32_t)i ) < 0 ) return -1;-- S->R->last_node = 1;- S->S[PARALLELISM_DEGREE - 1]->last_node = 1;- {- uint8_t block[BLAKE2S_BLOCKBYTES];- memset( block, 0, BLAKE2S_BLOCKBYTES );- memcpy( block, key, keylen );-- for( i = 0; i < PARALLELISM_DEGREE; ++i )- blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES );-- secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */- }- return 0;-}---int blake2sp_update( blake2sp_state *S, const void *pin, size_t inlen )-{- const unsigned char * in = (const unsigned char *)pin;- size_t left = S->buflen;- size_t fill = sizeof( S->buf ) - left;- size_t i;-- if( left && inlen >= fill )- {- memcpy( S->buf + left, in, fill );-- for( i = 0; i < PARALLELISM_DEGREE; ++i )- blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );-- in += fill;- inlen -= fill;- left = 0;- }--#if defined(_OPENMP)- #pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)-#else- for( i = 0; i < PARALLELISM_DEGREE; ++i )-#endif- {-#if defined(_OPENMP)- size_t i = omp_get_thread_num();-#endif- size_t inlen__ = inlen;- const unsigned char *in__ = ( const unsigned char * )in;- in__ += i * BLAKE2S_BLOCKBYTES;-- while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )- {- blake2s_update( S->S[i], in__, BLAKE2S_BLOCKBYTES );- in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;- inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;- }- }-- in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );- inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;-- if( inlen > 0 )- memcpy( S->buf + left, in, inlen );-- S->buflen = left + inlen;- return 0;-}---int blake2sp_final( blake2sp_state *S, void *out, size_t outlen )-{- uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];- size_t i;-- if(out == NULL || outlen < S->outlen) {- return -1;- }-- for( i = 0; i < PARALLELISM_DEGREE; ++i )- {- if( S->buflen > i * BLAKE2S_BLOCKBYTES )- {- size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;-- if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;-- blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );- }-- blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES );- }-- for( i = 0; i < PARALLELISM_DEGREE; ++i )- blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES );-- return blake2s_final( S->R, out, S->outlen );-}---int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )-{- uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];- blake2s_state S[PARALLELISM_DEGREE][1];- blake2s_state FS[1];- size_t i;-- /* Verify parameters */- if ( NULL == in && inlen > 0 ) return -1;-- if ( NULL == out ) return -1;-- if ( NULL == key && keylen > 0) return -1;-- if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;-- if( keylen > BLAKE2S_KEYBYTES ) return -1;-- for( i = 0; i < PARALLELISM_DEGREE; ++i )- if( blake2sp_init_leaf( S[i], outlen, keylen, (uint32_t)i ) < 0 ) return -1;-- S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */-- if( keylen > 0 )- {- uint8_t block[BLAKE2S_BLOCKBYTES];- memset( block, 0, BLAKE2S_BLOCKBYTES );- memcpy( block, key, keylen );-- for( i = 0; i < PARALLELISM_DEGREE; ++i )- blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES );-- secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */- }--#if defined(_OPENMP)- #pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)-#else-- for( i = 0; i < PARALLELISM_DEGREE; ++i )-#endif- {-#if defined(_OPENMP)- size_t i = omp_get_thread_num();-#endif- size_t inlen__ = inlen;- const unsigned char *in__ = ( const unsigned char * )in;- in__ += i * BLAKE2S_BLOCKBYTES;-- while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )- {- blake2s_update( S[i], in__, BLAKE2S_BLOCKBYTES );- in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;- inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;- }-- if( inlen__ > i * BLAKE2S_BLOCKBYTES )- {- const size_t left = inlen__ - i * BLAKE2S_BLOCKBYTES;- const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES;- blake2s_update( S[i], in__, len );- }-- blake2s_final( S[i], hash[i], BLAKE2S_OUTBYTES );- }-- if( blake2sp_init_root( FS, outlen, keylen ) < 0 )- return -1;-- FS->last_node = 1;-- for( i = 0; i < PARALLELISM_DEGREE; ++i )- blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES );-- return blake2s_final( FS, out, outlen );-}----#if defined(BLAKE2SP_SELFTEST)-#include <string.h>-#include "blake2-kat.h"-int main( void )-{- uint8_t key[BLAKE2S_KEYBYTES];- uint8_t buf[BLAKE2_KAT_LENGTH];- size_t i, step;-- for( i = 0; i < BLAKE2S_KEYBYTES; ++i )- key[i] = ( uint8_t )i;-- for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )- buf[i] = ( uint8_t )i;-- /* Test simple API */- for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )- {- uint8_t hash[BLAKE2S_OUTBYTES];- blake2sp( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES );-- if( 0 != memcmp( hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES ) )- {- goto fail;- }- }-- /* Test streaming API */- for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {- for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {- uint8_t hash[BLAKE2S_OUTBYTES];- blake2sp_state S;- uint8_t * p = buf;- size_t mlen = i;- int err = 0;-- if( (err = blake2sp_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) {- goto fail;- }-- while (mlen >= step) {- if ( (err = blake2sp_update(&S, p, step)) < 0 ) {- goto fail;- }- mlen -= step;- p += step;- }- if ( (err = blake2sp_update(&S, p, mlen)) < 0) {- goto fail;- }- if ( (err = blake2sp_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {- goto fail;- }-- if (0 != memcmp(hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES)) {- goto fail;- }- }- }-- puts( "ok" );- return 0;-fail:- puts("error");- return -1;-}-#endif
− c/archive_check_magic.c
@@ -1,175 +0,0 @@-/*-- * 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_check_magic.c 201089 2009-12-28 02:20:23Z kientzle $");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif--#include <stdio.h>-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif-#if defined(_WIN32) && !defined(__CYGWIN__)-#include <windows.h>-#include <winbase.h>-#endif--#include "archive_private.h"--static void-errmsg(const char *m)-{- size_t s = strlen(m);- ssize_t written;-- while (s > 0) {- written = write(2, m, s);- if (written <= 0)- return;- m += written;- s -= written;- }-}--static __LA_DEAD void-diediedie(void)-{-#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)- /* Cause a breakpoint exception */- DebugBreak();-#endif- abort(); /* Terminate the program abnormally. */-}--static const char *-state_name(unsigned s)-{- switch (s) {- case ARCHIVE_STATE_NEW: return ("new");- case ARCHIVE_STATE_HEADER: return ("header");- case ARCHIVE_STATE_DATA: return ("data");- case ARCHIVE_STATE_EOF: return ("eof");- case ARCHIVE_STATE_CLOSED: return ("closed");- case ARCHIVE_STATE_FATAL: return ("fatal");- default: return ("??");- }-}--static const char *-archive_handle_type_name(unsigned m)-{- switch (m) {- case ARCHIVE_WRITE_MAGIC: return ("archive_write");- case ARCHIVE_READ_MAGIC: return ("archive_read");- case ARCHIVE_WRITE_DISK_MAGIC: return ("archive_write_disk");- case ARCHIVE_READ_DISK_MAGIC: return ("archive_read_disk");- case ARCHIVE_MATCH_MAGIC: return ("archive_match");- default: return NULL;- }-}---static char *-write_all_states(char *buff, unsigned int states)-{- unsigned int lowbit;-- buff[0] = '\0';-- /* A trick for computing the lowest set bit. */- while ((lowbit = states & (1 + ~states)) != 0) {- states &= ~lowbit; /* Clear the low bit. */- strcat(buff, state_name(lowbit));- if (states != 0)- strcat(buff, "/");- }- return buff;-}--/*- * Check magic value and current state.- * Magic value mismatches are fatal and result in calls to abort().- * State mismatches return ARCHIVE_FATAL.- * Otherwise, returns ARCHIVE_OK.- *- * This is designed to catch serious programming errors that violate- * the libarchive API.- */-int-__archive_check_magic(struct archive *a, unsigned int magic,- unsigned int state, const char *function)-{- char states1[64];- char states2[64];- const char *handle_type;-- /*- * If this isn't some form of archive handle,- * then the library user has screwed up so bad that- * we don't even have a reliable way to report an error.- */- handle_type = archive_handle_type_name(a->magic);-- if (!handle_type) {- errmsg("PROGRAMMER ERROR: Function ");- errmsg(function);- errmsg(" invoked with invalid archive handle.\n");- diediedie();- }-- if (a->magic != magic) {- archive_set_error(a, -1,- "PROGRAMMER ERROR: Function '%s' invoked"- " on '%s' archive object, which is not supported.",- function,- handle_type);- a->state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }-- if ((a->state & state) == 0) {- /* If we're already FATAL, don't overwrite the error. */- if (a->state != ARCHIVE_STATE_FATAL)- archive_set_error(a, -1,- "INTERNAL ERROR: Function '%s' invoked with"- " archive structure in state '%s',"- " should be in state '%s'",- function,- write_all_states(states1, a->state),- write_all_states(states2, state));- a->state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- return ARCHIVE_OK;-}
− c/archive_cmdline.c
@@ -1,227 +0,0 @@-/*-- * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#ifdef HAVE_STRING_H-# include <string.h>-#endif-#ifdef HAVE_STDLIB_H-# include <stdlib.h>-#endif--#include "archive.h"-#include "archive_cmdline_private.h"-#include "archive_string.h"--static int cmdline_set_path(struct archive_cmdline *, const char *);-static int cmdline_add_arg(struct archive_cmdline *, const char *);--static ssize_t-extract_quotation(struct archive_string *as, const char *p)-{- const char *s;-- for (s = p + 1; *s;) {- if (*s == '\\') {- if (s[1] != '\0') {- archive_strappend_char(as, s[1]);- s += 2;- } else- s++;- } else if (*s == '"')- break;- else {- archive_strappend_char(as, s[0]);- s++;- }- }- if (*s != '"')- return (ARCHIVE_FAILED);/* Invalid sequence. */- return ((ssize_t)(s + 1 - p));-}--static ssize_t-get_argument(struct archive_string *as, const char *p)-{- const char *s = p;-- archive_string_empty(as);-- /* Skip beginning space characters. */- while (*s != '\0' && *s == ' ')- s++;- /* Copy non-space characters. */- while (*s != '\0' && *s != ' ') {- if (*s == '\\') {- if (s[1] != '\0') {- archive_strappend_char(as, s[1]);- s += 2;- } else {- s++;/* Ignore this character.*/- break;- }- } else if (*s == '"') {- ssize_t q = extract_quotation(as, s);- if (q < 0)- return (ARCHIVE_FAILED);/* Invalid sequence. */- s += q;- } else {- archive_strappend_char(as, s[0]);- s++;- }- }- return ((ssize_t)(s - p));-}--/*- * Set up command line arguments.- * Returns ARCHIVE_OK if everything okey.- * Returns ARCHIVE_FAILED if there is a lack of the `"' terminator or an- * empty command line.- * Returns ARCHIVE_FATAL if no memory.- */-int-__archive_cmdline_parse(struct archive_cmdline *data, const char *cmd)-{- struct archive_string as;- const char *p;- ssize_t al;- int r;-- archive_string_init(&as);-- /* Get first argument as a command path. */- al = get_argument(&as, cmd);- if (al < 0) {- r = ARCHIVE_FAILED;/* Invalid sequence. */- goto exit_function;- }- if (archive_strlen(&as) == 0) {- r = ARCHIVE_FAILED;/* An empty command path. */- goto exit_function;- }- r = cmdline_set_path(data, as.s);- if (r != ARCHIVE_OK)- goto exit_function;- p = strrchr(as.s, '/');- if (p == NULL)- p = as.s;- else- p++;- r = cmdline_add_arg(data, p);- if (r != ARCHIVE_OK)- goto exit_function;- cmd += al;-- for (;;) {- al = get_argument(&as, cmd);- if (al < 0) {- r = ARCHIVE_FAILED;/* Invalid sequence. */- goto exit_function;- }- if (al == 0)- break;- cmd += al;- if (archive_strlen(&as) == 0 && *cmd == '\0')- break;- r = cmdline_add_arg(data, as.s);- if (r != ARCHIVE_OK)- goto exit_function;- }- r = ARCHIVE_OK;-exit_function:- archive_string_free(&as);- return (r);-}--/*- * Set the program path.- */-static int-cmdline_set_path(struct archive_cmdline *data, const char *path)-{- char *newptr;-- newptr = realloc(data->path, strlen(path) + 1);- if (newptr == NULL)- return (ARCHIVE_FATAL);- data->path = newptr;- strcpy(data->path, path);- return (ARCHIVE_OK);-}--/*- * Add a argument for the program.- */-static int-cmdline_add_arg(struct archive_cmdline *data, const char *arg)-{- char **newargv;-- if (data->path == NULL)- return (ARCHIVE_FAILED);-- newargv = realloc(data->argv, (data->argc + 2) * sizeof(char *));- if (newargv == NULL)- return (ARCHIVE_FATAL);- data->argv = newargv;- data->argv[data->argc] = strdup(arg);- if (data->argv[data->argc] == NULL)- return (ARCHIVE_FATAL);- /* Set the terminator of argv. */- data->argv[++data->argc] = NULL;- return (ARCHIVE_OK);-}--struct archive_cmdline *-__archive_cmdline_allocate(void)-{- return (struct archive_cmdline *)- calloc(1, sizeof(struct archive_cmdline));-}--/*- * Release the resources.- */-int-__archive_cmdline_free(struct archive_cmdline *data)-{-- if (data) {- free(data->path);- if (data->argv != NULL) {- int i;- for (i = 0; data->argv[i] != NULL; i++)- free(data->argv[i]);- free(data->argv);- }- free(data);- }- return (ARCHIVE_OK);-}-
− c/archive_cmdline_private.h
@@ -1,47 +0,0 @@-/*-- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- */--#ifndef ARCHIVE_CMDLINE_PRIVATE_H-#define ARCHIVE_CMDLINE_PRIVATE_H--#ifndef __LIBARCHIVE_BUILD-#ifndef __LIBARCHIVE_TEST-#error This header is only to be used internally to libarchive.-#endif-#endif--struct archive_cmdline {- char *path;- char **argv;- int argc;-};--struct archive_cmdline *__archive_cmdline_allocate(void);-int __archive_cmdline_parse(struct archive_cmdline *, const char *);-int __archive_cmdline_free(struct archive_cmdline *);--#endif
− c/archive_crc32.h
@@ -1,83 +0,0 @@-/*-- * Copyright (c) 2009 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.- *- * $FreeBSD: head/lib/libarchive/archive_crc32.h 201102 2009-12-28 03:11:36Z kientzle $- */--#ifndef ARCHIVE_CRC32_H-#define ARCHIVE_CRC32_H--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--/*- * When zlib is unavailable, we should still be able to validate- * uncompressed zip archives. That requires us to be able to compute- * the CRC32 check value. This is a drop-in compatible replacement- * for crc32() from zlib. It's slower than the zlib implementation,- * but still pretty fast: This runs about 300MB/s on my 3GHz P4- * compared to about 800MB/s for the zlib implementation.- */-static unsigned long-crc32(unsigned long crc, const void *_p, size_t len)-{- unsigned long crc2, b, i;- const unsigned char *p = _p;- static volatile int crc_tbl_inited = 0;- static unsigned long crc_tbl[256];-- if (!crc_tbl_inited) {- for (b = 0; b < 256; ++b) {- crc2 = b;- for (i = 8; i > 0; --i) {- if (crc2 & 1)- crc2 = (crc2 >> 1) ^ 0xedb88320UL;- else - crc2 = (crc2 >> 1);- }- crc_tbl[b] = crc2;- }- crc_tbl_inited = 1;- }-- crc = crc ^ 0xffffffffUL;- /* A use of this loop is about 20% - 30% faster than- * no use version in any optimization option of gcc. */- for (;len >= 8; len -= 8) {- crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);- crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);- crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);- crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);- crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);- crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);- crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);- crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);- }- while (len--)- crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);- return (crc ^ 0xffffffffUL);-}--#endif
− c/archive_cryptor.c
@@ -1,534 +0,0 @@-/*--* Copyright (c) 2014 Michihiro NAKAJIMA-* All rights reserved.-*-* Redistribution and use in source and binary forms, with or without-* modification, are permitted provided that the following conditions-* are met:-* 1. Redistributions of source code must retain the above copyright-* notice, this list of conditions and the following disclaimer.-* 2. Redistributions in binary form must reproduce the above copyright-* notice, this list of conditions and the following disclaimer in the-* documentation and/or other materials provided with the distribution.-*-* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR-* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.-* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,-* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT-* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-*/--#include "archive_platform.h"--#ifdef HAVE_STRING_H-#include <string.h>-#endif-#include "archive.h"-#include "archive_cryptor_private.h"--/*- * On systems that do not support any recognized crypto libraries,- * this file will normally define no usable symbols.- *- * But some compilers and linkers choke on empty object files, so- * define a public symbol that will always exist. This could- * be removed someday if this file gains another always-present- * symbol definition.- */-int __libarchive_cryptor_build_hack(void) {- return 0;-}--#ifdef ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto--static int-pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,- size_t salt_len, unsigned rounds, uint8_t *derived_key,- size_t derived_key_len)-{- CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)pw,- pw_len, salt, salt_len, kCCPRFHmacAlgSHA1, rounds,- derived_key, derived_key_len);- return 0;-}--#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)-#ifdef _MSC_VER-#pragma comment(lib, "Bcrypt.lib")-#endif--static int-pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,- size_t salt_len, unsigned rounds, uint8_t *derived_key,- size_t derived_key_len)-{- NTSTATUS status;- BCRYPT_ALG_HANDLE hAlg;-- status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM,- MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG);- if (!BCRYPT_SUCCESS(status))- return -1;-- status = BCryptDeriveKeyPBKDF2(hAlg,- (PUCHAR)(uintptr_t)pw, (ULONG)pw_len,- (PUCHAR)(uintptr_t)salt, (ULONG)salt_len, rounds,- (PUCHAR)derived_key, (ULONG)derived_key_len, 0);-- BCryptCloseAlgorithmProvider(hAlg, 0);-- return (BCRYPT_SUCCESS(status)) ? 0: -1;-}--#elif defined(HAVE_LIBMBEDCRYPTO) && defined(HAVE_MBEDTLS_PKCS5_H)--static int-pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,- size_t salt_len, unsigned rounds, uint8_t *derived_key,- size_t derived_key_len)-{- mbedtls_md_context_t ctx;- const mbedtls_md_info_t *info;- int ret;-- mbedtls_md_init(&ctx);- info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);- if (info == NULL) {- mbedtls_md_free(&ctx);- return (-1);- }- ret = mbedtls_md_setup(&ctx, info, 1);- if (ret != 0) {- mbedtls_md_free(&ctx);- return (-1);- }- ret = mbedtls_pkcs5_pbkdf2_hmac(&ctx, (const unsigned char *)pw,- pw_len, salt, salt_len, rounds, derived_key_len, derived_key);-- mbedtls_md_free(&ctx);- return (ret);-}--#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_PBKDF2_H)--static int-pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,- size_t salt_len, unsigned rounds, uint8_t *derived_key,- size_t derived_key_len) {- pbkdf2_hmac_sha1((unsigned)pw_len, (const uint8_t *)pw, rounds,- salt_len, salt, derived_key_len, derived_key);- return 0;-}--#elif defined(HAVE_LIBCRYPTO) && defined(HAVE_PKCS5_PBKDF2_HMAC_SHA1)--static int-pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,- size_t salt_len, unsigned rounds, uint8_t *derived_key,- size_t derived_key_len) {-- PKCS5_PBKDF2_HMAC_SHA1(pw, pw_len, salt, salt_len, rounds,- derived_key_len, derived_key);- return 0;-}--#else--/* Stub */-static int-pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,- size_t salt_len, unsigned rounds, uint8_t *derived_key,- size_t derived_key_len) {- (void)pw; /* UNUSED */- (void)pw_len; /* UNUSED */- (void)salt; /* UNUSED */- (void)salt_len; /* UNUSED */- (void)rounds; /* UNUSED */- (void)derived_key; /* UNUSED */- (void)derived_key_len; /* UNUSED */- return -1; /* UNSUPPORTED */-}--#endif--#ifdef ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto-# if MAC_OS_X_VERSION_MAX_ALLOWED < 1090-# define kCCAlgorithmAES kCCAlgorithmAES128-# endif--static int-aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)-{- CCCryptorStatus r;-- ctx->key_len = key_len;- memcpy(ctx->key, key, key_len);- memset(ctx->nonce, 0, sizeof(ctx->nonce));- ctx->encr_pos = AES_BLOCK_SIZE;- r = CCCryptorCreateWithMode(kCCEncrypt, kCCModeECB, kCCAlgorithmAES,- ccNoPadding, NULL, key, key_len, NULL, 0, 0, 0, &ctx->ctx);- return (r == kCCSuccess)? 0: -1;-}--static int-aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)-{- CCCryptorRef ref = ctx->ctx;- CCCryptorStatus r;-- r = CCCryptorReset(ref, NULL);- if (r != kCCSuccess && r != kCCUnimplemented)- return -1;- r = CCCryptorUpdate(ref, ctx->nonce, AES_BLOCK_SIZE, ctx->encr_buf,- AES_BLOCK_SIZE, NULL);- return (r == kCCSuccess)? 0: -1;-}--static int-aes_ctr_release(archive_crypto_ctx *ctx)-{- memset(ctx->key, 0, ctx->key_len);- memset(ctx->nonce, 0, sizeof(ctx->nonce));- return 0;-}--#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)--static int-aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)-{- BCRYPT_ALG_HANDLE hAlg;- BCRYPT_KEY_HANDLE hKey;- DWORD keyObj_len, aes_key_len;- PBYTE keyObj;- ULONG result;- NTSTATUS status;- BCRYPT_KEY_LENGTHS_STRUCT key_lengths;-- ctx->hAlg = NULL;- ctx->hKey = NULL;- ctx->keyObj = NULL;- switch (key_len) {- case 16: aes_key_len = 128; break;- case 24: aes_key_len = 192; break;- case 32: aes_key_len = 256; break;- default: return -1;- }- status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_AES_ALGORITHM,- MS_PRIMITIVE_PROVIDER, 0);- if (!BCRYPT_SUCCESS(status))- return -1;- status = BCryptGetProperty(hAlg, BCRYPT_KEY_LENGTHS, (PUCHAR)&key_lengths,- sizeof(key_lengths), &result, 0);- if (!BCRYPT_SUCCESS(status)) {- BCryptCloseAlgorithmProvider(hAlg, 0);- return -1;- }- if (key_lengths.dwMinLength > aes_key_len- || key_lengths.dwMaxLength < aes_key_len) {- BCryptCloseAlgorithmProvider(hAlg, 0);- return -1;- }- status = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PUCHAR)&keyObj_len,- sizeof(keyObj_len), &result, 0);- if (!BCRYPT_SUCCESS(status)) {- BCryptCloseAlgorithmProvider(hAlg, 0);- return -1;- }- keyObj = (PBYTE)HeapAlloc(GetProcessHeap(), 0, keyObj_len);- if (keyObj == NULL) {- BCryptCloseAlgorithmProvider(hAlg, 0);- return -1;- }- status = BCryptSetProperty(hAlg, BCRYPT_CHAINING_MODE,- (PUCHAR)BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB), 0);- if (!BCRYPT_SUCCESS(status)) {- BCryptCloseAlgorithmProvider(hAlg, 0);- HeapFree(GetProcessHeap(), 0, keyObj);- return -1;- }- status = BCryptGenerateSymmetricKey(hAlg, &hKey,- keyObj, keyObj_len,- (PUCHAR)(uintptr_t)key, (ULONG)key_len, 0);- if (!BCRYPT_SUCCESS(status)) {- BCryptCloseAlgorithmProvider(hAlg, 0);- HeapFree(GetProcessHeap(), 0, keyObj);- return -1;- }-- ctx->hAlg = hAlg;- ctx->hKey = hKey;- ctx->keyObj = keyObj;- ctx->keyObj_len = keyObj_len;- ctx->encr_pos = AES_BLOCK_SIZE;-- return 0;-}--static int-aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)-{- NTSTATUS status;- ULONG result;-- status = BCryptEncrypt(ctx->hKey, (PUCHAR)ctx->nonce, AES_BLOCK_SIZE,- NULL, NULL, 0, (PUCHAR)ctx->encr_buf, AES_BLOCK_SIZE,- &result, 0);- return BCRYPT_SUCCESS(status) ? 0 : -1;-}--static int-aes_ctr_release(archive_crypto_ctx *ctx)-{-- if (ctx->hAlg != NULL) {- BCryptCloseAlgorithmProvider(ctx->hAlg, 0);- ctx->hAlg = NULL;- BCryptDestroyKey(ctx->hKey);- ctx->hKey = NULL;- HeapFree(GetProcessHeap(), 0, ctx->keyObj);- ctx->keyObj = NULL;- }- memset(ctx, 0, sizeof(*ctx));- return 0;-}--#elif defined(HAVE_LIBMBEDCRYPTO) && defined(HAVE_MBEDTLS_AES_H)--static int-aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)-{- mbedtls_aes_init(&ctx->ctx);- ctx->key_len = key_len;- memcpy(ctx->key, key, key_len);- memset(ctx->nonce, 0, sizeof(ctx->nonce));- ctx->encr_pos = AES_BLOCK_SIZE;- return 0;-}--static int-aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)-{- if (mbedtls_aes_setkey_enc(&ctx->ctx, ctx->key,- ctx->key_len * 8) != 0)- return (-1);- if (mbedtls_aes_crypt_ecb(&ctx->ctx, MBEDTLS_AES_ENCRYPT, ctx->nonce,- ctx->encr_buf) != 0)- return (-1);- return 0;-}--static int-aes_ctr_release(archive_crypto_ctx *ctx)-{- mbedtls_aes_free(&ctx->ctx);- memset(ctx, 0, sizeof(*ctx));- return 0;-}--#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_AES_H)--static int-aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)-{- ctx->key_len = key_len;- memcpy(ctx->key, key, key_len);- memset(ctx->nonce, 0, sizeof(ctx->nonce));- ctx->encr_pos = AES_BLOCK_SIZE;- memset(&ctx->ctx, 0, sizeof(ctx->ctx));- return 0;-}--static int-aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)-{-#if NETTLE_VERSION_MAJOR < 3- aes_set_encrypt_key(&ctx->ctx, ctx->key_len, ctx->key);- aes_encrypt(&ctx->ctx, AES_BLOCK_SIZE, ctx->encr_buf, ctx->nonce);-#else- switch(ctx->key_len) {- case AES128_KEY_SIZE:- aes128_set_encrypt_key(&ctx->ctx.c128, ctx->key);- aes128_encrypt(&ctx->ctx.c128, AES_BLOCK_SIZE, ctx->encr_buf,- ctx->nonce);- break;- case AES192_KEY_SIZE:- aes192_set_encrypt_key(&ctx->ctx.c192, ctx->key);- aes192_encrypt(&ctx->ctx.c192, AES_BLOCK_SIZE, ctx->encr_buf,- ctx->nonce);- break;- case AES256_KEY_SIZE:- aes256_set_encrypt_key(&ctx->ctx.c256, ctx->key);- aes256_encrypt(&ctx->ctx.c256, AES_BLOCK_SIZE, ctx->encr_buf,- ctx->nonce);- break;- default:- return -1;- break;- }-#endif- return 0;-}--static int-aes_ctr_release(archive_crypto_ctx *ctx)-{- memset(ctx, 0, sizeof(*ctx));- return 0;-}--#elif defined(HAVE_LIBCRYPTO)--static int-aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)-{- if ((ctx->ctx = EVP_CIPHER_CTX_new()) == NULL)- return -1;-- switch (key_len) {- case 16: ctx->type = EVP_aes_128_ecb(); break;- case 24: ctx->type = EVP_aes_192_ecb(); break;- case 32: ctx->type = EVP_aes_256_ecb(); break;- default: ctx->type = NULL; return -1;- }-- ctx->key_len = key_len;- memcpy(ctx->key, key, key_len);- memset(ctx->nonce, 0, sizeof(ctx->nonce));- ctx->encr_pos = AES_BLOCK_SIZE;- return 0;-}--static int-aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)-{- int outl = 0;- int r;-- r = EVP_EncryptInit_ex(ctx->ctx, ctx->type, NULL, ctx->key, NULL);- if (r == 0)- return -1;- r = EVP_EncryptUpdate(ctx->ctx, ctx->encr_buf, &outl, ctx->nonce,- AES_BLOCK_SIZE);- if (r == 0 || outl != AES_BLOCK_SIZE)- return -1;- return 0;-}--static int-aes_ctr_release(archive_crypto_ctx *ctx)-{- EVP_CIPHER_CTX_free(ctx->ctx);- memset(ctx->key, 0, ctx->key_len);- memset(ctx->nonce, 0, sizeof(ctx->nonce));- return 0;-}--#else--#define ARCHIVE_CRYPTOR_STUB-/* Stub */-static int-aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)-{- (void)ctx; /* UNUSED */- (void)key; /* UNUSED */- (void)key_len; /* UNUSED */- return -1;-}--static int-aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)-{- (void)ctx; /* UNUSED */- return -1;-}--static int-aes_ctr_release(archive_crypto_ctx *ctx)-{- (void)ctx; /* UNUSED */- return 0;-}--#endif--#ifdef ARCHIVE_CRYPTOR_STUB-static int-aes_ctr_update(archive_crypto_ctx *ctx, const uint8_t * const in,- size_t in_len, uint8_t * const out, size_t *out_len)-{- (void)ctx; /* UNUSED */- (void)in; /* UNUSED */- (void)in_len; /* UNUSED */- (void)out; /* UNUSED */- (void)out_len; /* UNUSED */- aes_ctr_encrypt_counter(ctx); /* UNUSED */ /* Fix unused function warning */- return -1;-}--#else-static void-aes_ctr_increase_counter(archive_crypto_ctx *ctx)-{- uint8_t *const nonce = ctx->nonce;- int j;-- for (j = 0; j < 8; j++) {- if (++nonce[j])- break;- }-}--static int-aes_ctr_update(archive_crypto_ctx *ctx, const uint8_t * const in,- size_t in_len, uint8_t * const out, size_t *out_len)-{- uint8_t *const ebuf = ctx->encr_buf;- unsigned pos = ctx->encr_pos;- unsigned max = (unsigned)((in_len < *out_len)? in_len: *out_len);- unsigned i;-- for (i = 0; i < max; ) {- if (pos == AES_BLOCK_SIZE) {- aes_ctr_increase_counter(ctx);- if (aes_ctr_encrypt_counter(ctx) != 0)- return -1;- while (max -i >= AES_BLOCK_SIZE) {- for (pos = 0; pos < AES_BLOCK_SIZE; pos++)- out[i+pos] = in[i+pos] ^ ebuf[pos];- i += AES_BLOCK_SIZE;- aes_ctr_increase_counter(ctx);- if (aes_ctr_encrypt_counter(ctx) != 0)- return -1;- }- pos = 0;- if (i >= max)- break;- }- out[i] = in[i] ^ ebuf[pos++];- i++;- }- ctx->encr_pos = pos;- *out_len = i;-- return 0;-}-#endif /* ARCHIVE_CRYPTOR_STUB */---const struct archive_cryptor __archive_cryptor =-{- &pbkdf2_sha1,- &aes_ctr_init,- &aes_ctr_update,- &aes_ctr_release,- &aes_ctr_init,- &aes_ctr_update,- &aes_ctr_release,-};
− c/archive_cryptor_private.h
@@ -1,188 +0,0 @@-/*--* Copyright (c) 2014 Michihiro NAKAJIMA-* All rights reserved.-*-* Redistribution and use in source and binary forms, with or without-* modification, are permitted provided that the following conditions-* are met:-* 1. Redistributions of source code must retain the above copyright-* notice, this list of conditions and the following disclaimer.-* 2. Redistributions in binary form must reproduce the above copyright-* notice, this list of conditions and the following disclaimer in the-* documentation and/or other materials provided with the distribution.-*-* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR-* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.-* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,-* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT-* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-*/--#ifndef ARCHIVE_CRYPTOR_PRIVATE_H_INCLUDED-#define ARCHIVE_CRYPTOR_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif-/*- * On systems that do not support any recognized crypto libraries,- * the archive_cryptor.c file will normally define no usable symbols.- *- * But some compilers and linkers choke on empty object files, so- * define a public symbol that will always exist. This could- * be removed someday if this file gains another always-present- * symbol definition.- */-int __libarchive_cryptor_build_hack(void);--#ifdef __APPLE__-# include <AvailabilityMacros.h>-# if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080-# define ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto-# endif-#endif--#ifdef ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto-#include <CommonCrypto/CommonCryptor.h>-#include <CommonCrypto/CommonKeyDerivation.h>-#define AES_BLOCK_SIZE 16-#define AES_MAX_KEY_SIZE kCCKeySizeAES256--typedef struct {- CCCryptorRef ctx;- uint8_t key[AES_MAX_KEY_SIZE];- unsigned key_len;- uint8_t nonce[AES_BLOCK_SIZE];- uint8_t encr_buf[AES_BLOCK_SIZE];- unsigned encr_pos;-} archive_crypto_ctx;--#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)-#include <bcrypt.h>--/* Common in other bcrypt implementations, but missing from VS2008. */-#ifndef BCRYPT_SUCCESS-#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)-#endif--#define AES_MAX_KEY_SIZE 32-#define AES_BLOCK_SIZE 16-typedef struct {- BCRYPT_ALG_HANDLE hAlg;- BCRYPT_KEY_HANDLE hKey;- PBYTE keyObj;- DWORD keyObj_len;- uint8_t nonce[AES_BLOCK_SIZE];- uint8_t encr_buf[AES_BLOCK_SIZE];- unsigned encr_pos;-} archive_crypto_ctx;--#elif defined(HAVE_LIBMBEDCRYPTO) && defined(HAVE_MBEDTLS_AES_H)-#include <mbedtls/aes.h>-#include <mbedtls/md.h>-#include <mbedtls/pkcs5.h>--#define AES_MAX_KEY_SIZE 32-#define AES_BLOCK_SIZE 16--typedef struct {- mbedtls_aes_context ctx;- uint8_t key[AES_MAX_KEY_SIZE];- unsigned key_len;- uint8_t nonce[AES_BLOCK_SIZE];- uint8_t encr_buf[AES_BLOCK_SIZE];- unsigned encr_pos;-} archive_crypto_ctx;--#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_AES_H)-#if defined(HAVE_NETTLE_PBKDF2_H)-#include <nettle/pbkdf2.h>-#endif-#include <nettle/aes.h>-#include <nettle/version.h>--typedef struct {-#if NETTLE_VERSION_MAJOR < 3- struct aes_ctx ctx;-#else- union {- struct aes128_ctx c128;- struct aes192_ctx c192;- struct aes256_ctx c256;- } ctx;-#endif- uint8_t key[AES_MAX_KEY_SIZE];- unsigned key_len;- uint8_t nonce[AES_BLOCK_SIZE];- uint8_t encr_buf[AES_BLOCK_SIZE];- unsigned encr_pos;-} archive_crypto_ctx;--#elif defined(HAVE_LIBCRYPTO)-#include "archive_openssl_evp_private.h"-#define AES_BLOCK_SIZE 16-#define AES_MAX_KEY_SIZE 32--typedef struct {- EVP_CIPHER_CTX *ctx;- const EVP_CIPHER *type;- uint8_t key[AES_MAX_KEY_SIZE];- unsigned key_len;- uint8_t nonce[AES_BLOCK_SIZE];- uint8_t encr_buf[AES_BLOCK_SIZE];- unsigned encr_pos;-} archive_crypto_ctx;--#else--#define AES_BLOCK_SIZE 16-#define AES_MAX_KEY_SIZE 32-typedef int archive_crypto_ctx;--#endif--/* defines */-#define archive_pbkdf2_sha1(pw, pw_len, salt, salt_len, rounds, dk, dk_len)\- __archive_cryptor.pbkdf2sha1(pw, pw_len, salt, salt_len, rounds, dk, dk_len)--#define archive_decrypto_aes_ctr_init(ctx, key, key_len) \- __archive_cryptor.decrypto_aes_ctr_init(ctx, key, key_len)-#define archive_decrypto_aes_ctr_update(ctx, in, in_len, out, out_len) \- __archive_cryptor.decrypto_aes_ctr_update(ctx, in, in_len, out, out_len)-#define archive_decrypto_aes_ctr_release(ctx) \- __archive_cryptor.decrypto_aes_ctr_release(ctx)--#define archive_encrypto_aes_ctr_init(ctx, key, key_len) \- __archive_cryptor.encrypto_aes_ctr_init(ctx, key, key_len)-#define archive_encrypto_aes_ctr_update(ctx, in, in_len, out, out_len) \- __archive_cryptor.encrypto_aes_ctr_update(ctx, in, in_len, out, out_len)-#define archive_encrypto_aes_ctr_release(ctx) \- __archive_cryptor.encrypto_aes_ctr_release(ctx)--/* Minimal interface to cryptographic functionality for internal use in- * libarchive */-struct archive_cryptor-{- /* PKCS5 PBKDF2 HMAC-SHA1 */- int (*pbkdf2sha1)(const char *pw, size_t pw_len, const uint8_t *salt,- size_t salt_len, unsigned rounds, uint8_t *derived_key,- size_t derived_key_len);- /* AES CTR mode(little endian version) */- int (*decrypto_aes_ctr_init)(archive_crypto_ctx *, const uint8_t *, size_t);- int (*decrypto_aes_ctr_update)(archive_crypto_ctx *, const uint8_t *,- size_t, uint8_t *, size_t *);- int (*decrypto_aes_ctr_release)(archive_crypto_ctx *);- int (*encrypto_aes_ctr_init)(archive_crypto_ctx *, const uint8_t *, size_t);- int (*encrypto_aes_ctr_update)(archive_crypto_ctx *, const uint8_t *,- size_t, uint8_t *, size_t *);- int (*encrypto_aes_ctr_release)(archive_crypto_ctx *);-};--extern const struct archive_cryptor __archive_cryptor;--#endif
− c/archive_digest.c
@@ -1,1565 +0,0 @@-/*--* Copyright (c) 2003-2007 Tim Kientzle-* Copyright (c) 2011 Andres Mejia-* Copyright (c) 2011 Michihiro NAKAJIMA-* All rights reserved.-*-* Redistribution and use in source and binary forms, with or without-* modification, are permitted provided that the following conditions-* are met:-* 1. Redistributions of source code must retain the above copyright-* notice, this list of conditions and the following disclaimer.-* 2. Redistributions in binary form must reproduce the above copyright-* notice, this list of conditions and the following disclaimer in the-* documentation and/or other materials provided with the distribution.-*-* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR-* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.-* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,-* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT-* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-*/--#include "archive_platform.h"--#include "archive.h"-#include "archive_digest_private.h"--/* In particular, force the configure probe to break if it tries- * to test a combination of OpenSSL and libmd. */-#if defined(ARCHIVE_CRYPTO_OPENSSL) && defined(ARCHIVE_CRYPTO_LIBMD)-#error Cannot use both OpenSSL and libmd.-#endif--/* Common in other bcrypt implementations, but missing from VS2008. */-#ifndef BCRYPT_SUCCESS-#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)-#endif--/*- * Message digest functions for Windows platform.- */-#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\- defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\- defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\- defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\- defined(ARCHIVE_CRYPTO_SHA512_WIN)--/*- * Initialize a Message digest.- */-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA-static int-win_crypto_init(Digest_CTX *ctx, const WCHAR *algo)-{- NTSTATUS status;- ctx->valid = 0;-- status = BCryptOpenAlgorithmProvider(&ctx->hAlg, algo, NULL, 0);- if (!BCRYPT_SUCCESS(status))- return (ARCHIVE_FAILED);- status = BCryptCreateHash(ctx->hAlg, &ctx->hHash, NULL, 0, NULL, 0, 0);- if (!BCRYPT_SUCCESS(status)) {- BCryptCloseAlgorithmProvider(ctx->hAlg, 0);- return (ARCHIVE_FAILED);- }-- ctx->valid = 1;- return (ARCHIVE_OK);-}-#else-static int-win_crypto_init(Digest_CTX *ctx, DWORD prov, ALG_ID algId)-{-- ctx->valid = 0;- if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,- prov, CRYPT_VERIFYCONTEXT)) {- if (GetLastError() != (DWORD)NTE_BAD_KEYSET)- return (ARCHIVE_FAILED);- if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,- prov, CRYPT_NEWKEYSET))- return (ARCHIVE_FAILED);- }-- if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) {- CryptReleaseContext(ctx->cryptProv, 0);- return (ARCHIVE_FAILED);- }-- ctx->valid = 1;- return (ARCHIVE_OK);-}-#endif--/*- * Update a Message digest.- */-static int-win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)-{-- if (!ctx->valid)- return (ARCHIVE_FAILED);--#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- BCryptHashData(ctx->hHash,- (PUCHAR)(uintptr_t)buf,- len, 0);-#else- CryptHashData(ctx->hash,- (unsigned char *)(uintptr_t)buf,- (DWORD)len, 0);-#endif- return (ARCHIVE_OK);-}--static int-win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)-{-#if !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA)- DWORD siglen = (DWORD)bufsize;-#endif-- if (!ctx->valid)- return (ARCHIVE_FAILED);--#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- BCryptFinishHash(ctx->hHash, buf, (ULONG)bufsize, 0);- BCryptDestroyHash(ctx->hHash);- BCryptCloseAlgorithmProvider(ctx->hAlg, 0);-#else- CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);- CryptDestroyHash(ctx->hash);- CryptReleaseContext(ctx->cryptProv, 0);-#endif- ctx->valid = 0;- return (ARCHIVE_OK);-}--#endif /* defined(ARCHIVE_CRYPTO_*_WIN) */---/* MD5 implementations */-#if defined(ARCHIVE_CRYPTO_MD5_LIBC)--static int-__archive_md5init(archive_md5_ctx *ctx)-{- MD5Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_md5update(archive_md5_ctx *ctx, const void *indata,- size_t insize)-{- MD5Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_md5final(archive_md5_ctx *ctx, void *md)-{- MD5Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)--static int-__archive_md5init(archive_md5_ctx *ctx)-{- MD5Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_md5update(archive_md5_ctx *ctx, const void *indata,- size_t insize)-{- MD5Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_md5final(archive_md5_ctx *ctx, void *md)-{- MD5Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)--static int-__archive_md5init(archive_md5_ctx *ctx)-{- CC_MD5_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_md5update(archive_md5_ctx *ctx, const void *indata,- size_t insize)-{- CC_MD5_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_md5final(archive_md5_ctx *ctx, void *md)-{- CC_MD5_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_MD5_MBEDTLS)--static int-__archive_md5init(archive_md5_ctx *ctx)-{- mbedtls_md5_init(ctx);- if (mbedtls_md5_starts_ret(ctx) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_md5update(archive_md5_ctx *ctx, const void *indata,- size_t insize)-{- if (mbedtls_md5_update_ret(ctx, indata, insize) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_md5final(archive_md5_ctx *ctx, void *md)-{- if (mbedtls_md5_finish_ret(ctx, md) == 0) {- mbedtls_md5_free(ctx);- return (ARCHIVE_OK);- } else {- mbedtls_md5_free(ctx);- return (ARCHIVE_FATAL);- }-}--#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)--static int-__archive_md5init(archive_md5_ctx *ctx)-{- md5_init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_md5update(archive_md5_ctx *ctx, const void *indata,- size_t insize)-{- md5_update(ctx, insize, indata);- return (ARCHIVE_OK);-}--static int-__archive_md5final(archive_md5_ctx *ctx, void *md)-{- md5_digest(ctx, MD5_DIGEST_SIZE, md);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)--static int-__archive_md5init(archive_md5_ctx *ctx)-{- if ((*ctx = EVP_MD_CTX_new()) == NULL)- return (ARCHIVE_FAILED);- if (!EVP_DigestInit(*ctx, EVP_md5()))- return (ARCHIVE_FAILED);- return (ARCHIVE_OK);-}--static int-__archive_md5update(archive_md5_ctx *ctx, const void *indata,- size_t insize)-{- EVP_DigestUpdate(*ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_md5final(archive_md5_ctx *ctx, void *md)-{- /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so- * this is meant to cope with that. Real fix is probably to fix- * archive_write_set_format_xar.c- */- if (*ctx) {- EVP_DigestFinal(*ctx, md, NULL);- EVP_MD_CTX_free(*ctx);- *ctx = NULL;- }- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_MD5_WIN)--static int-__archive_md5init(archive_md5_ctx *ctx)-{-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM));-#else- return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5));-#endif-}--static int-__archive_md5update(archive_md5_ctx *ctx, const void *indata,- size_t insize)-{- return (win_crypto_Update(ctx, indata, insize));-}--static int-__archive_md5final(archive_md5_ctx *ctx, void *md)-{- return (win_crypto_Final(md, 16, ctx));-}--#else--static int-__archive_md5init(archive_md5_ctx *ctx)-{- (void)ctx; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_md5update(archive_md5_ctx *ctx, const void *indata,- size_t insize)-{- (void)ctx; /* UNUSED */- (void)indata; /* UNUSED */- (void)insize; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_md5final(archive_md5_ctx *ctx, void *md)-{- (void)ctx; /* UNUSED */- (void)md; /* UNUSED */- return (ARCHIVE_FAILED);-}--#endif--/* RIPEMD160 implementations */-#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)--static int-__archive_ripemd160init(archive_rmd160_ctx *ctx)-{- RMD160Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,- size_t insize)-{- RMD160Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)-{- RMD160Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)--static int-__archive_ripemd160init(archive_rmd160_ctx *ctx)-{- RIPEMD160_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,- size_t insize)-{- RIPEMD160_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)-{- RIPEMD160_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_RMD160_MBEDTLS)--static int-__archive_ripemd160init(archive_rmd160_ctx *ctx)-{- mbedtls_ripemd160_init(ctx);- if (mbedtls_ripemd160_starts_ret(ctx) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,- size_t insize)-{- if (mbedtls_ripemd160_update_ret(ctx, indata, insize) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)-{- if (mbedtls_ripemd160_finish_ret(ctx, md) == 0) {- mbedtls_ripemd160_free(ctx);- return (ARCHIVE_OK);- } else {- mbedtls_ripemd160_free(ctx);- return (ARCHIVE_FATAL);- }-}--#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)--static int-__archive_ripemd160init(archive_rmd160_ctx *ctx)-{- ripemd160_init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,- size_t insize)-{- ripemd160_update(ctx, insize, indata);- return (ARCHIVE_OK);-}--static int-__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)-{- ripemd160_digest(ctx, RIPEMD160_DIGEST_SIZE, md);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)--static int-__archive_ripemd160init(archive_rmd160_ctx *ctx)-{- if ((*ctx = EVP_MD_CTX_new()) == NULL)- return (ARCHIVE_FAILED);- if (!EVP_DigestInit(*ctx, EVP_ripemd160()))- return (ARCHIVE_FAILED);- return (ARCHIVE_OK);-}--static int-__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,- size_t insize)-{- EVP_DigestUpdate(*ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)-{- if (*ctx) {- EVP_DigestFinal(*ctx, md, NULL);- EVP_MD_CTX_free(*ctx);- *ctx = NULL;- }- return (ARCHIVE_OK);-}--#else--static int-__archive_ripemd160init(archive_rmd160_ctx *ctx)-{- (void)ctx; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,- size_t insize)-{- (void)ctx; /* UNUSED */- (void)indata; /* UNUSED */- (void)insize; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)-{- (void)ctx; /* UNUSED */- (void)md; /* UNUSED */- return (ARCHIVE_FAILED);-}--#endif--/* SHA1 implementations */-#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)--static int-__archive_sha1init(archive_sha1_ctx *ctx)-{- SHA1Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,- size_t insize)-{- SHA1Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha1final(archive_sha1_ctx *ctx, void *md)-{- SHA1Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)--static int-__archive_sha1init(archive_sha1_ctx *ctx)-{- SHA1_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,- size_t insize)-{- SHA1_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha1final(archive_sha1_ctx *ctx, void *md)-{- SHA1_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)--static int-__archive_sha1init(archive_sha1_ctx *ctx)-{- CC_SHA1_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,- size_t insize)-{- CC_SHA1_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha1final(archive_sha1_ctx *ctx, void *md)-{- CC_SHA1_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS)--static int-__archive_sha1init(archive_sha1_ctx *ctx)-{- mbedtls_sha1_init(ctx);- if (mbedtls_sha1_starts_ret(ctx) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,- size_t insize)-{- if (mbedtls_sha1_update_ret(ctx, indata, insize) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_sha1final(archive_sha1_ctx *ctx, void *md)-{- if (mbedtls_sha1_finish_ret(ctx, md) == 0) {- mbedtls_sha1_free(ctx);- return (ARCHIVE_OK);- } else {- mbedtls_sha1_free(ctx);- return (ARCHIVE_FATAL);- }-}--#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)--static int-__archive_sha1init(archive_sha1_ctx *ctx)-{- sha1_init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,- size_t insize)-{- sha1_update(ctx, insize, indata);- return (ARCHIVE_OK);-}--static int-__archive_sha1final(archive_sha1_ctx *ctx, void *md)-{- sha1_digest(ctx, SHA1_DIGEST_SIZE, md);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)--static int-__archive_sha1init(archive_sha1_ctx *ctx)-{- if ((*ctx = EVP_MD_CTX_new()) == NULL)- return (ARCHIVE_FAILED);- if (!EVP_DigestInit(*ctx, EVP_sha1()))- return (ARCHIVE_FAILED);- return (ARCHIVE_OK);-}--static int-__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,- size_t insize)-{- EVP_DigestUpdate(*ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha1final(archive_sha1_ctx *ctx, void *md)-{- /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so- * this is meant to cope with that. Real fix is probably to fix- * archive_write_set_format_xar.c- */- if (*ctx) {- EVP_DigestFinal(*ctx, md, NULL);- EVP_MD_CTX_free(*ctx);- *ctx = NULL;- }- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)--static int-__archive_sha1init(archive_sha1_ctx *ctx)-{-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM));-#else- return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1));-#endif-}--static int-__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,- size_t insize)-{- return (win_crypto_Update(ctx, indata, insize));-}--static int-__archive_sha1final(archive_sha1_ctx *ctx, void *md)-{- return (win_crypto_Final(md, 20, ctx));-}--#else--static int-__archive_sha1init(archive_sha1_ctx *ctx)-{- (void)ctx; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,- size_t insize)-{- (void)ctx; /* UNUSED */- (void)indata; /* UNUSED */- (void)insize; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_sha1final(archive_sha1_ctx *ctx, void *md)-{- (void)ctx; /* UNUSED */- (void)md; /* UNUSED */- return (ARCHIVE_FAILED);-}--#endif--/* SHA256 implementations */-#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)--static int-__archive_sha256init(archive_sha256_ctx *ctx)-{- SHA256_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,- size_t insize)-{- SHA256_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha256final(archive_sha256_ctx *ctx, void *md)-{- SHA256_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)--static int-__archive_sha256init(archive_sha256_ctx *ctx)-{- SHA256Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,- size_t insize)-{- SHA256Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha256final(archive_sha256_ctx *ctx, void *md)-{- SHA256Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)--static int-__archive_sha256init(archive_sha256_ctx *ctx)-{- SHA256Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,- size_t insize)-{- SHA256Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha256final(archive_sha256_ctx *ctx, void *md)-{- SHA256Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)--static int-__archive_sha256init(archive_sha256_ctx *ctx)-{- SHA256_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,- size_t insize)-{- SHA256_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha256final(archive_sha256_ctx *ctx, void *md)-{- SHA256_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)--static int-__archive_sha256init(archive_sha256_ctx *ctx)-{- CC_SHA256_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,- size_t insize)-{- CC_SHA256_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha256final(archive_sha256_ctx *ctx, void *md)-{- CC_SHA256_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS)--static int-__archive_sha256init(archive_sha256_ctx *ctx)-{- mbedtls_sha256_init(ctx);- if (mbedtls_sha256_starts_ret(ctx, 0) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,- size_t insize)-{- if (mbedtls_sha256_update_ret(ctx, indata, insize) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_sha256final(archive_sha256_ctx *ctx, void *md)-{- if (mbedtls_sha256_finish_ret(ctx, md) == 0) {- mbedtls_sha256_free(ctx);- return (ARCHIVE_OK);- } else {- mbedtls_sha256_free(ctx);- return (ARCHIVE_FATAL);- }-}--#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)--static int-__archive_sha256init(archive_sha256_ctx *ctx)-{- sha256_init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,- size_t insize)-{- sha256_update(ctx, insize, indata);- return (ARCHIVE_OK);-}--static int-__archive_sha256final(archive_sha256_ctx *ctx, void *md)-{- sha256_digest(ctx, SHA256_DIGEST_SIZE, md);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)--static int-__archive_sha256init(archive_sha256_ctx *ctx)-{- if ((*ctx = EVP_MD_CTX_new()) == NULL)- return (ARCHIVE_FAILED);- if (!EVP_DigestInit(*ctx, EVP_sha256()))- return (ARCHIVE_FAILED);- return (ARCHIVE_OK);-}--static int-__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,- size_t insize)-{- EVP_DigestUpdate(*ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha256final(archive_sha256_ctx *ctx, void *md)-{- if (*ctx) {- EVP_DigestFinal(*ctx, md, NULL);- EVP_MD_CTX_free(*ctx);- *ctx = NULL;- }- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)--static int-__archive_sha256init(archive_sha256_ctx *ctx)-{-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM));-#else- return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256));-#endif-}--static int-__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,- size_t insize)-{- return (win_crypto_Update(ctx, indata, insize));-}--static int-__archive_sha256final(archive_sha256_ctx *ctx, void *md)-{- return (win_crypto_Final(md, 32, ctx));-}--#else--static int-__archive_sha256init(archive_sha256_ctx *ctx)-{- (void)ctx; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,- size_t insize)-{- (void)ctx; /* UNUSED */- (void)indata; /* UNUSED */- (void)insize; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_sha256final(archive_sha256_ctx *ctx, void *md)-{- (void)ctx; /* UNUSED */- (void)md; /* UNUSED */- return (ARCHIVE_FAILED);-}--#endif--/* SHA384 implementations */-#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)--static int-__archive_sha384init(archive_sha384_ctx *ctx)-{- SHA384_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,- size_t insize)-{- SHA384_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha384final(archive_sha384_ctx *ctx, void *md)-{- SHA384_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)--static int-__archive_sha384init(archive_sha384_ctx *ctx)-{- SHA384Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,- size_t insize)-{- SHA384Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha384final(archive_sha384_ctx *ctx, void *md)-{- SHA384Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)--static int-__archive_sha384init(archive_sha384_ctx *ctx)-{- SHA384Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,- size_t insize)-{- SHA384Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha384final(archive_sha384_ctx *ctx, void *md)-{- SHA384Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)--static int-__archive_sha384init(archive_sha384_ctx *ctx)-{- CC_SHA384_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,- size_t insize)-{- CC_SHA384_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha384final(archive_sha384_ctx *ctx, void *md)-{- CC_SHA384_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS)--static int-__archive_sha384init(archive_sha384_ctx *ctx)-{- mbedtls_sha512_init(ctx);- if (mbedtls_sha512_starts_ret(ctx, 1) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,- size_t insize)-{- if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_sha384final(archive_sha384_ctx *ctx, void *md)-{- if (mbedtls_sha512_finish_ret(ctx, md) == 0) {- mbedtls_sha512_free(ctx);- return (ARCHIVE_OK);- } else {- mbedtls_sha512_free(ctx);- return (ARCHIVE_FATAL);- }-}--#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)--static int-__archive_sha384init(archive_sha384_ctx *ctx)-{- sha384_init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,- size_t insize)-{- sha384_update(ctx, insize, indata);- return (ARCHIVE_OK);-}--static int-__archive_sha384final(archive_sha384_ctx *ctx, void *md)-{- sha384_digest(ctx, SHA384_DIGEST_SIZE, md);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)--static int-__archive_sha384init(archive_sha384_ctx *ctx)-{- if ((*ctx = EVP_MD_CTX_new()) == NULL)- return (ARCHIVE_FAILED);- if (!EVP_DigestInit(*ctx, EVP_sha384()))- return (ARCHIVE_FAILED);- return (ARCHIVE_OK);-}--static int-__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,- size_t insize)-{- EVP_DigestUpdate(*ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha384final(archive_sha384_ctx *ctx, void *md)-{- if (*ctx) {- EVP_DigestFinal(*ctx, md, NULL);- EVP_MD_CTX_free(*ctx);- *ctx = NULL;- }- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)--static int-__archive_sha384init(archive_sha384_ctx *ctx)-{-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM));-#else- return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384));-#endif-}--static int-__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,- size_t insize)-{- return (win_crypto_Update(ctx, indata, insize));-}--static int-__archive_sha384final(archive_sha384_ctx *ctx, void *md)-{- return (win_crypto_Final(md, 48, ctx));-}--#else--static int-__archive_sha384init(archive_sha384_ctx *ctx)-{- (void)ctx; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,- size_t insize)-{- (void)ctx; /* UNUSED */- (void)indata; /* UNUSED */- (void)insize; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_sha384final(archive_sha384_ctx *ctx, void *md)-{- (void)ctx; /* UNUSED */- (void)md; /* UNUSED */- return (ARCHIVE_FAILED);-}--#endif--/* SHA512 implementations */-#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)--static int-__archive_sha512init(archive_sha512_ctx *ctx)-{- SHA512_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,- size_t insize)-{- SHA512_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha512final(archive_sha512_ctx *ctx, void *md)-{- SHA512_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)--static int-__archive_sha512init(archive_sha512_ctx *ctx)-{- SHA512Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,- size_t insize)-{- SHA512Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha512final(archive_sha512_ctx *ctx, void *md)-{- SHA512Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)--static int-__archive_sha512init(archive_sha512_ctx *ctx)-{- SHA512Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,- size_t insize)-{- SHA512Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha512final(archive_sha512_ctx *ctx, void *md)-{- SHA512Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)--static int-__archive_sha512init(archive_sha512_ctx *ctx)-{- SHA512_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,- size_t insize)-{- SHA512_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha512final(archive_sha512_ctx *ctx, void *md)-{- SHA512_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)--static int-__archive_sha512init(archive_sha512_ctx *ctx)-{- CC_SHA512_Init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,- size_t insize)-{- CC_SHA512_Update(ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha512final(archive_sha512_ctx *ctx, void *md)-{- CC_SHA512_Final(md, ctx);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS)--static int-__archive_sha512init(archive_sha512_ctx *ctx)-{- mbedtls_sha512_init(ctx);- if (mbedtls_sha512_starts_ret(ctx, 0) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,- size_t insize)-{- if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0)- return (ARCHIVE_OK);- else- return (ARCHIVE_FATAL);-}--static int-__archive_sha512final(archive_sha512_ctx *ctx, void *md)-{- if (mbedtls_sha512_finish_ret(ctx, md) == 0) {- mbedtls_sha512_free(ctx);- return (ARCHIVE_OK);- } else {- mbedtls_sha512_free(ctx);- return (ARCHIVE_FATAL);- }-}--#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)--static int-__archive_sha512init(archive_sha512_ctx *ctx)-{- sha512_init(ctx);- return (ARCHIVE_OK);-}--static int-__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,- size_t insize)-{- sha512_update(ctx, insize, indata);- return (ARCHIVE_OK);-}--static int-__archive_sha512final(archive_sha512_ctx *ctx, void *md)-{- sha512_digest(ctx, SHA512_DIGEST_SIZE, md);- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)--static int-__archive_sha512init(archive_sha512_ctx *ctx)-{- if ((*ctx = EVP_MD_CTX_new()) == NULL)- return (ARCHIVE_FAILED);- if (!EVP_DigestInit(*ctx, EVP_sha512()))- return (ARCHIVE_FAILED);- return (ARCHIVE_OK);-}--static int-__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,- size_t insize)-{- EVP_DigestUpdate(*ctx, indata, insize);- return (ARCHIVE_OK);-}--static int-__archive_sha512final(archive_sha512_ctx *ctx, void *md)-{- if (*ctx) {- EVP_DigestFinal(*ctx, md, NULL);- EVP_MD_CTX_free(*ctx);- *ctx = NULL;- }- return (ARCHIVE_OK);-}--#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)--static int-__archive_sha512init(archive_sha512_ctx *ctx)-{-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM));-#else- return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512));-#endif-}--static int-__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,- size_t insize)-{- return (win_crypto_Update(ctx, indata, insize));-}--static int-__archive_sha512final(archive_sha512_ctx *ctx, void *md)-{- return (win_crypto_Final(md, 64, ctx));-}--#else--static int-__archive_sha512init(archive_sha512_ctx *ctx)-{- (void)ctx; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,- size_t insize)-{- (void)ctx; /* UNUSED */- (void)indata; /* UNUSED */- (void)insize; /* UNUSED */- return (ARCHIVE_FAILED);-}--static int-__archive_sha512final(archive_sha512_ctx *ctx, void *md)-{- (void)ctx; /* UNUSED */- (void)md; /* UNUSED */- return (ARCHIVE_FAILED);-}--#endif--/* NOTE: Message Digest functions are set based on availability and by the- * following order of preference.- * 1. libc- * 2. libc2- * 3. libc3- * 4. libSystem- * 5. Nettle- * 6. OpenSSL- * 7. libmd- * 8. Windows API- */-const struct archive_digest __archive_digest =-{-/* MD5 */- &__archive_md5init,- &__archive_md5update,- &__archive_md5final,--/* RIPEMD160 */- &__archive_ripemd160init,- &__archive_ripemd160update,- &__archive_ripemd160final,--/* SHA1 */- &__archive_sha1init,- &__archive_sha1update,- &__archive_sha1final,--/* SHA256 */- &__archive_sha256init,- &__archive_sha256update,- &__archive_sha256final,--/* SHA384 */- &__archive_sha384init,- &__archive_sha384update,- &__archive_sha384final,--/* SHA512 */- &__archive_sha512init,- &__archive_sha512update,- &__archive_sha512final-};
− c/archive_digest_private.h
@@ -1,426 +0,0 @@-/*--* Copyright (c) 2003-2007 Tim Kientzle-* Copyright (c) 2011 Andres Mejia-* 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.-*/--#ifndef ARCHIVE_DIGEST_PRIVATE_H_INCLUDED-#define ARCHIVE_DIGEST_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif-#ifndef __LIBARCHIVE_CONFIG_H_INCLUDED-#error "Should have include config.h first!"-#endif--/*- * Crypto support in various Operating Systems:- *- * NetBSD:- * - MD5 and SHA1 in libc: without _ after algorithm name- * - SHA2 in libc: with _ after algorithm name- *- * OpenBSD:- * - MD5, SHA1 and SHA2 in libc: without _ after algorithm name- * - OpenBSD 4.4 and earlier have SHA2 in libc with _ after algorithm name- *- * DragonFly and FreeBSD:- * - MD5 libmd: without _ after algorithm name- * - SHA1, SHA256 and SHA512 in libmd: with _ after algorithm name- *- * Mac OS X (10.4 and later):- * - MD5, SHA1 and SHA2 in libSystem: with CC_ prefix and _ after algorithm name- *- * OpenSSL:- * - MD5, SHA1 and SHA2 in libcrypto: with _ after algorithm name- *- * Windows:- * - MD5, SHA1 and SHA2 in archive_crypto.c using Windows crypto API- */--/* libc crypto headers */-#if defined(ARCHIVE_CRYPTO_MD5_LIBC)-#include <md5.h>-#endif-#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)-#include <rmd160.h>-#endif-#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)-#include <sha1.h>-#endif-#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\- defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\- defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\- defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\- defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\- defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\- defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\- defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\- defined(ARCHIVE_CRYPTO_SHA512_LIBC3)-#include <sha2.h>-#endif--/* libmd crypto headers */-#if defined(ARCHIVE_CRYPTO_MD5_LIBMD) ||\- defined(ARCHIVE_CRYPTO_RMD160_LIBMD) ||\- defined(ARCHIVE_CRYPTO_SHA1_LIBMD) ||\- defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\- defined(ARCHIVE_CRYPTO_SHA512_LIBMD)-#define ARCHIVE_CRYPTO_LIBMD 1-#endif--#if defined(ARCHIVE_CRYPTO_MD5_LIBMD)-#include <md5.h>-#endif-#if defined(ARCHIVE_CRYPTO_RMD160_LIBMD)-#include <ripemd.h>-#endif-#if defined(ARCHIVE_CRYPTO_SHA1_LIBMD)-#include <sha.h>-#endif-#if defined(ARCHIVE_CRYPTO_SHA256_LIBMD)-#include <sha256.h>-#endif-#if defined(ARCHIVE_CRYPTO_SHA512_LIBMD)-#include <sha512.h>-#endif--/* libSystem crypto headers */-#if defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\- defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\- defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\- defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\- defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)-#include <CommonCrypto/CommonDigest.h>-#endif--/* mbed TLS crypto headers */-#if defined(ARCHIVE_CRYPTO_MD5_MBEDTLS)-#include <mbedtls/md5.h>-#endif-#if defined(ARCHIVE_CRYPTO_RMD160_MBEDTLS)-#include <mbedtls/ripemd160.h>-#endif-#if defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS)-#include <mbedtls/sha1.h>-#endif-#if defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS)-#include <mbedtls/sha256.h>-#endif-#if defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS) ||\- defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS)-#include <mbedtls/sha512.h>-#endif--/* Nettle crypto headers */-#if defined(ARCHIVE_CRYPTO_MD5_NETTLE)-#include <nettle/md5.h>-#endif-#if defined(ARCHIVE_CRYPTO_RMD160_NETTLE)-#include <nettle/ripemd160.h>-#endif-#if defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\- defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\- defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\- defined(ARCHIVE_CRYPTO_SHA512_NETTLE)-#include <nettle/sha.h>-#endif--/* OpenSSL crypto headers */-#if defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\- defined(ARCHIVE_CRYPTO_RMD160_OPENSSL) ||\- defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\- defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\- defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\- defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)-#define ARCHIVE_CRYPTO_OPENSSL 1-#include "archive_openssl_evp_private.h"-#endif--/* Windows crypto headers */-#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\- defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\- defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\- defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\- defined(ARCHIVE_CRYPTO_SHA512_WIN)-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA-/* don't use bcrypt when XP needs to be supported */-#include <bcrypt.h>-typedef struct {- int valid;- BCRYPT_ALG_HANDLE hAlg;- BCRYPT_HASH_HANDLE hHash;-} Digest_CTX;-#else-#include <windows.h>-#include <wincrypt.h>-typedef struct {- int valid;- HCRYPTPROV cryptProv;- HCRYPTHASH hash;-} Digest_CTX;-#endif-#endif--/* typedefs */-#if defined(ARCHIVE_CRYPTO_MD5_LIBC)-typedef MD5_CTX archive_md5_ctx;-#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)-typedef MD5_CTX archive_md5_ctx;-#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)-typedef CC_MD5_CTX archive_md5_ctx;-#elif defined(ARCHIVE_CRYPTO_MD5_MBEDTLS)-typedef mbedtls_md5_context archive_md5_ctx;-#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)-typedef struct md5_ctx archive_md5_ctx;-#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)-typedef EVP_MD_CTX *archive_md5_ctx;-#elif defined(ARCHIVE_CRYPTO_MD5_WIN)-typedef Digest_CTX archive_md5_ctx;-#else-typedef unsigned char archive_md5_ctx;-#endif--#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)-typedef RMD160_CTX archive_rmd160_ctx;-#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)-typedef RIPEMD160_CTX archive_rmd160_ctx;-#elif defined(ARCHIVE_CRYPTO_RMD160_MBEDTLS)-typedef mbedtls_ripemd160_context archive_rmd160_ctx;-#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)-typedef struct ripemd160_ctx archive_rmd160_ctx;-#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)-typedef EVP_MD_CTX *archive_rmd160_ctx;-#else-typedef unsigned char archive_rmd160_ctx;-#endif--#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)-typedef SHA1_CTX archive_sha1_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)-typedef SHA1_CTX archive_sha1_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)-typedef CC_SHA1_CTX archive_sha1_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS)-typedef mbedtls_sha1_context archive_sha1_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)-typedef struct sha1_ctx archive_sha1_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)-typedef EVP_MD_CTX *archive_sha1_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)-typedef Digest_CTX archive_sha1_ctx;-#else-typedef unsigned char archive_sha1_ctx;-#endif--#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)-typedef SHA256_CTX archive_sha256_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)-typedef SHA256_CTX archive_sha256_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)-typedef SHA2_CTX archive_sha256_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)-typedef SHA256_CTX archive_sha256_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)-typedef CC_SHA256_CTX archive_sha256_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS)-typedef mbedtls_sha256_context archive_sha256_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)-typedef struct sha256_ctx archive_sha256_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)-typedef EVP_MD_CTX *archive_sha256_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)-typedef Digest_CTX archive_sha256_ctx;-#else-typedef unsigned char archive_sha256_ctx;-#endif--#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)-typedef SHA384_CTX archive_sha384_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)-typedef SHA384_CTX archive_sha384_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)-typedef SHA2_CTX archive_sha384_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)-typedef CC_SHA512_CTX archive_sha384_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS)-typedef mbedtls_sha512_context archive_sha384_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)-typedef struct sha384_ctx archive_sha384_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)-typedef EVP_MD_CTX *archive_sha384_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)-typedef Digest_CTX archive_sha384_ctx;-#else-typedef unsigned char archive_sha384_ctx;-#endif--#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)-typedef SHA512_CTX archive_sha512_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)-typedef SHA512_CTX archive_sha512_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)-typedef SHA2_CTX archive_sha512_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)-typedef SHA512_CTX archive_sha512_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)-typedef CC_SHA512_CTX archive_sha512_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS)-typedef mbedtls_sha512_context archive_sha512_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)-typedef struct sha512_ctx archive_sha512_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)-typedef EVP_MD_CTX *archive_sha512_ctx;-#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)-typedef Digest_CTX archive_sha512_ctx;-#else-typedef unsigned char archive_sha512_ctx;-#endif--/* defines */-#if defined(ARCHIVE_CRYPTO_MD5_LIBC) ||\- defined(ARCHIVE_CRYPTO_MD5_LIBMD) || \- defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\- defined(ARCHIVE_CRYPTO_MD5_MBEDTLS) ||\- defined(ARCHIVE_CRYPTO_MD5_NETTLE) ||\- defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\- defined(ARCHIVE_CRYPTO_MD5_WIN)-#define ARCHIVE_HAS_MD5-#endif-#define archive_md5_init(ctx)\- __archive_digest.md5init(ctx)-#define archive_md5_final(ctx, md)\- __archive_digest.md5final(ctx, md)-#define archive_md5_update(ctx, buf, n)\- __archive_digest.md5update(ctx, buf, n)--#if defined(ARCHIVE_CRYPTO_RMD160_LIBC) ||\- defined(ARCHIVE_CRYPTO_RMD160_MBEDTLS) ||\- defined(ARCHIVE_CRYPTO_RMD160_NETTLE) ||\- defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)-#define ARCHIVE_HAS_RMD160-#endif-#define archive_rmd160_init(ctx)\- __archive_digest.rmd160init(ctx)-#define archive_rmd160_final(ctx, md)\- __archive_digest.rmd160final(ctx, md)-#define archive_rmd160_update(ctx, buf, n)\- __archive_digest.rmd160update(ctx, buf, n)--#if defined(ARCHIVE_CRYPTO_SHA1_LIBC) ||\- defined(ARCHIVE_CRYPTO_SHA1_LIBMD) || \- defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\- defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS) ||\- defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\- defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\- defined(ARCHIVE_CRYPTO_SHA1_WIN)-#define ARCHIVE_HAS_SHA1-#endif-#define archive_sha1_init(ctx)\- __archive_digest.sha1init(ctx)-#define archive_sha1_final(ctx, md)\- __archive_digest.sha1final(ctx, md)-#define archive_sha1_update(ctx, buf, n)\- __archive_digest.sha1update(ctx, buf, n)--#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\- defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\- defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\- defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\- defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\- defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS) ||\- defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\- defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\- defined(ARCHIVE_CRYPTO_SHA256_WIN)-#define ARCHIVE_HAS_SHA256-#endif-#define archive_sha256_init(ctx)\- __archive_digest.sha256init(ctx)-#define archive_sha256_final(ctx, md)\- __archive_digest.sha256final(ctx, md)-#define archive_sha256_update(ctx, buf, n)\- __archive_digest.sha256update(ctx, buf, n)--#if defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\- defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\- defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\- defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\- defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS) ||\- defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\- defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\- defined(ARCHIVE_CRYPTO_SHA384_WIN)-#define ARCHIVE_HAS_SHA384-#endif-#define archive_sha384_init(ctx)\- __archive_digest.sha384init(ctx)-#define archive_sha384_final(ctx, md)\- __archive_digest.sha384final(ctx, md)-#define archive_sha384_update(ctx, buf, n)\- __archive_digest.sha384update(ctx, buf, n)--#if defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\- defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\- defined(ARCHIVE_CRYPTO_SHA512_LIBC3) ||\- defined(ARCHIVE_CRYPTO_SHA512_LIBMD) ||\- defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM) ||\- defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS) ||\- defined(ARCHIVE_CRYPTO_SHA512_NETTLE) ||\- defined(ARCHIVE_CRYPTO_SHA512_OPENSSL) ||\- defined(ARCHIVE_CRYPTO_SHA512_WIN)-#define ARCHIVE_HAS_SHA512-#endif-#define archive_sha512_init(ctx)\- __archive_digest.sha512init(ctx)-#define archive_sha512_final(ctx, md)\- __archive_digest.sha512final(ctx, md)-#define archive_sha512_update(ctx, buf, n)\- __archive_digest.sha512update(ctx, buf, n)--/* Minimal interface to digest functionality for internal use in libarchive */-struct archive_digest-{- /* Message Digest */- int (*md5init)(archive_md5_ctx *ctx);- int (*md5update)(archive_md5_ctx *, const void *, size_t);- int (*md5final)(archive_md5_ctx *, void *);- int (*rmd160init)(archive_rmd160_ctx *);- int (*rmd160update)(archive_rmd160_ctx *, const void *, size_t);- int (*rmd160final)(archive_rmd160_ctx *, void *);- int (*sha1init)(archive_sha1_ctx *);- int (*sha1update)(archive_sha1_ctx *, const void *, size_t);- int (*sha1final)(archive_sha1_ctx *, void *);- int (*sha256init)(archive_sha256_ctx *);- int (*sha256update)(archive_sha256_ctx *, const void *, size_t);- int (*sha256final)(archive_sha256_ctx *, void *);- int (*sha384init)(archive_sha384_ctx *);- int (*sha384update)(archive_sha384_ctx *, const void *, size_t);- int (*sha384final)(archive_sha384_ctx *, void *);- int (*sha512init)(archive_sha512_ctx *);- int (*sha512update)(archive_sha512_ctx *, const void *, size_t);- int (*sha512final)(archive_sha512_ctx *, void *);-};--extern const struct archive_digest __archive_digest;--#endif
− c/archive_disk_acl_darwin.c
@@ -1,559 +0,0 @@-/*-- * Copyright (c) 2017 Martin Matuska- * 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"--#if ARCHIVE_ACL_DARWIN--#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#if HAVE_ERRNO_H-#include <errno.h>-#endif-#if HAVE_MEMBERSHIP_H-#include <membership.h>-#endif-#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_SYS_ACL_H-#define _ACL_PRIVATE /* For debugging */-#include <sys/acl.h>-#endif--#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_disk_private.h"-#include "archive_write_disk_private.h"--typedef struct {- const int a_perm; /* Libarchive permission or flag */- const int p_perm; /* Platform permission or flag */-} acl_perm_map_t;--static const acl_perm_map_t acl_nfs4_perm_map[] = {- {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},- {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},- {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},- {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},- {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},- {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},-#if HAVE_DECL_ACL_SYNCHRONIZE- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}-#endif-};--static const int acl_nfs4_perm_map_size =- (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));--static const acl_perm_map_t acl_nfs4_flag_map[] = {- {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},- {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},- {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},- {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}-};--static const int acl_nfs4_flag_map_size =- (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));--static int translate_guid(struct archive *a, acl_entry_t acl_entry,- int *ae_id, int *ae_tag, const char **ae_name)-{- void *q;- uid_t ugid;- int r, idtype;-- q = acl_get_qualifier(acl_entry);- if (q == NULL)- return (1);- r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);- if (r != 0) {- acl_free(q);- return (1);- }- if (idtype == ID_TYPE_UID) {- *ae_tag = ARCHIVE_ENTRY_ACL_USER;- *ae_id = ugid;- *ae_name = archive_read_disk_uname(a, *ae_id);- } else if (idtype == ID_TYPE_GID) {- *ae_tag = ARCHIVE_ENTRY_ACL_GROUP;- *ae_id = ugid;- *ae_name = archive_read_disk_gname(a, *ae_id);- } else- r = 1;-- acl_free(q);- return (r);-}--static void-add_trivial_nfs4_acl(struct archive_entry *entry)-{- mode_t mode;- int i;- const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA;- const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA |- ARCHIVE_ENTRY_ACL_APPEND_DATA;- const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE;- const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |- ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |- ARCHIVE_ENTRY_ACL_READ_ACL |- ARCHIVE_ENTRY_ACL_SYNCHRONIZE;- const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |- ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |- ARCHIVE_ENTRY_ACL_WRITE_ACL |- ARCHIVE_ENTRY_ACL_WRITE_OWNER;-- struct {- const int type;- const int tag;- int permset;- } tacl_entry[] = {- {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},- {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},- {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0},- {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset},- {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset},- {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset}- };-- mode = archive_entry_mode(entry);-- /* Permissions for everyone@ */- if (mode & 0004)- tacl_entry[5].permset |= rperm;- if (mode & 0002)- tacl_entry[5].permset |= wperm;- if (mode & 0001)- tacl_entry[5].permset |= eperm;-- /* Permissions for group@ */- if (mode & 0040)- tacl_entry[4].permset |= rperm;- else if (mode & 0004)- tacl_entry[2].permset |= rperm;- if (mode & 0020)- tacl_entry[4].permset |= wperm;- else if (mode & 0002)- tacl_entry[2].permset |= wperm;- if (mode & 0010)- tacl_entry[4].permset |= eperm;- else if (mode & 0001)- tacl_entry[2].permset |= eperm;-- /* Permissions for owner@ */- if (mode & 0400) {- tacl_entry[3].permset |= rperm;- if (!(mode & 0040) && (mode & 0004))- tacl_entry[0].permset |= rperm;- } else if ((mode & 0040) || (mode & 0004))- tacl_entry[1].permset |= rperm;- if (mode & 0200) {- tacl_entry[3].permset |= wperm;- if (!(mode & 0020) && (mode & 0002))- tacl_entry[0].permset |= wperm;- } else if ((mode & 0020) || (mode & 0002))- tacl_entry[1].permset |= wperm;- if (mode & 0100) {- tacl_entry[3].permset |= eperm;- if (!(mode & 0010) && (mode & 0001))- tacl_entry[0].permset |= eperm;- } else if ((mode & 0010) || (mode & 0001))- tacl_entry[1].permset |= eperm;-- for (i = 0; i < 6; i++) {- if (tacl_entry[i].permset != 0) {- archive_entry_acl_add_entry(entry,- tacl_entry[i].type, tacl_entry[i].permset,- tacl_entry[i].tag, -1, NULL);- }- }-- return;-}--static int-translate_acl(struct archive_read_disk *a,- struct archive_entry *entry, acl_t acl)-{- acl_tag_t acl_tag;- acl_flagset_t acl_flagset;- acl_entry_t acl_entry;- acl_permset_t acl_permset;- int i, entry_acl_type;- int r, s, ae_id, ae_tag, ae_perm;- const char *ae_name;-- s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);- if (s == -1) {- archive_set_error(&a->archive, errno,- "Failed to get first ACL entry");- return (ARCHIVE_WARN);- }-- while (s == 0) {- ae_id = -1;- ae_name = NULL;- ae_perm = 0;-- if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {- archive_set_error(&a->archive, errno,- "Failed to get ACL tag type");- return (ARCHIVE_WARN);- }- switch (acl_tag) {- case ACL_EXTENDED_ALLOW:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;- r = translate_guid(&a->archive, acl_entry,- &ae_id, &ae_tag, &ae_name);- break;- case ACL_EXTENDED_DENY:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;- r = translate_guid(&a->archive, acl_entry,- &ae_id, &ae_tag, &ae_name);- break;- default:- /* Skip types that libarchive can't support. */- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);- continue;- }-- /* Skip if translate_guid() above failed */- if (r != 0) {- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);- continue;- }-- /*- * Libarchive stores "flag" (NFSv4 inheritance bits)- * in the ae_perm bitmap.- *- * acl_get_flagset_np() fails with non-NFSv4 ACLs- */- if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {- archive_set_error(&a->archive, errno,- "Failed to get flagset from a NFSv4 ACL entry");- return (ARCHIVE_WARN);- }- for (i = 0; i < acl_nfs4_flag_map_size; ++i) {- r = acl_get_flag_np(acl_flagset,- acl_nfs4_flag_map[i].p_perm);- if (r == -1) {- archive_set_error(&a->archive, errno,- "Failed to check flag in a NFSv4 "- "ACL flagset");- return (ARCHIVE_WARN);- } else if (r)- ae_perm |= acl_nfs4_flag_map[i].a_perm;- }-- if (acl_get_permset(acl_entry, &acl_permset) != 0) {- archive_set_error(&a->archive, errno,- "Failed to get ACL permission set");- return (ARCHIVE_WARN);- }-- for (i = 0; i < acl_nfs4_perm_map_size; ++i) {- /*- * acl_get_perm() is spelled differently on different- * platforms; see above.- */- r = acl_get_perm_np(acl_permset,- acl_nfs4_perm_map[i].p_perm);- if (r == -1) {- archive_set_error(&a->archive, errno,- "Failed to check permission in an ACL "- "permission set");- return (ARCHIVE_WARN);- } else if (r)- ae_perm |= acl_nfs4_perm_map[i].a_perm;- }--#if !HAVE_DECL_ACL_SYNCHRONIZE- /* On Mac OS X without ACL_SYNCHRONIZE assume it is set */- ae_perm |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;-#endif-- archive_entry_acl_add_entry(entry, entry_acl_type,- ae_perm, ae_tag,- ae_id, ae_name);-- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);- }- return (ARCHIVE_OK);-}--static int-set_acl(struct archive *a, int fd, const char *name,- struct archive_acl *abstract_acl,- int ae_requested_type, const char *tname)-{- acl_t acl;- acl_entry_t acl_entry;- acl_permset_t acl_permset;- acl_flagset_t acl_flagset;- int ret;- int ae_type, ae_permset, ae_tag, ae_id;- uuid_t ae_uuid;- uid_t ae_uid;- gid_t ae_gid;- const char *ae_name;- int entries;- int i;-- ret = ARCHIVE_OK;- entries = archive_acl_reset(abstract_acl, ae_requested_type);- if (entries == 0)- return (ARCHIVE_OK);-- if (ae_requested_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- errno = ENOENT;- archive_set_error(a, errno, "Unsupported ACL type");- return (ARCHIVE_FAILED);- }-- acl = acl_init(entries);- if (acl == (acl_t)NULL) {- archive_set_error(a, errno,- "Failed to initialize ACL working storage");- return (ARCHIVE_FAILED);- }-- while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,- &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {- /*- * Mac OS doesn't support NFSv4 ACLs for- * owner@, group@ and everyone@.- * We skip any of these ACLs found.- */- if (ae_tag == ARCHIVE_ENTRY_ACL_USER_OBJ ||- ae_tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ ||- ae_tag == ARCHIVE_ENTRY_ACL_EVERYONE)- continue;-- if (acl_create_entry(&acl, &acl_entry) != 0) {- archive_set_error(a, errno,- "Failed to create a new ACL entry");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- switch (ae_type) {- case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:- acl_set_tag_type(acl_entry, ACL_EXTENDED_ALLOW);- break;- case ARCHIVE_ENTRY_ACL_TYPE_DENY:- acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY);- break;- default:- /* We don't support any other types on MacOS */- continue;- }-- switch (ae_tag) {- case ARCHIVE_ENTRY_ACL_USER:- ae_uid = archive_write_disk_uid(a, ae_name, ae_id);- if (mbr_uid_to_uuid(ae_uid, ae_uuid) != 0)- continue;- if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)- continue;- break;- case ARCHIVE_ENTRY_ACL_GROUP:- ae_gid = archive_write_disk_gid(a, ae_name, ae_id);- if (mbr_gid_to_uuid(ae_gid, ae_uuid) != 0)- continue;- if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)- continue;- break;- default:- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unsupported ACL tag");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- if (acl_get_permset(acl_entry, &acl_permset) != 0) {- archive_set_error(a, errno,- "Failed to get ACL permission set");- ret = ARCHIVE_FAILED;- goto exit_free;- }- if (acl_clear_perms(acl_permset) != 0) {- archive_set_error(a, errno,- "Failed to clear ACL permissions");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- for (i = 0; i < acl_nfs4_perm_map_size; ++i) {- if (ae_permset & acl_nfs4_perm_map[i].a_perm) {- if (acl_add_perm(acl_permset,- acl_nfs4_perm_map[i].p_perm) != 0) {- archive_set_error(a, errno,- "Failed to add ACL permission");- ret = ARCHIVE_FAILED;- goto exit_free;- }- }- }-- /*- * acl_get_flagset_np() fails with non-NFSv4 ACLs- */- if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {- archive_set_error(a, errno,- "Failed to get flagset from an NFSv4 ACL entry");- ret = ARCHIVE_FAILED;- goto exit_free;- }- if (acl_clear_flags_np(acl_flagset) != 0) {- archive_set_error(a, errno,- "Failed to clear flags from an NFSv4 ACL flagset");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- for (i = 0; i < acl_nfs4_flag_map_size; ++i) {- if (ae_permset & acl_nfs4_flag_map[i].a_perm) {- if (acl_add_flag_np(acl_flagset,- acl_nfs4_flag_map[i].p_perm) != 0) {- archive_set_error(a, errno,- "Failed to add flag to "- "NFSv4 ACL flagset");- ret = ARCHIVE_FAILED;- goto exit_free;- }- }- }- }-- if (fd >= 0) {- if (acl_set_fd_np(fd, acl, ACL_TYPE_EXTENDED) == 0)- ret = ARCHIVE_OK;- else {- if (errno == EOPNOTSUPP) {- /* Filesystem doesn't support ACLs */- ret = ARCHIVE_OK;- } else {- archive_set_error(a, errno,- "Failed to set acl on fd: %s", tname);- ret = ARCHIVE_WARN;- }- }- } else if (acl_set_link_np(name, ACL_TYPE_EXTENDED, acl) != 0) {- if (errno == EOPNOTSUPP) {- /* Filesystem doesn't support ACLs */- ret = ARCHIVE_OK;- } else {- archive_set_error(a, errno, "Failed to set acl: %s",- tname);- ret = ARCHIVE_WARN;- }- }-exit_free:- acl_free(acl);- return (ret);-}--int-archive_read_disk_entry_setup_acls(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- const char *accpath;- acl_t acl;- int r;-- accpath = NULL;-- if (*fd < 0) {- accpath = archive_read_disk_entry_setup_path(a, entry, fd);- if (accpath == NULL)- return (ARCHIVE_WARN);- }-- archive_entry_acl_clear(entry);-- acl = NULL;-- if (*fd >= 0)- acl = acl_get_fd_np(*fd, ACL_TYPE_EXTENDED);- else if (!a->follow_symlinks)- acl = acl_get_link_np(accpath, ACL_TYPE_EXTENDED);- else- acl = acl_get_file(accpath, ACL_TYPE_EXTENDED);-- if (acl != NULL) {- r = translate_acl(a, entry, acl);- acl_free(acl);- acl = NULL;-- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, errno,- "Couldn't translate NFSv4 ACLs");- }-- /*- * Because Mac OS doesn't support owner@, group@ and everyone@- * ACLs we need to add NFSv4 ACLs mirroring the file mode to- * the archive entry. Otherwise extraction on non-Mac platforms- * would lead to an invalid file mode.- */- if ((archive_entry_acl_types(entry) &- ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)- add_trivial_nfs4_acl(entry);-- return (r);- }- return (ARCHIVE_OK);-}--int-archive_write_disk_set_acls(struct archive *a, int fd, const char *name,- struct archive_acl *abstract_acl, __LA_MODE_T mode)-{- int ret = ARCHIVE_OK;-- (void)mode; /* UNUSED */-- if ((archive_acl_types(abstract_acl) &- ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {- ret = set_acl(a, fd, name, abstract_acl,- ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");- }- return (ret);-}-#endif /* ARCHIVE_ACL_DARWIN */
− c/archive_disk_acl_freebsd.c
@@ -1,712 +0,0 @@-/*-- * Copyright (c) 2003-2009 Tim Kientzle- * Copyright (c) 2010-2012 Michihiro NAKAJIMA- * Copyright (c) 2017 Martin Matuska- * 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"--#if ARCHIVE_ACL_FREEBSD--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_SYS_ACL_H-#define _ACL_PRIVATE /* For debugging */-#include <sys/acl.h>-#endif--#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_disk_private.h"-#include "archive_write_disk_private.h"--typedef struct {- const int a_perm; /* Libarchive permission or flag */- const int p_perm; /* Platform permission or flag */-} acl_perm_map_t;--static const acl_perm_map_t acl_posix_perm_map[] = {- {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},- {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},- {ARCHIVE_ENTRY_ACL_READ, ACL_READ},-};--static const int acl_posix_perm_map_size =- (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0]));--#if ARCHIVE_ACL_FREEBSD_NFS4-static const acl_perm_map_t acl_nfs4_perm_map[] = {- {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},- {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},- {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},- {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},- {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},- {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}-};--static const int acl_nfs4_perm_map_size =- (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));--static const acl_perm_map_t acl_nfs4_flag_map[] = {- {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},- {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},- {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},- {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},- {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},-#ifdef ACL_ENTRY_INHERITED- {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}-#endif-};--static const int acl_nfs4_flag_map_size =- (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));-#endif /* ARCHIVE_ACL_FREEBSD_NFS4 */--static int-translate_acl(struct archive_read_disk *a,- struct archive_entry *entry, acl_t acl, int default_entry_acl_type)-{-#if ARCHIVE_ACL_FREEBSD_NFS4- int brand;- acl_flagset_t acl_flagset;- acl_entry_type_t acl_type;-#endif- acl_tag_t acl_tag;- acl_entry_t acl_entry;- acl_permset_t acl_permset;- int i, entry_acl_type, perm_map_size;- const acl_perm_map_t *perm_map;- int r, s, ae_id, ae_tag, ae_perm;- void *q;- const char *ae_name;--#if ARCHIVE_ACL_FREEBSD_NFS4- // FreeBSD "brands" ACLs as POSIX.1e or NFSv4- // Make sure the "brand" on this ACL is consistent- // with the default_entry_acl_type bits provided.- if (acl_get_brand_np(acl, &brand) != 0) {- archive_set_error(&a->archive, errno,- "Failed to read ACL brand");- return (ARCHIVE_WARN);- }- switch (brand) {- case ACL_BRAND_POSIX:- switch (default_entry_acl_type) {- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid ACL entry type for POSIX.1e ACL");- return (ARCHIVE_WARN);- }- break;- case ACL_BRAND_NFS4:- if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid ACL entry type for NFSv4 ACL");- return (ARCHIVE_WARN);- }- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Unknown ACL brand");- return (ARCHIVE_WARN);- }-#endif-- s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);- if (s == -1) {- archive_set_error(&a->archive, errno,- "Failed to get first ACL entry");- return (ARCHIVE_WARN);- }-- while (s == 1) {- ae_id = -1;- ae_name = NULL;- ae_perm = 0;-- if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {- archive_set_error(&a->archive, errno,- "Failed to get ACL tag type");- return (ARCHIVE_WARN);- }- switch (acl_tag) {- case ACL_USER:- q = acl_get_qualifier(acl_entry);- if (q != NULL) {- ae_id = (int)*(uid_t *)q;- acl_free(q);- ae_name = archive_read_disk_uname(&a->archive,- ae_id);- }- ae_tag = ARCHIVE_ENTRY_ACL_USER;- break;- case ACL_GROUP:- q = acl_get_qualifier(acl_entry);- if (q != NULL) {- ae_id = (int)*(gid_t *)q;- acl_free(q);- ae_name = archive_read_disk_gname(&a->archive,- ae_id);- }- ae_tag = ARCHIVE_ENTRY_ACL_GROUP;- break;- case ACL_MASK:- ae_tag = ARCHIVE_ENTRY_ACL_MASK;- break;- case ACL_USER_OBJ:- ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;- break;- case ACL_GROUP_OBJ:- ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- break;- case ACL_OTHER:- ae_tag = ARCHIVE_ENTRY_ACL_OTHER;- break;-#if ARCHIVE_ACL_FREEBSD_NFS4- case ACL_EVERYONE:- ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;- break;-#endif- default:- /* Skip types that libarchive can't support. */- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);- continue;- }-- // XXX acl_type maps to allow/deny/audit/YYYY bits- entry_acl_type = default_entry_acl_type;--#if ARCHIVE_ACL_FREEBSD_NFS4- if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- /*- * acl_get_entry_type_np() fails with non-NFSv4 ACLs- */- if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {- archive_set_error(&a->archive, errno, "Failed "- "to get ACL type from a NFSv4 ACL entry");- return (ARCHIVE_WARN);- }- switch (acl_type) {- case ACL_ENTRY_TYPE_ALLOW:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;- break;- case ACL_ENTRY_TYPE_DENY:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;- break;- case ACL_ENTRY_TYPE_AUDIT:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;- break;- case ACL_ENTRY_TYPE_ALARM:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;- break;- default:- archive_set_error(&a->archive, errno,- "Invalid NFSv4 ACL entry type");- return (ARCHIVE_WARN);- }-- /*- * Libarchive stores "flag" (NFSv4 inheritance bits)- * in the ae_perm bitmap.- *- * acl_get_flagset_np() fails with non-NFSv4 ACLs- */- if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {- archive_set_error(&a->archive, errno,- "Failed to get flagset from a NFSv4 "- "ACL entry");- return (ARCHIVE_WARN);- }- for (i = 0; i < acl_nfs4_flag_map_size; ++i) {- r = acl_get_flag_np(acl_flagset,- acl_nfs4_flag_map[i].p_perm);- if (r == -1) {- archive_set_error(&a->archive, errno,- "Failed to check flag in a NFSv4 "- "ACL flagset");- return (ARCHIVE_WARN);- } else if (r)- ae_perm |= acl_nfs4_flag_map[i].a_perm;- }- }-#endif-- if (acl_get_permset(acl_entry, &acl_permset) != 0) {- archive_set_error(&a->archive, errno,- "Failed to get ACL permission set");- return (ARCHIVE_WARN);- }--#if ARCHIVE_ACL_FREEBSD_NFS4- if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- perm_map_size = acl_nfs4_perm_map_size;- perm_map = acl_nfs4_perm_map;- } else {-#endif- perm_map_size = acl_posix_perm_map_size;- perm_map = acl_posix_perm_map;-#if ARCHIVE_ACL_FREEBSD_NFS4- }-#endif-- for (i = 0; i < perm_map_size; ++i) {- r = acl_get_perm_np(acl_permset, perm_map[i].p_perm);- if (r == -1) {- archive_set_error(&a->archive, errno,- "Failed to check permission in an ACL "- "permission set");- return (ARCHIVE_WARN);- } else if (r)- ae_perm |= perm_map[i].a_perm;- }-- archive_entry_acl_add_entry(entry, entry_acl_type,- ae_perm, ae_tag,- ae_id, ae_name);-- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);- if (s == -1) {- archive_set_error(&a->archive, errno,- "Failed to get next ACL entry");- return (ARCHIVE_WARN);- }- }- return (ARCHIVE_OK);-}--static int-set_acl(struct archive *a, int fd, const char *name,- struct archive_acl *abstract_acl, __LA_MODE_T mode,- int ae_requested_type, const char *tname)-{- int acl_type = 0;- acl_t acl;- acl_entry_t acl_entry;- acl_permset_t acl_permset;-#if ARCHIVE_ACL_FREEBSD_NFS4- acl_flagset_t acl_flagset;- int r;-#endif- int ret;- int ae_type, ae_permset, ae_tag, ae_id;- int perm_map_size;- const acl_perm_map_t *perm_map;- uid_t ae_uid;- gid_t ae_gid;- const char *ae_name;- int entries;- int i;-- ret = ARCHIVE_OK;- entries = archive_acl_reset(abstract_acl, ae_requested_type);- if (entries == 0)- return (ARCHIVE_OK);--- switch (ae_requested_type) {- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:- acl_type = ACL_TYPE_ACCESS;- break;- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:- acl_type = ACL_TYPE_DEFAULT;- break;-#if ARCHIVE_ACL_FREEBSD_NFS4- case ARCHIVE_ENTRY_ACL_TYPE_NFS4:- acl_type = ACL_TYPE_NFS4;- break;-#endif- default:- errno = ENOENT;- archive_set_error(a, errno, "Unsupported ACL type");- return (ARCHIVE_FAILED);- }-- if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {- errno = EINVAL;- archive_set_error(a, errno,- "Cannot set default ACL on non-directory");- return (ARCHIVE_WARN);- }-- acl = acl_init(entries);- if (acl == (acl_t)NULL) {- archive_set_error(a, errno,- "Failed to initialize ACL working storage");- return (ARCHIVE_FAILED);- }-- while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,- &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {- if (acl_create_entry(&acl, &acl_entry) != 0) {- archive_set_error(a, errno,- "Failed to create a new ACL entry");- ret = ARCHIVE_FAILED;- goto exit_free;- }- switch (ae_tag) {- case ARCHIVE_ENTRY_ACL_USER:- ae_uid = archive_write_disk_uid(a, ae_name, ae_id);- acl_set_tag_type(acl_entry, ACL_USER);- acl_set_qualifier(acl_entry, &ae_uid);- break;- case ARCHIVE_ENTRY_ACL_GROUP:- ae_gid = archive_write_disk_gid(a, ae_name, ae_id);- acl_set_tag_type(acl_entry, ACL_GROUP);- acl_set_qualifier(acl_entry, &ae_gid);- break;- case ARCHIVE_ENTRY_ACL_USER_OBJ:- acl_set_tag_type(acl_entry, ACL_USER_OBJ);- break;- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);- break;- case ARCHIVE_ENTRY_ACL_MASK:- acl_set_tag_type(acl_entry, ACL_MASK);- break;- case ARCHIVE_ENTRY_ACL_OTHER:- acl_set_tag_type(acl_entry, ACL_OTHER);- break;-#if ARCHIVE_ACL_FREEBSD_NFS4- case ARCHIVE_ENTRY_ACL_EVERYONE:- acl_set_tag_type(acl_entry, ACL_EVERYONE);- break;-#endif- default:- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unsupported ACL tag");- ret = ARCHIVE_FAILED;- goto exit_free;- }--#if ARCHIVE_ACL_FREEBSD_NFS4- r = 0;- switch (ae_type) {- case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:- r = acl_set_entry_type_np(acl_entry,- ACL_ENTRY_TYPE_ALLOW);- break;- case ARCHIVE_ENTRY_ACL_TYPE_DENY:- r = acl_set_entry_type_np(acl_entry,- ACL_ENTRY_TYPE_DENY);- break;- case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:- r = acl_set_entry_type_np(acl_entry,- ACL_ENTRY_TYPE_AUDIT);- break;- case ARCHIVE_ENTRY_ACL_TYPE_ALARM:- r = acl_set_entry_type_np(acl_entry,- ACL_ENTRY_TYPE_ALARM);- break;- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:- // These don't translate directly into the system ACL.- break;- default:- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unsupported ACL entry type");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- if (r != 0) {- archive_set_error(a, errno,- "Failed to set ACL entry type");- ret = ARCHIVE_FAILED;- goto exit_free;- }-#endif-- if (acl_get_permset(acl_entry, &acl_permset) != 0) {- archive_set_error(a, errno,- "Failed to get ACL permission set");- ret = ARCHIVE_FAILED;- goto exit_free;- }- if (acl_clear_perms(acl_permset) != 0) {- archive_set_error(a, errno,- "Failed to clear ACL permissions");- ret = ARCHIVE_FAILED;- goto exit_free;- }-#if ARCHIVE_ACL_FREEBSD_NFS4- if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- perm_map_size = acl_nfs4_perm_map_size;- perm_map = acl_nfs4_perm_map;- } else {-#endif- perm_map_size = acl_posix_perm_map_size;- perm_map = acl_posix_perm_map;-#if ARCHIVE_ACL_FREEBSD_NFS4- }-#endif-- for (i = 0; i < perm_map_size; ++i) {- if (ae_permset & perm_map[i].a_perm) {- if (acl_add_perm(acl_permset,- perm_map[i].p_perm) != 0) {- archive_set_error(a, errno,- "Failed to add ACL permission");- ret = ARCHIVE_FAILED;- goto exit_free;- }- }- }--#if ARCHIVE_ACL_FREEBSD_NFS4- if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- /*- * acl_get_flagset_np() fails with non-NFSv4 ACLs- */- if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {- archive_set_error(a, errno,- "Failed to get flagset from an NFSv4 "- "ACL entry");- ret = ARCHIVE_FAILED;- goto exit_free;- }- if (acl_clear_flags_np(acl_flagset) != 0) {- archive_set_error(a, errno,- "Failed to clear flags from an NFSv4 "- "ACL flagset");- ret = ARCHIVE_FAILED;- goto exit_free;- }- for (i = 0; i < acl_nfs4_flag_map_size; ++i) {- if (ae_permset & acl_nfs4_flag_map[i].a_perm) {- if (acl_add_flag_np(acl_flagset,- acl_nfs4_flag_map[i].p_perm) != 0) {- archive_set_error(a, errno,- "Failed to add flag to "- "NFSv4 ACL flagset");- ret = ARCHIVE_FAILED;- goto exit_free;- }- }- }- }-#endif- }-- /* Try restoring the ACL through 'fd' if we can. */- if (fd >= 0) {- if (acl_set_fd_np(fd, acl, acl_type) == 0)- ret = ARCHIVE_OK;- else {- if (errno == EOPNOTSUPP) {- /* Filesystem doesn't support ACLs */- ret = ARCHIVE_OK;- } else {- archive_set_error(a, errno,- "Failed to set acl on fd: %s", tname);- ret = ARCHIVE_WARN;- }- }- }-#if HAVE_ACL_SET_LINK_NP- else if (acl_set_link_np(name, acl_type, acl) != 0)-#else- /* FreeBSD older than 8.0 */- else if (S_ISLNK(mode)) {- /* acl_set_file() follows symbolic links, skip */- ret = ARCHIVE_OK;- } else if (acl_set_file(name, acl_type, acl) != 0)-#endif- {- if (errno == EOPNOTSUPP) {- /* Filesystem doesn't support ACLs */- ret = ARCHIVE_OK;- } else {- archive_set_error(a, errno, "Failed to set acl: %s",- tname);- ret = ARCHIVE_WARN;- }- }-exit_free:- acl_free(acl);- return (ret);-}--int-archive_read_disk_entry_setup_acls(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- const char *accpath;- acl_t acl;- int r;-- accpath = NULL;-- if (*fd < 0) {- accpath = archive_read_disk_entry_setup_path(a, entry, fd);- if (accpath == NULL)- return (ARCHIVE_WARN);- }-- archive_entry_acl_clear(entry);-- acl = NULL;--#if ARCHIVE_ACL_FREEBSD_NFS4- /* Try NFSv4 ACL first. */- if (*fd >= 0)- acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4);- else if (!a->follow_symlinks)- acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);- else- acl = acl_get_file(accpath, ACL_TYPE_NFS4);-- /* Ignore "trivial" ACLs that just mirror the file mode. */- if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {- acl_free(acl);- acl = NULL;- return (ARCHIVE_OK);- }-- if (acl != NULL) {- r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);- acl_free(acl);- acl = NULL;-- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, errno,- "Couldn't translate NFSv4 ACLs");- }-- return (r);- }-#endif-- /* Retrieve access ACL from file. */- if (*fd >= 0)- acl = acl_get_fd_np(*fd, ACL_TYPE_ACCESS);-#if HAVE_ACL_GET_LINK_NP- else if (!a->follow_symlinks)- acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);-#else- else if ((!a->follow_symlinks)- && (archive_entry_filetype(entry) == AE_IFLNK))- /* We can't get the ACL of a symlink, so we assume it can't- have one. */- acl = NULL;-#endif- else- acl = acl_get_file(accpath, ACL_TYPE_ACCESS);--#if HAVE_ACL_IS_TRIVIAL_NP- /* Ignore "trivial" ACLs that just mirror the file mode. */- if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {- acl_free(acl);- acl = NULL;- }-#endif-- if (acl != NULL) {- r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);- acl_free(acl);- acl = NULL;-- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, errno,- "Couldn't translate access ACLs");- return (r);- }- }-- /* Only directories can have default ACLs. */- if (S_ISDIR(archive_entry_mode(entry))) {- if (*fd >= 0)- acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);- else- acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);- if (acl != NULL) {- r = translate_acl(a, entry, acl,- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);- acl_free(acl);- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, errno,- "Couldn't translate default ACLs");- return (r);- }- }- }- return (ARCHIVE_OK);-}--int-archive_write_disk_set_acls(struct archive *a, int fd, const char *name,- struct archive_acl *abstract_acl, __LA_MODE_T mode)-{- int ret = ARCHIVE_OK;-- (void)mode; /* UNUSED */-- if ((archive_acl_types(abstract_acl)- & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {- if ((archive_acl_types(abstract_acl)- & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {- ret = set_acl(a, fd, name, abstract_acl, mode,- ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");- if (ret != ARCHIVE_OK)- return (ret);- }- if ((archive_acl_types(abstract_acl)- & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)- ret = set_acl(a, fd, name, abstract_acl, mode,- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");-- /* Simultaneous POSIX.1e and NFSv4 is not supported */- return (ret);- }-#if ARCHIVE_ACL_FREEBSD_NFS4- else if ((archive_acl_types(abstract_acl) &- ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {- ret = set_acl(a, fd, name, abstract_acl, mode,- ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");- }-#endif- return (ret);-}-#endif /* ARCHIVE_ACL_FREEBSD */
− c/archive_disk_acl_linux.c
@@ -1,760 +0,0 @@-/*-- * Copyright (c) 2003-2009 Tim Kientzle- * Copyright (c) 2010-2012 Michihiro NAKAJIMA- * Copyright (c) 2017 Martin Matuska- * 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"--#if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_LIBRICHACL--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#if HAVE_ACL_LIBACL_H-#include <acl/libacl.h>-#endif-#ifdef HAVE_SYS_ACL_H-#include <sys/acl.h>-#endif-#ifdef HAVE_SYS_RICHACL_H-#include <sys/richacl.h>-#endif--#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_disk_private.h"-#include "archive_write_disk_private.h"--typedef struct {- const int a_perm; /* Libarchive permission or flag */- const int p_perm; /* Platform permission or flag */-} acl_perm_map_t;--#if ARCHIVE_ACL_LIBACL-static const acl_perm_map_t acl_posix_perm_map[] = {- {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},- {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},- {ARCHIVE_ENTRY_ACL_READ, ACL_READ},-};--static const int acl_posix_perm_map_size =- (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0]));-#endif /* ARCHIVE_ACL_LIBACL */--#if ARCHIVE_ACL_LIBRICHACL-static const acl_perm_map_t acl_nfs4_perm_map[] = {- {ARCHIVE_ENTRY_ACL_EXECUTE, RICHACE_EXECUTE},- {ARCHIVE_ENTRY_ACL_READ_DATA, RICHACE_READ_DATA},- {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, RICHACE_LIST_DIRECTORY},- {ARCHIVE_ENTRY_ACL_WRITE_DATA, RICHACE_WRITE_DATA},- {ARCHIVE_ENTRY_ACL_ADD_FILE, RICHACE_ADD_FILE},- {ARCHIVE_ENTRY_ACL_APPEND_DATA, RICHACE_APPEND_DATA},- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, RICHACE_ADD_SUBDIRECTORY},- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, RICHACE_READ_NAMED_ATTRS},- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, RICHACE_WRITE_NAMED_ATTRS},- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, RICHACE_DELETE_CHILD},- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, RICHACE_READ_ATTRIBUTES},- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, RICHACE_WRITE_ATTRIBUTES},- {ARCHIVE_ENTRY_ACL_DELETE, RICHACE_DELETE},- {ARCHIVE_ENTRY_ACL_READ_ACL, RICHACE_READ_ACL},- {ARCHIVE_ENTRY_ACL_WRITE_ACL, RICHACE_WRITE_ACL},- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, RICHACE_WRITE_OWNER},- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, RICHACE_SYNCHRONIZE}-};--static const int acl_nfs4_perm_map_size =- (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));--static const acl_perm_map_t acl_nfs4_flag_map[] = {- {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, RICHACE_FILE_INHERIT_ACE},- {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, RICHACE_DIRECTORY_INHERIT_ACE},- {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, RICHACE_NO_PROPAGATE_INHERIT_ACE},- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, RICHACE_INHERIT_ONLY_ACE},- {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, RICHACE_INHERITED_ACE}-};--static const int acl_nfs4_flag_map_size =- (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));-#endif /* ARCHIVE_ACL_LIBRICHACL */--#if ARCHIVE_ACL_LIBACL-/*- * Translate POSIX.1e ACLs into libarchive internal structure- */-static int-translate_acl(struct archive_read_disk *a,- struct archive_entry *entry, acl_t acl, int default_entry_acl_type)-{- acl_tag_t acl_tag;- acl_entry_t acl_entry;- acl_permset_t acl_permset;- int i, entry_acl_type;- int r, s, ae_id, ae_tag, ae_perm;- void *q;- const char *ae_name;-- s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);- if (s == -1) {- archive_set_error(&a->archive, errno,- "Failed to get first ACL entry");- return (ARCHIVE_WARN);- }-- while (s == 1) {- ae_id = -1;- ae_name = NULL;- ae_perm = 0;-- if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {- archive_set_error(&a->archive, errno,- "Failed to get ACL tag type");- return (ARCHIVE_WARN);- }- switch (acl_tag) {- case ACL_USER:- q = acl_get_qualifier(acl_entry);- if (q != NULL) {- ae_id = (int)*(uid_t *)q;- acl_free(q);- ae_name = archive_read_disk_uname(&a->archive,- ae_id);- }- ae_tag = ARCHIVE_ENTRY_ACL_USER;- break;- case ACL_GROUP:- q = acl_get_qualifier(acl_entry);- if (q != NULL) {- ae_id = (int)*(gid_t *)q;- acl_free(q);- ae_name = archive_read_disk_gname(&a->archive,- ae_id);- }- ae_tag = ARCHIVE_ENTRY_ACL_GROUP;- break;- case ACL_MASK:- ae_tag = ARCHIVE_ENTRY_ACL_MASK;- break;- case ACL_USER_OBJ:- ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;- break;- case ACL_GROUP_OBJ:- ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- break;- case ACL_OTHER:- ae_tag = ARCHIVE_ENTRY_ACL_OTHER;- break;- default:- /* Skip types that libarchive can't support. */- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);- continue;- }-- // XXX acl_type maps to allow/deny/audit/YYYY bits- entry_acl_type = default_entry_acl_type;-- if (acl_get_permset(acl_entry, &acl_permset) != 0) {- archive_set_error(&a->archive, errno,- "Failed to get ACL permission set");- return (ARCHIVE_WARN);- }-- for (i = 0; i < acl_posix_perm_map_size; ++i) {- r = acl_get_perm(acl_permset,- acl_posix_perm_map[i].p_perm);- if (r == -1) {- archive_set_error(&a->archive, errno,- "Failed to check permission in an ACL "- "permission set");- return (ARCHIVE_WARN);- } else if (r)- ae_perm |= acl_posix_perm_map[i].a_perm;- }-- archive_entry_acl_add_entry(entry, entry_acl_type,- ae_perm, ae_tag,- ae_id, ae_name);-- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);- if (s == -1) {- archive_set_error(&a->archive, errno,- "Failed to get next ACL entry");- return (ARCHIVE_WARN);- }- }- return (ARCHIVE_OK);-}-#endif /* ARCHIVE_ACL_LIBACL */--#if ARCHIVE_ACL_LIBRICHACL-/*- * Translate RichACL into libarchive internal ACL- */-static int-translate_richacl(struct archive_read_disk *a, struct archive_entry *entry,- struct richacl *richacl)-{- int ae_id, ae_tag, ae_perm;- int entry_acl_type, i;- const char *ae_name;-- struct richace *richace;-- richacl_for_each_entry(richace, richacl) {- ae_name = NULL;- ae_tag = 0;- ae_perm = 0;- ae_id = -1;-- switch (richace->e_type) {- case RICHACE_ACCESS_ALLOWED_ACE_TYPE:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;- break;- case RICHACE_ACCESS_DENIED_ACE_TYPE:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;- break;- default: /* Unknown entry type, skip */- continue;- }-- /* Unsupported */- if (richace->e_flags & RICHACE_UNMAPPED_WHO)- continue;-- if (richace->e_flags & RICHACE_SPECIAL_WHO) {- switch (richace->e_id) {- case RICHACE_OWNER_SPECIAL_ID:- ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;- break;- case RICHACE_GROUP_SPECIAL_ID:- ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- break;- case RICHACE_EVERYONE_SPECIAL_ID:- ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;- break;- default: /* Unknown special ID type */- continue;- }- } else {- ae_id = richace->e_id;- if (richace->e_flags & RICHACE_IDENTIFIER_GROUP) {- ae_tag = ARCHIVE_ENTRY_ACL_GROUP;- ae_name = archive_read_disk_gname(&a->archive,- (gid_t)(richace->e_id));- } else {- ae_tag = ARCHIVE_ENTRY_ACL_USER;- ae_name = archive_read_disk_uname(&a->archive,- (uid_t)(richace->e_id));- }- }- for (i = 0; i < acl_nfs4_flag_map_size; ++i) {- if ((richace->e_flags &- acl_nfs4_flag_map[i].p_perm) != 0)- ae_perm |= acl_nfs4_flag_map[i].a_perm;- }- for (i = 0; i < acl_nfs4_perm_map_size; ++i) {- if ((richace->e_mask &- acl_nfs4_perm_map[i].p_perm) != 0)- ae_perm |=- acl_nfs4_perm_map[i].a_perm;- }-- archive_entry_acl_add_entry(entry, entry_acl_type,- ae_perm, ae_tag, ae_id, ae_name);- }- return (ARCHIVE_OK);-}-#endif /* ARCHIVE_ACL_LIBRICHACL */--#if ARCHIVE_ACL_LIBRICHACL-static int-_richacl_mode_to_mask(short mode)-{- int mask = 0;-- if (mode & S_IROTH)- mask |= RICHACE_POSIX_MODE_READ;- if (mode & S_IWOTH)- mask |= RICHACE_POSIX_MODE_WRITE;- if (mode & S_IXOTH)- mask |= RICHACE_POSIX_MODE_EXEC;-- return (mask);-}--static void-_richacl_mode_to_masks(struct richacl *richacl, __LA_MODE_T mode)-{- richacl->a_owner_mask = _richacl_mode_to_mask((mode & 0700) >> 6);- richacl->a_group_mask = _richacl_mode_to_mask((mode & 0070) >> 3);- richacl->a_other_mask = _richacl_mode_to_mask(mode & 0007);-}-#endif /* ARCHIVE_ACL_LIBRICHACL */--#if ARCHIVE_ACL_LIBRICHACL-static int-set_richacl(struct archive *a, int fd, const char *name,- struct archive_acl *abstract_acl, __LA_MODE_T mode,- int ae_requested_type, const char *tname)-{- int ae_type, ae_permset, ae_tag, ae_id;- uid_t ae_uid;- gid_t ae_gid;- const char *ae_name;- int entries;- int i;- int ret;- int e = 0;- struct richacl *richacl = NULL;- struct richace *richace;-- ret = ARCHIVE_OK;- entries = archive_acl_reset(abstract_acl, ae_requested_type);- if (entries == 0)- return (ARCHIVE_OK);-- if (ae_requested_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- errno = ENOENT;- archive_set_error(a, errno, "Unsupported ACL type");- return (ARCHIVE_FAILED);- }-- if (S_ISLNK(mode)) {- /* Linux does not support RichACLs on symbolic links */- return (ARCHIVE_OK);- }-- richacl = richacl_alloc(entries);- if (richacl == NULL) {- archive_set_error(a, errno,- "Failed to initialize RichACL working storage");- return (ARCHIVE_FAILED);- }-- e = 0;-- while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,- &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {- richace = &(richacl->a_entries[e]);-- richace->e_flags = 0;- richace->e_mask = 0;-- switch (ae_tag) {- case ARCHIVE_ENTRY_ACL_USER:- ae_uid = archive_write_disk_uid(a, ae_name, ae_id);- richace->e_id = ae_uid;- break;- case ARCHIVE_ENTRY_ACL_GROUP:- ae_gid = archive_write_disk_gid(a, ae_name, ae_id);- richace->e_id = ae_gid;- richace->e_flags |= RICHACE_IDENTIFIER_GROUP;- break;- case ARCHIVE_ENTRY_ACL_USER_OBJ:- richace->e_flags |= RICHACE_SPECIAL_WHO;- richace->e_id = RICHACE_OWNER_SPECIAL_ID;- break;- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- richace->e_flags |= RICHACE_SPECIAL_WHO;- richace->e_id = RICHACE_GROUP_SPECIAL_ID;- break;- case ARCHIVE_ENTRY_ACL_EVERYONE:- richace->e_flags |= RICHACE_SPECIAL_WHO;- richace->e_id = RICHACE_EVERYONE_SPECIAL_ID;- break;- default:- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unsupported ACL tag");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- switch (ae_type) {- case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:- richace->e_type =- RICHACE_ACCESS_ALLOWED_ACE_TYPE;- break;- case ARCHIVE_ENTRY_ACL_TYPE_DENY:- richace->e_type =- RICHACE_ACCESS_DENIED_ACE_TYPE;- break;- case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:- case ARCHIVE_ENTRY_ACL_TYPE_ALARM:- break;- default:- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unsupported ACL entry type");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- for (i = 0; i < acl_nfs4_perm_map_size; ++i) {- if (ae_permset & acl_nfs4_perm_map[i].a_perm)- richace->e_mask |= acl_nfs4_perm_map[i].p_perm;- }-- for (i = 0; i < acl_nfs4_flag_map_size; ++i) {- if (ae_permset &- acl_nfs4_flag_map[i].a_perm)- richace->e_flags |= acl_nfs4_flag_map[i].p_perm;- }- e++;- }-- /* Fill RichACL masks */- _richacl_mode_to_masks(richacl, mode);-- if (fd >= 0) {- if (richacl_set_fd(fd, richacl) == 0)- ret = ARCHIVE_OK;- else {- if (errno == EOPNOTSUPP) {- /* Filesystem doesn't support ACLs */- ret = ARCHIVE_OK;- } else {- archive_set_error(a, errno,- "Failed to set richacl on fd: %s", tname);- ret = ARCHIVE_WARN;- }- }- } else if (richacl_set_file(name, richacl) != 0) {- if (errno == EOPNOTSUPP) {- /* Filesystem doesn't support ACLs */- ret = ARCHIVE_OK;- } else {- archive_set_error(a, errno, "Failed to set richacl: %s",- tname);- ret = ARCHIVE_WARN;- }- }-exit_free:- richacl_free(richacl);- return (ret);-}-#endif /* ARCHIVE_ACL_RICHACL */--#if ARCHIVE_ACL_LIBACL-static int-set_acl(struct archive *a, int fd, const char *name,- struct archive_acl *abstract_acl, __LA_MODE_T mode,- int ae_requested_type, const char *tname)-{- int acl_type = 0;- int ae_type, ae_permset, ae_tag, ae_id;- uid_t ae_uid;- gid_t ae_gid;- const char *ae_name;- int entries;- int i;- int ret;- acl_t acl = NULL;- acl_entry_t acl_entry;- acl_permset_t acl_permset;-- ret = ARCHIVE_OK;- entries = archive_acl_reset(abstract_acl, ae_requested_type);- if (entries == 0)- return (ARCHIVE_OK);-- switch (ae_requested_type) {- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:- acl_type = ACL_TYPE_ACCESS;- break;- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:- acl_type = ACL_TYPE_DEFAULT;- break;- default:- errno = ENOENT;- archive_set_error(a, errno, "Unsupported ACL type");- return (ARCHIVE_FAILED);- }-- if (S_ISLNK(mode)) {- /* Linux does not support ACLs on symbolic links */- return (ARCHIVE_OK);- }-- if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {- errno = EINVAL;- archive_set_error(a, errno,- "Cannot set default ACL on non-directory");- return (ARCHIVE_WARN);- }-- acl = acl_init(entries);- if (acl == (acl_t)NULL) {- archive_set_error(a, errno,- "Failed to initialize ACL working storage");- return (ARCHIVE_FAILED);- }-- while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,- &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {-- if (acl_create_entry(&acl, &acl_entry) != 0) {- archive_set_error(a, errno,- "Failed to create a new ACL entry");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- switch (ae_tag) {- case ARCHIVE_ENTRY_ACL_USER:- ae_uid = archive_write_disk_uid(a, ae_name, ae_id);- acl_set_tag_type(acl_entry, ACL_USER);- acl_set_qualifier(acl_entry, &ae_uid);- break;- case ARCHIVE_ENTRY_ACL_GROUP:- ae_gid = archive_write_disk_gid(a, ae_name, ae_id);- acl_set_tag_type(acl_entry, ACL_GROUP);- acl_set_qualifier(acl_entry, &ae_gid);- break;- case ARCHIVE_ENTRY_ACL_USER_OBJ:- acl_set_tag_type(acl_entry, ACL_USER_OBJ);- break;- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);- break;- case ARCHIVE_ENTRY_ACL_MASK:- acl_set_tag_type(acl_entry, ACL_MASK);- break;- case ARCHIVE_ENTRY_ACL_OTHER:- acl_set_tag_type(acl_entry, ACL_OTHER);- break;- default:- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unsupported ACL tag");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- if (acl_get_permset(acl_entry, &acl_permset) != 0) {- archive_set_error(a, errno,- "Failed to get ACL permission set");- ret = ARCHIVE_FAILED;- goto exit_free;- }- if (acl_clear_perms(acl_permset) != 0) {- archive_set_error(a, errno,- "Failed to clear ACL permissions");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- for (i = 0; i < acl_posix_perm_map_size; ++i) {- if (ae_permset & acl_posix_perm_map[i].a_perm) {- if (acl_add_perm(acl_permset,- acl_posix_perm_map[i].p_perm) != 0) {- archive_set_error(a, errno,- "Failed to add ACL permission");- ret = ARCHIVE_FAILED;- goto exit_free;- }- }- }-- }-- if (fd >= 0 && ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {- if (acl_set_fd(fd, acl) == 0)- ret = ARCHIVE_OK;- else {- if (errno == EOPNOTSUPP) {- /* Filesystem doesn't support ACLs */- ret = ARCHIVE_OK;- } else {- archive_set_error(a, errno,- "Failed to set acl on fd: %s", tname);- ret = ARCHIVE_WARN;- }- }- } else if (acl_set_file(name, acl_type, acl) != 0) {- if (errno == EOPNOTSUPP) {- /* Filesystem doesn't support ACLs */- ret = ARCHIVE_OK;- } else {- archive_set_error(a, errno, "Failed to set acl: %s",- tname);- ret = ARCHIVE_WARN;- }- }-exit_free:- acl_free(acl);- return (ret);-}-#endif /* ARCHIVE_ACL_LIBACL */--int-archive_read_disk_entry_setup_acls(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- const char *accpath;- int r;-#if ARCHIVE_ACL_LIBACL- acl_t acl;-#endif-#if ARCHIVE_ACL_LIBRICHACL- struct richacl *richacl;- mode_t mode;-#endif-- accpath = NULL;- r = ARCHIVE_OK;-- /* For default ACLs we need reachable accpath */- if (*fd < 0 || S_ISDIR(archive_entry_mode(entry))) {- accpath = archive_read_disk_entry_setup_path(a, entry, fd);- if (accpath == NULL)- return (ARCHIVE_WARN);- }-- archive_entry_acl_clear(entry);--#if ARCHIVE_ACL_LIBACL- acl = NULL;-#endif-#if ARCHIVE_ACL_LIBRICHACL- richacl = NULL;-#endif--#if ARCHIVE_ACL_LIBRICHACL- /* Try NFSv4 ACL first. */- if (*fd >= 0)- richacl = richacl_get_fd(*fd);- else if ((!a->follow_symlinks)- && (archive_entry_filetype(entry) == AE_IFLNK))- /* We can't get the ACL of a symlink, so we assume it can't- have one */- richacl = NULL;- else- richacl = richacl_get_file(accpath);-- /* Ignore "trivial" ACLs that just mirror the file mode. */- if (richacl != NULL) {- mode = archive_entry_mode(entry);- if (richacl_equiv_mode(richacl, &mode) == 0) {- richacl_free(richacl);- richacl = NULL;- return (ARCHIVE_OK);- }- }-- if (richacl != NULL) {- r = translate_richacl(a, entry, richacl);- richacl_free(richacl);- richacl = NULL;-- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, errno,- "Couldn't translate NFSv4 ACLs");- }-- return (r);- }-#endif /* ARCHIVE_ACL_LIBRICHACL */--#if ARCHIVE_ACL_LIBACL- /* Retrieve access ACL from file. */- if (*fd >= 0)- acl = acl_get_fd(*fd);- else if ((!a->follow_symlinks)- && (archive_entry_filetype(entry) == AE_IFLNK))- /* We can't get the ACL of a symlink, so we assume it can't- have one. */- acl = NULL;- else- acl = acl_get_file(accpath, ACL_TYPE_ACCESS);-- if (acl != NULL) {- r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);- acl_free(acl);- acl = NULL;-- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, errno,- "Couldn't translate access ACLs");- return (r);- }- }-- /* Only directories can have default ACLs. */- if (S_ISDIR(archive_entry_mode(entry))) {- acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);- if (acl != NULL) {- r = translate_acl(a, entry, acl,- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);- acl_free(acl);- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, errno,- "Couldn't translate default ACLs");- return (r);- }- }- }-#endif /* ARCHIVE_ACL_LIBACL */- return (r);-}--int-archive_write_disk_set_acls(struct archive *a, int fd, const char *name,- struct archive_acl *abstract_acl, __LA_MODE_T mode)-{- int ret = ARCHIVE_OK;--#if !ARCHIVE_ACL_LIBRICHACL- (void)mode; /* UNUSED */-#endif--#if ARCHIVE_ACL_LIBRICHACL- if ((archive_acl_types(abstract_acl)- & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {- ret = set_richacl(a, fd, name, abstract_acl, mode,- ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");- }-#if ARCHIVE_ACL_LIBACL- else-#endif-#endif /* ARCHIVE_ACL_LIBRICHACL */-#if ARCHIVE_ACL_LIBACL- if ((archive_acl_types(abstract_acl)- & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {- if ((archive_acl_types(abstract_acl)- & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {- ret = set_acl(a, fd, name, abstract_acl, mode,- ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");- if (ret != ARCHIVE_OK)- return (ret);- }- if ((archive_acl_types(abstract_acl)- & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)- ret = set_acl(a, fd, name, abstract_acl, mode,- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");- }-#endif /* ARCHIVE_ACL_LIBACL */- return (ret);-}-#endif /* ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_LIBRICHACL */
− c/archive_disk_acl_sunos.c
@@ -1,824 +0,0 @@-/*-- * Copyright (c) 2017 Martin Matuska- * 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"--#if ARCHIVE_ACL_SUNOS--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_SYS_ACL_H-#define _ACL_PRIVATE /* For debugging */-#include <sys/acl.h>-#endif--#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_disk_private.h"-#include "archive_write_disk_private.h"--typedef struct {- const int a_perm; /* Libarchive permission or flag */- const int p_perm; /* Platform permission or flag */-} acl_perm_map_t;--static const acl_perm_map_t acl_posix_perm_map[] = {- {ARCHIVE_ENTRY_ACL_EXECUTE, S_IXOTH },- {ARCHIVE_ENTRY_ACL_WRITE, S_IWOTH },- {ARCHIVE_ENTRY_ACL_READ, S_IROTH }-};--static const int acl_posix_perm_map_size =- (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0]));--#if ARCHIVE_ACL_SUNOS_NFS4-static const acl_perm_map_t acl_nfs4_perm_map[] = {- {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},- {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},- {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},- {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},- {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},- {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}-};--static const int acl_nfs4_perm_map_size =- (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));--static const acl_perm_map_t acl_nfs4_flag_map[] = {- {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},- {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},- {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},- {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},- {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},-#ifdef ACE_INHERITED_ACE- {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}-#endif-};--const int acl_nfs4_flag_map_size =- (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));--#endif /* ARCHIVE_ACL_SUNOS_NFS4 */--static void *-sunacl_get(int cmd, int *aclcnt, int fd, const char *path)-{- int cnt, cntcmd;- size_t size;- void *aclp;-- if (cmd == GETACL) {- cntcmd = GETACLCNT;- size = sizeof(aclent_t);- }-#if ARCHIVE_ACL_SUNOS_NFS4- else if (cmd == ACE_GETACL) {- cntcmd = ACE_GETACLCNT;- size = sizeof(ace_t);- }-#endif- else {- errno = EINVAL;- *aclcnt = -1;- return (NULL);- }-- aclp = NULL;- cnt = -2;-- while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) {- if (path != NULL)- cnt = acl(path, cntcmd, 0, NULL);- else- cnt = facl(fd, cntcmd, 0, NULL);-- if (cnt > 0) {- if (aclp == NULL)- aclp = malloc(cnt * size);- else- aclp = realloc(NULL, cnt * size);- if (aclp != NULL) {- if (path != NULL)- cnt = acl(path, cmd, cnt, aclp);- else- cnt = facl(fd, cmd, cnt, aclp);- }- } else {- free(aclp);- aclp = NULL;- break;- }- }-- *aclcnt = cnt;- return (aclp);-}--/*- * Check if acl is trivial- * This is a FreeBSD acl_is_trivial_np() implementation for Solaris- */-static int-sun_acl_is_trivial(void *aclp, int aclcnt, mode_t mode, int is_nfs4,- int is_dir, int *trivialp)-{-#if ARCHIVE_ACL_SUNOS_NFS4- int i, p;- const uint32_t rperm = ACE_READ_DATA;- const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA;- const uint32_t eperm = ACE_EXECUTE;- const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |- ACE_READ_ACL | ACE_SYNCHRONIZE;- const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES |- ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER;-- ace_t *ace;- ace_t tace[6];-#endif-- if (aclp == NULL || trivialp == NULL)- return (-1);-- *trivialp = 0;-- /*- * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with- * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries,- * including mask.- */- if (!is_nfs4) {- if (aclcnt == 4)- *trivialp = 1;- return (0);- }--#if ARCHIVE_ACL_SUNOS_NFS4- /*- * Continue with checking NFSv4 ACLs- *- * Create list of trivial ace's to be compared- */-- /* owner@ allow pre */- tace[0].a_flags = ACE_OWNER;- tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;- tace[0].a_access_mask = 0;-- /* owner@ deny */- tace[1].a_flags = ACE_OWNER;- tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE;- tace[1].a_access_mask = 0;-- /* group@ deny */- tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;- tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE;- tace[2].a_access_mask = 0;-- /* owner@ allow */- tace[3].a_flags = ACE_OWNER;- tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;- tace[3].a_access_mask = ownset;-- /* group@ allow */- tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;- tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;- tace[4].a_access_mask = pubset;-- /* everyone@ allow */- tace[5].a_flags = ACE_EVERYONE;- tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;- tace[5].a_access_mask = pubset;-- /* Permissions for everyone@ */- if (mode & 0004)- tace[5].a_access_mask |= rperm;- if (mode & 0002)- tace[5].a_access_mask |= wperm;- if (mode & 0001)- tace[5].a_access_mask |= eperm;-- /* Permissions for group@ */- if (mode & 0040)- tace[4].a_access_mask |= rperm;- else if (mode & 0004)- tace[2].a_access_mask |= rperm;- if (mode & 0020)- tace[4].a_access_mask |= wperm;- else if (mode & 0002)- tace[2].a_access_mask |= wperm;- if (mode & 0010)- tace[4].a_access_mask |= eperm;- else if (mode & 0001)- tace[2].a_access_mask |= eperm;-- /* Permissions for owner@ */- if (mode & 0400) {- tace[3].a_access_mask |= rperm;- if (!(mode & 0040) && (mode & 0004))- tace[0].a_access_mask |= rperm;- } else if ((mode & 0040) || (mode & 0004))- tace[1].a_access_mask |= rperm;- if (mode & 0200) {- tace[3].a_access_mask |= wperm;- if (!(mode & 0020) && (mode & 0002))- tace[0].a_access_mask |= wperm;- } else if ((mode & 0020) || (mode & 0002))- tace[1].a_access_mask |= wperm;- if (mode & 0100) {- tace[3].a_access_mask |= eperm;- if (!(mode & 0010) && (mode & 0001))- tace[0].a_access_mask |= eperm;- } else if ((mode & 0010) || (mode & 0001))- tace[1].a_access_mask |= eperm;-- /* Check if the acl count matches */- p = 3;- for (i = 0; i < 3; i++) {- if (tace[i].a_access_mask != 0)- p++;- }- if (aclcnt != p)- return (0);-- p = 0;- for (i = 0; i < 6; i++) {- if (tace[i].a_access_mask != 0) {- ace = &((ace_t *)aclp)[p];- /*- * Illumos added ACE_DELETE_CHILD to write perms for- * directories. We have to check against that, too.- */- if (ace->a_flags != tace[i].a_flags ||- ace->a_type != tace[i].a_type ||- (ace->a_access_mask != tace[i].a_access_mask &&- (!is_dir || (tace[i].a_access_mask & wperm) == 0 ||- ace->a_access_mask !=- (tace[i].a_access_mask | ACE_DELETE_CHILD))))- return (0);- p++;- }- }-- *trivialp = 1;-#else /* !ARCHIVE_ACL_SUNOS_NFS4 */- (void)is_dir; /* UNUSED */- (void)aclp; /* UNUSED */-#endif /* !ARCHIVE_ACL_SUNOS_NFS4 */- return (0);-}--/*- * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL- */-static int-translate_acl(struct archive_read_disk *a,- struct archive_entry *entry, void *aclp, int aclcnt,- int default_entry_acl_type)-{- int e, i;- int ae_id, ae_tag, ae_perm;- int entry_acl_type;- const char *ae_name;- aclent_t *aclent;-#if ARCHIVE_ACL_SUNOS_NFS4- ace_t *ace;-#endif-- if (aclcnt <= 0)- return (ARCHIVE_OK);-- for (e = 0; e < aclcnt; e++) {- ae_name = NULL;- ae_tag = 0;- ae_perm = 0;--#if ARCHIVE_ACL_SUNOS_NFS4- if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- ace = &((ace_t *)aclp)[e];- ae_id = ace->a_who;-- switch(ace->a_type) {- case ACE_ACCESS_ALLOWED_ACE_TYPE:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;- break;- case ACE_ACCESS_DENIED_ACE_TYPE:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;- break;- case ACE_SYSTEM_AUDIT_ACE_TYPE:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;- break;- case ACE_SYSTEM_ALARM_ACE_TYPE:- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;- break;- default:- /* Unknown entry type, skip */- continue;- }-- if ((ace->a_flags & ACE_OWNER) != 0)- ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;- else if ((ace->a_flags & ACE_GROUP) != 0)- ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- else if ((ace->a_flags & ACE_EVERYONE) != 0)- ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;- else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) {- ae_tag = ARCHIVE_ENTRY_ACL_GROUP;- ae_name = archive_read_disk_gname(&a->archive,- ae_id);- } else {- ae_tag = ARCHIVE_ENTRY_ACL_USER;- ae_name = archive_read_disk_uname(&a->archive,- ae_id);- }-- for (i = 0; i < acl_nfs4_flag_map_size; ++i) {- if ((ace->a_flags &- acl_nfs4_flag_map[i].p_perm) != 0)- ae_perm |= acl_nfs4_flag_map[i].a_perm;- }-- for (i = 0; i < acl_nfs4_perm_map_size; ++i) {- if ((ace->a_access_mask &- acl_nfs4_perm_map[i].p_perm) != 0)- ae_perm |= acl_nfs4_perm_map[i].a_perm;- }- } else-#endif /* ARCHIVE_ACL_SUNOS_NFS4 */- if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {- aclent = &((aclent_t *)aclp)[e];- if ((aclent->a_type & ACL_DEFAULT) != 0)- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;- else- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;- ae_id = aclent->a_id;-- switch(aclent->a_type) {- case DEF_USER:- case USER:- ae_name = archive_read_disk_uname(&a->archive,- ae_id);- ae_tag = ARCHIVE_ENTRY_ACL_USER;- break;- case DEF_GROUP:- case GROUP:- ae_name = archive_read_disk_gname(&a->archive,- ae_id);- ae_tag = ARCHIVE_ENTRY_ACL_GROUP;- break;- case DEF_CLASS_OBJ:- case CLASS_OBJ:- ae_tag = ARCHIVE_ENTRY_ACL_MASK;- break;- case DEF_USER_OBJ:- case USER_OBJ:- ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;- break;- case DEF_GROUP_OBJ:- case GROUP_OBJ:- ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;- break;- case DEF_OTHER_OBJ:- case OTHER_OBJ:- ae_tag = ARCHIVE_ENTRY_ACL_OTHER;- break;- default:- /* Unknown tag type, skip */- continue;- }-- for (i = 0; i < acl_posix_perm_map_size; ++i) {- if ((aclent->a_perm &- acl_posix_perm_map[i].p_perm) != 0)- ae_perm |= acl_posix_perm_map[i].a_perm;- }- } else- return (ARCHIVE_WARN);-- archive_entry_acl_add_entry(entry, entry_acl_type,- ae_perm, ae_tag, ae_id, ae_name);- }- return (ARCHIVE_OK);-}--static int-set_acl(struct archive *a, int fd, const char *name,- struct archive_acl *abstract_acl, __LA_MODE_T mode,- int ae_requested_type, const char *tname)-{- aclent_t *aclent;-#if ARCHIVE_ACL_SUNOS_NFS4- ace_t *ace;-#endif- int cmd, e, r;- void *aclp;- int ret;- int ae_type, ae_permset, ae_tag, ae_id;- int perm_map_size;- const acl_perm_map_t *perm_map;- uid_t ae_uid;- gid_t ae_gid;- const char *ae_name;- int entries;- int i;-- ret = ARCHIVE_OK;- entries = archive_acl_reset(abstract_acl, ae_requested_type);- if (entries == 0)- return (ARCHIVE_OK);-- switch (ae_requested_type) {- case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:- cmd = SETACL;- aclp = malloc(entries * sizeof(aclent_t));- break;-#if ARCHIVE_ACL_SUNOS_NFS4- case ARCHIVE_ENTRY_ACL_TYPE_NFS4:- cmd = ACE_SETACL;- aclp = malloc(entries * sizeof(ace_t));-- break;-#endif- default:- errno = ENOENT;- archive_set_error(a, errno, "Unsupported ACL type");- return (ARCHIVE_FAILED);- }-- if (aclp == NULL) {- archive_set_error(a, errno,- "Can't allocate memory for acl buffer");- return (ARCHIVE_FAILED);- }-- if (S_ISLNK(mode)) {- /* Skip ACLs on symbolic links */- ret = ARCHIVE_OK;- goto exit_free;- }-- e = 0;-- while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,- &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {- aclent = NULL;-#if ARCHIVE_ACL_SUNOS_NFS4- ace = NULL;-#endif- if (cmd == SETACL) {- aclent = &((aclent_t *)aclp)[e];- aclent->a_id = -1;- aclent->a_type = 0;- aclent->a_perm = 0;- }-#if ARCHIVE_ACL_SUNOS_NFS4- else { /* cmd == ACE_SETACL */- ace = &((ace_t *)aclp)[e];- ace->a_who = -1;- ace->a_access_mask = 0;- ace->a_flags = 0;- }-#endif /* ARCHIVE_ACL_SUNOS_NFS4 */-- switch (ae_tag) {- case ARCHIVE_ENTRY_ACL_USER:- ae_uid = archive_write_disk_uid(a, ae_name, ae_id);- if (aclent != NULL) {- aclent->a_id = ae_uid;- aclent->a_type |= USER;- }-#if ARCHIVE_ACL_SUNOS_NFS4- else {- ace->a_who = ae_uid;- }-#endif- break;- case ARCHIVE_ENTRY_ACL_GROUP:- ae_gid = archive_write_disk_gid(a, ae_name, ae_id);- if (aclent != NULL) {- aclent->a_id = ae_gid;- aclent->a_type |= GROUP;- }-#if ARCHIVE_ACL_SUNOS_NFS4- else {- ace->a_who = ae_gid;- ace->a_flags |= ACE_IDENTIFIER_GROUP;- }-#endif- break;- case ARCHIVE_ENTRY_ACL_USER_OBJ:- if (aclent != NULL)- aclent->a_type |= USER_OBJ;-#if ARCHIVE_ACL_SUNOS_NFS4- else {- ace->a_flags |= ACE_OWNER;- }-#endif- break;- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:- if (aclent != NULL)- aclent->a_type |= GROUP_OBJ;-#if ARCHIVE_ACL_SUNOS_NFS4- else {- ace->a_flags |= ACE_GROUP;- ace->a_flags |= ACE_IDENTIFIER_GROUP;- }-#endif- break;- case ARCHIVE_ENTRY_ACL_MASK:- if (aclent != NULL)- aclent->a_type |= CLASS_OBJ;- break;- case ARCHIVE_ENTRY_ACL_OTHER:- if (aclent != NULL)- aclent->a_type |= OTHER_OBJ;- break;-#if ARCHIVE_ACL_SUNOS_NFS4- case ARCHIVE_ENTRY_ACL_EVERYONE:- if (ace != NULL)- ace->a_flags |= ACE_EVERYONE;- break;-#endif- default:- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unsupported ACL tag");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- r = 0;- switch (ae_type) {-#if ARCHIVE_ACL_SUNOS_NFS4- case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:- if (ace != NULL)- ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;- else- r = -1;- break;- case ARCHIVE_ENTRY_ACL_TYPE_DENY:- if (ace != NULL)- ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE;- else- r = -1;- break;- case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:- if (ace != NULL)- ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE;- else- r = -1;- break;- case ARCHIVE_ENTRY_ACL_TYPE_ALARM:- if (ace != NULL)- ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE;- else- r = -1;- break;-#endif- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:- if (aclent == NULL)- r = -1;- break;- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:- if (aclent != NULL)- aclent->a_type |= ACL_DEFAULT;- else- r = -1;- break;- default:- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unsupported ACL entry type");- ret = ARCHIVE_FAILED;- goto exit_free;- }-- if (r != 0) {- errno = EINVAL;- archive_set_error(a, errno,- "Failed to set ACL entry type");- ret = ARCHIVE_FAILED;- goto exit_free;- }--#if ARCHIVE_ACL_SUNOS_NFS4- if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- perm_map_size = acl_nfs4_perm_map_size;- perm_map = acl_nfs4_perm_map;- } else {-#endif- perm_map_size = acl_posix_perm_map_size;- perm_map = acl_posix_perm_map;-#if ARCHIVE_ACL_SUNOS_NFS4- }-#endif- for (i = 0; i < perm_map_size; ++i) {- if (ae_permset & perm_map[i].a_perm) {-#if ARCHIVE_ACL_SUNOS_NFS4- if (ae_requested_type ==- ARCHIVE_ENTRY_ACL_TYPE_NFS4)- ace->a_access_mask |=- perm_map[i].p_perm;- else-#endif- aclent->a_perm |= perm_map[i].p_perm;- }- }--#if ARCHIVE_ACL_SUNOS_NFS4- if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {- for (i = 0; i < acl_nfs4_flag_map_size; ++i) {- if (ae_permset & acl_nfs4_flag_map[i].a_perm) {- ace->a_flags |=- acl_nfs4_flag_map[i].p_perm;- }- }- }-#endif- e++;- }-- /* Try restoring the ACL through 'fd' if we can. */- if (fd >= 0) {- if (facl(fd, cmd, entries, aclp) == 0)- ret = ARCHIVE_OK;- else {- if (errno == EOPNOTSUPP) {- /* Filesystem doesn't support ACLs */- ret = ARCHIVE_OK;- } else {- archive_set_error(a, errno,- "Failed to set acl on fd: %s", tname);- ret = ARCHIVE_WARN;- }- }- } else if (acl(name, cmd, entries, aclp) != 0) {- if (errno == EOPNOTSUPP) {- /* Filesystem doesn't support ACLs */- ret = ARCHIVE_OK;- } else {- archive_set_error(a, errno, "Failed to set acl: %s",- tname);- ret = ARCHIVE_WARN;- }- }-exit_free:- free(aclp);- return (ret);-}--int-archive_read_disk_entry_setup_acls(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- const char *accpath;- void *aclp;- int aclcnt;- int r;-- accpath = NULL;-- if (*fd < 0) {- accpath = archive_read_disk_entry_setup_path(a, entry, fd);- if (accpath == NULL)- return (ARCHIVE_WARN);- }-- archive_entry_acl_clear(entry);-- aclp = NULL;--#if ARCHIVE_ACL_SUNOS_NFS4- if (*fd >= 0)- aclp = sunacl_get(ACE_GETACL, &aclcnt, *fd, NULL);- else if ((!a->follow_symlinks)- && (archive_entry_filetype(entry) == AE_IFLNK))- /* We can't get the ACL of a symlink, so we assume it can't- have one. */- aclp = NULL;- else- aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, accpath);-- if (aclp != NULL && sun_acl_is_trivial(aclp, aclcnt,- archive_entry_mode(entry), 1, S_ISDIR(archive_entry_mode(entry)),- &r) == 0 && r == 1) {- free(aclp);- aclp = NULL;- return (ARCHIVE_OK);- }-- if (aclp != NULL) {- r = translate_acl(a, entry, aclp, aclcnt,- ARCHIVE_ENTRY_ACL_TYPE_NFS4);- free(aclp);- aclp = NULL;-- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, errno,- "Couldn't translate NFSv4 ACLs");- }- return (r);- }-#endif /* ARCHIVE_ACL_SUNOS_NFS4 */-- /* Retrieve POSIX.1e ACLs from file. */- if (*fd >= 0)- aclp = sunacl_get(GETACL, &aclcnt, *fd, NULL);- else if ((!a->follow_symlinks)- && (archive_entry_filetype(entry) == AE_IFLNK))- /* We can't get the ACL of a symlink, so we assume it can't- have one. */- aclp = NULL;- else- aclp = sunacl_get(GETACL, &aclcnt, 0, accpath);-- /* Ignore "trivial" ACLs that just mirror the file mode. */- if (aclp != NULL && sun_acl_is_trivial(aclp, aclcnt,- archive_entry_mode(entry), 0, S_ISDIR(archive_entry_mode(entry)),- &r) == 0 && r == 1) {- free(aclp);- aclp = NULL;- }-- if (aclp != NULL)- {- r = translate_acl(a, entry, aclp, aclcnt,- ARCHIVE_ENTRY_ACL_TYPE_ACCESS);- free(aclp);- aclp = NULL;-- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, errno,- "Couldn't translate access ACLs");- return (r);- }- }-- return (ARCHIVE_OK);-}--int-archive_write_disk_set_acls(struct archive *a, int fd, const char *name,- struct archive_acl *abstract_acl, __LA_MODE_T mode)-{- int ret = ARCHIVE_OK;-- (void)mode; /* UNUSED */-- if ((archive_acl_types(abstract_acl)- & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {- /* Solaris writes POSIX.1e access and default ACLs together */- ret = set_acl(a, fd, name, abstract_acl, mode,- ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");-- /* Simultaneous POSIX.1e and NFSv4 is not supported */- return (ret);- }-#if ARCHIVE_ACL_SUNOS_NFS4- else if ((archive_acl_types(abstract_acl) &- ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {- ret = set_acl(a, fd, name, abstract_acl, mode,- ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");- }-#endif- return (ret);-}-#endif /* ARCHIVE_ACL_SUNOS */
− c/archive_endian.h
@@ -1,195 +0,0 @@-/*-- * Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF- * SUCH DAMAGE.- *- * $FreeBSD: head/lib/libarchive/archive_endian.h 201085 2009-12-28 02:17:15Z kientzle $- *- * Borrowed from FreeBSD's <sys/endian.h>- */--#ifndef ARCHIVE_ENDIAN_H_INCLUDED-#define ARCHIVE_ENDIAN_H_INCLUDED--/* Note: This is a purely internal header! */-/* Do not use this outside of libarchive internal code! */--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--/*- * Disabling inline keyword for compilers known to choke on it:- * - Watcom C++ in C code. (For any version?)- * - SGI MIPSpro- * - Microsoft Visual C++ 6.0 (supposedly newer versions too)- * - IBM VisualAge 6 (XL v6)- * - Sun WorkShop C (SunPro) before 5.9- */-#if defined(__WATCOMC__) || defined(__sgi) || defined(__hpux) || defined(__BORLANDC__)-#define inline-#elif defined(__IBMC__) && __IBMC__ < 700-#define inline-#elif defined(__SUNPRO_C) && __SUNPRO_C < 0x590-#define inline-#elif defined(_MSC_VER) || defined(__osf__)-#define inline __inline-#endif--/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */--static inline uint16_t-archive_be16dec(const void *pp)-{- unsigned char const *p = (unsigned char const *)pp;-- /* Store into unsigned temporaries before left shifting, to avoid- promotion to signed int and then left shifting into the sign bit,- which is undefined behaviour. */- unsigned int p1 = p[1];- unsigned int p0 = p[0];-- return ((p0 << 8) | p1);-}--static inline uint32_t-archive_be32dec(const void *pp)-{- unsigned char const *p = (unsigned char const *)pp;-- /* Store into unsigned temporaries before left shifting, to avoid- promotion to signed int and then left shifting into the sign bit,- which is undefined behaviour. */- unsigned int p3 = p[3];- unsigned int p2 = p[2];- unsigned int p1 = p[1];- unsigned int p0 = p[0];-- return ((p0 << 24) | (p1 << 16) | (p2 << 8) | p3);-}--static inline uint64_t-archive_be64dec(const void *pp)-{- unsigned char const *p = (unsigned char const *)pp;-- return (((uint64_t)archive_be32dec(p) << 32) | archive_be32dec(p + 4));-}--static inline uint16_t-archive_le16dec(const void *pp)-{- unsigned char const *p = (unsigned char const *)pp;-- /* Store into unsigned temporaries before left shifting, to avoid- promotion to signed int and then left shifting into the sign bit,- which is undefined behaviour. */- unsigned int p1 = p[1];- unsigned int p0 = p[0];-- return ((p1 << 8) | p0);-}--static inline uint32_t-archive_le32dec(const void *pp)-{- unsigned char const *p = (unsigned char const *)pp;-- /* Store into unsigned temporaries before left shifting, to avoid- promotion to signed int and then left shifting into the sign bit,- which is undefined behaviour. */- unsigned int p3 = p[3];- unsigned int p2 = p[2];- unsigned int p1 = p[1];- unsigned int p0 = p[0];-- return ((p3 << 24) | (p2 << 16) | (p1 << 8) | p0);-}--static inline uint64_t-archive_le64dec(const void *pp)-{- unsigned char const *p = (unsigned char const *)pp;-- return (((uint64_t)archive_le32dec(p + 4) << 32) | archive_le32dec(p));-}--static inline void-archive_be16enc(void *pp, uint16_t u)-{- unsigned char *p = (unsigned char *)pp;-- p[0] = (u >> 8) & 0xff;- p[1] = u & 0xff;-}--static inline void-archive_be32enc(void *pp, uint32_t u)-{- unsigned char *p = (unsigned char *)pp;-- p[0] = (u >> 24) & 0xff;- p[1] = (u >> 16) & 0xff;- p[2] = (u >> 8) & 0xff;- p[3] = u & 0xff;-}--static inline void-archive_be64enc(void *pp, uint64_t u)-{- unsigned char *p = (unsigned char *)pp;-- archive_be32enc(p, (uint32_t)(u >> 32));- archive_be32enc(p + 4, (uint32_t)(u & 0xffffffff));-}--static inline void-archive_le16enc(void *pp, uint16_t u)-{- unsigned char *p = (unsigned char *)pp;-- p[0] = u & 0xff;- p[1] = (u >> 8) & 0xff;-}--static inline void-archive_le32enc(void *pp, uint32_t u)-{- unsigned char *p = (unsigned char *)pp;-- p[0] = u & 0xff;- p[1] = (u >> 8) & 0xff;- p[2] = (u >> 16) & 0xff;- p[3] = (u >> 24) & 0xff;-}--static inline void-archive_le64enc(void *pp, uint64_t u)-{- unsigned char *p = (unsigned char *)pp;-- archive_le32enc(p, (uint32_t)(u & 0xffffffff));- archive_le32enc(p + 4, (uint32_t)(u >> 32));-}--#endif
− c/archive_entry.c
@@ -1,2149 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2016 Martin Matuska- * 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_entry.c 201096 2009-12-28 02:41:27Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#if MAJOR_IN_MKDEV-#include <sys/mkdev.h>-#define HAVE_MAJOR-#elif MAJOR_IN_SYSMACROS-#include <sys/sysmacros.h>-#define HAVE_MAJOR-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_LINUX_FS_H-#include <linux/fs.h> /* for Linux file flags */-#endif-/*- * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.- * As the include guards don't agree, the order of include is important.- */-#ifdef HAVE_LINUX_EXT2_FS_H-#include <linux/ext2_fs.h> /* for Linux file flags */-#endif-#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)-#include <ext2fs/ext2_fs.h> /* for Linux file flags */-#endif-#include <stddef.h>-#include <stdio.h>-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_WCHAR_H-#include <wchar.h>-#endif--#include "archive.h"-#include "archive_acl_private.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_entry_private.h"--#if !defined(HAVE_MAJOR) && !defined(major)-/* Replacement for major/minor/makedev. */-#define major(x) ((int)(0x00ff & ((x) >> 8)))-#define minor(x) ((int)(0xffff00ff & (x)))-#define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min)))-#endif--/* Play games to come up with a suitable makedev() definition. */-#ifdef __QNXNTO__-/* QNX. <sigh> */-#include <sys/netmgr.h>-#define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min))-#elif defined makedev-/* There's a "makedev" macro. */-#define ae_makedev(maj, min) makedev((maj), (min))-#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__))-/* Windows. <sigh> */-#define ae_makedev(maj, min) mkdev((maj), (min))-#else-/* There's a "makedev" function. */-#define ae_makedev(maj, min) makedev((maj), (min))-#endif--/*- * This adjustment is needed to support the following idiom for adding- * 1000ns to the stored time:- * archive_entry_set_atime(archive_entry_atime(),- * archive_entry_atime_nsec() + 1000)- * The additional if() here compensates for ambiguity in the C standard,- * which permits two possible interpretations of a % b when a is negative.- */-#define FIX_NS(t,ns) \- do { \- t += ns / 1000000000; \- ns %= 1000000000; \- if (ns < 0) { --t; ns += 1000000000; } \- } while (0)--static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear);-static const wchar_t *ae_wcstofflags(const wchar_t *stringp,- unsigned long *setp, unsigned long *clrp);-static const char *ae_strtofflags(const char *stringp,- unsigned long *setp, unsigned long *clrp);--#ifndef HAVE_WCSCPY-static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)-{- wchar_t *dest = s1;- while ((*s1 = *s2) != L'\0')- ++s1, ++s2;- return dest;-}-#endif-#ifndef HAVE_WCSLEN-static size_t wcslen(const wchar_t *s)-{- const wchar_t *p = s;- while (*p != L'\0')- ++p;- return p - s;-}-#endif-#ifndef HAVE_WMEMCMP-/* Good enough for simple equality testing, but not for sorting. */-#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t))-#endif--/****************************************************************************- *- * Public Interface- *- ****************************************************************************/--struct archive_entry *-archive_entry_clear(struct archive_entry *entry)-{- if (entry == NULL)- return (NULL);- archive_mstring_clean(&entry->ae_fflags_text);- archive_mstring_clean(&entry->ae_gname);- archive_mstring_clean(&entry->ae_hardlink);- archive_mstring_clean(&entry->ae_pathname);- archive_mstring_clean(&entry->ae_sourcepath);- archive_mstring_clean(&entry->ae_symlink);- archive_mstring_clean(&entry->ae_uname);- archive_entry_copy_mac_metadata(entry, NULL, 0);- archive_acl_clear(&entry->acl);- archive_entry_xattr_clear(entry);- archive_entry_sparse_clear(entry);- free(entry->stat);- entry->ae_symlink_type = AE_SYMLINK_TYPE_UNDEFINED;- memset(entry, 0, sizeof(*entry));- return entry;-}--struct archive_entry *-archive_entry_clone(struct archive_entry *entry)-{- struct archive_entry *entry2;- struct ae_xattr *xp;- struct ae_sparse *sp;- size_t s;- const void *p;-- /* Allocate new structure and copy over all of the fields. */- /* TODO: Should we copy the archive over? Or require a new archive- * as an argument? */- entry2 = archive_entry_new2(entry->archive);- if (entry2 == NULL)- return (NULL);- entry2->ae_stat = entry->ae_stat;- entry2->ae_fflags_set = entry->ae_fflags_set;- entry2->ae_fflags_clear = entry->ae_fflags_clear;-- /* TODO: XXX If clone can have a different archive, what do we do here if- * character sets are different? XXX */- archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);- archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname);- archive_mstring_copy(&entry2->ae_hardlink, &entry->ae_hardlink);- archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname);- archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath);- archive_mstring_copy(&entry2->ae_symlink, &entry->ae_symlink);- entry2->ae_set = entry->ae_set;- archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname);-- /* Copy symlink type */- entry2->ae_symlink_type = entry->ae_symlink_type;-- /* Copy encryption status */- entry2->encryption = entry->encryption;-- /* Copy digests */-#define copy_digest(_e2, _e, _t) \- memcpy(_e2->digest._t, _e->digest._t, sizeof(_e2->digest._t))-- copy_digest(entry2, entry, md5);- copy_digest(entry2, entry, rmd160);- copy_digest(entry2, entry, sha1);- copy_digest(entry2, entry, sha256);- copy_digest(entry2, entry, sha384);- copy_digest(entry2, entry, sha512);--#undef copy_digest- - /* Copy ACL data over. */- archive_acl_copy(&entry2->acl, &entry->acl);-- /* Copy Mac OS metadata. */- p = archive_entry_mac_metadata(entry, &s);- archive_entry_copy_mac_metadata(entry2, p, s);-- /* Copy xattr data over. */- xp = entry->xattr_head;- while (xp != NULL) {- archive_entry_xattr_add_entry(entry2,- xp->name, xp->value, xp->size);- xp = xp->next;- }-- /* Copy sparse data over. */- sp = entry->sparse_head;- while (sp != NULL) {- archive_entry_sparse_add_entry(entry2,- sp->offset, sp->length);- sp = sp->next;- }-- return (entry2);-}--void-archive_entry_free(struct archive_entry *entry)-{- archive_entry_clear(entry);- free(entry);-}--struct archive_entry *-archive_entry_new(void)-{- return archive_entry_new2(NULL);-}--struct archive_entry *-archive_entry_new2(struct archive *a)-{- struct archive_entry *entry;-- entry = (struct archive_entry *)calloc(1, sizeof(*entry));- if (entry == NULL)- return (NULL);- entry->archive = a;- entry->ae_symlink_type = AE_SYMLINK_TYPE_UNDEFINED;- return (entry);-}--/*- * Functions for reading fields from an archive_entry.- */--time_t-archive_entry_atime(struct archive_entry *entry)-{- return (entry->ae_stat.aest_atime);-}--long-archive_entry_atime_nsec(struct archive_entry *entry)-{- return (entry->ae_stat.aest_atime_nsec);-}--int-archive_entry_atime_is_set(struct archive_entry *entry)-{- return (entry->ae_set & AE_SET_ATIME);-}--time_t-archive_entry_birthtime(struct archive_entry *entry)-{- return (entry->ae_stat.aest_birthtime);-}--long-archive_entry_birthtime_nsec(struct archive_entry *entry)-{- return (entry->ae_stat.aest_birthtime_nsec);-}--int-archive_entry_birthtime_is_set(struct archive_entry *entry)-{- return (entry->ae_set & AE_SET_BIRTHTIME);-}--time_t-archive_entry_ctime(struct archive_entry *entry)-{- return (entry->ae_stat.aest_ctime);-}--int-archive_entry_ctime_is_set(struct archive_entry *entry)-{- return (entry->ae_set & AE_SET_CTIME);-}--long-archive_entry_ctime_nsec(struct archive_entry *entry)-{- return (entry->ae_stat.aest_ctime_nsec);-}--dev_t-archive_entry_dev(struct archive_entry *entry)-{- if (entry->ae_stat.aest_dev_is_broken_down)- return ae_makedev(entry->ae_stat.aest_devmajor,- entry->ae_stat.aest_devminor);- else- return (entry->ae_stat.aest_dev);-}--int-archive_entry_dev_is_set(struct archive_entry *entry)-{- return (entry->ae_set & AE_SET_DEV);-}--dev_t-archive_entry_devmajor(struct archive_entry *entry)-{- if (entry->ae_stat.aest_dev_is_broken_down)- return (entry->ae_stat.aest_devmajor);- else- return major(entry->ae_stat.aest_dev);-}--dev_t-archive_entry_devminor(struct archive_entry *entry)-{- if (entry->ae_stat.aest_dev_is_broken_down)- return (entry->ae_stat.aest_devminor);- else- return minor(entry->ae_stat.aest_dev);-}--__LA_MODE_T-archive_entry_filetype(struct archive_entry *entry)-{- return (AE_IFMT & entry->acl.mode);-}--void-archive_entry_fflags(struct archive_entry *entry,- unsigned long *set, unsigned long *clear)-{- *set = entry->ae_fflags_set;- *clear = entry->ae_fflags_clear;-}--/*- * Note: if text was provided, this just returns that text. If you- * really need the text to be rebuilt in a canonical form, set the- * text, ask for the bitmaps, then set the bitmaps. (Setting the- * bitmaps clears any stored text.) This design is deliberate: if- * we're editing archives, we don't want to discard flags just because- * they aren't supported on the current system. The bitmap<->text- * conversions are platform-specific (see below).- */-const char *-archive_entry_fflags_text(struct archive_entry *entry)-{- const char *f;- char *p;-- if (archive_mstring_get_mbs(entry->archive,- &entry->ae_fflags_text, &f) == 0) {- if (f != NULL)- return (f);- } else if (errno == ENOMEM)- __archive_errx(1, "No memory");-- if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0)- return (NULL);-- p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear);- if (p == NULL)- return (NULL);-- archive_mstring_copy_mbs(&entry->ae_fflags_text, p);- free(p);- if (archive_mstring_get_mbs(entry->archive,- &entry->ae_fflags_text, &f) == 0)- return (f);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--la_int64_t-archive_entry_gid(struct archive_entry *entry)-{- return (entry->ae_stat.aest_gid);-}--const char *-archive_entry_gname(struct archive_entry *entry)-{- const char *p;- if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--const char *-archive_entry_gname_utf8(struct archive_entry *entry)-{- const char *p;- if (archive_mstring_get_utf8(entry->archive, &entry->ae_gname, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}---const wchar_t *-archive_entry_gname_w(struct archive_entry *entry)-{- const wchar_t *p;- if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--int-_archive_entry_gname_l(struct archive_entry *entry,- const char **p, size_t *len, struct archive_string_conv *sc)-{- return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_gname, p, len, sc));-}--const char *-archive_entry_hardlink(struct archive_entry *entry)-{- const char *p;- if ((entry->ae_set & AE_SET_HARDLINK) == 0)- return (NULL);- if (archive_mstring_get_mbs(- entry->archive, &entry->ae_hardlink, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--const char *-archive_entry_hardlink_utf8(struct archive_entry *entry)-{- const char *p;- if ((entry->ae_set & AE_SET_HARDLINK) == 0)- return (NULL);- if (archive_mstring_get_utf8(- entry->archive, &entry->ae_hardlink, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--const wchar_t *-archive_entry_hardlink_w(struct archive_entry *entry)-{- const wchar_t *p;- if ((entry->ae_set & AE_SET_HARDLINK) == 0)- return (NULL);- if (archive_mstring_get_wcs(- entry->archive, &entry->ae_hardlink, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--int-_archive_entry_hardlink_l(struct archive_entry *entry,- const char **p, size_t *len, struct archive_string_conv *sc)-{- if ((entry->ae_set & AE_SET_HARDLINK) == 0) {- *p = NULL;- *len = 0;- return (0);- }- return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_hardlink, p, len, sc));-}--la_int64_t-archive_entry_ino(struct archive_entry *entry)-{- return (entry->ae_stat.aest_ino);-}--int-archive_entry_ino_is_set(struct archive_entry *entry)-{- return (entry->ae_set & AE_SET_INO);-}--la_int64_t-archive_entry_ino64(struct archive_entry *entry)-{- return (entry->ae_stat.aest_ino);-}--__LA_MODE_T-archive_entry_mode(struct archive_entry *entry)-{- return (entry->acl.mode);-}--time_t-archive_entry_mtime(struct archive_entry *entry)-{- return (entry->ae_stat.aest_mtime);-}--long-archive_entry_mtime_nsec(struct archive_entry *entry)-{- return (entry->ae_stat.aest_mtime_nsec);-}--int-archive_entry_mtime_is_set(struct archive_entry *entry)-{- return (entry->ae_set & AE_SET_MTIME);-}--unsigned int-archive_entry_nlink(struct archive_entry *entry)-{- return (entry->ae_stat.aest_nlink);-}--/* Instead, our caller could have chosen a specific encoding- * (archive_mstring_get_mbs, archive_mstring_get_utf8,- * archive_mstring_get_wcs). So we should try multiple- * encodings. Try mbs first because of history, even though- * utf8 might be better for pathname portability.- * Also omit wcs because of type mismatch (char * versus wchar *)- */-const char *-archive_entry_pathname(struct archive_entry *entry)-{- const char *p;- if (archive_mstring_get_mbs(- entry->archive, &entry->ae_pathname, &p) == 0)- return (p);-#if HAVE_EILSEQ /*{*/- if (errno == EILSEQ) {- if (archive_mstring_get_utf8(- entry->archive, &entry->ae_pathname, &p) == 0)- return (p);- }-#endif /*}*/- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--const char *-archive_entry_pathname_utf8(struct archive_entry *entry)-{- const char *p;- if (archive_mstring_get_utf8(- entry->archive, &entry->ae_pathname, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--const wchar_t *-archive_entry_pathname_w(struct archive_entry *entry)-{- const wchar_t *p;- if (archive_mstring_get_wcs(- entry->archive, &entry->ae_pathname, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--int-_archive_entry_pathname_l(struct archive_entry *entry,- const char **p, size_t *len, struct archive_string_conv *sc)-{- return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_pathname, p, len, sc));-}--__LA_MODE_T-archive_entry_perm(struct archive_entry *entry)-{- return (~AE_IFMT & entry->acl.mode);-}--dev_t-archive_entry_rdev(struct archive_entry *entry)-{- if (entry->ae_stat.aest_rdev_is_broken_down)- return ae_makedev(entry->ae_stat.aest_rdevmajor,- entry->ae_stat.aest_rdevminor);- else- return (entry->ae_stat.aest_rdev);-}--dev_t-archive_entry_rdevmajor(struct archive_entry *entry)-{- if (entry->ae_stat.aest_rdev_is_broken_down)- return (entry->ae_stat.aest_rdevmajor);- else- return major(entry->ae_stat.aest_rdev);-}--dev_t-archive_entry_rdevminor(struct archive_entry *entry)-{- if (entry->ae_stat.aest_rdev_is_broken_down)- return (entry->ae_stat.aest_rdevminor);- else- return minor(entry->ae_stat.aest_rdev);-}--la_int64_t-archive_entry_size(struct archive_entry *entry)-{- return (entry->ae_stat.aest_size);-}--int-archive_entry_size_is_set(struct archive_entry *entry)-{- return (entry->ae_set & AE_SET_SIZE);-}--const char *-archive_entry_sourcepath(struct archive_entry *entry)-{- const char *p;- if (archive_mstring_get_mbs(- entry->archive, &entry->ae_sourcepath, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--const wchar_t *-archive_entry_sourcepath_w(struct archive_entry *entry)-{- const wchar_t *p;- if (archive_mstring_get_wcs(- entry->archive, &entry->ae_sourcepath, &p) == 0)- return (p);- return (NULL);-}--const char *-archive_entry_symlink(struct archive_entry *entry)-{- const char *p;- if ((entry->ae_set & AE_SET_SYMLINK) == 0)- return (NULL);- if (archive_mstring_get_mbs(- entry->archive, &entry->ae_symlink, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--int-archive_entry_symlink_type(struct archive_entry *entry)-{- return (entry->ae_symlink_type);-}--const char *-archive_entry_symlink_utf8(struct archive_entry *entry)-{- const char *p;- if ((entry->ae_set & AE_SET_SYMLINK) == 0)- return (NULL);- if (archive_mstring_get_utf8(- entry->archive, &entry->ae_symlink, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--const wchar_t *-archive_entry_symlink_w(struct archive_entry *entry)-{- const wchar_t *p;- if ((entry->ae_set & AE_SET_SYMLINK) == 0)- return (NULL);- if (archive_mstring_get_wcs(- entry->archive, &entry->ae_symlink, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--int-_archive_entry_symlink_l(struct archive_entry *entry,- const char **p, size_t *len, struct archive_string_conv *sc)-{- if ((entry->ae_set & AE_SET_SYMLINK) == 0) {- *p = NULL;- *len = 0;- return (0);- }- return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_symlink, p, len, sc));-}--la_int64_t-archive_entry_uid(struct archive_entry *entry)-{- return (entry->ae_stat.aest_uid);-}--const char *-archive_entry_uname(struct archive_entry *entry)-{- const char *p;- if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--const char *-archive_entry_uname_utf8(struct archive_entry *entry)-{- const char *p;- if (archive_mstring_get_utf8(entry->archive, &entry->ae_uname, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--const wchar_t *-archive_entry_uname_w(struct archive_entry *entry)-{- const wchar_t *p;- if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)- return (p);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (NULL);-}--int-_archive_entry_uname_l(struct archive_entry *entry,- const char **p, size_t *len, struct archive_string_conv *sc)-{- return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_uname, p, len, sc));-}--int-archive_entry_is_data_encrypted(struct archive_entry *entry)-{- return ((entry->encryption & AE_ENCRYPTION_DATA) == AE_ENCRYPTION_DATA);-}--int-archive_entry_is_metadata_encrypted(struct archive_entry *entry)-{- return ((entry->encryption & AE_ENCRYPTION_METADATA) == AE_ENCRYPTION_METADATA);-}--int-archive_entry_is_encrypted(struct archive_entry *entry)-{- return (entry->encryption & (AE_ENCRYPTION_DATA|AE_ENCRYPTION_METADATA));-}--/*- * Functions to set archive_entry properties.- */--void-archive_entry_set_filetype(struct archive_entry *entry, unsigned int type)-{- entry->stat_valid = 0;- entry->acl.mode &= ~AE_IFMT;- entry->acl.mode |= AE_IFMT & type;-}--void-archive_entry_set_fflags(struct archive_entry *entry,- unsigned long set, unsigned long clear)-{- archive_mstring_clean(&entry->ae_fflags_text);- entry->ae_fflags_set = set;- entry->ae_fflags_clear = clear;-}--const char *-archive_entry_copy_fflags_text(struct archive_entry *entry,- const char *flags)-{- archive_mstring_copy_mbs(&entry->ae_fflags_text, flags);- return (ae_strtofflags(flags,- &entry->ae_fflags_set, &entry->ae_fflags_clear));-}--const wchar_t *-archive_entry_copy_fflags_text_w(struct archive_entry *entry,- const wchar_t *flags)-{- archive_mstring_copy_wcs(&entry->ae_fflags_text, flags);- return (ae_wcstofflags(flags,- &entry->ae_fflags_set, &entry->ae_fflags_clear));-}--void-archive_entry_set_gid(struct archive_entry *entry, la_int64_t g)-{- entry->stat_valid = 0;- entry->ae_stat.aest_gid = g;-}--void-archive_entry_set_gname(struct archive_entry *entry, const char *name)-{- archive_mstring_copy_mbs(&entry->ae_gname, name);-}--void-archive_entry_set_gname_utf8(struct archive_entry *entry, const char *name)-{- archive_mstring_copy_utf8(&entry->ae_gname, name);-}--void-archive_entry_copy_gname(struct archive_entry *entry, const char *name)-{- archive_mstring_copy_mbs(&entry->ae_gname, name);-}--void-archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)-{- archive_mstring_copy_wcs(&entry->ae_gname, name);-}--int-archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)-{- if (archive_mstring_update_utf8(entry->archive,- &entry->ae_gname, name) == 0)- return (1);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (0);-}--int-_archive_entry_copy_gname_l(struct archive_entry *entry,- const char *name, size_t len, struct archive_string_conv *sc)-{- return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc));-}--void-archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino)-{- entry->stat_valid = 0;- entry->ae_set |= AE_SET_INO;- entry->ae_stat.aest_ino = ino;-}--void-archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino)-{- entry->stat_valid = 0;- entry->ae_set |= AE_SET_INO;- entry->ae_stat.aest_ino = ino;-}--void-archive_entry_set_hardlink(struct archive_entry *entry, const char *target)-{- archive_mstring_copy_mbs(&entry->ae_hardlink, target);- if (target != NULL)- entry->ae_set |= AE_SET_HARDLINK;- else- entry->ae_set &= ~AE_SET_HARDLINK;-}--void-archive_entry_set_hardlink_utf8(struct archive_entry *entry, const char *target)-{- archive_mstring_copy_utf8(&entry->ae_hardlink, target);- if (target != NULL)- entry->ae_set |= AE_SET_HARDLINK;- else- entry->ae_set &= ~AE_SET_HARDLINK;-}--void-archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)-{- archive_mstring_copy_mbs(&entry->ae_hardlink, target);- if (target != NULL)- entry->ae_set |= AE_SET_HARDLINK;- else- entry->ae_set &= ~AE_SET_HARDLINK;-}--void-archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)-{- archive_mstring_copy_wcs(&entry->ae_hardlink, target);- if (target != NULL)- entry->ae_set |= AE_SET_HARDLINK;- else- entry->ae_set &= ~AE_SET_HARDLINK;-}--int-archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target)-{- if (target != NULL)- entry->ae_set |= AE_SET_HARDLINK;- else- entry->ae_set &= ~AE_SET_HARDLINK;- if (archive_mstring_update_utf8(entry->archive,- &entry->ae_hardlink, target) == 0)- return (1);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (0);-}--int-_archive_entry_copy_hardlink_l(struct archive_entry *entry,- const char *target, size_t len, struct archive_string_conv *sc)-{- int r;-- r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,- target, len, sc);- if (target != NULL && r == 0)- entry->ae_set |= AE_SET_HARDLINK;- else- entry->ae_set &= ~AE_SET_HARDLINK;- return (r);-}--void-archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)-{- FIX_NS(t, ns);- entry->stat_valid = 0;- entry->ae_set |= AE_SET_ATIME;- entry->ae_stat.aest_atime = t;- entry->ae_stat.aest_atime_nsec = ns;-}--void-archive_entry_unset_atime(struct archive_entry *entry)-{- archive_entry_set_atime(entry, 0, 0);- entry->ae_set &= ~AE_SET_ATIME;-}--void-archive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns)-{- FIX_NS(t, ns);- entry->stat_valid = 0;- entry->ae_set |= AE_SET_BIRTHTIME;- entry->ae_stat.aest_birthtime = t;- entry->ae_stat.aest_birthtime_nsec = ns;-}--void-archive_entry_unset_birthtime(struct archive_entry *entry)-{- archive_entry_set_birthtime(entry, 0, 0);- entry->ae_set &= ~AE_SET_BIRTHTIME;-}--void-archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)-{- FIX_NS(t, ns);- entry->stat_valid = 0;- entry->ae_set |= AE_SET_CTIME;- entry->ae_stat.aest_ctime = t;- entry->ae_stat.aest_ctime_nsec = ns;-}--void-archive_entry_unset_ctime(struct archive_entry *entry)-{- archive_entry_set_ctime(entry, 0, 0);- entry->ae_set &= ~AE_SET_CTIME;-}--void-archive_entry_set_dev(struct archive_entry *entry, dev_t d)-{- entry->stat_valid = 0;- entry->ae_set |= AE_SET_DEV;- entry->ae_stat.aest_dev_is_broken_down = 0;- entry->ae_stat.aest_dev = d;-}--void-archive_entry_set_devmajor(struct archive_entry *entry, dev_t m)-{- entry->stat_valid = 0;- entry->ae_set |= AE_SET_DEV;- entry->ae_stat.aest_dev_is_broken_down = 1;- entry->ae_stat.aest_devmajor = m;-}--void-archive_entry_set_devminor(struct archive_entry *entry, dev_t m)-{- entry->stat_valid = 0;- entry->ae_set |= AE_SET_DEV;- entry->ae_stat.aest_dev_is_broken_down = 1;- entry->ae_stat.aest_devminor = m;-}--/* Set symlink if symlink is already set, else set hardlink. */-void-archive_entry_set_link(struct archive_entry *entry, const char *target)-{- if (entry->ae_set & AE_SET_SYMLINK)- archive_mstring_copy_mbs(&entry->ae_symlink, target);- else- archive_mstring_copy_mbs(&entry->ae_hardlink, target);-}--void-archive_entry_set_link_utf8(struct archive_entry *entry, const char *target)-{- if (entry->ae_set & AE_SET_SYMLINK)- archive_mstring_copy_utf8(&entry->ae_symlink, target);- else- archive_mstring_copy_utf8(&entry->ae_hardlink, target);-}--/* Set symlink if symlink is already set, else set hardlink. */-void-archive_entry_copy_link(struct archive_entry *entry, const char *target)-{- if (entry->ae_set & AE_SET_SYMLINK)- archive_mstring_copy_mbs(&entry->ae_symlink, target);- else- archive_mstring_copy_mbs(&entry->ae_hardlink, target);-}--/* Set symlink if symlink is already set, else set hardlink. */-void-archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target)-{- if (entry->ae_set & AE_SET_SYMLINK)- archive_mstring_copy_wcs(&entry->ae_symlink, target);- else- archive_mstring_copy_wcs(&entry->ae_hardlink, target);-}--int-archive_entry_update_link_utf8(struct archive_entry *entry, const char *target)-{- int r;- if (entry->ae_set & AE_SET_SYMLINK)- r = archive_mstring_update_utf8(entry->archive,- &entry->ae_symlink, target);- else- r = archive_mstring_update_utf8(entry->archive,- &entry->ae_hardlink, target);- if (r == 0)- return (1);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (0);-}--int-_archive_entry_copy_link_l(struct archive_entry *entry,- const char *target, size_t len, struct archive_string_conv *sc)-{- int r;-- if (entry->ae_set & AE_SET_SYMLINK)- r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,- target, len, sc);- else- r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,- target, len, sc);- return (r);-}--void-archive_entry_set_mode(struct archive_entry *entry, mode_t m)-{- entry->stat_valid = 0;- entry->acl.mode = m;-}--void-archive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns)-{- FIX_NS(t, ns);- entry->stat_valid = 0;- entry->ae_set |= AE_SET_MTIME;- entry->ae_stat.aest_mtime = t;- entry->ae_stat.aest_mtime_nsec = ns;-}--void-archive_entry_unset_mtime(struct archive_entry *entry)-{- archive_entry_set_mtime(entry, 0, 0);- entry->ae_set &= ~AE_SET_MTIME;-}--void-archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink)-{- entry->stat_valid = 0;- entry->ae_stat.aest_nlink = nlink;-}--void-archive_entry_set_pathname(struct archive_entry *entry, const char *name)-{- archive_mstring_copy_mbs(&entry->ae_pathname, name);-}--void-archive_entry_set_pathname_utf8(struct archive_entry *entry, const char *name)-{- archive_mstring_copy_utf8(&entry->ae_pathname, name);-}--void-archive_entry_copy_pathname(struct archive_entry *entry, const char *name)-{- archive_mstring_copy_mbs(&entry->ae_pathname, name);-}--void-archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)-{- archive_mstring_copy_wcs(&entry->ae_pathname, name);-}--int-archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name)-{- if (archive_mstring_update_utf8(entry->archive,- &entry->ae_pathname, name) == 0)- return (1);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (0);-}--int-_archive_entry_copy_pathname_l(struct archive_entry *entry,- const char *name, size_t len, struct archive_string_conv *sc)-{- return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname,- name, len, sc));-}--void-archive_entry_set_perm(struct archive_entry *entry, mode_t p)-{- entry->stat_valid = 0;- entry->acl.mode &= AE_IFMT;- entry->acl.mode |= ~AE_IFMT & p;-}--void-archive_entry_set_rdev(struct archive_entry *entry, dev_t m)-{- entry->stat_valid = 0;- entry->ae_stat.aest_rdev = m;- entry->ae_stat.aest_rdev_is_broken_down = 0;-}--void-archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)-{- entry->stat_valid = 0;- entry->ae_stat.aest_rdev_is_broken_down = 1;- entry->ae_stat.aest_rdevmajor = m;-}--void-archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)-{- entry->stat_valid = 0;- entry->ae_stat.aest_rdev_is_broken_down = 1;- entry->ae_stat.aest_rdevminor = m;-}--void-archive_entry_set_size(struct archive_entry *entry, la_int64_t s)-{- entry->stat_valid = 0;- entry->ae_stat.aest_size = s;- entry->ae_set |= AE_SET_SIZE;-}--void-archive_entry_unset_size(struct archive_entry *entry)-{- archive_entry_set_size(entry, 0);- entry->ae_set &= ~AE_SET_SIZE;-}--void-archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path)-{- archive_mstring_copy_mbs(&entry->ae_sourcepath, path);-}--void-archive_entry_copy_sourcepath_w(struct archive_entry *entry, const wchar_t *path)-{- archive_mstring_copy_wcs(&entry->ae_sourcepath, path);-}--void-archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)-{- archive_mstring_copy_mbs(&entry->ae_symlink, linkname);- if (linkname != NULL)- entry->ae_set |= AE_SET_SYMLINK;- else- entry->ae_set &= ~AE_SET_SYMLINK;-}--void-archive_entry_set_symlink_type(struct archive_entry *entry, int type)-{- entry->ae_symlink_type = type;-}--void-archive_entry_set_symlink_utf8(struct archive_entry *entry, const char *linkname)-{- archive_mstring_copy_utf8(&entry->ae_symlink, linkname);- if (linkname != NULL)- entry->ae_set |= AE_SET_SYMLINK;- else- entry->ae_set &= ~AE_SET_SYMLINK;-}--void-archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)-{- archive_mstring_copy_mbs(&entry->ae_symlink, linkname);- if (linkname != NULL)- entry->ae_set |= AE_SET_SYMLINK;- else- entry->ae_set &= ~AE_SET_SYMLINK;-}--void-archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)-{- archive_mstring_copy_wcs(&entry->ae_symlink, linkname);- if (linkname != NULL)- entry->ae_set |= AE_SET_SYMLINK;- else- entry->ae_set &= ~AE_SET_SYMLINK;-}--int-archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname)-{- if (linkname != NULL)- entry->ae_set |= AE_SET_SYMLINK;- else- entry->ae_set &= ~AE_SET_SYMLINK;- if (archive_mstring_update_utf8(entry->archive,- &entry->ae_symlink, linkname) == 0)- return (1);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (0);-}--int-_archive_entry_copy_symlink_l(struct archive_entry *entry,- const char *linkname, size_t len, struct archive_string_conv *sc)-{- int r;-- r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,- linkname, len, sc);- if (linkname != NULL && r == 0)- entry->ae_set |= AE_SET_SYMLINK;- else- entry->ae_set &= ~AE_SET_SYMLINK;- return (r);-}--void-archive_entry_set_uid(struct archive_entry *entry, la_int64_t u)-{- entry->stat_valid = 0;- entry->ae_stat.aest_uid = u;-}--void-archive_entry_set_uname(struct archive_entry *entry, const char *name)-{- archive_mstring_copy_mbs(&entry->ae_uname, name);-}--void-archive_entry_set_uname_utf8(struct archive_entry *entry, const char *name)-{- archive_mstring_copy_utf8(&entry->ae_uname, name);-}--void-archive_entry_copy_uname(struct archive_entry *entry, const char *name)-{- archive_mstring_copy_mbs(&entry->ae_uname, name);-}--void-archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)-{- archive_mstring_copy_wcs(&entry->ae_uname, name);-}--int-archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)-{- if (archive_mstring_update_utf8(entry->archive,- &entry->ae_uname, name) == 0)- return (1);- if (errno == ENOMEM)- __archive_errx(1, "No memory");- return (0);-}--void-archive_entry_set_is_data_encrypted(struct archive_entry *entry, char is_encrypted)-{- if (is_encrypted) {- entry->encryption |= AE_ENCRYPTION_DATA;- } else {- entry->encryption &= ~AE_ENCRYPTION_DATA;- }-}--void-archive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_encrypted)-{- if (is_encrypted) {- entry->encryption |= AE_ENCRYPTION_METADATA;- } else {- entry->encryption &= ~AE_ENCRYPTION_METADATA;- }-}--int-_archive_entry_copy_uname_l(struct archive_entry *entry,- const char *name, size_t len, struct archive_string_conv *sc)-{- return (archive_mstring_copy_mbs_len_l(&entry->ae_uname,- name, len, sc));-}--const void *-archive_entry_mac_metadata(struct archive_entry *entry, size_t *s)-{- *s = entry->mac_metadata_size;- return entry->mac_metadata;-}--void-archive_entry_copy_mac_metadata(struct archive_entry *entry,- const void *p, size_t s)-{- free(entry->mac_metadata);- if (p == NULL || s == 0) {- entry->mac_metadata = NULL;- entry->mac_metadata_size = 0;- } else {- entry->mac_metadata_size = s;- entry->mac_metadata = malloc(s);- if (entry->mac_metadata == NULL)- abort();- memcpy(entry->mac_metadata, p, s);- }-}--/* Digest handling */-const unsigned char *-archive_entry_digest(struct archive_entry *entry, int type)-{- switch (type) {- case ARCHIVE_ENTRY_DIGEST_MD5:- return entry->digest.md5;- case ARCHIVE_ENTRY_DIGEST_RMD160:- return entry->digest.rmd160;- case ARCHIVE_ENTRY_DIGEST_SHA1:- return entry->digest.sha1;- case ARCHIVE_ENTRY_DIGEST_SHA256:- return entry->digest.sha256;- case ARCHIVE_ENTRY_DIGEST_SHA384:- return entry->digest.sha384;- case ARCHIVE_ENTRY_DIGEST_SHA512:- return entry->digest.sha512;- default:- return NULL;- }-}--int-archive_entry_set_digest(struct archive_entry *entry, int type,- const unsigned char *digest)-{-#define copy_digest(_e, _t, _d)\- memcpy(_e->digest._t, _d, sizeof(_e->digest._t))-- switch (type) {- case ARCHIVE_ENTRY_DIGEST_MD5:- copy_digest(entry, md5, digest);- break;- case ARCHIVE_ENTRY_DIGEST_RMD160:- copy_digest(entry, rmd160, digest);- break;- case ARCHIVE_ENTRY_DIGEST_SHA1:- copy_digest(entry, sha1, digest);- break;- case ARCHIVE_ENTRY_DIGEST_SHA256:- copy_digest(entry, sha256, digest);- break;- case ARCHIVE_ENTRY_DIGEST_SHA384:- copy_digest(entry, sha384, digest);- break;- case ARCHIVE_ENTRY_DIGEST_SHA512:- copy_digest(entry, sha512, digest);- break;- default:- return ARCHIVE_WARN;- }-- return ARCHIVE_OK;-#undef copy_digest-}--/*- * ACL management. The following would, of course, be a lot simpler- * if: 1) the last draft of POSIX.1e were a really thorough and- * complete standard that addressed the needs of ACL archiving and 2)- * everyone followed it faithfully. Alas, neither is true, so the- * following is a lot more complex than might seem necessary to the- * uninitiated.- */--struct archive_acl *-archive_entry_acl(struct archive_entry *entry)-{- return &entry->acl;-}--void-archive_entry_acl_clear(struct archive_entry *entry)-{- archive_acl_clear(&entry->acl);-}--/*- * Add a single ACL entry to the internal list of ACL data.- */-int-archive_entry_acl_add_entry(struct archive_entry *entry,- int type, int permset, int tag, int id, const char *name)-{- return archive_acl_add_entry(&entry->acl, type, permset, tag, id, name);-}--/*- * As above, but with a wide-character name.- */-int-archive_entry_acl_add_entry_w(struct archive_entry *entry,- int type, int permset, int tag, int id, const wchar_t *name)-{- return archive_acl_add_entry_w_len(&entry->acl,- type, permset, tag, id, name, wcslen(name));-}--/*- * Return a bitmask of ACL types in an archive entry ACL list- */-int-archive_entry_acl_types(struct archive_entry *entry)-{- return (archive_acl_types(&entry->acl));-}--/*- * Return a count of entries matching "want_type".- */-int-archive_entry_acl_count(struct archive_entry *entry, int want_type)-{- return archive_acl_count(&entry->acl, want_type);-}--/*- * Prepare for reading entries from the ACL data. Returns a count- * of entries matching "want_type", or zero if there are no- * non-extended ACL entries of that type.- */-int-archive_entry_acl_reset(struct archive_entry *entry, int want_type)-{- return archive_acl_reset(&entry->acl, want_type);-}--/*- * Return the next ACL entry in the list. Fake entries for the- * standard permissions and include them in the returned list.- */-int-archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,- int *permset, int *tag, int *id, const char **name)-{- int r;- r = archive_acl_next(entry->archive, &entry->acl, want_type, type,- permset, tag, id, name);- if (r == ARCHIVE_FATAL && errno == ENOMEM)- __archive_errx(1, "No memory");- return (r);-}--/*- * Generate a text version of the ACL. The flags parameter controls- * the style of the generated ACL.- */-wchar_t *-archive_entry_acl_to_text_w(struct archive_entry *entry, la_ssize_t *len,- int flags)-{- return (archive_acl_to_text_w(&entry->acl, len, flags,- entry->archive));-}--char *-archive_entry_acl_to_text(struct archive_entry *entry, la_ssize_t *len,- int flags)-{- return (archive_acl_to_text_l(&entry->acl, len, flags, NULL));-}--char *-_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len,- int flags, struct archive_string_conv *sc)-{- return (archive_acl_to_text_l(&entry->acl, len, flags, sc));-}--/*- * ACL text parser.- */-int-archive_entry_acl_from_text_w(struct archive_entry *entry,- const wchar_t *wtext, int type)-{- return (archive_acl_from_text_w(&entry->acl, wtext, type));-}--int-archive_entry_acl_from_text(struct archive_entry *entry,- const char *text, int type)-{- return (archive_acl_from_text_l(&entry->acl, text, type, NULL));-}--int-_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text,- int type, struct archive_string_conv *sc)-{- return (archive_acl_from_text_l(&entry->acl, text, type, sc));-}--/* Deprecated */-static int-archive_entry_acl_text_compat(int *flags)-{- if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0)- return (1);-- /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */- if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0)- *flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID;-- /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */- if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)- *flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;-- *flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA;-- return (0);-}--/* Deprecated */-const wchar_t *-archive_entry_acl_text_w(struct archive_entry *entry, int flags)-{- free(entry->acl.acl_text_w);- entry->acl.acl_text_w = NULL;- if (archive_entry_acl_text_compat(&flags) == 0)- entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl,- NULL, flags, entry->archive);- return (entry->acl.acl_text_w);-}--/* Deprecated */-const char *-archive_entry_acl_text(struct archive_entry *entry, int flags)-{- free(entry->acl.acl_text);- entry->acl.acl_text = NULL;- if (archive_entry_acl_text_compat(&flags) == 0)- entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL,- flags, NULL);-- return (entry->acl.acl_text);-}--/* Deprecated */-int-_archive_entry_acl_text_l(struct archive_entry *entry, int flags,- const char **acl_text, size_t *len, struct archive_string_conv *sc)-{- free(entry->acl.acl_text);- entry->acl.acl_text = NULL;-- if (archive_entry_acl_text_compat(&flags) == 0)- entry->acl.acl_text = archive_acl_to_text_l(&entry->acl,- (ssize_t *)len, flags, sc);-- *acl_text = entry->acl.acl_text;-- return (0);-}--/*- * Following code is modified from UC Berkeley sources, and- * is subject to the following copyright notice.- */--/*-- * Copyright (c) 1993- * The Regents of the University of California. 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.- * 4. Neither the name of the University nor the names of its contributors- * may be used to endorse or promote products derived from this software- * without specific prior written permission.- *- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF- * SUCH DAMAGE.- */--/*- * Supported file flags on FreeBSD and Mac OS:- * sappnd,sappend SF_APPEND- * arch,archived SF_ARCHIVED- * schg,schange,simmutable SF_IMMUTABLE- * sunlnk,sunlink SF_NOUNLINK (FreeBSD only)- * uappnd,uappend UF_APPEND- * compressed UF_COMPRESSED (Mac OS only)- * hidden,uhidden UF_HIDDEN- * uchg,uchange,uimmutable UF_IMMUTABLE- * nodump UF_NODUMP- * uunlnk,uunlink UF_NOUNLINK (FreeBSD only)- * offline,uoffline UF_OFFLINE (FreeBSD only)- * opaque UF_OPAQUE- * rdonly,urdonly,readonly UF_READONLY (FreeBSD only)- * reparse,ureparse UF_REPARSE (FreeBSD only)- * sparse,usparse UF_SPARSE (FreeBSD only)- * system,usystem UF_SYSTEM (FreeBSD only)- *- * See chflags(2) for more information- *- * Supported file attributes on Linux:- * a append only FS_APPEND_FL sappnd- * A no atime updates FS_NOATIME_FL atime- * c compress FS_COMPR_FL compress- * C no copy on write FS_NOCOW_FL cow- * d no dump FS_NODUMP_FL dump- * D synchronous directory updates FS_DIRSYNC_FL dirsync- * i immutable FS_IMMUTABLE_FL schg- * j data journalling FS_JOURNAL_DATA_FL journal- * P project hierarchy FS_PROJINHERIT_FL projinherit- * s secure deletion FS_SECRM_FL securedeletion- * S synchronous updates FS_SYNC_FL sync- * t no tail-merging FS_NOTAIL_FL tail- * T top of directory hierarchy FS_TOPDIR_FL topdir- * u undeletable FS_UNRM_FL undel- *- * See ioctl_iflags(2) for more information- *- * Equivalent file flags supported on FreeBSD / Mac OS and Linux:- * SF_APPEND FS_APPEND_FL sappnd- * SF_IMMUTABLE FS_IMMUTABLE_FL schg- * UF_NODUMP FS_NODUMP_FL nodump- */--static const struct flag {- const char *name;- const wchar_t *wname;- unsigned long set;- unsigned long clear;-} fileflags[] = {- /* Preferred (shorter) names per flag first, all prefixed by "no" */-#ifdef SF_APPEND- { "nosappnd", L"nosappnd", SF_APPEND, 0},- { "nosappend", L"nosappend", SF_APPEND, 0},-#endif-#if defined(FS_APPEND_FL) /* 'a' */- { "nosappnd", L"nosappnd", FS_APPEND_FL, 0},- { "nosappend", L"nosappend", FS_APPEND_FL, 0},-#elif defined(EXT2_APPEND_FL) /* 'a' */- { "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0},- { "nosappend", L"nosappend", EXT2_APPEND_FL, 0},-#endif-#ifdef SF_ARCHIVED- { "noarch", L"noarch", SF_ARCHIVED, 0},- { "noarchived", L"noarchived", SF_ARCHIVED, 0},-#endif-#ifdef SF_IMMUTABLE- { "noschg", L"noschg", SF_IMMUTABLE, 0},- { "noschange", L"noschange", SF_IMMUTABLE, 0},- { "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0},-#endif-#if defined(FS_IMMUTABLE_FL) /* 'i' */- { "noschg", L"noschg", FS_IMMUTABLE_FL, 0},- { "noschange", L"noschange", FS_IMMUTABLE_FL, 0},- { "nosimmutable", L"nosimmutable", FS_IMMUTABLE_FL, 0},-#elif defined(EXT2_IMMUTABLE_FL) /* 'i' */- { "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0},- { "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0},- { "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0},-#endif-#ifdef SF_NOUNLINK- { "nosunlnk", L"nosunlnk", SF_NOUNLINK, 0},- { "nosunlink", L"nosunlink", SF_NOUNLINK, 0},-#endif-#ifdef UF_APPEND- { "nouappnd", L"nouappnd", UF_APPEND, 0},- { "nouappend", L"nouappend", UF_APPEND, 0},-#endif-#ifdef UF_IMMUTABLE- { "nouchg", L"nouchg", UF_IMMUTABLE, 0},- { "nouchange", L"nouchange", UF_IMMUTABLE, 0},- { "nouimmutable", L"nouimmutable", UF_IMMUTABLE, 0},-#endif-#ifdef UF_NODUMP- { "nodump", L"nodump", 0, UF_NODUMP},-#endif-#if defined(FS_NODUMP_FL) /* 'd' */- { "nodump", L"nodump", 0, FS_NODUMP_FL},-#elif defined(EXT2_NODUMP_FL)- { "nodump", L"nodump", 0, EXT2_NODUMP_FL},-#endif-#ifdef UF_OPAQUE- { "noopaque", L"noopaque", UF_OPAQUE, 0},-#endif-#ifdef UF_NOUNLINK- { "nouunlnk", L"nouunlnk", UF_NOUNLINK, 0},- { "nouunlink", L"nouunlink", UF_NOUNLINK, 0},-#endif-#ifdef UF_COMPRESSED- /* Mac OS */- { "nocompressed", L"nocompressed", UF_COMPRESSED, 0},-#endif-#ifdef UF_HIDDEN- { "nohidden", L"nohidden", UF_HIDDEN, 0},- { "nouhidden", L"nouhidden", UF_HIDDEN, 0},-#endif-#ifdef FILE_ATTRIBUTE_HIDDEN- { "nohidden", L"nohidden", FILE_ATTRIBUTE_HIDDEN, 0},- { "nouhidden", L"nouhidden", FILE_ATTRIBUTE_HIDDEN, 0},-#endif-#ifdef UF_OFFLINE- { "nooffline", L"nooffline", UF_OFFLINE, 0},- { "nouoffline", L"nouoffline", UF_OFFLINE, 0},-#endif-#ifdef UF_READONLY- { "nordonly", L"nordonly", UF_READONLY, 0},- { "nourdonly", L"nourdonly", UF_READONLY, 0},- { "noreadonly", L"noreadonly", UF_READONLY, 0},-#endif-#ifdef FILE_ATTRIBUTE_READONLY- { "nordonly", L"nordonly", FILE_ATTRIBUTE_READONLY, 0},- { "nourdonly", L"nourdonly", FILE_ATTRIBUTE_READONLY, 0},- { "noreadonly", L"noreadonly", FILE_ATTRIBUTE_READONLY, 0},-#endif-#ifdef UF_SPARSE- { "nosparse", L"nosparse", UF_SPARSE, 0},- { "nousparse", L"nousparse", UF_SPARSE, 0},-#endif-#ifdef UF_REPARSE- { "noreparse", L"noreparse", UF_REPARSE, 0},- { "noureparse", L"noureparse", UF_REPARSE, 0},-#endif-#ifdef UF_SYSTEM- { "nosystem", L"nosystem", UF_SYSTEM, 0},- { "nousystem", L"nousystem", UF_SYSTEM, 0},-#endif-#ifdef FILE_ATTRIBUTE_SYSTEM- { "nosystem", L"nosystem", FILE_ATTRIBUTE_SYSTEM, 0},- { "nousystem", L"nousystem", FILE_ATTRIBUTE_SYSTEM, 0},-#endif-#if defined(FS_UNRM_FL) /* 'u' */- { "noundel", L"noundel", FS_UNRM_FL, 0},-#elif defined(EXT2_UNRM_FL)- { "noundel", L"noundel", EXT2_UNRM_FL, 0},-#endif--#if defined(FS_COMPR_FL) /* 'c' */- { "nocompress", L"nocompress", FS_COMPR_FL, 0},-#elif defined(EXT2_COMPR_FL)- { "nocompress", L"nocompress", EXT2_COMPR_FL, 0},-#endif--#if defined(FS_NOATIME_FL) /* 'A' */- { "noatime", L"noatime", 0, FS_NOATIME_FL},-#elif defined(EXT2_NOATIME_FL)- { "noatime", L"noatime", 0, EXT2_NOATIME_FL},-#endif-#if defined(FS_DIRSYNC_FL) /* 'D' */- { "nodirsync", L"nodirsync", FS_DIRSYNC_FL, 0},-#elif defined(EXT2_DIRSYNC_FL)- { "nodirsync", L"nodirsync", EXT2_DIRSYNC_FL, 0},-#endif-#if defined(FS_JOURNAL_DATA_FL) /* 'j' */- { "nojournal-data",L"nojournal-data", FS_JOURNAL_DATA_FL, 0},- { "nojournal", L"nojournal", FS_JOURNAL_DATA_FL, 0},-#elif defined(EXT3_JOURNAL_DATA_FL)- { "nojournal-data",L"nojournal-data", EXT3_JOURNAL_DATA_FL, 0},- { "nojournal", L"nojournal", EXT3_JOURNAL_DATA_FL, 0},-#endif-#if defined(FS_SECRM_FL) /* 's' */- { "nosecdel", L"nosecdel", FS_SECRM_FL, 0},- { "nosecuredeletion",L"nosecuredeletion",FS_SECRM_FL, 0},-#elif defined(EXT2_SECRM_FL)- { "nosecdel", L"nosecdel", EXT2_SECRM_FL, 0},- { "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL, 0},-#endif-#if defined(FS_SYNC_FL) /* 'S' */- { "nosync", L"nosync", FS_SYNC_FL, 0},-#elif defined(EXT2_SYNC_FL)- { "nosync", L"nosync", EXT2_SYNC_FL, 0},-#endif-#if defined(FS_NOTAIL_FL) /* 't' */- { "notail", L"notail", 0, FS_NOTAIL_FL},-#elif defined(EXT2_NOTAIL_FL)- { "notail", L"notail", 0, EXT2_NOTAIL_FL},-#endif-#if defined(FS_TOPDIR_FL) /* 'T' */- { "notopdir", L"notopdir", FS_TOPDIR_FL, 0},-#elif defined(EXT2_TOPDIR_FL)- { "notopdir", L"notopdir", EXT2_TOPDIR_FL, 0},-#endif-#ifdef FS_NOCOW_FL /* 'C' */- { "nocow", L"nocow", 0, FS_NOCOW_FL},-#endif-#ifdef FS_PROJINHERIT_FL /* 'P' */- { "noprojinherit",L"noprojinherit", FS_PROJINHERIT_FL, 0},-#endif- { NULL, NULL, 0, 0}-};--/*- * fflagstostr --- * Convert file flags to a comma-separated string. If no flags- * are set, return the empty string.- */-static char *-ae_fflagstostr(unsigned long bitset, unsigned long bitclear)-{- char *string, *dp;- const char *sp;- unsigned long bits;- const struct flag *flag;- size_t length;-- bits = bitset | bitclear;- length = 0;- for (flag = fileflags; flag->name != NULL; flag++)- if (bits & (flag->set | flag->clear)) {- length += strlen(flag->name) + 1;- bits &= ~(flag->set | flag->clear);- }-- if (length == 0)- return (NULL);- string = (char *)malloc(length);- if (string == NULL)- return (NULL);-- dp = string;- for (flag = fileflags; flag->name != NULL; flag++) {- if (bitset & flag->set || bitclear & flag->clear) {- sp = flag->name + 2;- } else if (bitset & flag->clear || bitclear & flag->set) {- sp = flag->name;- } else- continue;- bitset &= ~(flag->set | flag->clear);- bitclear &= ~(flag->set | flag->clear);- if (dp > string)- *dp++ = ',';- while ((*dp++ = *sp++) != '\0')- ;- dp--;- }-- *dp = '\0';- return (string);-}--/*- * strtofflags --- * Take string of arguments and return file flags. This- * version works a little differently than strtofflags(3).- * In particular, it always tests every token, skipping any- * unrecognized tokens. It returns a pointer to the first- * unrecognized token, or NULL if every token was recognized.- * This version is also const-correct and does not modify the- * provided string.- */-static const char *-ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)-{- const char *start, *end;- const struct flag *flag;- unsigned long set, clear;- const char *failed;-- set = clear = 0;- start = s;- failed = NULL;- /* Find start of first token. */- while (*start == '\t' || *start == ' ' || *start == ',')- start++;- while (*start != '\0') {- size_t length;- /* Locate end of token. */- end = start;- while (*end != '\0' && *end != '\t' &&- *end != ' ' && *end != ',')- end++;- length = end - start;- for (flag = fileflags; flag->name != NULL; flag++) {- size_t flag_length = strlen(flag->name);- if (length == flag_length- && memcmp(start, flag->name, length) == 0) {- /* Matched "noXXXX", so reverse the sense. */- clear |= flag->set;- set |= flag->clear;- break;- } else if (length == flag_length - 2- && memcmp(start, flag->name + 2, length) == 0) {- /* Matched "XXXX", so don't reverse. */- set |= flag->set;- clear |= flag->clear;- break;- }- }- /* Ignore unknown flag names. */- if (flag->name == NULL && failed == NULL)- failed = start;-- /* Find start of next token. */- start = end;- while (*start == '\t' || *start == ' ' || *start == ',')- start++;-- }-- if (setp)- *setp = set;- if (clrp)- *clrp = clear;-- /* Return location of first failure. */- return (failed);-}--/*- * wcstofflags --- * Take string of arguments and return file flags. This- * version works a little differently than strtofflags(3).- * In particular, it always tests every token, skipping any- * unrecognized tokens. It returns a pointer to the first- * unrecognized token, or NULL if every token was recognized.- * This version is also const-correct and does not modify the- * provided string.- */-static const wchar_t *-ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)-{- const wchar_t *start, *end;- const struct flag *flag;- unsigned long set, clear;- const wchar_t *failed;-- set = clear = 0;- start = s;- failed = NULL;- /* Find start of first token. */- while (*start == L'\t' || *start == L' ' || *start == L',')- start++;- while (*start != L'\0') {- size_t length;- /* Locate end of token. */- end = start;- while (*end != L'\0' && *end != L'\t' &&- *end != L' ' && *end != L',')- end++;- length = end - start;- for (flag = fileflags; flag->wname != NULL; flag++) {- size_t flag_length = wcslen(flag->wname);- if (length == flag_length- && wmemcmp(start, flag->wname, length) == 0) {- /* Matched "noXXXX", so reverse the sense. */- clear |= flag->set;- set |= flag->clear;- break;- } else if (length == flag_length - 2- && wmemcmp(start, flag->wname + 2, length) == 0) {- /* Matched "XXXX", so don't reverse. */- set |= flag->set;- clear |= flag->clear;- break;- }- }- /* Ignore unknown flag names. */- if (flag->wname == NULL && failed == NULL)- failed = start;-- /* Find start of next token. */- start = end;- while (*start == L'\t' || *start == L' ' || *start == L',')- start++;-- }-- if (setp)- *setp = set;- if (clrp)- *clrp = clear;-- /* Return location of first failure. */- return (failed);-}---#ifdef TEST-#include <stdio.h>-int-main(int argc, char **argv)-{- struct archive_entry *entry = archive_entry_new();- unsigned long set, clear;- const wchar_t *remainder;-- remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,");- archive_entry_fflags(entry, &set, &clear);-- wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder);-- wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry));- return (0);-}-#endif
− c/archive_entry.h
@@ -1,723 +0,0 @@-/*-- * Copyright (c) 2003-2008 Tim Kientzle- * Copyright (c) 2016 Martin Matuska- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD: head/lib/libarchive/archive_entry.h 201096 2009-12-28 02:41:27Z kientzle $- */--#ifndef ARCHIVE_ENTRY_H_INCLUDED-#define ARCHIVE_ENTRY_H_INCLUDED--/* Note: Compiler will complain if this does not match archive.h! */-#define ARCHIVE_VERSION_NUMBER 3007001--/*- * Note: archive_entry.h is for use outside of libarchive; the- * configuration headers (config.h, archive_platform.h, etc.) are- * purely internal. Do NOT use HAVE_XXX configuration macros to- * control the behavior of this header! If you must conditionalize,- * use predefined compiler and/or platform macros.- */--#include <sys/types.h>-#include <stddef.h> /* for wchar_t */-#include <stdint.h>-#include <time.h>--#if defined(_WIN32) && !defined(__CYGWIN__)-#include <windows.h>-#endif--/* Get a suitable 64-bit integer type. */-#if !defined(__LA_INT64_T_DEFINED)-# if ARCHIVE_VERSION_NUMBER < 4000000-#define __LA_INT64_T la_int64_t-# endif-#define __LA_INT64_T_DEFINED-# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)-typedef __int64 la_int64_t;-# else-#include <unistd.h>-# if defined(_SCO_DS) || defined(__osf__)-typedef long long la_int64_t;-# else-typedef int64_t la_int64_t;-# endif-# endif-#endif--/* The la_ssize_t should match the type used in 'struct stat' */-#if !defined(__LA_SSIZE_T_DEFINED)-/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */-# if ARCHIVE_VERSION_NUMBER < 4000000-#define __LA_SSIZE_T la_ssize_t-# endif-#define __LA_SSIZE_T_DEFINED-# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)-# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)-typedef ssize_t la_ssize_t;-# elif defined(_WIN64)-typedef __int64 la_ssize_t;-# else-typedef long la_ssize_t;-# endif-# else-# include <unistd.h> /* ssize_t */-typedef ssize_t la_ssize_t;-# endif-#endif--/* Get a suitable definition for mode_t */-#if ARCHIVE_VERSION_NUMBER >= 3999000-/* Switch to plain 'int' for libarchive 4.0. It's less broken than 'mode_t' */-# define __LA_MODE_T int-#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) && !defined(__WATCOMC__)-# define __LA_MODE_T unsigned short-#else-# define __LA_MODE_T mode_t-#endif--/* Large file support for Android */-#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__)-#include "android_lf.h"-#endif--/*- * On Windows, define LIBARCHIVE_STATIC if you're building or using a- * .lib. The default here assumes you're building a DLL. Only- * libarchive source should ever define __LIBARCHIVE_BUILD.- */-#if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC)-# ifdef __LIBARCHIVE_BUILD-# ifdef __GNUC__-# define __LA_DECL __attribute__((dllexport)) extern-# else-# define __LA_DECL __declspec(dllexport)-# endif-# else-# ifdef __GNUC__-# define __LA_DECL-# else-# define __LA_DECL __declspec(dllimport)-# endif-# endif-#elif defined __LIBARCHIVE_ENABLE_VISIBILITY-# define __LA_DECL __attribute__((visibility("default")))-#else-/* Static libraries on all platforms and shared libraries on non-Windows. */-# define __LA_DECL-#endif--#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1-# define __LA_DEPRECATED __attribute__((deprecated))-#else-# define __LA_DEPRECATED-#endif--#ifdef __cplusplus-extern "C" {-#endif--/*- * Description of an archive entry.- *- * You can think of this as "struct stat" with some text fields added in.- *- * TODO: Add "comment", "charset", and possibly other entries that are- * supported by "pax interchange" format. However, GNU, ustar, cpio,- * and other variants don't support these features, so they're not an- * excruciatingly high priority right now.- *- * TODO: "pax interchange" format allows essentially arbitrary- * key/value attributes to be attached to any entry. Supporting- * such extensions may make this library useful for special- * applications (e.g., a package manager could attach special- * package-management attributes to each entry).- */-struct archive;-struct archive_entry;--/*- * File-type constants. These are returned from archive_entry_filetype()- * and passed to archive_entry_set_filetype().- *- * These values match S_XXX defines on every platform I've checked,- * including Windows, AIX, Linux, Solaris, and BSD. They're- * (re)defined here because platforms generally don't define the ones- * they don't support. For example, Windows doesn't define S_IFLNK or- * S_IFBLK. Instead of having a mass of conditional logic and system- * checks to define any S_XXX values that aren't supported locally,- * I've just defined a new set of such constants so that- * libarchive-based applications can manipulate and identify archive- * entries properly even if the hosting platform can't store them on- * disk.- *- * These values are also used directly within some portable formats,- * such as cpio. If you find a platform that varies from these, the- * correct solution is to leave these alone and translate from these- * portable values to platform-native values when entries are read from- * or written to disk.- */-/*- * In libarchive 4.0, we can drop the casts here.- * They're needed to work around Borland C's broken mode_t.- */-#define AE_IFMT ((__LA_MODE_T)0170000)-#define AE_IFREG ((__LA_MODE_T)0100000)-#define AE_IFLNK ((__LA_MODE_T)0120000)-#define AE_IFSOCK ((__LA_MODE_T)0140000)-#define AE_IFCHR ((__LA_MODE_T)0020000)-#define AE_IFBLK ((__LA_MODE_T)0060000)-#define AE_IFDIR ((__LA_MODE_T)0040000)-#define AE_IFIFO ((__LA_MODE_T)0010000)--/*- * Symlink types- */-#define AE_SYMLINK_TYPE_UNDEFINED 0-#define AE_SYMLINK_TYPE_FILE 1-#define AE_SYMLINK_TYPE_DIRECTORY 2--/*- * Basic object manipulation- */--__LA_DECL struct archive_entry *archive_entry_clear(struct archive_entry *);-/* The 'clone' function does a deep copy; all of the strings are copied too. */-__LA_DECL struct archive_entry *archive_entry_clone(struct archive_entry *);-__LA_DECL void archive_entry_free(struct archive_entry *);-__LA_DECL struct archive_entry *archive_entry_new(void);--/*- * This form of archive_entry_new2() will pull character-set- * conversion information from the specified archive handle. The- * older archive_entry_new(void) form is equivalent to calling- * archive_entry_new2(NULL) and will result in the use of an internal- * default character-set conversion.- */-__LA_DECL struct archive_entry *archive_entry_new2(struct archive *);--/*- * Retrieve fields from an archive_entry.- *- * There are a number of implicit conversions among these fields. For- * example, if a regular string field is set and you read the _w wide- * character field, the entry will implicitly convert narrow-to-wide- * using the current locale. Similarly, dev values are automatically- * updated when you write devmajor or devminor and vice versa.- *- * In addition, fields can be "set" or "unset." Unset string fields- * return NULL, non-string fields have _is_set() functions to test- * whether they've been set. You can "unset" a string field by- * assigning NULL; non-string fields have _unset() functions to- * unset them.- *- * Note: There is one ambiguity in the above; string fields will- * also return NULL when implicit character set conversions fail.- * This is usually what you want.- */-__LA_DECL time_t archive_entry_atime(struct archive_entry *);-__LA_DECL long archive_entry_atime_nsec(struct archive_entry *);-__LA_DECL int archive_entry_atime_is_set(struct archive_entry *);-__LA_DECL time_t archive_entry_birthtime(struct archive_entry *);-__LA_DECL long archive_entry_birthtime_nsec(struct archive_entry *);-__LA_DECL int archive_entry_birthtime_is_set(struct archive_entry *);-__LA_DECL time_t archive_entry_ctime(struct archive_entry *);-__LA_DECL long archive_entry_ctime_nsec(struct archive_entry *);-__LA_DECL int archive_entry_ctime_is_set(struct archive_entry *);-__LA_DECL dev_t archive_entry_dev(struct archive_entry *);-__LA_DECL int archive_entry_dev_is_set(struct archive_entry *);-__LA_DECL dev_t archive_entry_devmajor(struct archive_entry *);-__LA_DECL dev_t archive_entry_devminor(struct archive_entry *);-__LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *);-__LA_DECL void archive_entry_fflags(struct archive_entry *,- unsigned long * /* set */,- unsigned long * /* clear */);-__LA_DECL const char *archive_entry_fflags_text(struct archive_entry *);-__LA_DECL la_int64_t archive_entry_gid(struct archive_entry *);-__LA_DECL const char *archive_entry_gname(struct archive_entry *);-__LA_DECL const char *archive_entry_gname_utf8(struct archive_entry *);-__LA_DECL const wchar_t *archive_entry_gname_w(struct archive_entry *);-__LA_DECL const char *archive_entry_hardlink(struct archive_entry *);-__LA_DECL const char *archive_entry_hardlink_utf8(struct archive_entry *);-__LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *);-__LA_DECL la_int64_t archive_entry_ino(struct archive_entry *);-__LA_DECL la_int64_t archive_entry_ino64(struct archive_entry *);-__LA_DECL int archive_entry_ino_is_set(struct archive_entry *);-__LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *);-__LA_DECL time_t archive_entry_mtime(struct archive_entry *);-__LA_DECL long archive_entry_mtime_nsec(struct archive_entry *);-__LA_DECL int archive_entry_mtime_is_set(struct archive_entry *);-__LA_DECL unsigned int archive_entry_nlink(struct archive_entry *);-__LA_DECL const char *archive_entry_pathname(struct archive_entry *);-__LA_DECL const char *archive_entry_pathname_utf8(struct archive_entry *);-__LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *);-__LA_DECL __LA_MODE_T archive_entry_perm(struct archive_entry *);-__LA_DECL dev_t archive_entry_rdev(struct archive_entry *);-__LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *);-__LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *);-__LA_DECL const char *archive_entry_sourcepath(struct archive_entry *);-__LA_DECL const wchar_t *archive_entry_sourcepath_w(struct archive_entry *);-__LA_DECL la_int64_t archive_entry_size(struct archive_entry *);-__LA_DECL int archive_entry_size_is_set(struct archive_entry *);-__LA_DECL const char *archive_entry_strmode(struct archive_entry *);-__LA_DECL const char *archive_entry_symlink(struct archive_entry *);-__LA_DECL const char *archive_entry_symlink_utf8(struct archive_entry *);-__LA_DECL int archive_entry_symlink_type(struct archive_entry *);-__LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *);-__LA_DECL la_int64_t archive_entry_uid(struct archive_entry *);-__LA_DECL const char *archive_entry_uname(struct archive_entry *);-__LA_DECL const char *archive_entry_uname_utf8(struct archive_entry *);-__LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *);-__LA_DECL int archive_entry_is_data_encrypted(struct archive_entry *);-__LA_DECL int archive_entry_is_metadata_encrypted(struct archive_entry *);-__LA_DECL int archive_entry_is_encrypted(struct archive_entry *);--/*- * Set fields in an archive_entry.- *- * Note: Before libarchive 2.4, there were 'set' and 'copy' versions- * of the string setters. 'copy' copied the actual string, 'set' just- * stored the pointer. In libarchive 2.4 and later, strings are- * always copied.- */--__LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long);-__LA_DECL void archive_entry_unset_atime(struct archive_entry *);-#if defined(_WIN32) && !defined(__CYGWIN__)-__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *);-#endif-__LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long);-__LA_DECL void archive_entry_unset_birthtime(struct archive_entry *);-__LA_DECL void archive_entry_set_ctime(struct archive_entry *, time_t, long);-__LA_DECL void archive_entry_unset_ctime(struct archive_entry *);-__LA_DECL void archive_entry_set_dev(struct archive_entry *, dev_t);-__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, dev_t);-__LA_DECL void archive_entry_set_devminor(struct archive_entry *, dev_t);-__LA_DECL void archive_entry_set_filetype(struct archive_entry *, unsigned int);-__LA_DECL void archive_entry_set_fflags(struct archive_entry *,- unsigned long /* set */, unsigned long /* clear */);-/* Returns pointer to start of first invalid token, or NULL if none. */-/* Note that all recognized tokens are processed, regardless. */-__LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *,- const char *);-__LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,- const wchar_t *);-__LA_DECL void archive_entry_set_gid(struct archive_entry *, la_int64_t);-__LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *);-__LA_DECL void archive_entry_set_gname_utf8(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_gname(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);-__LA_DECL int archive_entry_update_gname_utf8(struct archive_entry *, const char *);-__LA_DECL void archive_entry_set_hardlink(struct archive_entry *, const char *);-__LA_DECL void archive_entry_set_hardlink_utf8(struct archive_entry *, const char *);-__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 *);-__LA_DECL void archive_entry_set_ino(struct archive_entry *, la_int64_t);-__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 *);-__LA_DECL void archive_entry_set_link_utf8(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *);-__LA_DECL int archive_entry_update_link_utf8(struct archive_entry *, const char *);-__LA_DECL void archive_entry_set_mode(struct archive_entry *, __LA_MODE_T);-__LA_DECL void archive_entry_set_mtime(struct archive_entry *, time_t, long);-__LA_DECL void archive_entry_unset_mtime(struct archive_entry *);-__LA_DECL void archive_entry_set_nlink(struct archive_entry *, unsigned int);-__LA_DECL void archive_entry_set_pathname(struct archive_entry *, const char *);-__LA_DECL void archive_entry_set_pathname_utf8(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_pathname(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);-__LA_DECL int archive_entry_update_pathname_utf8(struct archive_entry *, const char *);-__LA_DECL void archive_entry_set_perm(struct archive_entry *, __LA_MODE_T);-__LA_DECL void archive_entry_set_rdev(struct archive_entry *, dev_t);-__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, dev_t);-__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, dev_t);-__LA_DECL void archive_entry_set_size(struct archive_entry *, la_int64_t);-__LA_DECL void archive_entry_unset_size(struct archive_entry *);-__LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_sourcepath_w(struct archive_entry *, const wchar_t *);-__LA_DECL void archive_entry_set_symlink(struct archive_entry *, const char *);-__LA_DECL void archive_entry_set_symlink_type(struct archive_entry *, int);-__LA_DECL void archive_entry_set_symlink_utf8(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_symlink(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *);-__LA_DECL int archive_entry_update_symlink_utf8(struct archive_entry *, const char *);-__LA_DECL void archive_entry_set_uid(struct archive_entry *, la_int64_t);-__LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *);-__LA_DECL void archive_entry_set_uname_utf8(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *);-__LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);-__LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char *);-__LA_DECL void archive_entry_set_is_data_encrypted(struct archive_entry *, char is_encrypted);-__LA_DECL void archive_entry_set_is_metadata_encrypted(struct archive_entry *, char is_encrypted);-/*- * Routines to bulk copy fields to/from a platform-native "struct- * stat." Libarchive used to just store a struct stat inside of each- * archive_entry object, but this created issues when trying to- * manipulate archives on systems different than the ones they were- * created on.- *- * TODO: On Linux and other LFS systems, provide both stat32 and- * stat64 versions of these functions and all of the macro glue so- * that archive_entry_stat is magically defined to- * archive_entry_stat32 or archive_entry_stat64 as appropriate.- */-__LA_DECL const struct stat *archive_entry_stat(struct archive_entry *);-__LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *);--/*- * Storage for Mac OS-specific AppleDouble metadata information.- * Apple-format tar files store a separate binary blob containing- * encoded metadata with ACL, extended attributes, etc.- * This provides a place to store that blob.- */--__LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *);-__LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t);--/*- * Digest routine. This is used to query the raw hex digest for the- * given entry. The type of digest is provided as an argument.- */-#define ARCHIVE_ENTRY_DIGEST_MD5 0x00000001-#define ARCHIVE_ENTRY_DIGEST_RMD160 0x00000002-#define ARCHIVE_ENTRY_DIGEST_SHA1 0x00000003-#define ARCHIVE_ENTRY_DIGEST_SHA256 0x00000004-#define ARCHIVE_ENTRY_DIGEST_SHA384 0x00000005-#define ARCHIVE_ENTRY_DIGEST_SHA512 0x00000006--__LA_DECL const unsigned char * archive_entry_digest(struct archive_entry *, int /* type */);--/*- * ACL routines. This used to simply store and return text-format ACL- * strings, but that proved insufficient for a number of reasons:- * = clients need control over uname/uid and gname/gid mappings- * = there are many different ACL text formats- * = would like to be able to read/convert archives containing ACLs- * on platforms that lack ACL libraries- *- * This last point, in particular, forces me to implement a reasonably- * complete set of ACL support routines.- */--/*- * Permission bits.- */-#define ARCHIVE_ENTRY_ACL_EXECUTE 0x00000001-#define ARCHIVE_ENTRY_ACL_WRITE 0x00000002-#define ARCHIVE_ENTRY_ACL_READ 0x00000004-#define ARCHIVE_ENTRY_ACL_READ_DATA 0x00000008-#define ARCHIVE_ENTRY_ACL_LIST_DIRECTORY 0x00000008-#define ARCHIVE_ENTRY_ACL_WRITE_DATA 0x00000010-#define ARCHIVE_ENTRY_ACL_ADD_FILE 0x00000010-#define ARCHIVE_ENTRY_ACL_APPEND_DATA 0x00000020-#define ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY 0x00000020-#define ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS 0x00000040-#define ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS 0x00000080-#define ARCHIVE_ENTRY_ACL_DELETE_CHILD 0x00000100-#define ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES 0x00000200-#define ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES 0x00000400-#define ARCHIVE_ENTRY_ACL_DELETE 0x00000800-#define ARCHIVE_ENTRY_ACL_READ_ACL 0x00001000-#define ARCHIVE_ENTRY_ACL_WRITE_ACL 0x00002000-#define ARCHIVE_ENTRY_ACL_WRITE_OWNER 0x00004000-#define ARCHIVE_ENTRY_ACL_SYNCHRONIZE 0x00008000--#define ARCHIVE_ENTRY_ACL_PERMS_POSIX1E \- (ARCHIVE_ENTRY_ACL_EXECUTE \- | ARCHIVE_ENTRY_ACL_WRITE \- | ARCHIVE_ENTRY_ACL_READ)--#define ARCHIVE_ENTRY_ACL_PERMS_NFS4 \- (ARCHIVE_ENTRY_ACL_EXECUTE \- | ARCHIVE_ENTRY_ACL_READ_DATA \- | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY \- | ARCHIVE_ENTRY_ACL_WRITE_DATA \- | ARCHIVE_ENTRY_ACL_ADD_FILE \- | ARCHIVE_ENTRY_ACL_APPEND_DATA \- | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY \- | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS \- | ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS \- | ARCHIVE_ENTRY_ACL_DELETE_CHILD \- | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES \- | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES \- | ARCHIVE_ENTRY_ACL_DELETE \- | ARCHIVE_ENTRY_ACL_READ_ACL \- | ARCHIVE_ENTRY_ACL_WRITE_ACL \- | ARCHIVE_ENTRY_ACL_WRITE_OWNER \- | ARCHIVE_ENTRY_ACL_SYNCHRONIZE)--/*- * Inheritance values (NFS4 ACLs only); included in permset.- */-#define ARCHIVE_ENTRY_ACL_ENTRY_INHERITED 0x01000000-#define ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT 0x02000000-#define ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT 0x04000000-#define ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT 0x08000000-#define ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY 0x10000000-#define ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS 0x20000000-#define ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS 0x40000000--#define ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4 \- (ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT \- | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT \- | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT \- | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY \- | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS \- | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS \- | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED)--/* We need to be able to specify combinations of these. */-#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 0x00000100 /* POSIX.1e only */-#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 0x00000200 /* POSIX.1e only */-#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 0x00000400 /* NFS4 only */-#define ARCHIVE_ENTRY_ACL_TYPE_DENY 0x00000800 /* NFS4 only */-#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 0x00001000 /* NFS4 only */-#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 0x00002000 /* NFS4 only */-#define ARCHIVE_ENTRY_ACL_TYPE_POSIX1E (ARCHIVE_ENTRY_ACL_TYPE_ACCESS \- | ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)-#define ARCHIVE_ENTRY_ACL_TYPE_NFS4 (ARCHIVE_ENTRY_ACL_TYPE_ALLOW \- | ARCHIVE_ENTRY_ACL_TYPE_DENY \- | ARCHIVE_ENTRY_ACL_TYPE_AUDIT \- | ARCHIVE_ENTRY_ACL_TYPE_ALARM)--/* Tag values mimic POSIX.1e */-#define ARCHIVE_ENTRY_ACL_USER 10001 /* Specified user. */-#define ARCHIVE_ENTRY_ACL_USER_OBJ 10002 /* User who owns the file. */-#define ARCHIVE_ENTRY_ACL_GROUP 10003 /* Specified group. */-#define ARCHIVE_ENTRY_ACL_GROUP_OBJ 10004 /* Group who owns the file. */-#define ARCHIVE_ENTRY_ACL_MASK 10005 /* Modify group access (POSIX.1e only) */-#define ARCHIVE_ENTRY_ACL_OTHER 10006 /* Public (POSIX.1e only) */-#define ARCHIVE_ENTRY_ACL_EVERYONE 10107 /* Everyone (NFS4 only) */--/*- * Set the ACL by clearing it and adding entries one at a time.- * Unlike the POSIX.1e ACL routines, you must specify the type- * (access/default) for each entry. Internally, the ACL data is just- * a soup of entries. API calls here allow you to retrieve just the- * entries of interest. This design (which goes against the spirit of- * POSIX.1e) is useful for handling archive formats that combine- * default and access information in a single ACL list.- */-__LA_DECL void archive_entry_acl_clear(struct archive_entry *);-__LA_DECL int archive_entry_acl_add_entry(struct archive_entry *,- int /* type */, int /* permset */, int /* tag */,- int /* qual */, const char * /* name */);-__LA_DECL int archive_entry_acl_add_entry_w(struct archive_entry *,- int /* type */, int /* permset */, int /* tag */,- int /* qual */, const wchar_t * /* name */);--/*- * To retrieve the ACL, first "reset", then repeatedly ask for the- * "next" entry. The want_type parameter allows you to request only- * certain types of entries.- */-__LA_DECL int archive_entry_acl_reset(struct archive_entry *, int /* want_type */);-__LA_DECL int archive_entry_acl_next(struct archive_entry *, int /* want_type */,- int * /* type */, int * /* permset */, int * /* tag */,- int * /* qual */, const char ** /* name */);--/*- * Construct a text-format ACL. The flags argument is a bitmask that- * can include any of the following:- *- * Flags only for archive entries with POSIX.1e ACL:- * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries.- * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries.- * ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each- * default ACL entry.- * ARCHIVE_ENTRY_ACL_STYLE_SOLARIS - Output only one colon after "other" and- * "mask" entries.- *- * Flags only for archive entries with NFSv4 ACL:- * ARCHIVE_ENTRY_ACL_STYLE_COMPACT - Do not output the minus character for- * unset permissions and flags in NFSv4 ACL permission and flag fields- *- * Flags for for archive entries with POSIX.1e ACL or NFSv4 ACL:- * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in- * each ACL entry.- * ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA - Separate entries with comma- * instead of newline.- */-#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 0x00000001-#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 0x00000002-#define ARCHIVE_ENTRY_ACL_STYLE_SOLARIS 0x00000004-#define ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA 0x00000008-#define ARCHIVE_ENTRY_ACL_STYLE_COMPACT 0x00000010--__LA_DECL wchar_t *archive_entry_acl_to_text_w(struct archive_entry *,- la_ssize_t * /* len */, int /* flags */);-__LA_DECL char *archive_entry_acl_to_text(struct archive_entry *,- la_ssize_t * /* len */, int /* flags */);-__LA_DECL int archive_entry_acl_from_text_w(struct archive_entry *,- const wchar_t * /* wtext */, int /* type */);-__LA_DECL int archive_entry_acl_from_text(struct archive_entry *,- const char * /* text */, int /* type */);--/* Deprecated constants */-#define OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024-#define OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048--/* Deprecated functions */-__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,- int /* flags */) __LA_DEPRECATED;-__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,- int /* flags */) __LA_DEPRECATED;--/* Return bitmask of ACL types in an archive entry */-__LA_DECL int archive_entry_acl_types(struct archive_entry *);--/* Return a count of entries matching 'want_type' */-__LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */);--/* Return an opaque ACL object. */-/* There's not yet anything clients can actually do with this... */-struct archive_acl;-__LA_DECL struct archive_acl *archive_entry_acl(struct archive_entry *);--/*- * extended attributes- */--__LA_DECL void archive_entry_xattr_clear(struct archive_entry *);-__LA_DECL void archive_entry_xattr_add_entry(struct archive_entry *,- const char * /* name */, const void * /* value */,- size_t /* size */);--/*- * To retrieve the xattr list, first "reset", then repeatedly ask for the- * "next" entry.- */--__LA_DECL int archive_entry_xattr_count(struct archive_entry *);-__LA_DECL int archive_entry_xattr_reset(struct archive_entry *);-__LA_DECL int archive_entry_xattr_next(struct archive_entry *,- const char ** /* name */, const void ** /* value */, size_t *);--/*- * sparse- */--__LA_DECL void archive_entry_sparse_clear(struct archive_entry *);-__LA_DECL void archive_entry_sparse_add_entry(struct archive_entry *,- la_int64_t /* offset */, la_int64_t /* length */);--/*- * To retrieve the xattr list, first "reset", then repeatedly ask for the- * "next" entry.- */--__LA_DECL int archive_entry_sparse_count(struct archive_entry *);-__LA_DECL int archive_entry_sparse_reset(struct archive_entry *);-__LA_DECL int archive_entry_sparse_next(struct archive_entry *,- la_int64_t * /* offset */, la_int64_t * /* length */);--/*- * Utility to match up hardlinks.- *- * The 'struct archive_entry_linkresolver' is a cache of archive entries- * for files with multiple links. Here's how to use it:- * 1. Create a lookup object with archive_entry_linkresolver_new()- * 2. Tell it the archive format you're using.- * 3. Hand each archive_entry to archive_entry_linkify().- * That function will return 0, 1, or 2 entries that should- * be written.- * 4. Call archive_entry_linkify(resolver, NULL) until- * no more entries are returned.- * 5. Call archive_entry_linkresolver_free(resolver) to free resources.- *- * The entries returned have their hardlink and size fields updated- * appropriately. If an entry is passed in that does not refer to- * a file with multiple links, it is returned unchanged. The intention- * is that you should be able to simply filter all entries through- * this machine.- *- * To make things more efficient, be sure that each entry has a valid- * nlinks value. The hardlink cache uses this to track when all links- * have been found. If the nlinks value is zero, it will keep every- * name in the cache indefinitely, which can use a lot of memory.- *- * Note that archive_entry_size() is reset to zero if the file- * body should not be written to the archive. Pay attention!- */-struct archive_entry_linkresolver;--/*- * There are three different strategies for marking hardlinks.- * The descriptions below name them after the best-known- * formats that rely on each strategy:- *- * "Old cpio" is the simplest, it always returns any entry unmodified.- * As far as I know, only cpio formats use this. Old cpio archives- * store every link with the full body; the onus is on the dearchiver- * to detect and properly link the files as they are restored.- * "tar" is also pretty simple; it caches a copy the first time it sees- * any link. Subsequent appearances are modified to be hardlink- * references to the first one without any body. Used by all tar- * formats, although the newest tar formats permit the "old cpio" strategy- * as well. This strategy is very simple for the dearchiver,- * and reasonably straightforward for the archiver.- * "new cpio" is trickier. It stores the body only with the last- * occurrence. The complication is that we might not- * see every link to a particular file in a single session, so- * there's no easy way to know when we've seen the last occurrence.- * The solution here is to queue one link until we see the next.- * At the end of the session, you can enumerate any remaining- * entries by calling archive_entry_linkify(NULL) and store those- * bodies. If you have a file with three links l1, l2, and l3,- * you'll get the following behavior if you see all three links:- * linkify(l1) => NULL (the resolver stores l1 internally)- * linkify(l2) => l1 (resolver stores l2, you write l1)- * linkify(l3) => l2, l3 (all links seen, you can write both).- * If you only see l1 and l2, you'll get this behavior:- * linkify(l1) => NULL- * linkify(l2) => l1- * linkify(NULL) => l2 (at end, you retrieve remaining links)- * As the name suggests, this strategy is used by newer cpio variants.- * It's noticeably more complex for the archiver, slightly more complex- * for the dearchiver than the tar strategy, but makes it straightforward- * to restore a file using any link by simply continuing to scan until- * you see a link that is stored with a body. In contrast, the tar- * strategy requires you to rescan the archive from the beginning to- * correctly extract an arbitrary link.- */--__LA_DECL struct archive_entry_linkresolver *archive_entry_linkresolver_new(void);-__LA_DECL void archive_entry_linkresolver_set_strategy(- struct archive_entry_linkresolver *, int /* format_code */);-__LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *);-__LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *,- struct archive_entry **, struct archive_entry **);-__LA_DECL struct archive_entry *archive_entry_partial_links(- struct archive_entry_linkresolver *res, unsigned int *links);-#ifdef __cplusplus-}-#endif--/* This is meaningless outside of this header. */-#undef __LA_DECL--#endif /* !ARCHIVE_ENTRY_H_INCLUDED */
− c/archive_entry_copy_bhfi.c
@@ -1,75 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#include "archive_private.h"-#include "archive_entry.h"--#if defined(_WIN32) && !defined(__CYGWIN__)--#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)--__inline static void-fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns)-{- ULARGE_INTEGER utc;-- utc.HighPart = filetime->dwHighDateTime;- utc.LowPart = filetime->dwLowDateTime;- if (utc.QuadPart >= EPOC_TIME) {- utc.QuadPart -= EPOC_TIME;- *t = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */- *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */- } else {- *t = 0;- *ns = 0;- }-}--void-archive_entry_copy_bhfi(struct archive_entry *entry,- BY_HANDLE_FILE_INFORMATION *bhfi)-{- time_t secs;- long nsecs;-- fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs);- archive_entry_set_atime(entry, secs, nsecs);- fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs);- archive_entry_set_mtime(entry, secs, nsecs);- fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs);- archive_entry_set_birthtime(entry, secs, nsecs);- archive_entry_set_ctime(entry, secs, nsecs);- archive_entry_set_dev(entry, bhfi->dwVolumeSerialNumber);- archive_entry_set_ino64(entry, (((int64_t)bhfi->nFileIndexHigh) << 32)- + bhfi->nFileIndexLow);- archive_entry_set_nlink(entry, bhfi->nNumberOfLinks);- archive_entry_set_size(entry, (((int64_t)bhfi->nFileSizeHigh) << 32)- + bhfi->nFileSizeLow);- /* archive_entry_set_mode(entry, st->st_mode); */-}-#endif
− c/archive_entry_copy_stat.c
@@ -1,83 +0,0 @@-/*-- * 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_entry_copy_stat.c 189466 2009-03-07 00:52:02Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif--#include "archive.h"-#include "archive_entry.h"--void-archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)-{-#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC- archive_entry_set_atime(entry, st->st_atime, st->st_atimespec.tv_nsec);- archive_entry_set_ctime(entry, st->st_ctime, st->st_ctimespec.tv_nsec);- archive_entry_set_mtime(entry, st->st_mtime, st->st_mtimespec.tv_nsec);-#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC- archive_entry_set_atime(entry, st->st_atime, st->st_atim.tv_nsec);- archive_entry_set_ctime(entry, st->st_ctime, st->st_ctim.tv_nsec);- archive_entry_set_mtime(entry, st->st_mtime, st->st_mtim.tv_nsec);-#elif HAVE_STRUCT_STAT_ST_MTIME_NSEC- archive_entry_set_atime(entry, st->st_atime, st->st_atime_nsec);- archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_nsec);- archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_nsec);-#elif HAVE_STRUCT_STAT_ST_MTIME_N- archive_entry_set_atime(entry, st->st_atime, st->st_atime_n);- archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_n);- archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_n);-#elif HAVE_STRUCT_STAT_ST_UMTIME- archive_entry_set_atime(entry, st->st_atime, st->st_uatime * 1000);- archive_entry_set_ctime(entry, st->st_ctime, st->st_uctime * 1000);- archive_entry_set_mtime(entry, st->st_mtime, st->st_umtime * 1000);-#elif HAVE_STRUCT_STAT_ST_MTIME_USEC- archive_entry_set_atime(entry, st->st_atime, st->st_atime_usec * 1000);- archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_usec * 1000);- archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_usec * 1000);-#else- archive_entry_set_atime(entry, st->st_atime, 0);- archive_entry_set_ctime(entry, st->st_ctime, 0);- archive_entry_set_mtime(entry, st->st_mtime, 0);-#endif-#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC- archive_entry_set_birthtime(entry, st->st_birthtime, st->st_birthtimespec.tv_nsec);-#elif HAVE_STRUCT_STAT_ST_BIRTHTIME- archive_entry_set_birthtime(entry, st->st_birthtime, 0);-#else- archive_entry_unset_birthtime(entry);-#endif- archive_entry_set_dev(entry, st->st_dev);- archive_entry_set_gid(entry, st->st_gid);- archive_entry_set_uid(entry, st->st_uid);- archive_entry_set_ino(entry, st->st_ino);- archive_entry_set_nlink(entry, st->st_nlink);- archive_entry_set_rdev(entry, st->st_rdev);- archive_entry_set_size(entry, st->st_size);- archive_entry_set_mode(entry, st->st_mode);-}
− c/archive_entry_link_resolver.c
@@ -1,447 +0,0 @@-/*-- * 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_entry_link_resolver.c 201100 2009-12-28 03:05:31Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#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--#include "archive.h"-#include "archive_entry.h"--/*- * This is mostly a pretty straightforward hash table implementation.- * The only interesting bit is the different strategies used to- * match up links. These strategies match those used by various- * archiving formats:- * tar - content stored with first link, remainder refer back to it.- * This requires us to match each subsequent link up with the- * first appearance.- * cpio - Old cpio just stored body with each link, match-ups were- * implicit. This is trivial.- * new cpio - New cpio only stores body with last link, match-ups- * are implicit. This is actually quite tricky; see the notes- * below.- */--/* Users pass us a format code, we translate that into a strategy here. */-#define ARCHIVE_ENTRY_LINKIFY_LIKE_TAR 0-#define ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE 1-#define ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO 2-#define ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO 3--/* Initial size of link cache. */-#define links_cache_initial_size 1024--struct links_entry {- struct links_entry *next;- struct links_entry *previous;- struct archive_entry *canonical;- struct archive_entry *entry;- size_t hash;- unsigned int links; /* # links not yet seen */-};--struct archive_entry_linkresolver {- struct links_entry **buckets;- struct links_entry *spare;- unsigned long number_entries;- size_t number_buckets;- int strategy;-};--#define NEXT_ENTRY_DEFERRED 1-#define NEXT_ENTRY_PARTIAL 2-#define NEXT_ENTRY_ALL (NEXT_ENTRY_DEFERRED | NEXT_ENTRY_PARTIAL)--static struct links_entry *find_entry(struct archive_entry_linkresolver *,- struct archive_entry *);-static void grow_hash(struct archive_entry_linkresolver *);-static struct links_entry *insert_entry(struct archive_entry_linkresolver *,- struct archive_entry *);-static struct links_entry *next_entry(struct archive_entry_linkresolver *,- int);--struct archive_entry_linkresolver *-archive_entry_linkresolver_new(void)-{- struct archive_entry_linkresolver *res;-- /* Check for positive power-of-two */- if (links_cache_initial_size == 0 ||- (links_cache_initial_size & (links_cache_initial_size - 1)) != 0)- return (NULL);-- res = calloc(1, sizeof(struct archive_entry_linkresolver));- if (res == NULL)- return (NULL);- res->number_buckets = links_cache_initial_size;- res->buckets = calloc(res->number_buckets, sizeof(res->buckets[0]));- if (res->buckets == NULL) {- free(res);- return (NULL);- }- return (res);-}--void-archive_entry_linkresolver_set_strategy(struct archive_entry_linkresolver *res,- int fmt)-{- int fmtbase = fmt & ARCHIVE_FORMAT_BASE_MASK;-- switch (fmtbase) {- case ARCHIVE_FORMAT_7ZIP:- case ARCHIVE_FORMAT_AR:- case ARCHIVE_FORMAT_ZIP:- res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO;- break;- case ARCHIVE_FORMAT_CPIO:- switch (fmt) {- case ARCHIVE_FORMAT_CPIO_SVR4_NOCRC:- case ARCHIVE_FORMAT_CPIO_SVR4_CRC:- res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO;- break;- default:- res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO;- break;- }- break;- case ARCHIVE_FORMAT_MTREE:- res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE;- break;- case ARCHIVE_FORMAT_ISO9660:- case ARCHIVE_FORMAT_SHAR:- case ARCHIVE_FORMAT_TAR:- case ARCHIVE_FORMAT_XAR:- res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_TAR;- break;- default:- res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO;- break;- }-}--void-archive_entry_linkresolver_free(struct archive_entry_linkresolver *res)-{- struct links_entry *le;-- if (res == NULL)- return;-- while ((le = next_entry(res, NEXT_ENTRY_ALL)) != NULL)- archive_entry_free(le->entry);- free(res->buckets);- free(res);-}--void-archive_entry_linkify(struct archive_entry_linkresolver *res,- struct archive_entry **e, struct archive_entry **f)-{- struct links_entry *le;- struct archive_entry *t;-- *f = NULL; /* Default: Don't return a second entry. */-- if (*e == NULL) {- le = next_entry(res, NEXT_ENTRY_DEFERRED);- if (le != NULL) {- *e = le->entry;- le->entry = NULL;- }- return;- }-- /* If it has only one link, then we're done. */- if (archive_entry_nlink(*e) == 1)- return;- /* Directories, devices never have hardlinks. */- if (archive_entry_filetype(*e) == AE_IFDIR- || archive_entry_filetype(*e) == AE_IFBLK- || archive_entry_filetype(*e) == AE_IFCHR)- return;-- switch (res->strategy) {- case ARCHIVE_ENTRY_LINKIFY_LIKE_TAR:- le = find_entry(res, *e);- if (le != NULL) {- archive_entry_unset_size(*e);- archive_entry_copy_hardlink(*e,- archive_entry_pathname(le->canonical));- } else- insert_entry(res, *e);- return;- case ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE:- le = find_entry(res, *e);- if (le != NULL) {- archive_entry_copy_hardlink(*e,- archive_entry_pathname(le->canonical));- } else- insert_entry(res, *e);- return;- case ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO:- /* This one is trivial. */- return;- case ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO:- le = find_entry(res, *e);- if (le != NULL) {- /*- * Put the new entry in le, return the- * old entry from le.- */- t = *e;- *e = le->entry;- le->entry = t;- /* Make the old entry into a hardlink. */- archive_entry_unset_size(*e);- archive_entry_copy_hardlink(*e,- archive_entry_pathname(le->canonical));- /* If we ran out of links, return the- * final entry as well. */- if (le->links == 0) {- *f = le->entry;- le->entry = NULL;- }- } else {- /*- * If we haven't seen it, tuck it away- * for future use.- */- le = insert_entry(res, *e);- if (le == NULL)- /* XXX We should return an error code XXX */- return;- le->entry = *e;- *e = NULL;- }- return;- default:- break;- }- return;-}--static struct links_entry *-find_entry(struct archive_entry_linkresolver *res,- struct archive_entry *entry)-{- struct links_entry *le;- size_t hash, bucket;- dev_t dev;- int64_t ino;-- /* Free a held entry. */- if (res->spare != NULL) {- archive_entry_free(res->spare->canonical);- archive_entry_free(res->spare->entry);- free(res->spare);- res->spare = NULL;- }-- dev = archive_entry_dev(entry);- ino = archive_entry_ino64(entry);- hash = (size_t)(dev ^ ino);-- /* Try to locate this entry in the links cache. */- bucket = hash & (res->number_buckets - 1);- for (le = res->buckets[bucket]; le != NULL; le = le->next) {- if (le->hash == hash- && dev == archive_entry_dev(le->canonical)- && ino == archive_entry_ino64(le->canonical)) {- /*- * Decrement link count each time and release- * the entry if it hits zero. This saves- * memory and is necessary for detecting- * missed links.- */- --le->links;- if (le->links > 0)- return (le);- /* Remove it from this hash bucket. */- if (le->previous != NULL)- le->previous->next = le->next;- if (le->next != NULL)- le->next->previous = le->previous;- if (res->buckets[bucket] == le)- res->buckets[bucket] = le->next;- res->number_entries--;- /* Defer freeing this entry. */- res->spare = le;- return (le);- }- }- return (NULL);-}--static struct links_entry *-next_entry(struct archive_entry_linkresolver *res, int mode)-{- struct links_entry *le;- size_t bucket;-- /* Free a held entry. */- if (res->spare != NULL) {- archive_entry_free(res->spare->canonical);- archive_entry_free(res->spare->entry);- free(res->spare);- res->spare = NULL;- }-- /* Look for next non-empty bucket in the links cache. */- for (bucket = 0; bucket < res->number_buckets; bucket++) {- for (le = res->buckets[bucket]; le != NULL; le = le->next) {- if (le->entry != NULL &&- (mode & NEXT_ENTRY_DEFERRED) == 0)- continue;- if (le->entry == NULL &&- (mode & NEXT_ENTRY_PARTIAL) == 0)- continue;- /* Remove it from this hash bucket. */- if (le->next != NULL)- le->next->previous = le->previous;- if (le->previous != NULL)- le->previous->next = le->next;- else- res->buckets[bucket] = le->next;- res->number_entries--;- /* Defer freeing this entry. */- res->spare = le;- return (le);- }- }- return (NULL);-}--static struct links_entry *-insert_entry(struct archive_entry_linkresolver *res,- struct archive_entry *entry)-{- struct links_entry *le;- size_t hash, bucket;-- /* Add this entry to the links cache. */- le = calloc(1, sizeof(struct links_entry));- if (le == NULL)- return (NULL);- le->canonical = archive_entry_clone(entry);-- /* If the links cache is getting too full, enlarge the hash table. */- if (res->number_entries > res->number_buckets * 2)- grow_hash(res);-- hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry));- bucket = hash & (res->number_buckets - 1);-- /* If we could allocate the entry, record it. */- if (res->buckets[bucket] != NULL)- res->buckets[bucket]->previous = le;- res->number_entries++;- le->next = res->buckets[bucket];- le->previous = NULL;- res->buckets[bucket] = le;- le->hash = hash;- le->links = archive_entry_nlink(entry) - 1;- return (le);-}--static void-grow_hash(struct archive_entry_linkresolver *res)-{- struct links_entry *le, **new_buckets;- size_t new_size;- size_t i, bucket;-- /* Try to enlarge the bucket list. */- new_size = res->number_buckets * 2;- if (new_size < res->number_buckets)- return;- new_buckets = calloc(new_size, sizeof(struct links_entry *));-- if (new_buckets == NULL)- return;-- for (i = 0; i < res->number_buckets; i++) {- while (res->buckets[i] != NULL) {- /* Remove entry from old bucket. */- le = res->buckets[i];- res->buckets[i] = le->next;-- /* Add entry to new bucket. */- bucket = le->hash & (new_size - 1);-- if (new_buckets[bucket] != NULL)- new_buckets[bucket]->previous = le;- le->next = new_buckets[bucket];- le->previous = NULL;- new_buckets[bucket] = le;- }- }- free(res->buckets);- res->buckets = new_buckets;- res->number_buckets = new_size;-}--struct archive_entry *-archive_entry_partial_links(struct archive_entry_linkresolver *res,- unsigned int *links)-{- struct archive_entry *e;- struct links_entry *le;-- /* Free a held entry. */- if (res->spare != NULL) {- archive_entry_free(res->spare->canonical);- archive_entry_free(res->spare->entry);- free(res->spare);- res->spare = NULL;- }-- le = next_entry(res, NEXT_ENTRY_PARTIAL);- if (le != NULL) {- e = le->canonical;- if (links != NULL)- *links = le->links;- le->canonical = NULL;- } else {- e = NULL;- if (links != NULL)- *links = 0;- }- return (e);-}
− c/archive_entry_locale.h
@@ -1,92 +0,0 @@-/*-- * Copyright (c) 2011 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- */--#ifndef ARCHIVE_ENTRY_LOCALE_H_INCLUDED-#define ARCHIVE_ENTRY_LOCALE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--struct archive_entry;-struct archive_string_conv;--/*- * Utility functions to set and get entry attributes by translating- * character-set. These are designed for use in format readers and writers.- *- * The return code and interface of these are quite different from other- * functions for archive_entry defined in archive_entry.h.- * Common return code are:- * Return 0 if the string conversion succeeded.- * Return -1 if the string conversion failed.- */--#define archive_entry_gname_l _archive_entry_gname_l-int _archive_entry_gname_l(struct archive_entry *,- const char **, size_t *, struct archive_string_conv *);-#define archive_entry_hardlink_l _archive_entry_hardlink_l-int _archive_entry_hardlink_l(struct archive_entry *,- const char **, size_t *, struct archive_string_conv *);-#define archive_entry_pathname_l _archive_entry_pathname_l-int _archive_entry_pathname_l(struct archive_entry *,- const char **, size_t *, struct archive_string_conv *);-#define archive_entry_symlink_l _archive_entry_symlink_l-int _archive_entry_symlink_l(struct archive_entry *,- const char **, size_t *, struct archive_string_conv *);-#define archive_entry_uname_l _archive_entry_uname_l-int _archive_entry_uname_l(struct archive_entry *,- const char **, size_t *, struct archive_string_conv *);-#define archive_entry_acl_text_l _archive_entry_acl_text_l-int _archive_entry_acl_text_l(struct archive_entry *, int,-const char **, size_t *, struct archive_string_conv *) __LA_DEPRECATED;-#define archive_entry_acl_to_text_l _archive_entry_acl_to_text_l-char *_archive_entry_acl_to_text_l(struct archive_entry *, ssize_t *, int,- struct archive_string_conv *);-#define archive_entry_acl_from_text_l _archive_entry_acl_from_text_l-int _archive_entry_acl_from_text_l(struct archive_entry *, const char* text,- int type, struct archive_string_conv *);-#define archive_entry_copy_gname_l _archive_entry_copy_gname_l-int _archive_entry_copy_gname_l(struct archive_entry *,- const char *, size_t, struct archive_string_conv *);-#define archive_entry_copy_hardlink_l _archive_entry_copy_hardlink_l-int _archive_entry_copy_hardlink_l(struct archive_entry *,- const char *, size_t, struct archive_string_conv *);-#define archive_entry_copy_link_l _archive_entry_copy_link_l-int _archive_entry_copy_link_l(struct archive_entry *,- const char *, size_t, struct archive_string_conv *);-#define archive_entry_copy_pathname_l _archive_entry_copy_pathname_l-int _archive_entry_copy_pathname_l(struct archive_entry *,- const char *, size_t, struct archive_string_conv *);-#define archive_entry_copy_symlink_l _archive_entry_copy_symlink_l-int _archive_entry_copy_symlink_l(struct archive_entry *,- const char *, size_t, struct archive_string_conv *);-#define archive_entry_copy_uname_l _archive_entry_copy_uname_l-int _archive_entry_copy_uname_l(struct archive_entry *,- const char *, size_t, struct archive_string_conv *);--#endif /* ARCHIVE_ENTRY_LOCALE_H_INCLUDED */
− c/archive_entry_private.h
@@ -1,200 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD: head/lib/libarchive/archive_entry_private.h 201096 2009-12-28 02:41:27Z kientzle $- */--#ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED-#define ARCHIVE_ENTRY_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--#include "archive_acl_private.h"-#include "archive_string.h"--struct ae_xattr {- struct ae_xattr *next;-- char *name;- void *value;- size_t size;-};--struct ae_sparse {- struct ae_sparse *next;-- int64_t offset;- int64_t length;-};--struct ae_digest {- unsigned char md5[16];- unsigned char rmd160[20];- unsigned char sha1[20];- unsigned char sha256[32];- unsigned char sha384[48];- unsigned char sha512[64];-};--/*- * Description of an archive entry.- *- * Basically, this is a "struct stat" with a few text fields added in.- *- * TODO: Add "comment", "charset", and possibly other entries- * that are supported by "pax interchange" format. However, GNU, ustar,- * cpio, and other variants don't support these features, so they're not an- * excruciatingly high priority right now.- *- * TODO: "pax interchange" format allows essentially arbitrary- * key/value attributes to be attached to any entry. Supporting- * such extensions may make this library useful for special- * applications (e.g., a package manager could attach special- * package-management attributes to each entry). There are tricky- * API issues involved, so this is not going to happen until- * there's a real demand for it.- *- * TODO: Design a good API for handling sparse files.- */-struct archive_entry {- struct archive *archive;-- /*- * Note that ae_stat.st_mode & AE_IFMT can be 0!- *- * This occurs when the actual file type of the object is not- * in the archive. For example, 'tar' archives store- * hardlinks without marking the type of the underlying- * object.- */-- /*- * We have a "struct aest" for holding file metadata rather than just- * a "struct stat" because on some platforms the "struct stat" has- * fields which are too narrow to hold the range of possible values;- * we don't want to lose information if we read an archive and write- * out another (e.g., in "tar -cf new.tar @old.tar").- *- * The "stat" pointer points to some form of platform-specific struct- * stat; it is declared as a void * rather than a struct stat * as- * some platforms have multiple varieties of stat structures.- */- void *stat;- int stat_valid; /* Set to 0 whenever a field in aest changes. */-- struct aest {- int64_t aest_atime;- uint32_t aest_atime_nsec;- int64_t aest_ctime;- uint32_t aest_ctime_nsec;- int64_t aest_mtime;- uint32_t aest_mtime_nsec;- int64_t aest_birthtime;- uint32_t aest_birthtime_nsec;- int64_t aest_gid;- int64_t aest_ino;- uint32_t aest_nlink;- uint64_t aest_size;- int64_t aest_uid;- /*- * Because converting between device codes and- * major/minor values is platform-specific and- * inherently a bit risky, we only do that conversion- * lazily. That way, we will do a better job of- * preserving information in those cases where no- * conversion is actually required.- */- int aest_dev_is_broken_down;- dev_t aest_dev;- dev_t aest_devmajor;- dev_t aest_devminor;- int aest_rdev_is_broken_down;- dev_t aest_rdev;- dev_t aest_rdevmajor;- dev_t aest_rdevminor;- } ae_stat;-- int ae_set; /* bitmap of fields that are currently set */-#define AE_SET_HARDLINK 1-#define AE_SET_SYMLINK 2-#define AE_SET_ATIME 4-#define AE_SET_CTIME 8-#define AE_SET_MTIME 16-#define AE_SET_BIRTHTIME 32-#define AE_SET_SIZE 64-#define AE_SET_INO 128-#define AE_SET_DEV 256-- /*- * Use aes here so that we get transparent mbs<->wcs conversions.- */- struct archive_mstring ae_fflags_text; /* Text fflags per fflagstostr(3) */- unsigned long ae_fflags_set; /* Bitmap fflags */- unsigned long ae_fflags_clear;- struct archive_mstring ae_gname; /* Name of owning group */- struct archive_mstring ae_hardlink; /* Name of target for hardlink */- struct archive_mstring ae_pathname; /* Name of entry */- struct archive_mstring ae_symlink; /* symlink contents */- struct archive_mstring ae_uname; /* Name of owner */-- /* Not used within libarchive; useful for some clients. */- struct archive_mstring ae_sourcepath; /* Path this entry is sourced from. */--#define AE_ENCRYPTION_NONE 0-#define AE_ENCRYPTION_DATA 1-#define AE_ENCRYPTION_METADATA 2- char encryption;- - void *mac_metadata;- size_t mac_metadata_size;-- /* Digest support. */- struct ae_digest digest;-- /* ACL support. */- struct archive_acl acl;-- /* extattr support. */- struct ae_xattr *xattr_head;- struct ae_xattr *xattr_p;-- /* sparse support. */- struct ae_sparse *sparse_head;- struct ae_sparse *sparse_tail;- struct ae_sparse *sparse_p;-- /* Miscellaneous. */- char strmode[12];-- /* Symlink type support */- int ae_symlink_type;-};--int-archive_entry_set_digest(struct archive_entry *entry, int type,- const unsigned char *digest);--#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
− c/archive_entry_sparse.c
@@ -1,156 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2010-2011 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_entry_private.h"--/*- * sparse handling- */--void-archive_entry_sparse_clear(struct archive_entry *entry)-{- struct ae_sparse *sp;-- while (entry->sparse_head != NULL) {- sp = entry->sparse_head->next;- free(entry->sparse_head);- entry->sparse_head = sp;- }- entry->sparse_tail = NULL;-}--void-archive_entry_sparse_add_entry(struct archive_entry *entry,- la_int64_t offset, la_int64_t length)-{- struct ae_sparse *sp;-- if (offset < 0 || length < 0)- /* Invalid value */- return;- if (offset > INT64_MAX - length ||- offset + length > archive_entry_size(entry))- /* A value of "length" parameter is too large. */- return;- if ((sp = entry->sparse_tail) != NULL) {- if (sp->offset + sp->length > offset)- /* Invalid value. */- return;- if (sp->offset + sp->length == offset) {- if (sp->offset + sp->length + length < 0)- /* A value of "length" parameter is- * too large. */- return;- /* Expand existing sparse block size. */- sp->length += length;- return;- }- }-- if ((sp = (struct ae_sparse *)malloc(sizeof(*sp))) == NULL)- /* XXX Error XXX */- return;-- sp->offset = offset;- sp->length = length;- sp->next = NULL;-- if (entry->sparse_head == NULL)- entry->sparse_head = entry->sparse_tail = sp;- else {- /* Add a new sparse block to the tail of list. */- if (entry->sparse_tail != NULL)- entry->sparse_tail->next = sp;- entry->sparse_tail = sp;- }-}---/*- * returns number of the sparse entries- */-int-archive_entry_sparse_count(struct archive_entry *entry)-{- struct ae_sparse *sp;- int count = 0;-- for (sp = entry->sparse_head; sp != NULL; sp = sp->next)- count++;-- /*- * Sanity check if this entry is exactly sparse.- * If amount of sparse blocks is just one and it indicates the whole- * file data, we should remove it and return zero.- */- if (count == 1) {- sp = entry->sparse_head;- if (sp->offset == 0 &&- sp->length >= archive_entry_size(entry)) {- count = 0;- archive_entry_sparse_clear(entry);- }- }-- return (count);-}--int-archive_entry_sparse_reset(struct archive_entry * entry)-{- entry->sparse_p = entry->sparse_head;-- return archive_entry_sparse_count(entry);-}--int-archive_entry_sparse_next(struct archive_entry * entry,- la_int64_t *offset, la_int64_t *length)-{- if (entry->sparse_p) {- *offset = entry->sparse_p->offset;- *length = entry->sparse_p->length;-- entry->sparse_p = entry->sparse_p->next;-- return (ARCHIVE_OK);- } else {- *offset = 0;- *length = 0;- return (ARCHIVE_WARN);- }-}--/*- * end of sparse handling- */
− c/archive_entry_stat.c
@@ -1,118 +0,0 @@-/*-- * 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_entry_stat.c 201100 2009-12-28 03:05:31Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif--#include "archive_entry.h"-#include "archive_entry_private.h"--const struct stat *-archive_entry_stat(struct archive_entry *entry)-{- struct stat *st;- if (entry->stat == NULL) {- entry->stat = calloc(1, sizeof(*st));- if (entry->stat == NULL)- return (NULL);- entry->stat_valid = 0;- }-- /*- * If none of the underlying fields have been changed, we- * don't need to regenerate. In theory, we could use a bitmap- * here to flag only those items that have changed, but the- * extra complexity probably isn't worth it. It will be very- * rare for anyone to change just one field then request a new- * stat structure.- */- if (entry->stat_valid)- return (entry->stat);-- st = entry->stat;- /*- * Use the public interfaces to extract items, so that- * the appropriate conversions get invoked.- */- st->st_atime = archive_entry_atime(entry);-#if HAVE_STRUCT_STAT_ST_BIRTHTIME- st->st_birthtime = archive_entry_birthtime(entry);-#endif- st->st_ctime = archive_entry_ctime(entry);- st->st_mtime = archive_entry_mtime(entry);- st->st_dev = archive_entry_dev(entry);- st->st_gid = (gid_t)archive_entry_gid(entry);- st->st_uid = (uid_t)archive_entry_uid(entry);- st->st_ino = (ino_t)archive_entry_ino64(entry);- st->st_nlink = archive_entry_nlink(entry);- st->st_rdev = archive_entry_rdev(entry);- st->st_size = (off_t)archive_entry_size(entry);- st->st_mode = archive_entry_mode(entry);-- /*- * On systems that support high-res timestamps, copy that- * information into struct stat.- */-#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC- st->st_atimespec.tv_nsec = archive_entry_atime_nsec(entry);- st->st_ctimespec.tv_nsec = archive_entry_ctime_nsec(entry);- st->st_mtimespec.tv_nsec = archive_entry_mtime_nsec(entry);-#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC- st->st_atim.tv_nsec = archive_entry_atime_nsec(entry);- st->st_ctim.tv_nsec = archive_entry_ctime_nsec(entry);- st->st_mtim.tv_nsec = archive_entry_mtime_nsec(entry);-#elif HAVE_STRUCT_STAT_ST_MTIME_N- st->st_atime_n = archive_entry_atime_nsec(entry);- st->st_ctime_n = archive_entry_ctime_nsec(entry);- st->st_mtime_n = archive_entry_mtime_nsec(entry);-#elif HAVE_STRUCT_STAT_ST_UMTIME- st->st_uatime = archive_entry_atime_nsec(entry) / 1000;- st->st_uctime = archive_entry_ctime_nsec(entry) / 1000;- st->st_umtime = archive_entry_mtime_nsec(entry) / 1000;-#elif HAVE_STRUCT_STAT_ST_MTIME_USEC- st->st_atime_usec = archive_entry_atime_nsec(entry) / 1000;- st->st_ctime_usec = archive_entry_ctime_nsec(entry) / 1000;- st->st_mtime_usec = archive_entry_mtime_nsec(entry) / 1000;-#endif-#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC- st->st_birthtimespec.tv_nsec = archive_entry_birthtime_nsec(entry);-#endif-- /*- * TODO: On Linux, store 32 or 64 here depending on whether- * the cached stat structure is a stat32 or a stat64. This- * will allow us to support both variants interchangeably.- */- entry->stat_valid = 1;-- return (st);-}
− c/archive_entry_strmode.c
@@ -1,87 +0,0 @@-/*-- * 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: src/lib/libarchive/archive_entry_strmode.c,v 1.4 2008/06/15 05:14:01 kientzle Exp $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive_entry.h"-#include "archive_entry_private.h"--const char *-archive_entry_strmode(struct archive_entry *entry)-{- static const mode_t permbits[] =- { 0400, 0200, 0100, 0040, 0020, 0010, 0004, 0002, 0001 };- char *bp = entry->strmode;- mode_t mode;- int i;-- /* Fill in a default string, then selectively override. */- strcpy(bp, "?rwxrwxrwx ");-- mode = archive_entry_mode(entry);- switch (archive_entry_filetype(entry)) {- case AE_IFREG: bp[0] = '-'; break;- case AE_IFBLK: bp[0] = 'b'; break;- case AE_IFCHR: bp[0] = 'c'; break;- case AE_IFDIR: bp[0] = 'd'; break;- case AE_IFLNK: bp[0] = 'l'; break;- case AE_IFSOCK: bp[0] = 's'; break;- case AE_IFIFO: bp[0] = 'p'; break;- default:- if (archive_entry_hardlink(entry) != NULL) {- bp[0] = 'h';- break;- }- }-- for (i = 0; i < 9; i++)- if (!(mode & permbits[i]))- bp[i+1] = '-';-- if (mode & S_ISUID) {- if (mode & 0100) bp[3] = 's';- else bp[3] = 'S';- }- if (mode & S_ISGID) {- if (mode & 0010) bp[6] = 's';- else bp[6] = 'S';- }- if (mode & S_ISVTX) {- if (mode & 0001) bp[9] = 't';- else bp[9] = 'T';- }- if (archive_entry_acl_types(entry) != 0)- bp[10] = '+';-- return (bp);-}
− c/archive_entry_xattr.c
@@ -1,156 +0,0 @@-/*-- * 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_entry_xattr.c 201096 2009-12-28 02:41:27Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_LINUX_FS_H-#include <linux/fs.h> /* for Linux file flags */-#endif-/*- * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.- * As the include guards don't agree, the order of include is important.- */-#ifdef HAVE_LINUX_EXT2_FS_H-#include <linux/ext2_fs.h> /* for Linux file flags */-#endif-#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)-#include <ext2fs/ext2_fs.h> /* for Linux file flags */-#endif-#include <stddef.h>-#include <stdio.h>-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_WCHAR_H-#include <wchar.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_entry_private.h"--/*- * extended attribute handling- */--void-archive_entry_xattr_clear(struct archive_entry *entry)-{- struct ae_xattr *xp;-- while (entry->xattr_head != NULL) {- xp = entry->xattr_head->next;- free(entry->xattr_head->name);- free(entry->xattr_head->value);- free(entry->xattr_head);- entry->xattr_head = xp;- }-- entry->xattr_head = NULL;-}--void-archive_entry_xattr_add_entry(struct archive_entry *entry,- const char *name, const void *value, size_t size)-{- struct ae_xattr *xp;-- if ((xp = (struct ae_xattr *)malloc(sizeof(struct ae_xattr))) == NULL)- __archive_errx(1, "Out of memory");-- if ((xp->name = strdup(name)) == NULL)- __archive_errx(1, "Out of memory");-- if ((xp->value = malloc(size)) != NULL) {- memcpy(xp->value, value, size);- xp->size = size;- } else- xp->size = 0;-- xp->next = entry->xattr_head;- entry->xattr_head = xp;-}---/*- * returns number of the extended attribute entries- */-int-archive_entry_xattr_count(struct archive_entry *entry)-{- struct ae_xattr *xp;- int count = 0;-- for (xp = entry->xattr_head; xp != NULL; xp = xp->next)- count++;-- return count;-}--int-archive_entry_xattr_reset(struct archive_entry * entry)-{- entry->xattr_p = entry->xattr_head;-- return archive_entry_xattr_count(entry);-}--int-archive_entry_xattr_next(struct archive_entry * entry,- const char **name, const void **value, size_t *size)-{- if (entry->xattr_p) {- *name = entry->xattr_p->name;- *value = entry->xattr_p->value;- *size = entry->xattr_p->size;-- entry->xattr_p = entry->xattr_p->next;-- return (ARCHIVE_OK);- } else {- *name = NULL;- *value = NULL;- *size = (size_t)0;- return (ARCHIVE_WARN);- }-}--/*- * end of xattr handling- */
− c/archive_getdate.c
@@ -1,1104 +0,0 @@-/*- * This code is in the public domain and has no copyright.- *- * This is a plain C recursive-descent translation of an old- * public-domain YACC grammar that has been used for parsing dates in- * very many open-source projects.- *- * Since the original authors were generous enough to donate their- * work to the public domain, I feel compelled to match their- * generosity.- *- * Tim Kientzle, February 2009.- */--/*- * Header comment from original getdate.y:- */--/*-** Originally written by Steven M. Bellovin <smb@research.att.com> while-** at the University of North Carolina at Chapel Hill. Later tweaked by-** a couple of people on Usenet. Completely overhauled by Rich $alz-** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;-**-** This grammar has 10 shift/reduce conflicts.-**-** This code is in the public domain and has no copyright.-*/--#include "archive_platform.h"-#ifdef __FreeBSD__-#include <sys/cdefs.h>-__FBSDID("$FreeBSD$");-#endif--#include <ctype.h>-#include <stdio.h>-#include <stdlib.h>-#include <string.h>-#include <time.h>--#define __LIBARCHIVE_BUILD 1-#include "archive_getdate.h"--/* Basic time units. */-#define EPOCH 1970-#define MINUTE (60L)-#define HOUR (60L * MINUTE)-#define DAY (24L * HOUR)--/* Daylight-savings mode: on, off, or not yet known. */-enum DSTMODE { DSTon, DSToff, DSTmaybe };-/* Meridian: am or pm. */-enum { tAM, tPM };-/* Token types returned by nexttoken() */-enum { tAGO = 260, tDAY, tDAYZONE, tAMPM, tMONTH, tMONTH_UNIT, tSEC_UNIT,- tUNUMBER, tZONE, tDST };-struct token { int token; time_t value; };--/*- * Parser state.- */-struct gdstate {- struct token *tokenp; /* Pointer to next token. */- /* HaveXxxx counts how many of this kind of phrase we've seen;- * it's a fatal error to have more than one time, zone, day,- * or date phrase. */- int HaveYear;- int HaveMonth;- int HaveDay;- int HaveWeekDay; /* Day of week */- int HaveTime; /* Hour/minute/second */- int HaveZone; /* timezone and/or DST info */- int HaveRel; /* time offset; we can have more than one */- /* Absolute time values. */- time_t Timezone; /* Seconds offset from GMT */- time_t Day;- time_t Hour;- time_t Minutes;- time_t Month;- time_t Seconds;- time_t Year;- /* DST selection */- enum DSTMODE DSTmode;- /* Day of week accounting, e.g., "3rd Tuesday" */- time_t DayOrdinal; /* "3" in "3rd Tuesday" */- time_t DayNumber; /* "Tuesday" in "3rd Tuesday" */- /* Relative time values: hour/day/week offsets are measured in- * seconds, month/year are counted in months. */- time_t RelMonth;- time_t RelSeconds;-};--/*- * A series of functions that recognize certain common time phrases.- * Each function returns 1 if it managed to make sense of some of the- * tokens, zero otherwise.- */--/*- * hour:minute or hour:minute:second with optional AM, PM, or numeric- * timezone offset- */-static int-timephrase(struct gdstate *gds)-{- if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == ':'- && gds->tokenp[2].token == tUNUMBER- && gds->tokenp[3].token == ':'- && gds->tokenp[4].token == tUNUMBER) {- /* "12:14:18" or "22:08:07" */- ++gds->HaveTime;- gds->Hour = gds->tokenp[0].value;- gds->Minutes = gds->tokenp[2].value;- gds->Seconds = gds->tokenp[4].value;- gds->tokenp += 5;- }- else if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == ':'- && gds->tokenp[2].token == tUNUMBER) {- /* "12:14" or "22:08" */- ++gds->HaveTime;- gds->Hour = gds->tokenp[0].value;- gds->Minutes = gds->tokenp[2].value;- gds->Seconds = 0;- gds->tokenp += 3;- }- else if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == tAMPM) {- /* "7" is a time if it's followed by "am" or "pm" */- ++gds->HaveTime;- gds->Hour = gds->tokenp[0].value;- gds->Minutes = gds->Seconds = 0;- /* We'll handle the AM/PM below. */- gds->tokenp += 1;- } else {- /* We can't handle this. */- return 0;- }-- if (gds->tokenp[0].token == tAMPM) {- /* "7:12pm", "12:20:13am" */- if (gds->Hour == 12)- gds->Hour = 0;- if (gds->tokenp[0].value == tPM)- gds->Hour += 12;- gds->tokenp += 1;- }- if (gds->tokenp[0].token == '+'- && gds->tokenp[1].token == tUNUMBER) {- /* "7:14+0700" */- gds->HaveZone++;- gds->DSTmode = DSToff;- gds->Timezone = - ((gds->tokenp[1].value / 100) * HOUR- + (gds->tokenp[1].value % 100) * MINUTE);- gds->tokenp += 2;- }- if (gds->tokenp[0].token == '-'- && gds->tokenp[1].token == tUNUMBER) {- /* "19:14:12-0530" */- gds->HaveZone++;- gds->DSTmode = DSToff;- gds->Timezone = + ((gds->tokenp[1].value / 100) * HOUR- + (gds->tokenp[1].value % 100) * MINUTE);- gds->tokenp += 2;- }- return 1;-}--/*- * Timezone name, possibly including DST.- */-static int-zonephrase(struct gdstate *gds)-{- if (gds->tokenp[0].token == tZONE- && gds->tokenp[1].token == tDST) {- gds->HaveZone++;- gds->Timezone = gds->tokenp[0].value;- gds->DSTmode = DSTon;- gds->tokenp += 1;- return 1;- }-- if (gds->tokenp[0].token == tZONE) {- gds->HaveZone++;- gds->Timezone = gds->tokenp[0].value;- gds->DSTmode = DSToff;- gds->tokenp += 1;- return 1;- }-- if (gds->tokenp[0].token == tDAYZONE) {- gds->HaveZone++;- gds->Timezone = gds->tokenp[0].value;- gds->DSTmode = DSTon;- gds->tokenp += 1;- return 1;- }- return 0;-}--/*- * Year/month/day in various combinations.- */-static int-datephrase(struct gdstate *gds)-{- if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == '/'- && gds->tokenp[2].token == tUNUMBER- && gds->tokenp[3].token == '/'- && gds->tokenp[4].token == tUNUMBER) {- gds->HaveYear++;- gds->HaveMonth++;- gds->HaveDay++;- if (gds->tokenp[0].value >= 13) {- /* First number is big: 2004/01/29, 99/02/17 */- gds->Year = gds->tokenp[0].value;- gds->Month = gds->tokenp[2].value;- gds->Day = gds->tokenp[4].value;- } else if ((gds->tokenp[4].value >= 13)- || (gds->tokenp[2].value >= 13)) {- /* Last number is big: 01/07/98 */- /* Middle number is big: 01/29/04 */- gds->Month = gds->tokenp[0].value;- gds->Day = gds->tokenp[2].value;- gds->Year = gds->tokenp[4].value;- } else {- /* No significant clues: 02/03/04 */- gds->Month = gds->tokenp[0].value;- gds->Day = gds->tokenp[2].value;- gds->Year = gds->tokenp[4].value;- }- gds->tokenp += 5;- return 1;- }-- if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == '/'- && gds->tokenp[2].token == tUNUMBER) {- /* "1/15" */- gds->HaveMonth++;- gds->HaveDay++;- gds->Month = gds->tokenp[0].value;- gds->Day = gds->tokenp[2].value;- gds->tokenp += 3;- return 1;- }-- if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == '-'- && gds->tokenp[2].token == tUNUMBER- && gds->tokenp[3].token == '-'- && gds->tokenp[4].token == tUNUMBER) {- /* ISO 8601 format. yyyy-mm-dd. */- gds->HaveYear++;- gds->HaveMonth++;- gds->HaveDay++;- gds->Year = gds->tokenp[0].value;- gds->Month = gds->tokenp[2].value;- gds->Day = gds->tokenp[4].value;- gds->tokenp += 5;- return 1;- }-- if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == '-'- && gds->tokenp[2].token == tMONTH- && gds->tokenp[3].token == '-'- && gds->tokenp[4].token == tUNUMBER) {- gds->HaveYear++;- gds->HaveMonth++;- gds->HaveDay++;- if (gds->tokenp[0].value > 31) {- /* e.g. 1992-Jun-17 */- gds->Year = gds->tokenp[0].value;- gds->Month = gds->tokenp[2].value;- gds->Day = gds->tokenp[4].value;- } else {- /* e.g. 17-JUN-1992. */- gds->Day = gds->tokenp[0].value;- gds->Month = gds->tokenp[2].value;- gds->Year = gds->tokenp[4].value;- }- gds->tokenp += 5;- return 1;- }-- if (gds->tokenp[0].token == tMONTH- && gds->tokenp[1].token == tUNUMBER- && gds->tokenp[2].token == ','- && gds->tokenp[3].token == tUNUMBER) {- /* "June 17, 2001" */- gds->HaveYear++;- gds->HaveMonth++;- gds->HaveDay++;- gds->Month = gds->tokenp[0].value;- gds->Day = gds->tokenp[1].value;- gds->Year = gds->tokenp[3].value;- gds->tokenp += 4;- return 1;- }-- if (gds->tokenp[0].token == tMONTH- && gds->tokenp[1].token == tUNUMBER) {- /* "May 3" */- gds->HaveMonth++;- gds->HaveDay++;- gds->Month = gds->tokenp[0].value;- gds->Day = gds->tokenp[1].value;- gds->tokenp += 2;- return 1;- }-- if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == tMONTH- && gds->tokenp[2].token == tUNUMBER) {- /* "12 Sept 1997" */- gds->HaveYear++;- gds->HaveMonth++;- gds->HaveDay++;- gds->Day = gds->tokenp[0].value;- gds->Month = gds->tokenp[1].value;- gds->Year = gds->tokenp[2].value;- gds->tokenp += 3;- return 1;- }-- if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == tMONTH) {- /* "12 Sept" */- gds->HaveMonth++;- gds->HaveDay++;- gds->Day = gds->tokenp[0].value;- gds->Month = gds->tokenp[1].value;- gds->tokenp += 2;- return 1;- }-- return 0;-}--/*- * Relative time phrase: "tomorrow", "yesterday", "+1 hour", etc.- */-static int-relunitphrase(struct gdstate *gds)-{- if (gds->tokenp[0].token == '-'- && gds->tokenp[1].token == tUNUMBER- && gds->tokenp[2].token == tSEC_UNIT) {- /* "-3 hours" */- gds->HaveRel++;- gds->RelSeconds -= gds->tokenp[1].value * gds->tokenp[2].value;- gds->tokenp += 3;- return 1;- }- if (gds->tokenp[0].token == '+'- && gds->tokenp[1].token == tUNUMBER- && gds->tokenp[2].token == tSEC_UNIT) {- /* "+1 minute" */- gds->HaveRel++;- gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value;- gds->tokenp += 3;- return 1;- }- if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == tSEC_UNIT) {- /* "1 day" */- gds->HaveRel++;- gds->RelSeconds += gds->tokenp[0].value * gds->tokenp[1].value;- gds->tokenp += 2;- return 1;- }- if (gds->tokenp[0].token == '-'- && gds->tokenp[1].token == tUNUMBER- && gds->tokenp[2].token == tMONTH_UNIT) {- /* "-3 months" */- gds->HaveRel++;- gds->RelMonth -= gds->tokenp[1].value * gds->tokenp[2].value;- gds->tokenp += 3;- return 1;- }- if (gds->tokenp[0].token == '+'- && gds->tokenp[1].token == tUNUMBER- && gds->tokenp[2].token == tMONTH_UNIT) {- /* "+5 years" */- gds->HaveRel++;- gds->RelMonth += gds->tokenp[1].value * gds->tokenp[2].value;- gds->tokenp += 3;- return 1;- }- if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == tMONTH_UNIT) {- /* "2 years" */- gds->HaveRel++;- gds->RelMonth += gds->tokenp[0].value * gds->tokenp[1].value;- gds->tokenp += 2;- return 1;- }- if (gds->tokenp[0].token == tSEC_UNIT) {- /* "now", "tomorrow" */- gds->HaveRel++;- gds->RelSeconds += gds->tokenp[0].value;- gds->tokenp += 1;- return 1;- }- if (gds->tokenp[0].token == tMONTH_UNIT) {- /* "month" */- gds->HaveRel++;- gds->RelMonth += gds->tokenp[0].value;- gds->tokenp += 1;- return 1;- }- return 0;-}--/*- * Day of the week specification.- */-static int-dayphrase(struct gdstate *gds)-{- if (gds->tokenp[0].token == tDAY) {- /* "tues", "wednesday," */- gds->HaveWeekDay++;- gds->DayOrdinal = 1;- gds->DayNumber = gds->tokenp[0].value;- gds->tokenp += 1;- if (gds->tokenp[0].token == ',')- gds->tokenp += 1;- return 1;- }- if (gds->tokenp[0].token == tUNUMBER- && gds->tokenp[1].token == tDAY) {- /* "second tues" "3 wed" */- gds->HaveWeekDay++;- gds->DayOrdinal = gds->tokenp[0].value;- gds->DayNumber = gds->tokenp[1].value;- gds->tokenp += 2;- return 1;- }- return 0;-}--/*- * Try to match a phrase using one of the above functions.- * This layer also deals with a couple of generic issues.- */-static int-phrase(struct gdstate *gds)-{- if (timephrase(gds))- return 1;- if (zonephrase(gds))- return 1;- if (datephrase(gds))- return 1;- if (dayphrase(gds))- return 1;- if (relunitphrase(gds)) {- if (gds->tokenp[0].token == tAGO) {- gds->RelSeconds = -gds->RelSeconds;- gds->RelMonth = -gds->RelMonth;- gds->tokenp += 1;- }- return 1;- }-- /* Bare numbers sometimes have meaning. */- if (gds->tokenp[0].token == tUNUMBER) {- if (gds->HaveTime && !gds->HaveYear && !gds->HaveRel) {- gds->HaveYear++;- gds->Year = gds->tokenp[0].value;- gds->tokenp += 1;- return 1;- }-- if(gds->tokenp[0].value > 10000) {- /* "20040301" */- gds->HaveYear++;- gds->HaveMonth++;- gds->HaveDay++;- gds->Day= (gds->tokenp[0].value)%100;- gds->Month= (gds->tokenp[0].value/100)%100;- gds->Year = gds->tokenp[0].value/10000;- gds->tokenp += 1;- return 1;- }-- if (gds->tokenp[0].value < 24) {- gds->HaveTime++;- gds->Hour = gds->tokenp[0].value;- gds->Minutes = 0;- gds->Seconds = 0;- gds->tokenp += 1;- return 1;- }-- if ((gds->tokenp[0].value / 100 < 24)- && (gds->tokenp[0].value % 100 < 60)) {- /* "513" is same as "5:13" */- gds->Hour = gds->tokenp[0].value / 100;- gds->Minutes = gds->tokenp[0].value % 100;- gds->Seconds = 0;- gds->tokenp += 1;- return 1;- }- }-- return 0;-}--/*- * A dictionary of time words.- */-static struct LEXICON {- size_t abbrev;- const char *name;- int type;- time_t value;-} const TimeWords[] = {- /* am/pm */- { 0, "am", tAMPM, tAM },- { 0, "pm", tAMPM, tPM },-- /* Month names. */- { 3, "january", tMONTH, 1 },- { 3, "february", tMONTH, 2 },- { 3, "march", tMONTH, 3 },- { 3, "april", tMONTH, 4 },- { 3, "may", tMONTH, 5 },- { 3, "june", tMONTH, 6 },- { 3, "july", tMONTH, 7 },- { 3, "august", tMONTH, 8 },- { 3, "september", tMONTH, 9 },- { 3, "october", tMONTH, 10 },- { 3, "november", tMONTH, 11 },- { 3, "december", tMONTH, 12 },-- /* Days of the week. */- { 2, "sunday", tDAY, 0 },- { 3, "monday", tDAY, 1 },- { 2, "tuesday", tDAY, 2 },- { 3, "wednesday", tDAY, 3 },- { 2, "thursday", tDAY, 4 },- { 2, "friday", tDAY, 5 },- { 2, "saturday", tDAY, 6 },-- /* Timezones: Offsets are in seconds. */- { 0, "gmt", tZONE, 0*HOUR }, /* Greenwich Mean */- { 0, "ut", tZONE, 0*HOUR }, /* Universal (Coordinated) */- { 0, "utc", tZONE, 0*HOUR },- { 0, "wet", tZONE, 0*HOUR }, /* Western European */- { 0, "bst", tDAYZONE, 0*HOUR }, /* British Summer */- { 0, "wat", tZONE, 1*HOUR }, /* West Africa */- { 0, "at", tZONE, 2*HOUR }, /* Azores */- /* { 0, "bst", tZONE, 3*HOUR }, */ /* Brazil Standard: Conflict */- /* { 0, "gst", tZONE, 3*HOUR }, */ /* Greenland Standard: Conflict*/- { 0, "nft", tZONE, 3*HOUR+30*MINUTE }, /* Newfoundland */- { 0, "nst", tZONE, 3*HOUR+30*MINUTE }, /* Newfoundland Standard */- { 0, "ndt", tDAYZONE, 3*HOUR+30*MINUTE }, /* Newfoundland Daylight */- { 0, "ast", tZONE, 4*HOUR }, /* Atlantic Standard */- { 0, "adt", tDAYZONE, 4*HOUR }, /* Atlantic Daylight */- { 0, "est", tZONE, 5*HOUR }, /* Eastern Standard */- { 0, "edt", tDAYZONE, 5*HOUR }, /* Eastern Daylight */- { 0, "cst", tZONE, 6*HOUR }, /* Central Standard */- { 0, "cdt", tDAYZONE, 6*HOUR }, /* Central Daylight */- { 0, "mst", tZONE, 7*HOUR }, /* Mountain Standard */- { 0, "mdt", tDAYZONE, 7*HOUR }, /* Mountain Daylight */- { 0, "pst", tZONE, 8*HOUR }, /* Pacific Standard */- { 0, "pdt", tDAYZONE, 8*HOUR }, /* Pacific Daylight */- { 0, "yst", tZONE, 9*HOUR }, /* Yukon Standard */- { 0, "ydt", tDAYZONE, 9*HOUR }, /* Yukon Daylight */- { 0, "hst", tZONE, 10*HOUR }, /* Hawaii Standard */- { 0, "hdt", tDAYZONE, 10*HOUR }, /* Hawaii Daylight */- { 0, "cat", tZONE, 10*HOUR }, /* Central Alaska */- { 0, "ahst", tZONE, 10*HOUR }, /* Alaska-Hawaii Standard */- { 0, "nt", tZONE, 11*HOUR }, /* Nome */- { 0, "idlw", tZONE, 12*HOUR }, /* Intl Date Line West */- { 0, "cet", tZONE, -1*HOUR }, /* Central European */- { 0, "met", tZONE, -1*HOUR }, /* Middle European */- { 0, "mewt", tZONE, -1*HOUR }, /* Middle European Winter */- { 0, "mest", tDAYZONE, -1*HOUR }, /* Middle European Summer */- { 0, "swt", tZONE, -1*HOUR }, /* Swedish Winter */- { 0, "sst", tDAYZONE, -1*HOUR }, /* Swedish Summer */- { 0, "fwt", tZONE, -1*HOUR }, /* French Winter */- { 0, "fst", tDAYZONE, -1*HOUR }, /* French Summer */- { 0, "eet", tZONE, -2*HOUR }, /* Eastern Eur, USSR Zone 1 */- { 0, "bt", tZONE, -3*HOUR }, /* Baghdad, USSR Zone 2 */- { 0, "it", tZONE, -3*HOUR-30*MINUTE },/* Iran */- { 0, "zp4", tZONE, -4*HOUR }, /* USSR Zone 3 */- { 0, "zp5", tZONE, -5*HOUR }, /* USSR Zone 4 */- { 0, "ist", tZONE, -5*HOUR-30*MINUTE },/* Indian Standard */- { 0, "zp6", tZONE, -6*HOUR }, /* USSR Zone 5 */- /* { 0, "nst", tZONE, -6.5*HOUR }, */ /* North Sumatra: Conflict */- /* { 0, "sst", tZONE, -7*HOUR }, */ /* So Sumatra, USSR 6: Conflict */- { 0, "wast", tZONE, -7*HOUR }, /* West Australian Standard */- { 0, "wadt", tDAYZONE, -7*HOUR }, /* West Australian Daylight */- { 0, "jt", tZONE, -7*HOUR-30*MINUTE },/* Java (3pm in Cronusland!)*/- { 0, "cct", tZONE, -8*HOUR }, /* China Coast, USSR Zone 7 */- { 0, "jst", tZONE, -9*HOUR }, /* Japan Std, USSR Zone 8 */- { 0, "cast", tZONE, -9*HOUR-30*MINUTE },/* Ctrl Australian Std */- { 0, "cadt", tDAYZONE, -9*HOUR-30*MINUTE },/* Ctrl Australian Daylt */- { 0, "east", tZONE, -10*HOUR }, /* Eastern Australian Std */- { 0, "eadt", tDAYZONE, -10*HOUR }, /* Eastern Australian Daylt */- { 0, "gst", tZONE, -10*HOUR }, /* Guam Std, USSR Zone 9 */- { 0, "nzt", tZONE, -12*HOUR }, /* New Zealand */- { 0, "nzst", tZONE, -12*HOUR }, /* New Zealand Standard */- { 0, "nzdt", tDAYZONE, -12*HOUR }, /* New Zealand Daylight */- { 0, "idle", tZONE, -12*HOUR }, /* Intl Date Line East */-- { 0, "dst", tDST, 0 },-- /* Time units. */- { 4, "years", tMONTH_UNIT, 12 },- { 5, "months", tMONTH_UNIT, 1 },- { 9, "fortnights", tSEC_UNIT, 14 * DAY },- { 4, "weeks", tSEC_UNIT, 7 * DAY },- { 3, "days", tSEC_UNIT, DAY },- { 4, "hours", tSEC_UNIT, HOUR },- { 3, "minutes", tSEC_UNIT, MINUTE },- { 3, "seconds", tSEC_UNIT, 1 },-- /* Relative-time words. */- { 0, "tomorrow", tSEC_UNIT, DAY },- { 0, "yesterday", tSEC_UNIT, -DAY },- { 0, "today", tSEC_UNIT, 0 },- { 0, "now", tSEC_UNIT, 0 },- { 0, "last", tUNUMBER, -1 },- { 0, "this", tSEC_UNIT, 0 },- { 0, "next", tUNUMBER, 2 },- { 0, "first", tUNUMBER, 1 },- { 0, "1st", tUNUMBER, 1 },-/* { 0, "second", tUNUMBER, 2 }, */- { 0, "2nd", tUNUMBER, 2 },- { 0, "third", tUNUMBER, 3 },- { 0, "3rd", tUNUMBER, 3 },- { 0, "fourth", tUNUMBER, 4 },- { 0, "4th", tUNUMBER, 4 },- { 0, "fifth", tUNUMBER, 5 },- { 0, "5th", tUNUMBER, 5 },- { 0, "sixth", tUNUMBER, 6 },- { 0, "seventh", tUNUMBER, 7 },- { 0, "eighth", tUNUMBER, 8 },- { 0, "ninth", tUNUMBER, 9 },- { 0, "tenth", tUNUMBER, 10 },- { 0, "eleventh", tUNUMBER, 11 },- { 0, "twelfth", tUNUMBER, 12 },- { 0, "ago", tAGO, 1 },-- /* Military timezones. */- { 0, "a", tZONE, 1*HOUR },- { 0, "b", tZONE, 2*HOUR },- { 0, "c", tZONE, 3*HOUR },- { 0, "d", tZONE, 4*HOUR },- { 0, "e", tZONE, 5*HOUR },- { 0, "f", tZONE, 6*HOUR },- { 0, "g", tZONE, 7*HOUR },- { 0, "h", tZONE, 8*HOUR },- { 0, "i", tZONE, 9*HOUR },- { 0, "k", tZONE, 10*HOUR },- { 0, "l", tZONE, 11*HOUR },- { 0, "m", tZONE, 12*HOUR },- { 0, "n", tZONE, -1*HOUR },- { 0, "o", tZONE, -2*HOUR },- { 0, "p", tZONE, -3*HOUR },- { 0, "q", tZONE, -4*HOUR },- { 0, "r", tZONE, -5*HOUR },- { 0, "s", tZONE, -6*HOUR },- { 0, "t", tZONE, -7*HOUR },- { 0, "u", tZONE, -8*HOUR },- { 0, "v", tZONE, -9*HOUR },- { 0, "w", tZONE, -10*HOUR },- { 0, "x", tZONE, -11*HOUR },- { 0, "y", tZONE, -12*HOUR },- { 0, "z", tZONE, 0*HOUR },-- /* End of table. */- { 0, NULL, 0, 0 }-};--/*- * Year is either:- * = A number from 0 to 99, which means a year from 1970 to 2069, or- * = The actual year (>=100).- */-static time_t-Convert(time_t Month, time_t Day, time_t Year,- time_t Hours, time_t Minutes, time_t Seconds,- time_t Timezone, enum DSTMODE DSTmode)-{- signed char DaysInMonth[12] = {- 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31- };- time_t Julian;- int i;- struct tm *ltime;-#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)- struct tm tmbuf;-#endif-- if (Year < 69)- Year += 2000;- else if (Year < 100)- Year += 1900;- DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)- ? 29 : 28;- /* Checking for 2038 bogusly assumes that time_t is 32 bits. But- I'm too lazy to try to check for time_t overflow in another way. */- if (Year < EPOCH || Year >= 2038- || Month < 1 || Month > 12- /* Lint fluff: "conversion from long may lose accuracy" */- || Day < 1 || Day > DaysInMonth[(int)--Month]- || Hours < 0 || Hours > 23- || Minutes < 0 || Minutes > 59- || Seconds < 0 || Seconds > 59)- return -1;-- Julian = Day - 1;- for (i = 0; i < Month; i++)- Julian += DaysInMonth[i];- for (i = EPOCH; i < Year; i++)- Julian += 365 + (i % 4 == 0);- Julian *= DAY;- Julian += Timezone;- Julian += Hours * HOUR + Minutes * MINUTE + Seconds;-#if defined(HAVE_LOCALTIME_S)- ltime = localtime_s(&tmbuf, &Julian) ? NULL : &tmbuf;-#elif defined(HAVE_LOCALTIME_R)- ltime = localtime_r(&Julian, &tmbuf);-#else- ltime = localtime(&Julian);-#endif- if (DSTmode == DSTon- || (DSTmode == DSTmaybe && ltime->tm_isdst))- Julian -= HOUR;- return Julian;-}--static time_t-DSTcorrect(time_t Start, time_t Future)-{- time_t StartDay;- time_t FutureDay;- struct tm *ltime;-#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)- struct tm tmbuf;-#endif-#if defined(HAVE_LOCALTIME_S)- ltime = localtime_s(&tmbuf, &Start) ? NULL : &tmbuf;-#elif defined(HAVE_LOCALTIME_R)- ltime = localtime_r(&Start, &tmbuf);-#else- ltime = localtime(&Start);-#endif- StartDay = (ltime->tm_hour + 1) % 24;-#if defined(HAVE_LOCALTIME_S)- ltime = localtime_s(&tmbuf, &Future) ? NULL : &tmbuf;-#elif defined(HAVE_LOCALTIME_R)- ltime = localtime_r(&Future, &tmbuf);-#else- ltime = localtime(&Future);-#endif- FutureDay = (ltime->tm_hour + 1) % 24;- return (Future - Start) + (StartDay - FutureDay) * HOUR;-}---static time_t-RelativeDate(time_t Start, time_t zone, int dstmode,- time_t DayOrdinal, time_t DayNumber)-{- struct tm *tm;- time_t t, now;-#if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S)- struct tm tmbuf;-#endif-- t = Start - zone;-#if defined(HAVE_GMTIME_S)- tm = gmtime_s(&tmbuf, &t) ? NULL : &tmbuf;-#elif defined(HAVE_GMTIME_R)- tm = gmtime_r(&t, &tmbuf);-#else- tm = gmtime(&t);-#endif- now = Start;- now += DAY * ((DayNumber - tm->tm_wday + 7) % 7);- now += 7 * DAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);- if (dstmode == DSTmaybe)- return DSTcorrect(Start, now);- return now - Start;-}---static time_t-RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)-{- struct tm *tm;- time_t Month;- time_t Year;-#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)- struct tm tmbuf;-#endif-- if (RelMonth == 0)- return 0;-#if defined(HAVE_LOCALTIME_S)- tm = localtime_s(&tmbuf, &Start) ? NULL : &tmbuf;-#elif defined(HAVE_LOCALTIME_R)- tm = localtime_r(&Start, &tmbuf);-#else- tm = localtime(&Start);-#endif- Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;- Year = Month / 12;- Month = Month % 12 + 1;- return DSTcorrect(Start,- Convert(Month, (time_t)tm->tm_mday, Year,- (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,- Timezone, DSTmaybe));-}--/*- * Tokenizer.- */-static int-nexttoken(const char **in, time_t *value)-{- char c;- char buff[64];-- for ( ; ; ) {- while (isspace((unsigned char)**in))- ++*in;-- /* Skip parenthesized comments. */- if (**in == '(') {- int Count = 0;- do {- c = *(*in)++;- if (c == '\0')- return c;- if (c == '(')- Count++;- else if (c == ')')- Count--;- } while (Count > 0);- continue;- }-- /* Try the next token in the word table first. */- /* This allows us to match "2nd", for example. */- {- const char *src = *in;- const struct LEXICON *tp;- unsigned i = 0;-- /* Force to lowercase and strip '.' characters. */- while (*src != '\0'- && (isalnum((unsigned char)*src) || *src == '.')- && i < sizeof(buff)-1) {- if (*src != '.') {- if (isupper((unsigned char)*src))- buff[i++] = tolower((unsigned char)*src);- else- buff[i++] = *src;- }- src++;- }- buff[i] = '\0';-- /*- * Find the first match. If the word can be- * abbreviated, make sure we match at least- * the minimum abbreviation.- */- for (tp = TimeWords; tp->name; tp++) {- size_t abbrev = tp->abbrev;- if (abbrev == 0)- abbrev = strlen(tp->name);- if (strlen(buff) >= abbrev- && strncmp(tp->name, buff, strlen(buff))- == 0) {- /* Skip over token. */- *in = src;- /* Return the match. */- *value = tp->value;- return tp->type;- }- }- }-- /*- * Not in the word table, maybe it's a number. Note:- * Because '-' and '+' have other special meanings, I- * don't deal with signed numbers here.- */- if (isdigit((unsigned char)(c = **in))) {- for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )- *value = 10 * *value + c - '0';- (*in)--;- return (tUNUMBER);- }-- return *(*in)++;- }-}--#define TM_YEAR_ORIGIN 1900--/* Yield A - B, measured in seconds. */-static long-difftm (struct tm *a, struct tm *b)-{- int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);- int by = b->tm_year + (TM_YEAR_ORIGIN - 1);- int days = (- /* difference in day of year */- a->tm_yday - b->tm_yday- /* + intervening leap days */- + ((ay >> 2) - (by >> 2))- - (ay/100 - by/100)- + ((ay/100 >> 2) - (by/100 >> 2))- /* + difference in years * 365 */- + (long)(ay-by) * 365- );- return (days * DAY + (a->tm_hour - b->tm_hour) * HOUR- + (a->tm_min - b->tm_min) * MINUTE- + (a->tm_sec - b->tm_sec));-}--/*- *- * The public function.- *- * TODO: tokens[] array should be dynamically sized.- */-time_t-__archive_get_date(time_t now, const char *p)-{- struct token tokens[256];- struct gdstate _gds;- struct token *lasttoken;- struct gdstate *gds;- struct tm local, *tm;- struct tm gmt, *gmt_ptr;- time_t Start;- time_t tod;- long tzone;-- /* Clear out the parsed token array. */- memset(tokens, 0, sizeof(tokens));- /* Initialize the parser state. */- memset(&_gds, 0, sizeof(_gds));- gds = &_gds;-- /* Look up the current time. */-#if defined(HAVE_LOCALTIME_S)- tm = localtime_s(&local, &now) ? NULL : &local;-#elif defined(HAVE_LOCALTIME_R)- tm = localtime_r(&now, &local);-#else- memset(&local, 0, sizeof(local));- tm = localtime(&now);-#endif- if (tm == NULL)- return -1;-#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S)- local = *tm;-#endif-- /* Look up UTC if we can and use that to determine the current- * timezone offset. */-#if defined(HAVE_GMTIME_S)- gmt_ptr = gmtime_s(&gmt, &now) ? NULL : &gmt;-#elif defined(HAVE_GMTIME_R)- gmt_ptr = gmtime_r(&now, &gmt);-#else- memset(&gmt, 0, sizeof(gmt));- gmt_ptr = gmtime(&now);- if (gmt_ptr != NULL) {- /* Copy, in case localtime and gmtime use the same buffer. */- gmt = *gmt_ptr;- }-#endif- if (gmt_ptr != NULL)- tzone = difftm (&gmt, &local);- else- /* This system doesn't understand timezones; fake it. */- tzone = 0;- if(local.tm_isdst)- tzone += HOUR;-- /* Tokenize the input string. */- lasttoken = tokens;- while ((lasttoken->token = nexttoken(&p, &lasttoken->value)) != 0) {- ++lasttoken;- if (lasttoken > tokens + 255)- return -1;- }- gds->tokenp = tokens;-- /* Match phrases until we run out of input tokens. */- while (gds->tokenp < lasttoken) {- if (!phrase(gds))- return -1;- }-- /* Use current local timezone if none was specified. */- if (!gds->HaveZone) {- gds->Timezone = tzone;- gds->DSTmode = DSTmaybe;- }-- /* If a timezone was specified, use that for generating the default- * time components instead of the local timezone. */- if (gds->HaveZone && gmt_ptr != NULL) {- now -= gds->Timezone;-#if defined(HAVE_GMTIME_S)- gmt_ptr = gmtime_s(&gmt, &now) ? NULL : &gmt;-#elif defined(HAVE_GMTIME_R)- gmt_ptr = gmtime_r(&now, &gmt);-#else- gmt_ptr = gmtime(&now);-#endif- if (gmt_ptr != NULL)- local = *gmt_ptr;- now += gds->Timezone;- }-- if (!gds->HaveYear)- gds->Year = local.tm_year + 1900;- if (!gds->HaveMonth)- gds->Month = local.tm_mon + 1;- if (!gds->HaveDay)- gds->Day = local.tm_mday;- /* Note: No default for hour/min/sec; a specifier that just- * gives date always refers to 00:00 on that date. */-- /* If we saw more than one time, timezone, weekday, year, month,- * or day, then give up. */- if (gds->HaveTime > 1 || gds->HaveZone > 1 || gds->HaveWeekDay > 1- || gds->HaveYear > 1 || gds->HaveMonth > 1 || gds->HaveDay > 1)- return -1;-- /* Compute an absolute time based on whatever absolute information- * we collected. */- if (gds->HaveYear || gds->HaveMonth || gds->HaveDay- || gds->HaveTime || gds->HaveWeekDay) {- Start = Convert(gds->Month, gds->Day, gds->Year,- gds->Hour, gds->Minutes, gds->Seconds,- gds->Timezone, gds->DSTmode);- if (Start < 0)- return -1;- } else {- Start = now;- if (!gds->HaveRel)- Start -= local.tm_hour * HOUR + local.tm_min * MINUTE- + local.tm_sec;- }-- /* Add the relative offset. */- Start += gds->RelSeconds;- Start += RelativeMonth(Start, gds->Timezone, gds->RelMonth);-- /* Adjust for day-of-week offsets. */- if (gds->HaveWeekDay- && !(gds->HaveYear || gds->HaveMonth || gds->HaveDay)) {- tod = RelativeDate(Start, gds->Timezone,- gds->DSTmode, gds->DayOrdinal, gds->DayNumber);- Start += tod;- }-- /* -1 is an error indicator, so return 0 instead of -1 if- * that's the actual time. */- return Start == -1 ? 0 : Start;-}---#if defined(TEST)--/* ARGSUSED */-int-main(int argc, char **argv)-{- time_t d;- time_t now = time(NULL);-- while (*++argv != NULL) {- (void)printf("Input: %s\n", *argv);- d = get_date(now, *argv);- if (d == -1)- (void)printf("Bad format - couldn't convert.\n");- else- (void)printf("Output: %s\n", ctime(&d));- }- exit(0);- /* NOTREACHED */-}-#endif /* defined(TEST) */
− c/archive_getdate.h
@@ -1,39 +0,0 @@-/*-- * Copyright (c) 2003-2015 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- */--#ifndef ARCHIVE_GETDATE_H_INCLUDED-#define ARCHIVE_GETDATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--#include <time.h>--time_t __archive_get_date(time_t now, const char *);--#endif
− c/archive_hmac.c
@@ -1,339 +0,0 @@-/*--* Copyright (c) 2014 Michihiro NAKAJIMA-* All rights reserved.-*-* Redistribution and use in source and binary forms, with or without-* modification, are permitted provided that the following conditions-* are met:-* 1. Redistributions of source code must retain the above copyright-* notice, this list of conditions and the following disclaimer.-* 2. Redistributions in binary form must reproduce the above copyright-* notice, this list of conditions and the following disclaimer in the-* documentation and/or other materials provided with the distribution.-*-* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR-* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.-* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,-* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT-* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-*/--#include "archive_platform.h"--#ifdef HAVE_STRING_H-#include <string.h>-#endif-#include "archive.h"-#include "archive_hmac_private.h"--/*- * On systems that do not support any recognized crypto libraries,- * the archive_hmac.c file is expected to define no usable symbols.- *- * But some compilers and linkers choke on empty object files, so- * define a public symbol that will always exist. This could- * be removed someday if this file gains another always-present- * symbol definition.- */-int __libarchive_hmac_build_hack(void) {- return 0;-}---#ifdef ARCHIVE_HMAC_USE_Apple_CommonCrypto--static int-__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)-{- CCHmacInit(ctx, kCCHmacAlgSHA1, key, key_len);- return 0;-}--static void-__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,- size_t data_len)-{- CCHmacUpdate(ctx, data, data_len);-}--static void-__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)-{- CCHmacFinal(ctx, out);- *out_len = 20;-}--static void-__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)-{- memset(ctx, 0, sizeof(*ctx));-}--#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)--#ifndef BCRYPT_HASH_REUSABLE_FLAG-# define BCRYPT_HASH_REUSABLE_FLAG 0x00000020-#endif--static int-__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)-{-#ifdef __GNUC__-#pragma GCC diagnostic ignored "-Wcast-qual"-#endif- BCRYPT_ALG_HANDLE hAlg;- BCRYPT_HASH_HANDLE hHash;- DWORD hash_len;- PBYTE hash;- ULONG result;- NTSTATUS status;-- ctx->hAlg = NULL;- status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM,- MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG);- if (!BCRYPT_SUCCESS(status))- return -1;- status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PUCHAR)&hash_len,- sizeof(hash_len), &result, 0);- if (!BCRYPT_SUCCESS(status)) {- BCryptCloseAlgorithmProvider(hAlg, 0);- return -1;- }- hash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, hash_len);- if (hash == NULL) {- BCryptCloseAlgorithmProvider(hAlg, 0);- return -1;- }- status = BCryptCreateHash(hAlg, &hHash, NULL, 0,- (PUCHAR)key, (ULONG)key_len, BCRYPT_HASH_REUSABLE_FLAG);- if (!BCRYPT_SUCCESS(status)) {- BCryptCloseAlgorithmProvider(hAlg, 0);- HeapFree(GetProcessHeap(), 0, hash);- return -1;- }-- ctx->hAlg = hAlg;- ctx->hHash = hHash;- ctx->hash_len = hash_len;- ctx->hash = hash;-- return 0;-}--static void-__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,- size_t data_len)-{- BCryptHashData(ctx->hHash, (PUCHAR)(uintptr_t)data, (ULONG)data_len, 0);-}--static void-__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)-{- BCryptFinishHash(ctx->hHash, ctx->hash, ctx->hash_len, 0);- if (ctx->hash_len == *out_len)- memcpy(out, ctx->hash, *out_len);-}--static void-__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)-{- if (ctx->hAlg != NULL) {- BCryptCloseAlgorithmProvider(ctx->hAlg, 0);- HeapFree(GetProcessHeap(), 0, ctx->hash);- ctx->hAlg = NULL;- }-}--#elif defined(HAVE_LIBMBEDCRYPTO) && defined(HAVE_MBEDTLS_MD_H)--static int-__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)-{- const mbedtls_md_info_t *info;- int ret;-- mbedtls_md_init(ctx);- info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);- if (info == NULL) {- mbedtls_md_free(ctx);- return (-1);- }- ret = mbedtls_md_setup(ctx, info, 1);- if (ret != 0) {- mbedtls_md_free(ctx);- return (-1);- }- ret = mbedtls_md_hmac_starts(ctx, key, key_len);- if (ret != 0) {- mbedtls_md_free(ctx);- return (-1);- }- return 0;-}--static void-__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,- size_t data_len)-{- mbedtls_md_hmac_update(ctx, data, data_len);-}--static void __hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)-{- (void)out_len; /* UNUSED */-- mbedtls_md_hmac_finish(ctx, out);-}--static void __hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)-{- mbedtls_md_free(ctx);- memset(ctx, 0, sizeof(*ctx));-}--#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_HMAC_H)--static int-__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)-{- hmac_sha1_set_key(ctx, key_len, key);- return 0;-}--static void-__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,- size_t data_len)-{- hmac_sha1_update(ctx, data_len, data);-}--static void-__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)-{- hmac_sha1_digest(ctx, (unsigned)*out_len, out);-}--static void-__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)-{- memset(ctx, 0, sizeof(*ctx));-}--#elif defined(HAVE_LIBCRYPTO)--static int-__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)-{-#if OPENSSL_VERSION_NUMBER >= 0x30000000L- EVP_MAC *mac;-- char sha1[] = "SHA1";- OSSL_PARAM params[] = {- OSSL_PARAM_utf8_string("digest", sha1, sizeof(sha1) - 1),- OSSL_PARAM_END- };-- mac = EVP_MAC_fetch(NULL, "HMAC", NULL);- *ctx = EVP_MAC_CTX_new(mac);- EVP_MAC_free(mac);- if (*ctx == NULL)- return -1;-- EVP_MAC_init(*ctx, key, key_len, params);-#else- *ctx = HMAC_CTX_new();- if (*ctx == NULL)- return -1;- HMAC_Init_ex(*ctx, key, key_len, EVP_sha1(), NULL);-#endif- return 0;-}--static void-__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,- size_t data_len)-{-#if OPENSSL_VERSION_NUMBER >= 0x30000000L- EVP_MAC_update(*ctx, data, data_len);-#else- HMAC_Update(*ctx, data, data_len);-#endif-}--static void-__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)-{-#if OPENSSL_VERSION_NUMBER >= 0x30000000L- size_t len = *out_len;-#else- unsigned int len = (unsigned int)*out_len;-#endif--#if OPENSSL_VERSION_NUMBER >= 0x30000000L- EVP_MAC_final(*ctx, out, &len, *out_len);-#else- HMAC_Final(*ctx, out, &len);-#endif- *out_len = len;-}--static void-__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)-{-#if OPENSSL_VERSION_NUMBER >= 0x30000000L- EVP_MAC_CTX_free(*ctx);-#else- HMAC_CTX_free(*ctx);-#endif- *ctx = NULL;-}--#else--/* Stub */-static int-__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)-{- (void)ctx;/* UNUSED */- (void)key;/* UNUSED */- (void)key_len;/* UNUSED */- return -1;-}--static void-__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,- size_t data_len)-{- (void)ctx;/* UNUSED */- (void)data;/* UNUSED */- (void)data_len;/* UNUSED */-}--static void-__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)-{- (void)ctx;/* UNUSED */- (void)out;/* UNUSED */- (void)out_len;/* UNUSED */-}--static void-__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)-{- (void)ctx;/* UNUSED */-}--#endif--const struct archive_hmac __archive_hmac = {- &__hmac_sha1_init,- &__hmac_sha1_update,- &__hmac_sha1_final,- &__hmac_sha1_cleanup,-};
− c/archive_hmac_private.h
@@ -1,119 +0,0 @@-/*--* Copyright (c) 2014 Michihiro NAKAJIMA-* All rights reserved.-*-* Redistribution and use in source and binary forms, with or without-* modification, are permitted provided that the following conditions-* are met:-* 1. Redistributions of source code must retain the above copyright-* notice, this list of conditions and the following disclaimer.-* 2. Redistributions in binary form must reproduce the above copyright-* notice, this list of conditions and the following disclaimer in the-* documentation and/or other materials provided with the distribution.-*-* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR-* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.-* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,-* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT-* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-*/--#ifndef ARCHIVE_HMAC_PRIVATE_H_INCLUDED-#define ARCHIVE_HMAC_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif-/*- * On systems that do not support any recognized crypto libraries,- * the archive_hmac.c file is expected to define no usable symbols.- *- * But some compilers and linkers choke on empty object files, so- * define a public symbol that will always exist. This could- * be removed someday if this file gains another always-present- * symbol definition.- */-int __libarchive_hmac_build_hack(void);--#ifdef __APPLE__-# include <AvailabilityMacros.h>-# if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060-# define ARCHIVE_HMAC_USE_Apple_CommonCrypto-# endif-#endif--#ifdef ARCHIVE_HMAC_USE_Apple_CommonCrypto-#include <CommonCrypto/CommonHMAC.h>--typedef CCHmacContext archive_hmac_sha1_ctx;--#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)-#include <bcrypt.h>--typedef struct {- BCRYPT_ALG_HANDLE hAlg;- BCRYPT_HASH_HANDLE hHash;- DWORD hash_len;- PBYTE hash;--} archive_hmac_sha1_ctx;--#elif defined(HAVE_LIBMBEDCRYPTO) && defined(HAVE_MBEDTLS_MD_H)-#include <mbedtls/md.h>--typedef mbedtls_md_context_t archive_hmac_sha1_ctx;--#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_HMAC_H)-#include <nettle/hmac.h>--typedef struct hmac_sha1_ctx archive_hmac_sha1_ctx;--#elif defined(HAVE_LIBCRYPTO)-#include <openssl/opensslv.h>-#include <openssl/hmac.h>-#if OPENSSL_VERSION_NUMBER >= 0x30000000L-#include <openssl/params.h>--typedef EVP_MAC_CTX *archive_hmac_sha1_ctx;--#else-#include "archive_openssl_hmac_private.h"--typedef HMAC_CTX* archive_hmac_sha1_ctx;-#endif--#else--typedef int archive_hmac_sha1_ctx;--#endif---/* HMAC */-#define archive_hmac_sha1_init(ctx, key, key_len)\- __archive_hmac.__hmac_sha1_init(ctx, key, key_len)-#define archive_hmac_sha1_update(ctx, data, data_len)\- __archive_hmac.__hmac_sha1_update(ctx, data, data_len)-#define archive_hmac_sha1_final(ctx, out, out_len)\- __archive_hmac.__hmac_sha1_final(ctx, out, out_len)-#define archive_hmac_sha1_cleanup(ctx)\- __archive_hmac.__hmac_sha1_cleanup(ctx)---struct archive_hmac {- /* HMAC */- int (*__hmac_sha1_init)(archive_hmac_sha1_ctx *, const uint8_t *,- size_t);- void (*__hmac_sha1_update)(archive_hmac_sha1_ctx *, const uint8_t *,- size_t);- void (*__hmac_sha1_final)(archive_hmac_sha1_ctx *, uint8_t *, size_t *);- void (*__hmac_sha1_cleanup)(archive_hmac_sha1_ctx *);-};--extern const struct archive_hmac __archive_hmac;-#endif /* ARCHIVE_HMAC_PRIVATE_H_INCLUDED */
− c/archive_match.c
@@ -1,1875 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_entry.h"-#include "archive_getdate.h"-#include "archive_pathmatch.h"-#include "archive_rb.h"-#include "archive_string.h"--struct match {- struct match *next;- int matches;- struct archive_mstring pattern;-};--struct match_list {- struct match *first;- struct match **last;- int count;- int unmatched_count;- struct match *unmatched_next;- int unmatched_eof;-};--struct match_file {- struct archive_rb_node node;- struct match_file *next;- struct archive_mstring pathname;- int flag;- time_t mtime_sec;- long mtime_nsec;- time_t ctime_sec;- long ctime_nsec;-};--struct entry_list {- struct match_file *first;- struct match_file **last;- int count;-};--struct id_array {- size_t size;/* Allocated size */- size_t count;- int64_t *ids;-};--#define PATTERN_IS_SET 1-#define TIME_IS_SET 2-#define ID_IS_SET 4--struct archive_match {- struct archive archive;-- /* exclusion/inclusion set flag. */- int setflag;-- /* Recursively include directory content? */- int recursive_include;-- /*- * Matching filename patterns.- */- struct match_list exclusions;- struct match_list inclusions;-- /*- * Matching time stamps.- */- time_t now;- int newer_mtime_filter;- time_t newer_mtime_sec;- long newer_mtime_nsec;- int newer_ctime_filter;- time_t newer_ctime_sec;- long newer_ctime_nsec;- int older_mtime_filter;- time_t older_mtime_sec;- long older_mtime_nsec;- int older_ctime_filter;- time_t older_ctime_sec;- long older_ctime_nsec;- /*- * Matching time stamps with its filename.- */- struct archive_rb_tree exclusion_tree;- struct entry_list exclusion_entry_list;-- /*- * Matching file owners.- */- struct id_array inclusion_uids;- struct id_array inclusion_gids;- struct match_list inclusion_unames;- struct match_list inclusion_gnames;-};--static int add_pattern_from_file(struct archive_match *,- struct match_list *, int, const void *, int);-static int add_entry(struct archive_match *, int,- struct archive_entry *);-static int add_owner_id(struct archive_match *, struct id_array *,- int64_t);-static int add_owner_name(struct archive_match *, struct match_list *,- int, const void *);-static int add_pattern_mbs(struct archive_match *, struct match_list *,- const char *);-static int add_pattern_wcs(struct archive_match *, struct match_list *,- const wchar_t *);-static int cmp_key_mbs(const struct archive_rb_node *, const void *);-static int cmp_key_wcs(const struct archive_rb_node *, const void *);-static int cmp_node_mbs(const struct archive_rb_node *,- const struct archive_rb_node *);-static int cmp_node_wcs(const struct archive_rb_node *,- const struct archive_rb_node *);-static void entry_list_add(struct entry_list *, struct match_file *);-static void entry_list_free(struct entry_list *);-static void entry_list_init(struct entry_list *);-static int error_nomem(struct archive_match *);-static void match_list_add(struct match_list *, struct match *);-static void match_list_free(struct match_list *);-static void match_list_init(struct match_list *);-static int match_list_unmatched_inclusions_next(struct archive_match *,- struct match_list *, int, const void **);-static int match_owner_id(struct id_array *, int64_t);-#if !defined(_WIN32) || defined(__CYGWIN__)-static int match_owner_name_mbs(struct archive_match *,- struct match_list *, const char *);-#else-static int match_owner_name_wcs(struct archive_match *,- struct match_list *, const wchar_t *);-#endif-static int match_path_exclusion(struct archive_match *,- struct match *, int, const void *);-static int match_path_inclusion(struct archive_match *,- struct match *, int, const void *);-static int owner_excluded(struct archive_match *,- struct archive_entry *);-static int path_excluded(struct archive_match *, int, const void *);-static int set_timefilter(struct archive_match *, int, time_t, long,- time_t, long);-static int set_timefilter_pathname_mbs(struct archive_match *,- int, const char *);-static int set_timefilter_pathname_wcs(struct archive_match *,- int, const wchar_t *);-static int set_timefilter_date(struct archive_match *, int, const char *);-static int set_timefilter_date_w(struct archive_match *, int,- const wchar_t *);-static int time_excluded(struct archive_match *,- struct archive_entry *);-static int validate_time_flag(struct archive *, int, const char *);--#define get_date __archive_get_date--static const struct archive_rb_tree_ops rb_ops_mbs = {- cmp_node_mbs, cmp_key_mbs-};--static const struct archive_rb_tree_ops rb_ops_wcs = {- cmp_node_wcs, cmp_key_wcs-};--/*- * The matching logic here needs to be re-thought. I started out to- * try to mimic gtar's matching logic, but it's not entirely- * consistent. In particular 'tar -t' and 'tar -x' interpret patterns- * on the command line as anchored, but --exclude doesn't.- */--static int-error_nomem(struct archive_match *a)-{- archive_set_error(&(a->archive), ENOMEM, "No memory");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);-}--/*- * Create an ARCHIVE_MATCH object.- */-struct archive *-archive_match_new(void)-{- struct archive_match *a;-- a = (struct archive_match *)calloc(1, sizeof(*a));- if (a == NULL)- return (NULL);- a->archive.magic = ARCHIVE_MATCH_MAGIC;- a->archive.state = ARCHIVE_STATE_NEW;- a->recursive_include = 1;- match_list_init(&(a->inclusions));- match_list_init(&(a->exclusions));- __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs);- entry_list_init(&(a->exclusion_entry_list));- match_list_init(&(a->inclusion_unames));- match_list_init(&(a->inclusion_gnames));- time(&a->now);- return (&(a->archive));-}--/*- * Free an ARCHIVE_MATCH object.- */-int-archive_match_free(struct archive *_a)-{- struct archive_match *a;-- if (_a == NULL)- return (ARCHIVE_OK);- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free");- a = (struct archive_match *)_a;- match_list_free(&(a->inclusions));- match_list_free(&(a->exclusions));- entry_list_free(&(a->exclusion_entry_list));- free(a->inclusion_uids.ids);- free(a->inclusion_gids.ids);- match_list_free(&(a->inclusion_unames));- match_list_free(&(a->inclusion_gnames));- free(a);- return (ARCHIVE_OK);-}--/*- * Convenience function to perform all exclusion tests.- *- * Returns 1 if archive entry is excluded.- * Returns 0 if archive entry is not excluded.- * Returns <0 if something error happened.- */-int-archive_match_excluded(struct archive *_a, struct archive_entry *entry)-{- struct archive_match *a;- int r;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_excluded_ae");-- a = (struct archive_match *)_a;- if (entry == NULL) {- archive_set_error(&(a->archive), EINVAL, "entry is NULL");- return (ARCHIVE_FAILED);- }-- r = 0;- if (a->setflag & PATTERN_IS_SET) {-#if defined(_WIN32) && !defined(__CYGWIN__)- r = path_excluded(a, 0, archive_entry_pathname_w(entry));-#else- r = path_excluded(a, 1, archive_entry_pathname(entry));-#endif- if (r != 0)- return (r);- }-- if (a->setflag & TIME_IS_SET) {- r = time_excluded(a, entry);- if (r != 0)- return (r);- }-- if (a->setflag & ID_IS_SET)- r = owner_excluded(a, entry);- return (r);-}--/*- * Utility functions to manage exclusion/inclusion patterns- */--int-archive_match_exclude_pattern(struct archive *_a, const char *pattern)-{- struct archive_match *a;- int r;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_exclude_pattern");- a = (struct archive_match *)_a;-- if (pattern == NULL || *pattern == '\0') {- archive_set_error(&(a->archive), EINVAL, "pattern is empty");- return (ARCHIVE_FAILED);- }- if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)- return (r);- return (ARCHIVE_OK);-}--int-archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern)-{- struct archive_match *a;- int r;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w");- a = (struct archive_match *)_a;-- if (pattern == NULL || *pattern == L'\0') {- archive_set_error(&(a->archive), EINVAL, "pattern is empty");- return (ARCHIVE_FAILED);- }- if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)- return (r);- return (ARCHIVE_OK);-}--int-archive_match_exclude_pattern_from_file(struct archive *_a,- const char *pathname, int nullSeparator)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file");- a = (struct archive_match *)_a;-- return add_pattern_from_file(a, &(a->exclusions), 1, pathname,- nullSeparator);-}--int-archive_match_exclude_pattern_from_file_w(struct archive *_a,- const wchar_t *pathname, int nullSeparator)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w");- a = (struct archive_match *)_a;-- return add_pattern_from_file(a, &(a->exclusions), 0, pathname,- nullSeparator);-}--int-archive_match_include_pattern(struct archive *_a, const char *pattern)-{- struct archive_match *a;- int r;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_include_pattern");- a = (struct archive_match *)_a;-- if (pattern == NULL || *pattern == '\0') {- archive_set_error(&(a->archive), EINVAL, "pattern is empty");- return (ARCHIVE_FAILED);- }- if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)- return (r);- return (ARCHIVE_OK);-}--int-archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern)-{- struct archive_match *a;- int r;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_include_pattern_w");- a = (struct archive_match *)_a;-- if (pattern == NULL || *pattern == L'\0') {- archive_set_error(&(a->archive), EINVAL, "pattern is empty");- return (ARCHIVE_FAILED);- }- if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)- return (r);- return (ARCHIVE_OK);-}--int-archive_match_include_pattern_from_file(struct archive *_a,- const char *pathname, int nullSeparator)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file");- a = (struct archive_match *)_a;-- return add_pattern_from_file(a, &(a->inclusions), 1, pathname,- nullSeparator);-}--int-archive_match_include_pattern_from_file_w(struct archive *_a,- const wchar_t *pathname, int nullSeparator)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w");- a = (struct archive_match *)_a;-- return add_pattern_from_file(a, &(a->inclusions), 0, pathname,- nullSeparator);-}--/*- * Test functions for pathname patterns.- *- * Returns 1 if archive entry is excluded.- * Returns 0 if archive entry is not excluded.- * Returns <0 if something error happened.- */-int-archive_match_path_excluded(struct archive *_a,- struct archive_entry *entry)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_path_excluded");-- a = (struct archive_match *)_a;- if (entry == NULL) {- archive_set_error(&(a->archive), EINVAL, "entry is NULL");- return (ARCHIVE_FAILED);- }-- /* If we don't have exclusion/inclusion pattern set at all,- * the entry is always not excluded. */- if ((a->setflag & PATTERN_IS_SET) == 0)- return (0);-#if defined(_WIN32) && !defined(__CYGWIN__)- return (path_excluded(a, 0, archive_entry_pathname_w(entry)));-#else- return (path_excluded(a, 1, archive_entry_pathname(entry)));-#endif-}--/*- * When recursive inclusion of directory content is enabled,- * an inclusion pattern that matches a directory will also- * include everything beneath that directory. Enabled by default.- *- * For compatibility with GNU tar, exclusion patterns always- * match if a subset of the full patch matches (i.e., they are- * are not rooted at the beginning of the path) and thus there- * is no corresponding non-recursive exclusion mode.- */-int-archive_match_set_inclusion_recursion(struct archive *_a, int enabled)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_set_inclusion_recursion");- a = (struct archive_match *)_a;- a->recursive_include = enabled;- return (ARCHIVE_OK);-}--/*- * Utility functions to get statistic information for inclusion patterns.- */-int-archive_match_path_unmatched_inclusions(struct archive *_a)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions");- a = (struct archive_match *)_a;-- return (a->inclusions.unmatched_count);-}--int-archive_match_path_unmatched_inclusions_next(struct archive *_a,- const char **_p)-{- struct archive_match *a;- const void *v;- int r;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next");- a = (struct archive_match *)_a;-- r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v);- *_p = (const char *)v;- return (r);-}--int-archive_match_path_unmatched_inclusions_next_w(struct archive *_a,- const wchar_t **_p)-{- struct archive_match *a;- const void *v;- int r;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w");- a = (struct archive_match *)_a;-- r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v);- *_p = (const wchar_t *)v;- return (r);-}--/*- * Add inclusion/exclusion patterns.- */-static int-add_pattern_mbs(struct archive_match *a, struct match_list *list,- const char *pattern)-{- struct match *match;- size_t len;-- match = calloc(1, sizeof(*match));- if (match == NULL)- return (error_nomem(a));- /* Both "foo/" and "foo" should match "foo/bar". */- len = strlen(pattern);- if (len && pattern[len - 1] == '/')- --len;- archive_mstring_copy_mbs_len(&(match->pattern), pattern, len);- match_list_add(list, match);- a->setflag |= PATTERN_IS_SET;- return (ARCHIVE_OK);-}--static int-add_pattern_wcs(struct archive_match *a, struct match_list *list,- const wchar_t *pattern)-{- struct match *match;- size_t len;-- match = calloc(1, sizeof(*match));- if (match == NULL)- return (error_nomem(a));- /* Both "foo/" and "foo" should match "foo/bar". */- len = wcslen(pattern);- if (len && pattern[len - 1] == L'/')- --len;- archive_mstring_copy_wcs_len(&(match->pattern), pattern, len);- match_list_add(list, match);- a->setflag |= PATTERN_IS_SET;- return (ARCHIVE_OK);-}--static int-add_pattern_from_file(struct archive_match *a, struct match_list *mlist,- int mbs, const void *pathname, int nullSeparator)-{- struct archive *ar;- struct archive_entry *ae;- struct archive_string as;- const void *buff;- size_t size;- int64_t offset;- int r;-- ar = archive_read_new(); - if (ar == NULL) {- archive_set_error(&(a->archive), ENOMEM, "No memory");- return (ARCHIVE_FATAL);- }- r = archive_read_support_format_raw(ar);- r = archive_read_support_format_empty(ar);- if (r != ARCHIVE_OK) {- archive_copy_error(&(a->archive), ar);- archive_read_free(ar);- return (r);- }- if (mbs)- r = archive_read_open_filename(ar, pathname, 512*20);- else- r = archive_read_open_filename_w(ar, pathname, 512*20);- if (r != ARCHIVE_OK) {- archive_copy_error(&(a->archive), ar);- archive_read_free(ar);- return (r);- }- r = archive_read_next_header(ar, &ae);- if (r != ARCHIVE_OK) {- archive_read_free(ar);- if (r == ARCHIVE_EOF) {- return (ARCHIVE_OK);- } else {- archive_copy_error(&(a->archive), ar);- return (r);- }- }-- archive_string_init(&as);-- while ((r = archive_read_data_block(ar, &buff, &size, &offset))- == ARCHIVE_OK) {- const char *b = (const char *)buff;-- while (size) {- const char *s = (const char *)b;- size_t length = 0;- int found_separator = 0;-- while (length < size) {- if (nullSeparator) {- if (*b == '\0') {- found_separator = 1;- break;- }- } else {- if (*b == 0x0d || *b == 0x0a) {- found_separator = 1;- break;- }- }- b++;- length++;- }- if (!found_separator) {- archive_strncat(&as, s, length);- /* Read next data block. */- break;- }- b++;- size -= length + 1;- archive_strncat(&as, s, length);-- /* If the line is not empty, add the pattern. */- if (archive_strlen(&as) > 0) {- /* Add pattern. */- r = add_pattern_mbs(a, mlist, as.s);- if (r != ARCHIVE_OK) {- archive_read_free(ar);- archive_string_free(&as);- return (r);- }- archive_string_empty(&as);- }- }- }-- /* If an error occurred, report it immediately. */- if (r < ARCHIVE_OK) {- archive_copy_error(&(a->archive), ar);- archive_read_free(ar);- archive_string_free(&as);- return (r);- }-- /* If the line is not empty, add the pattern. */- if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) {- /* Add pattern. */- r = add_pattern_mbs(a, mlist, as.s);- if (r != ARCHIVE_OK) {- archive_read_free(ar);- archive_string_free(&as);- return (r);- }- }- archive_read_free(ar);- archive_string_free(&as);- return (ARCHIVE_OK);-}--/*- * Test if pathname is excluded by inclusion/exclusion patterns.- */-static int-path_excluded(struct archive_match *a, int mbs, const void *pathname)-{- struct match *match;- struct match *matched;- int r;-- if (a == NULL)- return (0);-- /* Mark off any unmatched inclusions. */- /* In particular, if a filename does appear in the archive and- * is explicitly included and excluded, then we don't report- * it as missing even though we don't extract it.- */- matched = NULL;- for (match = a->inclusions.first; match != NULL;- match = match->next){- if (match->matches == 0 &&- (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {- if (r < 0)- return (r);- a->inclusions.unmatched_count--;- match->matches++;- matched = match;- }- }-- /* Exclusions take priority */- for (match = a->exclusions.first; match != NULL;- match = match->next){- r = match_path_exclusion(a, match, mbs, pathname);- if (r)- return (r);- }-- /* It's not excluded and we found an inclusion above, so it's- * included. */- if (matched != NULL)- return (0);--- /* We didn't find an unmatched inclusion, check the remaining ones. */- for (match = a->inclusions.first; match != NULL;- match = match->next){- /* We looked at previously-unmatched inclusions already. */- if (match->matches > 0 &&- (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {- if (r < 0)- return (r);- match->matches++;- return (0);- }- }-- /* If there were inclusions, default is to exclude. */- if (a->inclusions.first != NULL)- return (1);-- /* No explicit inclusions, default is to match. */- return (0);-}--/*- * This is a little odd, but it matches the default behavior of- * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar'- *- */-static int-match_path_exclusion(struct archive_match *a, struct match *m,- int mbs, const void *pn)-{- int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END;- int r;-- if (mbs) {- const char *p;- r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);- if (r == 0)- return (archive_pathmatch(p, (const char *)pn, flag));- } else {- const wchar_t *p;- r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);- if (r == 0)- return (archive_pathmatch_w(p, (const wchar_t *)pn,- flag));- }- if (errno == ENOMEM)- return (error_nomem(a));- return (0);-}--/*- * Again, mimic gtar: inclusions are always anchored (have to match- * the beginning of the path) even though exclusions are not anchored.- */-static int-match_path_inclusion(struct archive_match *a, struct match *m,- int mbs, const void *pn)-{- /* Recursive operation requires only a prefix match. */- int flag = a->recursive_include ?- PATHMATCH_NO_ANCHOR_END :- 0;- int r;-- if (mbs) {- const char *p;- r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);- if (r == 0)- return (archive_pathmatch(p, (const char *)pn, flag));- } else {- const wchar_t *p;- r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);- if (r == 0)- return (archive_pathmatch_w(p, (const wchar_t *)pn,- flag));- }- if (errno == ENOMEM)- return (error_nomem(a));- return (0);-}--static void-match_list_init(struct match_list *list)-{- list->first = NULL;- list->last = &(list->first);- list->count = 0;-}--static void-match_list_free(struct match_list *list)-{- struct match *p, *q;-- for (p = list->first; p != NULL; ) {- q = p;- p = p->next;- archive_mstring_clean(&(q->pattern));- free(q);- }-}--static void-match_list_add(struct match_list *list, struct match *m)-{- *list->last = m;- list->last = &(m->next);- list->count++;- list->unmatched_count++;-}--static int-match_list_unmatched_inclusions_next(struct archive_match *a,- struct match_list *list, int mbs, const void **vp)-{- struct match *m;-- *vp = NULL;- if (list->unmatched_eof) {- list->unmatched_eof = 0;- return (ARCHIVE_EOF);- }- if (list->unmatched_next == NULL) {- if (list->unmatched_count == 0)- return (ARCHIVE_EOF);- list->unmatched_next = list->first;- }-- for (m = list->unmatched_next; m != NULL; m = m->next) {- int r;-- if (m->matches)- continue;- if (mbs) {- const char *p;- r = archive_mstring_get_mbs(&(a->archive),- &(m->pattern), &p);- if (r < 0 && errno == ENOMEM)- return (error_nomem(a));- if (p == NULL)- p = "";- *vp = p;- } else {- const wchar_t *p;- r = archive_mstring_get_wcs(&(a->archive),- &(m->pattern), &p);- if (r < 0 && errno == ENOMEM)- return (error_nomem(a));- if (p == NULL)- p = L"";- *vp = p;- }- list->unmatched_next = m->next;- if (list->unmatched_next == NULL)- /* To return EOF next time. */- list->unmatched_eof = 1;- return (ARCHIVE_OK);- }- list->unmatched_next = NULL;- return (ARCHIVE_EOF);-}--/*- * Utility functions to manage inclusion timestamps.- */-int-archive_match_include_time(struct archive *_a, int flag, time_t sec,- long nsec)-{- int r;-- r = validate_time_flag(_a, flag, "archive_match_include_time");- if (r != ARCHIVE_OK)- return (r);- return set_timefilter((struct archive_match *)_a, flag,- sec, nsec, sec, nsec);-}--int-archive_match_include_date(struct archive *_a, int flag,- const char *datestr)-{- int r;-- r = validate_time_flag(_a, flag, "archive_match_include_date");- if (r != ARCHIVE_OK)- return (r);- return set_timefilter_date((struct archive_match *)_a, flag, datestr);-}--int-archive_match_include_date_w(struct archive *_a, int flag,- const wchar_t *datestr)-{- int r;-- r = validate_time_flag(_a, flag, "archive_match_include_date_w");- if (r != ARCHIVE_OK)- return (r);-- return set_timefilter_date_w((struct archive_match *)_a, flag, datestr);-}--int-archive_match_include_file_time(struct archive *_a, int flag,- const char *pathname)-{- int r;-- r = validate_time_flag(_a, flag, "archive_match_include_file_time");- if (r != ARCHIVE_OK)- return (r);- return set_timefilter_pathname_mbs((struct archive_match *)_a,- flag, pathname);-}--int-archive_match_include_file_time_w(struct archive *_a, int flag,- const wchar_t *pathname)-{- int r;-- r = validate_time_flag(_a, flag, "archive_match_include_file_time_w");- if (r != ARCHIVE_OK)- return (r);- return set_timefilter_pathname_wcs((struct archive_match *)_a,- flag, pathname);-}--int-archive_match_exclude_entry(struct archive *_a, int flag,- struct archive_entry *entry)-{- struct archive_match *a;- int r;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_time_include_entry");- a = (struct archive_match *)_a;-- if (entry == NULL) {- archive_set_error(&(a->archive), EINVAL, "entry is NULL");- return (ARCHIVE_FAILED);- }- r = validate_time_flag(_a, flag, "archive_match_exclude_entry");- if (r != ARCHIVE_OK)- return (r);- return (add_entry(a, flag, entry));-}--/*- * Test function for time stamps.- *- * Returns 1 if archive entry is excluded.- * Returns 0 if archive entry is not excluded.- * Returns <0 if something error happened.- */-int-archive_match_time_excluded(struct archive *_a,- struct archive_entry *entry)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae");-- a = (struct archive_match *)_a;- if (entry == NULL) {- archive_set_error(&(a->archive), EINVAL, "entry is NULL");- return (ARCHIVE_FAILED);- }-- /* If we don't have inclusion time set at all, the entry is always- * not excluded. */- if ((a->setflag & TIME_IS_SET) == 0)- return (0);- return (time_excluded(a, entry));-}--static int-validate_time_flag(struct archive *_a, int flag, const char *_fn)-{- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, _fn);-- /* Check a type of time. */- if (flag &- ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) {- archive_set_error(_a, EINVAL, "Invalid time flag");- return (ARCHIVE_FAILED);- }- if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) {- archive_set_error(_a, EINVAL, "No time flag");- return (ARCHIVE_FAILED);- }-- /* Check a type of comparison. */- if (flag &- ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER- | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) {- archive_set_error(_a, EINVAL, "Invalid comparison flag");- return (ARCHIVE_FAILED);- }- if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER- | ARCHIVE_MATCH_EQUAL)) == 0) {- archive_set_error(_a, EINVAL, "No comparison flag");- return (ARCHIVE_FAILED);- }-- return (ARCHIVE_OK);-}--#define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\- ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL)-static int-set_timefilter(struct archive_match *a, int timetype,- time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec)-{- if (timetype & ARCHIVE_MATCH_MTIME) {- if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {- a->newer_mtime_filter = timetype;- a->newer_mtime_sec = mtime_sec;- a->newer_mtime_nsec = mtime_nsec;- a->setflag |= TIME_IS_SET;- }- if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {- a->older_mtime_filter = timetype;- a->older_mtime_sec = mtime_sec;- a->older_mtime_nsec = mtime_nsec;- a->setflag |= TIME_IS_SET;- }- }- if (timetype & ARCHIVE_MATCH_CTIME) {- if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {- a->newer_ctime_filter = timetype;- a->newer_ctime_sec = ctime_sec;- a->newer_ctime_nsec = ctime_nsec;- a->setflag |= TIME_IS_SET;- }- if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {- a->older_ctime_filter = timetype;- a->older_ctime_sec = ctime_sec;- a->older_ctime_nsec = ctime_nsec;- a->setflag |= TIME_IS_SET;- }- }- return (ARCHIVE_OK);-}--static int-set_timefilter_date(struct archive_match *a, int timetype, const char *datestr)-{- time_t t;-- if (datestr == NULL || *datestr == '\0') {- archive_set_error(&(a->archive), EINVAL, "date is empty");- return (ARCHIVE_FAILED);- }- t = get_date(a->now, datestr);- if (t == (time_t)-1) {- archive_set_error(&(a->archive), EINVAL, "invalid date string");- return (ARCHIVE_FAILED);- }- return set_timefilter(a, timetype, t, 0, t, 0);-}--static int-set_timefilter_date_w(struct archive_match *a, int timetype,- const wchar_t *datestr)-{- struct archive_string as;- time_t t;-- if (datestr == NULL || *datestr == L'\0') {- archive_set_error(&(a->archive), EINVAL, "date is empty");- return (ARCHIVE_FAILED);- }-- archive_string_init(&as);- if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) {- archive_string_free(&as);- if (errno == ENOMEM)- return (error_nomem(a));- archive_set_error(&(a->archive), -1,- "Failed to convert WCS to MBS");- return (ARCHIVE_FAILED);- }- t = get_date(a->now, as.s);- archive_string_free(&as);- if (t == (time_t)-1) {- archive_set_error(&(a->archive), EINVAL, "invalid date string");- return (ARCHIVE_FAILED);- }- return set_timefilter(a, timetype, t, 0, t, 0);-}--#if defined(_WIN32) && !defined(__CYGWIN__)-#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)-static int-set_timefilter_find_data(struct archive_match *a, int timetype,- DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime,- DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime)-{- ULARGE_INTEGER utc;- time_t ctime_sec, mtime_sec;- long ctime_ns, mtime_ns;-- utc.HighPart = ftCreationTime_dwHighDateTime;- utc.LowPart = ftCreationTime_dwLowDateTime;- if (utc.QuadPart >= EPOC_TIME) {- utc.QuadPart -= EPOC_TIME;- ctime_sec = (time_t)(utc.QuadPart / 10000000);- ctime_ns = (long)(utc.QuadPart % 10000000) * 100;- } else {- ctime_sec = 0;- ctime_ns = 0;- }- utc.HighPart = ftLastWriteTime_dwHighDateTime;- utc.LowPart = ftLastWriteTime_dwLowDateTime;- if (utc.QuadPart >= EPOC_TIME) {- utc.QuadPart -= EPOC_TIME;- mtime_sec = (time_t)(utc.QuadPart / 10000000);- mtime_ns = (long)(utc.QuadPart % 10000000) * 100;- } else {- mtime_sec = 0;- mtime_ns = 0;- }- return set_timefilter(a, timetype,- mtime_sec, mtime_ns, ctime_sec, ctime_ns);-}--static int-set_timefilter_pathname_mbs(struct archive_match *a, int timetype,- const char *path)-{- /* NOTE: stat() on Windows cannot handle nano seconds. */- HANDLE h;- WIN32_FIND_DATAA d;-- if (path == NULL || *path == '\0') {- archive_set_error(&(a->archive), EINVAL, "pathname is empty");- return (ARCHIVE_FAILED);- }- h = FindFirstFileA(path, &d);- if (h == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- archive_set_error(&(a->archive), errno,- "Failed to FindFirstFileA");- return (ARCHIVE_FAILED);- }- FindClose(h);- return set_timefilter_find_data(a, timetype,- d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,- d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);-}--static int-set_timefilter_pathname_wcs(struct archive_match *a, int timetype,- const wchar_t *path)-{- HANDLE h;- WIN32_FIND_DATAW d;-- if (path == NULL || *path == L'\0') {- archive_set_error(&(a->archive), EINVAL, "pathname is empty");- return (ARCHIVE_FAILED);- }- h = FindFirstFileW(path, &d);- if (h == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- archive_set_error(&(a->archive), errno,- "Failed to FindFirstFile");- return (ARCHIVE_FAILED);- }- FindClose(h);- return set_timefilter_find_data(a, timetype,- d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,- d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);-}--#else /* _WIN32 && !__CYGWIN__ */--static int-set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st)-{- struct archive_entry *ae;- time_t ctime_sec, mtime_sec;- long ctime_ns, mtime_ns;-- ae = archive_entry_new();- if (ae == NULL)- return (error_nomem(a));- archive_entry_copy_stat(ae, st);- ctime_sec = archive_entry_ctime(ae);- ctime_ns = archive_entry_ctime_nsec(ae);- mtime_sec = archive_entry_mtime(ae);- mtime_ns = archive_entry_mtime_nsec(ae);- archive_entry_free(ae);- return set_timefilter(a, timetype, mtime_sec, mtime_ns,- ctime_sec, ctime_ns);-}--static int-set_timefilter_pathname_mbs(struct archive_match *a, int timetype,- const char *path)-{- struct stat st;-- if (path == NULL || *path == '\0') {- archive_set_error(&(a->archive), EINVAL, "pathname is empty");- return (ARCHIVE_FAILED);- }- if (la_stat(path, &st) != 0) {- archive_set_error(&(a->archive), errno, "Failed to stat()");- return (ARCHIVE_FAILED);- }- return (set_timefilter_stat(a, timetype, &st));-}--static int-set_timefilter_pathname_wcs(struct archive_match *a, int timetype,- const wchar_t *path)-{- struct archive_string as;- int r;-- if (path == NULL || *path == L'\0') {- archive_set_error(&(a->archive), EINVAL, "pathname is empty");- return (ARCHIVE_FAILED);- }-- /* Convert WCS filename to MBS filename. */- archive_string_init(&as);- if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) {- archive_string_free(&as);- if (errno == ENOMEM)- return (error_nomem(a));- archive_set_error(&(a->archive), -1,- "Failed to convert WCS to MBS");- return (ARCHIVE_FAILED);- }-- r = set_timefilter_pathname_mbs(a, timetype, as.s);- archive_string_free(&as);-- return (r);-}-#endif /* _WIN32 && !__CYGWIN__ */--/*- * Call back functions for archive_rb.- */-static int-cmp_node_mbs(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- struct match_file *f1 = (struct match_file *)(uintptr_t)n1;- struct match_file *f2 = (struct match_file *)(uintptr_t)n2;- const char *p1, *p2;-- archive_mstring_get_mbs(NULL, &(f1->pathname), &p1);- archive_mstring_get_mbs(NULL, &(f2->pathname), &p2);- if (p1 == NULL)- return (1);- if (p2 == NULL)- return (-1);- return (strcmp(p1, p2));-}- -static int-cmp_key_mbs(const struct archive_rb_node *n, const void *key)-{- struct match_file *f = (struct match_file *)(uintptr_t)n;- const char *p;-- archive_mstring_get_mbs(NULL, &(f->pathname), &p);- if (p == NULL)- return (-1);- return (strcmp(p, (const char *)key));-}--static int-cmp_node_wcs(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- struct match_file *f1 = (struct match_file *)(uintptr_t)n1;- struct match_file *f2 = (struct match_file *)(uintptr_t)n2;- const wchar_t *p1, *p2;-- archive_mstring_get_wcs(NULL, &(f1->pathname), &p1);- archive_mstring_get_wcs(NULL, &(f2->pathname), &p2);- if (p1 == NULL)- return (1);- if (p2 == NULL)- return (-1);- return (wcscmp(p1, p2));-}- -static int-cmp_key_wcs(const struct archive_rb_node *n, const void *key)-{- struct match_file *f = (struct match_file *)(uintptr_t)n;- const wchar_t *p;-- archive_mstring_get_wcs(NULL, &(f->pathname), &p);- if (p == NULL)- return (-1);- return (wcscmp(p, (const wchar_t *)key));-}--static void-entry_list_init(struct entry_list *list)-{- list->first = NULL;- list->last = &(list->first);- list->count = 0;-}--static void-entry_list_free(struct entry_list *list)-{- struct match_file *p, *q;-- for (p = list->first; p != NULL; ) {- q = p;- p = p->next;- archive_mstring_clean(&(q->pathname));- free(q);- }-}--static void-entry_list_add(struct entry_list *list, struct match_file *file)-{- *list->last = file;- list->last = &(file->next);- list->count++;-}--static int-add_entry(struct archive_match *a, int flag,- struct archive_entry *entry)-{- struct match_file *f;- const void *pathname;- int r;-- f = calloc(1, sizeof(*f));- if (f == NULL)- return (error_nomem(a));--#if defined(_WIN32) && !defined(__CYGWIN__)- pathname = archive_entry_pathname_w(entry);- if (pathname == NULL) {- free(f);- archive_set_error(&(a->archive), EINVAL, "pathname is NULL");- return (ARCHIVE_FAILED);- }- archive_mstring_copy_wcs(&(f->pathname), pathname);- a->exclusion_tree.rbt_ops = &rb_ops_wcs;-#else- (void)rb_ops_wcs;- pathname = archive_entry_pathname(entry);- if (pathname == NULL) {- free(f);- archive_set_error(&(a->archive), EINVAL, "pathname is NULL");- return (ARCHIVE_FAILED);- }- archive_mstring_copy_mbs(&(f->pathname), pathname);- a->exclusion_tree.rbt_ops = &rb_ops_mbs;-#endif- f->flag = flag;- f->mtime_sec = archive_entry_mtime(entry);- f->mtime_nsec = archive_entry_mtime_nsec(entry);- f->ctime_sec = archive_entry_ctime(entry);- f->ctime_nsec = archive_entry_ctime_nsec(entry);- r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node));- if (!r) {- struct match_file *f2;-- /* Get the duplicated file. */- f2 = (struct match_file *)__archive_rb_tree_find_node(- &(a->exclusion_tree), pathname);-- /*- * We always overwrite comparison condition.- * If you do not want to overwrite it, you should not- * call archive_match_exclude_entry(). We cannot know- * what behavior you really expect since overwriting- * condition might be different with the flag.- */- if (f2 != NULL) {- f2->flag = f->flag;- f2->mtime_sec = f->mtime_sec;- f2->mtime_nsec = f->mtime_nsec;- f2->ctime_sec = f->ctime_sec;- f2->ctime_nsec = f->ctime_nsec;- }- /* Release the duplicated file. */- archive_mstring_clean(&(f->pathname));- free(f);- return (ARCHIVE_OK);- }- entry_list_add(&(a->exclusion_entry_list), f);- a->setflag |= TIME_IS_SET;- return (ARCHIVE_OK);-}--/*- * Test if entry is excluded by its timestamp.- */-static int-time_excluded(struct archive_match *a, struct archive_entry *entry)-{- struct match_file *f;- const void *pathname;- time_t sec;- long nsec;-- /*- * If this file/dir is excluded by a time comparison, skip it.- */- if (a->newer_ctime_filter) {- /* If ctime is not set, use mtime instead. */- if (archive_entry_ctime_is_set(entry))- sec = archive_entry_ctime(entry);- else- sec = archive_entry_mtime(entry);- if (sec < a->newer_ctime_sec)- return (1); /* Too old, skip it. */- if (sec == a->newer_ctime_sec) {- if (archive_entry_ctime_is_set(entry))- nsec = archive_entry_ctime_nsec(entry);- else- nsec = archive_entry_mtime_nsec(entry);- if (nsec < a->newer_ctime_nsec)- return (1); /* Too old, skip it. */- if (nsec == a->newer_ctime_nsec &&- (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL)- == 0)- return (1); /* Equal, skip it. */- }- }- if (a->older_ctime_filter) {- /* If ctime is not set, use mtime instead. */- if (archive_entry_ctime_is_set(entry))- sec = archive_entry_ctime(entry);- else- sec = archive_entry_mtime(entry);- if (sec > a->older_ctime_sec)- return (1); /* Too new, skip it. */- if (sec == a->older_ctime_sec) {- if (archive_entry_ctime_is_set(entry))- nsec = archive_entry_ctime_nsec(entry);- else- nsec = archive_entry_mtime_nsec(entry);- if (nsec > a->older_ctime_nsec)- return (1); /* Too new, skip it. */- if (nsec == a->older_ctime_nsec &&- (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL)- == 0)- return (1); /* Equal, skip it. */- }- }- if (a->newer_mtime_filter) {- sec = archive_entry_mtime(entry);- if (sec < a->newer_mtime_sec)- return (1); /* Too old, skip it. */- if (sec == a->newer_mtime_sec) {- nsec = archive_entry_mtime_nsec(entry);- if (nsec < a->newer_mtime_nsec)- return (1); /* Too old, skip it. */- if (nsec == a->newer_mtime_nsec &&- (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL)- == 0)- return (1); /* Equal, skip it. */- }- }- if (a->older_mtime_filter) {- sec = archive_entry_mtime(entry);- if (sec > a->older_mtime_sec)- return (1); /* Too new, skip it. */- nsec = archive_entry_mtime_nsec(entry);- if (sec == a->older_mtime_sec) {- if (nsec > a->older_mtime_nsec)- return (1); /* Too new, skip it. */- if (nsec == a->older_mtime_nsec &&- (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL)- == 0)- return (1); /* Equal, skip it. */- }- }-- /* If there is no exclusion list, include the file. */- if (a->exclusion_entry_list.count == 0)- return (0);--#if defined(_WIN32) && !defined(__CYGWIN__)- pathname = archive_entry_pathname_w(entry);- a->exclusion_tree.rbt_ops = &rb_ops_wcs;-#else- (void)rb_ops_wcs;- pathname = archive_entry_pathname(entry);- a->exclusion_tree.rbt_ops = &rb_ops_mbs;-#endif- if (pathname == NULL)- return (0);-- f = (struct match_file *)__archive_rb_tree_find_node(- &(a->exclusion_tree), pathname);- /* If the file wasn't rejected, include it. */- if (f == NULL)- return (0);-- if (f->flag & ARCHIVE_MATCH_CTIME) {- sec = archive_entry_ctime(entry);- if (f->ctime_sec > sec) {- if (f->flag & ARCHIVE_MATCH_OLDER)- return (1);- } else if (f->ctime_sec < sec) {- if (f->flag & ARCHIVE_MATCH_NEWER)- return (1);- } else {- nsec = archive_entry_ctime_nsec(entry);- if (f->ctime_nsec > nsec) {- if (f->flag & ARCHIVE_MATCH_OLDER)- return (1);- } else if (f->ctime_nsec < nsec) {- if (f->flag & ARCHIVE_MATCH_NEWER)- return (1);- } else if (f->flag & ARCHIVE_MATCH_EQUAL)- return (1);- }- }- if (f->flag & ARCHIVE_MATCH_MTIME) {- sec = archive_entry_mtime(entry);- if (f->mtime_sec > sec) {- if (f->flag & ARCHIVE_MATCH_OLDER)- return (1);- } else if (f->mtime_sec < sec) {- if (f->flag & ARCHIVE_MATCH_NEWER)- return (1);- } else {- nsec = archive_entry_mtime_nsec(entry);- if (f->mtime_nsec > nsec) {- if (f->flag & ARCHIVE_MATCH_OLDER)- return (1);- } else if (f->mtime_nsec < nsec) {- if (f->flag & ARCHIVE_MATCH_NEWER)- return (1);- } else if (f->flag & ARCHIVE_MATCH_EQUAL)- return (1);- }- }- return (0);-}--/*- * Utility functions to manage inclusion owners- */--int-archive_match_include_uid(struct archive *_a, la_int64_t uid)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_include_uid");- a = (struct archive_match *)_a;- return (add_owner_id(a, &(a->inclusion_uids), uid));-}--int-archive_match_include_gid(struct archive *_a, la_int64_t gid)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_include_gid");- a = (struct archive_match *)_a;- return (add_owner_id(a, &(a->inclusion_gids), gid));-}--int-archive_match_include_uname(struct archive *_a, const char *uname)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_include_uname");- a = (struct archive_match *)_a;- return (add_owner_name(a, &(a->inclusion_unames), 1, uname));-}--int-archive_match_include_uname_w(struct archive *_a, const wchar_t *uname)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_include_uname_w");- a = (struct archive_match *)_a;- return (add_owner_name(a, &(a->inclusion_unames), 0, uname));-}--int-archive_match_include_gname(struct archive *_a, const char *gname)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_include_gname");- a = (struct archive_match *)_a;- return (add_owner_name(a, &(a->inclusion_gnames), 1, gname));-}--int-archive_match_include_gname_w(struct archive *_a, const wchar_t *gname)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_include_gname_w");- a = (struct archive_match *)_a;- return (add_owner_name(a, &(a->inclusion_gnames), 0, gname));-}--/*- * Test function for owner(uid, gid, uname, gname).- *- * Returns 1 if archive entry is excluded.- * Returns 0 if archive entry is not excluded.- * Returns <0 if something error happened.- */-int-archive_match_owner_excluded(struct archive *_a,- struct archive_entry *entry)-{- struct archive_match *a;-- archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,- ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae");-- a = (struct archive_match *)_a;- if (entry == NULL) {- archive_set_error(&(a->archive), EINVAL, "entry is NULL");- return (ARCHIVE_FAILED);- }-- /* If we don't have inclusion id set at all, the entry is always- * not excluded. */- if ((a->setflag & ID_IS_SET) == 0)- return (0);- return (owner_excluded(a, entry));-}--static int-add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)-{- unsigned i;-- if (ids->count + 1 >= ids->size) {- void *p;-- if (ids->size == 0)- ids->size = 8;- else- ids->size *= 2;- p = realloc(ids->ids, sizeof(*ids->ids) * ids->size);- if (p == NULL)- return (error_nomem(a));- ids->ids = (int64_t *)p;- }-- /* Find an insert point. */- for (i = 0; i < ids->count; i++) {- if (ids->ids[i] >= id)- break;- }-- /* Add owner id. */- if (i == ids->count)- ids->ids[ids->count++] = id;- else if (ids->ids[i] != id) {- memmove(&(ids->ids[i+1]), &(ids->ids[i]),- (ids->count - i) * sizeof(ids->ids[0]));- ids->ids[i] = id;- ids->count++;- }- a->setflag |= ID_IS_SET;- return (ARCHIVE_OK);-}--static int-match_owner_id(struct id_array *ids, int64_t id)-{- unsigned b, m, t;-- t = 0;- b = (unsigned)ids->count;- while (t < b) {- m = (t + b)>>1;- if (ids->ids[m] == id)- return (1);- if (ids->ids[m] < id)- t = m + 1;- else- b = m;- }- return (0);-}--static int-add_owner_name(struct archive_match *a, struct match_list *list,- int mbs, const void *name)-{- struct match *match;-- match = calloc(1, sizeof(*match));- if (match == NULL)- return (error_nomem(a));- if (mbs)- archive_mstring_copy_mbs(&(match->pattern), name);- else- archive_mstring_copy_wcs(&(match->pattern), name);- match_list_add(list, match);- a->setflag |= ID_IS_SET;- return (ARCHIVE_OK);-}--#if !defined(_WIN32) || defined(__CYGWIN__)-static int-match_owner_name_mbs(struct archive_match *a, struct match_list *list,- const char *name)-{- struct match *m;- const char *p;-- if (name == NULL || *name == '\0')- return (0);- for (m = list->first; m; m = m->next) {- if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p)- < 0 && errno == ENOMEM)- return (error_nomem(a));- if (p != NULL && strcmp(p, name) == 0) {- m->matches++;- return (1);- }- }- return (0);-}-#else-static int-match_owner_name_wcs(struct archive_match *a, struct match_list *list,- const wchar_t *name)-{- struct match *m;- const wchar_t *p;-- if (name == NULL || *name == L'\0')- return (0);- for (m = list->first; m; m = m->next) {- if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p)- < 0 && errno == ENOMEM)- return (error_nomem(a));- if (p != NULL && wcscmp(p, name) == 0) {- m->matches++;- return (1);- }- }- return (0);-}-#endif--/*- * Test if entry is excluded by uid, gid, uname or gname.- */-static int-owner_excluded(struct archive_match *a, struct archive_entry *entry)-{- int r;-- if (a->inclusion_uids.count) {- if (!match_owner_id(&(a->inclusion_uids),- archive_entry_uid(entry)))- return (1);- }-- if (a->inclusion_gids.count) {- if (!match_owner_id(&(a->inclusion_gids),- archive_entry_gid(entry)))- return (1);- }-- if (a->inclusion_unames.count) {-#if defined(_WIN32) && !defined(__CYGWIN__)- r = match_owner_name_wcs(a, &(a->inclusion_unames),- archive_entry_uname_w(entry));-#else- r = match_owner_name_mbs(a, &(a->inclusion_unames),- archive_entry_uname(entry));-#endif- if (!r)- return (1);- else if (r < 0)- return (r);- }-- if (a->inclusion_gnames.count) {-#if defined(_WIN32) && !defined(__CYGWIN__)- r = match_owner_name_wcs(a, &(a->inclusion_gnames),- archive_entry_gname_w(entry));-#else- r = match_owner_name_mbs(a, &(a->inclusion_gnames),- archive_entry_gname(entry));-#endif- if (!r)- return (1);- else if (r < 0)- return (r);- }- return (0);-}-
− c/archive_openssl_evp_private.h
@@ -1,54 +0,0 @@-/*-- * 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.- */--#ifndef ARCHIVE_OPENSSL_EVP_PRIVATE_H_INCLUDED-#define ARCHIVE_OPENSSL_EVP_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--#include <openssl/evp.h>-#include <openssl/opensslv.h>--#if OPENSSL_VERSION_NUMBER < 0x10100000L || \- (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)-#include <stdlib.h> /* malloc, free */-#include <string.h> /* memset */-static inline EVP_MD_CTX *EVP_MD_CTX_new(void)-{- EVP_MD_CTX *ctx = (EVP_MD_CTX *)calloc(1, sizeof(EVP_MD_CTX));- return ctx;-}--static inline void EVP_MD_CTX_free(EVP_MD_CTX *ctx)-{- EVP_MD_CTX_cleanup(ctx);- memset(ctx, 0, sizeof(*ctx));- free(ctx);-}-#endif--#endif
− c/archive_openssl_hmac_private.h
@@ -1,54 +0,0 @@-/*-- * 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.- */--#ifndef ARCHIVE_OPENSSL_HMAC_PRIVATE_H_INCLUDED-#define ARCHIVE_OPENSSL_HMAC_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--#include <openssl/hmac.h>-#include <openssl/opensslv.h>--#if OPENSSL_VERSION_NUMBER < 0x10100000L || \- (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)-#include <stdlib.h> /* malloc, free */-#include <string.h> /* memset */-static inline HMAC_CTX *HMAC_CTX_new(void)-{- HMAC_CTX *ctx = (HMAC_CTX *)calloc(1, sizeof(HMAC_CTX));- return ctx;-}--static inline void HMAC_CTX_free(HMAC_CTX *ctx)-{- HMAC_CTX_cleanup(ctx);- memset(ctx, 0, sizeof(*ctx));- free(ctx);-}-#endif--#endif
− c/archive_options.c
@@ -1,218 +0,0 @@-/*-- * Copyright (c) 2011 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif--#include "archive_options_private.h"--static const char *-parse_option(const char **str,- const char **mod, const char **opt, const char **val);--int-_archive_set_option(struct archive *a,- const char *m, const char *o, const char *v,- int magic, const char *fn, option_handler use_option)-{- const char *mp, *op, *vp;- int r;-- archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);-- mp = (m != NULL && m[0] != '\0') ? m : NULL;- op = (o != NULL && o[0] != '\0') ? o : NULL;- vp = (v != NULL && v[0] != '\0') ? v : NULL;-- if (op == NULL && vp == NULL)- return (ARCHIVE_OK);- if (op == NULL) {- archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");- return (ARCHIVE_FAILED);- }-- r = use_option(a, mp, op, vp);- if (r == ARCHIVE_WARN - 1) {- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unknown module name: `%s'", mp);- return (ARCHIVE_FAILED);- }- if (r == ARCHIVE_WARN) {- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Undefined option: `%s%s%s%s%s%s'",- vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:"");- return (ARCHIVE_FAILED);- }- return (r);-}--int-_archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v,- option_handler use_format_option, option_handler use_filter_option)-{- int r1, r2;-- if (o == NULL && v == NULL)- return (ARCHIVE_OK);- if (o == NULL)- return (ARCHIVE_FAILED);-- r1 = use_format_option(a, m, o, v);- if (r1 == ARCHIVE_FATAL)- return (ARCHIVE_FATAL);-- r2 = use_filter_option(a, m, o, v);- if (r2 == ARCHIVE_FATAL)- return (ARCHIVE_FATAL);-- if (r2 == ARCHIVE_WARN - 1)- return r1;- return r1 > r2 ? r1 : r2;-}--int-_archive_set_options(struct archive *a, const char *options,- int magic, const char *fn, option_handler use_option)-{- int allok = 1, anyok = 0, ignore_mod_err = 0, r;- char *data;- const char *s, *mod, *opt, *val;-- archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);-- if (options == NULL || options[0] == '\0')- return ARCHIVE_OK;-- if ((data = strdup(options)) == NULL) {- archive_set_error(a,- ENOMEM, "Out of memory adding file to list");- return (ARCHIVE_FATAL);- }- s = (const char *)data;-- do {- mod = opt = val = NULL;-- parse_option(&s, &mod, &opt, &val);- if (mod == NULL && opt != NULL &&- strcmp("__ignore_wrong_module_name__", opt) == 0) {- /* Ignore module name error */- if (val != NULL) {- ignore_mod_err = 1;- anyok = 1;- }- continue;- }-- r = use_option(a, mod, opt, val);- if (r == ARCHIVE_FATAL) {- free(data);- return (ARCHIVE_FATAL);- }- if (r == ARCHIVE_FAILED && mod != NULL) {- free(data);- return (ARCHIVE_FAILED);- }- if (r == ARCHIVE_WARN - 1) {- if (ignore_mod_err)- continue;- /* The module name is wrong. */- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unknown module name: `%s'", mod);- free(data);- return (ARCHIVE_FAILED);- }- if (r == ARCHIVE_WARN) {- /* The option name is wrong. No-one used this. */- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Undefined option: `%s%s%s'",- mod?mod:"", mod?":":"", opt);- free(data);- return (ARCHIVE_FAILED);- }- if (r == ARCHIVE_OK)- anyok = 1;- else- allok = 0;- } while (s != NULL);-- free(data);- return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED;-}--static const char *-parse_option(const char **s, const char **m, const char **o, const char **v)-{- const char *end, *mod, *opt, *val;- char *p;-- end = NULL;- mod = NULL;- opt = *s;- val = "1";-- p = strchr(opt, ',');-- if (p != NULL) {- *p = '\0';- end = ((const char *)p) + 1;- }-- if (0 == strlen(opt)) {- *s = end;- *m = NULL;- *o = NULL;- *v = NULL;- return end;- }-- p = strchr(opt, ':');- if (p != NULL) {- *p = '\0';- mod = opt;- opt = ++p;- }-- p = strchr(opt, '=');- if (p != NULL) {- *p = '\0';- val = ++p;- } else if (opt[0] == '!') {- ++opt;- val = NULL;- }-- *s = end;- *m = mod;- *o = opt;- *v = val;-- return end;-}-
− c/archive_options_private.h
@@ -1,51 +0,0 @@-/*-- * Copyright (c) 2011 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.- */--#ifndef ARCHIVE_OPTIONS_PRIVATE_H_INCLUDED-#define ARCHIVE_OPTIONS_PRIVATE_H_INCLUDED--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#include "archive_private.h"--typedef int (*option_handler)(struct archive *a,- const char *mod, const char *opt, const char *val);--int-_archive_set_option(struct archive *a,- const char *mod, const char *opt, const char *val,- int magic, const char *fn, option_handler use_option);--int-_archive_set_options(struct archive *a, const char *options,- int magic, const char *fn, option_handler use_option);--int-_archive_set_either_option(struct archive *a,- const char *m, const char *o, const char *v,- option_handler use_format_option, option_handler use_filter_option);--#endif
− c/archive_pack_dev.c
@@ -1,337 +0,0 @@-/* $NetBSD: pack_dev.c,v 1.12 2013/06/14 16:28:20 tsutsui Exp $ */--/*-- * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.- * All rights reserved.- *- * This code is derived from software contributed to The NetBSD Foundation- * by Charles M. Hannum.- *- * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE- * POSSIBILITY OF SUCH DAMAGE.- */--/* Originally from NetBSD's mknod(8) source. */--#include "archive_platform.h"--#if HAVE_SYS_CDEFS_H-#include <sys/cdefs.h>-#endif-#if !defined(lint)-__RCSID("$NetBSD$");-#endif /* not lint */--#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif--#include <stdio.h>-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#if MAJOR_IN_MKDEV-#include <sys/mkdev.h>-#define HAVE_MAJOR-#elif MAJOR_IN_SYSMACROS-#include <sys/sysmacros.h>-#define HAVE_MAJOR-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive_pack_dev.h"--static pack_t pack_netbsd;-static pack_t pack_freebsd;-static pack_t pack_8_8;-static pack_t pack_12_20;-static pack_t pack_14_18;-static pack_t pack_8_24;-static pack_t pack_bsdos;-static int __LA_LIBC_CC compare_format(const void *, const void *);--static const char iMajorError[] = "invalid major number";-static const char iMinorError[] = "invalid minor number";-static const char tooManyFields[] = "too many fields for format";--/* This is blatantly stolen from libarchive/archive_entry.c,- * in an attempt to get this to play nice on MinGW... */-#if !defined(HAVE_MAJOR) && !defined(major)-/* Replacement for major/minor/makedev. */-#define major(x) ((int)(0x00ff & ((x) >> 8)))-#define minor(x) ((int)(0xffff00ff & (x)))-#define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min)))-#endif--/* Play games to come up with a suitable makedev() definition. */-#ifdef __QNXNTO__-/* QNX. <sigh> */-#include <sys/netmgr.h>-#define apd_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min))-#elif defined makedev-/* There's a "makedev" macro. */-#define apd_makedev(maj, min) makedev((maj), (min))-#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__))-/* Windows. <sigh> */-#define apd_makedev(maj, min) mkdev((maj), (min))-#else-/* There's a "makedev" function. */-#define apd_makedev(maj, min) makedev((maj), (min))-#endif--/* exported */-dev_t-pack_native(int n, unsigned long numbers[], const char **error)-{- dev_t dev = 0;-- if (n == 2) {- dev = apd_makedev(numbers[0], numbers[1]);- if ((unsigned long)major(dev) != numbers[0])- *error = iMajorError;- else if ((unsigned long)minor(dev) != numbers[1])- *error = iMinorError;- } else- *error = tooManyFields;- return (dev);-}---static dev_t-pack_netbsd(int n, unsigned long numbers[], const char **error)-{- dev_t dev = 0;-- if (n == 2) {- dev = makedev_netbsd(numbers[0], numbers[1]);- if ((unsigned long)major_netbsd(dev) != numbers[0])- *error = iMajorError;- else if ((unsigned long)minor_netbsd(dev) != numbers[1])- *error = iMinorError;- } else- *error = tooManyFields;- return (dev);-}---#define major_freebsd(x) ((int32_t)(((x) & 0x0000ff00) >> 8))-#define minor_freebsd(x) ((int32_t)(((x) & 0xffff00ff) >> 0))-#define makedev_freebsd(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \- (((y) << 0) & 0xffff00ff)))--static dev_t-pack_freebsd(int n, unsigned long numbers[], const char **error)-{- dev_t dev = 0;-- if (n == 2) {- dev = makedev_freebsd(numbers[0], numbers[1]);- if ((unsigned long)major_freebsd(dev) != numbers[0])- *error = iMajorError;- if ((unsigned long)minor_freebsd(dev) != numbers[1])- *error = iMinorError;- } else- *error = tooManyFields;- return (dev);-}---#define major_8_8(x) ((int32_t)(((x) & 0x0000ff00) >> 8))-#define minor_8_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))-#define makedev_8_8(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \- (((y) << 0) & 0x000000ff)))--static dev_t-pack_8_8(int n, unsigned long numbers[], const char **error)-{- dev_t dev = 0;-- if (n == 2) {- dev = makedev_8_8(numbers[0], numbers[1]);- if ((unsigned long)major_8_8(dev) != numbers[0])- *error = iMajorError;- if ((unsigned long)minor_8_8(dev) != numbers[1])- *error = iMinorError;- } else- *error = tooManyFields;- return (dev);-}---#define major_12_20(x) ((int32_t)(((x) & 0xfff00000) >> 20))-#define minor_12_20(x) ((int32_t)(((x) & 0x000fffff) >> 0))-#define makedev_12_20(x,y) ((dev_t)((((x) << 20) & 0xfff00000) | \- (((y) << 0) & 0x000fffff)))--static dev_t-pack_12_20(int n, unsigned long numbers[], const char **error)-{- dev_t dev = 0;-- if (n == 2) {- dev = makedev_12_20(numbers[0], numbers[1]);- if ((unsigned long)major_12_20(dev) != numbers[0])- *error = iMajorError;- if ((unsigned long)minor_12_20(dev) != numbers[1])- *error = iMinorError;- } else- *error = tooManyFields;- return (dev);-}---#define major_14_18(x) ((int32_t)(((x) & 0xfffc0000) >> 18))-#define minor_14_18(x) ((int32_t)(((x) & 0x0003ffff) >> 0))-#define makedev_14_18(x,y) ((dev_t)((((x) << 18) & 0xfffc0000) | \- (((y) << 0) & 0x0003ffff)))--static dev_t-pack_14_18(int n, unsigned long numbers[], const char **error)-{- dev_t dev = 0;-- if (n == 2) {- dev = makedev_14_18(numbers[0], numbers[1]);- if ((unsigned long)major_14_18(dev) != numbers[0])- *error = iMajorError;- if ((unsigned long)minor_14_18(dev) != numbers[1])- *error = iMinorError;- } else- *error = tooManyFields;- return (dev);-}---#define major_8_24(x) ((int32_t)(((x) & 0xff000000) >> 24))-#define minor_8_24(x) ((int32_t)(((x) & 0x00ffffff) >> 0))-#define makedev_8_24(x,y) ((dev_t)((((x) << 24) & 0xff000000) | \- (((y) << 0) & 0x00ffffff)))--static dev_t-pack_8_24(int n, unsigned long numbers[], const char **error)-{- dev_t dev = 0;-- if (n == 2) {- dev = makedev_8_24(numbers[0], numbers[1]);- if ((unsigned long)major_8_24(dev) != numbers[0])- *error = iMajorError;- if ((unsigned long)minor_8_24(dev) != numbers[1])- *error = iMinorError;- } else- *error = tooManyFields;- return (dev);-}---#define major_12_12_8(x) ((int32_t)(((x) & 0xfff00000) >> 20))-#define unit_12_12_8(x) ((int32_t)(((x) & 0x000fff00) >> 8))-#define subunit_12_12_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))-#define makedev_12_12_8(x,y,z) ((dev_t)((((x) << 20) & 0xfff00000) | \- (((y) << 8) & 0x000fff00) | \- (((z) << 0) & 0x000000ff)))--static dev_t-pack_bsdos(int n, unsigned long numbers[], const char **error)-{- dev_t dev = 0;-- if (n == 2) {- dev = makedev_12_20(numbers[0], numbers[1]);- if ((unsigned long)major_12_20(dev) != numbers[0])- *error = iMajorError;- if ((unsigned long)minor_12_20(dev) != numbers[1])- *error = iMinorError;- } else if (n == 3) {- dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]);- if ((unsigned long)major_12_12_8(dev) != numbers[0])- *error = iMajorError;- if ((unsigned long)unit_12_12_8(dev) != numbers[1])- *error = "invalid unit number";- if ((unsigned long)subunit_12_12_8(dev) != numbers[2])- *error = "invalid subunit number";- } else- *error = tooManyFields;- return (dev);-}--- /* list of formats and pack functions */- /* this list must be sorted lexically */-static const struct format {- const char *name;- pack_t *pack;-} formats[] = {- {"386bsd", pack_8_8},- {"4bsd", pack_8_8},- {"bsdos", pack_bsdos},- {"freebsd", pack_freebsd},- {"hpux", pack_8_24},- {"isc", pack_8_8},- {"linux", pack_8_8},- {"native", pack_native},- {"netbsd", pack_netbsd},- {"osf1", pack_12_20},- {"sco", pack_8_8},- {"solaris", pack_14_18},- {"sunos", pack_8_8},- {"svr3", pack_8_8},- {"svr4", pack_14_18},- {"ultrix", pack_8_8},-};--static int-__LA_LIBC_CC-compare_format(const void *key, const void *element)-{- const char *name;- const struct format *format;-- name = key;- format = element;-- return (strcmp(name, format->name));-}---pack_t *-pack_find(const char *name)-{- struct format *format;-- format = bsearch(name, formats,- sizeof(formats)/sizeof(formats[0]),- sizeof(formats[0]), compare_format);- if (format == 0)- return (NULL);- return (format->pack);-}
− c/archive_pack_dev.h
@@ -1,49 +0,0 @@-/* $NetBSD: pack_dev.h,v 1.8 2013/06/14 16:28:20 tsutsui Exp $ */--/*-- * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.- * All rights reserved.- *- * This code is derived from software contributed to The NetBSD Foundation- * by Charles M. Hannum.- *- * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE- * POSSIBILITY OF SUCH DAMAGE.- */--/* Originally from NetBSD's mknod(8) source. */--#ifndef ARCHIVE_PACK_DEV_H-#define ARCHIVE_PACK_DEV_H--typedef dev_t pack_t(int, unsigned long [], const char **);--pack_t *pack_find(const char *);-pack_t pack_native;--#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8)))-#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \- (((x) & 0x000000ff) >> 0)))-#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \- (((y) << 12) & 0xfff00000) | \- (((y) << 0) & 0x000000ff)))--#endif /* ARCHIVE_PACK_DEV_H */
− c/archive_pathmatch.c
@@ -1,463 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_WCHAR_H-#include <wchar.h>-#endif--#include "archive_pathmatch.h"--/*- * Check whether a character 'c' is matched by a list specification [...]:- * * Leading '!' or '^' negates the class.- * * <char>-<char> is a range of characters- * * \<char> removes any special meaning for <char>- *- * Some interesting boundary cases:- * a-d-e is one range (a-d) followed by two single characters - and e.- * \a-\d is same as a-d- * a\-d is three single characters: a, d, -- * Trailing - is not special (so [a-] is two characters a and -).- * Initial - is not special ([a-] is same as [-a] is same as [\\-a])- * This function never sees a trailing \.- * [] always fails- * [!] always succeeds- */-static int-pm_list(const char *start, const char *end, const char c, int flags)-{- const char *p = start;- char rangeStart = '\0', nextRangeStart;- int match = 1, nomatch = 0;-- /* This will be used soon... */- (void)flags; /* UNUSED */-- /* If this is a negated class, return success for nomatch. */- if ((*p == '!' || *p == '^') && p < end) {- match = 0;- nomatch = 1;- ++p;- }-- while (p < end) {- nextRangeStart = '\0';- switch (*p) {- case '-':- /* Trailing or initial '-' is not special. */- if ((rangeStart == '\0') || (p == end - 1)) {- if (*p == c)- return (match);- } else {- char rangeEnd = *++p;- if (rangeEnd == '\\')- rangeEnd = *++p;- if ((rangeStart <= c) && (c <= rangeEnd))- return (match);- }- break;- case '\\':- ++p;- /* Fall through */- default:- if (*p == c)- return (match);- nextRangeStart = *p; /* Possible start of range. */- }- rangeStart = nextRangeStart;- ++p;- }- return (nomatch);-}--static int-pm_list_w(const wchar_t *start, const wchar_t *end, const wchar_t c, int flags)-{- const wchar_t *p = start;- wchar_t rangeStart = L'\0', nextRangeStart;- int match = 1, nomatch = 0;-- /* This will be used soon... */- (void)flags; /* UNUSED */-- /* If this is a negated class, return success for nomatch. */- if ((*p == L'!' || *p == L'^') && p < end) {- match = 0;- nomatch = 1;- ++p;- }-- while (p < end) {- nextRangeStart = L'\0';- switch (*p) {- case L'-':- /* Trailing or initial '-' is not special. */- if ((rangeStart == L'\0') || (p == end - 1)) {- if (*p == c)- return (match);- } else {- wchar_t rangeEnd = *++p;- if (rangeEnd == L'\\')- rangeEnd = *++p;- if ((rangeStart <= c) && (c <= rangeEnd))- return (match);- }- break;- case L'\\':- ++p;- /* Fall through */- default:- if (*p == c)- return (match);- nextRangeStart = *p; /* Possible start of range. */- }- rangeStart = nextRangeStart;- ++p;- }- return (nomatch);-}--/*- * If s is pointing to "./", ".//", "./././" or the like, skip it.- */-static const char *-pm_slashskip(const char *s) {- while ((*s == '/')- || (s[0] == '.' && s[1] == '/')- || (s[0] == '.' && s[1] == '\0'))- ++s;- return (s);-}--static const wchar_t *-pm_slashskip_w(const wchar_t *s) {- while ((*s == L'/')- || (s[0] == L'.' && s[1] == L'/')- || (s[0] == L'.' && s[1] == L'\0'))- ++s;- return (s);-}--static int-pm(const char *p, const char *s, int flags)-{- const char *end;-- /*- * Ignore leading './', './/', '././', etc.- */- if (s[0] == '.' && s[1] == '/')- s = pm_slashskip(s + 1);- if (p[0] == '.' && p[1] == '/')- p = pm_slashskip(p + 1);-- for (;;) {- switch (*p) {- case '\0':- if (s[0] == '/') {- if (flags & PATHMATCH_NO_ANCHOR_END)- return (1);- /* "dir" == "dir/" == "dir/." */- s = pm_slashskip(s);- }- return (*s == '\0');- case '?':- /* ? always succeeds, unless we hit end of 's' */- if (*s == '\0')- return (0);- break;- case '*':- /* "*" == "**" == "***" ... */- while (*p == '*')- ++p;- /* Trailing '*' always succeeds. */- if (*p == '\0')- return (1);- while (*s) {- if (archive_pathmatch(p, s, flags))- return (1);- ++s;- }- return (0);- case '[':- /*- * Find the end of the [...] character class,- * ignoring \] that might occur within the class.- */- end = p + 1;- while (*end != '\0' && *end != ']') {- if (*end == '\\' && end[1] != '\0')- ++end;- ++end;- }- if (*end == ']') {- /* We found [...], try to match it. */- if (!pm_list(p + 1, end, *s, flags))- return (0);- p = end; /* Jump to trailing ']' char. */- break;- } else- /* No final ']', so just match '['. */- if (*p != *s)- return (0);- break;- case '\\':- /* Trailing '\\' matches itself. */- if (p[1] == '\0') {- if (*s != '\\')- return (0);- } else {- ++p;- if (*p != *s)- return (0);- }- break;- case '/':- if (*s != '/' && *s != '\0')- return (0);- /* Note: pattern "/\./" won't match "/";- * pm_slashskip() correctly stops at backslash. */- p = pm_slashskip(p);- s = pm_slashskip(s);- if (*p == '\0' && (flags & PATHMATCH_NO_ANCHOR_END))- return (1);- --p; /* Counteract the increment below. */- --s;- break;- case '$':- /* '$' is special only at end of pattern and only- * if PATHMATCH_NO_ANCHOR_END is specified. */- if (p[1] == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)){- /* "dir" == "dir/" == "dir/." */- return (*pm_slashskip(s) == '\0');- }- /* Otherwise, '$' is not special. */- /* FALL THROUGH */- default:- if (*p != *s)- return (0);- break;- }- ++p;- ++s;- }-}--static int-pm_w(const wchar_t *p, const wchar_t *s, int flags)-{- const wchar_t *end;-- /*- * Ignore leading './', './/', '././', etc.- */- if (s[0] == L'.' && s[1] == L'/')- s = pm_slashskip_w(s + 1);- if (p[0] == L'.' && p[1] == L'/')- p = pm_slashskip_w(p + 1);-- for (;;) {- switch (*p) {- case L'\0':- if (s[0] == L'/') {- if (flags & PATHMATCH_NO_ANCHOR_END)- return (1);- /* "dir" == "dir/" == "dir/." */- s = pm_slashskip_w(s);- }- return (*s == L'\0');- case L'?':- /* ? always succeeds, unless we hit end of 's' */- if (*s == L'\0')- return (0);- break;- case L'*':- /* "*" == "**" == "***" ... */- while (*p == L'*')- ++p;- /* Trailing '*' always succeeds. */- if (*p == L'\0')- return (1);- while (*s) {- if (archive_pathmatch_w(p, s, flags))- return (1);- ++s;- }- return (0);- case L'[':- /*- * Find the end of the [...] character class,- * ignoring \] that might occur within the class.- */- end = p + 1;- while (*end != L'\0' && *end != L']') {- if (*end == L'\\' && end[1] != L'\0')- ++end;- ++end;- }- if (*end == L']') {- /* We found [...], try to match it. */- if (!pm_list_w(p + 1, end, *s, flags))- return (0);- p = end; /* Jump to trailing ']' char. */- break;- } else- /* No final ']', so just match '['. */- if (*p != *s)- return (0);- break;- case L'\\':- /* Trailing '\\' matches itself. */- if (p[1] == L'\0') {- if (*s != L'\\')- return (0);- } else {- ++p;- if (*p != *s)- return (0);- }- break;- case L'/':- if (*s != L'/' && *s != L'\0')- return (0);- /* Note: pattern "/\./" won't match "/";- * pm_slashskip() correctly stops at backslash. */- p = pm_slashskip_w(p);- s = pm_slashskip_w(s);- if (*p == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END))- return (1);- --p; /* Counteract the increment below. */- --s;- break;- case L'$':- /* '$' is special only at end of pattern and only- * if PATHMATCH_NO_ANCHOR_END is specified. */- if (p[1] == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END)){- /* "dir" == "dir/" == "dir/." */- return (*pm_slashskip_w(s) == L'\0');- }- /* Otherwise, '$' is not special. */- /* FALL THROUGH */- default:- if (*p != *s)- return (0);- break;- }- ++p;- ++s;- }-}--/* Main entry point. */-int-__archive_pathmatch(const char *p, const char *s, int flags)-{- /* Empty pattern only matches the empty string. */- if (p == NULL || *p == '\0')- return (s == NULL || *s == '\0');- else if (s == NULL)- return (0);-- /* Leading '^' anchors the start of the pattern. */- if (*p == '^') {- ++p;- flags &= ~PATHMATCH_NO_ANCHOR_START;- }-- if (*p == '/' && *s != '/')- return (0);-- /* Certain patterns anchor implicitly. */- if (*p == '*' || *p == '/') {- while (*p == '/')- ++p;- while (*s == '/')- ++s;- return (pm(p, s, flags));- }-- /* If start is unanchored, try to match start of each path element. */- if (flags & PATHMATCH_NO_ANCHOR_START) {- for ( ; s != NULL; s = strchr(s, '/')) {- if (*s == '/')- s++;- if (pm(p, s, flags))- return (1);- }- return (0);- }-- /* Default: Match from beginning. */- return (pm(p, s, flags));-}--int-__archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)-{- /* Empty pattern only matches the empty string. */- if (p == NULL || *p == L'\0')- return (s == NULL || *s == L'\0');- else if (s == NULL)- return (0);-- /* Leading '^' anchors the start of the pattern. */- if (*p == L'^') {- ++p;- flags &= ~PATHMATCH_NO_ANCHOR_START;- }-- if (*p == L'/' && *s != L'/')- return (0);-- /* Certain patterns anchor implicitly. */- if (*p == L'*' || *p == L'/') {- while (*p == L'/')- ++p;- while (*s == L'/')- ++s;- return (pm_w(p, s, flags));- }-- /* If start is unanchored, try to match start of each path element. */- if (flags & PATHMATCH_NO_ANCHOR_START) {- for ( ; s != NULL; s = wcschr(s, L'/')) {- if (*s == L'/')- s++;- if (pm_w(p, s, flags))- return (1);- }- return (0);- }-- /* Default: Match from beginning. */- return (pm_w(p, s, flags));-}
− c/archive_pathmatch.h
@@ -1,52 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- */--#ifndef ARCHIVE_PATHMATCH_H-#define ARCHIVE_PATHMATCH_H--#ifndef __LIBARCHIVE_BUILD-#ifndef __LIBARCHIVE_TEST-#error This header is only to be used internally to libarchive.-#endif-#endif--/* Don't anchor at beginning unless the pattern starts with "^" */-#define PATHMATCH_NO_ANCHOR_START 1-/* Don't anchor at end unless the pattern ends with "$" */-#define PATHMATCH_NO_ANCHOR_END 2--/* Note that "^" and "$" are not special unless you set the corresponding- * flag above. */--int __archive_pathmatch(const char *p, const char *s, int flags);-int __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags);--#define archive_pathmatch(p, s, f) __archive_pathmatch(p, s, f)-#define archive_pathmatch_w(p, s, f) __archive_pathmatch_w(p, s, f)--#endif
− c/archive_platform.h
@@ -1,233 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD: head/lib/libarchive/archive_platform.h 201090 2009-12-28 02:22:04Z kientzle $- */--/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */--/*- * This header is the first thing included in any of the libarchive- * source files. As far as possible, platform-specific issues should- * be dealt with here and not within individual source files. I'm- * actively trying to minimize #if blocks within the main source,- * since they obfuscate the code.- */--#ifndef ARCHIVE_PLATFORM_H_INCLUDED-#define ARCHIVE_PLATFORM_H_INCLUDED--/* archive.h and archive_entry.h require this. */-#define __LIBARCHIVE_BUILD 1--#if defined(PLATFORM_CONFIG_H)-/* Use hand-built config.h in environments that need it. */-#include PLATFORM_CONFIG_H-#elif defined(HAVE_CONFIG_H)-/* Most POSIX platforms use the 'configure' script to build config.h */-#include "config.h"-#else-/* Warn if the library hasn't been (automatically or manually) configured. */-#error Oops: No config.h and no pre-built configuration in archive_platform.h.-#endif--/* On macOS check for some symbols based on the deployment target version. */-#if defined(__APPLE__)-# undef HAVE_FUTIMENS-# undef HAVE_UTIMENSAT-# include <AvailabilityMacros.h>-# if MAC_OS_X_VERSION_MIN_REQUIRED >= 101300-# define HAVE_FUTIMENS 1-# define HAVE_UTIMENSAT 1-# endif-#endif--/* It should be possible to get rid of this by extending the feature-test- * macros to cover Windows API functions, probably along with non-trivial- * refactoring of code to find structures that sit more cleanly on top of- * either Windows or Posix APIs. */-#if (defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)-#include "archive_windows.h"-/* The C library on Windows specifies a calling convention for callback- * functions and exports; when we interact with them (capture pointers,- * call and pass function pointers) we need to match their calling- * convention.- * This only matters when libarchive is built with /Gr, /Gz or /Gv- * (which change the default calling convention.) */-#define __LA_LIBC_CC __cdecl-#else-#define la_stat(path,stref) stat(path,stref)-#define __LA_LIBC_CC-#endif--/*- * The config files define a lot of feature macros. The following- * uses those macros to select/define replacements and include key- * headers as required.- */--/* Get a real definition for __FBSDID or __RCSID if we can */-#if HAVE_SYS_CDEFS_H-#include <sys/cdefs.h>-#endif--/* If not, define them so as to avoid dangling semicolons. */-#ifndef __FBSDID-#define __FBSDID(a) struct _undefined_hack-#endif-#ifndef __RCSID-#define __RCSID(a) struct _undefined_hack-#endif--/* Try to get standard C99-style integer type definitions. */-#if HAVE_INTTYPES_H-#include <inttypes.h>-#endif-#if HAVE_STDINT_H-#include <stdint.h>-#endif--/* Borland warns about its own constants! */-#if defined(__BORLANDC__)-# if HAVE_DECL_UINT64_MAX-# undef UINT64_MAX-# undef HAVE_DECL_UINT64_MAX-# endif-# if HAVE_DECL_UINT64_MIN-# undef UINT64_MIN-# undef HAVE_DECL_UINT64_MIN-# endif-# if HAVE_DECL_INT64_MAX-# undef INT64_MAX-# undef HAVE_DECL_INT64_MAX-# endif-# if HAVE_DECL_INT64_MIN-# undef INT64_MIN-# undef HAVE_DECL_INT64_MIN-# endif-#endif--/* Some platforms lack the standard *_MAX definitions. */-#if !HAVE_DECL_SIZE_MAX-#define SIZE_MAX (~(size_t)0)-#endif-#if !HAVE_DECL_SSIZE_MAX-#define SSIZE_MAX ((ssize_t)(SIZE_MAX >> 1))-#endif-#if !HAVE_DECL_UINT32_MAX-#define UINT32_MAX (~(uint32_t)0)-#endif-#if !HAVE_DECL_INT32_MAX-#define INT32_MAX ((int32_t)(UINT32_MAX >> 1))-#endif-#if !HAVE_DECL_INT32_MIN-#define INT32_MIN ((int32_t)(~INT32_MAX))-#endif-#if !HAVE_DECL_UINT64_MAX-#define UINT64_MAX (~(uint64_t)0)-#endif-#if !HAVE_DECL_INT64_MAX-#define INT64_MAX ((int64_t)(UINT64_MAX >> 1))-#endif-#if !HAVE_DECL_INT64_MIN-#define INT64_MIN ((int64_t)(~INT64_MAX))-#endif-#if !HAVE_DECL_UINTMAX_MAX-#define UINTMAX_MAX (~(uintmax_t)0)-#endif-#if !HAVE_DECL_INTMAX_MAX-#define INTMAX_MAX ((intmax_t)(UINTMAX_MAX >> 1))-#endif-#if !HAVE_DECL_INTMAX_MIN-#define INTMAX_MIN ((intmax_t)(~INTMAX_MAX))-#endif--/* Some platforms lack the standard PRIxN/PRIdN definitions. */-#if !HAVE_INTTYPES_H || !defined(PRIx32) || !defined(PRId32)-#ifndef PRIx32-#if SIZEOF_INT == 4-#define PRIx32 "x"-#elif SIZEOF_LONG == 4-#define PRIx32 "lx"-#else-#error No suitable 32-bit unsigned integer type found for this platform-#endif-#endif // PRIx32-#ifndef PRId32-#if SIZEOF_INT == 4-#define PRId32 "d"-#elif SIZEOF_LONG == 4-#define PRId32 "ld"-#else-#error No suitable 32-bit signed integer type found for this platform-#endif-#endif // PRId32-#endif // !HAVE_INTTYPES_H || !defined(PRIx32) || !defined(PRId32)--/*- * If we can't restore metadata using a file descriptor, then- * for compatibility's sake, close files before trying to restore metadata.- */-#if defined(HAVE_FCHMOD) || defined(HAVE_FUTIMES) || defined(HAVE_ACL_SET_FD) || defined(HAVE_ACL_SET_FD_NP) || defined(HAVE_FCHOWN)-#define CAN_RESTORE_METADATA_FD-#endif--/*- * glibc 2.24 deprecates readdir_r- * bionic c deprecates readdir_r too- */-#if defined(HAVE_READDIR_R) && (!defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24)) && (!defined(__ANDROID__))-#define USE_READDIR_R 1-#else-#undef USE_READDIR_R-#endif--/* Set up defaults for internal error codes. */-#ifndef ARCHIVE_ERRNO_FILE_FORMAT-#if HAVE_EFTYPE-#define ARCHIVE_ERRNO_FILE_FORMAT EFTYPE-#else-#if HAVE_EILSEQ-#define ARCHIVE_ERRNO_FILE_FORMAT EILSEQ-#else-#define ARCHIVE_ERRNO_FILE_FORMAT EINVAL-#endif-#endif-#endif--#ifndef ARCHIVE_ERRNO_PROGRAMMER-#define ARCHIVE_ERRNO_PROGRAMMER EINVAL-#endif--#ifndef ARCHIVE_ERRNO_MISC-#define ARCHIVE_ERRNO_MISC (-1)-#endif--#if defined(__GNUC__) && (__GNUC__ >= 7)-#define __LA_FALLTHROUGH __attribute__((fallthrough))-#else-#define __LA_FALLTHROUGH-#endif--#endif /* !ARCHIVE_PLATFORM_H_INCLUDED */
− c/archive_platform_acl.h
@@ -1,55 +0,0 @@-/*-- * Copyright (c) 2017 Martin Matuska- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- */--/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */--#ifndef ARCHIVE_PLATFORM_ACL_H_INCLUDED-#define ARCHIVE_PLATFORM_ACL_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#ifndef __LIBARCHIVE_TEST_COMMON-#error This header is only to be used internally to libarchive.-#endif-#endif--/*- * Determine what ACL types are supported- */-#if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_SUNOS || ARCHIVE_ACL_LIBACL-#define ARCHIVE_ACL_POSIX1E 1-#endif--#if ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_SUNOS_NFS4 || \- ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL-#define ARCHIVE_ACL_NFS4 1-#endif--#if ARCHIVE_ACL_POSIX1E || ARCHIVE_ACL_NFS4-#define ARCHIVE_ACL_SUPPORT 1-#endif--#endif /* ARCHIVE_PLATFORM_ACL_H_INCLUDED */
− c/archive_platform_xattr.h
@@ -1,47 +0,0 @@-/*-- * Copyright (c) 2017 Martin Matuska- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- */--/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */--#ifndef ARCHIVE_PLATFORM_XATTR_H_INCLUDED-#define ARCHIVE_PLATFORM_XATTR_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#ifndef __LIBARCHIVE_TEST_COMMON-#error This header is only to be used internally to libarchive.-#endif-#endif--/*- * Determine if we support extended attributes- */-#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_FREEBSD || \- ARCHIVE_XATTR_AIX-#define ARCHIVE_XATTR_SUPPORT 1-#endif--#endif /* ARCHIVE_PLATFORM_XATTR_H_INCLUDED */
− c/archive_ppmd7.c
@@ -1,1168 +0,0 @@-/* Ppmd7.c -- PPMdH codec-2010-03-12 : Igor Pavlov : Public domain-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */--#include "archive_platform.h"--#include <stdlib.h>--#include "archive_ppmd7_private.h"--#ifdef PPMD_32BIT- #define Ppmd7_GetPtr(p, ptr) (ptr)- #define Ppmd7_GetContext(p, ptr) (ptr)- #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats)-#else- #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs)))- #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs)))- #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats)))-#endif--#define Ppmd7_GetBinSumm(p) \- &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \- p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \- (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \- 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \- ((p->RunLength >> 26) & 0x20)]--#define kTopValue (1 << 24)-#define MAX_FREQ 124-#define UNIT_SIZE 12--#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)-#define U2I(nu) (p->Units2Indx[(nu) - 1])-#define I2U(indx) (p->Indx2Units[indx])--#ifdef PPMD_32BIT- #define REF(ptr) (ptr)-#else- #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))-#endif--#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))--#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))-#define STATS(ctx) Ppmd7_GetStats(p, ctx)-#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx)-#define SUFFIX(ctx) CTX((ctx)->Suffix)--static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};-static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };--typedef CPpmd7_Context * CTX_PTR;--struct CPpmd7_Node_;--typedef- #ifdef PPMD_32BIT- struct CPpmd7_Node_ *- #else- UInt32- #endif- CPpmd7_Node_Ref;--typedef struct CPpmd7_Node_-{- UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */- UInt16 NU;- CPpmd7_Node_Ref Next; /* must be at offset >= 4 */- CPpmd7_Node_Ref Prev;-} CPpmd7_Node;--#ifdef PPMD_32BIT- #define NODE(ptr) (ptr)-#else- #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs)))-#endif--static void Ppmd7_Update1(CPpmd7 *p);-static void Ppmd7_Update1_0(CPpmd7 *p);-static void Ppmd7_Update2(CPpmd7 *p);-static void Ppmd7_UpdateBin(CPpmd7 *p);-static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked,- UInt32 *scale);--/* ----------- Base ----------- */--static void Ppmd7_Construct(CPpmd7 *p)-{- unsigned i, k, m;-- p->Base = 0;-- for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)- {- unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);- do { p->Units2Indx[k++] = (Byte)i; } while(--step);- p->Indx2Units[i] = (Byte)k;- }-- p->NS2BSIndx[0] = (0 << 1);- p->NS2BSIndx[1] = (1 << 1);- memset(p->NS2BSIndx + 2, (2 << 1), 9);- memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);-- for (i = 0; i < 3; i++)- p->NS2Indx[i] = (Byte)i;- for (m = i, k = 1; i < 256; i++)- {- p->NS2Indx[i] = (Byte)m;- if (--k == 0)- k = (++m) - 2;- }-- memset(p->HB2Flag, 0, 0x40);- memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);-}--static void Ppmd7_Free(CPpmd7 *p)-{- free(p->Base);- p->Size = 0;- p->Base = 0;-}--static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size)-{- if (p->Base == 0 || p->Size != size)- {- /* RestartModel() below assumes that p->Size >= UNIT_SIZE- (see the calculation of m->MinContext). */- if (size < UNIT_SIZE) {- return False;- }- Ppmd7_Free(p);- p->AlignOffset =- #ifdef PPMD_32BIT- (4 - size) & 3;- #else- 4 - (size & 3);- #endif- if ((p->Base = (Byte *)malloc(p->AlignOffset + size- #ifndef PPMD_32BIT- + UNIT_SIZE- #endif- )) == 0)- return False;- p->Size = size;- }- return True;-}--static void InsertNode(CPpmd7 *p, void *node, unsigned indx)-{- *((CPpmd_Void_Ref *)node) = p->FreeList[indx];- p->FreeList[indx] = REF(node);-}--static void *RemoveNode(CPpmd7 *p, unsigned indx)-{- CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);- p->FreeList[indx] = *node;- return node;-}--static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx)-{- unsigned i, nu = I2U(oldIndx) - I2U(newIndx);- ptr = (Byte *)ptr + U2B(I2U(newIndx));- if (I2U(i = U2I(nu)) != nu)- {- unsigned k = I2U(--i);- InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);- }- InsertNode(p, ptr, i);-}--static void GlueFreeBlocks(CPpmd7 *p)-{- #ifdef PPMD_32BIT- CPpmd7_Node headItem;- CPpmd7_Node_Ref head = &headItem;- #else- CPpmd7_Node_Ref head = p->AlignOffset + p->Size;- #endif- - CPpmd7_Node_Ref n = head;- unsigned i;-- p->GlueCount = 255;-- /* create doubly-linked list of free blocks */- for (i = 0; i < PPMD_NUM_INDEXES; i++)- {- UInt16 nu = I2U(i);- CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];- p->FreeList[i] = 0;- while (next != 0)- {- CPpmd7_Node *node = NODE(next);- node->Next = n;- n = NODE(n)->Prev = next;- next = *(const CPpmd7_Node_Ref *)node;- node->Stamp = 0;- node->NU = (UInt16)nu;- }- }- NODE(head)->Stamp = 1;- NODE(head)->Next = n;- NODE(n)->Prev = head;- if (p->LoUnit != p->HiUnit)- ((CPpmd7_Node *)p->LoUnit)->Stamp = 1;- - /* Glue free blocks */- while (n != head)- {- CPpmd7_Node *node = NODE(n);- UInt32 nu = (UInt32)node->NU;- for (;;)- {- CPpmd7_Node *node2 = NODE(n) + nu;- nu += node2->NU;- if (node2->Stamp != 0 || nu >= 0x10000)- break;- NODE(node2->Prev)->Next = node2->Next;- NODE(node2->Next)->Prev = node2->Prev;- node->NU = (UInt16)nu;- }- n = node->Next;- }- - /* Fill lists of free blocks */- for (n = NODE(head)->Next; n != head;)- {- CPpmd7_Node *node = NODE(n);- unsigned nu;- CPpmd7_Node_Ref next = node->Next;- for (nu = node->NU; nu > 128; nu -= 128, node += 128)- InsertNode(p, node, PPMD_NUM_INDEXES - 1);- if (I2U(i = U2I(nu)) != nu)- {- unsigned k = I2U(--i);- InsertNode(p, node + k, nu - k - 1);- }- InsertNode(p, node, i);- n = next;- }-}--static void *AllocUnitsRare(CPpmd7 *p, unsigned indx)-{- unsigned i;- void *retVal;- if (p->GlueCount == 0)- {- GlueFreeBlocks(p);- if (p->FreeList[indx] != 0)- return RemoveNode(p, indx);- }- i = indx;- do- {- if (++i == PPMD_NUM_INDEXES)- {- UInt32 numBytes = U2B(I2U(indx));- p->GlueCount--;- return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);- }- }- while (p->FreeList[i] == 0);- retVal = RemoveNode(p, i);- SplitBlock(p, retVal, i, indx);- return retVal;-}--static void *AllocUnits(CPpmd7 *p, unsigned indx)-{- UInt32 numBytes;- if (p->FreeList[indx] != 0)- return RemoveNode(p, indx);- numBytes = U2B(I2U(indx));- if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))- {- void *retVal = p->LoUnit;- p->LoUnit += numBytes;- return retVal;- }- return AllocUnitsRare(p, indx);-}--#define MyMem12Cpy(dest, src, num) \- { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \- do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); }--static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)-{- unsigned i0 = U2I(oldNU);- unsigned i1 = U2I(newNU);- if (i0 == i1)- return oldPtr;- if (p->FreeList[i1] != 0)- {- void *ptr = RemoveNode(p, i1);- MyMem12Cpy(ptr, oldPtr, newNU);- InsertNode(p, oldPtr, i0);- return ptr;- }- SplitBlock(p, oldPtr, i0, i1);- return oldPtr;-}--#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))--static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)-{- (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);- (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);-}--static void RestartModel(CPpmd7 *p)-{- unsigned i, k, m;-- memset(p->FreeList, 0, sizeof(p->FreeList));- p->Text = p->Base + p->AlignOffset;- p->HiUnit = p->Text + p->Size;- p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;- p->GlueCount = 0;-- p->OrderFall = p->MaxOrder;- p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;- p->PrevSuccess = 0;-- p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */- p->MinContext->Suffix = 0;- p->MinContext->NumStats = 256;- p->MinContext->SummFreq = 256 + 1;- p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */- p->LoUnit += U2B(256 / 2);- p->MinContext->Stats = REF(p->FoundState);- for (i = 0; i < 256; i++)- {- CPpmd_State *s = &p->FoundState[i];- s->Symbol = (Byte)i;- s->Freq = 1;- SetSuccessor(s, 0);- }-- for (i = 0; i < 128; i++)- for (k = 0; k < 8; k++)- {- UInt16 *dest = p->BinSumm[i] + k;- UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2));- for (m = 0; m < 64; m += 8)- dest[m] = val;- }- - for (i = 0; i < 25; i++)- for (k = 0; k < 16; k++)- {- CPpmd_See *s = &p->See[i][k];- s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4));- s->Count = 4;- }-}--static void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)-{- p->MaxOrder = maxOrder;- RestartModel(p);- p->DummySee.Shift = PPMD_PERIOD_BITS;- p->DummySee.Summ = 0; /* unused */- p->DummySee.Count = 64; /* unused */-}--static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)-{- CPpmd_State upState;- CTX_PTR c = p->MinContext;- CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);- CPpmd_State *ps[PPMD7_MAX_ORDER];- unsigned numPs = 0;- - if (!skip)- ps[numPs++] = p->FoundState;- - while (c->Suffix)- {- CPpmd_Void_Ref successor;- CPpmd_State *s;- c = SUFFIX(c);- if (c->NumStats != 1)- {- for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);- }- else- s = ONE_STATE(c);- successor = SUCCESSOR(s);- if (successor != upBranch)- {- c = CTX(successor);- if (numPs == 0)- return c;- break;- }- ps[numPs++] = s;- }- - upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch);- SetSuccessor(&upState, upBranch + 1);- - if (c->NumStats == 1)- upState.Freq = ONE_STATE(c)->Freq;- else- {- UInt32 cf, s0;- CPpmd_State *s;- for (s = STATS(c); s->Symbol != upState.Symbol; s++);- cf = s->Freq - 1;- s0 = c->SummFreq - c->NumStats - cf;- upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));- }-- while (numPs != 0)- {- /* Create Child */- CTX_PTR c1; /* = AllocContext(p); */- if (p->HiUnit != p->LoUnit)- c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);- else if (p->FreeList[0] != 0)- c1 = (CTX_PTR)RemoveNode(p, 0);- else- {- c1 = (CTX_PTR)AllocUnitsRare(p, 0);- if (!c1)- return NULL;- }- c1->NumStats = 1;- *ONE_STATE(c1) = upState;- c1->Suffix = REF(c);- SetSuccessor(ps[--numPs], REF(c1));- c = c1;- }- - return c;-}--static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)-{- CPpmd_State tmp = *t1;- *t1 = *t2;- *t2 = tmp;-}--static void UpdateModel(CPpmd7 *p)-{- CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);- CTX_PTR c;- unsigned s0, ns;- - if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)- {- c = SUFFIX(p->MinContext);- - if (c->NumStats == 1)- {- CPpmd_State *s = ONE_STATE(c);- if (s->Freq < 32)- s->Freq++;- }- else- {- CPpmd_State *s = STATS(c);- if (s->Symbol != p->FoundState->Symbol)- {- do { s++; } while (s->Symbol != p->FoundState->Symbol);- if (s[0].Freq >= s[-1].Freq)- {- SwapStates(&s[0], &s[-1]);- s--;- }- }- if (s->Freq < MAX_FREQ - 9)- {- s->Freq += 2;- c->SummFreq += 2;- }- }- }-- if (p->OrderFall == 0)- {- p->MinContext = p->MaxContext = CreateSuccessors(p, True);- if (p->MinContext == 0)- {- RestartModel(p);- return;- }- SetSuccessor(p->FoundState, REF(p->MinContext));- return;- }- - *p->Text++ = p->FoundState->Symbol;- successor = REF(p->Text);- if (p->Text >= p->UnitsStart)- {- RestartModel(p);- return;- }- - if (fSuccessor)- {- if (fSuccessor <= successor)- {- CTX_PTR cs = CreateSuccessors(p, False);- if (cs == NULL)- {- RestartModel(p);- return;- }- fSuccessor = REF(cs);- }- if (--p->OrderFall == 0)- {- successor = fSuccessor;- p->Text -= (p->MaxContext != p->MinContext);- }- }- else- {- SetSuccessor(p->FoundState, successor);- fSuccessor = REF(p->MinContext);- }- - s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1);- - for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c))- {- unsigned ns1;- UInt32 cf, sf;- if ((ns1 = c->NumStats) != 1)- {- if ((ns1 & 1) == 0)- {- /* Expand for one UNIT */- unsigned oldNU = ns1 >> 1;- unsigned i = U2I(oldNU);- if (i != U2I(oldNU + 1))- {- void *ptr = AllocUnits(p, i + 1);- void *oldPtr;- if (!ptr)- {- RestartModel(p);- return;- }- oldPtr = STATS(c);- MyMem12Cpy(ptr, oldPtr, oldNU);- InsertNode(p, oldPtr, i);- c->Stats = STATS_REF(ptr);- }- }- c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1)));- }- else- {- CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);- if (!s)- {- RestartModel(p);- return;- }- *s = *ONE_STATE(c);- c->Stats = REF(s);- if (s->Freq < MAX_FREQ / 4 - 1)- s->Freq <<= 1;- else- s->Freq = MAX_FREQ - 4;- c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3));- }- cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6);- sf = (UInt32)s0 + c->SummFreq;- if (cf < 6 * sf)- {- cf = 1 + (cf > sf) + (cf >= 4 * sf);- c->SummFreq += 3;- }- else- {- cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);- c->SummFreq = (UInt16)(c->SummFreq + cf);- }- {- CPpmd_State *s = STATS(c) + ns1;- SetSuccessor(s, successor);- s->Symbol = p->FoundState->Symbol;- s->Freq = (Byte)cf;- c->NumStats = (UInt16)(ns1 + 1);- }- }- p->MaxContext = p->MinContext = CTX(fSuccessor);-}- -static void Rescale(CPpmd7 *p)-{- unsigned i, adder, sumFreq, escFreq;- CPpmd_State *stats = STATS(p->MinContext);- CPpmd_State *s = p->FoundState;- {- CPpmd_State tmp = *s;- for (; s != stats; s--)- s[0] = s[-1];- *s = tmp;- }- escFreq = p->MinContext->SummFreq - s->Freq;- s->Freq += 4;- adder = (p->OrderFall != 0);- s->Freq = (Byte)((s->Freq + adder) >> 1);- sumFreq = s->Freq;- - i = p->MinContext->NumStats - 1;- do- {- escFreq -= (++s)->Freq;- s->Freq = (Byte)((s->Freq + adder) >> 1);- sumFreq += s->Freq;- if (s[0].Freq > s[-1].Freq)- {- CPpmd_State *s1 = s;- CPpmd_State tmp = *s1;- do- s1[0] = s1[-1];- while (--s1 != stats && tmp.Freq > s1[-1].Freq);- *s1 = tmp;- }- }- while (--i);- - if (s->Freq == 0)- {- unsigned numStats = p->MinContext->NumStats;- unsigned n0, n1;- do { i++; } while ((--s)->Freq == 0);- escFreq += i;- p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i);- if (p->MinContext->NumStats == 1)- {- CPpmd_State tmp = *stats;- do- {- tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1));- escFreq >>= 1;- }- while (escFreq > 1);- InsertNode(p, stats, U2I(((numStats + 1) >> 1)));- *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;- return;- }- n0 = (numStats + 1) >> 1;- n1 = (p->MinContext->NumStats + 1) >> 1;- if (n0 != n1)- p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));- }- p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));- p->FoundState = STATS(p->MinContext);-}--static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)-{- CPpmd_See *see;- unsigned nonMasked = p->MinContext->NumStats - numMasked;- if (p->MinContext->NumStats != 256)- {- see = p->See[p->NS2Indx[nonMasked - 1]] +- (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +- 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +- 4 * (numMasked > nonMasked) +- p->HiBitsFlag;- {- unsigned r = (see->Summ >> see->Shift);- see->Summ = (UInt16)(see->Summ - r);- *escFreq = r + (r == 0);- }- }- else- {- see = &p->DummySee;- *escFreq = 1;- }- return see;-}--static void NextContext(CPpmd7 *p)-{- CTX_PTR c = CTX(SUCCESSOR(p->FoundState));- if (p->OrderFall == 0 && (Byte *)c > p->Text)- p->MinContext = p->MaxContext = c;- else- UpdateModel(p);-}--static void Ppmd7_Update1(CPpmd7 *p)-{- CPpmd_State *s = p->FoundState;- s->Freq += 4;- p->MinContext->SummFreq += 4;- if (s[0].Freq > s[-1].Freq)- {- SwapStates(&s[0], &s[-1]);- p->FoundState = --s;- if (s->Freq > MAX_FREQ)- Rescale(p);- }- NextContext(p);-}--static void Ppmd7_Update1_0(CPpmd7 *p)-{- p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);- p->RunLength += p->PrevSuccess;- p->MinContext->SummFreq += 4;- if ((p->FoundState->Freq += 4) > MAX_FREQ)- Rescale(p);- NextContext(p);-}--static void Ppmd7_UpdateBin(CPpmd7 *p)-{- p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));- p->PrevSuccess = 1;- p->RunLength++;- NextContext(p);-}--static void Ppmd7_Update2(CPpmd7 *p)-{- p->MinContext->SummFreq += 4;- if ((p->FoundState->Freq += 4) > MAX_FREQ)- Rescale(p);- p->RunLength = p->InitRL;- UpdateModel(p);-}--/* ---------- Decode ---------- */--static Bool Ppmd_RangeDec_Init(CPpmd7z_RangeDec *p)-{- unsigned i;- p->Low = p->Bottom = 0;- p->Range = 0xFFFFFFFF;- for (i = 0; i < 4; i++)- p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);- return (p->Code < 0xFFFFFFFF);-}--static Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)-{- if (p->Stream->Read((void *)p->Stream) != 0)- return False;- return Ppmd_RangeDec_Init(p);-}--static Bool PpmdRAR_RangeDec_Init(CPpmd7z_RangeDec *p)-{- if (!Ppmd_RangeDec_Init(p))- return False;- p->Bottom = 0x8000;- return True;-}--static UInt32 Range_GetThreshold(void *pp, UInt32 total)-{- CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;- return (p->Code - p->Low) / (p->Range /= total);-}--static void Range_Normalize(CPpmd7z_RangeDec *p)-{- while (1)- {- if((p->Low ^ (p->Low + p->Range)) >= kTopValue)- {- if(p->Range >= p->Bottom)- break;- else- p->Range = ((uint32_t)(-(int32_t)p->Low)) & (p->Bottom - 1);- }- p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);- p->Range <<= 8;- p->Low <<= 8;- }-}--static void Range_Decode_7z(void *pp, UInt32 start, UInt32 size)-{- CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;- p->Code -= start * p->Range;- p->Range *= size;- Range_Normalize(p);-}--static void Range_Decode_RAR(void *pp, UInt32 start, UInt32 size)-{- CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;- p->Low += start * p->Range;- p->Range *= size;- Range_Normalize(p);-}--static UInt32 Range_DecodeBit_7z(void *pp, UInt32 size0)-{- CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;- UInt32 newBound = (p->Range >> 14) * size0;- UInt32 symbol;- if (p->Code < newBound)- {- symbol = 0;- p->Range = newBound;- }- else- {- symbol = 1;- p->Code -= newBound;- p->Range -= newBound;- }- Range_Normalize(p);- return symbol;-}--static UInt32 Range_DecodeBit_RAR(void *pp, UInt32 size0)-{- CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;- UInt32 bit, value = p->p.GetThreshold(p, PPMD_BIN_SCALE);- if(value < size0)- {- bit = 0;- p->p.Decode(p, 0, size0);- }- else- {- bit = 1;- p->p.Decode(p, size0, PPMD_BIN_SCALE - size0);- }- return bit;-}--static void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)-{- p->p.GetThreshold = Range_GetThreshold;- p->p.Decode = Range_Decode_7z;- p->p.DecodeBit = Range_DecodeBit_7z;-}--static void PpmdRAR_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)-{- p->p.GetThreshold = Range_GetThreshold;- p->p.Decode = Range_Decode_RAR;- p->p.DecodeBit = Range_DecodeBit_RAR;-}--#define MASK(sym) ((signed char *)charMask)[sym]--static int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc)-{- size_t charMask[256 / sizeof(size_t)];- if (p->MinContext->NumStats != 1)- {- CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);- unsigned i;- UInt32 count, hiCnt;- if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq))- {- Byte symbol;- rc->Decode(rc, 0, s->Freq);- p->FoundState = s;- symbol = s->Symbol;- Ppmd7_Update1_0(p);- return symbol;- }- p->PrevSuccess = 0;- i = p->MinContext->NumStats - 1;- do- {- if ((hiCnt += (++s)->Freq) > count)- {- Byte symbol;- rc->Decode(rc, hiCnt - s->Freq, s->Freq);- p->FoundState = s;- symbol = s->Symbol;- Ppmd7_Update1(p);- return symbol;- }- }- while (--i);- if (count >= p->MinContext->SummFreq)- return -2;- p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];- rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt);- PPMD_SetAllBitsIn256Bytes(charMask);- MASK(s->Symbol) = 0;- i = p->MinContext->NumStats - 1;- do { MASK((--s)->Symbol) = 0; } while (--i);- }- else- {- UInt16 *prob = Ppmd7_GetBinSumm(p);- if (rc->DecodeBit(rc, *prob) == 0)- {- Byte symbol;- *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);- symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;- Ppmd7_UpdateBin(p);- return symbol;- }- *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);- p->InitEsc = PPMD7_kExpEscape[*prob >> 10];- PPMD_SetAllBitsIn256Bytes(charMask);- MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;- p->PrevSuccess = 0;- }- for (;;)- {- CPpmd_State *ps[256], *s;- UInt32 freqSum, count, hiCnt;- CPpmd_See *see;- unsigned i, num, numMasked = p->MinContext->NumStats;- do- {- p->OrderFall++;- if (!p->MinContext->Suffix)- return -1;- p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);- }- while (p->MinContext->NumStats == numMasked);- hiCnt = 0;- s = Ppmd7_GetStats(p, p->MinContext);- i = 0;- num = p->MinContext->NumStats - numMasked;- do- {- int k = (int)(MASK(s->Symbol));- hiCnt += (s->Freq & k);- ps[i] = s++;- i -= k;- }- while (i != num);-- see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);- freqSum += hiCnt;- count = rc->GetThreshold(rc, freqSum);-- if (count < hiCnt)- {- Byte symbol;- CPpmd_State **pps = ps;- for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);- s = *pps;- rc->Decode(rc, hiCnt - s->Freq, s->Freq);- Ppmd_See_Update(see);- p->FoundState = s;- symbol = s->Symbol;- Ppmd7_Update2(p);- return symbol;- }- if (count >= freqSum)- return -2;- rc->Decode(rc, hiCnt, freqSum - hiCnt);- see->Summ = (UInt16)(see->Summ + freqSum);- do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);- }-}--/* ---------- Encode ---------- Ppmd7Enc.c */--#define kTopValue (1 << 24)--static void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p)-{- p->Low = 0;- p->Range = 0xFFFFFFFF;- p->Cache = 0;- p->CacheSize = 1;-}--static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)-{- if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0)- {- Byte temp = p->Cache;- do- {- p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32)));- temp = 0xFF;- }- while(--p->CacheSize != 0);- p->Cache = (Byte)((UInt32)p->Low >> 24);- }- p->CacheSize++;- p->Low = ((UInt32)p->Low << 8) & 0xFFFFFFFF;-}--static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total)-{- p->Low += (UInt64)start * (UInt64)(p->Range /= total);- p->Range *= size;- while (p->Range < kTopValue)- {- p->Range <<= 8;- RangeEnc_ShiftLow(p);- }-}--static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0)-{- p->Range = (p->Range >> 14) * size0;- while (p->Range < kTopValue)- {- p->Range <<= 8;- RangeEnc_ShiftLow(p);- }-}--static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0)-{- UInt32 newBound = (p->Range >> 14) * size0;- p->Low += newBound;- p->Range -= newBound;- while (p->Range < kTopValue)- {- p->Range <<= 8;- RangeEnc_ShiftLow(p);- }-}--static void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p)-{- unsigned i;- for (i = 0; i < 5; i++)- RangeEnc_ShiftLow(p);-}---#define MASK(sym) ((signed char *)charMask)[sym]--static void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol)-{- size_t charMask[256 / sizeof(size_t)];- if (p->MinContext->NumStats != 1)- {- CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);- UInt32 sum;- unsigned i;- if (s->Symbol == symbol)- {- RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq);- p->FoundState = s;- Ppmd7_Update1_0(p);- return;- }- p->PrevSuccess = 0;- sum = s->Freq;- i = p->MinContext->NumStats - 1;- do- {- if ((++s)->Symbol == symbol)- {- RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq);- p->FoundState = s;- Ppmd7_Update1(p);- return;- }- sum += s->Freq;- }- while (--i);- - p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];- PPMD_SetAllBitsIn256Bytes(charMask);- MASK(s->Symbol) = 0;- i = p->MinContext->NumStats - 1;- do { MASK((--s)->Symbol) = 0; } while (--i);- RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);- }- else- {- UInt16 *prob = Ppmd7_GetBinSumm(p);- CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);- if (s->Symbol == symbol)- {- RangeEnc_EncodeBit_0(rc, *prob);- *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);- p->FoundState = s;- Ppmd7_UpdateBin(p);- return;- }- else- {- RangeEnc_EncodeBit_1(rc, *prob);- *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);- p->InitEsc = PPMD7_kExpEscape[*prob >> 10];- PPMD_SetAllBitsIn256Bytes(charMask);- MASK(s->Symbol) = 0;- p->PrevSuccess = 0;- }- }- for (;;)- {- UInt32 escFreq;- CPpmd_See *see;- CPpmd_State *s;- UInt32 sum;- unsigned i, numMasked = p->MinContext->NumStats;- do- {- p->OrderFall++;- if (!p->MinContext->Suffix)- return; /* EndMarker (symbol = -1) */- p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);- }- while (p->MinContext->NumStats == numMasked);- - see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);- s = Ppmd7_GetStats(p, p->MinContext);- sum = 0;- i = p->MinContext->NumStats;- do- {- int cur = s->Symbol;- if (cur == symbol)- {- UInt32 low = sum;- CPpmd_State *s1 = s;- do- {- sum += (s->Freq & (int)(MASK(s->Symbol)));- s++;- }- while (--i);- RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq);- Ppmd_See_Update(see);- p->FoundState = s1;- Ppmd7_Update2(p);- return;- }- sum += (s->Freq & (int)(MASK(cur)));- MASK(cur) = 0;- s++;- }- while (--i);- - RangeEnc_Encode(rc, sum, escFreq, sum + escFreq);- see->Summ = (UInt16)(see->Summ + sum + escFreq);- }-}--const IPpmd7 __archive_ppmd7_functions =-{- &Ppmd7_Construct,- &Ppmd7_Alloc,- &Ppmd7_Free,- &Ppmd7_Init,- &Ppmd7z_RangeDec_CreateVTable,- &PpmdRAR_RangeDec_CreateVTable,- &Ppmd7z_RangeDec_Init,- &PpmdRAR_RangeDec_Init,- &Ppmd7_DecodeSymbol,- &Ppmd7z_RangeEnc_Init,- &Ppmd7z_RangeEnc_FlushData,- &Ppmd7_EncodeSymbol-};
− c/archive_ppmd7_private.h
@@ -1,119 +0,0 @@-/* Ppmd7.h -- PPMdH compression codec-2010-03-12 : Igor Pavlov : Public domain-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */--/* This code supports virtual RangeDecoder and includes the implementation-of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H.-If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */--#ifndef ARCHIVE_PPMD7_PRIVATE_H_INCLUDED-#define ARCHIVE_PPMD7_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--#include "archive_ppmd_private.h"--#define PPMD7_MIN_ORDER 2-#define PPMD7_MAX_ORDER 64--#define PPMD7_MIN_MEM_SIZE (1 << 11)-#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFFu - 12 * 3)--struct CPpmd7_Context_;--typedef- #ifdef PPMD_32BIT- struct CPpmd7_Context_ *- #else- UInt32- #endif- CPpmd7_Context_Ref;--typedef struct CPpmd7_Context_-{- UInt16 NumStats;- UInt16 SummFreq;- CPpmd_State_Ref Stats;- CPpmd7_Context_Ref Suffix;-} CPpmd7_Context;--#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)--typedef struct-{- CPpmd7_Context *MinContext, *MaxContext;- CPpmd_State *FoundState;- unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;- Int32 RunLength, InitRL; /* must be 32-bit at least */-- UInt32 Size;- UInt32 GlueCount;- Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;- UInt32 AlignOffset;-- Byte Indx2Units[PPMD_NUM_INDEXES];- Byte Units2Indx[128];- CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];- Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256];- CPpmd_See DummySee, See[25][16];- UInt16 BinSumm[128][64];-} CPpmd7;--/* ---------- Decode ---------- */--typedef struct-{- UInt32 (*GetThreshold)(void *p, UInt32 total);- void (*Decode)(void *p, UInt32 start, UInt32 size);- UInt32 (*DecodeBit)(void *p, UInt32 size0);-} IPpmd7_RangeDec;--typedef struct-{- IPpmd7_RangeDec p;- UInt32 Range;- UInt32 Code;- UInt32 Low;- UInt32 Bottom;- IByteIn *Stream;-} CPpmd7z_RangeDec;--/* ---------- Encode ---------- */--typedef struct-{- UInt64 Low;- UInt32 Range;- Byte Cache;- UInt64 CacheSize;- IByteOut *Stream;-} CPpmd7z_RangeEnc;--typedef struct-{- /* Base Functions */- void (*Ppmd7_Construct)(CPpmd7 *p);- Bool (*Ppmd7_Alloc)(CPpmd7 *p, UInt32 size);- void (*Ppmd7_Free)(CPpmd7 *p);- void (*Ppmd7_Init)(CPpmd7 *p, unsigned maxOrder);- #define Ppmd7_WasAllocated(p) ((p)->Base != NULL)-- /* Decode Functions */- void (*Ppmd7z_RangeDec_CreateVTable)(CPpmd7z_RangeDec *p);- void (*PpmdRAR_RangeDec_CreateVTable)(CPpmd7z_RangeDec *p);- Bool (*Ppmd7z_RangeDec_Init)(CPpmd7z_RangeDec *p);- Bool (*PpmdRAR_RangeDec_Init)(CPpmd7z_RangeDec *p);- #define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)- int (*Ppmd7_DecodeSymbol)(CPpmd7 *p, IPpmd7_RangeDec *rc);-- /* Encode Functions */- void (*Ppmd7z_RangeEnc_Init)(CPpmd7z_RangeEnc *p);- void (*Ppmd7z_RangeEnc_FlushData)(CPpmd7z_RangeEnc *p);-- void (*Ppmd7_EncodeSymbol)(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol);-} IPpmd7;--extern const IPpmd7 __archive_ppmd7_functions;-#endif
− c/archive_ppmd8.c
@@ -1,1287 +0,0 @@-/* Ppmd8.c -- PPMdI codec-2016-05-21 : Igor Pavlov : Public domain-This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */--#include "archive_platform.h"--#include <string.h>--#include "archive_ppmd8_private.h"--const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };-static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};--#define MAX_FREQ 124-#define UNIT_SIZE 12--#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)-#define U2I(nu) (p->Units2Indx[(nu) - 1])-#define I2U(indx) (p->Indx2Units[indx])--#ifdef PPMD_32BIT- #define REF(ptr) (ptr)-#else- #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))-#endif--#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))--#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref))-#define STATS(ctx) Ppmd8_GetStats(p, ctx)-#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx)-#define SUFFIX(ctx) CTX((ctx)->Suffix)--#define kTop (1 << 24)-#define kBot (1 << 15)--typedef CPpmd8_Context * CTX_PTR;--struct CPpmd8_Node_;--typedef- #ifdef PPMD_32BIT- struct CPpmd8_Node_ *- #else- UInt32- #endif- CPpmd8_Node_Ref;--typedef struct CPpmd8_Node_-{- UInt32 Stamp;- CPpmd8_Node_Ref Next;- UInt32 NU;-} CPpmd8_Node;--#ifdef PPMD_32BIT- #define NODE(ptr) (ptr)-#else- #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs)))-#endif--#define EMPTY_NODE 0xFFFFFFFF--void Ppmd8_Construct(CPpmd8 *p)-{- unsigned i, k, m;-- p->Base = 0;-- for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)- {- unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);- do { p->Units2Indx[k++] = (Byte)i; } while (--step);- p->Indx2Units[i] = (Byte)k;- }-- p->NS2BSIndx[0] = (0 << 1);- p->NS2BSIndx[1] = (1 << 1);- memset(p->NS2BSIndx + 2, (2 << 1), 9);- memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);-- for (i = 0; i < 5; i++)- p->NS2Indx[i] = (Byte)i;- for (m = i, k = 1; i < 260; i++)- {- p->NS2Indx[i] = (Byte)m;- if (--k == 0)- k = (++m) - 4;- }-}--void Ppmd8_Free(CPpmd8 *p)-{- free(p->Base);- p->Size = 0;- p->Base = 0;-}--Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size)-{- if (p->Base == 0 || p->Size != size)- {- Ppmd8_Free(p);- p->AlignOffset =- #ifdef PPMD_32BIT- (4 - size) & 3;- #else- 4 - (size & 3);- #endif- if ((p->Base = (Byte *)malloc(p->AlignOffset + size)) == 0)- return False;- p->Size = size;- }- return True;-}--static void InsertNode(CPpmd8 *p, void *node, unsigned indx)-{- ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE;- ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx];- ((CPpmd8_Node *)node)->NU = I2U(indx);- p->FreeList[indx] = REF(node);- p->Stamps[indx]++;-}--static void *RemoveNode(CPpmd8 *p, unsigned indx)-{- CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]);- p->FreeList[indx] = node->Next;- p->Stamps[indx]--;- return node;-}--static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx)-{- unsigned i, nu = I2U(oldIndx) - I2U(newIndx);- ptr = (Byte *)ptr + U2B(I2U(newIndx));- if (I2U(i = U2I(nu)) != nu)- {- unsigned k = I2U(--i);- InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);- }- InsertNode(p, ptr, i);-}--static void GlueFreeBlocks(CPpmd8 *p)-{- CPpmd8_Node_Ref head = 0;- CPpmd8_Node_Ref *prev = &head;- unsigned i;-- p->GlueCount = 1 << 13;- memset(p->Stamps, 0, sizeof(p->Stamps));- - /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end.- All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */- if (p->LoUnit != p->HiUnit)- ((CPpmd8_Node *)p->LoUnit)->Stamp = 0;-- /* Glue free blocks */- for (i = 0; i < PPMD_NUM_INDEXES; i++)- {- CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i];- p->FreeList[i] = 0;- while (next != 0)- {- CPpmd8_Node *node = NODE(next);- if (node->NU != 0)- {- CPpmd8_Node *node2;- *prev = next;- prev = &(node->Next);- while ((node2 = node + node->NU)->Stamp == EMPTY_NODE)- {- node->NU += node2->NU;- node2->NU = 0;- }- }- next = node->Next;- }- }- *prev = 0;- - /* Fill lists of free blocks */- while (head != 0)- {- CPpmd8_Node *node = NODE(head);- unsigned nu;- head = node->Next;- nu = node->NU;- if (nu == 0)- continue;- for (; nu > 128; nu -= 128, node += 128)- InsertNode(p, node, PPMD_NUM_INDEXES - 1);- if (I2U(i = U2I(nu)) != nu)- {- unsigned k = I2U(--i);- InsertNode(p, node + k, nu - k - 1);- }- InsertNode(p, node, i);- }-}--static void *AllocUnitsRare(CPpmd8 *p, unsigned indx)-{- unsigned i;- void *retVal;- if (p->GlueCount == 0)- {- GlueFreeBlocks(p);- if (p->FreeList[indx] != 0)- return RemoveNode(p, indx);- }- i = indx;- do- {- if (++i == PPMD_NUM_INDEXES)- {- UInt32 numBytes = U2B(I2U(indx));- p->GlueCount--;- return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);- }- }- while (p->FreeList[i] == 0);- retVal = RemoveNode(p, i);- SplitBlock(p, retVal, i, indx);- return retVal;-}--static void *AllocUnits(CPpmd8 *p, unsigned indx)-{- UInt32 numBytes;- if (p->FreeList[indx] != 0)- return RemoveNode(p, indx);- numBytes = U2B(I2U(indx));- if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))- {- void *retVal = p->LoUnit;- p->LoUnit += numBytes;- return retVal;- }- return AllocUnitsRare(p, indx);-}--#define MyMem12Cpy(dest, src, num) \- { UInt32 *d = (UInt32 *)dest; const UInt32 *z = (const UInt32 *)src; UInt32 n = num; \- do { d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; } while (--n); }--static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU)-{- unsigned i0 = U2I(oldNU);- unsigned i1 = U2I(newNU);- if (i0 == i1)- return oldPtr;- if (p->FreeList[i1] != 0)- {- void *ptr = RemoveNode(p, i1);- MyMem12Cpy(ptr, oldPtr, newNU);- InsertNode(p, oldPtr, i0);- return ptr;- }- SplitBlock(p, oldPtr, i0, i1);- return oldPtr;-}--static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu)-{- InsertNode(p, ptr, U2I(nu));-}--static void SpecialFreeUnit(CPpmd8 *p, void *ptr)-{- if ((Byte *)ptr != p->UnitsStart)- InsertNode(p, ptr, 0);- else- {- #ifdef PPMD8_FREEZE_SUPPORT- *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */- #endif- p->UnitsStart += UNIT_SIZE;- }-}--static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu)-{- unsigned indx = U2I(nu);- void *ptr;- if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx])- return oldPtr;- ptr = RemoveNode(p, indx);- MyMem12Cpy(ptr, oldPtr, nu);- if ((Byte*)oldPtr != p->UnitsStart)- InsertNode(p, oldPtr, indx);- else- p->UnitsStart += U2B(I2U(indx));- return ptr;-}--static void ExpandTextArea(CPpmd8 *p)-{- UInt32 count[PPMD_NUM_INDEXES];- unsigned i;- memset(count, 0, sizeof(count));- if (p->LoUnit != p->HiUnit)- ((CPpmd8_Node *)p->LoUnit)->Stamp = 0;- - {- CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart;- for (; node->Stamp == EMPTY_NODE; node += node->NU)- {- node->Stamp = 0;- count[U2I(node->NU)]++;- }- p->UnitsStart = (Byte *)node;- }- - for (i = 0; i < PPMD_NUM_INDEXES; i++)- {- CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i];- while (count[i] != 0)- {- CPpmd8_Node *node = NODE(*next);- while (node->Stamp == 0)- {- *next = node->Next;- node = NODE(*next);- p->Stamps[i]--;- if (--count[i] == 0)- break;- }- next = &node->Next;- }- }-}--#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))--static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)-{- (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);- (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);-}--#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); }--static void RestartModel(CPpmd8 *p)-{- unsigned i, k, m, r;-- memset(p->FreeList, 0, sizeof(p->FreeList));- memset(p->Stamps, 0, sizeof(p->Stamps));- RESET_TEXT(0);- p->HiUnit = p->Text + p->Size;- p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;- p->GlueCount = 0;-- p->OrderFall = p->MaxOrder;- p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;- p->PrevSuccess = 0;-- p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */- p->MinContext->Suffix = 0;- p->MinContext->NumStats = 255;- p->MinContext->Flags = 0;- p->MinContext->SummFreq = 256 + 1;- p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */- p->LoUnit += U2B(256 / 2);- p->MinContext->Stats = REF(p->FoundState);- for (i = 0; i < 256; i++)- {- CPpmd_State *s = &p->FoundState[i];- s->Symbol = (Byte)i;- s->Freq = 1;- SetSuccessor(s, 0);- }-- for (i = m = 0; m < 25; m++)- {- while (p->NS2Indx[i] == m)- i++;- for (k = 0; k < 8; k++)- {- UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1));- UInt16 *dest = p->BinSumm[m] + k;- for (r = 0; r < 64; r += 8)- dest[r] = val;- }- }-- for (i = m = 0; m < 24; m++)- {- while (p->NS2Indx[i + 3] == m + 3)- i++;- for (k = 0; k < 32; k++)- {- CPpmd_See *s = &p->See[m][k];- s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4));- s->Count = 7;- }- }-}--void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod)-{- p->MaxOrder = maxOrder;- p->RestoreMethod = restoreMethod;- RestartModel(p);- p->DummySee.Shift = PPMD_PERIOD_BITS;- p->DummySee.Summ = 0; /* unused */- p->DummySee.Count = 64; /* unused */-}--static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale)-{- unsigned i = ctx->NumStats, escFreq, sumFreq, flags;- CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1);- ctx->Stats = REF(s);- #ifdef PPMD8_FREEZE_SUPPORT- /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */- scale |= (ctx->SummFreq >= ((UInt32)1 << 15));- #endif- flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40);- escFreq = ctx->SummFreq - s->Freq;- sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale));- do- {- escFreq -= (++s)->Freq;- sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale));- flags |= 0x08 * (s->Symbol >= 0x40);- }- while (--i);- ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale));- ctx->Flags = (Byte)flags;-}--static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)-{- CPpmd_State tmp = *t1;- *t1 = *t2;- *t2 = tmp;-}--static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order)-{- int i;- unsigned tmp;- CPpmd_State *s;- - if (!ctx->NumStats)- {- s = ONE_STATE(ctx);- if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart)- {- if (order < p->MaxOrder)- SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1));- else- SetSuccessor(s, 0);- if (SUCCESSOR(s) || order <= 9) /* O_BOUND */- return REF(ctx);- }- SpecialFreeUnit(p, ctx);- return 0;- }-- ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1));-- for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--)- if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart)- {- CPpmd_State *s2 = STATS(ctx) + (i--);- SetSuccessor(s, 0);- SwapStates(s, s2);- }- else if (order < p->MaxOrder)- SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1));- else- SetSuccessor(s, 0);- - if (i != ctx->NumStats && order)- {- ctx->NumStats = (Byte)i;- s = STATS(ctx);- if (i < 0)- {- FreeUnits(p, s, tmp);- SpecialFreeUnit(p, ctx);- return 0;- }- if (i == 0)- {- ctx->Flags = (Byte)((ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40));- *ONE_STATE(ctx) = *s;- FreeUnits(p, s, tmp);- /* 9.31: the code was fixed. It's was not BUG, if Freq <= MAX_FREQ = 124 */- ONE_STATE(ctx)->Freq = (Byte)(((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3);- }- else- Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i);- }- return REF(ctx);-}--#ifdef PPMD8_FREEZE_SUPPORT-static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order)-{- CPpmd_State *s;- if (!ctx->NumStats)- {- s = ONE_STATE(ctx);- if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder)- SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1));- else- SetSuccessor(s, 0);- /* Suffix context can be removed already, since different (high-order)- Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */- if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF))- {- FreeUnits(p, ctx, 1);- return 0;- }- else- return REF(ctx);- }-- for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--)- if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder)- SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1));- else- SetSuccessor(s, 0);- - return REF(ctx);-}-#endif--static UInt32 GetUsedMemory(const CPpmd8 *p)-{- UInt32 v = 0;- unsigned i;- for (i = 0; i < PPMD_NUM_INDEXES; i++)- v += p->Stamps[i] * I2U(i);- return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v);-}--#ifdef PPMD8_FREEZE_SUPPORT- #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor)-#else- #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1)-#endif--static void RestoreModel(CPpmd8 *p, CTX_PTR c1- #ifdef PPMD8_FREEZE_SUPPORT- , CTX_PTR fSuccessor- #endif- )-{- CTX_PTR c;- CPpmd_State *s;- RESET_TEXT(0);- for (c = p->MaxContext; c != c1; c = SUFFIX(c))- if (--(c->NumStats) == 0)- {- s = STATS(c);- c->Flags = (Byte)((c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40));- *ONE_STATE(c) = *s;- SpecialFreeUnit(p, s);- ONE_STATE(c)->Freq = (Byte)(((unsigned)ONE_STATE(c)->Freq + 11) >> 3);- }- else- Refresh(p, c, (c->NumStats+3) >> 1, 0);- - for (; c != p->MinContext; c = SUFFIX(c))- if (!c->NumStats)- ONE_STATE(c)->Freq = (Byte)(ONE_STATE(c)->Freq - (ONE_STATE(c)->Freq >> 1));- else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats)- Refresh(p, c, (c->NumStats + 2) >> 1, 1);-- #ifdef PPMD8_FREEZE_SUPPORT- if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)- {- p->MaxContext = fSuccessor;- p->GlueCount += !(p->Stamps[1] & 1);- }- else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE)- {- while (p->MaxContext->Suffix)- p->MaxContext = SUFFIX(p->MaxContext);- RemoveBinContexts(p, p->MaxContext, 0);- p->RestoreMethod++;- p->GlueCount = 0;- p->OrderFall = p->MaxOrder;- }- else- #endif- if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1))- RestartModel(p);- else- {- while (p->MaxContext->Suffix)- p->MaxContext = SUFFIX(p->MaxContext);- do- {- CutOff(p, p->MaxContext, 0);- ExpandTextArea(p);- }- while (GetUsedMemory(p) > 3 * (p->Size >> 2));- p->GlueCount = 0;- p->OrderFall = p->MaxOrder;- }-}--static CTX_PTR CreateSuccessors(CPpmd8 *p, Bool skip, CPpmd_State *s1, CTX_PTR c)-{- CPpmd_State upState;- Byte flags;- CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);- /* fixed over Shkarin's code. Maybe it could work without + 1 too. */- CPpmd_State *ps[PPMD8_MAX_ORDER + 1];- unsigned numPs = 0;- - if (!skip)- ps[numPs++] = p->FoundState;- - while (c->Suffix)- {- CPpmd_Void_Ref successor;- CPpmd_State *s;- c = SUFFIX(c);- if (s1)- {- s = s1;- s1 = NULL;- }- else if (c->NumStats != 0)- {- for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);- if (s->Freq < MAX_FREQ - 9)- {- s->Freq++;- c->SummFreq++;- }- }- else- {- s = ONE_STATE(c);- s->Freq = (Byte)(s->Freq + (!SUFFIX(c)->NumStats & (s->Freq < 24)));- }- successor = SUCCESSOR(s);- if (successor != upBranch)- {- c = CTX(successor);- if (numPs == 0)- return c;- break;- }- ps[numPs++] = s;- }- - upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch);- SetSuccessor(&upState, upBranch + 1);- flags = (Byte)(0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40));-- if (c->NumStats == 0)- upState.Freq = ONE_STATE(c)->Freq;- else- {- UInt32 cf, s0;- CPpmd_State *s;- for (s = STATS(c); s->Symbol != upState.Symbol; s++);- cf = s->Freq - 1;- s0 = c->SummFreq - c->NumStats - cf;- upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0)));- }-- do- {- /* Create Child */- CTX_PTR c1; /* = AllocContext(p); */- if (p->HiUnit != p->LoUnit)- c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);- else if (p->FreeList[0] != 0)- c1 = (CTX_PTR)RemoveNode(p, 0);- else- {- c1 = (CTX_PTR)AllocUnitsRare(p, 0);- if (!c1)- return NULL;- }- c1->NumStats = 0;- c1->Flags = flags;- *ONE_STATE(c1) = upState;- c1->Suffix = REF(c);- SetSuccessor(ps[--numPs], REF(c1));- c = c1;- }- while (numPs != 0);- - return c;-}--static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c)-{- CPpmd_State *s = NULL;- CTX_PTR c1 = c;- CPpmd_Void_Ref upBranch = REF(p->Text);- - #ifdef PPMD8_FREEZE_SUPPORT- /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */- CPpmd_State *ps[PPMD8_MAX_ORDER + 1];- unsigned numPs = 0;- ps[numPs++] = p->FoundState;- #endif-- SetSuccessor(p->FoundState, upBranch);- p->OrderFall++;-- for (;;)- {- if (s1)- {- c = SUFFIX(c);- s = s1;- s1 = NULL;- }- else- {- if (!c->Suffix)- {- #ifdef PPMD8_FREEZE_SUPPORT- if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)- {- do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs);- RESET_TEXT(1);- p->OrderFall = 1;- }- #endif- return c;- }- c = SUFFIX(c);- if (c->NumStats)- {- if ((s = STATS(c))->Symbol != p->FoundState->Symbol)- do { s++; } while (s->Symbol != p->FoundState->Symbol);- if (s->Freq < MAX_FREQ - 9)- {- s->Freq += 2;- c->SummFreq += 2;- }- }- else- {- s = ONE_STATE(c);- s->Freq = (Byte)(s->Freq + (s->Freq < 32));- }- }- if (SUCCESSOR(s))- break;- #ifdef PPMD8_FREEZE_SUPPORT- ps[numPs++] = s;- #endif- SetSuccessor(s, upBranch);- p->OrderFall++;- }- - #ifdef PPMD8_FREEZE_SUPPORT- if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)- {- c = CTX(SUCCESSOR(s));- do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs);- RESET_TEXT(1);- p->OrderFall = 1;- return c;- }- else- #endif- if (SUCCESSOR(s) <= upBranch)- {- CTX_PTR successor;- CPpmd_State *s2 = p->FoundState;- p->FoundState = s;-- successor = CreateSuccessors(p, False, NULL, c);- if (successor == NULL)- SetSuccessor(s, 0);- else- SetSuccessor(s, REF(successor));- p->FoundState = s2;- }- - if (p->OrderFall == 1 && c1 == p->MaxContext)- {- SetSuccessor(p->FoundState, SUCCESSOR(s));- p->Text--;- }- if (SUCCESSOR(s) == 0)- return NULL;- return CTX(SUCCESSOR(s));-}--static void UpdateModel(CPpmd8 *p)-{- CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);- CTX_PTR c;- unsigned s0, ns, fFreq = p->FoundState->Freq;- Byte flag, fSymbol = p->FoundState->Symbol;- CPpmd_State *s = NULL;- - if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)- {- c = SUFFIX(p->MinContext);- - if (c->NumStats == 0)- {- s = ONE_STATE(c);- if (s->Freq < 32)- s->Freq++;- }- else- {- s = STATS(c);- if (s->Symbol != p->FoundState->Symbol)- {- do { s++; } while (s->Symbol != p->FoundState->Symbol);- if (s[0].Freq >= s[-1].Freq)- {- SwapStates(&s[0], &s[-1]);- s--;- }- }- if (s->Freq < MAX_FREQ - 9)- {- s->Freq += 2;- c->SummFreq += 2;- }- }- }- - c = p->MaxContext;- if (p->OrderFall == 0 && fSuccessor)- {- CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext);- if (cs == 0)- {- SetSuccessor(p->FoundState, 0);- RESTORE_MODEL(c, CTX(fSuccessor));- }- else- {- SetSuccessor(p->FoundState, REF(cs));- p->MaxContext = cs;- }- return;- }- - *p->Text++ = p->FoundState->Symbol;- successor = REF(p->Text);- if (p->Text >= p->UnitsStart)- {- RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */- return;- }- - if (!fSuccessor)- {- CTX_PTR cs = ReduceOrder(p, s, p->MinContext);- if (cs == NULL)- {- RESTORE_MODEL(c, 0);- return;- }- fSuccessor = REF(cs);- }- else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart)- {- CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext);- if (cs == NULL)- {- RESTORE_MODEL(c, 0);- return;- }- fSuccessor = REF(cs);- }- - if (--p->OrderFall == 0)- {- successor = fSuccessor;- p->Text -= (p->MaxContext != p->MinContext);- }- #ifdef PPMD8_FREEZE_SUPPORT- else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)- {- successor = fSuccessor;- RESET_TEXT(0);- p->OrderFall = 0;- }- #endif- - s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq;- flag = (Byte)(0x08 * (fSymbol >= 0x40));- - for (; c != p->MinContext; c = SUFFIX(c))- {- unsigned ns1;- UInt32 cf, sf;- if ((ns1 = c->NumStats) != 0)- {- if ((ns1 & 1) != 0)- {- /* Expand for one UNIT */- unsigned oldNU = (ns1 + 1) >> 1;- unsigned i = U2I(oldNU);- if (i != U2I(oldNU + 1))- {- void *ptr = AllocUnits(p, i + 1);- void *oldPtr;- if (!ptr)- {- RESTORE_MODEL(c, CTX(fSuccessor));- return;- }- oldPtr = STATS(c);- MyMem12Cpy(ptr, oldPtr, oldNU);- InsertNode(p, oldPtr, i);- c->Stats = STATS_REF(ptr);- }- }- c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns));- }- else- {- CPpmd_State *s2 = (CPpmd_State*)AllocUnits(p, 0);- if (!s2)- {- RESTORE_MODEL(c, CTX(fSuccessor));- return;- }- *s2 = *ONE_STATE(c);- c->Stats = REF(s2);- if (s2->Freq < MAX_FREQ / 4 - 1)- s2->Freq <<= 1;- else- s2->Freq = MAX_FREQ - 4;- c->SummFreq = (UInt16)(s2->Freq + p->InitEsc + (ns > 2));- }- cf = 2 * fFreq * (c->SummFreq + 6);- sf = (UInt32)s0 + c->SummFreq;- if (cf < 6 * sf)- {- cf = 1 + (cf > sf) + (cf >= 4 * sf);- c->SummFreq += 4;- }- else- {- cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf);- c->SummFreq = (UInt16)(c->SummFreq + cf);- }- {- CPpmd_State *s2 = STATS(c) + ns1 + 1;- SetSuccessor(s2, successor);- s2->Symbol = fSymbol;- s2->Freq = (Byte)cf;- c->Flags |= flag;- c->NumStats = (Byte)(ns1 + 1);- }- }- p->MaxContext = p->MinContext = CTX(fSuccessor);-}- -static void Rescale(CPpmd8 *p)-{- unsigned i, adder, sumFreq, escFreq;- CPpmd_State *stats = STATS(p->MinContext);- CPpmd_State *s = p->FoundState;- {- CPpmd_State tmp = *s;- for (; s != stats; s--)- s[0] = s[-1];- *s = tmp;- }- escFreq = p->MinContext->SummFreq - s->Freq;- s->Freq += 4;- adder = (p->OrderFall != 0- #ifdef PPMD8_FREEZE_SUPPORT- || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE- #endif- );- s->Freq = (Byte)((s->Freq + adder) >> 1);- sumFreq = s->Freq;- - i = p->MinContext->NumStats;- do- {- escFreq -= (++s)->Freq;- s->Freq = (Byte)((s->Freq + adder) >> 1);- sumFreq += s->Freq;- if (s[0].Freq > s[-1].Freq)- {- CPpmd_State *s1 = s;- CPpmd_State tmp = *s1;- do- s1[0] = s1[-1];- while (--s1 != stats && tmp.Freq > s1[-1].Freq);- *s1 = tmp;- }- }- while (--i);- - if (s->Freq == 0)- {- unsigned numStats = p->MinContext->NumStats;- unsigned n0, n1;- do { i++; } while ((--s)->Freq == 0);- escFreq += i;- p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i);- if (p->MinContext->NumStats == 0)- {- CPpmd_State tmp = *stats;- tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq);- if (tmp.Freq > MAX_FREQ / 3)- tmp.Freq = MAX_FREQ / 3;- InsertNode(p, stats, U2I((numStats + 2) >> 1));- p->MinContext->Flags = (Byte)((p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40));- *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;- return;- }- n0 = (numStats + 2) >> 1;- n1 = (p->MinContext->NumStats + 2) >> 1;- if (n0 != n1)- p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));- p->MinContext->Flags &= ~0x08;- p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40);- i = p->MinContext->NumStats;- do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i);- }- p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));- p->MinContext->Flags |= 0x4;- p->FoundState = STATS(p->MinContext);-}--CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq)-{- CPpmd_See *see;- if (p->MinContext->NumStats != 0xFF)- {- see = p->See[(unsigned)p->NS2Indx[(unsigned)p->MinContext->NumStats + 2] - 3] +- (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) +- 2 * (unsigned)(2 * (unsigned)p->MinContext->NumStats <- ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) +- p->MinContext->Flags;- {- unsigned r = (see->Summ >> see->Shift);- see->Summ = (UInt16)(see->Summ - r);- *escFreq = r + (r == 0);- }- }- else- {- see = &p->DummySee;- *escFreq = 1;- }- return see;-}--static void NextContext(CPpmd8 *p)-{- CTX_PTR c = CTX(SUCCESSOR(p->FoundState));- if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart)- p->MinContext = p->MaxContext = c;- else- {- UpdateModel(p);- p->MinContext = p->MaxContext;- }-}--void Ppmd8_Update1(CPpmd8 *p)-{- CPpmd_State *s = p->FoundState;- s->Freq += 4;- p->MinContext->SummFreq += 4;- if (s[0].Freq > s[-1].Freq)- {- SwapStates(&s[0], &s[-1]);- p->FoundState = --s;- if (s->Freq > MAX_FREQ)- Rescale(p);- }- NextContext(p);-}--void Ppmd8_Update1_0(CPpmd8 *p)-{- p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq);- p->RunLength += p->PrevSuccess;- p->MinContext->SummFreq += 4;- if ((p->FoundState->Freq += 4) > MAX_FREQ)- Rescale(p);- NextContext(p);-}--void Ppmd8_UpdateBin(CPpmd8 *p)-{- p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196));- p->PrevSuccess = 1;- p->RunLength++;- NextContext(p);-}--void Ppmd8_Update2(CPpmd8 *p)-{- p->MinContext->SummFreq += 4;- if ((p->FoundState->Freq += 4) > MAX_FREQ)- Rescale(p);- p->RunLength = p->InitRL;- UpdateModel(p);- p->MinContext = p->MaxContext;-}--/* Ppmd8Dec.c -- PPMdI Decoder-2010-04-16 : Igor Pavlov : Public domain-This code is based on:- PPMd var.I (2002): Dmitry Shkarin : Public domain- Carryless rangecoder (1999): Dmitry Subbotin : Public domain */--Bool Ppmd8_RangeDec_Init(CPpmd8 *p)-{- unsigned i;- p->Low = 0;- p->Range = 0xFFFFFFFF;- p->Code = 0;- for (i = 0; i < 4; i++)- p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In);- return (p->Code < 0xFFFFFFFF);-}--static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total)-{- return p->Code / (p->Range /= total);-}--static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size)-{- start *= p->Range;- p->Low += start;- p->Code -= start;- p->Range *= size;-- while ((p->Low ^ (p->Low + p->Range)) < kTop ||- (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1)))- {- p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In);- p->Range <<= 8;- p->Low <<= 8;- }-}--#define MASK(sym) ((signed char *)charMask)[sym]--int Ppmd8_DecodeSymbol(CPpmd8 *p)-{- size_t charMask[256 / sizeof(size_t)];- if (p->MinContext->NumStats != 0)- {- CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext);- unsigned i;- UInt32 count, hiCnt;- if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq))- {- Byte symbol;- RangeDec_Decode(p, 0, s->Freq);- p->FoundState = s;- symbol = s->Symbol;- Ppmd8_Update1_0(p);- return symbol;- }- p->PrevSuccess = 0;- i = p->MinContext->NumStats;- do- {- if ((hiCnt += (++s)->Freq) > count)- {- Byte symbol;- RangeDec_Decode(p, hiCnt - s->Freq, s->Freq);- p->FoundState = s;- symbol = s->Symbol;- Ppmd8_Update1(p);- return symbol;- }- }- while (--i);- if (count >= p->MinContext->SummFreq)- return -2;- RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt);- PPMD_SetAllBitsIn256Bytes(charMask);- MASK(s->Symbol) = 0;- i = p->MinContext->NumStats;- do { MASK((--s)->Symbol) = 0; } while (--i);- }- else- {- UInt16 *prob = Ppmd8_GetBinSumm(p);- if (((p->Code / (p->Range >>= 14)) < *prob))- {- Byte symbol;- RangeDec_Decode(p, 0, *prob);- *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);- symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol;- Ppmd8_UpdateBin(p);- return symbol;- }- RangeDec_Decode(p, *prob, (1 << 14) - *prob);- *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);- p->InitEsc = PPMD8_kExpEscape[*prob >> 10];- PPMD_SetAllBitsIn256Bytes(charMask);- MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0;- p->PrevSuccess = 0;- }- for (;;)- {- CPpmd_State *ps[256], *s;- UInt32 freqSum, count, hiCnt;- CPpmd_See *see;- unsigned i, num, numMasked = p->MinContext->NumStats;- do- {- p->OrderFall++;- if (!p->MinContext->Suffix)- return -1;- p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix);- }- while (p->MinContext->NumStats == numMasked);- hiCnt = 0;- s = Ppmd8_GetStats(p, p->MinContext);- i = 0;- num = p->MinContext->NumStats - numMasked;- do- {- int k = (int)(MASK(s->Symbol));- hiCnt += (s->Freq & k);- ps[i] = s++;- i -= k;- }- while (i != num);- - see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum);- freqSum += hiCnt;- count = RangeDec_GetThreshold(p, freqSum);- - if (count < hiCnt)- {- Byte symbol;- CPpmd_State **pps = ps;- for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);- s = *pps;- RangeDec_Decode(p, hiCnt - s->Freq, s->Freq);- Ppmd_See_Update(see);- p->FoundState = s;- symbol = s->Symbol;- Ppmd8_Update2(p);- return symbol;- }- if (count >= freqSum)- return -2;- RangeDec_Decode(p, hiCnt, freqSum - hiCnt);- see->Summ = (UInt16)(see->Summ + freqSum);- do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);- }-}--/* H->I changes:- NS2Indx- GlewCount, and Glue method- BinSum- See / EscFreq- CreateSuccessors updates more suffix contexts- UpdateModel consts.- PrevSuccess Update-*/--const IPpmd8 __archive_ppmd8_functions =-{- &Ppmd8_Construct,- &Ppmd8_Alloc,- &Ppmd8_Free,- &Ppmd8_Init,- &Ppmd8_RangeDec_Init,- &Ppmd8_DecodeSymbol,-};
− c/archive_ppmd8_private.h
@@ -1,148 +0,0 @@-/* Ppmd8.h -- PPMdI codec-2011-01-27 : Igor Pavlov : Public domain-This code is based on:- PPMd var.I (2002): Dmitry Shkarin : Public domain- Carryless rangecoder (1999): Dmitry Subbotin : Public domain */--#ifndef ARCHIVE_PPMD8_PRIVATE_H_INCLUDED-#define ARCHIVE_PPMD8_PRIVATE_H_INCLUDED--#include "archive_ppmd_private.h"--#define PPMD8_MIN_ORDER 2-#define PPMD8_MAX_ORDER 16--struct CPpmd8_Context_;--typedef- #ifdef PPMD_32BIT- struct CPpmd8_Context_ *- #else- UInt32- #endif- CPpmd8_Context_Ref;--#pragma pack(push, 1)--typedef struct CPpmd8_Context_-{- Byte NumStats;- Byte Flags;- UInt16 SummFreq;- CPpmd_State_Ref Stats;- CPpmd8_Context_Ref Suffix;-} CPpmd8_Context;--#pragma pack(pop)--#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)--/* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed- code is not compatible with original code for some files compressed- in FREEZE mode. So we disable FREEZE mode support. */--enum-{- PPMD8_RESTORE_METHOD_RESTART,- PPMD8_RESTORE_METHOD_CUT_OFF- #ifdef PPMD8_FREEZE_SUPPORT- , PPMD8_RESTORE_METHOD_FREEZE- #endif-};--typedef struct-{- CPpmd8_Context *MinContext, *MaxContext;- CPpmd_State *FoundState;- unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder;- Int32 RunLength, InitRL; /* must be 32-bit at least */-- UInt32 Size;- UInt32 GlueCount;- Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;- UInt32 AlignOffset;- unsigned RestoreMethod;-- /* Range Coder */- UInt32 Range;- UInt32 Code;- UInt32 Low;- union- {- IByteIn *In;- IByteOut *Out;- } Stream;-- Byte Indx2Units[PPMD_NUM_INDEXES];- Byte Units2Indx[128];- CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];- UInt32 Stamps[PPMD_NUM_INDEXES];-- Byte NS2BSIndx[256], NS2Indx[260];- CPpmd_See DummySee, See[24][32];- UInt16 BinSumm[25][64];-} CPpmd8;--void Ppmd8_Construct(CPpmd8 *p);-Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size);-void Ppmd8_Free(CPpmd8 *p);-void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod);-#define Ppmd8_WasAllocated(p) ((p)->Base != NULL)---/* ---------- Internal Functions ---------- */--extern const Byte PPMD8_kExpEscape[16];--#ifdef PPMD_32BIT- #define Ppmd8_GetPtr(p, ptr) (ptr)- #define Ppmd8_GetContext(p, ptr) (ptr)- #define Ppmd8_GetStats(p, ctx) ((ctx)->Stats)-#else- #define Ppmd8_GetPtr(p, offs) ((void *)((p)->Base + (offs)))- #define Ppmd8_GetContext(p, offs) ((CPpmd8_Context *)Ppmd8_GetPtr((p), (offs)))- #define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats)))-#endif--void Ppmd8_Update1(CPpmd8 *p);-void Ppmd8_Update1_0(CPpmd8 *p);-void Ppmd8_Update2(CPpmd8 *p);-void Ppmd8_UpdateBin(CPpmd8 *p);--#define Ppmd8_GetBinSumm(p) \- &p->BinSumm[p->NS2Indx[Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \- p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \- p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)]--CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale);---/* ---------- Decode ---------- */--Bool Ppmd8_RangeDec_Init(CPpmd8 *p);-#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0)-int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */--/* ---------- Encode ---------- */--#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; }-void Ppmd8_RangeEnc_FlushData(CPpmd8 *p);-void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */--typedef struct-{- /* Base Functions */- void (*Ppmd8_Construct)(CPpmd8 *p);- Bool (*Ppmd8_Alloc)(CPpmd8 *p, UInt32 size);- void (*Ppmd8_Free)(CPpmd8 *p);- void (*Ppmd8_Init)(CPpmd8 *p, unsigned max_order, unsigned restore_method);- #define Ppmd7_WasAllocated(p) ((p)->Base != NULL)-- /* Decode Functions */- int (*Ppmd8_RangeDec_Init)(CPpmd8 *p);- int (*Ppmd8_DecodeSymbol)(CPpmd8 *p);-} IPpmd8;--extern const IPpmd8 __archive_ppmd8_functions;--#endif
− c/archive_ppmd_private.h
@@ -1,151 +0,0 @@-/* Ppmd.h -- PPMD codec common code-2010-03-12 : Igor Pavlov : Public domain-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */--#ifndef ARCHIVE_PPMD_PRIVATE_H_INCLUDED-#define ARCHIVE_PPMD_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--#include <stddef.h>--#include "archive_read_private.h"--/*** Begin defined in Types.h ***/--#if !defined(ZCONF_H)-typedef unsigned char Byte;-#endif-typedef short Int16;-typedef unsigned short UInt16;--#ifdef _LZMA_UINT32_IS_ULONG-typedef long Int32;-typedef unsigned long UInt32;-#else-typedef int Int32;-typedef unsigned int UInt32;-#endif--#ifdef _SZ_NO_INT_64--/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.- NOTES: Some code will work incorrectly in that case! */--typedef long Int64;-typedef unsigned long UInt64;--#else--#if defined(_MSC_VER) || defined(__BORLANDC__)-typedef __int64 Int64;-typedef unsigned __int64 UInt64;-#define UINT64_CONST(n) n-#else-typedef long long int Int64;-typedef unsigned long long int UInt64;-#define UINT64_CONST(n) n ## ULL-#endif--#endif--typedef int Bool;-#define True 1-#define False 0--/* The following interfaces use first parameter as pointer to structure */--typedef struct-{- struct archive_read *a;- Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */-} IByteIn;--typedef struct-{- struct archive_write *a;- void (*Write)(void *p, Byte b);-} IByteOut;--/*** End defined in Types.h ***/-/*** Begin defined in CpuArch.h ***/--#if defined(_M_IX86) || defined(__i386__)-#define MY_CPU_X86-#endif--#if defined(MY_CPU_X86) || defined(_M_ARM)-#define MY_CPU_32BIT-#endif--#ifdef MY_CPU_32BIT-#define PPMD_32BIT-#endif--/*** End defined in CpuArch.h ***/--#define PPMD_INT_BITS 7-#define PPMD_PERIOD_BITS 7-#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))--#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))-#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)-#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))-#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))--#define PPMD_N1 4-#define PPMD_N2 4-#define PPMD_N3 4-#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)-#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)--/* SEE-contexts for PPM-contexts with masked symbols */-typedef struct-{- UInt16 Summ; /* Freq */- Byte Shift; /* Speed of Freq change; low Shift is for fast change */- Byte Count; /* Count to next change of Shift */-} CPpmd_See;--#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \- { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }--typedef struct-{- Byte Symbol;- Byte Freq;- UInt16 SuccessorLow;- UInt16 SuccessorHigh;-} CPpmd_State;--typedef- #ifdef PPMD_32BIT- CPpmd_State *- #else- UInt32- #endif- CPpmd_State_Ref;--typedef- #ifdef PPMD_32BIT- void *- #else- UInt32- #endif- CPpmd_Void_Ref;--typedef- #ifdef PPMD_32BIT- Byte *- #else- UInt32- #endif- CPpmd_Byte_Ref;--#define PPMD_SetAllBitsIn256Bytes(p) \- { unsigned j; for (j = 0; j < 256 / sizeof(p[0]); j += 8) { \- p[j+7] = p[j+6] = p[j+5] = p[j+4] = p[j+3] = p[j+2] = p[j+1] = p[j+0] = ~(size_t)0; }}--#endif
− c/archive_private.h
@@ -1,180 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD: head/lib/libarchive/archive_private.h 201098 2009-12-28 02:58:14Z kientzle $- */--#ifndef ARCHIVE_PRIVATE_H_INCLUDED-#define ARCHIVE_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--#if HAVE_ICONV_H-#include <iconv.h>-#endif--#include "archive.h"-#include "archive_string.h"--#if defined(__GNUC__) && (__GNUC__ > 2 || \- (__GNUC__ == 2 && __GNUC_MINOR__ >= 5))-#define __LA_DEAD __attribute__((__noreturn__))-#else-#define __LA_DEAD-#endif--#if defined(__GNUC__) && (__GNUC__ > 2 || \- (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))-#define __LA_UNUSED __attribute__((__unused__))-#else-#define __LA_UNUSED-#endif--#define ARCHIVE_WRITE_MAGIC (0xb0c5c0deU)-#define ARCHIVE_READ_MAGIC (0xdeb0c5U)-#define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)-#define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U)-#define ARCHIVE_MATCH_MAGIC (0xcad11c9U)--#define ARCHIVE_STATE_NEW 1U-#define ARCHIVE_STATE_HEADER 2U-#define ARCHIVE_STATE_DATA 4U-#define ARCHIVE_STATE_EOF 0x10U-#define ARCHIVE_STATE_CLOSED 0x20U-#define ARCHIVE_STATE_FATAL 0x8000U-#define ARCHIVE_STATE_ANY (0xFFFFU & ~ARCHIVE_STATE_FATAL)--struct archive_vtable {- int (*archive_close)(struct archive *);- int (*archive_free)(struct archive *);- int (*archive_write_header)(struct archive *,- struct archive_entry *);- int (*archive_write_finish_entry)(struct archive *);- ssize_t (*archive_write_data)(struct archive *,- const void *, size_t);- ssize_t (*archive_write_data_block)(struct archive *,- const void *, size_t, int64_t);-- int (*archive_read_next_header)(struct archive *,- struct archive_entry **);- int (*archive_read_next_header2)(struct archive *,- struct archive_entry *);- int (*archive_read_data_block)(struct archive *,- const void **, size_t *, int64_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_string_conv;--struct archive {- /*- * The magic/state values are used to sanity-check the- * client's usage. If an API function is called at a- * ridiculous time, or the client passes us an invalid- * pointer, these values allow me to catch that.- */- unsigned int magic;- unsigned int state;-- /*- * Some public API functions depend on the "real" type of the- * archive object.- */- const struct archive_vtable *vtable;-- int archive_format;- const char *archive_format_name;-- /* Number of file entries processed. */- int file_count;-- int archive_error_number;- const char *error;- struct archive_string error_string;-- char *current_code;- unsigned current_codepage; /* Current ACP(ANSI CodePage). */- unsigned current_oemcp; /* Current OEMCP(OEM CodePage). */- struct archive_string_conv *sconv;-- /*- * Used by archive_read_data() to track blocks and copy- * data to client buffers, filling gaps with zero bytes.- */- const char *read_data_block;- int64_t read_data_offset;- int64_t read_data_output_offset;- size_t read_data_remaining;-- /*- * Used by formats/filters to determine the amount of data- * requested from a call to archive_read_data(). This is only- * useful when the format/filter has seek support.- */- char read_data_is_posix_read;- size_t read_data_requested;-};--/* Check magic value and state; return(ARCHIVE_FATAL) if it isn't valid. */-int __archive_check_magic(struct archive *, unsigned int magic,- unsigned int state, const char *func);-#define archive_check_magic(a, expected_magic, allowed_states, function_name) \- do { \- int magic_test = __archive_check_magic((a), (expected_magic), \- (allowed_states), (function_name)); \- if (magic_test == ARCHIVE_FATAL) \- return ARCHIVE_FATAL; \- } while (0)--void __archive_errx(int retvalue, const char *msg) __LA_DEAD;--void __archive_ensure_cloexec_flag(int fd);-int __archive_mktemp(const char *tmpdir);-#if defined(_WIN32) && !defined(__CYGWIN__)-int __archive_mkstemp(wchar_t *template);-#else-int __archive_mkstemp(char *template);-#endif--int __archive_clean(struct archive *);--void __archive_reset_read_data(struct archive *);--#define err_combine(a,b) ((a) < (b) ? (a) : (b))--#if defined(__BORLANDC__) || (defined(_MSC_VER) && _MSC_VER <= 1300)-# define ARCHIVE_LITERAL_LL(x) x##i64-# define ARCHIVE_LITERAL_ULL(x) x##ui64-#else-# define ARCHIVE_LITERAL_LL(x) x##ll-# define ARCHIVE_LITERAL_ULL(x) x##ull-#endif--#endif
− c/archive_random.c
@@ -1,301 +0,0 @@-/*-- * Copyright (c) 2014 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif--#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))--#ifdef HAVE_FCNTL-#include <fcntl.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif-#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_SYS_TIME_H-#include <sys/time.h>-#endif-#ifdef HAVE_PTHREAD_H-#include <pthread.h>-#endif--static void la_arc4random_buf(void *, size_t);--#endif /* HAVE_ARC4RANDOM_BUF */--#include "archive.h"-#include "archive_random_private.h"--#if defined(_WIN32) && !defined(__CYGWIN__)-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA-/* don't use bcrypt when XP needs to be supported */-#include <bcrypt.h>--/* Common in other bcrypt implementations, but missing from VS2008. */-#ifndef BCRYPT_SUCCESS-#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)-#endif--#elif defined(HAVE_WINCRYPT_H)-#include <wincrypt.h>-#endif-#endif--#ifndef O_CLOEXEC-#define O_CLOEXEC 0-#endif--/*- * Random number generator function.- * This simply calls arc4random_buf function if the platform provides it.- */--int-archive_random(void *buf, size_t nbytes)-{-#if defined(_WIN32) && !defined(__CYGWIN__)-# if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- NTSTATUS status;- BCRYPT_ALG_HANDLE hAlg;-- status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0);- if (!BCRYPT_SUCCESS(status))- return ARCHIVE_FAILED;- status = BCryptGenRandom(hAlg, buf, nbytes, 0);- BCryptCloseAlgorithmProvider(hAlg, 0);- if (!BCRYPT_SUCCESS(status))- return ARCHIVE_FAILED;-- return ARCHIVE_OK;-# else- HCRYPTPROV hProv;- BOOL success;-- success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,- CRYPT_VERIFYCONTEXT);- if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) {- success = CryptAcquireContext(&hProv, NULL, NULL,- PROV_RSA_FULL, CRYPT_NEWKEYSET);- }- if (success) {- success = CryptGenRandom(hProv, (DWORD)nbytes, (BYTE*)buf);- CryptReleaseContext(hProv, 0);- if (success)- return ARCHIVE_OK;- }- /* TODO: Does this case really happen? */- return ARCHIVE_FAILED;-# endif-#elif !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))- la_arc4random_buf(buf, nbytes);- return ARCHIVE_OK;-#else- arc4random_buf(buf, nbytes);- return ARCHIVE_OK;-#endif-}--#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))--/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */-/*- * Copyright (c) 1996, David Mazieres <dm@uun.org>- * Copyright (c) 2008, Damien Miller <djm@openbsd.org>- *- * Permission to use, copy, modify, and distribute this software for any- * purpose with or without fee is hereby granted, provided that the above- * copyright notice and this permission notice appear in all copies.- *- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.- */--/*- * Arc4 random number generator for OpenBSD.- *- * This code is derived from section 17.1 of Applied Cryptography,- * second edition, which describes a stream cipher allegedly- * compatible with RSA Labs "RC4" cipher (the actual description of- * which is a trade secret). The same algorithm is used as a stream- * cipher called "arcfour" in Tatu Ylonen's ssh package.- *- * RC4 is a registered trademark of RSA Laboratories.- */--#ifdef __GNUC__-#define inline __inline-#else /* !__GNUC__ */-#define inline-#endif /* !__GNUC__ */--struct arc4_stream {- uint8_t i;- uint8_t j;- uint8_t s[256];-};--#define RANDOMDEV "/dev/urandom"-#define KEYSIZE 128-#ifdef HAVE_PTHREAD_H-static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;-#define _ARC4_LOCK() pthread_mutex_lock(&arc4random_mtx);-#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx);-#else-#define _ARC4_LOCK()-#define _ARC4_UNLOCK()-#endif--static int rs_initialized;-static struct arc4_stream rs;-static pid_t arc4_stir_pid;-static int arc4_count;--static inline uint8_t arc4_getbyte(void);-static void arc4_stir(void);--static inline void-arc4_init(void)-{- int n;-- for (n = 0; n < 256; n++)- rs.s[n] = n;- rs.i = 0;- rs.j = 0;-}--static inline void-arc4_addrandom(uint8_t *dat, int datlen)-{- int n;- uint8_t si;-- rs.i--;- for (n = 0; n < 256; n++) {- rs.i = (rs.i + 1);- si = rs.s[rs.i];- rs.j = (rs.j + si + dat[n % datlen]);- rs.s[rs.i] = rs.s[rs.j];- rs.s[rs.j] = si;- }- rs.j = rs.i;-}--static void-arc4_stir(void)-{- int done, fd, i;- struct {- struct timeval tv;- pid_t pid;- uint8_t rnd[KEYSIZE];- } rdat;-- if (!rs_initialized) {- arc4_init();- rs_initialized = 1;- }- done = 0;- fd = open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0);- if (fd >= 0) {- if (read(fd, &rdat, KEYSIZE) == KEYSIZE)- done = 1;- (void)close(fd);- }- if (!done) {- (void)gettimeofday(&rdat.tv, NULL);- rdat.pid = getpid();- /* We'll just take whatever was on the stack too... */- }-- arc4_addrandom((uint8_t *)&rdat, KEYSIZE);-- /*- * Discard early keystream, as per recommendations in:- * "(Not So) Random Shuffles of RC4" by Ilya Mironov.- * As per the Network Operations Division, cryptographic requirements- * published on wikileaks on March 2017.- */-- for (i = 0; i < 3072; i++)- (void)arc4_getbyte();- arc4_count = 1600000;-}--static void-arc4_stir_if_needed(void)-{- pid_t pid = getpid();-- if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) {- arc4_stir_pid = pid;- arc4_stir();- }-}--static inline uint8_t-arc4_getbyte(void)-{- uint8_t si, sj;-- rs.i = (rs.i + 1);- si = rs.s[rs.i];- rs.j = (rs.j + si);- sj = rs.s[rs.j];- rs.s[rs.i] = sj;- rs.s[rs.j] = si;- return (rs.s[(si + sj) & 0xff]);-}--static void-la_arc4random_buf(void *_buf, size_t n)-{- uint8_t *buf = (uint8_t *)_buf;- _ARC4_LOCK();- arc4_stir_if_needed();- while (n--) {- if (--arc4_count <= 0)- arc4_stir();- buf[n] = arc4_getbyte();- }- _ARC4_UNLOCK();-}--#endif /* !HAVE_ARC4RANDOM_BUF */
− c/archive_random_private.h
@@ -1,36 +0,0 @@-/*-- * Copyright (c) 2014 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#ifndef ARCHIVE_RANDOM_PRIVATE_H_INCLUDED-#define ARCHIVE_RANDOM_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--/* Random number generator. */-int archive_random(void *buf, size_t nbytes);--#endif /* ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */
− c/archive_rb.c
@@ -1,709 +0,0 @@-/*-- * Copyright (c) 2001 The NetBSD Foundation, Inc.- * All rights reserved.- *- * This code is derived from software contributed to The NetBSD Foundation- * by Matt Thomas <matt@3am-software.com>.- *- * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE- * POSSIBILITY OF SUCH DAMAGE.- *- * Based on: NetBSD: rb.c,v 1.6 2010/04/30 13:58:09 joerg Exp- */--#include "archive_platform.h"--#include <stddef.h>--#include "archive_rb.h"--/* Keep in sync with archive_rb.h */-#define RB_DIR_LEFT 0-#define RB_DIR_RIGHT 1-#define RB_DIR_OTHER 1-#define rb_left rb_nodes[RB_DIR_LEFT]-#define rb_right rb_nodes[RB_DIR_RIGHT]--#define RB_FLAG_POSITION 0x2-#define RB_FLAG_RED 0x1-#define RB_FLAG_MASK (RB_FLAG_POSITION|RB_FLAG_RED)-#define RB_FATHER(rb) \- ((struct archive_rb_node *)((rb)->rb_info & ~RB_FLAG_MASK))-#define RB_SET_FATHER(rb, father) \- ((void)((rb)->rb_info = (uintptr_t)(father)|((rb)->rb_info & RB_FLAG_MASK)))--#define RB_SENTINEL_P(rb) ((rb) == NULL)-#define RB_LEFT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_left)-#define RB_RIGHT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_right)-#define RB_FATHER_SENTINEL_P(rb) RB_SENTINEL_P(RB_FATHER((rb)))-#define RB_CHILDLESS_P(rb) \- (RB_SENTINEL_P(rb) || (RB_LEFT_SENTINEL_P(rb) && RB_RIGHT_SENTINEL_P(rb)))-#define RB_TWOCHILDREN_P(rb) \- (!RB_SENTINEL_P(rb) && !RB_LEFT_SENTINEL_P(rb) && !RB_RIGHT_SENTINEL_P(rb))--#define RB_POSITION(rb) \- (((rb)->rb_info & RB_FLAG_POSITION) ? RB_DIR_RIGHT : RB_DIR_LEFT)-#define RB_RIGHT_P(rb) (RB_POSITION(rb) == RB_DIR_RIGHT)-#define RB_LEFT_P(rb) (RB_POSITION(rb) == RB_DIR_LEFT)-#define RB_RED_P(rb) (!RB_SENTINEL_P(rb) && ((rb)->rb_info & RB_FLAG_RED) != 0)-#define RB_BLACK_P(rb) (RB_SENTINEL_P(rb) || ((rb)->rb_info & RB_FLAG_RED) == 0)-#define RB_MARK_RED(rb) ((void)((rb)->rb_info |= RB_FLAG_RED))-#define RB_MARK_BLACK(rb) ((void)((rb)->rb_info &= ~RB_FLAG_RED))-#define RB_INVERT_COLOR(rb) ((void)((rb)->rb_info ^= RB_FLAG_RED))-#define RB_ROOT_P(rbt, rb) ((rbt)->rbt_root == (rb))-#define RB_SET_POSITION(rb, position) \- ((void)((position) ? ((rb)->rb_info |= RB_FLAG_POSITION) : \- ((rb)->rb_info &= ~RB_FLAG_POSITION)))-#define RB_ZERO_PROPERTIES(rb) ((void)((rb)->rb_info &= ~RB_FLAG_MASK))-#define RB_COPY_PROPERTIES(dst, src) \- ((void)((dst)->rb_info ^= ((dst)->rb_info ^ (src)->rb_info) & RB_FLAG_MASK))-#define RB_SWAP_PROPERTIES(a, b) do { \- uintptr_t xorinfo = ((a)->rb_info ^ (b)->rb_info) & RB_FLAG_MASK; \- (a)->rb_info ^= xorinfo; \- (b)->rb_info ^= xorinfo; \- } while (/*CONSTCOND*/ 0)--static void __archive_rb_tree_insert_rebalance(struct archive_rb_tree *,- struct archive_rb_node *);-static void __archive_rb_tree_removal_rebalance(struct archive_rb_tree *,- struct archive_rb_node *, unsigned int);--#define RB_SENTINEL_NODE NULL--#define T 1-#define F 0--void-__archive_rb_tree_init(struct archive_rb_tree *rbt,- const struct archive_rb_tree_ops *ops)-{- rbt->rbt_ops = ops;- *((struct archive_rb_node **)&rbt->rbt_root) = RB_SENTINEL_NODE;-}--struct archive_rb_node *-__archive_rb_tree_find_node(struct archive_rb_tree *rbt, const void *key)-{- archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;- struct archive_rb_node *parent = rbt->rbt_root;-- while (!RB_SENTINEL_P(parent)) {- const signed int diff = (*compare_key)(parent, key);- if (diff == 0)- return parent;- parent = parent->rb_nodes[diff > 0];- }-- return NULL;-}- -struct archive_rb_node *-__archive_rb_tree_find_node_geq(struct archive_rb_tree *rbt, const void *key)-{- archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;- struct archive_rb_node *parent = rbt->rbt_root;- struct archive_rb_node *last = NULL;-- while (!RB_SENTINEL_P(parent)) {- const signed int diff = (*compare_key)(parent, key);- if (diff == 0)- return parent;- if (diff < 0)- last = parent;- parent = parent->rb_nodes[diff > 0];- }-- return last;-}- -struct archive_rb_node *-__archive_rb_tree_find_node_leq(struct archive_rb_tree *rbt, const void *key)-{- archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;- struct archive_rb_node *parent = rbt->rbt_root;- struct archive_rb_node *last = NULL;-- while (!RB_SENTINEL_P(parent)) {- const signed int diff = (*compare_key)(parent, key);- if (diff == 0)- return parent;- if (diff > 0)- last = parent;- parent = parent->rb_nodes[diff > 0];- }-- return last;-}--int-__archive_rb_tree_insert_node(struct archive_rb_tree *rbt,- struct archive_rb_node *self)-{- archive_rbto_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes;- struct archive_rb_node *parent, *tmp;- unsigned int position;- int rebalance;-- tmp = rbt->rbt_root;- /*- * This is a hack. Because rbt->rbt_root is just a- * struct archive_rb_node *, just like rb_node->rb_nodes[RB_DIR_LEFT],- * we can use this fact to avoid a lot of tests for root and know- * that even at root, updating- * RB_FATHER(rb_node)->rb_nodes[RB_POSITION(rb_node)] will- * update rbt->rbt_root.- */- parent = (struct archive_rb_node *)(void *)&rbt->rbt_root;- position = RB_DIR_LEFT;-- /*- * Find out where to place this new leaf.- */- while (!RB_SENTINEL_P(tmp)) {- const signed int diff = (*compare_nodes)(tmp, self);- if (diff == 0) {- /*- * Node already exists; don't insert.- */- return F;- }- parent = tmp;- position = (diff > 0);- tmp = parent->rb_nodes[position];- }-- /*- * Initialize the node and insert as a leaf into the tree.- */- RB_SET_FATHER(self, parent);- RB_SET_POSITION(self, position);- if (parent == (struct archive_rb_node *)(void *)&rbt->rbt_root) {- RB_MARK_BLACK(self); /* root is always black */- rebalance = F;- } else {- /*- * All new nodes are colored red. We only need to rebalance- * if our parent is also red.- */- RB_MARK_RED(self);- rebalance = RB_RED_P(parent);- }- self->rb_left = parent->rb_nodes[position];- self->rb_right = parent->rb_nodes[position];- parent->rb_nodes[position] = self;-- /*- * Rebalance tree after insertion- */- if (rebalance)- __archive_rb_tree_insert_rebalance(rbt, self);-- return T;-}--/*- * Swap the location and colors of 'self' and its child @ which. The child- * can not be a sentinel node. This is our rotation function. However,- * since it preserves coloring, it great simplifies both insertion and- * removal since rotation almost always involves the exchanging of colors- * as a separate step.- */-/*ARGSUSED*/-static void-__archive_rb_tree_reparent_nodes(- struct archive_rb_node *old_father, const unsigned int which)-{- const unsigned int other = which ^ RB_DIR_OTHER;- struct archive_rb_node * const grandpa = RB_FATHER(old_father);- struct archive_rb_node * const old_child = old_father->rb_nodes[which];- struct archive_rb_node * const new_father = old_child;- struct archive_rb_node * const new_child = old_father;-- if (new_father == NULL)- return;- /*- * Exchange descendant linkages.- */- grandpa->rb_nodes[RB_POSITION(old_father)] = new_father;- new_child->rb_nodes[which] = old_child->rb_nodes[other];- new_father->rb_nodes[other] = new_child;-- /*- * Update ancestor linkages- */- RB_SET_FATHER(new_father, grandpa);- RB_SET_FATHER(new_child, new_father);-- /*- * Exchange properties between new_father and new_child. The only- * change is that new_child's position is now on the other side.- */- RB_SWAP_PROPERTIES(new_father, new_child);- RB_SET_POSITION(new_child, other);-- /*- * Make sure to reparent the new child to ourself.- */- if (!RB_SENTINEL_P(new_child->rb_nodes[which])) {- RB_SET_FATHER(new_child->rb_nodes[which], new_child);- RB_SET_POSITION(new_child->rb_nodes[which], which);- }--}--static void-__archive_rb_tree_insert_rebalance(struct archive_rb_tree *rbt,- struct archive_rb_node *self)-{- struct archive_rb_node * father = RB_FATHER(self);- struct archive_rb_node * grandpa;- struct archive_rb_node * uncle;- unsigned int which;- unsigned int other;-- for (;;) {- /*- * We are red and our parent is red, therefore we must have a- * grandfather and he must be black.- */- grandpa = RB_FATHER(father);- which = (father == grandpa->rb_right);- other = which ^ RB_DIR_OTHER;- uncle = grandpa->rb_nodes[other];-- if (RB_BLACK_P(uncle))- break;-- /*- * Case 1: our uncle is red- * Simply invert the colors of our parent and- * uncle and make our grandparent red. And- * then solve the problem up at his level.- */- RB_MARK_BLACK(uncle);- RB_MARK_BLACK(father);- if (RB_ROOT_P(rbt, grandpa)) {- /*- * If our grandpa is root, don't bother- * setting him to red, just return.- */- return;- }- RB_MARK_RED(grandpa);- self = grandpa;- father = RB_FATHER(self);- if (RB_BLACK_P(father)) {- /*- * If our great-grandpa is black, we're done.- */- return;- }- }-- /*- * Case 2&3: our uncle is black.- */- if (self == father->rb_nodes[other]) {- /*- * Case 2: we are on the same side as our uncle- * Swap ourselves with our parent so this case- * becomes case 3. Basically our parent becomes our- * child.- */- __archive_rb_tree_reparent_nodes(father, other);- }- /*- * Case 3: we are opposite a child of a black uncle.- * Swap our parent and grandparent. Since our grandfather- * is black, our father will become black and our new sibling- * (former grandparent) will become red.- */- __archive_rb_tree_reparent_nodes(grandpa, which);-- /*- * Final step: Set the root to black.- */- RB_MARK_BLACK(rbt->rbt_root);-}--static void-__archive_rb_tree_prune_node(struct archive_rb_tree *rbt,- struct archive_rb_node *self, int rebalance)-{- const unsigned int which = RB_POSITION(self);- struct archive_rb_node *father = RB_FATHER(self);-- /*- * Since we are childless, we know that self->rb_left is pointing- * to the sentinel node.- */- father->rb_nodes[which] = self->rb_left;-- /*- * Rebalance if requested.- */- if (rebalance)- __archive_rb_tree_removal_rebalance(rbt, father, which);-}--/*- * When deleting an interior node- */-static void-__archive_rb_tree_swap_prune_and_rebalance(struct archive_rb_tree *rbt,- struct archive_rb_node *self, struct archive_rb_node *standin)-{- const unsigned int standin_which = RB_POSITION(standin);- unsigned int standin_other = standin_which ^ RB_DIR_OTHER;- struct archive_rb_node *standin_son;- struct archive_rb_node *standin_father = RB_FATHER(standin);- int rebalance = RB_BLACK_P(standin);-- if (standin_father == self) {- /*- * As a child of self, any children would be opposite of- * our parent.- */- standin_son = standin->rb_nodes[standin_which];- } else {- /*- * Since we aren't a child of self, any children would be- * on the same side as our parent.- */- standin_son = standin->rb_nodes[standin_other];- }-- if (RB_RED_P(standin_son)) {- /*- * We know we have a red child so if we flip it to black- * we don't have to rebalance.- */- RB_MARK_BLACK(standin_son);- rebalance = F;-- if (standin_father != self) {- /*- * Change the son's parentage to point to his grandpa.- */- RB_SET_FATHER(standin_son, standin_father);- RB_SET_POSITION(standin_son, standin_which);- }- }-- if (standin_father == self) {- /*- * If we are about to delete the standin's father, then when- * we call rebalance, we need to use ourselves as our father.- * Otherwise remember our original father. Also, since we are- * our standin's father we only need to reparent the standin's- * brother.- *- * | R --> S |- * | Q S --> Q T |- * | t --> |- *- * Have our son/standin adopt his brother as his new son.- */- standin_father = standin;- } else {- /*- * | R --> S . |- * | / \ | T --> / \ | / |- * | ..... | S --> ..... | T |- *- * Sever standin's connection to his father.- */- standin_father->rb_nodes[standin_which] = standin_son;- /*- * Adopt the far son.- */- standin->rb_nodes[standin_other] = self->rb_nodes[standin_other];- RB_SET_FATHER(standin->rb_nodes[standin_other], standin);- /*- * Use standin_other because we need to preserve standin_which- * for the removal_rebalance.- */- standin_other = standin_which;- }-- /*- * Move the only remaining son to our standin. If our standin is our- * son, this will be the only son needed to be moved.- */- standin->rb_nodes[standin_other] = self->rb_nodes[standin_other];- RB_SET_FATHER(standin->rb_nodes[standin_other], standin);-- /*- * Now copy the result of self to standin and then replace- * self with standin in the tree.- */- RB_COPY_PROPERTIES(standin, self);- RB_SET_FATHER(standin, RB_FATHER(self));- RB_FATHER(standin)->rb_nodes[RB_POSITION(standin)] = standin;-- if (rebalance)- __archive_rb_tree_removal_rebalance(rbt, standin_father, standin_which);-}--/*- * We could do this by doing- * __archive_rb_tree_node_swap(rbt, self, which);- * __archive_rb_tree_prune_node(rbt, self, F);- *- * But it's more efficient to just evaluate and recolor the child.- */-static void-__archive_rb_tree_prune_blackred_branch(- struct archive_rb_node *self, unsigned int which)-{- struct archive_rb_node *father = RB_FATHER(self);- struct archive_rb_node *son = self->rb_nodes[which];-- /*- * Remove ourselves from the tree and give our former child our- * properties (position, color, root).- */- RB_COPY_PROPERTIES(son, self);- father->rb_nodes[RB_POSITION(son)] = son;- RB_SET_FATHER(son, father);-}-/*- *- */-void-__archive_rb_tree_remove_node(struct archive_rb_tree *rbt,- struct archive_rb_node *self)-{- struct archive_rb_node *standin;- unsigned int which;-- /*- * In the following diagrams, we (the node to be removed) are S. Red- * nodes are lowercase. T could be either red or black.- *- * Remember the major axiom of the red-black tree: the number of- * black nodes from the root to each leaf is constant across all- * leaves, only the number of red nodes varies.- *- * Thus removing a red leaf doesn't require any other changes to a- * red-black tree. So if we must remove a node, attempt to rearrange- * the tree so we can remove a red node.- *- * The simplest case is a childless red node or a childless root node:- *- * | T --> T | or | R --> * |- * | s --> * |- */- if (RB_CHILDLESS_P(self)) {- const int rebalance = RB_BLACK_P(self) && !RB_ROOT_P(rbt, self);- __archive_rb_tree_prune_node(rbt, self, rebalance);- return;- }- if (!RB_TWOCHILDREN_P(self)) {- /*- * The next simplest case is the node we are deleting is- * black and has one red child.- *- * | T --> T --> T |- * | S --> R --> R |- * | r --> s --> * |- */- which = RB_LEFT_SENTINEL_P(self) ? RB_DIR_RIGHT : RB_DIR_LEFT;- __archive_rb_tree_prune_blackred_branch(self, which);- return;- }-- /*- * We invert these because we prefer to remove from the inside of- * the tree.- */- which = RB_POSITION(self) ^ RB_DIR_OTHER;-- /*- * Let's find the node closes to us opposite of our parent- * Now swap it with ourself, "prune" it, and rebalance, if needed.- */- standin = __archive_rb_tree_iterate(rbt, self, which);- __archive_rb_tree_swap_prune_and_rebalance(rbt, self, standin);-}--static void-__archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt,- struct archive_rb_node *parent, unsigned int which)-{-- while (RB_BLACK_P(parent->rb_nodes[which])) {- unsigned int other = which ^ RB_DIR_OTHER;- struct archive_rb_node *brother = parent->rb_nodes[other];-- if (brother == NULL)- return;/* The tree may be broken. */- /*- * For cases 1, 2a, and 2b, our brother's children must- * be black and our father must be black- */- if (RB_BLACK_P(parent)- && RB_BLACK_P(brother->rb_left)- && RB_BLACK_P(brother->rb_right)) {- if (RB_RED_P(brother)) {- /*- * Case 1: Our brother is red, swap its- * position (and colors) with our parent. - * This should now be case 2b (unless C or E- * has a red child which is case 3; thus no- * explicit branch to case 2b).- *- * B -> D- * A d -> b E- * C E -> A C- */- __archive_rb_tree_reparent_nodes(parent, other);- brother = parent->rb_nodes[other];- if (brother == NULL)- return;/* The tree may be broken. */- } else {- /*- * Both our parent and brother are black.- * Change our brother to red, advance up rank- * and go through the loop again.- *- * B -> *B- * *A D -> A d- * C E -> C E- */- RB_MARK_RED(brother);- if (RB_ROOT_P(rbt, parent))- return; /* root == parent == black */- which = RB_POSITION(parent);- parent = RB_FATHER(parent);- continue;- }- }- /*- * Avoid an else here so that case 2a above can hit either- * case 2b, 3, or 4.- */- if (RB_RED_P(parent)- && RB_BLACK_P(brother)- && RB_BLACK_P(brother->rb_left)- && RB_BLACK_P(brother->rb_right)) {- /*- * We are black, our father is red, our brother and- * both nephews are black. Simply invert/exchange the- * colors of our father and brother (to black and red- * respectively).- *- * | f --> F |- * | * B --> * b |- * | N N --> N N |- */- RB_MARK_BLACK(parent);- RB_MARK_RED(brother);- break; /* We're done! */- } else {- /*- * Our brother must be black and have at least one- * red child (it may have two).- */- if (RB_BLACK_P(brother->rb_nodes[other])) {- /*- * Case 3: our brother is black, our near- * nephew is red, and our far nephew is black.- * Swap our brother with our near nephew. - * This result in a tree that matches case 4.- * (Our father could be red or black).- *- * | F --> F |- * | x B --> x B |- * | n --> n |- */- __archive_rb_tree_reparent_nodes(brother, which);- brother = parent->rb_nodes[other];- }- /*- * Case 4: our brother is black and our far nephew- * is red. Swap our father and brother locations and- * change our far nephew to black. (these can be- * done in either order so we change the color first).- * The result is a valid red-black tree and is a- * terminal case. (again we don't care about the- * father's color)- *- * If the father is red, we will get a red-black-black- * tree:- * | f -> f --> b |- * | B -> B --> F N |- * | n -> N --> |- *- * If the father is black, we will get an all black- * tree:- * | F -> F --> B |- * | B -> B --> F N |- * | n -> N --> |- *- * If we had two red nephews, then after the swap,- * our former father would have a red grandson. - */- if (brother->rb_nodes[other] == NULL)- return;/* The tree may be broken. */- RB_MARK_BLACK(brother->rb_nodes[other]);- __archive_rb_tree_reparent_nodes(parent, other);- break; /* We're done! */- }- }-}--struct archive_rb_node *-__archive_rb_tree_iterate(struct archive_rb_tree *rbt,- struct archive_rb_node *self, const unsigned int direction)-{- const unsigned int other = direction ^ RB_DIR_OTHER;-- if (self == NULL) {- self = rbt->rbt_root;- if (RB_SENTINEL_P(self))- return NULL;- while (!RB_SENTINEL_P(self->rb_nodes[direction]))- self = self->rb_nodes[direction];- return self;- }- /*- * We can't go any further in this direction. We proceed up in the- * opposite direction until our parent is in direction we want to go.- */- if (RB_SENTINEL_P(self->rb_nodes[direction])) {- while (!RB_ROOT_P(rbt, self)) {- if (other == (unsigned int)RB_POSITION(self))- return RB_FATHER(self);- self = RB_FATHER(self);- }- return NULL;- }-- /*- * Advance down one in current direction and go down as far as possible- * in the opposite direction.- */- self = self->rb_nodes[direction];- while (!RB_SENTINEL_P(self->rb_nodes[other]))- self = self->rb_nodes[other];- return self;-}
− c/archive_rb.h
@@ -1,113 +0,0 @@-/*-- * Copyright (c) 2001 The NetBSD Foundation, Inc.- * All rights reserved.- *- * This code is derived from software contributed to The NetBSD Foundation- * by Matt Thomas <matt@3am-software.com>.- *- * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE- * POSSIBILITY OF SUCH DAMAGE.- *- * Based on NetBSD: rb.h,v 1.13 2009/08/16 10:57:01 yamt Exp- */--#ifndef ARCHIVE_RB_H_INCLUDED-#define ARCHIVE_RB_H_INCLUDED--struct archive_rb_node {- struct archive_rb_node *rb_nodes[2];- /*- * rb_info contains the two flags and the parent back pointer.- * We put the two flags in the low two bits since we know that- * rb_node will have an alignment of 4 or 8 bytes.- */- uintptr_t rb_info;-};--#define ARCHIVE_RB_DIR_LEFT 0-#define ARCHIVE_RB_DIR_RIGHT 1--#define ARCHIVE_RB_TREE_MIN(T) \- __archive_rb_tree_iterate((T), NULL, ARCHIVE_RB_DIR_LEFT)-#define ARCHIVE_RB_TREE_MAX(T) \- __archive_rb_tree_iterate((T), NULL, ARCHIVE_RB_DIR_RIGHT)-#define ARCHIVE_RB_TREE_NEXT(T, N) \- __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_RIGHT)-#define ARCHIVE_RB_TREE_PREV(T, N) \- __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_LEFT)-#define ARCHIVE_RB_TREE_FOREACH(N, T) \- for ((N) = ARCHIVE_RB_TREE_MIN(T); (N); \- (N) = ARCHIVE_RB_TREE_NEXT((T), (N)))-#define ARCHIVE_RB_TREE_FOREACH_REVERSE(N, T) \- for ((N) = ARCHIVE_RB_TREE_MAX(T); (N); \- (N) = ARCHIVE_RB_TREE_PREV((T), (N)))-#define ARCHIVE_RB_TREE_FOREACH_SAFE(N, T, S) \- for ((N) = ARCHIVE_RB_TREE_MIN(T); \- (N) && ((S) = ARCHIVE_RB_TREE_NEXT((T), (N)), 1); \- (N) = (S))-#define ARCHIVE_RB_TREE_FOREACH_REVERSE_SAFE(N, T, S) \- for ((N) = ARCHIVE_RB_TREE_MAX(T); \- (N) && ((S) = ARCHIVE_RB_TREE_PREV((T), (N)), 1); \- (N) = (S))--/*- * archive_rbto_compare_nodes_fn:- * return a positive value if the first node < the second node.- * return a negative value if the first node > the second node.- * return 0 if they are considered same.- *- * archive_rbto_compare_key_fn:- * return a positive value if the node < the key.- * return a negative value if the node > the key.- * return 0 if they are considered same.- */--typedef signed int (*const archive_rbto_compare_nodes_fn)(const struct archive_rb_node *,- const struct archive_rb_node *);-typedef signed int (*const archive_rbto_compare_key_fn)(const struct archive_rb_node *,- const void *);--struct archive_rb_tree_ops {- archive_rbto_compare_nodes_fn rbto_compare_nodes;- archive_rbto_compare_key_fn rbto_compare_key;-};--struct archive_rb_tree {- struct archive_rb_node *rbt_root;- const struct archive_rb_tree_ops *rbt_ops;-};--void __archive_rb_tree_init(struct archive_rb_tree *,- const struct archive_rb_tree_ops *);-int __archive_rb_tree_insert_node(struct archive_rb_tree *,- struct archive_rb_node *);-struct archive_rb_node *- __archive_rb_tree_find_node(struct archive_rb_tree *, const void *);-struct archive_rb_node *- __archive_rb_tree_find_node_geq(struct archive_rb_tree *, const void *);-struct archive_rb_node *- __archive_rb_tree_find_node_leq(struct archive_rb_tree *, const void *);-void __archive_rb_tree_remove_node(struct archive_rb_tree *, struct archive_rb_node *);-struct archive_rb_node *- __archive_rb_tree_iterate(struct archive_rb_tree *,- struct archive_rb_node *, const unsigned int);--#endif /* ARCHIVE_RB_H_*/
− c/archive_read.c
@@ -1,1756 +0,0 @@-/*-- * Copyright (c) 2003-2011 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--/*- * This file contains the "essential" portions of the read API, that- * is, stuff that will probably always be used by any client that- * actually needs to read an archive. Optional pieces have been, as- * far as possible, separated out into separate files to avoid- * needlessly bloating statically-linked clients.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:23Z 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_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_private.h"--#define minimum(a, b) (a < b ? a : b)--static int choose_filters(struct archive_read *);-static int choose_format(struct archive_read *);-static int close_filters(struct archive_read *);-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_filter_count(struct archive *);-static int _archive_read_close(struct archive *);-static int _archive_read_data_block(struct archive *,- const void **, size_t *, int64_t *);-static int _archive_read_free(struct archive *);-static int _archive_read_next_header(struct archive *,- struct archive_entry **);-static int _archive_read_next_header2(struct archive *,- struct archive_entry *);-static int64_t advance_file_pointer(struct archive_read_filter *, int64_t);--static const struct archive_vtable-archive_read_vtable = {- .archive_filter_bytes = _archive_filter_bytes,- .archive_filter_code = _archive_filter_code,- .archive_filter_name = _archive_filter_name,- .archive_filter_count = _archive_filter_count,- .archive_read_data_block = _archive_read_data_block,- .archive_read_next_header = _archive_read_next_header,- .archive_read_next_header2 = _archive_read_next_header2,- .archive_free = _archive_read_free,- .archive_close = _archive_read_close,-};--/*- * Allocate, initialize and return a struct archive object.- */-struct archive *-archive_read_new(void)-{- struct archive_read *a;-- a = (struct archive_read *)calloc(1, sizeof(*a));- if (a == NULL)- return (NULL);- a->archive.magic = ARCHIVE_READ_MAGIC;-- a->archive.state = ARCHIVE_STATE_NEW;- a->entry = archive_entry_new2(&a->archive);- a->archive.vtable = &archive_read_vtable;-- a->passphrases.last = &a->passphrases.first;-- return (&a->archive);-}--/*- * Record the do-not-extract-to file. This belongs in archive_read_extract.c.- */-void-archive_read_extract_set_skip_file(struct archive *_a, la_int64_t d,- la_int64_t i)-{- struct archive_read *a = (struct archive_read *)_a;-- if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_extract_set_skip_file"))- return;- a->skip_file_set = 1;- a->skip_file_dev = d;- a->skip_file_ino = i;-}--/*- * Open the archive- */-int-archive_read_open(struct archive *a, void *client_data,- archive_open_callback *client_opener, archive_read_callback *client_reader,- archive_close_callback *client_closer)-{- /* Old archive_read_open() is just a thin shell around- * archive_read_open1. */- archive_read_set_open_callback(a, client_opener);- archive_read_set_read_callback(a, client_reader);- archive_read_set_close_callback(a, client_closer);- archive_read_set_callback_data(a, client_data);- return archive_read_open1(a);-}---int-archive_read_open2(struct archive *a, void *client_data,- archive_open_callback *client_opener,- archive_read_callback *client_reader,- archive_skip_callback *client_skipper,- archive_close_callback *client_closer)-{- /* Old archive_read_open2() is just a thin shell around- * archive_read_open1. */- archive_read_set_callback_data(a, client_data);- archive_read_set_open_callback(a, client_opener);- archive_read_set_read_callback(a, client_reader);- archive_read_set_skip_callback(a, client_skipper);- archive_read_set_close_callback(a, client_closer);- return archive_read_open1(a);-}--static ssize_t-client_read_proxy(struct archive_read_filter *self, const void **buff)-{- ssize_t r;- r = (self->archive->client.reader)(&self->archive->archive,- self->data, buff);- return (r);-}--static int64_t-client_skip_proxy(struct archive_read_filter *self, int64_t request)-{- if (request < 0)- __archive_errx(1, "Negative skip requested.");- if (request == 0)- return 0;-- if (self->archive->client.skipper != NULL) {- /* Seek requests over 1GiB are broken down into- * multiple seeks. This avoids overflows when the- * requests get passed through 32-bit arguments. */- int64_t skip_limit = (int64_t)1 << 30;- int64_t total = 0;- for (;;) {- int64_t get, ask = request;- if (ask > skip_limit)- ask = skip_limit;- get = (self->archive->client.skipper)- (&self->archive->archive, self->data, ask);- total += get;- if (get == 0 || get == request)- return (total);- if (get > request)- return ARCHIVE_FATAL;- request -= get;- }- } else if (self->archive->client.seeker != NULL- && request > 64 * 1024) {- /* If the client provided a seeker but not a skipper,- * we can use the seeker to skip forward.- *- * Note: This isn't always a good idea. The client- * skipper is allowed to skip by less than requested- * if it needs to maintain block alignment. The- * seeker is not allowed to play such games, so using- * the seeker here may be a performance loss compared- * to just reading and discarding. That's why we- * only do this for skips of over 64k.- */- int64_t before = self->position;- int64_t after = (self->archive->client.seeker)- (&self->archive->archive, self->data, request, SEEK_CUR);- if (after != before + request)- return ARCHIVE_FATAL;- return after - before;- }- return 0;-}--static int64_t-client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)-{- /* DO NOT use the skipper here! If we transparently handled- * forward seek here by using the skipper, that will break- * other libarchive code that assumes a successful forward- * seek means it can also seek backwards.- */- if (self->archive->client.seeker == NULL) {- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "Current client reader does not support seeking a device");- return (ARCHIVE_FAILED);- }- return (self->archive->client.seeker)(&self->archive->archive,- self->data, offset, whence);-}--static int-read_client_close_proxy(struct archive_read *a)-{- int r = ARCHIVE_OK, r2;- unsigned int i;-- if (a->client.closer == NULL)- return (r);- for (i = 0; i < a->client.nodes; i++)- {- r2 = (a->client.closer)- ((struct archive *)a, a->client.dataset[i].data);- if (r > r2)- r = r2;- }- return (r);-}--static int-client_close_proxy(struct archive_read_filter *self)-{- return read_client_close_proxy(self->archive);-}--static int-client_open_proxy(struct archive_read_filter *self)-{- int r = ARCHIVE_OK;- if (self->archive->client.opener != NULL)- r = (self->archive->client.opener)(- (struct archive *)self->archive, self->data);- return (r);-}--static int-client_switch_proxy(struct archive_read_filter *self, unsigned int iindex)-{- int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK;- void *data2 = NULL;-- /* Don't do anything if already in the specified data node */- if (self->archive->client.cursor == iindex)- return (ARCHIVE_OK);-- self->archive->client.cursor = iindex;- data2 = self->archive->client.dataset[self->archive->client.cursor].data;- if (self->archive->client.switcher != NULL)- {- r1 = r2 = (self->archive->client.switcher)- ((struct archive *)self->archive, self->data, data2);- self->data = data2;- }- else- {- /* Attempt to call close and open instead */- if (self->archive->client.closer != NULL)- r1 = (self->archive->client.closer)- ((struct archive *)self->archive, self->data);- self->data = data2;- r2 = client_open_proxy(self);- }- return (r1 < r2) ? r1 : r2;-}--int-archive_read_set_open_callback(struct archive *_a,- archive_open_callback *client_opener)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_set_open_callback");- a->client.opener = client_opener;- return ARCHIVE_OK;-}--int-archive_read_set_read_callback(struct archive *_a,- archive_read_callback *client_reader)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_set_read_callback");- a->client.reader = client_reader;- return ARCHIVE_OK;-}--int-archive_read_set_skip_callback(struct archive *_a,- archive_skip_callback *client_skipper)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_set_skip_callback");- a->client.skipper = client_skipper;- return ARCHIVE_OK;-}--int-archive_read_set_seek_callback(struct archive *_a,- archive_seek_callback *client_seeker)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_set_seek_callback");- a->client.seeker = client_seeker;- return ARCHIVE_OK;-}--int-archive_read_set_close_callback(struct archive *_a,- archive_close_callback *client_closer)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_set_close_callback");- a->client.closer = client_closer;- return ARCHIVE_OK;-}--int-archive_read_set_switch_callback(struct archive *_a,- archive_switch_callback *client_switcher)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_set_switch_callback");- a->client.switcher = client_switcher;- return ARCHIVE_OK;-}--int-archive_read_set_callback_data(struct archive *_a, void *client_data)-{- return archive_read_set_callback_data2(_a, client_data, 0);-}--int-archive_read_set_callback_data2(struct archive *_a, void *client_data,- unsigned int iindex)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_set_callback_data2");-- if (a->client.nodes == 0)- {- a->client.dataset = (struct archive_read_data_node *)- calloc(1, sizeof(*a->client.dataset));- if (a->client.dataset == NULL)- {- archive_set_error(&a->archive, ENOMEM,- "No memory.");- return ARCHIVE_FATAL;- }- a->client.nodes = 1;- }-- if (iindex > a->client.nodes - 1)- {- archive_set_error(&a->archive, EINVAL,- "Invalid index specified.");- return ARCHIVE_FATAL;- }- a->client.dataset[iindex].data = client_data;- a->client.dataset[iindex].begin_position = -1;- a->client.dataset[iindex].total_size = -1;- return ARCHIVE_OK;-}--int-archive_read_add_callback_data(struct archive *_a, void *client_data,- unsigned int iindex)-{- struct archive_read *a = (struct archive_read *)_a;- void *p;- unsigned int i;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_add_callback_data");- if (iindex > a->client.nodes) {- archive_set_error(&a->archive, EINVAL,- "Invalid index specified.");- return ARCHIVE_FATAL;- }- p = realloc(a->client.dataset, sizeof(*a->client.dataset)- * (++(a->client.nodes)));- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory.");- return ARCHIVE_FATAL;- }- a->client.dataset = (struct archive_read_data_node *)p;- for (i = a->client.nodes - 1; i > iindex; i--) {- a->client.dataset[i].data = a->client.dataset[i-1].data;- a->client.dataset[i].begin_position = -1;- a->client.dataset[i].total_size = -1;- }- a->client.dataset[iindex].data = client_data;- a->client.dataset[iindex].begin_position = -1;- a->client.dataset[iindex].total_size = -1;- return ARCHIVE_OK;-}--int-archive_read_append_callback_data(struct archive *_a, void *client_data)-{- struct archive_read *a = (struct archive_read *)_a;- return archive_read_add_callback_data(_a, client_data, a->client.nodes);-}--int-archive_read_prepend_callback_data(struct archive *_a, void *client_data)-{- return archive_read_add_callback_data(_a, client_data, 0);-}--static const struct archive_read_filter_vtable-none_reader_vtable = {- .read = client_read_proxy,- .close = client_close_proxy,-};--int-archive_read_open1(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct archive_read_filter *filter, *tmp;- int slot, e = ARCHIVE_OK;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_open");- archive_clear_error(&a->archive);-- if (a->client.reader == NULL) {- archive_set_error(&a->archive, EINVAL,- "No reader function provided to archive_read_open");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }-- /* Open data source. */- if (a->client.opener != NULL) {- e = (a->client.opener)(&a->archive, a->client.dataset[0].data);- if (e != 0) {- /* If the open failed, call the closer to clean up. */- read_client_close_proxy(a);- return (e);- }- }-- filter = calloc(1, sizeof(*filter));- if (filter == NULL)- return (ARCHIVE_FATAL);- filter->bidder = NULL;- filter->upstream = NULL;- filter->archive = a;- filter->data = a->client.dataset[0].data;- filter->vtable = &none_reader_vtable;- filter->name = "none";- filter->code = ARCHIVE_FILTER_NONE;- filter->can_skip = 1;- filter->can_seek = 1;-- a->client.dataset[0].begin_position = 0;- if (!a->filter || !a->bypass_filter_bidding)- {- a->filter = filter;- /* Build out the input pipeline. */- e = choose_filters(a);- if (e < ARCHIVE_WARN) {- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- }- else- {- /* Need to add "NONE" type filter at the end of the filter chain */- tmp = a->filter;- while (tmp->upstream)- tmp = tmp->upstream;- tmp->upstream = filter;- }-- if (!a->format)- {- slot = choose_format(a);- if (slot < 0) {- close_filters(a);- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- a->format = &(a->formats[slot]);- }-- a->archive.state = ARCHIVE_STATE_HEADER;-- /* Ensure libarchive starts from the first node in a multivolume set */- client_switch_proxy(a->filter, 0);- return (e);-}--/*- * Allow each registered stream transform to bid on whether- * it wants to handle this stream. Repeat until we've finished- * building the pipeline.- */--/* We won't build a filter pipeline with more stages than this. */-#define MAX_NUMBER_FILTERS 25--static int-choose_filters(struct archive_read *a)-{- int number_bidders, i, bid, best_bid, number_filters;- struct archive_read_filter_bidder *bidder, *best_bidder;- struct archive_read_filter *filter;- ssize_t avail;- int r;-- for (number_filters = 0; number_filters < MAX_NUMBER_FILTERS; ++number_filters) {- number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);-- best_bid = 0;- best_bidder = NULL;-- bidder = a->bidders;- for (i = 0; i < number_bidders; i++, bidder++) {- if (bidder->vtable == NULL)- continue;- bid = (bidder->vtable->bid)(bidder, a->filter);- if (bid > best_bid) {- best_bid = bid;- best_bidder = bidder;- }- }-- /* If no bidder, we're done. */- if (best_bidder == NULL) {- /* Verify the filter by asking it for some data. */- __archive_read_filter_ahead(a->filter, 1, &avail);- if (avail < 0) {- __archive_read_free_filters(a);- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);- }-- filter- = (struct archive_read_filter *)calloc(1, sizeof(*filter));- if (filter == NULL)- return (ARCHIVE_FATAL);- filter->bidder = best_bidder;- filter->archive = a;- filter->upstream = a->filter;- a->filter = filter;- r = (best_bidder->vtable->init)(a->filter);- if (r != ARCHIVE_OK) {- __archive_read_free_filters(a);- return (ARCHIVE_FATAL);- }- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Input requires too many filters for decoding");- return (ARCHIVE_FATAL);-}--int-__archive_read_header(struct archive_read *a, struct archive_entry *entry)-{- if (!a->filter->vtable->read_header)- return (ARCHIVE_OK);- return a->filter->vtable->read_header(a->filter, entry);-}--/*- * Read header of next entry.- */-static int-_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)-{- struct archive_read *a = (struct archive_read *)_a;- int r1 = ARCHIVE_OK, r2;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_read_next_header");-- archive_entry_clear(entry);- archive_clear_error(&a->archive);-- /*- * If client didn't consume entire data, skip any remainder- * (This is especially important for GNU incremental directories.)- */- if (a->archive.state == ARCHIVE_STATE_DATA) {- r1 = archive_read_data_skip(&a->archive);- if (r1 == ARCHIVE_EOF)- archive_set_error(&a->archive, EIO,- "Premature end-of-file.");- if (r1 == ARCHIVE_EOF || r1 == ARCHIVE_FATAL) {- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- }-- /* Record start-of-header offset in uncompressed stream. */- a->header_position = a->filter->position;-- ++_a->file_count;- r2 = (a->format->read_header)(a, entry);-- /*- * EOF and FATAL are persistent at this layer. By- * modifying the state, we guarantee that future calls to- * read a header or read data will fail.- */- switch (r2) {- case ARCHIVE_EOF:- a->archive.state = ARCHIVE_STATE_EOF;- --_a->file_count;/* Revert a file counter. */- break;- case ARCHIVE_OK:- a->archive.state = ARCHIVE_STATE_DATA;- break;- case ARCHIVE_WARN:- a->archive.state = ARCHIVE_STATE_DATA;- break;- case ARCHIVE_RETRY:- break;- case ARCHIVE_FATAL:- a->archive.state = ARCHIVE_STATE_FATAL;- break;- }-- __archive_reset_read_data(&a->archive);-- a->data_start_node = a->client.cursor;- /* EOF always wins; otherwise return the worst error. */- return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1;-}--static int-_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)-{- int ret;- struct archive_read *a = (struct archive_read *)_a;- *entryp = NULL;- ret = _archive_read_next_header2(_a, a->entry);- *entryp = a->entry;- return ret;-}--/*- * Allow each registered format to bid on whether it wants to handle- * the next entry. Return index of winning bidder.- */-static int-choose_format(struct archive_read *a)-{- int slots;- int i;- int bid, best_bid;- int best_bid_slot;-- slots = sizeof(a->formats) / sizeof(a->formats[0]);- best_bid = -1;- best_bid_slot = -1;-- /* Set up a->format for convenience of bidders. */- a->format = &(a->formats[0]);- for (i = 0; i < slots; i++, a->format++) {- if (a->format->bid) {- bid = (a->format->bid)(a, best_bid);- if (bid == ARCHIVE_FATAL)- return (ARCHIVE_FATAL);- if (a->filter->position != 0)- __archive_read_seek(a, 0, SEEK_SET);- if ((bid > best_bid) || (best_bid_slot < 0)) {- best_bid = bid;- best_bid_slot = i;- }- }- }-- /*- * There were no bidders; this is a serious programmer error- * and demands a quick and definitive abort.- */- if (best_bid_slot < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "No formats registered");- return (ARCHIVE_FATAL);- }-- /*- * There were bidders, but no non-zero bids; this means we- * can't support this stream.- */- if (best_bid < 1) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unrecognized archive format");- return (ARCHIVE_FATAL);- }-- return (best_bid_slot);-}--/*- * Return the file offset (within the uncompressed data stream) where- * the last header started.- */-la_int64_t-archive_read_header_position(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_header_position");- return (a->header_position);-}--/*- * Returns 1 if the archive contains at least one encrypted entry.- * If the archive format not support encryption at all- * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned.- * If for any other reason (e.g. not enough data read so far)- * we cannot say whether there are encrypted entries, then- * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned.- * In general, this function will return values below zero when the- * reader is uncertain or totally incapable of encryption support.- * When this function returns 0 you can be sure that the reader- * supports encryption detection but no encrypted entries have- * been found yet.- *- * NOTE: If the metadata/header of an archive is also encrypted, you- * cannot rely on the number of encrypted entries. That is why this- * function does not return the number of encrypted entries but#- * just shows that there are some.- */-int-archive_read_has_encrypted_entries(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- int format_supports_encryption = archive_read_format_capabilities(_a)- & (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);-- if (!_a || !format_supports_encryption) {- /* Format in general doesn't support encryption */- return ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED;- }-- /* A reader potentially has read enough data now. */- if (a->format && a->format->has_encrypted_entries) {- return (a->format->has_encrypted_entries)(a);- }-- /* For any other reason we cannot say how many entries are there. */- return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;-}--/*- * Returns a bitmask of capabilities that are supported by the archive format reader.- * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned.- */-int-archive_read_format_capabilities(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- if (a && a->format && a->format->format_capabilties) {- return (a->format->format_capabilties)(a);- }- return ARCHIVE_READ_FORMAT_CAPS_NONE;-}--/*- * Read data from an archive entry, using a read(2)-style interface.- * This is a convenience routine that just calls- * archive_read_data_block and copies the results into the client- * buffer, filling any gaps with zero bytes. Clients using this- * API can be completely ignorant of sparse-file issues; sparse files- * will simply be padded with nulls.- *- * DO NOT intermingle calls to this function and archive_read_data_block- * to read a single entry body.- */-la_ssize_t-archive_read_data(struct archive *_a, void *buff, size_t s)-{- struct archive *a = (struct archive *)_a;- char *dest;- const void *read_buf;- size_t bytes_read;- size_t len;- int r;-- bytes_read = 0;- dest = (char *)buff;-- while (s > 0) {- if (a->read_data_offset == a->read_data_output_offset &&- a->read_data_remaining == 0) {- read_buf = a->read_data_block;- a->read_data_is_posix_read = 1;- a->read_data_requested = s;- r = archive_read_data_block(a, &read_buf,- &a->read_data_remaining, &a->read_data_offset);- a->read_data_block = read_buf;- if (r == ARCHIVE_EOF)- return (bytes_read);- /*- * Error codes are all negative, so the status- * return here cannot be confused with a valid- * byte count. (ARCHIVE_OK is zero.)- */- if (r < ARCHIVE_OK)- return (r);- }-- if (a->read_data_offset < a->read_data_output_offset) {- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,- "Encountered out-of-order sparse blocks");- return (ARCHIVE_RETRY);- }-- /* Compute the amount of zero padding needed. */- if (a->read_data_output_offset + (int64_t)s <- a->read_data_offset) {- len = s;- } else if (a->read_data_output_offset <- a->read_data_offset) {- len = (size_t)(a->read_data_offset -- a->read_data_output_offset);- } else- len = 0;-- /* Add zeroes. */- memset(dest, 0, len);- s -= len;- a->read_data_output_offset += len;- dest += len;- bytes_read += len;-- /* Copy data if there is any space left. */- if (s > 0) {- len = a->read_data_remaining;- if (len > s)- len = s;- if (len) {- memcpy(dest, a->read_data_block, len);- s -= len;- a->read_data_block += len;- a->read_data_remaining -= len;- a->read_data_output_offset += len;- a->read_data_offset += len;- dest += len;- bytes_read += len;- }- }- }- a->read_data_is_posix_read = 0;- a->read_data_requested = 0;- return (bytes_read);-}--/*- * Reset the read_data_* variables, used for starting a new entry.- */-void __archive_reset_read_data(struct archive * a)-{- a->read_data_output_offset = 0;- a->read_data_remaining = 0;- a->read_data_is_posix_read = 0;- a->read_data_requested = 0;-- /* extra resets, from rar.c */- a->read_data_block = NULL;- a->read_data_offset = 0;-}--/*- * Skip over all remaining data in this entry.- */-int-archive_read_data_skip(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- int r;- const void *buff;- size_t size;- int64_t offset;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_data_skip");-- if (a->format->read_data_skip != NULL)- r = (a->format->read_data_skip)(a);- else {- while ((r = archive_read_data_block(&a->archive,- &buff, &size, &offset))- == ARCHIVE_OK)- ;- }-- if (r == ARCHIVE_EOF)- r = ARCHIVE_OK;-- a->archive.state = ARCHIVE_STATE_HEADER;- return (r);-}--la_int64_t-archive_seek_data(struct archive *_a, int64_t offset, int whence)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,- "archive_seek_data_block");-- if (a->format->seek_data == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Internal error: "- "No format_seek_data_block function registered");- return (ARCHIVE_FATAL);- }-- return (a->format->seek_data)(a, offset, whence);-}--/*- * Read the next block of entry data from the archive.- * This is a zero-copy interface; the client receives a pointer,- * size, and file offset of the next available block of data.- *- * Returns ARCHIVE_OK if the operation is successful, ARCHIVE_EOF if- * the end of entry is encountered.- */-static int-_archive_read_data_block(struct archive *_a,- const void **buff, size_t *size, int64_t *offset)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_data_block");-- if (a->format->read_data == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Internal error: "- "No format->read_data function registered");- return (ARCHIVE_FATAL);- }-- 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->closed && f->vtable != NULL) {- int r1 = (f->vtable->close)(f);- f->closed = 1;- if (r1 < r)- r = r1;- }- free(f->buffer);- f->buffer = NULL;- f = t;- }- return r;-}--void-__archive_read_free_filters(struct archive_read *a)-{- /* Make sure filters are closed and their buffers are freed */- close_filters(a);-- while (a->filter != NULL) {- struct archive_read_filter *t = a->filter->upstream;- free(a->filter);- a->filter = t;- }-}--/*- * return the count of # of filters in use- */-static int-_archive_filter_count(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct archive_read_filter *p = a->filter;- int count = 0;- while(p) {- count++;- p = p->upstream;- }- return count;-}--/*- * 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;-- archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close");- if (a->archive.state == ARCHIVE_STATE_CLOSED)- return (ARCHIVE_OK);- archive_clear_error(&a->archive);- a->archive.state = ARCHIVE_STATE_CLOSED;-- /* TODO: Clean up the formatters. */-- /* Release the filter objects. */- r1 = close_filters(a);- if (r1 < r)- r = r1;-- return (r);-}--/*- * Release memory and other resources.- */-static int-_archive_read_free(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct archive_read_passphrase *p;- int i, n;- int slots;- int r = ARCHIVE_OK;-- if (_a == NULL)- return (ARCHIVE_OK);- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free");- if (a->archive.state != ARCHIVE_STATE_CLOSED- && a->archive.state != ARCHIVE_STATE_FATAL)- 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->format = &(a->formats[i]);- if (a->formats[i].cleanup)- (a->formats[i].cleanup)(a);- }-- /* Free the filters */- __archive_read_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].vtable == NULL ||- a->bidders[i].vtable->free == NULL)- continue;- (a->bidders[i].vtable->free)(&a->bidders[i]);- }-- /* Release passphrase list. */- p = a->passphrases.first;- while (p != NULL) {- struct archive_read_passphrase *np = p->next;-- /* A passphrase should be cleaned. */- memset(p->passphrase, 0, strlen(p->passphrase));- free(p->passphrase);- free(p);- p = np;- }-- archive_string_free(&a->archive.error_string);- archive_entry_free(a->entry);- a->archive.magic = 0;- __archive_clean(&a->archive);- free(a->client.dataset);- free(a);- 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;- /* We use n == -1 for 'the last filter', which is always the- * client proxy. */- if (n == -1 && f != NULL) {- struct archive_read_filter *last = f;- f = f->upstream;- while (f != NULL) {- last = f;- f = f->upstream;- }- return (last);- }- 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 ? f->name : NULL;-}--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->position;-}--/*- * Used internally by read format handlers to register their bid and- * initialization functions.- */-int-__archive_read_register_format(struct archive_read *a,- void *format_data,- const char *name,- int (*bid)(struct archive_read *, int),- int (*options)(struct archive_read *, const char *, const char *),- int (*read_header)(struct archive_read *, struct archive_entry *),- int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),- int (*read_data_skip)(struct archive_read *),- int64_t (*seek_data)(struct archive_read *, int64_t, int),- int (*cleanup)(struct archive_read *),- int (*format_capabilities)(struct archive_read *),- int (*has_encrypted_entries)(struct archive_read *))-{- int i, number_slots;-- archive_check_magic(&a->archive,- ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "__archive_read_register_format");-- number_slots = sizeof(a->formats) / sizeof(a->formats[0]);-- for (i = 0; i < number_slots; i++) {- if (a->formats[i].bid == bid)- return (ARCHIVE_WARN); /* We've already installed */- if (a->formats[i].bid == NULL) {- a->formats[i].bid = bid;- a->formats[i].options = options;- a->formats[i].read_header = read_header;- a->formats[i].read_data = read_data;- a->formats[i].read_data_skip = read_data_skip;- a->formats[i].seek_data = seek_data;- a->formats[i].cleanup = cleanup;- a->formats[i].data = format_data;- a->formats[i].name = name;- a->formats[i].format_capabilties = format_capabilities;- a->formats[i].has_encrypted_entries = has_encrypted_entries;- return (ARCHIVE_OK);- }- }-- archive_set_error(&a->archive, ENOMEM,- "Not enough slots for format registration");- return (ARCHIVE_FATAL);-}--/*- * Used internally by decompression routines to register their bid and- * initialization functions.- */-int-__archive_read_register_bidder(struct archive_read *a,- void *bidder_data,- const char *name,- const struct archive_read_filter_bidder_vtable *vtable)-{- struct archive_read_filter_bidder *bidder;- int i, number_slots;-- archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "__archive_read_register_bidder");-- number_slots = sizeof(a->bidders) / sizeof(a->bidders[0]);-- for (i = 0; i < number_slots; i++) {- if (a->bidders[i].vtable != NULL)- continue;- memset(a->bidders + i, 0, sizeof(a->bidders[0]));- bidder = (a->bidders + i);- bidder->data = bidder_data;- bidder->name = name;- bidder->vtable = vtable;- if (bidder->vtable->bid == NULL || bidder->vtable->init == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Internal error: "- "no bid/init for filter bidder");- return (ARCHIVE_FATAL);- }-- return (ARCHIVE_OK);- }-- archive_set_error(&a->archive, ENOMEM,- "Not enough slots for filter registration");- return (ARCHIVE_FATAL);-}--/*- * The next section implements the peek/consume internal I/O- * system used by archive readers. This system allows simple- * read-ahead for consumers while preserving zero-copy operation- * most of the time.- *- * The two key operations:- * * The read-ahead function returns a pointer to a block of data- * that satisfies a minimum request.- * * The consume function advances the file pointer.- *- * In the ideal case, filters generate blocks of data- * and __archive_read_ahead() just returns pointers directly into- * those blocks. Then __archive_read_consume() just bumps those- * pointers. Only if your request would span blocks does the I/O- * layer use a copy buffer to provide you with a contiguous block of- * data.- *- * A couple of useful idioms:- * * "I just want some data." Ask for 1 byte and pay attention to- * the "number of bytes available" from __archive_read_ahead().- * Consume whatever you actually use.- * * "I want to output a large block of data." As above, ask for 1 byte,- * emit all that's available (up to whatever limit you have), consume- * it all, then repeat until you're done. This effectively means that- * you're passing along the blocks that came from your provider.- * * "I want to peek ahead by a large amount." Ask for 4k or so, then- * double and repeat until you get an error or have enough. Note- * that the I/O layer will likely end up expanding its copy buffer- * to fit your request, so use this technique cautiously. This- * technique is used, for example, by some of the format tasting- * code that has uncertain look-ahead needs.- */--/*- * Looks ahead in the input stream:- * * If 'avail' pointer is provided, that returns number of bytes available- * in the current buffer, which may be much larger than requested.- * * If end-of-file, *avail gets set to zero.- * * If error, *avail gets error code.- * * If request can be met, returns pointer to data.- * * If minimum request cannot be met, returns NULL.- *- * Note: If you just want "some data", ask for 1 byte and pay attention- * to *avail, which will have the actual amount available. If you- * know exactly how many bytes you need, just ask for that and treat- * a NULL return as an error.- *- * Important: This does NOT move the file pointer. See- * __archive_read_consume() below.- */-const void *-__archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)-{- return (__archive_read_filter_ahead(a->filter, min, avail));-}--const void *-__archive_read_filter_ahead(struct archive_read_filter *filter,- size_t min, ssize_t *avail)-{- ssize_t bytes_read;- size_t tocopy;-- if (filter->fatal) {- if (avail)- *avail = ARCHIVE_FATAL;- return (NULL);- }-- /*- * Keep pulling more data until we can satisfy the request.- */- for (;;) {-- /*- * If we can satisfy from the copy buffer (and the- * copy buffer isn't empty), we're done. In particular,- * note that min == 0 is a perfectly well-defined- * request.- */- if (filter->avail >= min && filter->avail > 0) {- if (avail != NULL)- *avail = filter->avail;- return (filter->next);- }-- /*- * We can satisfy directly from client buffer if everything- * currently in the copy buffer is still in the client buffer.- */- if (filter->client_total >= filter->client_avail + filter->avail- && filter->client_avail + filter->avail >= min) {- /* "Roll back" to client buffer. */- filter->client_avail += filter->avail;- filter->client_next -= filter->avail;- /* Copy buffer is now empty. */- filter->avail = 0;- filter->next = filter->buffer;- /* Return data from client buffer. */- if (avail != NULL)- *avail = filter->client_avail;- return (filter->client_next);- }-- /* Move data forward in copy buffer if necessary. */- if (filter->next > filter->buffer &&- filter->next + min > filter->buffer + filter->buffer_size) {- if (filter->avail > 0)- memmove(filter->buffer, filter->next,- filter->avail);- filter->next = filter->buffer;- }-- /* If we've used up the client data, get more. */- if (filter->client_avail <= 0) {- if (filter->end_of_file) {- if (avail != NULL)- *avail = 0;- return (NULL);- }- bytes_read = (filter->vtable->read)(filter,- &filter->client_buff);- if (bytes_read < 0) { /* Read error. */- filter->client_total = filter->client_avail = 0;- filter->client_next =- filter->client_buff = NULL;- filter->fatal = 1;- if (avail != NULL)- *avail = ARCHIVE_FATAL;- return (NULL);- }- if (bytes_read == 0) {- /* Check for another client object first */- if (filter->archive->client.cursor !=- filter->archive->client.nodes - 1) {- if (client_switch_proxy(filter,- filter->archive->client.cursor + 1)- == ARCHIVE_OK)- continue;- }- /* Premature end-of-file. */- filter->client_total = filter->client_avail = 0;- filter->client_next =- filter->client_buff = NULL;- filter->end_of_file = 1;- /* Return whatever we do have. */- if (avail != NULL)- *avail = filter->avail;- return (NULL);- }- filter->client_total = bytes_read;- filter->client_avail = filter->client_total;- filter->client_next = filter->client_buff;- } else {- /*- * We can't satisfy the request from the copy- * buffer or the existing client data, so we- * need to copy more client data over to the- * copy buffer.- */-- /* Ensure the buffer is big enough. */- if (min > filter->buffer_size) {- size_t s, t;- char *p;-- /* Double the buffer; watch for overflow. */- s = t = filter->buffer_size;- if (s == 0)- s = min;- while (s < min) {- t *= 2;- if (t <= s) { /* Integer overflow! */- archive_set_error(- &filter->archive->archive,- ENOMEM,- "Unable to allocate copy"- " buffer");- filter->fatal = 1;- if (avail != NULL)- *avail = ARCHIVE_FATAL;- return (NULL);- }- s = t;- }- /* Now s >= min, so allocate a new buffer. */- p = (char *)malloc(s);- if (p == NULL) {- archive_set_error(- &filter->archive->archive,- ENOMEM,- "Unable to allocate copy buffer");- filter->fatal = 1;- if (avail != NULL)- *avail = ARCHIVE_FATAL;- return (NULL);- }- /* Move data into newly-enlarged buffer. */- if (filter->avail > 0)- memmove(p, filter->next, filter->avail);- free(filter->buffer);- filter->next = filter->buffer = p;- filter->buffer_size = s;- }-- /* We can add client data to copy buffer. */- /* First estimate: copy to fill rest of buffer. */- tocopy = (filter->buffer + filter->buffer_size)- - (filter->next + filter->avail);- /* Don't waste time buffering more than we need to. */- if (tocopy + filter->avail > min)- tocopy = min - filter->avail;- /* Don't copy more than is available. */- if (tocopy > filter->client_avail)- tocopy = filter->client_avail;-- memcpy(filter->next + filter->avail,- filter->client_next, tocopy);- /* Remove this data from client buffer. */- filter->client_next += tocopy;- filter->client_avail -= tocopy;- /* add it to copy buffer. */- filter->avail += tocopy;- }- }-}--/*- * Move the file pointer forward.- */-int64_t-__archive_read_consume(struct archive_read *a, int64_t request)-{- return (__archive_read_filter_consume(a->filter, request));-}--int64_t-__archive_read_filter_consume(struct archive_read_filter * filter,- int64_t request)-{- int64_t skipped;-- if (request < 0)- return ARCHIVE_FATAL;- if (request == 0)- return 0;-- skipped = advance_file_pointer(filter, request);- if (skipped == request)- return (skipped);- /* We hit EOF before we satisfied the skip request. */- if (skipped < 0) /* Map error code to 0 for error message below. */- skipped = 0;- archive_set_error(&filter->archive->archive,- ARCHIVE_ERRNO_MISC,- "Truncated input file (needed %jd bytes, only %jd available)",- (intmax_t)request, (intmax_t)skipped);- return (ARCHIVE_FATAL);-}--/*- * Advance the file pointer by the amount requested.- * Returns the amount actually advanced, which may be less than the- * request if EOF is encountered first.- * Returns a negative value if there's an I/O error.- */-static int64_t-advance_file_pointer(struct archive_read_filter *filter, int64_t request)-{- int64_t bytes_skipped, total_bytes_skipped = 0;- ssize_t bytes_read;- size_t min;-- if (filter->fatal)- return (-1);-- /* Use up the copy buffer first. */- if (filter->avail > 0) {- min = (size_t)minimum(request, (int64_t)filter->avail);- filter->next += min;- filter->avail -= min;- request -= min;- filter->position += min;- total_bytes_skipped += min;- }-- /* Then use up the client buffer. */- if (filter->client_avail > 0) {- min = (size_t)minimum(request, (int64_t)filter->client_avail);- filter->client_next += min;- filter->client_avail -= min;- request -= min;- filter->position += min;- total_bytes_skipped += min;- }- if (request == 0)- return (total_bytes_skipped);-- /* If there's an optimized skip function, use it. */- if (filter->can_skip != 0) {- bytes_skipped = client_skip_proxy(filter, request);- if (bytes_skipped < 0) { /* error */- filter->fatal = 1;- return (bytes_skipped);- }- filter->position += bytes_skipped;- total_bytes_skipped += bytes_skipped;- request -= bytes_skipped;- if (request == 0)- return (total_bytes_skipped);- }-- /* Use ordinary reads as necessary to complete the request. */- for (;;) {- bytes_read = (filter->vtable->read)(filter, &filter->client_buff);- if (bytes_read < 0) {- filter->client_buff = NULL;- filter->fatal = 1;- return (bytes_read);- }-- if (bytes_read == 0) {- if (filter->archive->client.cursor !=- filter->archive->client.nodes - 1) {- if (client_switch_proxy(filter,- filter->archive->client.cursor + 1)- == ARCHIVE_OK)- continue;- }- filter->client_buff = NULL;- filter->end_of_file = 1;- return (total_bytes_skipped);- }-- if (bytes_read >= request) {- filter->client_next =- ((const char *)filter->client_buff) + request;- filter->client_avail = (size_t)(bytes_read - request);- filter->client_total = bytes_read;- total_bytes_skipped += request;- filter->position += request;- return (total_bytes_skipped);- }-- filter->position += bytes_read;- total_bytes_skipped += bytes_read;- request -= bytes_read;- }-}--/**- * Returns ARCHIVE_FAILED if seeking isn't supported.- */-int64_t-__archive_read_seek(struct archive_read *a, int64_t offset, int whence)-{- return __archive_read_filter_seek(a->filter, offset, whence);-}--int64_t-__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,- int whence)-{- struct archive_read_client *client;- int64_t r;- unsigned int cursor;-- if (filter->closed || filter->fatal)- return (ARCHIVE_FATAL);- if (filter->can_seek == 0)- return (ARCHIVE_FAILED);-- client = &(filter->archive->client);- switch (whence) {- case SEEK_CUR:- /* Adjust the offset and use SEEK_SET instead */- offset += filter->position;- __LA_FALLTHROUGH;- case SEEK_SET:- cursor = 0;- while (1)- {- if (client->dataset[cursor].begin_position < 0 ||- client->dataset[cursor].total_size < 0 ||- client->dataset[cursor].begin_position +- client->dataset[cursor].total_size - 1 > offset ||- cursor + 1 >= client->nodes)- break;- r = client->dataset[cursor].begin_position +- client->dataset[cursor].total_size;- client->dataset[++cursor].begin_position = r;- }- while (1) {- r = client_switch_proxy(filter, cursor);- if (r != ARCHIVE_OK)- return r;- if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)- return r;- client->dataset[cursor].total_size = r;- if (client->dataset[cursor].begin_position +- client->dataset[cursor].total_size - 1 > offset ||- cursor + 1 >= client->nodes)- break;- r = client->dataset[cursor].begin_position +- client->dataset[cursor].total_size;- client->dataset[++cursor].begin_position = r;- }- offset -= client->dataset[cursor].begin_position;- if (offset < 0- || offset > client->dataset[cursor].total_size)- return ARCHIVE_FATAL;- if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0)- return r;- break;-- case SEEK_END:- cursor = 0;- while (1) {- if (client->dataset[cursor].begin_position < 0 ||- client->dataset[cursor].total_size < 0 ||- cursor + 1 >= client->nodes)- break;- r = client->dataset[cursor].begin_position +- client->dataset[cursor].total_size;- client->dataset[++cursor].begin_position = r;- }- while (1) {- r = client_switch_proxy(filter, cursor);- if (r != ARCHIVE_OK)- return r;- if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)- return r;- client->dataset[cursor].total_size = r;- r = client->dataset[cursor].begin_position +- client->dataset[cursor].total_size;- if (cursor + 1 >= client->nodes)- break;- client->dataset[++cursor].begin_position = r;- }- while (1) {- if (r + offset >=- client->dataset[cursor].begin_position)- break;- offset += client->dataset[cursor].total_size;- if (cursor == 0)- break;- cursor--;- r = client->dataset[cursor].begin_position +- client->dataset[cursor].total_size;- }- offset = (r + offset) - client->dataset[cursor].begin_position;- if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK)- return r;- r = client_seek_proxy(filter, offset, SEEK_SET);- if (r < ARCHIVE_OK)- return r;- break;-- default:- return (ARCHIVE_FATAL);- }- r += client->dataset[cursor].begin_position;-- if (r >= 0) {- /*- * Ouch. Clearing the buffer like this hurts, especially- * at bid time. A lot of our efficiency at bid time comes- * from having bidders reuse the data we've already read.- *- * TODO: If the seek request is in data we already- * have, then don't call the seek callback.- *- * TODO: Zip seeks to end-of-file at bid time. If- * other formats also start doing this, we may need to- * find a way for clients to fudge the seek offset to- * a block boundary.- *- * Hmmm... If whence was SEEK_END, we know the file- * size is (r - offset). Can we use that to simplify- * the TODO items above?- */- filter->avail = filter->client_avail = 0;- filter->next = filter->buffer;- filter->position = r;- filter->end_of_file = 0;- }- return r;-}
− c/archive_read_add_passphrase.c
@@ -1,190 +0,0 @@-/*-- * Copyright (c) 2014 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#include "archive_read_private.h"--static void-add_passphrase_to_tail(struct archive_read *a,- struct archive_read_passphrase *p)-{- *a->passphrases.last = p;- a->passphrases.last = &p->next;- p->next = NULL;-}--static struct archive_read_passphrase *-remove_passphrases_from_head(struct archive_read *a)-{- struct archive_read_passphrase *p;-- p = a->passphrases.first;- if (p != NULL)- a->passphrases.first = p->next;- return (p);-}--static void-insert_passphrase_to_head(struct archive_read *a,- struct archive_read_passphrase *p)-{- p->next = a->passphrases.first;- a->passphrases.first = p;- if (&a->passphrases.first == a->passphrases.last) {- a->passphrases.last = &p->next;- p->next = NULL;- }-}--static struct archive_read_passphrase *-new_read_passphrase(struct archive_read *a, const char *passphrase)-{- struct archive_read_passphrase *p;-- p = malloc(sizeof(*p));- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (NULL);- }- p->passphrase = strdup(passphrase);- if (p->passphrase == NULL) {- free(p);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (NULL);- }- return (p);-}--int-archive_read_add_passphrase(struct archive *_a, const char *passphrase)-{- struct archive_read *a = (struct archive_read *)_a;- struct archive_read_passphrase *p;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_add_passphrase");-- if (passphrase == NULL || passphrase[0] == '\0') {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Empty passphrase is unacceptable");- return (ARCHIVE_FAILED);- }-- p = new_read_passphrase(a, passphrase);- if (p == NULL)- return (ARCHIVE_FATAL);- add_passphrase_to_tail(a, p);-- return (ARCHIVE_OK);-}--int-archive_read_set_passphrase_callback(struct archive *_a, void *client_data,- archive_passphrase_callback *cb)-{- struct archive_read *a = (struct archive_read *)_a;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_set_passphrase_callback");-- a->passphrases.callback = cb;- a->passphrases.client_data = client_data;- return (ARCHIVE_OK);-}--/*- * Call this in advance when you start to get a passphrase for decryption- * for a entry.- */-void-__archive_read_reset_passphrase(struct archive_read *a)-{-- a->passphrases.candidate = -1;-}--/*- * Get a passphrase for decryption.- */-const char *-__archive_read_next_passphrase(struct archive_read *a)-{- struct archive_read_passphrase *p;- const char *passphrase;-- if (a->passphrases.candidate < 0) {- /* Count out how many passphrases we have. */- int cnt = 0;-- for (p = a->passphrases.first; p != NULL; p = p->next)- cnt++;- a->passphrases.candidate = cnt;- p = a->passphrases.first;- } else if (a->passphrases.candidate > 1) {- /* Rotate a passphrase list. */- a->passphrases.candidate--;- p = remove_passphrases_from_head(a);- add_passphrase_to_tail(a, p);- /* Pick a new passphrase candidate up. */- p = a->passphrases.first;- } else if (a->passphrases.candidate == 1) {- /* This case is that all candidates failed to decrypt. */- a->passphrases.candidate = 0;- if (a->passphrases.first->next != NULL) {- /* Rotate a passphrase list. */- p = remove_passphrases_from_head(a);- add_passphrase_to_tail(a, p);- }- p = NULL;- } else /* There is no passphrase candidate. */- p = NULL;-- if (p != NULL)- passphrase = p->passphrase;- else if (a->passphrases.callback != NULL) {- /* Get a passphrase through a call-back function- * since we tried all passphrases out or we don't- * have it. */- passphrase = a->passphrases.callback(&a->archive,- a->passphrases.client_data);- if (passphrase != NULL) {- p = new_read_passphrase(a, passphrase);- if (p == NULL)- return (NULL);- insert_passphrase_to_head(a, p);- a->passphrases.candidate = 1;- }- } else- passphrase = NULL;-- return (passphrase);-}
− c/archive_read_append_filter.c
@@ -1,204 +0,0 @@-/*-- * Copyright (c) 2003-2012 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_read_private.h"--int-archive_read_append_filter(struct archive *_a, int code)-{- int r1, r2, number_bidders, i;- char str[20];- struct archive_read_filter_bidder *bidder;- struct archive_read_filter *filter;- struct archive_read *a = (struct archive_read *)_a;-- r2 = (ARCHIVE_OK);- switch (code)- {- case ARCHIVE_FILTER_NONE:- /* No filter to add, so do nothing.- * NOTE: An initial "NONE" type filter is always set at the end of the- * filter chain.- */- r1 = (ARCHIVE_OK);- break;- case ARCHIVE_FILTER_GZIP:- strcpy(str, "gzip");- r1 = archive_read_support_filter_gzip(_a);- break;- case ARCHIVE_FILTER_BZIP2:- strcpy(str, "bzip2");- r1 = archive_read_support_filter_bzip2(_a);- break;- case ARCHIVE_FILTER_COMPRESS:- strcpy(str, "compress (.Z)");- r1 = archive_read_support_filter_compress(_a);- break;- case ARCHIVE_FILTER_PROGRAM:- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Cannot append program filter using archive_read_append_filter");- return (ARCHIVE_FATAL);- case ARCHIVE_FILTER_LZMA:- strcpy(str, "lzma");- r1 = archive_read_support_filter_lzma(_a);- break;- case ARCHIVE_FILTER_XZ:- strcpy(str, "xz");- r1 = archive_read_support_filter_xz(_a);- break;- case ARCHIVE_FILTER_UU:- strcpy(str, "uu");- r1 = archive_read_support_filter_uu(_a);- break;- case ARCHIVE_FILTER_RPM:- strcpy(str, "rpm");- r1 = archive_read_support_filter_rpm(_a);- break;- case ARCHIVE_FILTER_LZ4:- strcpy(str, "lz4");- r1 = archive_read_support_filter_lz4(_a);- break;- case ARCHIVE_FILTER_ZSTD:- strcpy(str, "zstd");- r1 = archive_read_support_filter_zstd(_a);- break;- case ARCHIVE_FILTER_LZIP:- strcpy(str, "lzip");- r1 = archive_read_support_filter_lzip(_a);- break;- case ARCHIVE_FILTER_LRZIP:- strcpy(str, "lrzip");- r1 = archive_read_support_filter_lrzip(_a);- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Invalid filter code specified");- return (ARCHIVE_FATAL);- }-- if (code != ARCHIVE_FILTER_NONE)- {- number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);-- bidder = a->bidders;- for (i = 0; i < number_bidders; i++, bidder++)- {- if (!bidder->name || !strcmp(bidder->name, str))- break;- }- if (!bidder->name || strcmp(bidder->name, str))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Internal error: Unable to append filter");- return (ARCHIVE_FATAL);- }-- filter- = (struct archive_read_filter *)calloc(1, sizeof(*filter));- if (filter == NULL)- {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- filter->bidder = bidder;- filter->archive = a;- filter->upstream = a->filter;- a->filter = filter;- r2 = (bidder->vtable->init)(a->filter);- if (r2 != ARCHIVE_OK) {- __archive_read_free_filters(a);- return (ARCHIVE_FATAL);- }- }-- a->bypass_filter_bidding = 1;- return (r1 < r2) ? r1 : r2;-}--int-archive_read_append_filter_program(struct archive *_a, const char *cmd)-{- return (archive_read_append_filter_program_signature(_a, cmd, NULL, 0));-}--int-archive_read_append_filter_program_signature(struct archive *_a,- const char *cmd, const void *signature, size_t signature_len)-{- int r, number_bidders, i;- struct archive_read_filter_bidder *bidder;- struct archive_read_filter *filter;- struct archive_read *a = (struct archive_read *)_a;-- if (archive_read_support_filter_program_signature(_a, cmd, signature,- signature_len) != (ARCHIVE_OK))- return (ARCHIVE_FATAL);-- number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);-- bidder = a->bidders;- for (i = 0; i < number_bidders; i++, bidder++)- {- /* Program bidder name set to filter name after initialization */- if (bidder->data && !bidder->name)- break;- }- if (!bidder->data)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Internal error: Unable to append program filter");- return (ARCHIVE_FATAL);- }-- filter- = (struct archive_read_filter *)calloc(1, sizeof(*filter));- if (filter == NULL)- {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- filter->bidder = bidder;- filter->archive = a;- filter->upstream = a->filter;- a->filter = filter;- r = (bidder->vtable->init)(a->filter);- if (r != ARCHIVE_OK) {- __archive_read_free_filters(a);- return (ARCHIVE_FATAL);- }- bidder->name = a->filter->name;-- a->bypass_filter_bidding = 1;- return r;-}
− c/archive_read_data_into_fd.c
@@ -1,144 +0,0 @@-/*-- * 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: src/lib/libarchive/archive_read_data_into_fd.c,v 1.16 2008/05/23 05:01:29 cperciva Exp $");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"-#include "archive_private.h"--/* Maximum amount of data to write at one time. */-#define MAX_WRITE (1024 * 1024)--/*- * This implementation minimizes copying of data and is sparse-file aware.- */-static int-pad_to(struct archive *a, int fd, int can_lseek,- size_t nulls_size, const char *nulls,- int64_t target_offset, int64_t actual_offset)-{- size_t to_write;- ssize_t bytes_written;-- if (can_lseek) {- actual_offset = lseek(fd,- target_offset - actual_offset, SEEK_CUR);- if (actual_offset != target_offset) {- archive_set_error(a, errno, "Seek error");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);- }- while (target_offset > actual_offset) {- to_write = nulls_size;- if (target_offset < actual_offset + (int64_t)nulls_size)- to_write = (size_t)(target_offset - actual_offset);- bytes_written = write(fd, nulls, to_write);- if (bytes_written < 0) {- archive_set_error(a, errno, "Write error");- return (ARCHIVE_FATAL);- }- actual_offset += bytes_written;- }- return (ARCHIVE_OK);-}---int-archive_read_data_into_fd(struct archive *a, int fd)-{- struct stat st;- int r, r2;- const void *buff;- size_t size, bytes_to_write;- ssize_t bytes_written;- int64_t target_offset;- int64_t actual_offset = 0;- int can_lseek;- char *nulls = NULL;- size_t nulls_size = 16384;-- archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_data_into_fd");-- can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode);- if (!can_lseek) {- nulls = calloc(1, nulls_size);- if (!nulls) {- r = ARCHIVE_FATAL;- goto cleanup;- }- }-- while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) ==- ARCHIVE_OK) {- const char *p = buff;- if (target_offset > actual_offset) {- r = pad_to(a, fd, can_lseek, nulls_size, nulls,- target_offset, actual_offset);- if (r != ARCHIVE_OK)- break;- actual_offset = target_offset;- }- while (size > 0) {- bytes_to_write = size;- if (bytes_to_write > MAX_WRITE)- bytes_to_write = MAX_WRITE;- bytes_written = write(fd, p, bytes_to_write);- if (bytes_written < 0) {- archive_set_error(a, errno, "Write error");- r = ARCHIVE_FATAL;- goto cleanup;- }- actual_offset += bytes_written;- p += bytes_written;- size -= bytes_written;- }- }-- if (r == ARCHIVE_EOF && target_offset > actual_offset) {- r2 = pad_to(a, fd, can_lseek, nulls_size, nulls,- target_offset, actual_offset);- if (r2 != ARCHIVE_OK)- r = r2;- }--cleanup:- free(nulls);- if (r != ARCHIVE_EOF)- return (r);- return (ARCHIVE_OK);-}
− c/archive_read_disk_entry_from_file.c
@@ -1,1086 +0,0 @@-/*-- * Copyright (c) 2003-2009 Tim Kientzle- * Copyright (c) 2010-2012 Michihiro NAKAJIMA- * Copyright (c) 2016 Martin Matuska- * 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");--/* This is the tree-walking code for POSIX systems. */-#if !defined(_WIN32) || defined(__CYGWIN__)--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_SYS_EXTATTR_H-#include <sys/extattr.h>-#endif-#ifdef HAVE_SYS_IOCTL_H-#include <sys/ioctl.h>-#endif-#ifdef HAVE_SYS_PARAM_H-#include <sys/param.h>-#endif-#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#if defined(HAVE_SYS_XATTR_H)-#include <sys/xattr.h>-#elif defined(HAVE_ATTR_XATTR_H)-#include <attr/xattr.h>-#endif-#ifdef HAVE_SYS_EA_H-#include <sys/ea.h>-#endif-#ifdef HAVE_COPYFILE_H-#include <copyfile.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_LINUX_TYPES_H-#include <linux/types.h>-#endif-#ifdef HAVE_LINUX_FIEMAP_H-#include <linux/fiemap.h>-#endif-#ifdef HAVE_LINUX_FS_H-#include <linux/fs.h>-#endif-/*- * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.- * As the include guards don't agree, the order of include is important.- */-#ifdef HAVE_LINUX_EXT2_FS_H-#include <linux/ext2_fs.h> /* for Linux file flags */-#endif-#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)-#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */-#endif-#ifdef HAVE_PATHS_H-#include <paths.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_disk_private.h"--#ifndef O_CLOEXEC-#define O_CLOEXEC 0-#endif--static int setup_mac_metadata(struct archive_read_disk *,- struct archive_entry *, int *fd);-#ifdef ARCHIVE_XATTR_FREEBSD-static int setup_xattrs_namespace(struct archive_read_disk *,- struct archive_entry *, int *, int);-#endif-static int setup_xattrs(struct archive_read_disk *,- struct archive_entry *, int *fd);-static int setup_sparse(struct archive_read_disk *,- struct archive_entry *, int *fd);-#if defined(HAVE_LINUX_FIEMAP_H)-static int setup_sparse_fiemap(struct archive_read_disk *,- struct archive_entry *, int *fd);-#endif--#if !ARCHIVE_ACL_SUPPORT-int-archive_read_disk_entry_setup_acls(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- (void)a; /* UNUSED */- (void)entry; /* UNUSED */- (void)fd; /* UNUSED */- return (ARCHIVE_OK);-}-#endif--/*- * Enter working directory and return working pathname of archive_entry.- * If a pointer to an integer is provided and its value is below zero- * open a file descriptor on this pathname.- */-const char *-archive_read_disk_entry_setup_path(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- const char *path;-- path = archive_entry_sourcepath(entry);-- if (path == NULL || (a->tree != NULL &&- a->tree_enter_working_dir(a->tree) != 0))- path = archive_entry_pathname(entry);- if (path == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Couldn't determine path");- } else if (fd != NULL && *fd < 0 && a->tree != NULL &&- (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)) {- *fd = a->open_on_current_dir(a->tree, path,- O_RDONLY | O_NONBLOCK);- }- return (path);-}--int-archive_read_disk_entry_from_file(struct archive *_a,- struct archive_entry *entry,- int fd,- const struct stat *st)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- const char *path, *name;- struct stat s;- int initial_fd = fd;- int r, r1;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY,- "archive_read_disk_entry_from_file");-- archive_clear_error(_a);- path = archive_entry_sourcepath(entry);- if (path == NULL)- path = archive_entry_pathname(entry);-- if (a->tree == NULL) {- if (st == NULL) {-#if HAVE_FSTAT- if (fd >= 0) {- if (fstat(fd, &s) != 0) {- archive_set_error(&a->archive, errno,- "Can't fstat");- return (ARCHIVE_FAILED);- }- } else-#endif-#if HAVE_LSTAT- if (!a->follow_symlinks) {- if (lstat(path, &s) != 0) {- archive_set_error(&a->archive, errno,- "Can't lstat %s", path);- return (ARCHIVE_FAILED);- }- } else-#endif- if (la_stat(path, &s) != 0) {- archive_set_error(&a->archive, errno,- "Can't stat %s", path);- return (ARCHIVE_FAILED);- }- st = &s;- }- archive_entry_copy_stat(entry, st);- }-- /* Lookup uname/gname */- name = archive_read_disk_uname(_a, archive_entry_uid(entry));- if (name != NULL)- archive_entry_copy_uname(entry, name);- name = archive_read_disk_gname(_a, archive_entry_gid(entry));- if (name != NULL)- archive_entry_copy_gname(entry, name);--#ifdef HAVE_STRUCT_STAT_ST_FLAGS- /* On FreeBSD, we get flags for free with the stat. */- /* TODO: Does this belong in copy_stat()? */- if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && st->st_flags != 0)- archive_entry_set_fflags(entry, st->st_flags, 0);-#endif--#if (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \- (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))- /* Linux requires an extra ioctl to pull the flags. Although- * this is an extra step, it has a nice side-effect: We get an- * open file descriptor which we can use in the subsequent lookups. */- if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 &&- (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {- if (fd < 0) {- if (a->tree != NULL)- fd = a->open_on_current_dir(a->tree, path,- O_RDONLY | O_NONBLOCK | O_CLOEXEC);- else- fd = open(path, O_RDONLY | O_NONBLOCK |- O_CLOEXEC);- __archive_ensure_cloexec_flag(fd);- }- if (fd >= 0) {- int stflags;- r = ioctl(fd,-#if defined(FS_IOC_GETFLAGS)- FS_IOC_GETFLAGS,-#else- EXT2_IOC_GETFLAGS,-#endif- &stflags);- if (r == 0 && stflags != 0)- archive_entry_set_fflags(entry, stflags, 0);- }- }-#endif--#if defined(HAVE_READLINK) || defined(HAVE_READLINKAT)- if (S_ISLNK(st->st_mode)) {- size_t linkbuffer_len = st->st_size;- char *linkbuffer;- int lnklen;-- linkbuffer = malloc(linkbuffer_len + 1);- if (linkbuffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Couldn't read link data");- return (ARCHIVE_FAILED);- }- if (a->tree != NULL) {-#ifdef HAVE_READLINKAT- lnklen = readlinkat(a->tree_current_dir_fd(a->tree),- path, linkbuffer, linkbuffer_len);-#else- if (a->tree_enter_working_dir(a->tree) != 0) {- archive_set_error(&a->archive, errno,- "Couldn't read link data");- free(linkbuffer);- return (ARCHIVE_FAILED);- }- lnklen = readlink(path, linkbuffer, linkbuffer_len);-#endif /* HAVE_READLINKAT */- } else- lnklen = readlink(path, linkbuffer, linkbuffer_len);- if (lnklen < 0) {- archive_set_error(&a->archive, errno,- "Couldn't read link data");- free(linkbuffer);- return (ARCHIVE_FAILED);- }- linkbuffer[lnklen] = '\0';- archive_entry_set_symlink(entry, linkbuffer);- free(linkbuffer);- }-#endif /* HAVE_READLINK || HAVE_READLINKAT */-- r = 0;- if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0)- r = archive_read_disk_entry_setup_acls(a, entry, &fd);- if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) {- r1 = setup_xattrs(a, entry, &fd);- if (r1 < r)- r = r1;- }- if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {- r1 = setup_mac_metadata(a, entry, &fd);- if (r1 < r)- r = r1;- }- if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) {- r1 = setup_sparse(a, entry, &fd);- if (r1 < r)- r = r1;- }-- /* If we opened the file earlier in this function, close it. */- if (initial_fd != fd)- close(fd);- return (r);-}--#if defined(__APPLE__) && defined(HAVE_COPYFILE_H)-/*- * The Mac OS "copyfile()" API copies the extended metadata for a- * file into a separate file in AppleDouble format (see RFC 1740).- *- * Mac OS tar and cpio implementations store this extended- * metadata as a separate entry just before the regular entry- * with a "._" prefix added to the filename.- *- * Note that this is currently done unconditionally; the tar program has- * an option to discard this information before the archive is written.- *- * TODO: If there's a failure, report it and return ARCHIVE_WARN.- */-static int-setup_mac_metadata(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- int tempfd = -1;- int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;- struct stat copyfile_stat;- int ret = ARCHIVE_OK;- void *buff = NULL;- int have_attrs;- const char *name, *tempdir;- struct archive_string tempfile;-- (void)fd; /* UNUSED */-- name = archive_read_disk_entry_setup_path(a, entry, NULL);- if (name == NULL)- return (ARCHIVE_WARN);-- /* Short-circuit if there's nothing to do. */- have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);- if (have_attrs == -1) {- archive_set_error(&a->archive, errno,- "Could not check extended attributes");- return (ARCHIVE_WARN);- }- if (have_attrs == 0)- return (ARCHIVE_OK);-- tempdir = NULL;- if (issetugid() == 0)- tempdir = getenv("TMPDIR");- if (tempdir == NULL)- tempdir = _PATH_TMP;- archive_string_init(&tempfile);- archive_strcpy(&tempfile, tempdir);- archive_strcat(&tempfile, "tar.md.XXXXXX");- tempfd = mkstemp(tempfile.s);- if (tempfd < 0) {- archive_set_error(&a->archive, errno,- "Could not open extended attribute file");- ret = ARCHIVE_WARN;- goto cleanup;- }- __archive_ensure_cloexec_flag(tempfd);-- /* XXX I wish copyfile() could pack directly to a memory- * buffer; that would avoid the temp file here. For that- * matter, it would be nice if fcopyfile() actually worked,- * that would reduce the many open/close races here. */- if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) {- archive_set_error(&a->archive, errno,- "Could not pack extended attributes");- ret = ARCHIVE_WARN;- goto cleanup;- }- if (fstat(tempfd, ©file_stat)) {- archive_set_error(&a->archive, errno,- "Could not check size of extended attributes");- ret = ARCHIVE_WARN;- goto cleanup;- }- buff = malloc(copyfile_stat.st_size);- if (buff == NULL) {- archive_set_error(&a->archive, errno,- "Could not allocate memory for extended attributes");- ret = ARCHIVE_WARN;- goto cleanup;- }- if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) {- archive_set_error(&a->archive, errno,- "Could not read extended attributes into memory");- ret = ARCHIVE_WARN;- goto cleanup;- }- archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);--cleanup:- if (tempfd >= 0) {- close(tempfd);- unlink(tempfile.s);- }- archive_string_free(&tempfile);- free(buff);- return (ret);-}--#else--/*- * Stub implementation for non-Mac systems.- */-static int-setup_mac_metadata(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- (void)a; /* UNUSED */- (void)entry; /* UNUSED */- (void)fd; /* UNUSED */- return (ARCHIVE_OK);-}-#endif--#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX--/*- * Linux, Darwin and AIX extended attribute support.- *- * TODO: By using a stack-allocated buffer for the first- * call to getxattr(), we might be able to avoid the second- * call entirely. We only need the second call if the- * stack-allocated buffer is too small. But a modest buffer- * of 1024 bytes or so will often be big enough. Same applies- * to listxattr().- */---static int-setup_xattr(struct archive_read_disk *a,- struct archive_entry *entry, const char *name, int fd, const char *accpath)-{- ssize_t size;- void *value = NULL;--- if (fd >= 0) {-#if ARCHIVE_XATTR_LINUX- size = fgetxattr(fd, name, NULL, 0);-#elif ARCHIVE_XATTR_DARWIN- size = fgetxattr(fd, name, NULL, 0, 0, 0);-#elif ARCHIVE_XATTR_AIX- size = fgetea(fd, name, NULL, 0);-#endif- } else if (!a->follow_symlinks) {-#if ARCHIVE_XATTR_LINUX- size = lgetxattr(accpath, name, NULL, 0);-#elif ARCHIVE_XATTR_DARWIN- size = getxattr(accpath, name, NULL, 0, 0, XATTR_NOFOLLOW);-#elif ARCHIVE_XATTR_AIX- size = lgetea(accpath, name, NULL, 0);-#endif- } else {-#if ARCHIVE_XATTR_LINUX- size = getxattr(accpath, name, NULL, 0);-#elif ARCHIVE_XATTR_DARWIN- size = getxattr(accpath, name, NULL, 0, 0, 0);-#elif ARCHIVE_XATTR_AIX- size = getea(accpath, name, NULL, 0);-#endif- }-- if (size == -1) {- archive_set_error(&a->archive, errno,- "Couldn't query extended attribute");- return (ARCHIVE_WARN);- }-- if (size > 0 && (value = malloc(size)) == NULL) {- archive_set_error(&a->archive, errno, "Out of memory");- return (ARCHIVE_FATAL);- }--- if (fd >= 0) {-#if ARCHIVE_XATTR_LINUX- size = fgetxattr(fd, name, value, size);-#elif ARCHIVE_XATTR_DARWIN- size = fgetxattr(fd, name, value, size, 0, 0);-#elif ARCHIVE_XATTR_AIX- size = fgetea(fd, name, value, size);-#endif- } else if (!a->follow_symlinks) {-#if ARCHIVE_XATTR_LINUX- size = lgetxattr(accpath, name, value, size);-#elif ARCHIVE_XATTR_DARWIN- size = getxattr(accpath, name, value, size, 0, XATTR_NOFOLLOW);-#elif ARCHIVE_XATTR_AIX- size = lgetea(accpath, name, value, size);-#endif- } else {-#if ARCHIVE_XATTR_LINUX- size = getxattr(accpath, name, value, size);-#elif ARCHIVE_XATTR_DARWIN- size = getxattr(accpath, name, value, size, 0, 0);-#elif ARCHIVE_XATTR_AIX- size = getea(accpath, name, value, size);-#endif- }-- if (size == -1) {- archive_set_error(&a->archive, errno,- "Couldn't read extended attribute");- return (ARCHIVE_WARN);- }-- archive_entry_xattr_add_entry(entry, name, value, size);-- free(value);- return (ARCHIVE_OK);-}--static int-setup_xattrs(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- char *list, *p;- const char *path;- ssize_t list_size;-- path = NULL;-- if (*fd < 0) {- path = archive_read_disk_entry_setup_path(a, entry, fd);- if (path == NULL)- return (ARCHIVE_WARN);- }-- if (*fd >= 0) {-#if ARCHIVE_XATTR_LINUX- list_size = flistxattr(*fd, NULL, 0);-#elif ARCHIVE_XATTR_DARWIN- list_size = flistxattr(*fd, NULL, 0, 0);-#elif ARCHIVE_XATTR_AIX- list_size = flistea(*fd, NULL, 0);-#endif- } else if (!a->follow_symlinks) {-#if ARCHIVE_XATTR_LINUX- list_size = llistxattr(path, NULL, 0);-#elif ARCHIVE_XATTR_DARWIN- list_size = listxattr(path, NULL, 0, XATTR_NOFOLLOW);-#elif ARCHIVE_XATTR_AIX- list_size = llistea(path, NULL, 0);-#endif- } else {-#if ARCHIVE_XATTR_LINUX- list_size = listxattr(path, NULL, 0);-#elif ARCHIVE_XATTR_DARWIN- list_size = listxattr(path, NULL, 0, 0);-#elif ARCHIVE_XATTR_AIX- list_size = listea(path, NULL, 0);-#endif- }-- if (list_size == -1) {- if (errno == ENOTSUP || errno == ENOSYS)- return (ARCHIVE_OK);- archive_set_error(&a->archive, errno,- "Couldn't list extended attributes");- return (ARCHIVE_WARN);- }-- if (list_size == 0)- return (ARCHIVE_OK);-- if ((list = malloc(list_size)) == NULL) {- archive_set_error(&a->archive, errno, "Out of memory");- return (ARCHIVE_FATAL);- }-- if (*fd >= 0) {-#if ARCHIVE_XATTR_LINUX- list_size = flistxattr(*fd, list, list_size);-#elif ARCHIVE_XATTR_DARWIN- list_size = flistxattr(*fd, list, list_size, 0);-#elif ARCHIVE_XATTR_AIX- list_size = flistea(*fd, list, list_size);-#endif- } else if (!a->follow_symlinks) {-#if ARCHIVE_XATTR_LINUX- list_size = llistxattr(path, list, list_size);-#elif ARCHIVE_XATTR_DARWIN- list_size = listxattr(path, list, list_size, XATTR_NOFOLLOW);-#elif ARCHIVE_XATTR_AIX- list_size = llistea(path, list, list_size);-#endif- } else {-#if ARCHIVE_XATTR_LINUX- list_size = listxattr(path, list, list_size);-#elif ARCHIVE_XATTR_DARWIN- list_size = listxattr(path, list, list_size, 0);-#elif ARCHIVE_XATTR_AIX- list_size = listea(path, list, list_size);-#endif- }-- if (list_size == -1) {- archive_set_error(&a->archive, errno,- "Couldn't retrieve extended attributes");- free(list);- return (ARCHIVE_WARN);- }-- for (p = list; (p - list) < list_size; p += strlen(p) + 1) {-#if ARCHIVE_XATTR_LINUX- /* Linux: skip POSIX.1e ACL extended attributes */- if (strncmp(p, "system.", 7) == 0 &&- (strcmp(p + 7, "posix_acl_access") == 0 ||- strcmp(p + 7, "posix_acl_default") == 0))- continue;- if (strncmp(p, "trusted.SGI_", 12) == 0 &&- (strcmp(p + 12, "ACL_DEFAULT") == 0 ||- strcmp(p + 12, "ACL_FILE") == 0))- continue;-- /* Linux: xfsroot namespace is obsolete and unsupported */- if (strncmp(p, "xfsroot.", 8) == 0)- continue;-#endif- setup_xattr(a, entry, p, *fd, path);- }-- free(list);- return (ARCHIVE_OK);-}--#elif ARCHIVE_XATTR_FREEBSD--/*- * FreeBSD extattr interface.- */--/* TODO: Implement this. Follow the Linux model above, but- * with FreeBSD-specific system calls, of course. Be careful- * to not include the system extattrs that hold ACLs; we handle- * those separately.- */-static int-setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,- int namespace, const char *name, const char *fullname, int fd,- const char *path);--static int-setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,- int namespace, const char *name, const char *fullname, int fd,- const char *accpath)-{- ssize_t size;- void *value = NULL;-- if (fd >= 0)- size = extattr_get_fd(fd, namespace, name, NULL, 0);- else if (!a->follow_symlinks)- size = extattr_get_link(accpath, namespace, name, NULL, 0);- else- size = extattr_get_file(accpath, namespace, name, NULL, 0);-- if (size == -1) {- archive_set_error(&a->archive, errno,- "Couldn't query extended attribute");- return (ARCHIVE_WARN);- }-- if (size > 0 && (value = malloc(size)) == NULL) {- archive_set_error(&a->archive, errno, "Out of memory");- return (ARCHIVE_FATAL);- }-- if (fd >= 0)- size = extattr_get_fd(fd, namespace, name, value, size);- else if (!a->follow_symlinks)- size = extattr_get_link(accpath, namespace, name, value, size);- else- size = extattr_get_file(accpath, namespace, name, value, size);-- if (size == -1) {- free(value);- archive_set_error(&a->archive, errno,- "Couldn't read extended attribute");- return (ARCHIVE_WARN);- }-- archive_entry_xattr_add_entry(entry, fullname, value, size);-- free(value);- return (ARCHIVE_OK);-}--static int-setup_xattrs_namespace(struct archive_read_disk *a,- struct archive_entry *entry, int *fd, int namespace)-{- char buff[512];- char *list, *p;- ssize_t list_size;- const char *path;-- path = NULL;-- if (*fd < 0) {- path = archive_read_disk_entry_setup_path(a, entry, fd);- if (path == NULL)- return (ARCHIVE_WARN);- }-- if (*fd >= 0)- list_size = extattr_list_fd(*fd, namespace, NULL, 0);- else if (!a->follow_symlinks)- list_size = extattr_list_link(path, namespace, NULL, 0);- else- list_size = extattr_list_file(path, namespace, NULL, 0);-- if (list_size == -1 && errno == EOPNOTSUPP)- return (ARCHIVE_OK);- if (list_size == -1 && errno == EPERM)- return (ARCHIVE_OK);- if (list_size == -1) {- archive_set_error(&a->archive, errno,- "Couldn't list extended attributes");- return (ARCHIVE_WARN);- }-- if (list_size == 0)- return (ARCHIVE_OK);-- if ((list = malloc(list_size)) == NULL) {- archive_set_error(&a->archive, errno, "Out of memory");- return (ARCHIVE_FATAL);- }-- if (*fd >= 0)- list_size = extattr_list_fd(*fd, namespace, list, list_size);- else if (!a->follow_symlinks)- list_size = extattr_list_link(path, namespace, list, list_size);- else- list_size = extattr_list_file(path, namespace, list, list_size);-- if (list_size == -1) {- archive_set_error(&a->archive, errno,- "Couldn't retrieve extended attributes");- free(list);- return (ARCHIVE_WARN);- }-- p = list;- while ((p - list) < list_size) {- size_t len = 255 & (int)*p;- char *name;-- if (namespace == EXTATTR_NAMESPACE_SYSTEM) {- if (!strcmp(p + 1, "nfs4.acl") ||- !strcmp(p + 1, "posix1e.acl_access") ||- !strcmp(p + 1, "posix1e.acl_default")) {- p += 1 + len;- continue;- }- strcpy(buff, "system.");- } else {- strcpy(buff, "user.");- }- name = buff + strlen(buff);- memcpy(name, p + 1, len);- name[len] = '\0';- setup_xattr(a, entry, namespace, name, buff, *fd, path);- p += 1 + len;- }-- free(list);- return (ARCHIVE_OK);-}--static int-setup_xattrs(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- int namespaces[2];- int i, res;-- namespaces[0] = EXTATTR_NAMESPACE_USER;- namespaces[1] = EXTATTR_NAMESPACE_SYSTEM;-- for (i = 0; i < 2; i++) {- res = setup_xattrs_namespace(a, entry, fd,- namespaces[i]);- switch (res) {- case (ARCHIVE_OK):- case (ARCHIVE_WARN):- break;- default:- return (res);- }- }-- return (ARCHIVE_OK);-}--#else--/*- * Generic (stub) extended attribute support.- */-static int-setup_xattrs(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- (void)a; /* UNUSED */- (void)entry; /* UNUSED */- (void)fd; /* UNUSED */- return (ARCHIVE_OK);-}--#endif--#if defined(HAVE_LINUX_FIEMAP_H)--/*- * Linux FIEMAP sparse interface.- *- * The FIEMAP ioctl returns an "extent" for each physical allocation- * on disk. We need to process those to generate a more compact list- * of logical file blocks. We also need to be very careful to use- * FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes- * does not report allocations for newly-written data that hasn't- * been synced to disk.- *- * It's important to return a minimal sparse file list because we want- * to not trigger sparse file extensions if we don't have to, since- * not all readers support them.- */--static int-setup_sparse_fiemap(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- char buff[4096];- struct fiemap *fm;- struct fiemap_extent *fe;- int64_t size;- int count, do_fiemap, iters;- int exit_sts = ARCHIVE_OK;- const char *path;-- if (archive_entry_filetype(entry) != AE_IFREG- || archive_entry_size(entry) <= 0- || archive_entry_hardlink(entry) != NULL)- return (ARCHIVE_OK);-- if (*fd < 0) {- path = archive_read_disk_entry_setup_path(a, entry, NULL);- if (path == NULL)- return (ARCHIVE_FAILED);-- if (a->tree != NULL)- *fd = a->open_on_current_dir(a->tree, path,- O_RDONLY | O_NONBLOCK | O_CLOEXEC);- else- *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);- if (*fd < 0) {- archive_set_error(&a->archive, errno,- "Can't open `%s'", path);- return (ARCHIVE_FAILED);- }- __archive_ensure_cloexec_flag(*fd);- }-- /* Initialize buffer to avoid the error valgrind complains about. */- memset(buff, 0, sizeof(buff));- count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);- fm = (struct fiemap *)buff;- fm->fm_start = 0;- fm->fm_length = ~0ULL;;- fm->fm_flags = FIEMAP_FLAG_SYNC;- fm->fm_extent_count = count;- do_fiemap = 1;- size = archive_entry_size(entry);- for (iters = 0; ; ++iters) {- int i, r;-- r = ioctl(*fd, FS_IOC_FIEMAP, fm); - if (r < 0) {- /* When something error happens, it is better we- * should return ARCHIVE_OK because an earlier- * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */- goto exit_setup_sparse_fiemap;- }- if (fm->fm_mapped_extents == 0) {- if (iters == 0) {- /* Fully sparse file; insert a zero-length "data" entry */- archive_entry_sparse_add_entry(entry, 0, 0);- }- break;- }- fe = fm->fm_extents;- for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {- if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {- /* The fe_length of the last block does not- * adjust itself to its size files. */- int64_t length = fe->fe_length;- if (fe->fe_logical + length > (uint64_t)size)- length -= fe->fe_logical + length - size;- if (fe->fe_logical == 0 && length == size) {- /* This is not sparse. */- do_fiemap = 0;- break;- }- if (length > 0)- archive_entry_sparse_add_entry(entry,- fe->fe_logical, length);- }- if (fe->fe_flags & FIEMAP_EXTENT_LAST)- do_fiemap = 0;- }- if (do_fiemap) {- fe = fm->fm_extents + fm->fm_mapped_extents -1;- fm->fm_start = fe->fe_logical + fe->fe_length;- } else- break;- }-exit_setup_sparse_fiemap:- return (exit_sts);-}--#if !defined(SEEK_HOLE) || !defined(SEEK_DATA)-static int-setup_sparse(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- return setup_sparse_fiemap(a, entry, fd);-}-#endif-#endif /* defined(HAVE_LINUX_FIEMAP_H) */--#if defined(SEEK_HOLE) && defined(SEEK_DATA)--/*- * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris)- */--static int-setup_sparse(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- int64_t size;- off_t initial_off;- off_t off_s, off_e;- int exit_sts = ARCHIVE_OK;- int check_fully_sparse = 0;- const char *path;-- if (archive_entry_filetype(entry) != AE_IFREG- || archive_entry_size(entry) <= 0- || archive_entry_hardlink(entry) != NULL)- return (ARCHIVE_OK);-- /* Does filesystem support the reporting of hole ? */- if (*fd < 0)- path = archive_read_disk_entry_setup_path(a, entry, fd);- else- path = NULL;-- if (*fd >= 0) {-#ifdef _PC_MIN_HOLE_SIZE- if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)- return (ARCHIVE_OK);-#endif- initial_off = lseek(*fd, 0, SEEK_CUR);- if (initial_off != 0)- lseek(*fd, 0, SEEK_SET);- } else {- if (path == NULL)- return (ARCHIVE_FAILED);-#ifdef _PC_MIN_HOLE_SIZE- if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)- return (ARCHIVE_OK);-#endif- *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);- if (*fd < 0) {- archive_set_error(&a->archive, errno,- "Can't open `%s'", path);- return (ARCHIVE_FAILED);- }- __archive_ensure_cloexec_flag(*fd);- initial_off = 0;- }--#ifndef _PC_MIN_HOLE_SIZE- /* Check if the underlying filesystem supports seek hole */- off_s = lseek(*fd, 0, SEEK_HOLE);- if (off_s < 0)-#if defined(HAVE_LINUX_FIEMAP_H)- return setup_sparse_fiemap(a, entry, fd);-#else- goto exit_setup_sparse;-#endif- else if (off_s > 0)- lseek(*fd, 0, SEEK_SET);-#endif-- off_s = 0;- size = archive_entry_size(entry);- while (off_s < size) {- off_s = lseek(*fd, off_s, SEEK_DATA);- if (off_s == (off_t)-1) {- if (errno == ENXIO) {- /* no more hole */- if (archive_entry_sparse_count(entry) == 0) {- /* Potentially a fully-sparse file. */- check_fully_sparse = 1;- }- break;- }- archive_set_error(&a->archive, errno,- "lseek(SEEK_HOLE) failed");- exit_sts = ARCHIVE_FAILED;- goto exit_setup_sparse;- }- off_e = lseek(*fd, off_s, SEEK_HOLE);- if (off_e == (off_t)-1) {- if (errno == ENXIO) {- off_e = lseek(*fd, 0, SEEK_END);- if (off_e != (off_t)-1)- break;/* no more data */- }- archive_set_error(&a->archive, errno,- "lseek(SEEK_DATA) failed");- exit_sts = ARCHIVE_FAILED;- goto exit_setup_sparse;- }- if (off_s == 0 && off_e == size)- break;/* This is not sparse. */- archive_entry_sparse_add_entry(entry, off_s,- off_e - off_s);- off_s = off_e;- }-- if (check_fully_sparse) {- if (lseek(*fd, 0, SEEK_HOLE) == 0 &&- lseek(*fd, 0, SEEK_END) == size) {- /* Fully sparse file; insert a zero-length "data" entry */- archive_entry_sparse_add_entry(entry, 0, 0);- }- }-exit_setup_sparse:- lseek(*fd, initial_off, SEEK_SET);- return (exit_sts);-}--#elif !defined(HAVE_LINUX_FIEMAP_H)--/*- * Generic (stub) sparse support.- */-static int-setup_sparse(struct archive_read_disk *a,- struct archive_entry *entry, int *fd)-{- (void)a; /* UNUSED */- (void)entry; /* UNUSED */- (void)fd; /* UNUSED */- return (ARCHIVE_OK);-}--#endif--#endif /* !defined(_WIN32) || defined(__CYGWIN__) */-
− c/archive_read_disk_posix.c
@@ -1,2760 +0,0 @@-/*-- * Copyright (c) 2003-2009 Tim Kientzle- * Copyright (c) 2010-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--/* This is the tree-walking code for POSIX systems. */-#if !defined(_WIN32) || defined(__CYGWIN__)--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_SYS_PARAM_H-#include <sys/param.h>-#endif-#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_SYS_STATFS_H-#include <sys/statfs.h>-#endif-#ifdef HAVE_SYS_STATVFS_H-#include <sys/statvfs.h>-#endif-#ifdef HAVE_SYS_TIME_H-#include <sys/time.h>-#endif-#ifdef HAVE_LINUX_MAGIC_H-#include <linux/magic.h>-#endif-#ifdef HAVE_LINUX_FS_H-#include <linux/fs.h>-#elif HAVE_SYS_MOUNT_H-#include <sys/mount.h>-#endif-/*- * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.- * As the include guards don't agree, the order of include is important.- */-#ifdef HAVE_LINUX_EXT2_FS_H-#include <linux/ext2_fs.h> /* for Linux file flags */-#endif-#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)-#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */-#endif-#ifdef HAVE_DIRECT_H-#include <direct.h>-#endif-#ifdef HAVE_DIRENT_H-#include <dirent.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif-#ifdef HAVE_SYS_IOCTL_H-#include <sys/ioctl.h>-#endif--#include "archive.h"-#include "archive_string.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_disk_private.h"--#ifndef HAVE_FCHDIR-#error fchdir function required.-#endif-#ifndef O_BINARY-#define O_BINARY 0-#endif-#ifndef O_CLOEXEC-#define O_CLOEXEC 0-#endif--#if defined(__hpux) && !defined(HAVE_DIRFD)-#define dirfd(x) ((x)->__dd_fd)-#define HAVE_DIRFD-#endif--/*-- * This is a new directory-walking system that addresses a number- * of problems I've had with fts(3). In particular, it has no- * pathname-length limits (other than the size of 'int'), handles- * deep logical traversals, uses considerably less memory, and has- * an opaque interface (easier to modify in the future).- *- * Internally, it keeps a single list of "tree_entry" items that- * represent filesystem objects that require further attention.- * Non-directories are not kept in memory: they are pulled from- * readdir(), returned to the client, then freed as soon as possible.- * Any directory entry to be traversed gets pushed onto the stack.- *- * There is surprisingly little information that needs to be kept for- * each item on the stack. Just the name, depth (represented here as the- * string length of the parent directory's pathname), and some markers- * indicating how to get back to the parent (via chdir("..") for a- * regular dir or via fchdir(2) for a symlink).- */-/*- * TODO:- * 1) Loop checking.- * 3) Arbitrary logical traversals by closing/reopening intermediate fds.- */--struct restore_time {- const char *name;- time_t mtime;- long mtime_nsec;- time_t atime;- long atime_nsec;- mode_t filetype;- int noatime;-};--struct tree_entry {- int depth;- struct tree_entry *next;- struct tree_entry *parent;- struct archive_string name;- size_t dirname_length;- int64_t dev;- int64_t ino;- int flags;- int filesystem_id;- /* How to return back to the parent of a symlink. */- int symlink_parent_fd;- /* How to restore time of a directory. */- struct restore_time restore_time;-};--struct filesystem {- int64_t dev;- int synthetic;- int remote;- int noatime;-#if defined(USE_READDIR_R)- size_t name_max;-#endif- long incr_xfer_size;- long max_xfer_size;- long min_xfer_size;- long xfer_align;-- /*- * Buffer used for reading file contents.- */- /* Exactly allocated memory pointer. */- unsigned char *allocation_ptr;- /* Pointer adjusted to the filesystem alignment . */- unsigned char *buff;- size_t buff_size;-};--/* Definitions for tree_entry.flags bitmap. */-#define isDir 1 /* This entry is a regular directory. */-#define isDirLink 2 /* This entry is a symbolic link to a directory. */-#define needsFirstVisit 4 /* This is an initial entry. */-#define needsDescent 8 /* This entry needs to be previsited. */-#define needsOpen 16 /* This is a directory that needs to be opened. */-#define needsAscent 32 /* This entry needs to be postvisited. */--/*- * Local data for this package.- */-struct tree {- struct tree_entry *stack;- struct tree_entry *current;- DIR *d;-#define INVALID_DIR_HANDLE NULL- struct dirent *de;-#if defined(USE_READDIR_R)- struct dirent *dirent;- size_t dirent_allocated;-#endif- int flags;- int visit_type;- /* Error code from last failed operation. */- int tree_errno;-- /* Dynamically-sized buffer for holding path */- struct archive_string path;-- /* Last path element */- const char *basename;- /* Leading dir length */- size_t dirname_length;-- int depth;- int openCount;- int maxOpenCount;- int initial_dir_fd;- int working_dir_fd;-- struct stat lst;- struct stat st;- int descend;- int nlink;- /* How to restore time of a file. */- struct restore_time restore_time;-- struct entry_sparse {- int64_t length;- int64_t offset;- } *sparse_list, *current_sparse;- int sparse_count;- int sparse_list_size;-- char initial_symlink_mode;- char symlink_mode;- struct filesystem *current_filesystem;- struct filesystem *filesystem_table;- int initial_filesystem_id;- int current_filesystem_id;- int max_filesystem_id;- int allocated_filesystem;-- int entry_fd;- int entry_eof;- int64_t entry_remaining_bytes;- int64_t entry_total;- unsigned char *entry_buff;- size_t entry_buff_size;-};--/* Definitions for tree.flags bitmap. */-#define hasStat 16 /* The st entry is valid. */-#define hasLstat 32 /* The lst entry is valid. */-#define onWorkingDir 64 /* We are on the working dir where we are- * reading directory entry at this time. */-#define needsRestoreTimes 128-#define onInitialDir 256 /* We are on the initial dir. */--static int-tree_dir_next_posix(struct tree *t);--#ifdef HAVE_DIRENT_D_NAMLEN-/* BSD extension; avoids need for a strlen() call. */-#define D_NAMELEN(dp) (dp)->d_namlen-#else-#define D_NAMELEN(dp) (strlen((dp)->d_name))-#endif--/* Initiate/terminate a tree traversal. */-static struct tree *tree_open(const char *, int, int);-static struct tree *tree_reopen(struct tree *, const char *, int);-static void tree_close(struct tree *);-static void tree_free(struct tree *);-static void tree_push(struct tree *, const char *, int, int64_t, int64_t,- struct restore_time *);-static int tree_enter_initial_dir(struct tree *);-static int tree_enter_working_dir(struct tree *);-static int tree_current_dir_fd(struct tree *);--/*- * tree_next() returns Zero if there is no next entry, non-zero if- * there is. Note that directories are visited three times.- * Directories are always visited first as part of enumerating their- * parent; that is a "regular" visit. If tree_descend() is invoked at- * that time, the directory is added to a work list and will- * subsequently be visited two more times: once just after descending- * into the directory ("postdescent") and again just after ascending- * back to the parent ("postascent").- *- * TREE_ERROR_DIR is returned if the descent failed (because the- * directory couldn't be opened, for instance). This is returned- * instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a- * fatal error, but it does imply that the relevant subtree won't be- * visited. TREE_ERROR_FATAL is returned for an error that left the- * traversal completely hosed. Right now, this is only returned for- * chdir() failures during ascent.- */-#define TREE_REGULAR 1-#define TREE_POSTDESCENT 2-#define TREE_POSTASCENT 3-#define TREE_ERROR_DIR -1-#define TREE_ERROR_FATAL -2--static int tree_next(struct tree *);--/*- * Return information about the current entry.- */--/*- * The current full pathname, length of the full pathname, and a name- * that can be used to access the file. Because tree does use chdir- * extensively, the access path is almost never the same as the full- * current path.- *- * TODO: On platforms that support it, use openat()-style operations- * to eliminate the chdir() operations entirely while still supporting- * arbitrarily deep traversals. This makes access_path troublesome to- * support, of course, which means we'll need a rich enough interface- * that clients can function without it. (In particular, we'll need- * tree_current_open() that returns an open file descriptor.)- *- */-static const char *tree_current_path(struct tree *);-static const char *tree_current_access_path(struct tree *);--/*- * Request the lstat() or stat() data for the current path. Since the- * tree package needs to do some of this anyway, and caches the- * results, you should take advantage of it here if you need it rather- * than make a redundant stat() or lstat() call of your own.- */-static const struct stat *tree_current_stat(struct tree *);-static const struct stat *tree_current_lstat(struct tree *);-static int tree_current_is_symblic_link_target(struct tree *);--/* The following functions use tricks to avoid a certain number of- * stat()/lstat() calls. */-/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */-static int tree_current_is_physical_dir(struct tree *);-/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */-static int tree_current_is_dir(struct tree *);-static int update_current_filesystem(struct archive_read_disk *a,- int64_t dev);-static int setup_current_filesystem(struct archive_read_disk *);-static int tree_target_is_same_as_parent(struct tree *, const struct stat *);--static int _archive_read_disk_open(struct archive *, const char *);-static int _archive_read_free(struct archive *);-static int _archive_read_close(struct archive *);-static int _archive_read_data_block(struct archive *,- const void **, size_t *, int64_t *);-static int _archive_read_next_header(struct archive *,- struct archive_entry **);-static int _archive_read_next_header2(struct archive *,- struct archive_entry *);-static const char *trivial_lookup_gname(void *, int64_t gid);-static const char *trivial_lookup_uname(void *, int64_t uid);-static int setup_sparse(struct archive_read_disk *, struct archive_entry *);-static int close_and_restore_time(int fd, struct tree *,- struct restore_time *);-static int open_on_current_dir(struct tree *, const char *, int);-static int tree_dup(int);---static const struct archive_vtable-archive_read_disk_vtable = {- .archive_free = _archive_read_free,- .archive_close = _archive_read_close,- .archive_read_data_block = _archive_read_data_block,- .archive_read_next_header = _archive_read_next_header,- .archive_read_next_header2 = _archive_read_next_header2,-};--const char *-archive_read_disk_gname(struct archive *_a, la_int64_t gid)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_gname"))- return (NULL);- if (a->lookup_gname == NULL)- return (NULL);- return ((*a->lookup_gname)(a->lookup_gname_data, gid));-}--const char *-archive_read_disk_uname(struct archive *_a, la_int64_t uid)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_uname"))- return (NULL);- if (a->lookup_uname == NULL)- return (NULL);- return ((*a->lookup_uname)(a->lookup_uname_data, uid));-}--int-archive_read_disk_set_gname_lookup(struct archive *_a,- void *private_data,- const char * (*lookup_gname)(void *private, la_int64_t gid),- void (*cleanup_gname)(void *private))-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup");-- if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)- (a->cleanup_gname)(a->lookup_gname_data);-- a->lookup_gname = lookup_gname;- a->cleanup_gname = cleanup_gname;- a->lookup_gname_data = private_data;- return (ARCHIVE_OK);-}--int-archive_read_disk_set_uname_lookup(struct archive *_a,- void *private_data,- const char * (*lookup_uname)(void *private, la_int64_t uid),- void (*cleanup_uname)(void *private))-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup");-- if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)- (a->cleanup_uname)(a->lookup_uname_data);-- a->lookup_uname = lookup_uname;- a->cleanup_uname = cleanup_uname;- a->lookup_uname_data = private_data;- return (ARCHIVE_OK);-}--/*- * Create a new archive_read_disk object and initialize it with global state.- */-struct archive *-archive_read_disk_new(void)-{- struct archive_read_disk *a;-- a = (struct archive_read_disk *)calloc(1, sizeof(*a));- if (a == NULL)- return (NULL);- a->archive.magic = ARCHIVE_READ_DISK_MAGIC;- a->archive.state = ARCHIVE_STATE_NEW;- a->archive.vtable = &archive_read_disk_vtable;- a->entry = archive_entry_new2(&a->archive);- a->lookup_uname = trivial_lookup_uname;- a->lookup_gname = trivial_lookup_gname;- a->flags = ARCHIVE_READDISK_MAC_COPYFILE;- a->open_on_current_dir = open_on_current_dir;- a->tree_current_dir_fd = tree_current_dir_fd;- a->tree_enter_working_dir = tree_enter_working_dir;- return (&a->archive);-}--static int-_archive_read_free(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- int r;-- if (_a == NULL)- return (ARCHIVE_OK);- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free");-- if (a->archive.state != ARCHIVE_STATE_CLOSED)- r = _archive_read_close(&a->archive);- else- r = ARCHIVE_OK;-- tree_free(a->tree);- if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)- (a->cleanup_gname)(a->lookup_gname_data);- if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)- (a->cleanup_uname)(a->lookup_uname_data);- archive_string_free(&a->archive.error_string);- archive_entry_free(a->entry);- a->archive.magic = 0;- __archive_clean(&a->archive);- free(a);- return (r);-}--static int-_archive_read_close(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close");-- if (a->archive.state != ARCHIVE_STATE_FATAL)- a->archive.state = ARCHIVE_STATE_CLOSED;-- tree_close(a->tree);-- return (ARCHIVE_OK);-}--static void-setup_symlink_mode(struct archive_read_disk *a, char symlink_mode,- int follow_symlinks)-{- a->symlink_mode = symlink_mode;- a->follow_symlinks = follow_symlinks;- if (a->tree != NULL) {- a->tree->initial_symlink_mode = a->symlink_mode;- a->tree->symlink_mode = a->symlink_mode;- }-}--int-archive_read_disk_set_symlink_logical(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_logical");- setup_symlink_mode(a, 'L', 1);- return (ARCHIVE_OK);-}--int-archive_read_disk_set_symlink_physical(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_physical");- setup_symlink_mode(a, 'P', 0);- return (ARCHIVE_OK);-}--int-archive_read_disk_set_symlink_hybrid(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_hybrid");- setup_symlink_mode(a, 'H', 1);/* Follow symlinks initially. */- return (ARCHIVE_OK);-}--int-archive_read_disk_set_atime_restored(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime");-#ifdef HAVE_UTIMES- a->flags |= ARCHIVE_READDISK_RESTORE_ATIME;- if (a->tree != NULL)- a->tree->flags |= needsRestoreTimes;- return (ARCHIVE_OK);-#else- /* Display warning and unset flag */- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Cannot restore access time on this system");- a->flags &= ~ARCHIVE_READDISK_RESTORE_ATIME;- return (ARCHIVE_WARN);-#endif-}--int-archive_read_disk_set_behavior(struct archive *_a, int flags)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- int r = ARCHIVE_OK;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");-- a->flags = flags;-- if (flags & ARCHIVE_READDISK_RESTORE_ATIME)- r = archive_read_disk_set_atime_restored(_a);- else {- if (a->tree != NULL)- a->tree->flags &= ~needsRestoreTimes;- }- return (r);-}--/*- * Trivial implementations of gname/uname lookup functions.- * These are normally overridden by the client, but these stub- * versions ensure that we always have something that works.- */-static const char *-trivial_lookup_gname(void *private_data, int64_t gid)-{- (void)private_data; /* UNUSED */- (void)gid; /* UNUSED */- return (NULL);-}--static const char *-trivial_lookup_uname(void *private_data, int64_t uid)-{- (void)private_data; /* UNUSED */- (void)uid; /* UNUSED */- return (NULL);-}--/*- * Allocate memory for the reading buffer adjusted to the filesystem- * alignment.- */-static int-setup_suitable_read_buffer(struct archive_read_disk *a)-{- struct tree *t = a->tree;- struct filesystem *cf = t->current_filesystem;- size_t asize;- size_t s;-- if (cf->allocation_ptr == NULL) {- /* If we couldn't get a filesystem alignment,- * we use 4096 as default value but we won't use- * O_DIRECT to open() and openat() operations. */- long xfer_align = (cf->xfer_align == -1)?4096:cf->xfer_align;-- if (cf->max_xfer_size != -1)- asize = cf->max_xfer_size + xfer_align;- else {- long incr = cf->incr_xfer_size;- /* Some platform does not set a proper value to- * incr_xfer_size.*/- if (incr < 0)- incr = cf->min_xfer_size;- if (cf->min_xfer_size < 0) {- incr = xfer_align;- asize = xfer_align;- } else- asize = cf->min_xfer_size;-- /* Increase a buffer size up to 64K bytes in- * a proper increment size. */- while (asize < 1024*64)- asize += incr;- /* Take a margin to adjust to the filesystem- * alignment. */- asize += xfer_align;- }- cf->allocation_ptr = malloc(asize);- if (cf->allocation_ptr == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Couldn't allocate memory");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }-- /*- * Calculate proper address for the filesystem.- */- s = (uintptr_t)cf->allocation_ptr;- s %= xfer_align;- if (s > 0)- s = xfer_align - s;-- /*- * Set a read buffer pointer in the proper alignment of- * the current filesystem.- */- cf->buff = cf->allocation_ptr + s;- cf->buff_size = asize - xfer_align;- }- return (ARCHIVE_OK);-}--static int-_archive_read_data_block(struct archive *_a, const void **buff,- size_t *size, int64_t *offset)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- struct tree *t = a->tree;- int r;- ssize_t bytes;- int64_t sparse_bytes;- size_t buffbytes;- int empty_sparse_region = 0;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_data_block");-- if (t->entry_eof || t->entry_remaining_bytes <= 0) {- r = ARCHIVE_EOF;- goto abort_read_data;- }-- /*- * Open the current file.- */- if (t->entry_fd < 0) {- int flags = O_RDONLY | O_BINARY | O_CLOEXEC;-- /*- * Eliminate or reduce cache effects if we can.- *- * Carefully consider this to be enabled.- */-#if defined(O_DIRECT) && 0/* Disabled for now */- if (t->current_filesystem->xfer_align != -1 &&- t->nlink == 1)- flags |= O_DIRECT;-#endif-#if defined(O_NOATIME)- /*- * Linux has O_NOATIME flag; use it if we need.- */- if ((t->flags & needsRestoreTimes) != 0 &&- t->restore_time.noatime == 0)- flags |= O_NOATIME;-#endif- t->entry_fd = open_on_current_dir(t,- tree_current_access_path(t), flags);- __archive_ensure_cloexec_flag(t->entry_fd);-#if defined(O_NOATIME)- /*- * When we did open the file with O_NOATIME flag,- * if successful, set 1 to t->restore_time.noatime- * not to restore an atime of the file later.- * if failed by EPERM, retry it without O_NOATIME flag.- */- if (flags & O_NOATIME) {- if (t->entry_fd >= 0)- t->restore_time.noatime = 1;- else if (errno == EPERM)- flags &= ~O_NOATIME;- }-#endif- if (t->entry_fd < 0) {- archive_set_error(&a->archive, errno,- "Couldn't open %s", tree_current_path(t));- r = ARCHIVE_FAILED;- tree_enter_initial_dir(t);- goto abort_read_data;- }- tree_enter_initial_dir(t);- }-- /*- * Allocate read buffer if not allocated.- */- if (t->current_filesystem->allocation_ptr == NULL) {- r = setup_suitable_read_buffer(a);- if (r != ARCHIVE_OK) {- a->archive.state = ARCHIVE_STATE_FATAL;- goto abort_read_data;- }- }- t->entry_buff = t->current_filesystem->buff;- t->entry_buff_size = t->current_filesystem->buff_size;-- buffbytes = t->entry_buff_size;- if ((int64_t)buffbytes > t->current_sparse->length)- buffbytes = t->current_sparse->length;-- if (t->current_sparse->length == 0)- empty_sparse_region = 1;-- /*- * Skip hole.- * TODO: Should we consider t->current_filesystem->xfer_align?- */- if (t->current_sparse->offset > t->entry_total) {- if (lseek(t->entry_fd,- (off_t)t->current_sparse->offset, SEEK_SET) < 0) {- archive_set_error(&a->archive, errno, "Seek error");- r = ARCHIVE_FATAL;- a->archive.state = ARCHIVE_STATE_FATAL;- goto abort_read_data;- }- sparse_bytes = t->current_sparse->offset - t->entry_total;- t->entry_remaining_bytes -= sparse_bytes;- t->entry_total += sparse_bytes;- }-- /*- * Read file contents.- */- if (buffbytes > 0) {- bytes = read(t->entry_fd, t->entry_buff, buffbytes);- if (bytes < 0) {- archive_set_error(&a->archive, errno, "Read error");- r = ARCHIVE_FATAL;- a->archive.state = ARCHIVE_STATE_FATAL;- goto abort_read_data;- }- } else- bytes = 0;- /*- * Return an EOF unless we've read a leading empty sparse region, which- * is used to represent fully-sparse files.- */- if (bytes == 0 && !empty_sparse_region) {- /* Get EOF */- t->entry_eof = 1;- r = ARCHIVE_EOF;- goto abort_read_data;- }- *buff = t->entry_buff;- *size = bytes;- *offset = t->entry_total;- t->entry_total += bytes;- t->entry_remaining_bytes -= bytes;- if (t->entry_remaining_bytes == 0) {- /* Close the current file descriptor */- close_and_restore_time(t->entry_fd, t, &t->restore_time);- t->entry_fd = -1;- t->entry_eof = 1;- }- t->current_sparse->offset += bytes;- t->current_sparse->length -= bytes;- if (t->current_sparse->length == 0 && !t->entry_eof)- t->current_sparse++;- return (ARCHIVE_OK);--abort_read_data:- *buff = NULL;- *size = 0;- *offset = t->entry_total;- if (t->entry_fd >= 0) {- /* Close the current file descriptor */- close_and_restore_time(t->entry_fd, t, &t->restore_time);- t->entry_fd = -1;- }- return (r);-}--static int-next_entry(struct archive_read_disk *a, struct tree *t,- struct archive_entry *entry)-{- const struct stat *st; /* info to use for this entry */- const struct stat *lst;/* lstat() information */- const char *name;- int delayed, delayed_errno, descend, r;- struct archive_string delayed_str;-- delayed = ARCHIVE_OK;- delayed_errno = 0;- archive_string_init(&delayed_str);-- st = NULL;- lst = NULL;- t->descend = 0;- do {- switch (tree_next(t)) {- case TREE_ERROR_FATAL:- archive_set_error(&a->archive, t->tree_errno,- "%s: Unable to continue traversing directory tree",- tree_current_path(t));- a->archive.state = ARCHIVE_STATE_FATAL;- tree_enter_initial_dir(t);- return (ARCHIVE_FATAL);- case TREE_ERROR_DIR:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: Couldn't visit directory",- tree_current_path(t));- tree_enter_initial_dir(t);- return (ARCHIVE_FAILED);- case 0:- tree_enter_initial_dir(t);- return (ARCHIVE_EOF);- case TREE_POSTDESCENT:- case TREE_POSTASCENT:- break;- case TREE_REGULAR:- lst = tree_current_lstat(t);- if (lst == NULL) {- if (errno == ENOENT && t->depth > 0) {- delayed = ARCHIVE_WARN;- delayed_errno = errno;- if (delayed_str.length == 0) {- archive_string_sprintf(&delayed_str,- "%s", tree_current_path(t));- } else {- archive_string_sprintf(&delayed_str,- " %s", tree_current_path(t));- }- } else {- archive_set_error(&a->archive, errno,- "%s: Cannot stat",- tree_current_path(t));- tree_enter_initial_dir(t);- return (ARCHIVE_FAILED);- }- }- break;- }- } while (lst == NULL);--#ifdef __APPLE__- if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {- /* If we're using copyfile(), ignore "._XXX" files. */- const char *bname = strrchr(tree_current_path(t), '/');- if (bname == NULL)- bname = tree_current_path(t);- else- ++bname;- if (bname[0] == '.' && bname[1] == '_')- return (ARCHIVE_RETRY);- }-#endif-- archive_entry_copy_pathname(entry, tree_current_path(t));- /*- * Perform path matching.- */- if (a->matching) {- r = archive_match_path_excluded(a->matching, entry);- if (r < 0) {- archive_set_error(&(a->archive), errno,- "Failed : %s", archive_error_string(a->matching));- return (r);- }- if (r) {- if (a->excluded_cb_func)- a->excluded_cb_func(&(a->archive),- a->excluded_cb_data, entry);- return (ARCHIVE_RETRY);- }- }-- /*- * Distinguish 'L'/'P'/'H' symlink following.- */- switch(t->symlink_mode) {- case 'H':- /* 'H': After the first item, rest like 'P'. */- t->symlink_mode = 'P';- /* 'H': First item (from command line) like 'L'. */- /* FALLTHROUGH */- case 'L':- /* 'L': Do descend through a symlink to dir. */- descend = tree_current_is_dir(t);- /* 'L': Follow symlinks to files. */- a->symlink_mode = 'L';- a->follow_symlinks = 1;- /* 'L': Archive symlinks as targets, if we can. */- st = tree_current_stat(t);- if (st != NULL && !tree_target_is_same_as_parent(t, st))- break;- /* If stat fails, we have a broken symlink;- * in that case, don't follow the link. */- /* FALLTHROUGH */- default:- /* 'P': Don't descend through a symlink to dir. */- descend = tree_current_is_physical_dir(t);- /* 'P': Don't follow symlinks to files. */- a->symlink_mode = 'P';- a->follow_symlinks = 0;- /* 'P': Archive symlinks as symlinks. */- st = lst;- break;- }-- if (update_current_filesystem(a, st->st_dev) != ARCHIVE_OK) {- a->archive.state = ARCHIVE_STATE_FATAL;- tree_enter_initial_dir(t);- return (ARCHIVE_FATAL);- }- if (t->initial_filesystem_id == -1)- t->initial_filesystem_id = t->current_filesystem_id;- if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) {- if (t->initial_filesystem_id != t->current_filesystem_id)- descend = 0;- }- t->descend = descend;-- /*- * Honor nodump flag.- * If the file is marked with nodump flag, do not return this entry.- */- if (a->flags & ARCHIVE_READDISK_HONOR_NODUMP) {-#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)- if (st->st_flags & UF_NODUMP)- return (ARCHIVE_RETRY);-#elif (defined(FS_IOC_GETFLAGS) && defined(FS_NODUMP_FL) && \- defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \- (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && \- defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))- if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) {- int stflags;-- t->entry_fd = open_on_current_dir(t,- tree_current_access_path(t),- O_RDONLY | O_NONBLOCK | O_CLOEXEC);- __archive_ensure_cloexec_flag(t->entry_fd);- if (t->entry_fd >= 0) {- r = ioctl(t->entry_fd,-#ifdef FS_IOC_GETFLAGS- FS_IOC_GETFLAGS,-#else- EXT2_IOC_GETFLAGS,-#endif- &stflags);-#ifdef FS_NODUMP_FL- if (r == 0 && (stflags & FS_NODUMP_FL) != 0)-#else- if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0)-#endif- return (ARCHIVE_RETRY);- }- }-#endif- }-- archive_entry_copy_stat(entry, st);-- /* Save the times to be restored. This must be in before- * calling archive_read_disk_descend() or any chance of it,- * especially, invoking a callback. */- t->restore_time.mtime = archive_entry_mtime(entry);- t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry);- t->restore_time.atime = archive_entry_atime(entry);- t->restore_time.atime_nsec = archive_entry_atime_nsec(entry);- t->restore_time.filetype = archive_entry_filetype(entry);- t->restore_time.noatime = t->current_filesystem->noatime;-- /*- * Perform time matching.- */- if (a->matching) {- r = archive_match_time_excluded(a->matching, entry);- if (r < 0) {- archive_set_error(&(a->archive), errno,- "Failed : %s", archive_error_string(a->matching));- return (r);- }- if (r) {- if (a->excluded_cb_func)- a->excluded_cb_func(&(a->archive),- a->excluded_cb_data, entry);- return (ARCHIVE_RETRY);- }- }-- /* Lookup uname/gname */- name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry));- if (name != NULL)- archive_entry_copy_uname(entry, name);- name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry));- if (name != NULL)- archive_entry_copy_gname(entry, name);-- /*- * Perform owner matching.- */- if (a->matching) {- r = archive_match_owner_excluded(a->matching, entry);- if (r < 0) {- archive_set_error(&(a->archive), errno,- "Failed : %s", archive_error_string(a->matching));- return (r);- }- if (r) {- if (a->excluded_cb_func)- a->excluded_cb_func(&(a->archive),- a->excluded_cb_data, entry);- return (ARCHIVE_RETRY);- }- }-- /*- * Invoke a meta data filter callback.- */- if (a->metadata_filter_func) {- if (!a->metadata_filter_func(&(a->archive),- a->metadata_filter_data, entry))- return (ARCHIVE_RETRY);- }-- /*- * Populate the archive_entry with metadata from the disk.- */- archive_entry_copy_sourcepath(entry, tree_current_access_path(t));- r = archive_read_disk_entry_from_file(&(a->archive), entry,- t->entry_fd, st);-- if (r == ARCHIVE_OK) {- r = delayed;- if (r != ARCHIVE_OK) {- archive_string_sprintf(&delayed_str, ": %s",- "File removed before we read it");- archive_set_error(&(a->archive), delayed_errno,- "%s", delayed_str.s);- }- }- archive_string_free(&delayed_str);-- return (r);-}--static int-_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)-{- int ret;- struct archive_read_disk *a = (struct archive_read_disk *)_a;- *entryp = NULL;- ret = _archive_read_next_header2(_a, a->entry);- *entryp = a->entry;- return ret;-}--static int-_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- struct tree *t;- int r;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_read_next_header2");-- t = a->tree;- if (t->entry_fd >= 0) {- close_and_restore_time(t->entry_fd, t, &t->restore_time);- t->entry_fd = -1;- }-- archive_entry_clear(entry);-- for (;;) {- r = next_entry(a, t, entry);- if (t->entry_fd >= 0) {- close(t->entry_fd);- t->entry_fd = -1;- }-- if (r == ARCHIVE_RETRY) {- archive_entry_clear(entry);- continue;- }- break;- }-- /* Return to the initial directory. */- tree_enter_initial_dir(t);-- /*- * EOF and FATAL are persistent at this layer. By- * modifying the state, we guarantee that future calls to- * read a header or read data will fail.- */- switch (r) {- case ARCHIVE_EOF:- a->archive.state = ARCHIVE_STATE_EOF;- break;- case ARCHIVE_OK:- case ARCHIVE_WARN:- /* Overwrite the sourcepath based on the initial directory. */- archive_entry_copy_sourcepath(entry, tree_current_path(t));- t->entry_total = 0;- if (archive_entry_filetype(entry) == AE_IFREG) {- t->nlink = archive_entry_nlink(entry);- t->entry_remaining_bytes = archive_entry_size(entry);- t->entry_eof = (t->entry_remaining_bytes == 0)? 1: 0;- if (!t->entry_eof &&- setup_sparse(a, entry) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- } else {- t->entry_remaining_bytes = 0;- t->entry_eof = 1;- }- a->archive.state = ARCHIVE_STATE_DATA;- break;- case ARCHIVE_RETRY:- break;- case ARCHIVE_FATAL:- a->archive.state = ARCHIVE_STATE_FATAL;- break;- }-- __archive_reset_read_data(&a->archive);- return (r);-}--static int-setup_sparse(struct archive_read_disk *a, struct archive_entry *entry)-{- struct tree *t = a->tree;- int64_t length, offset;- int i;-- t->sparse_count = archive_entry_sparse_reset(entry);- if (t->sparse_count+1 > t->sparse_list_size) {- free(t->sparse_list);- t->sparse_list_size = t->sparse_count + 1;- t->sparse_list = malloc(sizeof(t->sparse_list[0]) *- t->sparse_list_size);- if (t->sparse_list == NULL) {- t->sparse_list_size = 0;- archive_set_error(&a->archive, ENOMEM,- "Can't allocate data");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- }- for (i = 0; i < t->sparse_count; i++) {- archive_entry_sparse_next(entry, &offset, &length);- t->sparse_list[i].offset = offset;- t->sparse_list[i].length = length;- }- if (i == 0) {- t->sparse_list[i].offset = 0;- t->sparse_list[i].length = archive_entry_size(entry);- } else {- t->sparse_list[i].offset = archive_entry_size(entry);- t->sparse_list[i].length = 0;- }- t->current_sparse = t->sparse_list;-- return (ARCHIVE_OK);-}--int-archive_read_disk_set_matching(struct archive *_a, struct archive *_ma,- void (*_excluded_func)(struct archive *, void *, struct archive_entry *),- void *_client_data)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_matching");- a->matching = _ma;- a->excluded_cb_func = _excluded_func;- a->excluded_cb_data = _client_data;- return (ARCHIVE_OK);-}--int-archive_read_disk_set_metadata_filter_callback(struct archive *_a,- int (*_metadata_filter_func)(struct archive *, void *,- struct archive_entry *), void *_client_data)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY,- "archive_read_disk_set_metadata_filter_callback");-- a->metadata_filter_func = _metadata_filter_func;- a->metadata_filter_data = _client_data;- return (ARCHIVE_OK);-}--int-archive_read_disk_can_descend(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- struct tree *t = a->tree;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_read_disk_can_descend");-- return (t->visit_type == TREE_REGULAR && t->descend);-}--/*- * Called by the client to mark the directory just returned from- * tree_next() as needing to be visited.- */-int-archive_read_disk_descend(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- struct tree *t = a->tree;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_read_disk_descend");-- if (!archive_read_disk_can_descend(_a))- return (ARCHIVE_OK);-- /*- * We must not treat the initial specified path as a physical dir,- * because if we do then we will try and ascend out of it by opening- * ".." which is (a) wrong and (b) causes spurious permissions errors- * if ".." is not readable by us. Instead, treat it as if it were a- * symlink. (This uses an extra fd, but it can only happen once at the- * top level of a traverse.) But we can't necessarily assume t->st is- * valid here (though t->lst is), which complicates the logic a- * little.- */- if (tree_current_is_physical_dir(t)) {- tree_push(t, t->basename, t->current_filesystem_id,- t->lst.st_dev, t->lst.st_ino, &t->restore_time);- if (t->stack->parent->parent != NULL)- t->stack->flags |= isDir;- else- t->stack->flags |= isDirLink;- } else if (tree_current_is_dir(t)) {- tree_push(t, t->basename, t->current_filesystem_id,- t->st.st_dev, t->st.st_ino, &t->restore_time);- t->stack->flags |= isDirLink;- }- t->descend = 0;- return (ARCHIVE_OK);-}--int-archive_read_disk_open(struct archive *_a, const char *pathname)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED,- "archive_read_disk_open");- archive_clear_error(&a->archive);-- return (_archive_read_disk_open(_a, pathname));-}--int-archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- struct archive_string path;- int ret;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED,- "archive_read_disk_open_w");- archive_clear_error(&a->archive);-- /* Make a char string from a wchar_t string. */- archive_string_init(&path);- if (archive_string_append_from_wcs(&path, pathname,- wcslen(pathname)) != 0) {- if (errno == ENOMEM)- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't convert a path to a char string");- a->archive.state = ARCHIVE_STATE_FATAL;- ret = ARCHIVE_FATAL;- } else- ret = _archive_read_disk_open(_a, path.s);-- archive_string_free(&path);- return (ret);-}--static int-_archive_read_disk_open(struct archive *_a, const char *pathname)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- if (a->tree != NULL)- a->tree = tree_reopen(a->tree, pathname,- a->flags & ARCHIVE_READDISK_RESTORE_ATIME);- else- a->tree = tree_open(pathname, a->symlink_mode,- a->flags & ARCHIVE_READDISK_RESTORE_ATIME);- if (a->tree == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate tar data");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- a->archive.state = ARCHIVE_STATE_HEADER;-- return (ARCHIVE_OK);-}--/*- * Return a current filesystem ID which is index of the filesystem entry- * you've visited through archive_read_disk.- */-int-archive_read_disk_current_filesystem(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_disk_current_filesystem");-- return (a->tree->current_filesystem_id);-}--static int-update_current_filesystem(struct archive_read_disk *a, int64_t dev)-{- struct tree *t = a->tree;- int i, fid;-- if (t->current_filesystem != NULL &&- t->current_filesystem->dev == dev)- return (ARCHIVE_OK);-- for (i = 0; i < t->max_filesystem_id; i++) {- if (t->filesystem_table[i].dev == dev) {- /* There is the filesystem ID we've already generated. */- t->current_filesystem_id = i;- t->current_filesystem = &(t->filesystem_table[i]);- return (ARCHIVE_OK);- }- }-- /*- * This is the new filesystem which we have to generate a new ID for.- */- fid = t->max_filesystem_id++;- if (t->max_filesystem_id > t->allocated_filesystem) {- size_t s;- void *p;-- s = t->max_filesystem_id * 2;- p = realloc(t->filesystem_table,- s * sizeof(*t->filesystem_table));- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate tar data");- return (ARCHIVE_FATAL);- }- t->filesystem_table = (struct filesystem *)p;- t->allocated_filesystem = s;- }- t->current_filesystem_id = fid;- t->current_filesystem = &(t->filesystem_table[fid]);- t->current_filesystem->dev = dev;- t->current_filesystem->allocation_ptr = NULL;- t->current_filesystem->buff = NULL;-- /* Setup the current filesystem properties which depend on- * platform specific. */- return (setup_current_filesystem(a));-}--/*- * Returns 1 if current filesystem is generated filesystem, 0 if it is not- * or -1 if it is unknown.- */-int-archive_read_disk_current_filesystem_is_synthetic(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_disk_current_filesystem");-- return (a->tree->current_filesystem->synthetic);-}--/*- * Returns 1 if current filesystem is remote filesystem, 0 if it is not- * or -1 if it is unknown.- */-int-archive_read_disk_current_filesystem_is_remote(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_disk_current_filesystem");-- return (a->tree->current_filesystem->remote);-}--#if defined(_PC_REC_INCR_XFER_SIZE) && defined(_PC_REC_MAX_XFER_SIZE) &&\- defined(_PC_REC_MIN_XFER_SIZE) && defined(_PC_REC_XFER_ALIGN)-static int-get_xfer_size(struct tree *t, int fd, const char *path)-{- t->current_filesystem->xfer_align = -1;- errno = 0;- if (fd >= 0) {- t->current_filesystem->incr_xfer_size =- fpathconf(fd, _PC_REC_INCR_XFER_SIZE);- t->current_filesystem->max_xfer_size =- fpathconf(fd, _PC_REC_MAX_XFER_SIZE);- t->current_filesystem->min_xfer_size =- fpathconf(fd, _PC_REC_MIN_XFER_SIZE);- t->current_filesystem->xfer_align =- fpathconf(fd, _PC_REC_XFER_ALIGN);- } else if (path != NULL) {- t->current_filesystem->incr_xfer_size =- pathconf(path, _PC_REC_INCR_XFER_SIZE);- t->current_filesystem->max_xfer_size =- pathconf(path, _PC_REC_MAX_XFER_SIZE);- t->current_filesystem->min_xfer_size =- pathconf(path, _PC_REC_MIN_XFER_SIZE);- t->current_filesystem->xfer_align =- pathconf(path, _PC_REC_XFER_ALIGN);- }- /* At least we need an alignment size. */- if (t->current_filesystem->xfer_align == -1)- return ((errno == EINVAL)?1:-1);- else- return (0);-}-#else-static int-get_xfer_size(struct tree *t, int fd, const char *path)-{- (void)t; /* UNUSED */- (void)fd; /* UNUSED */- (void)path; /* UNUSED */- return (1);/* Not supported */-}-#endif--#if defined(HAVE_STATVFS)-static inline __LA_UNUSED void-set_statvfs_transfer_size(struct filesystem *fs, const struct statvfs *sfs)-{- fs->xfer_align = sfs->f_frsize > 0 ? (long)sfs->f_frsize : -1;- fs->max_xfer_size = -1;-#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE)- fs->min_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;- fs->incr_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;-#else- fs->min_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;- fs->incr_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;-#endif-}-#endif--#if defined(HAVE_STRUCT_STATFS)-static inline __LA_UNUSED void-set_statfs_transfer_size(struct filesystem *fs, const struct statfs *sfs)-{- fs->xfer_align = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;- fs->max_xfer_size = -1;-#if defined(HAVE_STRUCT_STATFS_F_IOSIZE)- fs->min_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;- fs->incr_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;-#else- fs->min_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;- fs->incr_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;-#endif-}-#endif--#if defined(HAVE_STRUCT_STATFS) && defined(HAVE_STATFS) && \- defined(HAVE_FSTATFS) && defined(MNT_LOCAL) && !defined(ST_LOCAL)--/*- * Gather current filesystem properties on FreeBSD, OpenBSD and Mac OS X.- */-static int-setup_current_filesystem(struct archive_read_disk *a)-{- struct tree *t = a->tree;- struct statfs sfs;-#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC)-/* TODO: configure should set GETVFSBYNAME_ARG_TYPE to make- * this accurate; some platforms have both and we need the one that's- * used by getvfsbyname()- *- * Then the following would become:- * #if defined(GETVFSBYNAME_ARG_TYPE)- * GETVFSBYNAME_ARG_TYPE vfc;- * #endif- */-# if defined(HAVE_STRUCT_XVFSCONF)- struct xvfsconf vfc;-# else- struct vfsconf vfc;-# endif-#endif- int r, xr = 0;-#if !defined(HAVE_STRUCT_STATFS_F_NAMEMAX)- long nm;-#endif-- t->current_filesystem->synthetic = -1;- t->current_filesystem->remote = -1;- if (tree_current_is_symblic_link_target(t)) {-#if defined(HAVE_OPENAT)- /*- * Get file system statistics on any directory- * where current is.- */- int fd = openat(tree_current_dir_fd(t),- tree_current_access_path(t), O_RDONLY | O_CLOEXEC);- __archive_ensure_cloexec_flag(fd);- if (fd < 0) {- archive_set_error(&a->archive, errno,- "openat failed");- return (ARCHIVE_FAILED);- }- r = fstatfs(fd, &sfs);- if (r == 0)- xr = get_xfer_size(t, fd, NULL);- close(fd);-#else- if (tree_enter_working_dir(t) != 0) {- archive_set_error(&a->archive, errno, "fchdir failed");- return (ARCHIVE_FAILED);- }- r = statfs(tree_current_access_path(t), &sfs);- if (r == 0)- xr = get_xfer_size(t, -1, tree_current_access_path(t));-#endif- } else {- r = fstatfs(tree_current_dir_fd(t), &sfs);- if (r == 0)- xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);- }- if (r == -1 || xr == -1) {- archive_set_error(&a->archive, errno, "statfs failed");- return (ARCHIVE_FAILED);- } else if (xr == 1) {- /* pathconf(_PC_REX_*) operations are not supported. */- set_statfs_transfer_size(t->current_filesystem, &sfs);- }- if (sfs.f_flags & MNT_LOCAL)- t->current_filesystem->remote = 0;- else- t->current_filesystem->remote = 1;--#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC)- r = getvfsbyname(sfs.f_fstypename, &vfc);- if (r == -1) {- archive_set_error(&a->archive, errno, "getvfsbyname failed");- return (ARCHIVE_FAILED);- }- if (vfc.vfc_flags & VFCF_SYNTHETIC)- t->current_filesystem->synthetic = 1;- else- t->current_filesystem->synthetic = 0;-#endif--#if defined(MNT_NOATIME)- if (sfs.f_flags & MNT_NOATIME)- t->current_filesystem->noatime = 1;- else-#endif- t->current_filesystem->noatime = 0;--#if defined(USE_READDIR_R)- /* Set maximum filename length. */-#if defined(HAVE_STRUCT_STATFS_F_NAMEMAX)- t->current_filesystem->name_max = sfs.f_namemax;-#else-# if defined(_PC_NAME_MAX)- /* Mac OS X does not have f_namemax in struct statfs. */- if (tree_current_is_symblic_link_target(t)) {- if (tree_enter_working_dir(t) != 0) {- archive_set_error(&a->archive, errno, "fchdir failed");- return (ARCHIVE_FAILED);- }- nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);- } else- nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);-# else- nm = -1;-# endif- if (nm == -1)- t->current_filesystem->name_max = NAME_MAX;- else- t->current_filesystem->name_max = nm;-#endif- if (t->current_filesystem->name_max == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Cannot determine name_max");- return (ARCHIVE_FAILED);- }-#endif /* USE_READDIR_R */- return (ARCHIVE_OK);-}--#elif (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS)) && defined(ST_LOCAL)--/*- * Gather current filesystem properties on NetBSD- */-static int-setup_current_filesystem(struct archive_read_disk *a)-{- struct tree *t = a->tree;- struct statvfs svfs;- int r, xr = 0;-- t->current_filesystem->synthetic = -1;- if (tree_enter_working_dir(t) != 0) {- archive_set_error(&a->archive, errno, "fchdir failed");- return (ARCHIVE_FAILED);- }- if (tree_current_is_symblic_link_target(t)) {- r = statvfs(tree_current_access_path(t), &svfs);- if (r == 0)- xr = get_xfer_size(t, -1, tree_current_access_path(t));- } else {-#ifdef HAVE_FSTATVFS- r = fstatvfs(tree_current_dir_fd(t), &svfs);- if (r == 0)- xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);-#else- r = statvfs(".", &svfs);- if (r == 0)- xr = get_xfer_size(t, -1, ".");-#endif- }- if (r == -1 || xr == -1) {- t->current_filesystem->remote = -1;- archive_set_error(&a->archive, errno, "statvfs failed");- return (ARCHIVE_FAILED);- } else if (xr == 1) {- /* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN- * for pathconf() function. */- set_statvfs_transfer_size(t->current_filesystem, &svfs);- }- if (svfs.f_flag & ST_LOCAL)- t->current_filesystem->remote = 0;- else- t->current_filesystem->remote = 1;--#if defined(ST_NOATIME)- if (svfs.f_flag & ST_NOATIME)- t->current_filesystem->noatime = 1;- else-#endif- t->current_filesystem->noatime = 0;-- /* Set maximum filename length. */- t->current_filesystem->name_max = svfs.f_namemax;- return (ARCHIVE_OK);-}--#elif defined(HAVE_SYS_STATFS_H) && defined(HAVE_LINUX_MAGIC_H) &&\- defined(HAVE_STATFS) && defined(HAVE_FSTATFS)-/*- * Note: statfs is deprecated since LSB 3.2- */--#ifndef CIFS_SUPER_MAGIC-#define CIFS_SUPER_MAGIC 0xFF534D42-#endif-#ifndef DEVFS_SUPER_MAGIC-#define DEVFS_SUPER_MAGIC 0x1373-#endif--/*- * Gather current filesystem properties on Linux- */-static int-setup_current_filesystem(struct archive_read_disk *a)-{- struct tree *t = a->tree;- struct statfs sfs;-#if defined(HAVE_STATVFS)- struct statvfs svfs;-#endif- int r, vr = 0, xr = 0;-- if (tree_current_is_symblic_link_target(t)) {-#if defined(HAVE_OPENAT)- /*- * Get file system statistics on any directory- * where current is.- */- int fd = openat(tree_current_dir_fd(t),- tree_current_access_path(t), O_RDONLY | O_CLOEXEC);- __archive_ensure_cloexec_flag(fd);- if (fd < 0) {- archive_set_error(&a->archive, errno,- "openat failed");- return (ARCHIVE_FAILED);- }-#if defined(HAVE_FSTATVFS)- vr = fstatvfs(fd, &svfs);/* for f_flag, mount flags */-#endif- r = fstatfs(fd, &sfs);- if (r == 0)- xr = get_xfer_size(t, fd, NULL);- close(fd);-#else- if (tree_enter_working_dir(t) != 0) {- archive_set_error(&a->archive, errno, "fchdir failed");- return (ARCHIVE_FAILED);- }-#if defined(HAVE_STATVFS)- vr = statvfs(tree_current_access_path(t), &svfs);-#endif- r = statfs(tree_current_access_path(t), &sfs);- if (r == 0)- xr = get_xfer_size(t, -1, tree_current_access_path(t));-#endif- } else {-#ifdef HAVE_FSTATFS-#if defined(HAVE_FSTATVFS)- vr = fstatvfs(tree_current_dir_fd(t), &svfs);-#endif- r = fstatfs(tree_current_dir_fd(t), &sfs);- if (r == 0)- xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);-#else- if (tree_enter_working_dir(t) != 0) {- archive_set_error(&a->archive, errno, "fchdir failed");- return (ARCHIVE_FAILED);- }-#if defined(HAVE_STATVFS)- vr = statvfs(".", &svfs);-#endif- r = statfs(".", &sfs);- if (r == 0)- xr = get_xfer_size(t, -1, ".");-#endif- }- if (r == -1 || xr == -1 || vr == -1) {- t->current_filesystem->synthetic = -1;- t->current_filesystem->remote = -1;- archive_set_error(&a->archive, errno, "statfs failed");- return (ARCHIVE_FAILED);- } else if (xr == 1) {- /* pathconf(_PC_REX_*) operations are not supported. */-#if defined(HAVE_STATVFS)- set_statvfs_transfer_size(t->current_filesystem, &svfs);-#else- set_statfs_transfer_size(t->current_filesystem, &sfs);-#endif- }- switch (sfs.f_type) {- case AFS_SUPER_MAGIC:- case CIFS_SUPER_MAGIC:- case CODA_SUPER_MAGIC:- case NCP_SUPER_MAGIC:/* NetWare */- case NFS_SUPER_MAGIC:- case SMB_SUPER_MAGIC:- t->current_filesystem->remote = 1;- t->current_filesystem->synthetic = 0;- break;- case DEVFS_SUPER_MAGIC:- case PROC_SUPER_MAGIC:- case USBDEVICE_SUPER_MAGIC:- t->current_filesystem->remote = 0;- t->current_filesystem->synthetic = 1;- break;- default:- t->current_filesystem->remote = 0;- t->current_filesystem->synthetic = 0;- break;- }--#if defined(ST_NOATIME)-#if defined(HAVE_STATVFS)- if (svfs.f_flag & ST_NOATIME)-#else- if (sfs.f_flags & ST_NOATIME)-#endif- t->current_filesystem->noatime = 1;- else-#endif- t->current_filesystem->noatime = 0;--#if defined(USE_READDIR_R)- /* Set maximum filename length. */-#if defined(HAVE_STATVFS)- t->current_filesystem->name_max = svfs.f_namemax;-#else- t->current_filesystem->name_max = sfs.f_namelen;-#endif- if (t->current_filesystem->name_max == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Cannot determine name_max");- return (ARCHIVE_FAILED);- }-#endif- return (ARCHIVE_OK);-}--#elif defined(HAVE_SYS_STATVFS_H) &&\- (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS))--/*- * Gather current filesystem properties on other posix platform.- */-static int-setup_current_filesystem(struct archive_read_disk *a)-{- struct tree *t = a->tree;- struct statvfs svfs;- int r, xr = 0;-- t->current_filesystem->synthetic = -1;/* Not supported */- t->current_filesystem->remote = -1;/* Not supported */- if (tree_current_is_symblic_link_target(t)) {-#if defined(HAVE_OPENAT)- /*- * Get file system statistics on any directory- * where current is.- */- int fd = openat(tree_current_dir_fd(t),- tree_current_access_path(t), O_RDONLY | O_CLOEXEC);- __archive_ensure_cloexec_flag(fd);- if (fd < 0) {- archive_set_error(&a->archive, errno,- "openat failed");- return (ARCHIVE_FAILED);- }- r = fstatvfs(fd, &svfs);- if (r == 0)- xr = get_xfer_size(t, fd, NULL);- close(fd);-#else- if (tree_enter_working_dir(t) != 0) {- archive_set_error(&a->archive, errno, "fchdir failed");- return (ARCHIVE_FAILED);- }- r = statvfs(tree_current_access_path(t), &svfs);- if (r == 0)- xr = get_xfer_size(t, -1, tree_current_access_path(t));-#endif- } else {-#ifdef HAVE_FSTATVFS- r = fstatvfs(tree_current_dir_fd(t), &svfs);- if (r == 0)- xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);-#else- if (tree_enter_working_dir(t) != 0) {- archive_set_error(&a->archive, errno, "fchdir failed");- return (ARCHIVE_FAILED);- }- r = statvfs(".", &svfs);- if (r == 0)- xr = get_xfer_size(t, -1, ".");-#endif- }- if (r == -1 || xr == -1) {- t->current_filesystem->synthetic = -1;- t->current_filesystem->remote = -1;- archive_set_error(&a->archive, errno, "statvfs failed");- return (ARCHIVE_FAILED);- } else if (xr == 1) {- /* pathconf(_PC_REX_*) operations are not supported. */- set_statvfs_transfer_size(t->current_filesystem, &svfs);- }--#if defined(ST_NOATIME)- if (svfs.f_flag & ST_NOATIME)- t->current_filesystem->noatime = 1;- else-#endif- t->current_filesystem->noatime = 0;--#if defined(USE_READDIR_R)- /* Set maximum filename length. */- t->current_filesystem->name_max = svfs.f_namemax;- if (t->current_filesystem->name_max == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Cannot determine name_max");- return (ARCHIVE_FAILED);- }-#endif- return (ARCHIVE_OK);-}--#else--/*- * Generic: Gather current filesystem properties.- * TODO: Is this generic function really needed?- */-static int-setup_current_filesystem(struct archive_read_disk *a)-{- struct tree *t = a->tree;-#if defined(_PC_NAME_MAX) && defined(USE_READDIR_R)- long nm;-#endif- t->current_filesystem->synthetic = -1;/* Not supported */- t->current_filesystem->remote = -1;/* Not supported */- t->current_filesystem->noatime = 0;- (void)get_xfer_size(t, -1, ".");/* Dummy call to avoid build error. */- t->current_filesystem->xfer_align = -1;/* Unknown */- t->current_filesystem->max_xfer_size = -1;- t->current_filesystem->min_xfer_size = -1;- t->current_filesystem->incr_xfer_size = -1;--#if defined(USE_READDIR_R)- /* Set maximum filename length. */-# if defined(_PC_NAME_MAX)- if (tree_current_is_symblic_link_target(t)) {- if (tree_enter_working_dir(t) != 0) {- archive_set_error(&a->archive, errno, "fchdir failed");- return (ARCHIVE_FAILED);- }- nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);- } else- nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);- if (nm == -1)-# endif /* _PC_NAME_MAX */- /*- * Some systems (HP-UX or others?) incorrectly defined- * NAME_MAX macro to be a smaller value.- */-# if defined(NAME_MAX) && NAME_MAX >= 255- t->current_filesystem->name_max = NAME_MAX;-# else- /* No way to get a trusted value of maximum filename- * length. */- t->current_filesystem->name_max = PATH_MAX;-# endif /* NAME_MAX */-# if defined(_PC_NAME_MAX)- else- t->current_filesystem->name_max = nm;-# endif /* _PC_NAME_MAX */- if (t->current_filesystem->name_max == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Cannot determine name_max");- return (ARCHIVE_FAILED);- }-#endif /* USE_READDIR_R */- return (ARCHIVE_OK);-}--#endif--static int-close_and_restore_time(int fd, struct tree *t, struct restore_time *rt)-{-#ifndef HAVE_UTIMES- (void)t; /* UNUSED */- (void)rt; /* UNUSED */- return (close(fd));-#else-#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__)- struct timespec timespecs[2];-#endif- struct timeval times[2];-- if ((t->flags & needsRestoreTimes) == 0 || rt->noatime) {- if (fd >= 0)- return (close(fd));- else- return (0);- }--#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__)- timespecs[1].tv_sec = rt->mtime;- timespecs[1].tv_nsec = rt->mtime_nsec;-- timespecs[0].tv_sec = rt->atime;- timespecs[0].tv_nsec = rt->atime_nsec;- /* futimens() is defined in POSIX.1-2008. */- if (futimens(fd, timespecs) == 0)- return (close(fd));-#endif-- times[1].tv_sec = rt->mtime;- times[1].tv_usec = rt->mtime_nsec / 1000;-- times[0].tv_sec = rt->atime;- times[0].tv_usec = rt->atime_nsec / 1000;--#if !defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES) && !defined(__CYGWIN__)- if (futimes(fd, times) == 0)- return (close(fd));-#endif- close(fd);-#if defined(HAVE_FUTIMESAT)- if (futimesat(tree_current_dir_fd(t), rt->name, times) == 0)- return (0);-#endif-#ifdef HAVE_LUTIMES- if (lutimes(rt->name, times) != 0)-#else- if (AE_IFLNK != rt->filetype && utimes(rt->name, times) != 0)-#endif- return (-1);-#endif- return (0);-}--static int-open_on_current_dir(struct tree *t, const char *path, int flags)-{-#ifdef HAVE_OPENAT- return (openat(tree_current_dir_fd(t), path, flags));-#else- if (tree_enter_working_dir(t) != 0)- return (-1);- return (open(path, flags));-#endif-}--static int-tree_dup(int fd)-{- int new_fd;-#ifdef F_DUPFD_CLOEXEC- static volatile int can_dupfd_cloexec = 1;-- if (can_dupfd_cloexec) {- new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);- if (new_fd != -1)- return (new_fd);- /* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC,- * but it cannot be used. So we have to try dup(). */- /* We won't try F_DUPFD_CLOEXEC. */- can_dupfd_cloexec = 0;- }-#endif /* F_DUPFD_CLOEXEC */- new_fd = dup(fd);- __archive_ensure_cloexec_flag(new_fd);- return (new_fd);-}--/*- * Add a directory path to the current stack.- */-static void-tree_push(struct tree *t, const char *path, int filesystem_id,- int64_t dev, int64_t ino, struct restore_time *rt)-{- struct tree_entry *te;-- te = calloc(1, sizeof(*te));- if (te == NULL)- __archive_errx(1, "Out of memory");- te->next = t->stack;- te->parent = t->current;- if (te->parent)- te->depth = te->parent->depth + 1;- t->stack = te;- archive_string_init(&te->name);- te->symlink_parent_fd = -1;- archive_strcpy(&te->name, path);- te->flags = needsDescent | needsOpen | needsAscent;- te->filesystem_id = filesystem_id;- te->dev = dev;- te->ino = ino;- te->dirname_length = t->dirname_length;- te->restore_time.name = te->name.s;- if (rt != NULL) {- te->restore_time.mtime = rt->mtime;- te->restore_time.mtime_nsec = rt->mtime_nsec;- te->restore_time.atime = rt->atime;- te->restore_time.atime_nsec = rt->atime_nsec;- te->restore_time.filetype = rt->filetype;- te->restore_time.noatime = rt->noatime;- }-}--/*- * Append a name to the current dir path.- */-static void-tree_append(struct tree *t, const char *name, size_t name_length)-{- size_t size_needed;-- t->path.s[t->dirname_length] = '\0';- t->path.length = t->dirname_length;- /* Strip trailing '/' from name, unless entire name is "/". */- while (name_length > 1 && name[name_length - 1] == '/')- name_length--;-- /* Resize pathname buffer as needed. */- size_needed = name_length + t->dirname_length + 2;- archive_string_ensure(&t->path, size_needed);- /* Add a separating '/' if it's needed. */- if (t->dirname_length > 0 && t->path.s[archive_strlen(&t->path)-1] != '/')- archive_strappend_char(&t->path, '/');- t->basename = t->path.s + archive_strlen(&t->path);- archive_strncat(&t->path, name, name_length);- t->restore_time.name = t->basename;-}--/*- * Open a directory tree for traversal.- */-static struct tree *-tree_open(const char *path, int symlink_mode, int restore_time)-{- struct tree *t;-- if ((t = calloc(1, sizeof(*t))) == NULL)- return (NULL);- archive_string_init(&t->path);- archive_string_ensure(&t->path, 31);- t->initial_symlink_mode = symlink_mode;- return (tree_reopen(t, path, restore_time));-}--static struct tree *-tree_reopen(struct tree *t, const char *path, int restore_time)-{-#if defined(O_PATH)- /* Linux */- const int o_flag = O_PATH;-#elif defined(O_SEARCH)- /* SunOS */- const int o_flag = O_SEARCH;-#elif defined(__FreeBSD__) && defined(O_EXEC)- /* FreeBSD */- const int o_flag = O_EXEC;-#endif-- t->flags = (restore_time != 0)?needsRestoreTimes:0;- t->flags |= onInitialDir;- t->visit_type = 0;- t->tree_errno = 0;- t->dirname_length = 0;- t->depth = 0;- t->descend = 0;- t->current = NULL;- t->d = INVALID_DIR_HANDLE;- t->symlink_mode = t->initial_symlink_mode;- archive_string_empty(&t->path);- t->entry_fd = -1;- t->entry_eof = 0;- t->entry_remaining_bytes = 0;- t->initial_filesystem_id = -1;-- /* First item is set up a lot like a symlink traversal. */- tree_push(t, path, 0, 0, 0, NULL);- t->stack->flags = needsFirstVisit;- t->maxOpenCount = t->openCount = 1;- t->initial_dir_fd = open(".", O_RDONLY | O_CLOEXEC);-#if defined(O_PATH) || defined(O_SEARCH) || \- (defined(__FreeBSD__) && defined(O_EXEC))- /*- * Most likely reason to fail opening "." is that it's not readable,- * so try again for execute. The consequences of not opening this are- * unhelpful and unnecessary errors later.- */- if (t->initial_dir_fd < 0)- t->initial_dir_fd = open(".", o_flag | O_CLOEXEC);-#endif- __archive_ensure_cloexec_flag(t->initial_dir_fd);- t->working_dir_fd = tree_dup(t->initial_dir_fd);- return (t);-}--static int-tree_descent(struct tree *t)-{- int flag, new_fd, r = 0;-- t->dirname_length = archive_strlen(&t->path);- flag = O_RDONLY | O_CLOEXEC;-#if defined(O_DIRECTORY)- flag |= O_DIRECTORY;-#endif- new_fd = open_on_current_dir(t, t->stack->name.s, flag);- __archive_ensure_cloexec_flag(new_fd);- if (new_fd < 0) {- t->tree_errno = errno;- r = TREE_ERROR_DIR;- } else {- t->depth++;- /* If it is a link, set up fd for the ascent. */- if (t->stack->flags & isDirLink) {- t->stack->symlink_parent_fd = t->working_dir_fd;- t->openCount++;- if (t->openCount > t->maxOpenCount)- t->maxOpenCount = t->openCount;- } else- close(t->working_dir_fd);- /* Renew the current working directory. */- t->working_dir_fd = new_fd;- t->flags &= ~onWorkingDir;- }- return (r);-}--/*- * We've finished a directory; ascend back to the parent.- */-static int-tree_ascend(struct tree *t)-{- struct tree_entry *te;- int new_fd, r = 0, prev_dir_fd;-- te = t->stack;- prev_dir_fd = t->working_dir_fd;- if (te->flags & isDirLink)- new_fd = te->symlink_parent_fd;- else {- new_fd = open_on_current_dir(t, "..", O_RDONLY | O_CLOEXEC);- __archive_ensure_cloexec_flag(new_fd);- }- if (new_fd < 0) {- t->tree_errno = errno;- r = TREE_ERROR_FATAL;- } else {- /* Renew the current working directory. */- t->working_dir_fd = new_fd;- t->flags &= ~onWorkingDir;- /* Current directory has been changed, we should- * close an fd of previous working directory. */- close_and_restore_time(prev_dir_fd, t, &te->restore_time);- if (te->flags & isDirLink) {- t->openCount--;- te->symlink_parent_fd = -1;- }- t->depth--;- }- return (r);-}--/*- * Return to the initial directory where tree_open() was performed.- */-static int-tree_enter_initial_dir(struct tree *t)-{- int r = 0;-- if ((t->flags & onInitialDir) == 0) {- r = fchdir(t->initial_dir_fd);- if (r == 0) {- t->flags &= ~onWorkingDir;- t->flags |= onInitialDir;- }- }- return (r);-}--/*- * Restore working directory of directory traversals.- */-static int-tree_enter_working_dir(struct tree *t)-{- int r = 0;-- /*- * Change the current directory if really needed.- * Sometimes this is unneeded when we did not do- * descent.- */- if (t->depth > 0 && (t->flags & onWorkingDir) == 0) {- r = fchdir(t->working_dir_fd);- if (r == 0) {- t->flags &= ~onInitialDir;- t->flags |= onWorkingDir;- }- }- return (r);-}--static int-tree_current_dir_fd(struct tree *t)-{- return (t->working_dir_fd);-}--/*- * Pop the working stack.- */-static void-tree_pop(struct tree *t)-{- struct tree_entry *te;-- t->path.s[t->dirname_length] = '\0';- t->path.length = t->dirname_length;- if (t->stack == t->current && t->current != NULL)- t->current = t->current->parent;- te = t->stack;- t->stack = te->next;- t->dirname_length = te->dirname_length;- t->basename = t->path.s + t->dirname_length;- while (t->basename[0] == '/')- t->basename++;- archive_string_free(&te->name);- free(te);-}--/*- * Get the next item in the tree traversal.- */-static int-tree_next(struct tree *t)-{- int r;-- while (t->stack != NULL) {- /* If there's an open dir, get the next entry from there. */- if (t->d != INVALID_DIR_HANDLE) {- r = tree_dir_next_posix(t);- if (r == 0)- continue;- return (r);- }-- if (t->stack->flags & needsFirstVisit) {- /* Top stack item needs a regular visit. */- t->current = t->stack;- tree_append(t, t->stack->name.s,- archive_strlen(&(t->stack->name)));- /* t->dirname_length = t->path_length; */- /* tree_pop(t); */- t->stack->flags &= ~needsFirstVisit;- return (t->visit_type = TREE_REGULAR);- } else if (t->stack->flags & needsDescent) {- /* Top stack item is dir to descend into. */- t->current = t->stack;- tree_append(t, t->stack->name.s,- archive_strlen(&(t->stack->name)));- t->stack->flags &= ~needsDescent;- r = tree_descent(t);- if (r != 0) {- tree_pop(t);- t->visit_type = r;- } else- t->visit_type = TREE_POSTDESCENT;- return (t->visit_type);- } else if (t->stack->flags & needsOpen) {- t->stack->flags &= ~needsOpen;- r = tree_dir_next_posix(t);- if (r == 0)- continue;- return (r);- } else if (t->stack->flags & needsAscent) {- /* Top stack item is dir and we're done with it. */- r = tree_ascend(t);- tree_pop(t);- t->visit_type = r != 0 ? r : TREE_POSTASCENT;- return (t->visit_type);- } else {- /* Top item on stack is dead. */- tree_pop(t);- t->flags &= ~hasLstat;- t->flags &= ~hasStat;- }- }- return (t->visit_type = 0);-}--static int-tree_dir_next_posix(struct tree *t)-{- int r;- const char *name;- size_t namelen;-- if (t->d == NULL) {-#if defined(USE_READDIR_R)- size_t dirent_size;-#endif--#if defined(HAVE_FDOPENDIR)- t->d = fdopendir(tree_dup(t->working_dir_fd));-#else /* HAVE_FDOPENDIR */- if (tree_enter_working_dir(t) == 0) {- t->d = opendir(".");-#ifdef HAVE_DIRFD- __archive_ensure_cloexec_flag(dirfd(t->d));-#endif- }-#endif /* HAVE_FDOPENDIR */- if (t->d == NULL) {- r = tree_ascend(t); /* Undo "chdir" */- tree_pop(t);- t->tree_errno = errno;- t->visit_type = r != 0 ? r : TREE_ERROR_DIR;- return (t->visit_type);- }-#if defined(USE_READDIR_R)- dirent_size = offsetof(struct dirent, d_name) +- t->filesystem_table[t->current->filesystem_id].name_max + 1;- if (t->dirent == NULL || t->dirent_allocated < dirent_size) {- free(t->dirent);- t->dirent = malloc(dirent_size);- if (t->dirent == NULL) {- closedir(t->d);- t->d = INVALID_DIR_HANDLE;- (void)tree_ascend(t);- tree_pop(t);- t->tree_errno = ENOMEM;- t->visit_type = TREE_ERROR_DIR;- return (t->visit_type);- }- t->dirent_allocated = dirent_size;- }-#endif /* USE_READDIR_R */- }- for (;;) {- errno = 0;-#if defined(USE_READDIR_R)- r = readdir_r(t->d, t->dirent, &t->de);-#ifdef _AIX- /* Note: According to the man page, return value 9 indicates- * that the readdir_r was not successful and the error code- * is set to the global errno variable. And then if the end- * of directory entries was reached, the return value is 9- * and the third parameter is set to NULL and errno is- * unchanged. */- if (r == 9)- r = errno;-#endif /* _AIX */- if (r != 0 || t->de == NULL) {-#else- t->de = readdir(t->d);- if (t->de == NULL) {- r = errno;-#endif- closedir(t->d);- t->d = INVALID_DIR_HANDLE;- if (r != 0) {- t->tree_errno = r;- t->visit_type = TREE_ERROR_DIR;- return (t->visit_type);- } else- return (0);- }- name = t->de->d_name;- namelen = D_NAMELEN(t->de);- t->flags &= ~hasLstat;- t->flags &= ~hasStat;- if (name[0] == '.' && name[1] == '\0')- continue;- if (name[0] == '.' && name[1] == '.' && name[2] == '\0')- continue;- tree_append(t, name, namelen);- return (t->visit_type = TREE_REGULAR);- }-}---/*- * Get the stat() data for the entry just returned from tree_next().- */-static const struct stat *-tree_current_stat(struct tree *t)-{- if (!(t->flags & hasStat)) {-#ifdef HAVE_FSTATAT- if (fstatat(tree_current_dir_fd(t),- tree_current_access_path(t), &t->st, 0) != 0)-#else- if (tree_enter_working_dir(t) != 0)- return NULL;- if (la_stat(tree_current_access_path(t), &t->st) != 0)-#endif- return NULL;- t->flags |= hasStat;- }- return (&t->st);-}--/*- * Get the lstat() data for the entry just returned from tree_next().- */-static const struct stat *-tree_current_lstat(struct tree *t)-{- if (!(t->flags & hasLstat)) {-#ifdef HAVE_FSTATAT- if (fstatat(tree_current_dir_fd(t),- tree_current_access_path(t), &t->lst,- AT_SYMLINK_NOFOLLOW) != 0)-#else- if (tree_enter_working_dir(t) != 0)- return NULL;-#ifdef HAVE_LSTAT- if (lstat(tree_current_access_path(t), &t->lst) != 0)-#else- if (la_stat(tree_current_access_path(t), &t->lst) != 0)-#endif-#endif- return NULL;- t->flags |= hasLstat;- }- return (&t->lst);-}--/*- * Test whether current entry is a dir or link to a dir.- */-static int-tree_current_is_dir(struct tree *t)-{- const struct stat *st;- /*- * If we already have lstat() info, then try some- * cheap tests to determine if this is a dir.- */- if (t->flags & hasLstat) {- /* If lstat() says it's a dir, it must be a dir. */- st = tree_current_lstat(t);- if (st == NULL)- return 0;- if (S_ISDIR(st->st_mode))- return 1;- /* Not a dir; might be a link to a dir. */- /* If it's not a link, then it's not a link to a dir. */- if (!S_ISLNK(st->st_mode))- return 0;- /*- * It's a link, but we don't know what it's a link to,- * so we'll have to use stat().- */- }-- st = tree_current_stat(t);- /* If we can't stat it, it's not a dir. */- if (st == NULL)- return 0;- /* Use the definitive test. Hopefully this is cached. */- return (S_ISDIR(st->st_mode));-}--/*- * Test whether current entry is a physical directory. Usually, we- * already have at least one of stat() or lstat() in memory, so we- * use tricks to try to avoid an extra trip to the disk.- */-static int-tree_current_is_physical_dir(struct tree *t)-{- const struct stat *st;-- /*- * If stat() says it isn't a dir, then it's not a dir.- * If stat() data is cached, this check is free, so do it first.- */- if (t->flags & hasStat) {- st = tree_current_stat(t);- if (st == NULL)- return (0);- if (!S_ISDIR(st->st_mode))- return (0);- }-- /*- * Either stat() said it was a dir (in which case, we have- * to determine whether it's really a link to a dir) or- * stat() info wasn't available. So we use lstat(), which- * hopefully is already cached.- */-- st = tree_current_lstat(t);- /* If we can't stat it, it's not a dir. */- if (st == NULL)- return 0;- /* Use the definitive test. Hopefully this is cached. */- return (S_ISDIR(st->st_mode));-}--/*- * Test whether the same file has been in the tree as its parent.- */-static int-tree_target_is_same_as_parent(struct tree *t, const struct stat *st)-{- struct tree_entry *te;-- for (te = t->current->parent; te != NULL; te = te->parent) {- if (te->dev == (int64_t)st->st_dev &&- te->ino == (int64_t)st->st_ino)- return (1);- }- return (0);-}--/*- * Test whether the current file is symbolic link target and- * on the other filesystem.- */-static int-tree_current_is_symblic_link_target(struct tree *t)-{- static const struct stat *lst, *st;-- lst = tree_current_lstat(t);- st = tree_current_stat(t);- return (st != NULL && lst != NULL &&- (int64_t)st->st_dev == t->current_filesystem->dev &&- st->st_dev != lst->st_dev);-}--/*- * Return the access path for the entry just returned from tree_next().- */-static const char *-tree_current_access_path(struct tree *t)-{- return (t->basename);-}--/*- * Return the full path for the entry just returned from tree_next().- */-static const char *-tree_current_path(struct tree *t)-{- return (t->path.s);-}--/*- * Terminate the traversal.- */-static void-tree_close(struct tree *t)-{-- if (t == NULL)- return;- if (t->entry_fd >= 0) {- close_and_restore_time(t->entry_fd, t, &t->restore_time);- t->entry_fd = -1;- }- /* Close the handle of readdir(). */- if (t->d != INVALID_DIR_HANDLE) {- closedir(t->d);- t->d = INVALID_DIR_HANDLE;- }- /* Release anything remaining in the stack. */- while (t->stack != NULL) {- if (t->stack->flags & isDirLink)- close(t->stack->symlink_parent_fd);- tree_pop(t);- }- if (t->working_dir_fd >= 0) {- close(t->working_dir_fd);- t->working_dir_fd = -1;- }- if (t->initial_dir_fd >= 0) {- close(t->initial_dir_fd);- t->initial_dir_fd = -1;- }-}--/*- * Release any resources.- */-static void-tree_free(struct tree *t)-{- int i;-- if (t == NULL)- return;- archive_string_free(&t->path);-#if defined(USE_READDIR_R)- free(t->dirent);-#endif- free(t->sparse_list);- for (i = 0; i < t->max_filesystem_id; i++)- free(t->filesystem_table[i].allocation_ptr);- free(t->filesystem_table);- free(t);-}--#endif
− c/archive_read_disk_private.h
@@ -1,98 +0,0 @@-/*-- * Copyright (c) 2003-2009 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD: head/lib/libarchive/archive_read_disk_private.h 201105 2009-12-28 03:20:54Z kientzle $- */--#ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED-#define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--#include "archive_platform_acl.h"--struct tree;-struct archive_entry;--struct archive_read_disk {- struct archive archive;-- /* Reused by archive_read_next_header() */- struct archive_entry *entry;-- /*- * Symlink mode is one of 'L'ogical, 'P'hysical, or 'H'ybrid,- * following an old BSD convention. 'L' follows all symlinks,- * 'P' follows none, 'H' follows symlinks only for the first- * item.- */- char symlink_mode;-- /*- * Since symlink interaction changes, we need to track whether- * we're following symlinks for the current item. 'L' mode above- * sets this true, 'P' sets it false, 'H' changes it as we traverse.- */- char follow_symlinks; /* Either 'L' or 'P'. */-- /* Directory traversals. */- struct tree *tree;- int (*open_on_current_dir)(struct tree*, const char *, int);- int (*tree_current_dir_fd)(struct tree*);- int (*tree_enter_working_dir)(struct tree*);-- /* Bitfield with ARCHIVE_READDISK_* tunables */- int flags;-- const char * (*lookup_gname)(void *private, int64_t gid);- void (*cleanup_gname)(void *private);- void *lookup_gname_data;- const char * (*lookup_uname)(void *private, int64_t uid);- void (*cleanup_uname)(void *private);- void *lookup_uname_data;-- int (*metadata_filter_func)(struct archive *, void *,- struct archive_entry *);- void *metadata_filter_data;-- /* ARCHIVE_MATCH object. */- struct archive *matching;- /* Callback function, this will be invoked when ARCHIVE_MATCH- * archive_match_*_excluded_ae return true. */- void (*excluded_cb_func)(struct archive *, void *,- struct archive_entry *);- void *excluded_cb_data;-};--const char *-archive_read_disk_entry_setup_path(struct archive_read_disk *,- struct archive_entry *, int *);--int-archive_read_disk_entry_setup_acls(struct archive_read_disk *,- struct archive_entry *, int *);-#endif
− c/archive_read_disk_set_standard_lookup.c
@@ -1,313 +0,0 @@-/*-- * 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_read_disk_set_standard_lookup.c 201109 2009-12-28 03:30:31Z kientzle $");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_GRP_H-#include <grp.h>-#endif-#ifdef HAVE_PWD_H-#include <pwd.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"--#if defined(_WIN32) && !defined(__CYGWIN__)-int-archive_read_disk_set_standard_lookup(struct archive *a)-{- archive_set_error(a, -1, "Standard lookups not available on Windows");- return (ARCHIVE_FATAL);-}-#else /* ! (_WIN32 && !__CYGWIN__) */-#define name_cache_size 127--static const char * const NO_NAME = "(noname)";--struct name_cache {- struct archive *archive;- char *buff;- size_t buff_size;- int probes;- int hits;- size_t size;- struct {- id_t id;- const char *name;- } cache[name_cache_size];-};--static const char * lookup_gname(void *, int64_t);-static const char * lookup_uname(void *, int64_t);-static void cleanup(void *);-static const char * lookup_gname_helper(struct name_cache *, id_t gid);-static const char * lookup_uname_helper(struct name_cache *, id_t uid);--/*- * Installs functions that use getpwuid()/getgrgid()---along with- * a simple cache to accelerate such lookups---into the archive_read_disk- * object. This is in a separate file because getpwuid()/getgrgid()- * can pull in a LOT of library code (including NIS/LDAP functions, which- * pull in DNS resolvers, etc). This can easily top 500kB, which makes- * it inappropriate for some space-constrained applications.- *- * Applications that are size-sensitive may want to just use the- * real default functions (defined in archive_read_disk.c) that just- * use the uid/gid without the lookup. Or define your own custom functions- * if you prefer.- */-int-archive_read_disk_set_standard_lookup(struct archive *a)-{- struct name_cache *ucache = malloc(sizeof(struct name_cache));- struct name_cache *gcache = malloc(sizeof(struct name_cache));-- if (ucache == NULL || gcache == NULL) {- archive_set_error(a, ENOMEM,- "Can't allocate uname/gname lookup cache");- free(ucache);- free(gcache);- return (ARCHIVE_FATAL);- }-- memset(ucache, 0, sizeof(*ucache));- ucache->archive = a;- ucache->size = name_cache_size;- memset(gcache, 0, sizeof(*gcache));- gcache->archive = a;- gcache->size = name_cache_size;-- archive_read_disk_set_gname_lookup(a, gcache, lookup_gname, cleanup);- archive_read_disk_set_uname_lookup(a, ucache, lookup_uname, cleanup);-- return (ARCHIVE_OK);-}--static void-cleanup(void *data)-{- struct name_cache *cache = (struct name_cache *)data;- size_t i;-- if (cache != NULL) {- for (i = 0; i < cache->size; i++) {- if (cache->cache[i].name != NULL &&- cache->cache[i].name != NO_NAME)- free((void *)(uintptr_t)cache->cache[i].name);- }- free(cache->buff);- free(cache);- }-}--/*- * Lookup uid/gid from uname/gname, return NULL if no match.- */-static const char *-lookup_name(struct name_cache *cache,- const char * (*lookup_fn)(struct name_cache *, id_t), id_t id)-{- const char *name;- int slot;--- cache->probes++;-- slot = id % cache->size;- if (cache->cache[slot].name != NULL) {- if (cache->cache[slot].id == id) {- cache->hits++;- if (cache->cache[slot].name == NO_NAME)- return (NULL);- return (cache->cache[slot].name);- }- if (cache->cache[slot].name != NO_NAME)- free((void *)(uintptr_t)cache->cache[slot].name);- cache->cache[slot].name = NULL;- }-- name = (lookup_fn)(cache, id);- if (name == NULL) {- /* Cache and return the negative response. */- cache->cache[slot].name = NO_NAME;- cache->cache[slot].id = id;- return (NULL);- }-- cache->cache[slot].name = name;- cache->cache[slot].id = id;- return (cache->cache[slot].name);-}--static const char *-lookup_uname(void *data, int64_t uid)-{- struct name_cache *uname_cache = (struct name_cache *)data;- return (lookup_name(uname_cache,- &lookup_uname_helper, (id_t)uid));-}--#if HAVE_GETPWUID_R-static const char *-lookup_uname_helper(struct name_cache *cache, id_t id)-{- struct passwd pwent, *result;- char * nbuff;- size_t nbuff_size;- int r;-- if (cache->buff_size == 0) {- cache->buff_size = 256;- cache->buff = malloc(cache->buff_size);- }- if (cache->buff == NULL)- return (NULL);- for (;;) {- result = &pwent; /* Old getpwuid_r ignores last arg. */- r = getpwuid_r((uid_t)id, &pwent,- cache->buff, cache->buff_size, &result);- if (r == 0)- break;- if (r != ERANGE)- break;- /* ERANGE means our buffer was too small, but POSIX- * doesn't tell us how big the buffer should be, so- * we just double it and try again. Because the buffer- * is kept around in the cache object, we shouldn't- * have to do this very often. */- nbuff_size = cache->buff_size * 2;- nbuff = realloc(cache->buff, nbuff_size);- if (nbuff == NULL)- break;- cache->buff = nbuff;- cache->buff_size = nbuff_size;- }- if (r != 0) {- archive_set_error(cache->archive, errno,- "Can't lookup user for id %d", (int)id);- return (NULL);- }- if (result == NULL)- return (NULL);-- return strdup(result->pw_name);-}-#else-static const char *-lookup_uname_helper(struct name_cache *cache, id_t id)-{- struct passwd *result;- (void)cache; /* UNUSED */-- result = getpwuid((uid_t)id);-- if (result == NULL)- return (NULL);-- return strdup(result->pw_name);-}-#endif--static const char *-lookup_gname(void *data, int64_t gid)-{- struct name_cache *gname_cache = (struct name_cache *)data;- return (lookup_name(gname_cache,- &lookup_gname_helper, (id_t)gid));-}--#if HAVE_GETGRGID_R-static const char *-lookup_gname_helper(struct name_cache *cache, id_t id)-{- struct group grent, *result;- char * nbuff;- size_t nbuff_size;- int r;-- if (cache->buff_size == 0) {- cache->buff_size = 256;- cache->buff = malloc(cache->buff_size);- }- if (cache->buff == NULL)- return (NULL);- for (;;) {- result = &grent; /* Old getgrgid_r ignores last arg. */- r = getgrgid_r((gid_t)id, &grent,- cache->buff, cache->buff_size, &result);- if (r == 0)- break;- if (r != ERANGE)- break;- /* ERANGE means our buffer was too small, but POSIX- * doesn't tell us how big the buffer should be, so- * we just double it and try again. */- nbuff_size = cache->buff_size * 2;- nbuff = realloc(cache->buff, nbuff_size);- if (nbuff == NULL)- break;- cache->buff = nbuff;- cache->buff_size = nbuff_size;- }- if (r != 0) {- archive_set_error(cache->archive, errno,- "Can't lookup group for id %d", (int)id);- return (NULL);- }- if (result == NULL)- return (NULL);-- return strdup(result->gr_name);-}-#else-static const char *-lookup_gname_helper(struct name_cache *cache, id_t id)-{- struct group *result;- (void)cache; /* UNUSED */-- result = getgrgid((gid_t)id);-- if (result == NULL)- return (NULL);-- return strdup(result->gr_name);-}-#endif--#endif /* ! (_WIN32 && !__CYGWIN__) */
− c/archive_read_disk_windows.c
@@ -1,2547 +0,0 @@-/*-- * Copyright (c) 2003-2009 Tim Kientzle- * Copyright (c) 2010-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */-#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#if defined(_WIN32) && !defined(__CYGWIN__)--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#include <winioctl.h>--#include "archive.h"-#include "archive_string.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_disk_private.h"--#ifndef O_BINARY-#define O_BINARY 0-#endif-#ifndef IO_REPARSE_TAG_SYMLINK-/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */-#define IO_REPARSE_TAG_SYMLINK 0xA000000CL-#endif--/*-- * This is a new directory-walking system that addresses a number- * of problems I've had with fts(3). In particular, it has no- * pathname-length limits (other than the size of 'int'), handles- * deep logical traversals, uses considerably less memory, and has- * an opaque interface (easier to modify in the future).- *- * Internally, it keeps a single list of "tree_entry" items that- * represent filesystem objects that require further attention.- * Non-directories are not kept in memory: they are pulled from- * readdir(), returned to the client, then freed as soon as possible.- * Any directory entry to be traversed gets pushed onto the stack.- *- * There is surprisingly little information that needs to be kept for- * each item on the stack. Just the name, depth (represented here as the- * string length of the parent directory's pathname), and some markers- * indicating how to get back to the parent (via chdir("..") for a- * regular dir or via fchdir(2) for a symlink).- */--struct restore_time {- const wchar_t *full_path;- FILETIME lastWriteTime;- FILETIME lastAccessTime;- mode_t filetype;-};--struct tree_entry {- int depth;- struct tree_entry *next;- struct tree_entry *parent;- size_t full_path_dir_length;- struct archive_wstring name;- struct archive_wstring full_path;- size_t dirname_length;- int64_t dev;- int64_t ino;- int flags;- int filesystem_id;- /* How to restore time of a directory. */- struct restore_time restore_time;-};--struct filesystem {- int64_t dev;- int synthetic;- int remote;- DWORD bytesPerSector;-};--/* Definitions for tree_entry.flags bitmap. */-#define isDir 1 /* This entry is a regular directory. */-#define isDirLink 2 /* This entry is a symbolic link to a directory. */-#define needsFirstVisit 4 /* This is an initial entry. */-#define needsDescent 8 /* This entry needs to be previsited. */-#define needsOpen 16 /* This is a directory that needs to be opened. */-#define needsAscent 32 /* This entry needs to be postvisited. */--/*- * On Windows, "first visit" is handled as a pattern to be handed to- * _findfirst(). This is consistent with Windows conventions that- * file patterns are handled within the application. On Posix,- * "first visit" is just returned to the client.- */--#define MAX_OVERLAPPED 8-#define READ_BUFFER_SIZE (1024 * 64) /* Default to 64KB per https://technet.microsoft.com/en-us/library/cc938632.aspx */-#define DIRECT_IO 0/* Disabled */-#define ASYNC_IO 1/* Enabled */--/*- * Local data for this package.- */-struct tree {- struct tree_entry *stack;- struct tree_entry *current;- HANDLE d;- WIN32_FIND_DATAW _findData;- WIN32_FIND_DATAW *findData;- int flags;- int visit_type;- /* Error code from last failed operation. */- int tree_errno;-- /* A full path with "\\?\" prefix. */- struct archive_wstring full_path;- size_t full_path_dir_length;- /* Dynamically-sized buffer for holding path */- struct archive_wstring path;-- /* Last path element */- const wchar_t *basename;- /* Leading dir length */- size_t dirname_length;-- int depth;-- BY_HANDLE_FILE_INFORMATION lst;- BY_HANDLE_FILE_INFORMATION st;- int descend;- /* How to restore time of a file. */- struct restore_time restore_time;-- struct entry_sparse {- int64_t length;- int64_t offset;- } *sparse_list, *current_sparse;- int sparse_count;- int sparse_list_size;-- char initial_symlink_mode;- char symlink_mode;- struct filesystem *current_filesystem;- struct filesystem *filesystem_table;- int initial_filesystem_id;- int current_filesystem_id;- int max_filesystem_id;- int allocated_filesystem;-- HANDLE entry_fh;- int entry_eof;- int64_t entry_remaining_bytes;- int64_t entry_total;-- int ol_idx_doing;- int ol_idx_done;- int ol_num_doing;- int ol_num_done;- int64_t ol_remaining_bytes;- int64_t ol_total;- struct la_overlapped {- OVERLAPPED ol;- struct archive * _a;- unsigned char *buff;- size_t buff_size;- int64_t offset;- size_t bytes_expected;- size_t bytes_transferred;- } ol[MAX_OVERLAPPED];- int direct_io;- int async_io;-};--#define bhfi_dev(bhfi) ((bhfi)->dwVolumeSerialNumber)-/* Treat FileIndex as i-node. We should remove a sequence number- * which is high-16-bits of nFileIndexHigh. */-#define bhfi_ino(bhfi) \- ((((int64_t)((bhfi)->nFileIndexHigh & 0x0000FFFFUL)) << 32) \- + (bhfi)->nFileIndexLow)--/* Definitions for tree.flags bitmap. */-#define hasStat 16 /* The st entry is valid. */-#define hasLstat 32 /* The lst entry is valid. */-#define needsRestoreTimes 128--static int-tree_dir_next_windows(struct tree *t, const wchar_t *pattern);--/* Initiate/terminate a tree traversal. */-static struct tree *tree_open(const wchar_t *, int, int);-static struct tree *tree_reopen(struct tree *, const wchar_t *, int);-static void tree_close(struct tree *);-static void tree_free(struct tree *);-static void tree_push(struct tree *, const wchar_t *, const wchar_t *,- int, int64_t, int64_t, struct restore_time *);--/*- * tree_next() returns Zero if there is no next entry, non-zero if- * there is. Note that directories are visited three times.- * Directories are always visited first as part of enumerating their- * parent; that is a "regular" visit. If tree_descend() is invoked at- * that time, the directory is added to a work list and will- * subsequently be visited two more times: once just after descending- * into the directory ("postdescent") and again just after ascending- * back to the parent ("postascent").- *- * TREE_ERROR_DIR is returned if the descent failed (because the- * directory couldn't be opened, for instance). This is returned- * instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a- * fatal error, but it does imply that the relevant subtree won't be- * visited. TREE_ERROR_FATAL is returned for an error that left the- * traversal completely hosed. Right now, this is only returned for- * chdir() failures during ascent.- */-#define TREE_REGULAR 1-#define TREE_POSTDESCENT 2-#define TREE_POSTASCENT 3-#define TREE_ERROR_DIR -1-#define TREE_ERROR_FATAL -2--static int tree_next(struct tree *);--/*- * Return information about the current entry.- */--/*- * The current full pathname, length of the full pathname, and a name- * that can be used to access the file. Because tree does use chdir- * extensively, the access path is almost never the same as the full- * current path.- *- */-static const wchar_t *tree_current_path(struct tree *);-static const wchar_t *tree_current_access_path(struct tree *);--/*- * Request the lstat() or stat() data for the current path. Since the- * tree package needs to do some of this anyway, and caches the- * results, you should take advantage of it here if you need it rather- * than make a redundant stat() or lstat() call of your own.- */-static const BY_HANDLE_FILE_INFORMATION *tree_current_stat(struct tree *);-static const BY_HANDLE_FILE_INFORMATION *tree_current_lstat(struct tree *);--/* The following functions use tricks to avoid a certain number of- * stat()/lstat() calls. */-/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */-static int tree_current_is_physical_dir(struct tree *);-/* "is_physical_link" is equivalent to S_ISLNK(tree_current_lstat()->st_mode) */-static int tree_current_is_physical_link(struct tree *);-/* Instead of archive_entry_copy_stat for BY_HANDLE_FILE_INFORMATION */-static void tree_archive_entry_copy_bhfi(struct archive_entry *,- struct tree *, const BY_HANDLE_FILE_INFORMATION *);-/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */-static int tree_current_is_dir(struct tree *);-static int update_current_filesystem(struct archive_read_disk *a,- int64_t dev);-static int setup_current_filesystem(struct archive_read_disk *);-static int tree_target_is_same_as_parent(struct tree *,- const BY_HANDLE_FILE_INFORMATION *);--static int _archive_read_disk_open_w(struct archive *, const wchar_t *);-static int _archive_read_free(struct archive *);-static int _archive_read_close(struct archive *);-static int _archive_read_data_block(struct archive *,- const void **, size_t *, int64_t *);-static int _archive_read_next_header(struct archive *,- struct archive_entry **);-static int _archive_read_next_header2(struct archive *,- struct archive_entry *);-static const char *trivial_lookup_gname(void *, int64_t gid);-static const char *trivial_lookup_uname(void *, int64_t uid);-static int setup_sparse(struct archive_read_disk *, struct archive_entry *);-static int close_and_restore_time(HANDLE, struct tree *,- struct restore_time *);-static int setup_sparse_from_disk(struct archive_read_disk *,- struct archive_entry *, HANDLE);-static int la_linkname_from_handle(HANDLE, wchar_t **, int *);-static int la_linkname_from_pathw(const wchar_t *, wchar_t **, int *);-static void entry_symlink_from_pathw(struct archive_entry *,- const wchar_t *path);--typedef struct _REPARSE_DATA_BUFFER {- ULONG ReparseTag;- USHORT ReparseDataLength;- USHORT Reserved;- union {- struct {- USHORT SubstituteNameOffset;- USHORT SubstituteNameLength;- USHORT PrintNameOffset;- USHORT PrintNameLength;- ULONG Flags;- WCHAR PathBuffer[1];- } SymbolicLinkReparseBuffer;- struct {- USHORT SubstituteNameOffset;- USHORT SubstituteNameLength;- USHORT PrintNameOffset;- USHORT PrintNameLength;- WCHAR PathBuffer[1];- } MountPointReparseBuffer;- struct {- UCHAR DataBuffer[1];- } GenericReparseBuffer;- } DUMMYUNIONNAME;-} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;--/*- * Reads the target of a symbolic link- *- * Returns 0 on success and -1 on failure- * outbuf is allocated in the function- */-static int-la_linkname_from_handle(HANDLE h, wchar_t **linkname, int *linktype)-{- DWORD inbytes;- REPARSE_DATA_BUFFER *buf;- BY_HANDLE_FILE_INFORMATION st;- size_t len;- BOOL ret;- BYTE *indata;- wchar_t *tbuf;-- ret = GetFileInformationByHandle(h, &st);- if (ret == 0 ||- (st.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {- return (-1);- }-- indata = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);- ret = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, indata,- 1024, &inbytes, NULL);- if (ret == 0) {- la_dosmaperr(GetLastError());- free(indata);- return (-1);- }-- buf = (REPARSE_DATA_BUFFER *) indata;- if (buf->ReparseTag != IO_REPARSE_TAG_SYMLINK) {- free(indata);- /* File is not a symbolic link */- errno = EINVAL;- return (-1);- }-- len = buf->SymbolicLinkReparseBuffer.SubstituteNameLength;- if (len <= 0) {- free(indata);- return (-1);- }-- tbuf = malloc(len + 1 * sizeof(wchar_t));- if (tbuf == NULL) {- free(indata);- return (-1);- }-- memcpy(tbuf, &((BYTE *)buf->SymbolicLinkReparseBuffer.PathBuffer)- [buf->SymbolicLinkReparseBuffer.SubstituteNameOffset], len);- free(indata);-- tbuf[len / sizeof(wchar_t)] = L'\0';-- *linkname = tbuf;-- /*- * Translate backslashes to slashes for libarchive internal use- */- while(*tbuf != L'\0') {- if (*tbuf == L'\\')- *tbuf = L'/';- tbuf++;- }-- if ((st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)- *linktype = AE_SYMLINK_TYPE_FILE;- else- *linktype = AE_SYMLINK_TYPE_DIRECTORY;-- return (0);-}--/*- * Returns AE_SYMLINK_TYPE_FILE, AE_SYMLINK_TYPE_DIRECTORY or -1 on error- */-static int-la_linkname_from_pathw(const wchar_t *path, wchar_t **outbuf, int *linktype)-{- HANDLE h;- const DWORD flag = FILE_FLAG_BACKUP_SEMANTICS |- FILE_FLAG_OPEN_REPARSE_POINT;- int ret;--# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileFlags = flag;- h = CreateFile2(path, 0,- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,- OPEN_EXISTING, &createExParams);-#else- h = CreateFileW(path, 0,- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,- OPEN_EXISTING, flag, NULL);-#endif- if (h == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- return (-1);- }-- ret = la_linkname_from_handle(h, outbuf, linktype);- CloseHandle(h);-- return (ret);-}--static void-entry_symlink_from_pathw(struct archive_entry *entry, const wchar_t *path)-{- wchar_t *linkname = NULL;- int ret, linktype;-- ret = la_linkname_from_pathw(path, &linkname, &linktype);- if (ret != 0)- return;- if (linktype >= 0) {- archive_entry_copy_symlink_w(entry, linkname);- archive_entry_set_symlink_type(entry, linktype);- }- free(linkname);-- return;-}--static const struct archive_vtable-archive_read_disk_vtable = {- .archive_free = _archive_read_free,- .archive_close = _archive_read_close,- .archive_read_data_block = _archive_read_data_block,- .archive_read_next_header = _archive_read_next_header,- .archive_read_next_header2 = _archive_read_next_header2,-};--const char *-archive_read_disk_gname(struct archive *_a, la_int64_t gid)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_gname"))- return (NULL);- if (a->lookup_gname == NULL)- return (NULL);- return ((*a->lookup_gname)(a->lookup_gname_data, gid));-}--const char *-archive_read_disk_uname(struct archive *_a, la_int64_t uid)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_uname"))- return (NULL);- if (a->lookup_uname == NULL)- return (NULL);- return ((*a->lookup_uname)(a->lookup_uname_data, uid));-}--int-archive_read_disk_set_gname_lookup(struct archive *_a,- void *private_data,- const char * (*lookup_gname)(void *private, la_int64_t gid),- void (*cleanup_gname)(void *private))-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup");-- if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)- (a->cleanup_gname)(a->lookup_gname_data);-- a->lookup_gname = lookup_gname;- a->cleanup_gname = cleanup_gname;- a->lookup_gname_data = private_data;- return (ARCHIVE_OK);-}--int-archive_read_disk_set_uname_lookup(struct archive *_a,- void *private_data,- const char * (*lookup_uname)(void *private, int64_t uid),- void (*cleanup_uname)(void *private))-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup");-- if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)- (a->cleanup_uname)(a->lookup_uname_data);-- a->lookup_uname = lookup_uname;- a->cleanup_uname = cleanup_uname;- a->lookup_uname_data = private_data;- return (ARCHIVE_OK);-}--/*- * Create a new archive_read_disk object and initialize it with global state.- */-struct archive *-archive_read_disk_new(void)-{- struct archive_read_disk *a;-- a = (struct archive_read_disk *)calloc(1, sizeof(*a));- if (a == NULL)- return (NULL);- a->archive.magic = ARCHIVE_READ_DISK_MAGIC;- a->archive.state = ARCHIVE_STATE_NEW;- a->archive.vtable = &archive_read_disk_vtable;- a->entry = archive_entry_new2(&a->archive);- a->lookup_uname = trivial_lookup_uname;- a->lookup_gname = trivial_lookup_gname;- a->flags = ARCHIVE_READDISK_MAC_COPYFILE;- return (&a->archive);-}--static int-_archive_read_free(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- int r;-- if (_a == NULL)- return (ARCHIVE_OK);- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free");-- if (a->archive.state != ARCHIVE_STATE_CLOSED)- r = _archive_read_close(&a->archive);- else- r = ARCHIVE_OK;-- tree_free(a->tree);- if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)- (a->cleanup_gname)(a->lookup_gname_data);- if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)- (a->cleanup_uname)(a->lookup_uname_data);- archive_string_free(&a->archive.error_string);- archive_entry_free(a->entry);- a->archive.magic = 0;- free(a);- return (r);-}--static int-_archive_read_close(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close");-- if (a->archive.state != ARCHIVE_STATE_FATAL)- a->archive.state = ARCHIVE_STATE_CLOSED;-- tree_close(a->tree);-- return (ARCHIVE_OK);-}--static void-setup_symlink_mode(struct archive_read_disk *a, char symlink_mode, - int follow_symlinks)-{- a->symlink_mode = symlink_mode;- a->follow_symlinks = follow_symlinks;- if (a->tree != NULL) {- a->tree->initial_symlink_mode = a->symlink_mode;- a->tree->symlink_mode = a->symlink_mode;- }-}--int-archive_read_disk_set_symlink_logical(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_logical");- setup_symlink_mode(a, 'L', 1);- return (ARCHIVE_OK);-}--int-archive_read_disk_set_symlink_physical(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_physical");- setup_symlink_mode(a, 'P', 0);- return (ARCHIVE_OK);-}--int-archive_read_disk_set_symlink_hybrid(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_hybrid");- setup_symlink_mode(a, 'H', 1);/* Follow symlinks initially. */- return (ARCHIVE_OK);-}--int-archive_read_disk_set_atime_restored(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime");- a->flags |= ARCHIVE_READDISK_RESTORE_ATIME;- if (a->tree != NULL)- a->tree->flags |= needsRestoreTimes;- return (ARCHIVE_OK);-}--int-archive_read_disk_set_behavior(struct archive *_a, int flags)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- int r = ARCHIVE_OK;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");-- a->flags = flags;-- if (flags & ARCHIVE_READDISK_RESTORE_ATIME)- r = archive_read_disk_set_atime_restored(_a);- else {- if (a->tree != NULL)- a->tree->flags &= ~needsRestoreTimes;- }- return (r);-}--/*- * Trivial implementations of gname/uname lookup functions.- * These are normally overridden by the client, but these stub- * versions ensure that we always have something that works.- */-static const char *-trivial_lookup_gname(void *private_data, int64_t gid)-{- (void)private_data; /* UNUSED */- (void)gid; /* UNUSED */- return (NULL);-}--static const char *-trivial_lookup_uname(void *private_data, int64_t uid)-{- (void)private_data; /* UNUSED */- (void)uid; /* UNUSED */- return (NULL);-}--static int64_t-align_num_per_sector(struct tree *t, int64_t size)-{- int64_t surplus;-- size += t->current_filesystem->bytesPerSector -1;- surplus = size % t->current_filesystem->bytesPerSector;- size -= surplus;- return (size);-}--static int-start_next_async_read(struct archive_read_disk *a, struct tree *t)-{- struct la_overlapped *olp;- DWORD buffbytes, rbytes;-- if (t->ol_remaining_bytes == 0)- return (ARCHIVE_EOF);-- olp = &(t->ol[t->ol_idx_doing]);- t->ol_idx_doing = (t->ol_idx_doing + 1) % MAX_OVERLAPPED;-- /* Allocate read buffer. */- if (olp->buff == NULL) {- void *p;- size_t s = (size_t)align_num_per_sector(t, READ_BUFFER_SIZE);- p = VirtualAlloc(NULL, s, MEM_COMMIT, PAGE_READWRITE);- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Couldn't allocate memory");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- olp->buff = p;- olp->buff_size = s;- olp->_a = &a->archive;- olp->ol.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);- if (olp->ol.hEvent == NULL) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "CreateEvent failed");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- } else- ResetEvent(olp->ol.hEvent);-- buffbytes = (DWORD)olp->buff_size;- if (buffbytes > t->current_sparse->length)- buffbytes = (DWORD)t->current_sparse->length;-- /* Skip hole. */- if (t->current_sparse->offset > t->ol_total) {- t->ol_remaining_bytes -=- t->current_sparse->offset - t->ol_total;- }-- olp->offset = t->current_sparse->offset;- olp->ol.Offset = (DWORD)(olp->offset & 0xffffffff);- olp->ol.OffsetHigh = (DWORD)(olp->offset >> 32);-- if (t->ol_remaining_bytes > buffbytes) {- olp->bytes_expected = buffbytes;- t->ol_remaining_bytes -= buffbytes;- } else {- olp->bytes_expected = (size_t)t->ol_remaining_bytes;- t->ol_remaining_bytes = 0;- }- olp->bytes_transferred = 0;- t->current_sparse->offset += buffbytes;- t->current_sparse->length -= buffbytes;- t->ol_total = t->current_sparse->offset;- if (t->current_sparse->length == 0 && t->ol_remaining_bytes > 0)- t->current_sparse++;-- if (!ReadFile(t->entry_fh, olp->buff, buffbytes, &rbytes, &(olp->ol))) {- DWORD lasterr;-- lasterr = GetLastError();- if (lasterr == ERROR_HANDLE_EOF) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Reading file truncated");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- } else if (lasterr != ERROR_IO_PENDING) {- if (lasterr == ERROR_NO_DATA)- errno = EAGAIN;- else if (lasterr == ERROR_ACCESS_DENIED)- errno = EBADF;- else- la_dosmaperr(lasterr);- archive_set_error(&a->archive, errno, "Read error");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- } else- olp->bytes_transferred = rbytes;- t->ol_num_doing++;-- return (t->ol_remaining_bytes == 0)? ARCHIVE_EOF: ARCHIVE_OK;-}--static void-cancel_async(struct tree *t)-{- if (t->ol_num_doing != t->ol_num_done) {- CancelIo(t->entry_fh);- t->ol_num_doing = t->ol_num_done = 0;- }-}--static int-_archive_read_data_block(struct archive *_a, const void **buff,- size_t *size, int64_t *offset)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- struct tree *t = a->tree;- struct la_overlapped *olp;- DWORD bytes_transferred;- int r = ARCHIVE_FATAL;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_data_block");-- if (t->entry_eof || t->entry_remaining_bytes <= 0) {- r = ARCHIVE_EOF;- goto abort_read_data;- }-- /*- * Make a request to read the file in asynchronous.- */- if (t->ol_num_doing == 0) {- do {- r = start_next_async_read(a, t);- if (r == ARCHIVE_FATAL)- goto abort_read_data;- if (!t->async_io)- break;- } while (r == ARCHIVE_OK && t->ol_num_doing < MAX_OVERLAPPED);- } else {- if ((r = start_next_async_read(a, t)) == ARCHIVE_FATAL)- goto abort_read_data;- }-- olp = &(t->ol[t->ol_idx_done]);- t->ol_idx_done = (t->ol_idx_done + 1) % MAX_OVERLAPPED;- if (olp->bytes_transferred)- bytes_transferred = (DWORD)olp->bytes_transferred;- else if (!GetOverlappedResult(t->entry_fh, &(olp->ol),- &bytes_transferred, TRUE)) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "GetOverlappedResult failed");- a->archive.state = ARCHIVE_STATE_FATAL;- r = ARCHIVE_FATAL;- goto abort_read_data;- }- t->ol_num_done++;-- if (bytes_transferred == 0 ||- olp->bytes_expected != bytes_transferred) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Reading file truncated");- a->archive.state = ARCHIVE_STATE_FATAL;- r = ARCHIVE_FATAL;- goto abort_read_data;- }-- *buff = olp->buff;- *size = bytes_transferred;- *offset = olp->offset;- if (olp->offset > t->entry_total)- t->entry_remaining_bytes -= olp->offset - t->entry_total;- t->entry_total = olp->offset + *size;- t->entry_remaining_bytes -= *size;- if (t->entry_remaining_bytes == 0) {- /* Close the current file descriptor */- close_and_restore_time(t->entry_fh, t, &t->restore_time);- t->entry_fh = INVALID_HANDLE_VALUE;- t->entry_eof = 1;- }- return (ARCHIVE_OK);--abort_read_data:- *buff = NULL;- *size = 0;- *offset = t->entry_total;- if (t->entry_fh != INVALID_HANDLE_VALUE) {- cancel_async(t);- /* Close the current file descriptor */- close_and_restore_time(t->entry_fh, t, &t->restore_time);- t->entry_fh = INVALID_HANDLE_VALUE;- }- return (r);-}--static int-next_entry(struct archive_read_disk *a, struct tree *t,- struct archive_entry *entry)-{- const BY_HANDLE_FILE_INFORMATION *st;- const BY_HANDLE_FILE_INFORMATION *lst;- const char*name;- int descend, r;-- st = NULL;- lst = NULL;- t->descend = 0;- do {- switch (tree_next(t)) {- case TREE_ERROR_FATAL:- archive_set_error(&a->archive, t->tree_errno,- "%ls: Unable to continue traversing directory tree",- tree_current_path(t));- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- case TREE_ERROR_DIR:- archive_set_error(&a->archive, t->tree_errno,- "%ls: Couldn't visit directory",- tree_current_path(t));- return (ARCHIVE_FAILED);- case 0:- return (ARCHIVE_EOF);- case TREE_POSTDESCENT:- case TREE_POSTASCENT:- break;- case TREE_REGULAR:- lst = tree_current_lstat(t);- if (lst == NULL) {- archive_set_error(&a->archive, t->tree_errno,- "%ls: Cannot stat",- tree_current_path(t));- return (ARCHIVE_FAILED);- }- break;- } - } while (lst == NULL);-- archive_entry_copy_pathname_w(entry, tree_current_path(t));-- /*- * Perform path matching.- */- if (a->matching) {- r = archive_match_path_excluded(a->matching, entry);- if (r < 0) {- archive_set_error(&(a->archive), errno,- "Failed : %s", archive_error_string(a->matching));- return (r);- }- if (r) {- if (a->excluded_cb_func)- a->excluded_cb_func(&(a->archive),- a->excluded_cb_data, entry);- return (ARCHIVE_RETRY);- }- }-- /*- * Distinguish 'L'/'P'/'H' symlink following.- */- switch(t->symlink_mode) {- case 'H':- /* 'H': After the first item, rest like 'P'. */- t->symlink_mode = 'P';- /* 'H': First item (from command line) like 'L'. */- /* FALLTHROUGH */- case 'L':- /* 'L': Do descend through a symlink to dir. */- descend = tree_current_is_dir(t);- /* 'L': Follow symlinks to files. */- a->symlink_mode = 'L';- a->follow_symlinks = 1;- /* 'L': Archive symlinks as targets, if we can. */- st = tree_current_stat(t);- if (st != NULL && !tree_target_is_same_as_parent(t, st))- break;- /* If stat fails, we have a broken symlink;- * in that case, don't follow the link. */- /* FALLTHROUGH */- default:- /* 'P': Don't descend through a symlink to dir. */- descend = tree_current_is_physical_dir(t);- /* 'P': Don't follow symlinks to files. */- a->symlink_mode = 'P';- a->follow_symlinks = 0;- /* 'P': Archive symlinks as symlinks. */- st = lst;- break;- }-- if (update_current_filesystem(a, bhfi_dev(st)) != ARCHIVE_OK) {- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- if (t->initial_filesystem_id == -1)- t->initial_filesystem_id = t->current_filesystem_id;- if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) {- if (t->initial_filesystem_id != t->current_filesystem_id)- return (ARCHIVE_RETRY);- }- t->descend = descend;-- tree_archive_entry_copy_bhfi(entry, t, st);-- /* Save the times to be restored. This must be in before- * calling archive_read_disk_descend() or any chance of it,- * especially, invoking a callback. */- t->restore_time.lastWriteTime = st->ftLastWriteTime;- t->restore_time.lastAccessTime = st->ftLastAccessTime;- t->restore_time.filetype = archive_entry_filetype(entry);-- /*- * Perform time matching.- */- if (a->matching) {- r = archive_match_time_excluded(a->matching, entry);- if (r < 0) {- archive_set_error(&(a->archive), errno,- "Failed : %s", archive_error_string(a->matching));- return (r);- }- if (r) {- if (a->excluded_cb_func)- a->excluded_cb_func(&(a->archive),- a->excluded_cb_data, entry);- return (ARCHIVE_RETRY);- }- }-- /* Lookup uname/gname */- name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry));- if (name != NULL)- archive_entry_copy_uname(entry, name);- name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry));- if (name != NULL)- archive_entry_copy_gname(entry, name);-- /*- * Perform owner matching.- */- if (a->matching) {- r = archive_match_owner_excluded(a->matching, entry);- if (r < 0) {- archive_set_error(&(a->archive), errno,- "Failed : %s", archive_error_string(a->matching));- return (r);- }- if (r) {- if (a->excluded_cb_func)- a->excluded_cb_func(&(a->archive),- a->excluded_cb_data, entry);- return (ARCHIVE_RETRY);- }- }-- /*- * File attributes- */- if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0) {- const int supported_attrs =- FILE_ATTRIBUTE_READONLY |- FILE_ATTRIBUTE_HIDDEN |- FILE_ATTRIBUTE_SYSTEM;- DWORD file_attrs = st->dwFileAttributes & supported_attrs;- if (file_attrs != 0)- archive_entry_set_fflags(entry, file_attrs, 0);- }-- /*- * Invoke a meta data filter callback.- */- if (a->metadata_filter_func) {- if (!a->metadata_filter_func(&(a->archive),- a->metadata_filter_data, entry))- return (ARCHIVE_RETRY);- }-- archive_entry_copy_sourcepath_w(entry, tree_current_access_path(t));-- r = ARCHIVE_OK;- if (archive_entry_filetype(entry) == AE_IFREG &&- archive_entry_size(entry) > 0) {- DWORD flags = FILE_FLAG_BACKUP_SEMANTICS;-#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;-#endif- if (t->async_io)- flags |= FILE_FLAG_OVERLAPPED;- if (t->direct_io)- flags |= FILE_FLAG_NO_BUFFERING;- else- flags |= FILE_FLAG_SEQUENTIAL_SCAN;-#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileFlags = flags;- t->entry_fh = CreateFile2(tree_current_access_path(t),- GENERIC_READ,- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,- OPEN_EXISTING, &createExParams);-#else- t->entry_fh = CreateFileW(tree_current_access_path(t),- GENERIC_READ,- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,- NULL, OPEN_EXISTING, flags, NULL);-#endif- if (t->entry_fh == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "Couldn't open %ls", tree_current_path(a->tree));- return (ARCHIVE_FAILED);- }-- /* Find sparse data from the disk. */- if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) {- if (archive_entry_hardlink(entry) == NULL &&- (st->dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0)- r = setup_sparse_from_disk(a, entry, t->entry_fh);- }- }- return (r);-}--static int-_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)-{- int ret;- struct archive_read_disk *a = (struct archive_read_disk *)_a;- *entryp = NULL;- ret = _archive_read_next_header2(_a, a->entry);- *entryp = a->entry;- return ret;-}--static int-_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- struct tree *t;- int r;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_read_next_header2");-- t = a->tree;- if (t->entry_fh != INVALID_HANDLE_VALUE) {- cancel_async(t);- close_and_restore_time(t->entry_fh, t, &t->restore_time);- t->entry_fh = INVALID_HANDLE_VALUE;- }-- archive_entry_clear(entry);-- while ((r = next_entry(a, t, entry)) == ARCHIVE_RETRY)- archive_entry_clear(entry);-- /*- * EOF and FATAL are persistent at this layer. By- * modifying the state, we guarantee that future calls to- * read a header or read data will fail.- */- switch (r) {- case ARCHIVE_EOF:- a->archive.state = ARCHIVE_STATE_EOF;- break;- case ARCHIVE_OK:- case ARCHIVE_WARN:- t->entry_total = 0;- if (archive_entry_filetype(entry) == AE_IFREG) {- t->entry_remaining_bytes = archive_entry_size(entry);- t->entry_eof = (t->entry_remaining_bytes == 0)? 1: 0;- if (!t->entry_eof &&- setup_sparse(a, entry) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- } else {- t->entry_remaining_bytes = 0;- t->entry_eof = 1;- }- t->ol_idx_doing = t->ol_idx_done = 0;- t->ol_num_doing = t->ol_num_done = 0;- t->ol_remaining_bytes = t->entry_remaining_bytes;- t->ol_total = 0;- a->archive.state = ARCHIVE_STATE_DATA;- break;- case ARCHIVE_RETRY:- break;- case ARCHIVE_FATAL:- a->archive.state = ARCHIVE_STATE_FATAL;- break;- }-- __archive_reset_read_data(&a->archive);- return (r);-}--static int-setup_sparse(struct archive_read_disk *a, struct archive_entry *entry)-{- struct tree *t = a->tree;- int64_t aligned, length, offset;- int i;-- t->sparse_count = archive_entry_sparse_reset(entry);- if (t->sparse_count+1 > t->sparse_list_size) {- free(t->sparse_list);- t->sparse_list_size = t->sparse_count + 1;- t->sparse_list = malloc(sizeof(t->sparse_list[0]) *- t->sparse_list_size);- if (t->sparse_list == NULL) {- t->sparse_list_size = 0;- archive_set_error(&a->archive, ENOMEM,- "Can't allocate data");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- }- /*- * Get sparse list and make sure those offsets and lengths are- * aligned by a sector size.- */- for (i = 0; i < t->sparse_count; i++) {- archive_entry_sparse_next(entry, &offset, &length);- aligned = align_num_per_sector(t, offset);- if (aligned != offset) {- aligned -= t->current_filesystem->bytesPerSector;- length += offset - aligned;- }- t->sparse_list[i].offset = aligned;- aligned = align_num_per_sector(t, length);- t->sparse_list[i].length = aligned;- }-- aligned = align_num_per_sector(t, archive_entry_size(entry));- if (i == 0) {- t->sparse_list[i].offset = 0;- t->sparse_list[i].length = aligned;- } else {- int j, last = i;-- t->sparse_list[i].offset = aligned;- t->sparse_list[i].length = 0;- for (i = 0; i < last; i++) {- if ((t->sparse_list[i].offset +- t->sparse_list[i].length) <= - t->sparse_list[i+1].offset)- continue;- /*- * Now sparse_list[i+1] is overlapped by sparse_list[i].- * Merge those two.- */- length = t->sparse_list[i+1].offset -- t->sparse_list[i].offset;- t->sparse_list[i+1].offset = t->sparse_list[i].offset;- t->sparse_list[i+1].length += length;- /* Remove sparse_list[i]. */- for (j = i; j < last; j++) {- t->sparse_list[j].offset =- t->sparse_list[j+1].offset;- t->sparse_list[j].length =- t->sparse_list[j+1].length;- }- last--;- }- }- t->current_sparse = t->sparse_list;-- return (ARCHIVE_OK);-}--int-archive_read_disk_set_matching(struct archive *_a, struct archive *_ma,- void (*_excluded_func)(struct archive *, void *, struct archive_entry *),- void *_client_data)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_read_disk_set_matching");- a->matching = _ma;- a->excluded_cb_func = _excluded_func;- a->excluded_cb_data = _client_data;- return (ARCHIVE_OK);-}--int-archive_read_disk_set_metadata_filter_callback(struct archive *_a,- int (*_metadata_filter_func)(struct archive *, void *,- struct archive_entry *), void *_client_data)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY,- "archive_read_disk_set_metadata_filter_callback");-- a->metadata_filter_func = _metadata_filter_func;- a->metadata_filter_data = _client_data;- return (ARCHIVE_OK);-}--int-archive_read_disk_can_descend(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- struct tree *t = a->tree;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_read_disk_can_descend");-- return (t->visit_type == TREE_REGULAR && t->descend);-}--/*- * Called by the client to mark the directory just returned from- * tree_next() as needing to be visited.- */-int-archive_read_disk_descend(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- struct tree *t = a->tree;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_read_disk_descend");-- if (!archive_read_disk_can_descend(_a))- return (ARCHIVE_OK);-- if (tree_current_is_physical_dir(t)) {- tree_push(t, t->basename, t->full_path.s,- t->current_filesystem_id,- bhfi_dev(&(t->lst)), bhfi_ino(&(t->lst)),- &t->restore_time);- t->stack->flags |= isDir;- } else if (tree_current_is_dir(t)) {- tree_push(t, t->basename, t->full_path.s,- t->current_filesystem_id,- bhfi_dev(&(t->st)), bhfi_ino(&(t->st)),- &t->restore_time);- t->stack->flags |= isDirLink;- }- t->descend = 0;- return (ARCHIVE_OK);-}--int-archive_read_disk_open(struct archive *_a, const char *pathname)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- struct archive_wstring wpath;- int ret;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED,- "archive_read_disk_open");- archive_clear_error(&a->archive);-- /* Make a wchar_t string from a char string. */- archive_string_init(&wpath);- if (archive_wstring_append_from_mbs(&wpath, pathname,- strlen(pathname)) != 0) {- if (errno == ENOMEM)- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't convert a path to a wchar_t string");- a->archive.state = ARCHIVE_STATE_FATAL;- ret = ARCHIVE_FATAL;- } else- ret = _archive_read_disk_open_w(_a, wpath.s);-- archive_wstring_free(&wpath);- return (ret);-}--int-archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,- ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED,- "archive_read_disk_open_w");- archive_clear_error(&a->archive);-- return (_archive_read_disk_open_w(_a, pathname));-}--static int-_archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- if (a->tree != NULL)- a->tree = tree_reopen(a->tree, pathname,- a->flags & ARCHIVE_READDISK_RESTORE_ATIME);- else- a->tree = tree_open(pathname, a->symlink_mode,- a->flags & ARCHIVE_READDISK_RESTORE_ATIME);- if (a->tree == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate directory traversal data");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- a->archive.state = ARCHIVE_STATE_HEADER;-- return (ARCHIVE_OK);-}--/*- * Return a current filesystem ID which is index of the filesystem entry- * you've visited through archive_read_disk.- */-int-archive_read_disk_current_filesystem(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_disk_current_filesystem");-- return (a->tree->current_filesystem_id);-}--static int-update_current_filesystem(struct archive_read_disk *a, int64_t dev)-{- struct tree *t = a->tree;- int i, fid;-- if (t->current_filesystem != NULL &&- t->current_filesystem->dev == dev)- return (ARCHIVE_OK);-- for (i = 0; i < t->max_filesystem_id; i++) {- if (t->filesystem_table[i].dev == dev) {- /* There is the filesystem ID we've already generated. */- t->current_filesystem_id = i;- t->current_filesystem = &(t->filesystem_table[i]);- return (ARCHIVE_OK);- }- }-- /*- * There is a new filesystem, we generate a new ID for.- */- fid = t->max_filesystem_id++;- if (t->max_filesystem_id > t->allocated_filesystem) {- size_t s;- void *p;-- s = t->max_filesystem_id * 2;- p = realloc(t->filesystem_table,- s * sizeof(*t->filesystem_table));- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate tar data");- return (ARCHIVE_FATAL);- }- t->filesystem_table = (struct filesystem *)p;- t->allocated_filesystem = (int)s;- }- t->current_filesystem_id = fid;- t->current_filesystem = &(t->filesystem_table[fid]);- t->current_filesystem->dev = dev;-- return (setup_current_filesystem(a));-}--/*- * Returns 1 if current filesystem is generated filesystem, 0 if it is not- * or -1 if it is unknown.- */-int-archive_read_disk_current_filesystem_is_synthetic(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_disk_current_filesystem");-- return (a->tree->current_filesystem->synthetic);-}--/*- * Returns 1 if current filesystem is remote filesystem, 0 if it is not- * or -1 if it is unknown.- */-int-archive_read_disk_current_filesystem_is_remote(struct archive *_a)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;-- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,- "archive_read_disk_current_filesystem");-- return (a->tree->current_filesystem->remote);-}--/*- * If symlink is broken, statfs or statvfs will fail.- * Use its directory path instead.- */-static wchar_t *-safe_path_for_statfs(struct tree *t)-{- const wchar_t *path;- wchar_t *cp, *p = NULL;-- path = tree_current_access_path(t);- if (tree_current_stat(t) == NULL) {- p = _wcsdup(path);- cp = wcsrchr(p, '/');- if (cp != NULL && wcslen(cp) >= 2) {- cp[1] = '.';- cp[2] = '\0';- path = p;- }- } else- p = _wcsdup(path);- return (p);-}--/*- * Get conditions of synthetic and remote on Windows- */-static int-setup_current_filesystem(struct archive_read_disk *a)-{- struct tree *t = a->tree;- wchar_t vol[256];- wchar_t *path;-- t->current_filesystem->synthetic = -1;/* Not supported */- path = safe_path_for_statfs(t);- if (!GetVolumePathNameW(path, vol, sizeof(vol)/sizeof(vol[0]))) {- free(path);- t->current_filesystem->remote = -1;- t->current_filesystem->bytesPerSector = 0;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "GetVolumePathName failed: %d", (int)GetLastError());- return (ARCHIVE_FAILED);- }- free(path);- switch (GetDriveTypeW(vol)) {- case DRIVE_UNKNOWN:- case DRIVE_NO_ROOT_DIR:- t->current_filesystem->remote = -1;- break;- case DRIVE_REMOTE:- t->current_filesystem->remote = 1;- break;- default:- t->current_filesystem->remote = 0;- break;- }-- if (!GetDiskFreeSpaceW(vol, NULL,- &(t->current_filesystem->bytesPerSector), NULL, NULL)) {- t->current_filesystem->bytesPerSector = 0;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "GetDiskFreeSpace failed: %d", (int)GetLastError());- return (ARCHIVE_FAILED);- }-- return (ARCHIVE_OK);-}--static int-close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt)-{- HANDLE handle;- int r = 0;-#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;-#endif-- if (h == INVALID_HANDLE_VALUE && AE_IFLNK == rt->filetype)- return (0);-- /* Close a file descriptor.- * It will not be used for SetFileTime() because it has been opened- * by a read only mode.- */- if (h != INVALID_HANDLE_VALUE)- CloseHandle(h);- if ((t->flags & needsRestoreTimes) == 0)- return (r);--#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;- handle = CreateFile2(rt->full_path, FILE_WRITE_ATTRIBUTES,- 0, OPEN_EXISTING, &createExParams);-#else- handle = CreateFileW(rt->full_path, FILE_WRITE_ATTRIBUTES,- 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);-#endif- if (handle == INVALID_HANDLE_VALUE) {- errno = EINVAL;- return (-1);- }-- if (SetFileTime(handle, NULL, &rt->lastAccessTime,- &rt->lastWriteTime) == 0) {- errno = EINVAL;- r = -1;- } else- r = 0;- CloseHandle(handle);- return (r);-}--/*- * Add a directory path to the current stack.- */-static void-tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path,- int filesystem_id, int64_t dev, int64_t ino, struct restore_time *rt)-{- struct tree_entry *te;-- te = calloc(1, sizeof(*te));- te->next = t->stack;- te->parent = t->current;- if (te->parent)- te->depth = te->parent->depth + 1;- t->stack = te;- archive_string_init(&te->name);- archive_wstrcpy(&te->name, path);- archive_string_init(&te->full_path);- archive_wstrcpy(&te->full_path, full_path);- te->flags = needsDescent | needsOpen | needsAscent;- te->filesystem_id = filesystem_id;- te->dev = dev;- te->ino = ino;- te->dirname_length = t->dirname_length;- te->full_path_dir_length = t->full_path_dir_length;- te->restore_time.full_path = te->full_path.s;- if (rt != NULL) {- te->restore_time.lastWriteTime = rt->lastWriteTime;- te->restore_time.lastAccessTime = rt->lastAccessTime;- te->restore_time.filetype = rt->filetype;- }-}--/*- * Append a name to the current dir path.- */-static void-tree_append(struct tree *t, const wchar_t *name, size_t name_length)-{- size_t size_needed;-- t->path.s[t->dirname_length] = L'\0';- t->path.length = t->dirname_length;- /* Strip trailing '/' from name, unless entire name is "/". */- while (name_length > 1 && name[name_length - 1] == L'/')- name_length--;-- /* Resize pathname buffer as needed. */- size_needed = name_length + t->dirname_length + 2;- archive_wstring_ensure(&t->path, size_needed);- /* Add a separating '/' if it's needed. */- if (t->dirname_length > 0 &&- t->path.s[archive_strlen(&t->path)-1] != L'/')- archive_wstrappend_wchar(&t->path, L'/');- t->basename = t->path.s + archive_strlen(&t->path);- archive_wstrncat(&t->path, name, name_length);- t->restore_time.full_path = t->basename;- if (t->full_path_dir_length > 0) {- t->full_path.s[t->full_path_dir_length] = L'\0';- t->full_path.length = t->full_path_dir_length;- size_needed = name_length + t->full_path_dir_length + 2;- archive_wstring_ensure(&t->full_path, size_needed);- /* Add a separating '\' if it's needed. */- if (t->full_path.s[archive_strlen(&t->full_path)-1] != L'\\')- archive_wstrappend_wchar(&t->full_path, L'\\');- archive_wstrncat(&t->full_path, name, name_length);- t->restore_time.full_path = t->full_path.s;- }-}--/*- * Open a directory tree for traversal.- */-static struct tree *-tree_open(const wchar_t *path, int symlink_mode, int restore_time)-{- struct tree *t;-- t = calloc(1, sizeof(*t));- archive_string_init(&(t->full_path));- archive_string_init(&t->path);- archive_wstring_ensure(&t->path, 15);- t->initial_symlink_mode = symlink_mode;- return (tree_reopen(t, path, restore_time));-}--static struct tree *-tree_reopen(struct tree *t, const wchar_t *path, int restore_time)-{- struct archive_wstring ws;- wchar_t *pathname, *p, *base;-- t->flags = (restore_time != 0)?needsRestoreTimes:0;- t->visit_type = 0;- t->tree_errno = 0;- t->full_path_dir_length = 0;- t->dirname_length = 0;- t->depth = 0;- t->descend = 0;- t->current = NULL;- t->d = INVALID_HANDLE_VALUE;- t->symlink_mode = t->initial_symlink_mode;- archive_string_empty(&(t->full_path));- archive_string_empty(&t->path);- t->entry_fh = INVALID_HANDLE_VALUE;- t->entry_eof = 0;- t->entry_remaining_bytes = 0;- t->initial_filesystem_id = -1;-- /* Get wchar_t strings from char strings. */- archive_string_init(&ws);- archive_wstrcpy(&ws, path);- pathname = ws.s;- /* Get a full-path-name. */- p = __la_win_permissive_name_w(pathname);- if (p == NULL)- goto failed;- archive_wstrcpy(&(t->full_path), p);- free(p);-- /* Convert path separators from '\' to '/' */- for (p = pathname; *p != L'\0'; ++p) {- if (*p == L'\\')- *p = L'/';- }- base = pathname;-- /* First item is set up a lot like a symlink traversal. */- /* printf("Looking for wildcard in %s\n", path); */- if ((base[0] == L'/' && base[1] == L'/' &&- base[2] == L'?' && base[3] == L'/' &&- (wcschr(base+4, L'*') || wcschr(base+4, L'?'))) ||- (!(base[0] == L'/' && base[1] == L'/' &&- base[2] == L'?' && base[3] == L'/') &&- (wcschr(base, L'*') || wcschr(base, L'?')))) {- // It has a wildcard in it...- // Separate the last element.- p = wcsrchr(base, L'/');- if (p != NULL) {- *p = L'\0';- tree_append(t, base, p - base);- t->dirname_length = archive_strlen(&t->path);- base = p + 1;- }- p = wcsrchr(t->full_path.s, L'\\');- if (p != NULL) {- *p = L'\0';- t->full_path.length = wcslen(t->full_path.s);- t->full_path_dir_length = archive_strlen(&t->full_path);- }- }- tree_push(t, base, t->full_path.s, 0, 0, 0, NULL);- archive_wstring_free(&ws);- t->stack->flags = needsFirstVisit;- /*- * Debug flag for Direct IO(No buffering) or Async IO.- * Those dependent on environment variable switches- * will be removed until next release.- */- {- const char *e;- if ((e = getenv("LIBARCHIVE_DIRECT_IO")) != NULL) {- if (e[0] == '0')- t->direct_io = 0;- else- t->direct_io = 1;- fprintf(stderr, "LIBARCHIVE_DIRECT_IO=%s\n",- (t->direct_io)?"Enabled":"Disabled");- } else- t->direct_io = DIRECT_IO;- if ((e = getenv("LIBARCHIVE_ASYNC_IO")) != NULL) {- if (e[0] == '0')- t->async_io = 0;- else- t->async_io = 1;- fprintf(stderr, "LIBARCHIVE_ASYNC_IO=%s\n",- (t->async_io)?"Enabled":"Disabled");- } else- t->async_io = ASYNC_IO;- }- return (t);-failed:- archive_wstring_free(&ws);- tree_free(t);- return (NULL);-}--static int-tree_descent(struct tree *t)-{- t->dirname_length = archive_strlen(&t->path);- t->full_path_dir_length = archive_strlen(&t->full_path);- t->depth++;- return (0);-}--/*- * We've finished a directory; ascend back to the parent.- */-static int-tree_ascend(struct tree *t)-{- struct tree_entry *te;-- te = t->stack;- t->depth--;- close_and_restore_time(INVALID_HANDLE_VALUE, t, &te->restore_time);- return (0);-}--/*- * Pop the working stack.- */-static void-tree_pop(struct tree *t)-{- struct tree_entry *te;-- t->full_path.s[t->full_path_dir_length] = L'\0';- t->full_path.length = t->full_path_dir_length;- t->path.s[t->dirname_length] = L'\0';- t->path.length = t->dirname_length;- if (t->stack == t->current && t->current != NULL)- t->current = t->current->parent;- te = t->stack;- t->stack = te->next;- t->dirname_length = te->dirname_length;- t->basename = t->path.s + t->dirname_length;- t->full_path_dir_length = te->full_path_dir_length;- while (t->basename[0] == L'/')- t->basename++;- archive_wstring_free(&te->name);- archive_wstring_free(&te->full_path);- free(te);-}--/*- * Get the next item in the tree traversal.- */-static int-tree_next(struct tree *t)-{- int r;-- while (t->stack != NULL) {- /* If there's an open dir, get the next entry from there. */- if (t->d != INVALID_HANDLE_VALUE) {- r = tree_dir_next_windows(t, NULL);- if (r == 0)- continue;- return (r);- }-- if (t->stack->flags & needsFirstVisit) {- wchar_t *d = t->stack->name.s;- t->stack->flags &= ~needsFirstVisit;- if (!(d[0] == L'/' && d[1] == L'/' &&- d[2] == L'?' && d[3] == L'/') &&- (wcschr(d, L'*') || wcschr(d, L'?'))) {- r = tree_dir_next_windows(t, d);- if (r == 0)- continue;- return (r);- } else {- HANDLE h = FindFirstFileW(t->stack->full_path.s, &t->_findData);- if (h == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- t->tree_errno = errno;- t->visit_type = TREE_ERROR_DIR;- return (t->visit_type);- }- t->findData = &t->_findData;- FindClose(h);- }- /* Top stack item needs a regular visit. */- t->current = t->stack;- tree_append(t, t->stack->name.s,- archive_strlen(&(t->stack->name)));- //t->dirname_length = t->path_length;- //tree_pop(t);- t->stack->flags &= ~needsFirstVisit;- return (t->visit_type = TREE_REGULAR);- } else if (t->stack->flags & needsDescent) {- /* Top stack item is dir to descend into. */- t->current = t->stack;- tree_append(t, t->stack->name.s,- archive_strlen(&(t->stack->name)));- t->stack->flags &= ~needsDescent;- r = tree_descent(t);- if (r != 0) {- tree_pop(t);- t->visit_type = r;- } else- t->visit_type = TREE_POSTDESCENT;- return (t->visit_type);- } else if (t->stack->flags & needsOpen) {- t->stack->flags &= ~needsOpen;- r = tree_dir_next_windows(t, L"*");- if (r == 0)- continue;- return (r);- } else if (t->stack->flags & needsAscent) {- /* Top stack item is dir and we're done with it. */- r = tree_ascend(t);- tree_pop(t);- t->visit_type = r != 0 ? r : TREE_POSTASCENT;- return (t->visit_type);- } else {- /* Top item on stack is dead. */- tree_pop(t);- t->flags &= ~hasLstat;- t->flags &= ~hasStat;- }- }- return (t->visit_type = 0);-}--static int-tree_dir_next_windows(struct tree *t, const wchar_t *pattern)-{- const wchar_t *name;- size_t namelen;- int r;-- for (;;) {- if (pattern != NULL) {- struct archive_wstring pt;-- archive_string_init(&pt);- archive_wstring_ensure(&pt,- archive_strlen(&(t->full_path))- + 2 + wcslen(pattern));- archive_wstring_copy(&pt, &(t->full_path));- archive_wstrappend_wchar(&pt, L'\\');- archive_wstrcat(&pt, pattern);- t->d = FindFirstFileW(pt.s, &t->_findData);- archive_wstring_free(&pt);- if (t->d == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- t->tree_errno = errno;- r = tree_ascend(t); /* Undo "chdir" */- tree_pop(t);- t->visit_type = r != 0 ? r : TREE_ERROR_DIR;- return (t->visit_type);- }- t->findData = &t->_findData;- pattern = NULL;- } else if (!FindNextFileW(t->d, &t->_findData)) {- FindClose(t->d);- t->d = INVALID_HANDLE_VALUE;- t->findData = NULL;- return (0);- }- name = t->findData->cFileName;- namelen = wcslen(name);- t->flags &= ~hasLstat;- t->flags &= ~hasStat;- if (name[0] == L'.' && name[1] == L'\0')- continue;- if (name[0] == L'.' && name[1] == L'.' && name[2] == L'\0')- continue;- tree_append(t, name, namelen);- return (t->visit_type = TREE_REGULAR);- }-}--#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)-static void-fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns)-{- ULARGE_INTEGER utc;-- utc.HighPart = filetime->dwHighDateTime;- utc.LowPart = filetime->dwLowDateTime;- if (utc.QuadPart >= EPOC_TIME) {- utc.QuadPart -= EPOC_TIME;- /* milli seconds base */- *t = (time_t)(utc.QuadPart / 10000000);- /* nano seconds base */- *ns = (long)(utc.QuadPart % 10000000) * 100;- } else {- *t = 0;- *ns = 0;- }-}--static void-entry_copy_bhfi(struct archive_entry *entry, const wchar_t *path,- const WIN32_FIND_DATAW *findData,- const BY_HANDLE_FILE_INFORMATION *bhfi)-{- time_t secs;- long nsecs;- mode_t mode;-- fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs);- archive_entry_set_atime(entry, secs, nsecs);- fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs);- archive_entry_set_mtime(entry, secs, nsecs);- fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs);- archive_entry_set_birthtime(entry, secs, nsecs);- archive_entry_set_ctime(entry, secs, nsecs);- archive_entry_set_dev(entry, bhfi_dev(bhfi));- archive_entry_set_ino64(entry, bhfi_ino(bhfi));- if (bhfi->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)- archive_entry_set_nlink(entry, bhfi->nNumberOfLinks + 1);- else- archive_entry_set_nlink(entry, bhfi->nNumberOfLinks);- archive_entry_set_size(entry,- (((int64_t)bhfi->nFileSizeHigh) << 32)- + bhfi->nFileSizeLow);- archive_entry_set_uid(entry, 0);- archive_entry_set_gid(entry, 0);- archive_entry_set_rdev(entry, 0);-- mode = S_IRUSR | S_IRGRP | S_IROTH;- if ((bhfi->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)- mode |= S_IWUSR | S_IWGRP | S_IWOTH;- if ((bhfi->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&- findData != NULL &&- findData->dwReserved0 == IO_REPARSE_TAG_SYMLINK) {- mode |= S_IFLNK;- entry_symlink_from_pathw(entry, path);- } else if (bhfi->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)- mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;- else {- const wchar_t *p;-- mode |= S_IFREG;- p = wcsrchr(path, L'.');- if (p != NULL && wcslen(p) == 4) {- switch (p[1]) {- case L'B': case L'b':- if ((p[2] == L'A' || p[2] == L'a' ) &&- (p[3] == L'T' || p[3] == L't' ))- mode |= S_IXUSR | S_IXGRP | S_IXOTH;- break;- case L'C': case L'c':- if (((p[2] == L'M' || p[2] == L'm' ) &&- (p[3] == L'D' || p[3] == L'd' )))- mode |= S_IXUSR | S_IXGRP | S_IXOTH;- break;- case L'E': case L'e':- if ((p[2] == L'X' || p[2] == L'x' ) &&- (p[3] == L'E' || p[3] == L'e' ))- mode |= S_IXUSR | S_IXGRP | S_IXOTH;- break;- default:- break;- }- }- }- archive_entry_set_mode(entry, mode);-}--static void-tree_archive_entry_copy_bhfi(struct archive_entry *entry, struct tree *t,- const BY_HANDLE_FILE_INFORMATION *bhfi)-{- entry_copy_bhfi(entry, tree_current_path(t), t->findData, bhfi);-}--static int-tree_current_file_information(struct tree *t, BY_HANDLE_FILE_INFORMATION *st,- int sim_lstat)-{- HANDLE h;- int r;- DWORD flag = FILE_FLAG_BACKUP_SEMANTICS;-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;-#endif-- if (sim_lstat && tree_current_is_physical_link(t))- flag |= FILE_FLAG_OPEN_REPARSE_POINT;-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileFlags = flag;- h = CreateFile2(tree_current_access_path(t), 0,- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,- OPEN_EXISTING, &createExParams);-#else- h = CreateFileW(tree_current_access_path(t), 0,- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,- OPEN_EXISTING, flag, NULL);-#endif- if (h == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- t->tree_errno = errno;- return (0);- }- r = GetFileInformationByHandle(h, st);- CloseHandle(h);- return (r);-}--/*- * Get the stat() data for the entry just returned from tree_next().- */-static const BY_HANDLE_FILE_INFORMATION *-tree_current_stat(struct tree *t)-{- if (!(t->flags & hasStat)) {- if (!tree_current_file_information(t, &t->st, 0))- return NULL;- t->flags |= hasStat;- }- return (&t->st);-}--/*- * Get the lstat() data for the entry just returned from tree_next().- */-static const BY_HANDLE_FILE_INFORMATION *-tree_current_lstat(struct tree *t)-{- if (!(t->flags & hasLstat)) {- if (!tree_current_file_information(t, &t->lst, 1))- return NULL;- t->flags |= hasLstat;- }- return (&t->lst);-}--/*- * Test whether current entry is a dir or link to a dir.- */-static int-tree_current_is_dir(struct tree *t)-{- if (t->findData)- return (t->findData->dwFileAttributes- & FILE_ATTRIBUTE_DIRECTORY);- return (0);-}--/*- * Test whether current entry is a physical directory. Usually, we- * already have at least one of stat() or lstat() in memory, so we- * use tricks to try to avoid an extra trip to the disk.- */-static int-tree_current_is_physical_dir(struct tree *t)-{- if (tree_current_is_physical_link(t))- return (0);- return (tree_current_is_dir(t));-}--/*- * Test whether current entry is a symbolic link.- */-static int-tree_current_is_physical_link(struct tree *t)-{- if (t->findData)- return ((t->findData->dwFileAttributes- & FILE_ATTRIBUTE_REPARSE_POINT) &&- (t->findData->dwReserved0- == IO_REPARSE_TAG_SYMLINK));- return (0);-}--/*- * Test whether the same file has been in the tree as its parent.- */-static int-tree_target_is_same_as_parent(struct tree *t,- const BY_HANDLE_FILE_INFORMATION *st)-{- struct tree_entry *te;- int64_t dev = bhfi_dev(st);- int64_t ino = bhfi_ino(st);-- for (te = t->current->parent; te != NULL; te = te->parent) {- if (te->dev == dev && te->ino == ino)- return (1);- }- return (0);-}--/*- * Return the access path for the entry just returned from tree_next().- */-static const wchar_t *-tree_current_access_path(struct tree *t)-{- return (t->full_path.s);-}--/*- * Return the full path for the entry just returned from tree_next().- */-static const wchar_t *-tree_current_path(struct tree *t)-{- return (t->path.s);-}--/*- * Terminate the traversal.- */-static void-tree_close(struct tree *t)-{-- if (t == NULL)- return;- if (t->entry_fh != INVALID_HANDLE_VALUE) {- cancel_async(t);- close_and_restore_time(t->entry_fh, t, &t->restore_time);- t->entry_fh = INVALID_HANDLE_VALUE;- }- /* Close the handle of FindFirstFileW */- if (t->d != INVALID_HANDLE_VALUE) {- FindClose(t->d);- t->d = INVALID_HANDLE_VALUE;- t->findData = NULL;- }- /* Release anything remaining in the stack. */- while (t->stack != NULL)- tree_pop(t);-}--/*- * Release any resources.- */-static void-tree_free(struct tree *t)-{- int i;-- if (t == NULL)- return;- archive_wstring_free(&t->path);- archive_wstring_free(&t->full_path);- free(t->sparse_list);- free(t->filesystem_table);- for (i = 0; i < MAX_OVERLAPPED; i++) {- if (t->ol[i].buff)- VirtualFree(t->ol[i].buff, 0, MEM_RELEASE);- CloseHandle(t->ol[i].ol.hEvent);- }- free(t);-}---/*- * Populate the archive_entry with metadata from the disk.- */-int-archive_read_disk_entry_from_file(struct archive *_a,- struct archive_entry *entry, int fd, const struct stat *st)-{- struct archive_read_disk *a = (struct archive_read_disk *)_a;- const wchar_t *path;- const wchar_t *wname;- const char *name;- HANDLE h;- BY_HANDLE_FILE_INFORMATION bhfi;- DWORD fileAttributes = 0;- int r;-- archive_clear_error(_a);- wname = archive_entry_sourcepath_w(entry);- if (wname == NULL)- wname = archive_entry_pathname_w(entry);- if (wname == NULL) {- archive_set_error(&a->archive, EINVAL,- "Can't get a wide character version of the path");- return (ARCHIVE_FAILED);- }- path = __la_win_permissive_name_w(wname);-- if (st == NULL) {- /*- * Get metadata through GetFileInformationByHandle().- */- if (fd >= 0) {- h = (HANDLE)_get_osfhandle(fd);- r = GetFileInformationByHandle(h, &bhfi);- if (r == 0) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "Can't GetFileInformationByHandle");- return (ARCHIVE_FAILED);- }- entry_copy_bhfi(entry, path, NULL, &bhfi);- } else {- WIN32_FIND_DATAW findData;- DWORD flag, desiredAccess;-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;-#endif-- h = FindFirstFileW(path, &findData);- if (h == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "Can't FindFirstFileW");- return (ARCHIVE_FAILED);- }- FindClose(h);-- flag = FILE_FLAG_BACKUP_SEMANTICS;- if (!a->follow_symlinks &&- (findData.dwFileAttributes- & FILE_ATTRIBUTE_REPARSE_POINT) &&- (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {- flag |= FILE_FLAG_OPEN_REPARSE_POINT;- desiredAccess = 0;- } else if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {- desiredAccess = 0;- } else- desiredAccess = GENERIC_READ;--# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileFlags = flag;- h = CreateFile2(path, desiredAccess,- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,- OPEN_EXISTING, &createExParams);-#else- h = CreateFileW(path, desiredAccess,- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,- OPEN_EXISTING, flag, NULL);-#endif- if (h == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "Can't CreateFileW");- return (ARCHIVE_FAILED);- }- r = GetFileInformationByHandle(h, &bhfi);- if (r == 0) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "Can't GetFileInformationByHandle");- CloseHandle(h);- return (ARCHIVE_FAILED);- }- entry_copy_bhfi(entry, path, &findData, &bhfi);- }- fileAttributes = bhfi.dwFileAttributes;- } else {- archive_entry_copy_stat(entry, st);- if (st->st_mode & S_IFLNK)- entry_symlink_from_pathw(entry, path);- h = INVALID_HANDLE_VALUE;- }-- /* Lookup uname/gname */- name = archive_read_disk_uname(_a, archive_entry_uid(entry));- if (name != NULL)- archive_entry_copy_uname(entry, name);- name = archive_read_disk_gname(_a, archive_entry_gid(entry));- if (name != NULL)- archive_entry_copy_gname(entry, name);-- /*- * File attributes- */- if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0) {- const int supported_attrs =- FILE_ATTRIBUTE_READONLY |- FILE_ATTRIBUTE_HIDDEN |- FILE_ATTRIBUTE_SYSTEM;- DWORD file_attrs = fileAttributes & supported_attrs;- if (file_attrs != 0)- archive_entry_set_fflags(entry, file_attrs, 0);- }-- /*- * Can this file be sparse file ?- */- if (archive_entry_filetype(entry) != AE_IFREG- || archive_entry_size(entry) <= 0- || archive_entry_hardlink(entry) != NULL) {- if (h != INVALID_HANDLE_VALUE && fd < 0)- CloseHandle(h);- return (ARCHIVE_OK);- }-- if (h == INVALID_HANDLE_VALUE) {- if (fd >= 0) {- h = (HANDLE)_get_osfhandle(fd);- } else {-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;- h = CreateFile2(path, GENERIC_READ,- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,- OPEN_EXISTING, &createExParams);-#else- h = CreateFileW(path, GENERIC_READ,- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);-#endif- if (h == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "Can't CreateFileW");- return (ARCHIVE_FAILED);- }- }- r = GetFileInformationByHandle(h, &bhfi);- if (r == 0) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "Can't GetFileInformationByHandle");- if (h != INVALID_HANDLE_VALUE && fd < 0)- CloseHandle(h);- return (ARCHIVE_FAILED);- }- fileAttributes = bhfi.dwFileAttributes;- }-- /* Sparse file must be set a mark, FILE_ATTRIBUTE_SPARSE_FILE */- if ((fileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) == 0) {- if (fd < 0)- CloseHandle(h);- return (ARCHIVE_OK);- }-- if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) {- r = setup_sparse_from_disk(a, entry, h);- if (fd < 0)- CloseHandle(h);- }-- return (r);-}--/*- * Windows sparse interface.- */-#if defined(__MINGW32__) && !defined(FSCTL_QUERY_ALLOCATED_RANGES)-#define FSCTL_QUERY_ALLOCATED_RANGES 0x940CF-typedef struct {- LARGE_INTEGER FileOffset;- LARGE_INTEGER Length;-} FILE_ALLOCATED_RANGE_BUFFER;-#endif--static int-setup_sparse_from_disk(struct archive_read_disk *a,- struct archive_entry *entry, HANDLE handle)-{- FILE_ALLOCATED_RANGE_BUFFER range, *outranges = NULL;- size_t outranges_size;- int64_t entry_size = archive_entry_size(entry);- int exit_sts = ARCHIVE_OK;-- range.FileOffset.QuadPart = 0;- range.Length.QuadPart = entry_size;- outranges_size = 2048;- outranges = (FILE_ALLOCATED_RANGE_BUFFER *)malloc(outranges_size);- if (outranges == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Couldn't allocate memory");- exit_sts = ARCHIVE_FATAL;- goto exit_setup_sparse;- }-- for (;;) {- DWORD retbytes;- BOOL ret;-- for (;;) {- ret = DeviceIoControl(handle,- FSCTL_QUERY_ALLOCATED_RANGES,- &range, sizeof(range), outranges,- (DWORD)outranges_size, &retbytes, NULL);- if (ret == 0 && GetLastError() == ERROR_MORE_DATA) {- free(outranges);- outranges_size *= 2;- outranges = (FILE_ALLOCATED_RANGE_BUFFER *)- malloc(outranges_size);- if (outranges == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Couldn't allocate memory");- exit_sts = ARCHIVE_FATAL;- goto exit_setup_sparse;- }- continue;- } else- break;- }- if (ret != 0) {- if (retbytes > 0) {- DWORD i, n;-- n = retbytes / sizeof(outranges[0]);- if (n == 1 &&- outranges[0].FileOffset.QuadPart == 0 &&- outranges[0].Length.QuadPart == entry_size)- break;/* This is not sparse. */- for (i = 0; i < n; i++)- archive_entry_sparse_add_entry(entry,- outranges[i].FileOffset.QuadPart,- outranges[i].Length.QuadPart);- range.FileOffset.QuadPart =- outranges[n-1].FileOffset.QuadPart- + outranges[n-1].Length.QuadPart;- range.Length.QuadPart =- entry_size - range.FileOffset.QuadPart;- if (range.Length.QuadPart > 0)- continue;- } else {- /* The entire file is a hole. Add one data block of size 0 at the end. */- archive_entry_sparse_add_entry(entry,- entry_size,- 0);- }- break;- } else {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "DeviceIoControl Failed: %lu", GetLastError());- exit_sts = ARCHIVE_FAILED;- goto exit_setup_sparse;- }- }-exit_setup_sparse:- free(outranges);-- return (exit_sts);-}--#endif
− c/archive_read_extract.c
@@ -1,60 +0,0 @@-/*-- * 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: src/lib/libarchive/archive_read_extract.c,v 1.61 2008/05/26 17:00:22 kientzle Exp $");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_private.h"--int-archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags)-{- struct archive_read_extract *extract;- struct archive_read * a = (struct archive_read *)_a;-- extract = __archive_read_get_extract(a);- if (extract == NULL)- return (ARCHIVE_FATAL);-- /* If we haven't initialized the archive_write_disk object, do it now. */- if (extract->ad == NULL) {- extract->ad = archive_write_disk_new();- if (extract->ad == NULL) {- archive_set_error(&a->archive, ENOMEM, "Can't extract");- return (ARCHIVE_FATAL);- }- archive_write_disk_set_standard_lookup(extract->ad);- }-- archive_write_disk_set_options(extract->ad, flags);- return (archive_read_extract2(&a->archive, entry, extract->ad));-}
− c/archive_read_extract2.c
@@ -1,155 +0,0 @@-/*-- * 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: src/lib/libarchive/archive_read_extract.c,v 1.61 2008/05/26 17:00:22 kientzle Exp $");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_private.h"--static int copy_data(struct archive *ar, struct archive *aw);-static int archive_read_extract_cleanup(struct archive_read *);---/* Retrieve an extract object without initialising the associated- * archive_write_disk object.- */-struct archive_read_extract *-__archive_read_get_extract(struct archive_read *a)-{- if (a->extract == NULL) {- a->extract = (struct archive_read_extract *)calloc(1, sizeof(*a->extract));- if (a->extract == NULL) {- archive_set_error(&a->archive, ENOMEM, "Can't extract");- return (NULL);- }- a->cleanup_archive_extract = archive_read_extract_cleanup;- }- return (a->extract);-}--/*- * Cleanup function for archive_extract.- */-static int-archive_read_extract_cleanup(struct archive_read *a)-{- int ret = ARCHIVE_OK;-- if (a->extract->ad != NULL) {- ret = archive_write_free(a->extract->ad);- }- free(a->extract);- a->extract = NULL;- return (ret);-}--int-archive_read_extract2(struct archive *_a, struct archive_entry *entry,- struct archive *ad)-{- struct archive_read *a = (struct archive_read *)_a;- int r, r2;-- /* Set up for this particular entry. */- if (a->skip_file_set)- archive_write_disk_set_skip_file(ad,- a->skip_file_dev, a->skip_file_ino);- r = archive_write_header(ad, entry);- if (r < ARCHIVE_WARN)- r = ARCHIVE_WARN;- if (r != ARCHIVE_OK)- /* If _write_header failed, copy the error. */- archive_copy_error(&a->archive, ad);- else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0)- /* Otherwise, pour data into the entry. */- r = copy_data(_a, ad);- r2 = archive_write_finish_entry(ad);- if (r2 < ARCHIVE_WARN)- r2 = ARCHIVE_WARN;- /* Use the first message. */- if (r2 != ARCHIVE_OK && r == ARCHIVE_OK)- archive_copy_error(&a->archive, ad);- /* Use the worst error return. */- if (r2 < r)- r = r2;- return (r);-}--void-archive_read_extract_set_progress_callback(struct archive *_a,- void (*progress_func)(void *), void *user_data)-{- struct archive_read *a = (struct archive_read *)_a;- struct archive_read_extract *extract = __archive_read_get_extract(a);- if (extract != NULL) {- extract->extract_progress = progress_func;- extract->extract_progress_user_data = user_data;- }-}--static int-copy_data(struct archive *ar, struct archive *aw)-{- int64_t offset;- const void *buff;- struct archive_read_extract *extract;- size_t size;- int r;-- extract = __archive_read_get_extract((struct archive_read *)ar);- if (extract == NULL)- return (ARCHIVE_FATAL);- for (;;) {- r = archive_read_data_block(ar, &buff, &size, &offset);- if (r == ARCHIVE_EOF)- return (ARCHIVE_OK);- if (r != ARCHIVE_OK)- return (r);- r = (int)archive_write_data_block(aw, buff, size, offset);- if (r < ARCHIVE_WARN)- r = ARCHIVE_WARN;- if (r < ARCHIVE_OK) {- archive_set_error(ar, archive_errno(aw),- "%s", archive_error_string(aw));- return (r);- }- if (extract->extract_progress)- (extract->extract_progress)- (extract->extract_progress_user_data);- }-}
− c/archive_read_open_fd.c
@@ -1,211 +0,0 @@-/*-- * 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_read_open_fd.c 201103 2009-12-28 03:13:49Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_IO_H-#include <io.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"--struct read_fd_data {- int fd;- size_t block_size;- char use_lseek;- void *buffer;-};--static int file_close(struct archive *, void *);-static ssize_t file_read(struct archive *, void *, const void **buff);-static int64_t file_seek(struct archive *, void *, int64_t request, int);-static int64_t file_skip(struct archive *, void *, int64_t request);--int-archive_read_open_fd(struct archive *a, int fd, size_t block_size)-{- struct stat st;- struct read_fd_data *mine;- void *b;-- archive_clear_error(a);- if (fstat(fd, &st) != 0) {- archive_set_error(a, errno, "Can't stat fd %d", fd);- return (ARCHIVE_FATAL);- }-- mine = (struct read_fd_data *)calloc(1, sizeof(*mine));- b = malloc(block_size);- if (mine == NULL || b == NULL) {- archive_set_error(a, ENOMEM, "No memory");- free(mine);- free(b);- return (ARCHIVE_FATAL);- }- mine->block_size = block_size;- mine->buffer = b;- mine->fd = fd;- /*- * Skip support is a performance optimization for anything- * that supports lseek(). On FreeBSD, only regular files and- * raw disk devices support lseek() and there's no portable- * way to determine if a device is a raw disk device, so we- * only enable this optimization for regular files.- */- if (S_ISREG(st.st_mode)) {- archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);- mine->use_lseek = 1;- }-#if defined(__CYGWIN__) || defined(_WIN32)- setmode(mine->fd, O_BINARY);-#endif-- archive_read_set_read_callback(a, file_read);- archive_read_set_skip_callback(a, file_skip);- archive_read_set_seek_callback(a, file_seek);- archive_read_set_close_callback(a, file_close);- archive_read_set_callback_data(a, mine);- return (archive_read_open1(a));-}--static ssize_t-file_read(struct archive *a, void *client_data, const void **buff)-{- struct read_fd_data *mine = (struct read_fd_data *)client_data;- ssize_t bytes_read;-- *buff = mine->buffer;- for (;;) {- bytes_read = read(mine->fd, mine->buffer, mine->block_size);- if (bytes_read < 0) {- if (errno == EINTR)- continue;- archive_set_error(a, errno, "Error reading fd %d",- mine->fd);- }- return (bytes_read);- }-}--static int64_t-file_skip(struct archive *a, void *client_data, int64_t request)-{- struct read_fd_data *mine = (struct read_fd_data *)client_data;- int64_t skip = request;- int64_t old_offset, new_offset;- int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */-- if (!mine->use_lseek)- return (0);-- /* Reduce a request that would overflow the 'skip' variable. */- if (sizeof(request) > sizeof(skip)) {- int64_t max_skip =- (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;- if (request > max_skip)- skip = max_skip;- }-- /* Reduce request to the next smallest multiple of block_size */- request = (request / mine->block_size) * mine->block_size;- if (request == 0)- return (0);-- if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) &&- ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0))- return (new_offset - old_offset);-- /* If seek failed once, it will probably fail again. */- mine->use_lseek = 0;-- /* Let libarchive recover with read+discard. */- if (errno == ESPIPE)- return (0);-- /*- * There's been an error other than ESPIPE. This is most- * likely caused by a programmer error (too large request)- * or a corrupted archive file.- */- archive_set_error(a, errno, "Error seeking");- return (-1);-}--/*- * TODO: Store the offset and use it in the read callback.- */-static int64_t-file_seek(struct archive *a, void *client_data, int64_t request, int whence)-{- struct read_fd_data *mine = (struct read_fd_data *)client_data;- int64_t r;-- /* We use off_t here because lseek() is declared that way. */- /* See above for notes about when off_t is less than 64 bits. */- r = lseek(mine->fd, request, whence);- if (r >= 0)- return r;-- if (errno == ESPIPE) {- archive_set_error(a, errno,- "A file descriptor(%d) is not seekable(PIPE)", mine->fd);- return (ARCHIVE_FAILED);- } else {- /* If the input is corrupted or truncated, fail. */- archive_set_error(a, errno,- "Error seeking in a file descriptor(%d)", mine->fd);- return (ARCHIVE_FATAL);- }-}--static int-file_close(struct archive *a, void *client_data)-{- struct read_fd_data *mine = (struct read_fd_data *)client_data;-- (void)a; /* UNUSED */- free(mine->buffer);- free(mine);- return (ARCHIVE_OK);-}
− c/archive_read_open_file.c
@@ -1,180 +0,0 @@-/*-- * 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_read_open_file.c 201093 2009-12-28 02:28:44Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_IO_H-#include <io.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"--struct read_FILE_data {- FILE *f;- size_t block_size;- void *buffer;- char can_skip;-};--static int file_close(struct archive *, void *);-static ssize_t file_read(struct archive *, void *, const void **buff);-static int64_t file_skip(struct archive *, void *, int64_t request);--int-archive_read_open_FILE(struct archive *a, FILE *f)-{- struct stat st;- struct read_FILE_data *mine;- size_t block_size = 128 * 1024;- void *b;-- archive_clear_error(a);- mine = (struct read_FILE_data *)malloc(sizeof(*mine));- b = malloc(block_size);- if (mine == NULL || b == NULL) {- archive_set_error(a, ENOMEM, "No memory");- free(mine);- free(b);- return (ARCHIVE_FATAL);- }- mine->block_size = block_size;- mine->buffer = b;- mine->f = f;- /*- * If we can't fstat() the file, it may just be that it's not- * a file. (On some platforms, FILE * objects can wrap I/O- * streams that don't support fileno()). As a result, fileno()- * should be used cautiously.)- */- if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) {- archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);- /* Enable the seek optimization only for regular files. */- mine->can_skip = 1;- } else- mine->can_skip = 0;--#if defined(__CYGWIN__) || defined(_WIN32)- setmode(fileno(mine->f), O_BINARY);-#endif-- archive_read_set_read_callback(a, file_read);- archive_read_set_skip_callback(a, file_skip);- archive_read_set_close_callback(a, file_close);- archive_read_set_callback_data(a, mine);- return (archive_read_open1(a));-}--static ssize_t-file_read(struct archive *a, void *client_data, const void **buff)-{- struct read_FILE_data *mine = (struct read_FILE_data *)client_data;- size_t bytes_read;-- *buff = mine->buffer;- bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f);- if (bytes_read < mine->block_size && ferror(mine->f)) {- archive_set_error(a, errno, "Error reading file");- }- return (bytes_read);-}--static int64_t-file_skip(struct archive *a, void *client_data, int64_t request)-{- struct read_FILE_data *mine = (struct read_FILE_data *)client_data;-#if HAVE_FSEEKO- off_t skip = (off_t)request;-#elif HAVE__FSEEKI64- int64_t skip = request;-#else- long skip = (long)request;-#endif- int skip_bits = sizeof(skip) * 8 - 1;-- (void)a; /* UNUSED */-- /*- * If we can't skip, return 0 as the amount we did step and- * the caller will work around by reading and discarding.- */- if (!mine->can_skip)- return (0);- if (request == 0)- return (0);-- /* If request is too big for a long or an off_t, reduce it. */- if (sizeof(request) > sizeof(skip)) {- int64_t max_skip =- (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;- if (request > max_skip)- skip = max_skip;- }--#ifdef __ANDROID__- /* fileno() isn't safe on all platforms ... see above. */- if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0)-#elif HAVE__FSEEKI64- if (_fseeki64(mine->f, skip, SEEK_CUR) != 0)-#elif HAVE_FSEEKO- if (fseeko(mine->f, skip, SEEK_CUR) != 0)-#else- if (fseek(mine->f, skip, SEEK_CUR) != 0)-#endif- {- mine->can_skip = 0;- return (0);- }- return (request);-}--static int-file_close(struct archive *a, void *client_data)-{- struct read_FILE_data *mine = (struct read_FILE_data *)client_data;-- (void)a; /* UNUSED */- free(mine->buffer);- free(mine);- return (ARCHIVE_OK);-}
− c/archive_read_open_filename.c
@@ -1,586 +0,0 @@-/*-- * 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_read_open_filename.c 201093 2009-12-28 02:28:44Z kientzle $");--#ifdef HAVE_SYS_IOCTL_H-#include <sys/ioctl.h>-#endif-#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_IO_H-#include <io.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)-#include <sys/disk.h>-#elif defined(__NetBSD__) || defined(__OpenBSD__)-#include <sys/disklabel.h>-#include <sys/dkio.h>-#elif defined(__DragonFly__)-#include <sys/diskslice.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_string.h"--#ifndef O_BINARY-#define O_BINARY 0-#endif-#ifndef O_CLOEXEC-#define O_CLOEXEC 0-#endif--struct read_file_data {- int fd;- size_t block_size;- void *buffer;- mode_t st_mode; /* Mode bits for opened file. */- char use_lseek;- enum fnt_e { FNT_STDIN, FNT_MBS, FNT_WCS } filename_type;- union {- char m[1];/* MBS filename. */- wchar_t w[1];/* WCS filename. */- } filename; /* Must be last! */-};--static int file_open(struct archive *, void *);-static int file_close(struct archive *, void *);-static int file_close2(struct archive *, void *);-static int file_switch(struct archive *, void *, void *);-static ssize_t file_read(struct archive *, void *, const void **buff);-static int64_t file_seek(struct archive *, void *, int64_t request, int);-static int64_t file_skip(struct archive *, void *, int64_t request);-static int64_t file_skip_lseek(struct archive *, void *, int64_t request);--int-archive_read_open_file(struct archive *a, const char *filename,- size_t block_size)-{- return (archive_read_open_filename(a, filename, block_size));-}--int-archive_read_open_filename(struct archive *a, const char *filename,- size_t block_size)-{- const char *filenames[2];- filenames[0] = filename;- filenames[1] = NULL;- return archive_read_open_filenames(a, filenames, block_size);-}--int-archive_read_open_filenames(struct archive *a, const char **filenames,- size_t block_size)-{- struct read_file_data *mine;- const char *filename = NULL;- if (filenames)- filename = *(filenames++);-- archive_clear_error(a);- do- {- if (filename == NULL)- filename = "";- mine = (struct read_file_data *)calloc(1,- sizeof(*mine) + strlen(filename));- if (mine == NULL)- goto no_memory;- strcpy(mine->filename.m, filename);- mine->block_size = block_size;- mine->fd = -1;- mine->buffer = NULL;- mine->st_mode = mine->use_lseek = 0;- if (filename == NULL || filename[0] == '\0') {- mine->filename_type = FNT_STDIN;- } else- mine->filename_type = FNT_MBS;- if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK))- return (ARCHIVE_FATAL);- if (filenames == NULL)- break;- filename = *(filenames++);- } while (filename != NULL && filename[0] != '\0');- archive_read_set_open_callback(a, file_open);- archive_read_set_read_callback(a, file_read);- archive_read_set_skip_callback(a, file_skip);- archive_read_set_close_callback(a, file_close);- archive_read_set_switch_callback(a, file_switch);- archive_read_set_seek_callback(a, file_seek);-- return (archive_read_open1(a));-no_memory:- archive_set_error(a, ENOMEM, "No memory");- return (ARCHIVE_FATAL);-}--int-archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,- size_t block_size)-{- struct read_file_data *mine = (struct read_file_data *)calloc(1,- sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t));- if (!mine)- {- archive_set_error(a, ENOMEM, "No memory");- return (ARCHIVE_FATAL);- }- mine->fd = -1;- mine->block_size = block_size;-- if (wfilename == NULL || wfilename[0] == L'\0') {- mine->filename_type = FNT_STDIN;- } else {-#if defined(_WIN32) && !defined(__CYGWIN__)- mine->filename_type = FNT_WCS;- wcscpy(mine->filename.w, wfilename);-#else- /*- * POSIX system does not support a wchar_t interface for- * open() system call, so we have to translate a wchar_t- * filename to multi-byte one and use it.- */- struct archive_string fn;-- archive_string_init(&fn);- if (archive_string_append_from_wcs(&fn, wfilename,- wcslen(wfilename)) != 0) {- if (errno == ENOMEM)- archive_set_error(a, errno,- "Can't allocate memory");- else- archive_set_error(a, EINVAL,- "Failed to convert a wide-character"- " filename to a multi-byte filename");- archive_string_free(&fn);- free(mine);- return (ARCHIVE_FATAL);- }- mine->filename_type = FNT_MBS;- strcpy(mine->filename.m, fn.s);- archive_string_free(&fn);-#endif- }- if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK))- return (ARCHIVE_FATAL);- archive_read_set_open_callback(a, file_open);- archive_read_set_read_callback(a, file_read);- archive_read_set_skip_callback(a, file_skip);- archive_read_set_close_callback(a, file_close);- archive_read_set_switch_callback(a, file_switch);- archive_read_set_seek_callback(a, file_seek);-- return (archive_read_open1(a));-}--static int-file_open(struct archive *a, void *client_data)-{- struct stat st;- struct read_file_data *mine = (struct read_file_data *)client_data;- void *buffer;- const char *filename = NULL;-#if defined(_WIN32) && !defined(__CYGWIN__)- const wchar_t *wfilename = NULL;-#endif- int fd = -1;- int is_disk_like = 0;-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)- off_t mediasize = 0; /* FreeBSD-specific, so off_t okay here. */-#elif defined(__NetBSD__) || defined(__OpenBSD__)- struct disklabel dl;-#elif defined(__DragonFly__)- struct partinfo pi;-#endif-- archive_clear_error(a);- if (mine->filename_type == FNT_STDIN) {- /* We used to delegate stdin support by- * directly calling archive_read_open_fd(a,0,block_size)- * here, but that doesn't (and shouldn't) handle the- * end-of-file flush when reading stdout from a pipe.- * Basically, read_open_fd() is intended for folks who- * are willing to handle such details themselves. This- * API is intended to be a little smarter for folks who- * want easy handling of the common case.- */- fd = 0;-#if defined(__CYGWIN__) || defined(_WIN32)- setmode(0, O_BINARY);-#endif- filename = "";- } else if (mine->filename_type == FNT_MBS) {- filename = mine->filename.m;- fd = open(filename, O_RDONLY | O_BINARY | O_CLOEXEC);- __archive_ensure_cloexec_flag(fd);- if (fd < 0) {- archive_set_error(a, errno,- "Failed to open '%s'", filename);- return (ARCHIVE_FATAL);- }- } else {-#if defined(_WIN32) && !defined(__CYGWIN__)- wfilename = mine->filename.w;- fd = _wopen(wfilename, O_RDONLY | O_BINARY);- if (fd < 0 && errno == ENOENT) {- wchar_t *fullpath;- fullpath = __la_win_permissive_name_w(wfilename);- if (fullpath != NULL) {- fd = _wopen(fullpath, O_RDONLY | O_BINARY);- free(fullpath);- }- }- if (fd < 0) {- archive_set_error(a, errno,- "Failed to open '%S'", wfilename);- return (ARCHIVE_FATAL);- }-#else- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Unexpedted operation in archive_read_open_filename");- goto fail;-#endif- }- if (fstat(fd, &st) != 0) {-#if defined(_WIN32) && !defined(__CYGWIN__)- if (mine->filename_type == FNT_WCS)- archive_set_error(a, errno, "Can't stat '%S'",- wfilename);- else-#endif- archive_set_error(a, errno, "Can't stat '%s'",- filename);- goto fail;- }-- /*- * Determine whether the input looks like a disk device or a- * tape device. The results are used below to select an I/O- * strategy:- * = "disk-like" devices support arbitrary lseek() and will- * support I/O requests of any size. So we get easy skipping- * and can cheat on block sizes to get better performance.- * = "tape-like" devices require strict blocking and use- * specialized ioctls for seeking.- * = "socket-like" devices cannot seek at all but can improve- * performance by using nonblocking I/O to read "whatever is- * available right now".- *- * Right now, we only specially recognize disk-like devices,- * but it should be straightforward to add probes and strategy- * here for tape-like and socket-like devices.- */- if (S_ISREG(st.st_mode)) {- /* Safety: Tell the extractor not to overwrite the input. */- archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);- /* Regular files act like disks. */- is_disk_like = 1;- }-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)- /* FreeBSD: if it supports DIOCGMEDIASIZE ioctl, it's disk-like. */- else if (S_ISCHR(st.st_mode) &&- ioctl(fd, DIOCGMEDIASIZE, &mediasize) == 0 &&- mediasize > 0) {- is_disk_like = 1;- }-#elif defined(__NetBSD__) || defined(__OpenBSD__)- /* Net/OpenBSD: if it supports DIOCGDINFO ioctl, it's disk-like. */- else if ((S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) &&- ioctl(fd, DIOCGDINFO, &dl) == 0 &&- dl.d_partitions[DISKPART(st.st_rdev)].p_size > 0) {- is_disk_like = 1;- }-#elif defined(__DragonFly__)- /* DragonFly BSD: if it supports DIOCGPART ioctl, it's disk-like. */- else if (S_ISCHR(st.st_mode) &&- ioctl(fd, DIOCGPART, &pi) == 0 &&- pi.media_size > 0) {- is_disk_like = 1;- }-#elif defined(__linux__)- /* Linux: All block devices are disk-like. */- else if (S_ISBLK(st.st_mode) &&- lseek(fd, 0, SEEK_CUR) == 0 &&- lseek(fd, 0, SEEK_SET) == 0 &&- lseek(fd, 0, SEEK_END) > 0 &&- lseek(fd, 0, SEEK_SET) == 0) {- is_disk_like = 1;- }-#endif- /* TODO: Add an "is_tape_like" variable and appropriate tests. */-- /* Disk-like devices prefer power-of-two block sizes. */- /* Use provided block_size as a guide so users have some control. */- if (is_disk_like) {- size_t new_block_size = 64 * 1024;- while (new_block_size < mine->block_size- && new_block_size < 64 * 1024 * 1024)- new_block_size *= 2;- mine->block_size = new_block_size;- }- buffer = malloc(mine->block_size);- if (buffer == NULL) {- archive_set_error(a, ENOMEM, "No memory");- goto fail;- }- mine->buffer = buffer;- mine->fd = fd;- /* Remember mode so close can decide whether to flush. */- mine->st_mode = st.st_mode;-- /* Disk-like inputs can use lseek(). */- if (is_disk_like)- mine->use_lseek = 1;-- return (ARCHIVE_OK);-fail:- /*- * Don't close file descriptors not opened or ones pointing referring- * to `FNT_STDIN`.- */- if (fd != -1 && fd != 0)- close(fd);- return (ARCHIVE_FATAL);-}--static ssize_t-file_read(struct archive *a, void *client_data, const void **buff)-{- struct read_file_data *mine = (struct read_file_data *)client_data;- ssize_t bytes_read;-- /* TODO: If a recent lseek() operation has left us- * mis-aligned, read and return a short block to try to get- * us back in alignment. */-- /* TODO: Someday, try mmap() here; if that succeeds, give- * the entire file to libarchive as a single block. That- * could be a lot faster than block-by-block manual I/O. */-- /* TODO: We might be able to improve performance on pipes and- * sockets by setting non-blocking I/O and just accepting- * whatever we get here instead of waiting for a full block- * worth of data. */-- *buff = mine->buffer;- for (;;) {- bytes_read = read(mine->fd, mine->buffer, mine->block_size);- if (bytes_read < 0) {- if (errno == EINTR)- continue;- else if (mine->filename_type == FNT_STDIN)- archive_set_error(a, errno,- "Error reading stdin");- else if (mine->filename_type == FNT_MBS)- archive_set_error(a, errno,- "Error reading '%s'", mine->filename.m);- else- archive_set_error(a, errno,- "Error reading '%S'", mine->filename.w);- }- return (bytes_read);- }-}--/*- * Regular files and disk-like block devices can use simple lseek- * without needing to round the request to the block size.- *- * TODO: This can leave future reads mis-aligned. Since we know the- * offset here, we should store it and use it in file_read() above- * to determine whether we should perform a short read to get back- * into alignment. Long series of mis-aligned reads can negatively- * impact disk throughput. (Of course, the performance impact should- * be carefully tested; extra code complexity is only worthwhile if- * it does provide measurable improvement.)- *- * TODO: Be lazy about the actual seek. There are a few pathological- * cases where libarchive makes a bunch of seek requests in a row- * without any intervening reads. This isn't a huge performance- * problem, since the kernel handles seeks lazily already, but- * it would be very slightly faster if we simply remembered the- * seek request here and then actually performed the seek at the- * top of the read callback above.- */-static int64_t-file_skip_lseek(struct archive *a, void *client_data, int64_t request)-{- struct read_file_data *mine = (struct read_file_data *)client_data;-#if defined(_WIN32) && !defined(__CYGWIN__)- /* We use _lseeki64() on Windows. */- int64_t old_offset, new_offset;-#else- off_t old_offset, new_offset;-#endif-- /* We use off_t here because lseek() is declared that way. */-- /* TODO: Deal with case where off_t isn't 64 bits.- * This shouldn't be a problem on Linux or other POSIX- * systems, since the configuration logic for libarchive- * tries to obtain a 64-bit off_t.- */- if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 &&- (new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0)- return (new_offset - old_offset);-- /* If lseek() fails, don't bother trying again. */- mine->use_lseek = 0;-- /* Let libarchive recover with read+discard */- if (errno == ESPIPE)- return (0);-- /* If the input is corrupted or truncated, fail. */- if (mine->filename_type == FNT_STDIN)- archive_set_error(a, errno, "Error seeking in stdin");- else if (mine->filename_type == FNT_MBS)- archive_set_error(a, errno, "Error seeking in '%s'",- mine->filename.m);- else- archive_set_error(a, errno, "Error seeking in '%S'",- mine->filename.w);- return (-1);-}---/*- * TODO: Implement another file_skip_XXXX that uses MTIO ioctls to- * accelerate operation on tape drives.- */--static int64_t-file_skip(struct archive *a, void *client_data, int64_t request)-{- struct read_file_data *mine = (struct read_file_data *)client_data;-- /* Delegate skip requests. */- if (mine->use_lseek)- return (file_skip_lseek(a, client_data, request));-- /* If we can't skip, return 0; libarchive will read+discard instead. */- return (0);-}--/*- * TODO: Store the offset and use it in the read callback.- */-static int64_t-file_seek(struct archive *a, void *client_data, int64_t request, int whence)-{- struct read_file_data *mine = (struct read_file_data *)client_data;- int64_t r;-- /* We use off_t here because lseek() is declared that way. */- /* See above for notes about when off_t is less than 64 bits. */- r = lseek(mine->fd, request, whence);- if (r >= 0)- return r;-- /* If the input is corrupted or truncated, fail. */- if (mine->filename_type == FNT_STDIN)- archive_set_error(a, errno, "Error seeking in stdin");- else if (mine->filename_type == FNT_MBS)- archive_set_error(a, errno, "Error seeking in '%s'",- mine->filename.m);- else- archive_set_error(a, errno, "Error seeking in '%S'",- mine->filename.w);- return (ARCHIVE_FATAL);-}--static int-file_close2(struct archive *a, void *client_data)-{- struct read_file_data *mine = (struct read_file_data *)client_data;-- (void)a; /* UNUSED */-- /* Only flush and close if open succeeded. */- if (mine->fd >= 0) {- /*- * Sometimes, we should flush the input before closing.- * Regular files: faster to just close without flush.- * Disk-like devices: Ditto.- * Tapes: must not flush (user might need to- * read the "next" item on a non-rewind device).- * Pipes and sockets: must flush (otherwise, the- * program feeding the pipe or socket may complain).- * Here, I flush everything except for regular files and- * device nodes.- */- if (!S_ISREG(mine->st_mode)- && !S_ISCHR(mine->st_mode)- && !S_ISBLK(mine->st_mode)) {- ssize_t bytesRead;- do {- bytesRead = read(mine->fd, mine->buffer,- mine->block_size);- } while (bytesRead > 0);- }- /* If a named file was opened, then it needs to be closed. */- if (mine->filename_type != FNT_STDIN)- close(mine->fd);- }- free(mine->buffer);- mine->buffer = NULL;- mine->fd = -1;- return (ARCHIVE_OK);-}--static int-file_close(struct archive *a, void *client_data)-{- struct read_file_data *mine = (struct read_file_data *)client_data;- file_close2(a, client_data);- free(mine);- return (ARCHIVE_OK);-}--static int-file_switch(struct archive *a, void *client_data1, void *client_data2)-{- file_close2(a, client_data1);- return file_open(a, client_data2);-}
− c/archive_read_open_memory.c
@@ -1,186 +0,0 @@-/*-- * 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: src/lib/libarchive/archive_read_open_memory.c,v 1.6 2007/07/06 15:51:59 kientzle Exp $");--#include <errno.h>-#include <stdlib.h>-#include <string.h>--#include "archive.h"--/*- * Glue to read an archive from a block of memory.- *- * This is mostly a huge help in building test harnesses;- * test programs can build archives in memory and read them- * back again without having to mess with files on disk.- */--struct read_memory_data {- const unsigned char *start;- const unsigned char *p;- const unsigned char *end;- ssize_t read_size;-};--static int memory_read_close(struct archive *, void *);-static int memory_read_open(struct archive *, void *);-static int64_t memory_read_seek(struct archive *, void *, int64_t offset, int whence);-static int64_t memory_read_skip(struct archive *, void *, int64_t request);-static ssize_t memory_read(struct archive *, void *, const void **buff);--int-archive_read_open_memory(struct archive *a, const void *buff, size_t size)-{- return archive_read_open_memory2(a, buff, size, size);-}--/*- * Don't use _open_memory2() in production code; the archive_read_open_memory()- * version is the one you really want. This is just here so that- * test harnesses can exercise block operations inside the library.- */-int-archive_read_open_memory2(struct archive *a, const void *buff,- size_t size, size_t read_size)-{- struct read_memory_data *mine;-- mine = (struct read_memory_data *)calloc(1, sizeof(*mine));- if (mine == NULL) {- archive_set_error(a, ENOMEM, "No memory");- return (ARCHIVE_FATAL);- }- mine->start = mine->p = (const unsigned char *)buff;- mine->end = mine->start + size;- mine->read_size = read_size;- archive_read_set_open_callback(a, memory_read_open);- archive_read_set_read_callback(a, memory_read);- archive_read_set_seek_callback(a, memory_read_seek);- archive_read_set_skip_callback(a, memory_read_skip);- archive_read_set_close_callback(a, memory_read_close);- archive_read_set_callback_data(a, mine);- return (archive_read_open1(a));-}--/*- * There's nothing to open.- */-static int-memory_read_open(struct archive *a, void *client_data)-{- (void)a; /* UNUSED */- (void)client_data; /* UNUSED */- return (ARCHIVE_OK);-}--/*- * This is scary simple: Just advance a pointer. Limiting- * to read_size is not technically necessary, but it exercises- * more of the internal logic when used with a small block size- * in a test harness. Production use should not specify a block- * size; then this is much faster.- */-static ssize_t-memory_read(struct archive *a, void *client_data, const void **buff)-{- struct read_memory_data *mine = (struct read_memory_data *)client_data;- ssize_t size;-- (void)a; /* UNUSED */- *buff = mine->p;- size = mine->end - mine->p;- if (size > mine->read_size)- size = mine->read_size;- mine->p += size;- return (size);-}--/*- * Advancing is just as simple. Again, this is doing more than- * necessary in order to better exercise internal code when used- * as a test harness.- */-static int64_t-memory_read_skip(struct archive *a, void *client_data, int64_t skip)-{- struct read_memory_data *mine = (struct read_memory_data *)client_data;-- (void)a; /* UNUSED */- if ((int64_t)skip > (int64_t)(mine->end - mine->p))- skip = mine->end - mine->p;- /* Round down to block size. */- skip /= mine->read_size;- skip *= mine->read_size;- mine->p += skip;- return (skip);-}--/*- * Seeking.- */-static int64_t-memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence)-{- struct read_memory_data *mine = (struct read_memory_data *)client_data;-- (void)a; /* UNUSED */- switch (whence) {- case SEEK_SET:- mine->p = mine->start + offset;- break;- case SEEK_CUR:- mine->p += offset;- break;- case SEEK_END:- mine->p = mine->end + offset;- break;- default:- return ARCHIVE_FATAL;- }- if (mine->p < mine->start) {- mine->p = mine->start;- return ARCHIVE_FAILED;- }- if (mine->p > mine->end) {- mine->p = mine->end;- return ARCHIVE_FAILED;- }- return (mine->p - mine->start);-}--/*- * Close is just cleaning up our one small bit of data.- */-static int-memory_read_close(struct archive *a, void *client_data)-{- struct read_memory_data *mine = (struct read_memory_data *)client_data;- (void)a; /* UNUSED */- free(mine);- return (ARCHIVE_OK);-}
− c/archive_read_private.h
@@ -1,267 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD: head/lib/libarchive/archive_read_private.h 201088 2009-12-28 02:18:55Z kientzle $- */--#ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED-#define ARCHIVE_READ_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#ifndef __LIBARCHIVE_TEST-#error This header is only to be used internally to libarchive.-#endif-#endif--#include "archive.h"-#include "archive_string.h"-#include "archive_private.h"--struct archive_read;-struct archive_read_filter_bidder;-struct archive_read_filter;--struct archive_read_filter_bidder_vtable {- /* Taste the upstream filter to see if we handle this. */- int (*bid)(struct archive_read_filter_bidder *,- struct archive_read_filter *);- /* Initialize a newly-created filter. */- int (*init)(struct archive_read_filter *);- /* Release the bidder's configuration data. */- void (*free)(struct archive_read_filter_bidder *);-};--/*- * How bidding works for filters:- * * 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 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. */- void *data;- /* Name of the filter */- const char *name;- const struct archive_read_filter_bidder_vtable *vtable;-};--struct archive_read_filter_vtable {- /* Return next block. */- ssize_t (*read)(struct archive_read_filter *, const void **);- /* Close (just this filter) and free(self). */- int (*close)(struct archive_read_filter *self);- /* Read any header metadata if available. */- int (*read_header)(struct archive_read_filter *self, struct archive_entry *entry);-};--/*- * This structure is allocated within the archive_read core- * and initialized by archive_read and the init() method of the- * corresponding bidder above.- */-struct archive_read_filter {- int64_t position;- /* Essentially all filters will need these values, so- * just declare them here. */- struct archive_read_filter_bidder *bidder; /* My bidder. */- struct archive_read_filter *upstream; /* Who I read from. */- struct archive_read *archive; /* Associated archive. */- const struct archive_read_filter_vtable *vtable;- /* My private data. */- void *data;-- const char *name;- int code;- int can_skip;- int can_seek;-- /* Used by reblocking logic. */- char *buffer;- size_t buffer_size;- char *next; /* Current read location. */- size_t avail; /* Bytes in my buffer. */- const void *client_buff; /* Client buffer information. */- size_t client_total;- const char *client_next;- size_t client_avail;- char end_of_file;- char closed;- char fatal;-};--/*- * The client looks a lot like a filter, so we just wrap it here.- *- * TODO: Make archive_read_filter and archive_read_client identical so- * that users of the library can easily register their own- * transformation filters. This will probably break the API/ABI and- * so should be deferred at least until libarchive 3.0.- */-struct archive_read_data_node {- int64_t begin_position;- int64_t total_size;- void *data;-};-struct archive_read_client {- archive_open_callback *opener;- archive_read_callback *reader;- archive_skip_callback *skipper;- archive_seek_callback *seeker;- archive_close_callback *closer;- archive_switch_callback *switcher;- unsigned int nodes;- unsigned int cursor;- int64_t position;- struct archive_read_data_node *dataset;-};-struct archive_read_passphrase {- char *passphrase;- struct archive_read_passphrase *next;-};--struct archive_read_extract {- struct archive *ad; /* archive_write_disk object */-- /* Progress function invoked during extract. */- void (*extract_progress)(void *);- void *extract_progress_user_data;-};--struct archive_read {- struct archive archive;-- struct archive_entry *entry;-- /* Dev/ino of the archive being read/written. */- int skip_file_set;- int64_t skip_file_dev;- int64_t skip_file_ino;-- /* Callbacks to open/read/write/close client archive streams. */- struct archive_read_client client;-- /* Registered filter bidders. */- struct archive_read_filter_bidder bidders[16];-- /* Last filter in chain */- struct archive_read_filter *filter;-- /* Whether to bypass filter bidding process */- int bypass_filter_bidding;-- /* File offset of beginning of most recently-read header. */- int64_t header_position;-- /* Nodes and offsets of compressed data block */- unsigned int data_start_node;- unsigned int data_end_node;-- /*- * Format detection is mostly the same as compression- * detection, with one significant difference: The bidders- * use the read_ahead calls above to examine the stream rather- * than having the supervisor hand them a block of data to- * examine.- */-- struct archive_format_descriptor {- void *data;- const char *name;- int (*bid)(struct archive_read *, int best_bid);- int (*options)(struct archive_read *, const char *key,- const char *value);- int (*read_header)(struct archive_read *, struct archive_entry *);- int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *);- int (*read_data_skip)(struct archive_read *);- int64_t (*seek_data)(struct archive_read *, int64_t, int);- int (*cleanup)(struct archive_read *);- int (*format_capabilties)(struct archive_read *);- int (*has_encrypted_entries)(struct archive_read *);- } formats[16];- struct archive_format_descriptor *format; /* Active format. */-- /*- * Various information needed by archive_extract.- */- struct archive_read_extract *extract;- int (*cleanup_archive_extract)(struct archive_read *);-- /*- * Decryption passphrase.- */- struct {- struct archive_read_passphrase *first;- struct archive_read_passphrase **last;- int candidate;- archive_passphrase_callback *callback;- void *client_data;- } passphrases;-};--int __archive_read_register_format(struct archive_read *a,- void *format_data,- const char *name,- int (*bid)(struct archive_read *, int),- int (*options)(struct archive_read *, const char *, const char *),- int (*read_header)(struct archive_read *, struct archive_entry *),- int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),- int (*read_data_skip)(struct archive_read *),- int64_t (*seek_data)(struct archive_read *, int64_t, int),- int (*cleanup)(struct archive_read *),- int (*format_capabilities)(struct archive_read *),- int (*has_encrypted_entries)(struct archive_read *));--int __archive_read_register_bidder(struct archive_read *a,- void *bidder_data,- const char *name,- const struct archive_read_filter_bidder_vtable *vtable);--const void *__archive_read_ahead(struct archive_read *, size_t, ssize_t *);-const void *__archive_read_filter_ahead(struct archive_read_filter *,- size_t, ssize_t *);-int64_t __archive_read_seek(struct archive_read*, int64_t, int);-int64_t __archive_read_filter_seek(struct archive_read_filter *, int64_t, int);-int64_t __archive_read_consume(struct archive_read *, int64_t);-int64_t __archive_read_filter_consume(struct archive_read_filter *, int64_t);-int __archive_read_header(struct archive_read *, struct archive_entry *);-int __archive_read_program(struct archive_read_filter *, const char *);-void __archive_read_free_filters(struct archive_read *);-struct archive_read_extract *__archive_read_get_extract(struct archive_read *);---/*- * Get a decryption passphrase.- */-void __archive_read_reset_passphrase(struct archive_read *a);-const char * __archive_read_next_passphrase(struct archive_read *a);-#endif
− c/archive_read_set_format.c
@@ -1,117 +0,0 @@-/*-- * Copyright (c) 2003-2012 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_read_private.h"--int-archive_read_set_format(struct archive *_a, int code)-{- int r1, r2, slots, i;- char str[10];- struct archive_read *a = (struct archive_read *)_a;-- if ((r1 = archive_read_support_format_by_code(_a, code)) < (ARCHIVE_OK))- return r1;-- r1 = r2 = (ARCHIVE_OK);- if (a->format)- r2 = (ARCHIVE_WARN);- switch (code & ARCHIVE_FORMAT_BASE_MASK)- {- case ARCHIVE_FORMAT_7ZIP:- strcpy(str, "7zip");- break;- case ARCHIVE_FORMAT_AR:- strcpy(str, "ar");- break;- case ARCHIVE_FORMAT_CAB:- strcpy(str, "cab");- break;- case ARCHIVE_FORMAT_CPIO:- strcpy(str, "cpio");- break;- case ARCHIVE_FORMAT_EMPTY:- strcpy(str, "empty");- break;- case ARCHIVE_FORMAT_ISO9660:- strcpy(str, "iso9660");- break;- case ARCHIVE_FORMAT_LHA:- strcpy(str, "lha");- break;- case ARCHIVE_FORMAT_MTREE:- strcpy(str, "mtree");- break;- case ARCHIVE_FORMAT_RAR:- strcpy(str, "rar");- break;- case ARCHIVE_FORMAT_RAR_V5:- strcpy(str, "rar5");- break;- case ARCHIVE_FORMAT_RAW:- strcpy(str, "raw");- break;- case ARCHIVE_FORMAT_TAR:- strcpy(str, "tar");- break;- case ARCHIVE_FORMAT_WARC:- strcpy(str, "warc");- break;- case ARCHIVE_FORMAT_XAR:- strcpy(str, "xar");- break;- case ARCHIVE_FORMAT_ZIP:- strcpy(str, "zip");- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Invalid format code specified");- return (ARCHIVE_FATAL);- }-- slots = sizeof(a->formats) / sizeof(a->formats[0]);- a->format = &(a->formats[0]);- for (i = 0; i < slots; i++, a->format++) {- if (!a->format->name || !strcmp(a->format->name, str))- break;- }- if (!a->format->name || strcmp(a->format->name, str))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Internal error: Unable to set format");- r1 = (ARCHIVE_FATAL);- }-- return (r1 < r2) ? r1 : r2;-}
− c/archive_read_set_options.c
@@ -1,133 +0,0 @@-/*-- * Copyright (c) 2011 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#include "archive_read_private.h"-#include "archive_options_private.h"--static int archive_set_format_option(struct archive *a,- const char *m, const char *o, const char *v);-static int archive_set_filter_option(struct archive *a,- const char *m, const char *o, const char *v);-static int archive_set_option(struct archive *a,- const char *m, const char *o, const char *v);--int-archive_read_set_format_option(struct archive *a, const char *m, const char *o,- const char *v)-{- return _archive_set_option(a, m, o, v,- ARCHIVE_READ_MAGIC, "archive_read_set_format_option",- archive_set_format_option);-}--int-archive_read_set_filter_option(struct archive *a, const char *m, const char *o,- const char *v)-{- return _archive_set_option(a, m, o, v,- ARCHIVE_READ_MAGIC, "archive_read_set_filter_option",- archive_set_filter_option);-}--int-archive_read_set_option(struct archive *a, const char *m, const char *o,- const char *v)-{- return _archive_set_option(a, m, o, v,- ARCHIVE_READ_MAGIC, "archive_read_set_option",- archive_set_option);-}--int-archive_read_set_options(struct archive *a, const char *options)-{- return _archive_set_options(a, options,- ARCHIVE_READ_MAGIC, "archive_read_set_options",- archive_set_option);-}--static int-archive_set_format_option(struct archive *_a, const char *m, const char *o,- const char *v)-{- struct archive_read *a = (struct archive_read *)_a;- size_t i;- int r, rv = ARCHIVE_WARN, matched_modules = 0;-- for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) {- struct archive_format_descriptor *format = &a->formats[i];-- if (format->options == NULL || format->name == NULL)- /* This format does not support option. */- continue;- if (m != NULL) {- if (strcmp(format->name, m) != 0)- continue;- ++matched_modules;- }-- a->format = format;- r = format->options(a, o, v);- a->format = NULL;-- if (r == ARCHIVE_FATAL)- return (ARCHIVE_FATAL);-- if (r == ARCHIVE_OK)- rv = ARCHIVE_OK;- }- /* If the format name didn't match, return a special code for- * _archive_set_option[s]. */- if (m != NULL && matched_modules == 0)- return ARCHIVE_WARN - 1;- return (rv);-}--static int-archive_set_filter_option(struct archive *_a, const char *m, const char *o,- const char *v)-{- (void)_a; /* UNUSED */- (void)o; /* UNUSED */- (void)v; /* UNUSED */-- /* If the filter name didn't match, return a special code for- * _archive_set_option[s]. */- if (m != NULL)- return ARCHIVE_WARN - 1;- return ARCHIVE_WARN;-}--static int-archive_set_option(struct archive *a, const char *m, const char *o,- const char *v)-{- return _archive_set_either_option(a, m, o, v,- archive_set_format_option,- archive_set_filter_option);-}
− c/archive_read_support_filter_all.c
@@ -1,85 +0,0 @@-/*-- * Copyright (c) 2003-2011 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#include "archive.h"-#include "archive_private.h"--#if ARCHIVE_VERSION_NUMBER < 4000000-/* Deprecated; remove in libarchive 4.0 */-int-archive_read_support_compression_all(struct archive *a)-{- return archive_read_support_filter_all(a);-}-#endif--int-archive_read_support_filter_all(struct archive *a)-{- archive_check_magic(a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_filter_all");-- /* Bzip falls back to "bunzip2" command-line */- archive_read_support_filter_bzip2(a);- /* The decompress code doesn't use an outside library. */- archive_read_support_filter_compress(a);- /* Gzip decompress falls back to "gzip -d" command-line. */- archive_read_support_filter_gzip(a);- /* Lzip falls back to "unlzip" command-line program. */- archive_read_support_filter_lzip(a);- /* The LZMA file format has a very weak signature, so it- * may not be feasible to keep this here, but we'll try.- * This will come back out if there are problems. */- /* Lzma falls back to "unlzma" command-line program. */- archive_read_support_filter_lzma(a);- /* Xz falls back to "unxz" command-line program. */- archive_read_support_filter_xz(a);- /* The decode code doesn't use an outside library. */- archive_read_support_filter_uu(a);- /* The decode code doesn't use an outside library. */- archive_read_support_filter_rpm(a);- /* The decode code always uses "lrzip -q -d" command-line. */- archive_read_support_filter_lrzip(a);- /* Lzop decompress falls back to "lzop -d" command-line. */- archive_read_support_filter_lzop(a);- /* The decode code always uses "grzip -d" command-line. */- archive_read_support_filter_grzip(a);- /* Lz4 falls back to "lz4 -d" command-line program. */- archive_read_support_filter_lz4(a);- /* Zstd falls back to "zstd -d" command-line program. */- archive_read_support_filter_zstd(a);-- /* Note: We always return ARCHIVE_OK here, even if some of the- * above return ARCHIVE_WARN. The intent here is to enable- * "as much as possible." Clients who need specific- * compression should enable those individually so they can- * verify the level of support. */- /* Clear any warning messages set by the above functions. */- archive_clear_error(a);- return (ARCHIVE_OK);-}
− c/archive_read_support_filter_by_code.c
@@ -1,83 +0,0 @@-/*-- * Copyright (c) 2020 Martin Matuska- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#include "archive.h"-#include "archive_private.h"--int-archive_read_support_filter_by_code(struct archive *a, int filter_code)-{- archive_check_magic(a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_filter_by_code");-- switch (filter_code) {- case ARCHIVE_FILTER_NONE:- return archive_read_support_filter_none(a);- break;- case ARCHIVE_FILTER_GZIP:- return archive_read_support_filter_gzip(a);- break;- case ARCHIVE_FILTER_BZIP2:- return archive_read_support_filter_bzip2(a);- break;- case ARCHIVE_FILTER_COMPRESS:- return archive_read_support_filter_compress(a);- break;- case ARCHIVE_FILTER_LZMA:- return archive_read_support_filter_lzma(a);- break;- case ARCHIVE_FILTER_XZ:- return archive_read_support_filter_xz(a);- break;- case ARCHIVE_FILTER_UU:- return archive_read_support_filter_uu(a);- break;- case ARCHIVE_FILTER_RPM:- return archive_read_support_filter_rpm(a);- break;- case ARCHIVE_FILTER_LZIP:- return archive_read_support_filter_lzip(a);- break;- case ARCHIVE_FILTER_LRZIP:- return archive_read_support_filter_lrzip(a);- break;- case ARCHIVE_FILTER_LZOP:- return archive_read_support_filter_lzop(a);- break;- case ARCHIVE_FILTER_GRZIP:- return archive_read_support_filter_grzip(a);- break;- case ARCHIVE_FILTER_LZ4:- return archive_read_support_filter_lz4(a);- break;- case ARCHIVE_FILTER_ZSTD:- return archive_read_support_filter_zstd(a);- break;- }- return (ARCHIVE_FATAL);-}
− c/archive_read_support_filter_bzip2.c
@@ -1,365 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#ifdef HAVE_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_UNISTD_H-#include <unistd.h>-#endif-#ifdef HAVE_BZLIB_H-#include <bzlib.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_read_private.h"--#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)-struct private_data {- bz_stream stream;- char *out_block;- size_t out_block_size;- char valid; /* True = decompressor is initialized */- char eof; /* True = found end of compressed data. */-};--/* Bzip2 filter */-static ssize_t bzip2_filter_read(struct archive_read_filter *, const void **);-static int bzip2_filter_close(struct archive_read_filter *);-#endif--/*- * Note that we can detect bzip2 archives even if we can't decompress- * them. (In fact, we like detecting them because we can give better- * error messages.) So the bid framework here gets compiled even- * if bzlib is unavailable.- */-static int bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);-static int bzip2_reader_init(struct archive_read_filter *);--#if ARCHIVE_VERSION_NUMBER < 4000000-/* Deprecated; remove in libarchive 4.0 */-int-archive_read_support_compression_bzip2(struct archive *a)-{- return archive_read_support_filter_bzip2(a);-}-#endif--static const struct archive_read_filter_bidder_vtable-bzip2_bidder_vtable = {- .bid = bzip2_reader_bid,- .init = bzip2_reader_init,-};--int-archive_read_support_filter_bzip2(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- if (__archive_read_register_bidder(a, NULL, "bzip2",- &bzip2_bidder_vtable) != ARCHIVE_OK)- return (ARCHIVE_FATAL);--#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- return (ARCHIVE_OK);-#else- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external bzip2 program");- return (ARCHIVE_WARN);-#endif-}--/*- * Test whether we can handle this data.- *- * This logic returns zero if any part of the signature fails. It- * also tries to Do The Right Thing if a very short buffer prevents us- * from verifying as much as we would like.- */-static int-bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_filter *filter)-{- const unsigned char *buffer;- ssize_t avail;- int bits_checked;-- (void)self; /* UNUSED */-- /* Minimal bzip2 archive is 14 bytes. */- buffer = __archive_read_filter_ahead(filter, 14, &avail);- if (buffer == NULL)- return (0);-- /* First three bytes must be "BZh" */- bits_checked = 0;- if (memcmp(buffer, "BZh", 3) != 0)- return (0);- bits_checked += 24;-- /* Next follows a compression flag which must be an ASCII digit. */- if (buffer[3] < '1' || buffer[3] > '9')- return (0);- bits_checked += 5;-- /* After BZh[1-9], there must be either a data block- * which begins with 0x314159265359 or an end-of-data- * marker of 0x177245385090. */- if (memcmp(buffer + 4, "\x31\x41\x59\x26\x53\x59", 6) == 0)- bits_checked += 48;- else if (memcmp(buffer + 4, "\x17\x72\x45\x38\x50\x90", 6) == 0)- bits_checked += 48;- else- return (0);-- return (bits_checked);-}--#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)--/*- * If we don't have the library on this system, we can't actually do the- * decompression. We can, however, still detect compressed archives- * and emit a useful message.- */-static int-bzip2_reader_init(struct archive_read_filter *self)-{- int r;-- r = __archive_read_program(self, "bzip2 -d");- /* Note: We set the format here even if __archive_read_program()- * above fails. We do, after all, know what the format is- * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_BZIP2;- self->name = "bzip2";- return (r);-}---#else--static const struct archive_read_filter_vtable-bzip2_reader_vtable = {- .read = bzip2_filter_read,- .close = bzip2_filter_close,-};--/*- * Setup the callbacks.- */-static int-bzip2_reader_init(struct archive_read_filter *self)-{- static const size_t out_block_size = 64 * 1024;- void *out_block;- struct private_data *state;-- self->code = ARCHIVE_FILTER_BZIP2;- self->name = "bzip2";-- state = (struct private_data *)calloc(sizeof(*state), 1);- out_block = (unsigned char *)malloc(out_block_size);- if (state == NULL || out_block == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for bzip2 decompression");- free(out_block);- free(state);- return (ARCHIVE_FATAL);- }-- self->data = state;- state->out_block_size = out_block_size;- state->out_block = out_block;- self->vtable = &bzip2_reader_vtable;-- return (ARCHIVE_OK);-}--/*- * Return the next block of decompressed data.- */-static ssize_t-bzip2_filter_read(struct archive_read_filter *self, const void **p)-{- struct private_data *state;- size_t decompressed;- const char *read_buf;- ssize_t ret;-- state = (struct private_data *)self->data;-- if (state->eof) {- *p = NULL;- return (0);- }-- /* Empty our output buffer. */- state->stream.next_out = state->out_block;- state->stream.avail_out = (uint32_t)state->out_block_size;-- /* Try to fill the output buffer. */- for (;;) {- if (!state->valid) {- if (bzip2_reader_bid(self->bidder, self->upstream) == 0) {- state->eof = 1;- *p = state->out_block;- decompressed = state->stream.next_out- - state->out_block;- return (decompressed);- }- /* Initialize compression library. */- ret = BZ2_bzDecompressInit(&(state->stream),- 0 /* library verbosity */,- 0 /* don't use low-mem algorithm */);-- /* If init fails, try low-memory algorithm instead. */- if (ret == BZ_MEM_ERROR)- ret = BZ2_bzDecompressInit(&(state->stream),- 0 /* library verbosity */,- 1 /* do use low-mem algo */);-- if (ret != BZ_OK) {- const char *detail = NULL;- int err = ARCHIVE_ERRNO_MISC;- switch (ret) {- case BZ_PARAM_ERROR:- detail = "invalid setup parameter";- break;- case BZ_MEM_ERROR:- err = ENOMEM;- detail = "out of memory";- break;- case BZ_CONFIG_ERROR:- detail = "mis-compiled library";- break;- }- archive_set_error(&self->archive->archive, err,- "Internal error initializing decompressor%s%s",- detail == NULL ? "" : ": ",- detail);- return (ARCHIVE_FATAL);- }- state->valid = 1;- }-- /* stream.next_in is really const, but bzlib- * doesn't declare it so. <sigh> */- read_buf =- __archive_read_filter_ahead(self->upstream, 1, &ret);- if (read_buf == NULL) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "truncated bzip2 input");- return (ARCHIVE_FATAL);- }- state->stream.next_in = (char *)(uintptr_t)read_buf;- state->stream.avail_in = (uint32_t)ret;- /* There is no more data, return whatever we have. */- if (ret == 0) {- state->eof = 1;- *p = state->out_block;- decompressed = state->stream.next_out- - state->out_block;- return (decompressed);- }-- /* Decompress as much as we can in one pass. */- ret = BZ2_bzDecompress(&(state->stream));- __archive_read_filter_consume(self->upstream,- state->stream.next_in - read_buf);-- switch (ret) {- case BZ_STREAM_END: /* Found end of stream. */- switch (BZ2_bzDecompressEnd(&(state->stream))) {- case BZ_OK:- break;- default:- archive_set_error(&(self->archive->archive),- ARCHIVE_ERRNO_MISC,- "Failed to clean up decompressor");- return (ARCHIVE_FATAL);- }- state->valid = 0;- /* FALLTHROUGH */- case BZ_OK: /* Decompressor made some progress. */- /* If we filled our buffer, update stats and return. */- if (state->stream.avail_out == 0) {- *p = state->out_block;- decompressed = state->stream.next_out- - state->out_block;- return (decompressed);- }- break;- default: /* Return an error. */- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC, "bzip decompression failed");- return (ARCHIVE_FATAL);- }- }-}--/*- * Clean up the decompressor.- */-static int-bzip2_filter_close(struct archive_read_filter *self)-{- struct private_data *state;- int ret = ARCHIVE_OK;-- state = (struct private_data *)self->data;-- if (state->valid) {- switch (BZ2_bzDecompressEnd(&state->stream)) {- case BZ_OK:- break;- default:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Failed to clean up decompressor");- ret = ARCHIVE_FATAL;- }- state->valid = 0;- }-- free(state->out_block);- free(state);- return (ret);-}--#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
− c/archive_read_support_filter_compress.c
@@ -1,452 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--/*- * This code borrows heavily from "compress" source code, which is- * protected by the following copyright. (Clause 3 dropped by request- * of the Regents.)- */--/*-- * Copyright (c) 1985, 1986, 1992, 1993- * The Regents of the University of California. All rights reserved.- *- * This code is derived from software contributed to Berkeley by- * Diomidis Spinellis and James A. Woods, derived from original- * work by Spencer Thomas and Joseph Orost.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- * 4. Neither the name of the University nor the names of its contributors- * may be used to endorse or promote products derived from this software- * without specific prior written permission.- *- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF- * SUCH DAMAGE.- */---#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_read_private.h"--/*- * Because LZW decompression is pretty simple, I've just implemented- * the whole decompressor here (cribbing from "compress" source code,- * of course), rather than relying on an external library. I have- * made an effort to clarify and simplify the algorithm, so the- * names and structure here don't exactly match those used by compress.- */--struct private_data {- /* Input variables. */- const unsigned char *next_in;- size_t avail_in;- size_t consume_unnotified;- int bit_buffer;- int bits_avail;- size_t bytes_in_section;-- /* Output variables. */- size_t out_block_size;- void *out_block;-- /* Decompression status variables. */- int use_reset_code;- int end_of_stream; /* EOF status. */- int maxcode; /* Largest code. */- int maxcode_bits; /* Length of largest code. */- int section_end_code; /* When to increase bits. */- int bits; /* Current code length. */- int oldcode; /* Previous code. */- int finbyte; /* Last byte of prev code. */-- /* Dictionary. */- int free_ent; /* Next dictionary entry. */- unsigned char suffix[65536];- uint16_t prefix[65536];-- /*- * Scratch area for expanding dictionary entries. Note:- * "worst" case here comes from compressing /dev/zero: the- * last code in the dictionary will code a sequence of- * 65536-256 zero bytes. Thus, we need stack space to expand- * a 65280-byte dictionary entry. (Of course, 32640:1- * compression could also be considered the "best" case. ;-)- */- unsigned char *stackp;- unsigned char stack[65300];-};--static int compress_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);-static int compress_bidder_init(struct archive_read_filter *);--static ssize_t compress_filter_read(struct archive_read_filter *, const void **);-static int compress_filter_close(struct archive_read_filter *);--static int getbits(struct archive_read_filter *, int n);-static int next_code(struct archive_read_filter *);--#if ARCHIVE_VERSION_NUMBER < 4000000-/* Deprecated; remove in libarchive 4.0 */-int-archive_read_support_compression_compress(struct archive *a)-{- return archive_read_support_filter_compress(a);-}-#endif--static const struct archive_read_filter_bidder_vtable-compress_bidder_vtable = {- .bid = compress_bidder_bid,- .init = compress_bidder_init,-};--int-archive_read_support_filter_compress(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- return __archive_read_register_bidder(a, NULL, "compress (.Z)",- &compress_bidder_vtable);-}--/*- * Test whether we can handle this data.- * This logic returns zero if any part of the signature fails.- */-static int-compress_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- const unsigned char *buffer;- ssize_t avail;- int bits_checked;-- (void)self; /* UNUSED */-- /* Shortest valid compress file is 3 bytes. */- buffer = __archive_read_filter_ahead(filter, 3, &avail);-- if (buffer == NULL)- return (0);-- bits_checked = 0;- /* First two bytes are the magic value */- if (buffer[0] != 0x1F || buffer[1] != 0x9D)- return (0);- /* Third byte holds compression parameters. */- if (buffer[2] & 0x20) /* Reserved bit, must be zero. */- return (0);- if (buffer[2] & 0x40) /* Reserved bit, must be zero. */- return (0);- bits_checked += 18;-- return (bits_checked);-}--static const struct archive_read_filter_vtable-compress_reader_vtable = {- .read = compress_filter_read,- .close = compress_filter_close,-};--/*- * Setup the callbacks.- */-static int-compress_bidder_init(struct archive_read_filter *self)-{- struct private_data *state;- static const size_t out_block_size = 64 * 1024;- void *out_block;- int code;-- self->code = ARCHIVE_FILTER_COMPRESS;- self->name = "compress (.Z)";-- state = (struct private_data *)calloc(sizeof(*state), 1);- out_block = malloc(out_block_size);- if (state == NULL || out_block == NULL) {- free(out_block);- free(state);- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for %s decompression",- self->name);- return (ARCHIVE_FATAL);- }-- self->data = state;- state->out_block_size = out_block_size;- state->out_block = out_block;- self->vtable = &compress_reader_vtable;-- /* XXX MOVE THE FOLLOWING OUT OF INIT() XXX */-- (void)getbits(self, 8); /* Skip first signature byte. */- (void)getbits(self, 8); /* Skip second signature byte. */-- /* Get compression parameters. */- code = getbits(self, 8);- if ((code & 0x1f) > 16) {- archive_set_error(&self->archive->archive, -1,- "Invalid compressed data");- return (ARCHIVE_FATAL);- }- state->maxcode_bits = code & 0x1f;- state->maxcode = (1 << state->maxcode_bits);- state->use_reset_code = code & 0x80;-- /* Initialize decompressor. */- state->free_ent = 256;- state->stackp = state->stack;- if (state->use_reset_code)- state->free_ent++;- state->bits = 9;- state->section_end_code = (1<<state->bits) - 1;- state->oldcode = -1;- for (code = 255; code >= 0; code--) {- state->prefix[code] = 0;- state->suffix[code] = code;- }- next_code(self);-- return (ARCHIVE_OK);-}--/*- * Return a block of data from the decompression buffer. Decompress more- * as necessary.- */-static ssize_t-compress_filter_read(struct archive_read_filter *self, const void **pblock)-{- struct private_data *state;- unsigned char *p, *start, *end;- int ret;-- state = (struct private_data *)self->data;- if (state->end_of_stream) {- *pblock = NULL;- return (0);- }- p = start = (unsigned char *)state->out_block;- end = start + state->out_block_size;-- while (p < end && !state->end_of_stream) {- if (state->stackp > state->stack) {- *p++ = *--state->stackp;- } else {- ret = next_code(self);- if (ret == -1)- state->end_of_stream = ret;- else if (ret != ARCHIVE_OK)- return (ret);- }- }-- *pblock = start;- return (p - start);-}--/*- * Close and release the filter.- */-static int-compress_filter_close(struct archive_read_filter *self)-{- struct private_data *state = (struct private_data *)self->data;-- free(state->out_block);- free(state);- return (ARCHIVE_OK);-}--/*- * Process the next code and fill the stack with the expansion- * of the code. Returns ARCHIVE_FATAL if there is a fatal I/O or- * format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.- */-static int-next_code(struct archive_read_filter *self)-{- struct private_data *state = (struct private_data *)self->data;- int code, newcode;-- static int debug_buff[1024];- static unsigned debug_index;-- code = newcode = getbits(self, state->bits);- if (code < 0)- return (code);-- debug_buff[debug_index++] = code;- if (debug_index >= sizeof(debug_buff)/sizeof(debug_buff[0]))- debug_index = 0;-- /* If it's a reset code, reset the dictionary. */- if ((code == 256) && state->use_reset_code) {- /*- * The original 'compress' implementation blocked its- * I/O in a manner that resulted in junk bytes being- * inserted after every reset. The next section skips- * this junk. (Yes, the number of *bytes* to skip is- * a function of the current *bit* length.)- */- int skip_bytes = state->bits -- (state->bytes_in_section % state->bits);- skip_bytes %= state->bits;- state->bits_avail = 0; /* Discard rest of this byte. */- while (skip_bytes-- > 0) {- code = getbits(self, 8);- if (code < 0)- return (code);- }- /* Now, actually do the reset. */- state->bytes_in_section = 0;- state->bits = 9;- state->section_end_code = (1 << state->bits) - 1;- state->free_ent = 257;- state->oldcode = -1;- return (next_code(self));- }-- if (code > state->free_ent- || (code == state->free_ent && state->oldcode < 0)) {- /* An invalid code is a fatal error. */- archive_set_error(&(self->archive->archive), -1,- "Invalid compressed data");- return (ARCHIVE_FATAL);- }-- /* Special case for KwKwK string. */- if (code >= state->free_ent) {- *state->stackp++ = state->finbyte;- code = state->oldcode;- }-- /* Generate output characters in reverse order. */- while (code >= 256) {- *state->stackp++ = state->suffix[code];- code = state->prefix[code];- }- *state->stackp++ = state->finbyte = code;-- /* Generate the new entry. */- code = state->free_ent;- if (code < state->maxcode && state->oldcode >= 0) {- state->prefix[code] = state->oldcode;- state->suffix[code] = state->finbyte;- ++state->free_ent;- }- if (state->free_ent > state->section_end_code) {- state->bits++;- state->bytes_in_section = 0;- if (state->bits == state->maxcode_bits)- state->section_end_code = state->maxcode;- else- state->section_end_code = (1 << state->bits) - 1;- }-- /* Remember previous code. */- state->oldcode = newcode;- return (ARCHIVE_OK);-}--/*- * Return next 'n' bits from stream.- *- * -1 indicates end of available data.- */-static int-getbits(struct archive_read_filter *self, int n)-{- struct private_data *state = (struct private_data *)self->data;- int code;- ssize_t ret;- static const int mask[] = {- 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,- 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff- };-- while (state->bits_avail < n) {- if (state->avail_in <= 0) {- if (state->consume_unnotified) {- __archive_read_filter_consume(self->upstream,- state->consume_unnotified);- state->consume_unnotified = 0;- }- state->next_in- = __archive_read_filter_ahead(self->upstream,- 1, &ret);- if (ret == 0)- return (-1);- if (ret < 0 || state->next_in == NULL)- return (ARCHIVE_FATAL);- state->consume_unnotified = state->avail_in = ret;- }- state->bit_buffer |= *state->next_in++ << state->bits_avail;- state->avail_in--;- state->bits_avail += 8;- state->bytes_in_section++;- }-- code = state->bit_buffer;- state->bit_buffer >>= n;- state->bits_avail -= n;-- return (code & mask[n]);-}
− c/archive_read_support_filter_grzip.c
@@ -1,112 +0,0 @@-/*-- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");---#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_read_private.h"--static const unsigned char grzip_magic[] = {- 0x47, 0x52, 0x5a, 0x69, 0x70, 0x49, 0x49, 0x00,- 0x02, 0x04, 0x3a, 0x29 };--static int grzip_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *);-static int grzip_bidder_init(struct archive_read_filter *);---static const struct archive_read_filter_bidder_vtable-grzip_bidder_vtable = {- .bid = grzip_bidder_bid,- .init = grzip_bidder_init,-};--int-archive_read_support_filter_grzip(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- if (__archive_read_register_bidder(a, NULL, NULL,- &grzip_bidder_vtable) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* This filter always uses an external program. */- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external grzip program for grzip decompression");- return (ARCHIVE_WARN);-}--/*- * Bidder just verifies the header and returns the number of verified bits.- */-static int-grzip_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- const unsigned char *p;- ssize_t avail;-- (void)self; /* UNUSED */-- p = __archive_read_filter_ahead(filter, sizeof(grzip_magic), &avail);- if (p == NULL || avail == 0)- return (0);-- if (memcmp(p, grzip_magic, sizeof(grzip_magic)))- return (0);-- return (sizeof(grzip_magic) * 8);-}--static int-grzip_bidder_init(struct archive_read_filter *self)-{- int r;-- r = __archive_read_program(self, "grzip -d");- /* Note: We set the format here even if __archive_read_program()- * above fails. We do, after all, know what the format is- * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_GRZIP;- self->name = "grzip";- return (r);-}
− c/archive_read_support_filter_gzip.c
@@ -1,536 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");---#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_endian.h"-#include "archive_private.h"-#include "archive_read_private.h"--#ifdef HAVE_ZLIB_H-struct private_data {- z_stream stream;- char in_stream;- unsigned char *out_block;- size_t out_block_size;- int64_t total_out;- unsigned long crc;- uint32_t mtime;- char *name;- char eof; /* True = found end of compressed data. */-};--/* Gzip Filter. */-static ssize_t gzip_filter_read(struct archive_read_filter *, const void **);-static int gzip_filter_close(struct archive_read_filter *);-#endif--/*- * Note that we can detect gzip archives even if we can't decompress- * them. (In fact, we like detecting them because we can give better- * error messages.) So the bid framework here gets compiled even- * if zlib is unavailable.- *- * TODO: If zlib is unavailable, gzip_bidder_init() should- * use the compress_program framework to try to fire up an external- * gzip program.- */-static int gzip_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *);-static int gzip_bidder_init(struct archive_read_filter *);--#if ARCHIVE_VERSION_NUMBER < 4000000-/* Deprecated; remove in libarchive 4.0 */-int-archive_read_support_compression_gzip(struct archive *a)-{- return archive_read_support_filter_gzip(a);-}-#endif--static const struct archive_read_filter_bidder_vtable-gzip_bidder_vtable = {- .bid = gzip_bidder_bid,- .init = gzip_bidder_init,-};--int-archive_read_support_filter_gzip(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- if (__archive_read_register_bidder(a, NULL, "gzip",- &gzip_bidder_vtable) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Signal the extent of gzip support with the return value here. */-#if HAVE_ZLIB_H- return (ARCHIVE_OK);-#else- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external gzip program");- return (ARCHIVE_WARN);-#endif-}--/*- * Read and verify the header.- *- * Returns zero if the header couldn't be validated, else returns- * number of bytes in header. If pbits is non-NULL, it receives a- * count of bits verified, suitable for use by bidder.- */-static ssize_t-peek_at_header(struct archive_read_filter *filter, int *pbits,-#ifdef HAVE_ZLIB_H- struct private_data *state-#else- void *state-#endif- )-{- const unsigned char *p;- ssize_t avail, len;- int bits = 0;- int header_flags;-#ifndef HAVE_ZLIB_H- (void)state; /* UNUSED */-#endif-- /* Start by looking at the first ten bytes of the header, which- * is all fixed layout. */- len = 10;- p = __archive_read_filter_ahead(filter, len, &avail);- if (p == NULL || avail == 0)- return (0);- /* We only support deflation- third byte must be 0x08. */- if (memcmp(p, "\x1F\x8B\x08", 3) != 0)- return (0);- bits += 24;- if ((p[3] & 0xE0)!= 0) /* No reserved flags set. */- return (0);- bits += 3;- header_flags = p[3];- /* Bytes 4-7 are mod time in little endian. */-#ifdef HAVE_ZLIB_H- if (state)- state->mtime = archive_le32dec(p + 4);-#endif- /* Byte 8 is deflate flags. */- /* XXXX TODO: return deflate flags back to consume_header for use- in initializing the decompressor. */- /* Byte 9 is OS. */-- /* Optional extra data: 2 byte length plus variable body. */- if (header_flags & 4) {- p = __archive_read_filter_ahead(filter, len + 2, &avail);- if (p == NULL)- return (0);- len += ((int)p[len + 1] << 8) | (int)p[len];- len += 2;- }-- /* Null-terminated optional filename. */- if (header_flags & 8) {-#ifdef HAVE_ZLIB_H- ssize_t file_start = len;-#endif- do {- ++len;- if (avail < len)- p = __archive_read_filter_ahead(filter,- len, &avail);- if (p == NULL)- return (0);- } while (p[len - 1] != 0);--#ifdef HAVE_ZLIB_H- if (state) {- /* Reset the name in case of repeat header reads. */- free(state->name);- state->name = strdup((const char *)&p[file_start]);- }-#endif- }-- /* Null-terminated optional comment. */- if (header_flags & 16) {- do {- ++len;- if (avail < len)- p = __archive_read_filter_ahead(filter,- len, &avail);- if (p == NULL)- return (0);- } while (p[len - 1] != 0);- }-- /* Optional header CRC */- if ((header_flags & 2)) {- p = __archive_read_filter_ahead(filter, len + 2, &avail);- if (p == NULL)- return (0);-#if 0- int hcrc = ((int)p[len + 1] << 8) | (int)p[len];- int crc = /* XXX TODO: Compute header CRC. */;- if (crc != hcrc)- return (0);- bits += 16;-#endif- len += 2;- }-- if (pbits != NULL)- *pbits = bits;- return (len);-}--/*- * Bidder just verifies the header and returns the number of verified bits.- */-static int-gzip_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- int bits_checked;-- (void)self; /* UNUSED */-- if (peek_at_header(filter, &bits_checked, NULL))- return (bits_checked);- return (0);-}--#ifndef HAVE_ZLIB_H--/*- * If we don't have the library on this system, we can't do the- * decompression directly. We can, however, try to run "gzip -d"- * in case that's available.- */-static int-gzip_bidder_init(struct archive_read_filter *self)-{- int r;-- r = __archive_read_program(self, "gzip -d");- /* Note: We set the format here even if __archive_read_program()- * above fails. We do, after all, know what the format is- * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_GZIP;- self->name = "gzip";- return (r);-}--#else--static int-gzip_read_header(struct archive_read_filter *self, struct archive_entry *entry)-{- struct private_data *state;-- state = (struct private_data *)self->data;-- /* A mtime of 0 is considered invalid/missing. */- if (state->mtime != 0)- archive_entry_set_mtime(entry, state->mtime, 0);-- /* If the name is available, extract it. */- if (state->name)- archive_entry_set_pathname(entry, state->name);-- return (ARCHIVE_OK);-}--static const struct archive_read_filter_vtable-gzip_reader_vtable = {- .read = gzip_filter_read,- .close = gzip_filter_close,-#ifdef HAVE_ZLIB_H- .read_header = gzip_read_header,-#endif-};--/*- * Initialize the filter object.- */-static int-gzip_bidder_init(struct archive_read_filter *self)-{- struct private_data *state;- static const size_t out_block_size = 64 * 1024;- void *out_block;-- self->code = ARCHIVE_FILTER_GZIP;- self->name = "gzip";-- state = (struct private_data *)calloc(sizeof(*state), 1);- out_block = (unsigned char *)malloc(out_block_size);- if (state == NULL || out_block == NULL) {- free(out_block);- free(state);- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for gzip decompression");- return (ARCHIVE_FATAL);- }-- self->data = state;- state->out_block_size = out_block_size;- state->out_block = out_block;- self->vtable = &gzip_reader_vtable;-- state->in_stream = 0; /* We're not actually within a stream yet. */-- return (ARCHIVE_OK);-}--static int-consume_header(struct archive_read_filter *self)-{- struct private_data *state;- ssize_t avail;- size_t len;- int ret;-- state = (struct private_data *)self->data;-- /* If this is a real header, consume it. */- len = peek_at_header(self->upstream, NULL, state);- if (len == 0)- return (ARCHIVE_EOF);- __archive_read_filter_consume(self->upstream, len);-- /* Initialize CRC accumulator. */- state->crc = crc32(0L, NULL, 0);-- /* Initialize compression library. */- state->stream.next_in = (unsigned char *)(uintptr_t)- __archive_read_filter_ahead(self->upstream, 1, &avail);- state->stream.avail_in = (uInt)avail;- ret = inflateInit2(&(state->stream),- -15 /* Don't check for zlib header */);-- /* Decipher the error code. */- switch (ret) {- case Z_OK:- state->in_stream = 1;- return (ARCHIVE_OK);- case Z_STREAM_ERROR:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Internal error initializing compression library: "- "invalid setup parameter");- break;- case Z_MEM_ERROR:- archive_set_error(&self->archive->archive, ENOMEM,- "Internal error initializing compression library: "- "out of memory");- break;- case Z_VERSION_ERROR:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Internal error initializing compression library: "- "invalid library version");- break;- default:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Internal error initializing compression library: "- " Zlib error %d", ret);- break;- }- return (ARCHIVE_FATAL);-}--static int-consume_trailer(struct archive_read_filter *self)-{- struct private_data *state;- const unsigned char *p;- ssize_t avail;-- state = (struct private_data *)self->data;-- state->in_stream = 0;- switch (inflateEnd(&(state->stream))) {- case Z_OK:- break;- default:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Failed to clean up gzip decompressor");- return (ARCHIVE_FATAL);- }-- /* GZip trailer is a fixed 8 byte structure. */- p = __archive_read_filter_ahead(self->upstream, 8, &avail);- if (p == NULL || avail == 0)- return (ARCHIVE_FATAL);-- /* XXX TODO: Verify the length and CRC. */-- /* We've verified the trailer, so consume it now. */- __archive_read_filter_consume(self->upstream, 8);-- return (ARCHIVE_OK);-}--static ssize_t-gzip_filter_read(struct archive_read_filter *self, const void **p)-{- struct private_data *state;- size_t decompressed;- ssize_t avail_in, max_in;- int ret;-- state = (struct private_data *)self->data;-- /* Empty our output buffer. */- state->stream.next_out = state->out_block;- state->stream.avail_out = (uInt)state->out_block_size;-- /* Try to fill the output buffer. */- while (state->stream.avail_out > 0 && !state->eof) {- /* If we're not in a stream, read a header- * and initialize the decompression library. */- if (!state->in_stream) {- ret = consume_header(self);- if (ret == ARCHIVE_EOF) {- state->eof = 1;- break;- }- if (ret < ARCHIVE_OK)- return (ret);- }-- /* Peek at the next available data. */- /* ZLib treats stream.next_in as const but doesn't declare- * it so, hence this ugly cast. */- state->stream.next_in = (unsigned char *)(uintptr_t)- __archive_read_filter_ahead(self->upstream, 1, &avail_in);- if (state->stream.next_in == NULL) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "truncated gzip input");- return (ARCHIVE_FATAL);- }- if (UINT_MAX >= SSIZE_MAX)- max_in = SSIZE_MAX;- else- max_in = UINT_MAX;- if (avail_in > max_in)- avail_in = max_in;- state->stream.avail_in = (uInt)avail_in;-- /* Decompress and consume some of that data. */- ret = inflate(&(state->stream), 0);- switch (ret) {- case Z_OK: /* Decompressor made some progress. */- __archive_read_filter_consume(self->upstream,- avail_in - state->stream.avail_in);- break;- case Z_STREAM_END: /* Found end of stream. */- __archive_read_filter_consume(self->upstream,- avail_in - state->stream.avail_in);- /* Consume the stream trailer; release the- * decompression library. */- ret = consume_trailer(self);- if (ret < ARCHIVE_OK)- return (ret);- break;- default:- /* Return an error. */- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "gzip decompression failed");- return (ARCHIVE_FATAL);- }- }-- /* We've read as much as we can. */- decompressed = state->stream.next_out - state->out_block;- state->total_out += decompressed;- if (decompressed == 0)- *p = NULL;- else- *p = state->out_block;- return (decompressed);-}--/*- * Clean up the decompressor.- */-static int-gzip_filter_close(struct archive_read_filter *self)-{- struct private_data *state;- int ret;-- state = (struct private_data *)self->data;- ret = ARCHIVE_OK;-- if (state->in_stream) {- switch (inflateEnd(&(state->stream))) {- case Z_OK:- break;- default:- archive_set_error(&(self->archive->archive),- ARCHIVE_ERRNO_MISC,- "Failed to clean up gzip compressor");- ret = ARCHIVE_FATAL;- }- }-- free(state->name);- free(state->out_block);- free(state);- return (ret);-}--#endif /* HAVE_ZLIB_H */
− c/archive_read_support_filter_lrzip.c
@@ -1,122 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");---#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_read_private.h"--#define LRZIP_HEADER_MAGIC "LRZI"-#define LRZIP_HEADER_MAGIC_LEN 4--static int lrzip_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *);-static int lrzip_bidder_init(struct archive_read_filter *);---static const struct archive_read_filter_bidder_vtable-lrzip_bidder_vtable = {- .bid = lrzip_bidder_bid,- .init = lrzip_bidder_init,-};--int-archive_read_support_filter_lrzip(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- if (__archive_read_register_bidder(a, NULL, "lrzip",- &lrzip_bidder_vtable) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* This filter always uses an external program. */- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external lrzip program for lrzip decompression");- return (ARCHIVE_WARN);-}--/*- * Bidder just verifies the header and returns the number of verified bits.- */-static int-lrzip_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- const unsigned char *p;- ssize_t avail, len;- int i;-- (void)self; /* UNUSED */- /* Start by looking at the first six bytes of the header, which- * is all fixed layout. */- len = 6;- p = __archive_read_filter_ahead(filter, len, &avail);- if (p == NULL || avail == 0)- return (0);-- if (memcmp(p, LRZIP_HEADER_MAGIC, LRZIP_HEADER_MAGIC_LEN))- return (0);-- /* current major version is always 0, verify this */- if (p[LRZIP_HEADER_MAGIC_LEN])- return 0;- /* support only v0.6+ lrzip for sanity */- i = p[LRZIP_HEADER_MAGIC_LEN + 1];- if ((i < 6) || (i > 10))- return 0;-- return (int)len;-}--static int-lrzip_bidder_init(struct archive_read_filter *self)-{- int r;-- r = __archive_read_program(self, "lrzip -d -q");- /* Note: We set the format here even if __archive_read_program()- * above fails. We do, after all, know what the format is- * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_LRZIP;- self->name = "lrzip";- return (r);-}
− c/archive_read_support_filter_lz4.c
@@ -1,742 +0,0 @@-/*-- * Copyright (c) 2014 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#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_UNISTD_H-#include <unistd.h>-#endif-#ifdef HAVE_LZ4_H-#include <lz4.h>-#endif--#include "archive.h"-#include "archive_endian.h"-#include "archive_private.h"-#include "archive_read_private.h"-#include "archive_xxhash.h"--#define LZ4_MAGICNUMBER 0x184d2204-#define LZ4_SKIPPABLED 0x184d2a50-#define LZ4_LEGACY 0x184c2102--#if defined(HAVE_LIBLZ4)-struct private_data {- enum { SELECT_STREAM,- READ_DEFAULT_STREAM,- READ_DEFAULT_BLOCK,- READ_LEGACY_STREAM,- READ_LEGACY_BLOCK,- } stage;- struct {- unsigned block_independence:1;- unsigned block_checksum:3;- unsigned stream_size:1;- unsigned stream_checksum:1;- unsigned preset_dictionary:1;- int block_maximum_size;- } flags;- int64_t stream_size;- uint32_t dict_id;- char *out_block;- size_t out_block_size;-- /* Bytes read but not yet consumed via __archive_read_consume() */- size_t unconsumed;- size_t decoded_size;- void *xxh32_state;-- char valid; /* True = decompressor is initialized */- char eof; /* True = found end of compressed data. */-};--#define LEGACY_BLOCK_SIZE (8 * 1024 * 1024)--/* Lz4 filter */-static ssize_t lz4_filter_read(struct archive_read_filter *, const void **);-static int lz4_filter_close(struct archive_read_filter *);-#endif--/*- * Note that we can detect lz4 archives even if we can't decompress- * them. (In fact, we like detecting them because we can give better- * error messages.) So the bid framework here gets compiled even- * if liblz4 is unavailable.- */-static int lz4_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);-static int lz4_reader_init(struct archive_read_filter *);-#if defined(HAVE_LIBLZ4)-static ssize_t lz4_filter_read_default_stream(struct archive_read_filter *,- const void **);-static ssize_t lz4_filter_read_legacy_stream(struct archive_read_filter *,- const void **);-#endif--static const struct archive_read_filter_bidder_vtable-lz4_bidder_vtable = {- .bid = lz4_reader_bid,- .init = lz4_reader_init,-};--int-archive_read_support_filter_lz4(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- if (__archive_read_register_bidder(a, NULL, "lz4",- &lz4_bidder_vtable) != ARCHIVE_OK)- return (ARCHIVE_FATAL);--#if defined(HAVE_LIBLZ4)- return (ARCHIVE_OK);-#else- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external lz4 program");- return (ARCHIVE_WARN);-#endif-}--/*- * Test whether we can handle this data.- *- * This logic returns zero if any part of the signature fails. It- * also tries to Do The Right Thing if a very short buffer prevents us- * from verifying as much as we would like.- */-static int-lz4_reader_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- const unsigned char *buffer;- ssize_t avail;- int bits_checked;- uint32_t number;-- (void)self; /* UNUSED */-- /* Minimal lz4 archive is 11 bytes. */- buffer = __archive_read_filter_ahead(filter, 11, &avail);- if (buffer == NULL)- return (0);-- /* First four bytes must be LZ4 magic numbers. */- bits_checked = 0;- if ((number = archive_le32dec(buffer)) == LZ4_MAGICNUMBER) {- unsigned char flag, BD;-- bits_checked += 32;- /* Next follows a stream descriptor. */- /* Descriptor Flags. */- flag = buffer[4];- /* A version number must be "01". */- if (((flag & 0xc0) >> 6) != 1)- return (0);- /* A reserved bit must be "0". */- if (flag & 2)- return (0);- bits_checked += 8;- BD = buffer[5];- /* A block maximum size should be more than 3. */- if (((BD & 0x70) >> 4) < 4)- return (0);- /* Reserved bits must be "0". */- if (BD & ~0x70)- return (0);- bits_checked += 8;- } else if (number == LZ4_LEGACY) {- bits_checked += 32;- }- - return (bits_checked);-}--#if !defined(HAVE_LIBLZ4)--/*- * If we don't have the library on this system, we can't actually do the- * decompression. We can, however, still detect compressed archives- * and emit a useful message.- */-static int-lz4_reader_init(struct archive_read_filter *self)-{- int r;-- r = __archive_read_program(self, "lz4 -d -q");- /* Note: We set the format here even if __archive_read_program()- * above fails. We do, after all, know what the format is- * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_LZ4;- self->name = "lz4";- return (r);-}---#else--static const struct archive_read_filter_vtable-lz4_reader_vtable = {- .read = lz4_filter_read,- .close = lz4_filter_close,-};--/*- * Setup the callbacks.- */-static int-lz4_reader_init(struct archive_read_filter *self)-{- struct private_data *state;-- self->code = ARCHIVE_FILTER_LZ4;- self->name = "lz4";-- state = (struct private_data *)calloc(sizeof(*state), 1);- if (state == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for lz4 decompression");- return (ARCHIVE_FATAL);- }-- self->data = state;- state->stage = SELECT_STREAM;- self->vtable = &lz4_reader_vtable;-- return (ARCHIVE_OK);-}--static int-lz4_allocate_out_block(struct archive_read_filter *self)-{- struct private_data *state = (struct private_data *)self->data;- size_t out_block_size = state->flags.block_maximum_size;- void *out_block;-- if (!state->flags.block_independence)- out_block_size += 64 * 1024;- if (state->out_block_size < out_block_size) {- free(state->out_block);- out_block = (unsigned char *)malloc(out_block_size);- state->out_block_size = out_block_size;- if (out_block == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for lz4 decompression");- return (ARCHIVE_FATAL);- }- state->out_block = out_block;- }- if (!state->flags.block_independence)- memset(state->out_block, 0, 64 * 1024);- return (ARCHIVE_OK);-}--static int-lz4_allocate_out_block_for_legacy(struct archive_read_filter *self)-{- struct private_data *state = (struct private_data *)self->data;- size_t out_block_size = LEGACY_BLOCK_SIZE;- void *out_block;-- if (state->out_block_size < out_block_size) {- free(state->out_block);- out_block = (unsigned char *)malloc(out_block_size);- state->out_block_size = out_block_size;- if (out_block == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for lz4 decompression");- return (ARCHIVE_FATAL);- }- state->out_block = out_block;- }- return (ARCHIVE_OK);-}--/*- * Return the next block of decompressed data.- */-static ssize_t-lz4_filter_read(struct archive_read_filter *self, const void **p)-{- struct private_data *state = (struct private_data *)self->data;- ssize_t ret;-- if (state->eof) {- *p = NULL;- return (0);- }-- __archive_read_filter_consume(self->upstream, state->unconsumed);- state->unconsumed = 0;-- switch (state->stage) {- case SELECT_STREAM:- break;- case READ_DEFAULT_STREAM:- case READ_LEGACY_STREAM:- /* Reading a lz4 stream already failed. */- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC, "Invalid sequence.");- return (ARCHIVE_FATAL);- case READ_DEFAULT_BLOCK:- ret = lz4_filter_read_default_stream(self, p);- if (ret != 0 || state->stage != SELECT_STREAM)- return ret;- break;- case READ_LEGACY_BLOCK:- ret = lz4_filter_read_legacy_stream(self, p);- if (ret != 0 || state->stage != SELECT_STREAM)- return ret;- break;- default:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC, "Program error.");- return (ARCHIVE_FATAL);- break;- }-- while (state->stage == SELECT_STREAM) {- const char *read_buf;-- /* Read a magic number. */- read_buf = __archive_read_filter_ahead(self->upstream, 4,- NULL);- if (read_buf == NULL) {- state->eof = 1;- *p = NULL;- return (0);- }- uint32_t number = archive_le32dec(read_buf);- __archive_read_filter_consume(self->upstream, 4);- if (number == LZ4_MAGICNUMBER)- return lz4_filter_read_default_stream(self, p);- else if (number == LZ4_LEGACY)- return lz4_filter_read_legacy_stream(self, p);- else if ((number & ~0xF) == LZ4_SKIPPABLED) {- read_buf = __archive_read_filter_ahead(- self->upstream, 4, NULL);- if (read_buf == NULL) {- archive_set_error(- &self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Malformed lz4 data");- return (ARCHIVE_FATAL);- }- uint32_t skip_bytes = archive_le32dec(read_buf);- __archive_read_filter_consume(self->upstream,- 4 + skip_bytes);- } else {- /* Ignore following unrecognized data. */- state->eof = 1;- *p = NULL;- return (0);- }- }- state->eof = 1;- *p = NULL;- return (0);-}--static int-lz4_filter_read_descriptor(struct archive_read_filter *self)-{- struct private_data *state = (struct private_data *)self->data;- const char *read_buf;- ssize_t bytes_remaining;- ssize_t descriptor_bytes;- unsigned char flag, bd;- unsigned int chsum, chsum_verifier;-- /* Make sure we have 2 bytes for flags. */- read_buf = __archive_read_filter_ahead(self->upstream, 2,- &bytes_remaining);- if (read_buf == NULL) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "truncated lz4 input");- return (ARCHIVE_FATAL);- }-- /*- Parse flags.- */- flag = (unsigned char)read_buf[0];- /* Verify version number. */- if ((flag & 0xc0) != 1<<6)- goto malformed_error;- /* A reserved bit must be zero. */- if (flag & 0x02)- goto malformed_error;- state->flags.block_independence = (flag & 0x20) != 0;- state->flags.block_checksum = (flag & 0x10)?4:0;- state->flags.stream_size = (flag & 0x08) != 0;- state->flags.stream_checksum = (flag & 0x04) != 0;- state->flags.preset_dictionary = (flag & 0x01) != 0;-- /* BD */- bd = (unsigned char)read_buf[1];- /* Reserved bits must be zero. */- if (bd & 0x8f)- goto malformed_error;- /* Get a maximum block size. */- switch (read_buf[1] >> 4) {- case 4: /* 64 KB */- state->flags.block_maximum_size = 64 * 1024;- break;- case 5: /* 256 KB */- state->flags.block_maximum_size = 256 * 1024;- break;- case 6: /* 1 MB */- state->flags.block_maximum_size = 1024 * 1024;- break;- case 7: /* 4 MB */- state->flags.block_maximum_size = 4 * 1024 * 1024;- break;- default:- goto malformed_error;- }-- /* Read the whole descriptor in a stream block. */- descriptor_bytes = 3;- if (state->flags.stream_size)- descriptor_bytes += 8;- if (state->flags.preset_dictionary)- descriptor_bytes += 4;- if (bytes_remaining < descriptor_bytes) {- read_buf = __archive_read_filter_ahead(self->upstream,- descriptor_bytes, &bytes_remaining);- if (read_buf == NULL) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "truncated lz4 input");- return (ARCHIVE_FATAL);- }- }- /* Check if a descriptor is corrupted */- chsum = __archive_xxhash.XXH32(read_buf, (int)descriptor_bytes -1, 0);- chsum = (chsum >> 8) & 0xff;- chsum_verifier = read_buf[descriptor_bytes-1] & 0xff;- if (chsum != chsum_verifier)-#ifndef DONT_FAIL_ON_CRC_ERROR- goto malformed_error;-#endif-- __archive_read_filter_consume(self->upstream, descriptor_bytes);-- /* Make sure we have a large enough buffer for uncompressed data. */- if (lz4_allocate_out_block(self) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- if (state->flags.stream_checksum)- state->xxh32_state = __archive_xxhash.XXH32_init(0);-- state->decoded_size = 0;- /* Success */- return (ARCHIVE_OK);-malformed_error:- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "malformed lz4 data");- return (ARCHIVE_FATAL);-}--static ssize_t-lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)-{- struct private_data *state = (struct private_data *)self->data;- ssize_t compressed_size;- const char *read_buf;- ssize_t bytes_remaining;- int checksum_size;- ssize_t uncompressed_size;- size_t prefix64k;-- *p = NULL;-- /* Make sure we have 4 bytes for a block size. */- read_buf = __archive_read_filter_ahead(self->upstream, 4,- &bytes_remaining);- if (read_buf == NULL)- goto truncated_error;- compressed_size = archive_le32dec(read_buf);- if ((compressed_size & 0x7fffffff) > state->flags.block_maximum_size)- goto malformed_error;- /* A compressed size == 0 means the end of stream blocks. */- if (compressed_size == 0) {- __archive_read_filter_consume(self->upstream, 4);- return 0;- }-- checksum_size = state->flags.block_checksum;- /* Check if the block is uncompressed. */- if (compressed_size & 0x80000000U) {- compressed_size &= 0x7fffffff;- uncompressed_size = compressed_size;- } else- uncompressed_size = 0;/* Unknown yet. */-- /*- Unfortunately, lz4 decompression API requires a whole block- for its decompression speed, so we read a whole block and allocate- a huge buffer used for decoded data.- */- read_buf = __archive_read_filter_ahead(self->upstream,- 4 + compressed_size + checksum_size, &bytes_remaining);- if (read_buf == NULL)- goto truncated_error;-- /* Optional processing, checking a block sum. */- if (checksum_size) {- unsigned int chsum = __archive_xxhash.XXH32(- read_buf + 4, (int)compressed_size, 0);- unsigned int chsum_block =- archive_le32dec(read_buf + 4 + compressed_size);- if (chsum != chsum_block)-#ifndef DONT_FAIL_ON_CRC_ERROR- goto malformed_error;-#endif- }--- /* If the block is uncompressed, there is nothing to do. */- if (uncompressed_size) {- /* Prepare a prefix 64k block for next block. */- if (!state->flags.block_independence) {- prefix64k = 64 * 1024;- if (uncompressed_size < (ssize_t)prefix64k) {- memcpy(state->out_block- + prefix64k - uncompressed_size,- read_buf + 4,- uncompressed_size);- memset(state->out_block, 0,- prefix64k - uncompressed_size);- } else {- memcpy(state->out_block,- read_buf + 4- + uncompressed_size - prefix64k,- prefix64k);- }- state->decoded_size = 0;- }- state->unconsumed = 4 + uncompressed_size + checksum_size;- *p = read_buf + 4;- return uncompressed_size;- }-- /*- Decompress a block data.- */- if (state->flags.block_independence) {- prefix64k = 0;- uncompressed_size = LZ4_decompress_safe(read_buf + 4,- state->out_block, (int)compressed_size,- state->flags.block_maximum_size);- } else {- prefix64k = 64 * 1024;- if (state->decoded_size) {- if (state->decoded_size < prefix64k) {- memmove(state->out_block- + prefix64k - state->decoded_size,- state->out_block + prefix64k,- state->decoded_size);- memset(state->out_block, 0,- prefix64k - state->decoded_size);- } else {- memmove(state->out_block,- state->out_block + state->decoded_size,- prefix64k);- }- }-#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- uncompressed_size = LZ4_decompress_safe_usingDict(- read_buf + 4,- state->out_block + prefix64k, (int)compressed_size,- state->flags.block_maximum_size,- state->out_block,- (int)prefix64k);-#else- uncompressed_size = LZ4_decompress_safe_withPrefix64k(- read_buf + 4,- state->out_block + prefix64k, (int)compressed_size,- state->flags.block_maximum_size);-#endif- }-- /* Check if an error occurred in the decompression process. */- if (uncompressed_size < 0) {- archive_set_error(&(self->archive->archive),- ARCHIVE_ERRNO_MISC, "lz4 decompression failed");- return (ARCHIVE_FATAL);- }-- state->unconsumed = 4 + compressed_size + checksum_size;- *p = state->out_block + prefix64k;- state->decoded_size = uncompressed_size;- return uncompressed_size;--malformed_error:- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "malformed lz4 data");- return (ARCHIVE_FATAL);-truncated_error:- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "truncated lz4 input");- return (ARCHIVE_FATAL);-}--static ssize_t-lz4_filter_read_default_stream(struct archive_read_filter *self, const void **p)-{- struct private_data *state = (struct private_data *)self->data;- const char *read_buf;- ssize_t bytes_remaining;- ssize_t ret;-- if (state->stage == SELECT_STREAM) {- state->stage = READ_DEFAULT_STREAM;- /* First, read a descriptor. */- if((ret = lz4_filter_read_descriptor(self)) != ARCHIVE_OK)- return (ret);- state->stage = READ_DEFAULT_BLOCK;- }- /* Decompress a block. */- ret = lz4_filter_read_data_block(self, p);-- /* If the end of block is detected, change the filter status- to read next stream. */- if (ret == 0 && *p == NULL)- state->stage = SELECT_STREAM;-- /* Optional processing, checking a stream sum. */- if (state->flags.stream_checksum) {- if (state->stage == SELECT_STREAM) {- unsigned int checksum;- unsigned int checksum_stream;- read_buf = __archive_read_filter_ahead(self->upstream,- 4, &bytes_remaining);- if (read_buf == NULL) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC, "truncated lz4 input");- return (ARCHIVE_FATAL);- }- checksum = archive_le32dec(read_buf);- __archive_read_filter_consume(self->upstream, 4);- checksum_stream = __archive_xxhash.XXH32_digest(- state->xxh32_state);- state->xxh32_state = NULL;- if (checksum != checksum_stream) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "lz4 stream checksum error");- return (ARCHIVE_FATAL);-#endif- }- } else if (ret > 0)- __archive_xxhash.XXH32_update(state->xxh32_state,- *p, (int)ret);- }- return (ret);-}--static ssize_t-lz4_filter_read_legacy_stream(struct archive_read_filter *self, const void **p)-{- struct private_data *state = (struct private_data *)self->data;- uint32_t compressed;- const char *read_buf;- ssize_t ret;-- *p = NULL;- ret = lz4_allocate_out_block_for_legacy(self);- if (ret != ARCHIVE_OK)- return ret;-- /* Make sure we have 4 bytes for a block size. */- read_buf = __archive_read_filter_ahead(self->upstream, 4, NULL);- if (read_buf == NULL) {- if (state->stage == SELECT_STREAM) {- state->stage = READ_LEGACY_STREAM;- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "truncated lz4 input");- return (ARCHIVE_FATAL);- }- state->stage = SELECT_STREAM;- return 0;- }- state->stage = READ_LEGACY_BLOCK;- compressed = archive_le32dec(read_buf);- if (compressed > LZ4_COMPRESSBOUND(LEGACY_BLOCK_SIZE)) {- state->stage = SELECT_STREAM;- return 0;- }-- /* Make sure we have a whole block. */- read_buf = __archive_read_filter_ahead(self->upstream,- 4 + compressed, NULL);- if (read_buf == NULL) {- archive_set_error(&(self->archive->archive),- ARCHIVE_ERRNO_MISC, "truncated lz4 input");- return (ARCHIVE_FATAL);- }- ret = LZ4_decompress_safe(read_buf + 4, state->out_block,- compressed, (int)state->out_block_size);- if (ret < 0) {- archive_set_error(&(self->archive->archive),- ARCHIVE_ERRNO_MISC, "lz4 decompression failed");- return (ARCHIVE_FATAL);- }- *p = state->out_block;- state->unconsumed = 4 + compressed;- return ret;-}--/*- * Clean up the decompressor.- */-static int-lz4_filter_close(struct archive_read_filter *self)-{- struct private_data *state;- int ret = ARCHIVE_OK;-- state = (struct private_data *)self->data;- free(state->xxh32_state);- free(state->out_block);- free(state);- return (ret);-}--#endif /* HAVE_LIBLZ4 */
− c/archive_read_support_filter_lzop.c
@@ -1,499 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif-#ifdef HAVE_LZO_LZOCONF_H-#include <lzo/lzoconf.h>-#endif-#ifdef HAVE_LZO_LZO1X_H-#include <lzo/lzo1x.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h> /* for crc32 and adler32 */-#endif--#include "archive.h"-#if !defined(HAVE_ZLIB_H) &&\- defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)-#include "archive_crc32.h"-#endif-#include "archive_endian.h"-#include "archive_private.h"-#include "archive_read_private.h"--#ifndef HAVE_ZLIB_H-#define adler32 lzo_adler32-#endif--#define LZOP_HEADER_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a"-#define LZOP_HEADER_MAGIC_LEN 9--#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)-struct read_lzop {- unsigned char *out_block;- size_t out_block_size;- int64_t total_out;- int flags;- uint32_t compressed_cksum;- uint32_t uncompressed_cksum;- size_t compressed_size;- size_t uncompressed_size;- size_t unconsumed_bytes;- char in_stream;- char eof; /* True = found end of compressed data. */-};--#define FILTER 0x0800-#define CRC32_HEADER 0x1000-#define EXTRA_FIELD 0x0040-#define ADLER32_UNCOMPRESSED 0x0001-#define ADLER32_COMPRESSED 0x0002-#define CRC32_UNCOMPRESSED 0x0100-#define CRC32_COMPRESSED 0x0200-#define MAX_BLOCK_SIZE (64 * 1024 * 1024)--static ssize_t lzop_filter_read(struct archive_read_filter *, const void **);-static int lzop_filter_close(struct archive_read_filter *);-#endif--static int lzop_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *);-static int lzop_bidder_init(struct archive_read_filter *);--static const struct archive_read_filter_bidder_vtable-lzop_bidder_vtable = {- .bid = lzop_bidder_bid,- .init = lzop_bidder_init,-};--int-archive_read_support_filter_lzop(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- if (__archive_read_register_bidder(a, NULL, NULL,- &lzop_bidder_vtable) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Signal the extent of lzop support with the return value here. */-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)- return (ARCHIVE_OK);-#else- /* Return ARCHIVE_WARN since this always uses an external program. */- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external lzop program for lzop decompression");- return (ARCHIVE_WARN);-#endif-}--/*- * Bidder just verifies the header and returns the number of verified bits.- */-static int-lzop_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- const unsigned char *p;- ssize_t avail;-- (void)self; /* UNUSED */-- p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, &avail);- if (p == NULL || avail == 0)- return (0);-- if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))- return (0);-- return (LZOP_HEADER_MAGIC_LEN * 8);-}--#if !defined(HAVE_LZO_LZOCONF_H) || !defined(HAVE_LZO_LZO1X_H)-/*- * If we don't have the library on this system, we can't do the- * decompression directly. We can, however, try to run "lzop -d"- * in case that's available.- */-static int-lzop_bidder_init(struct archive_read_filter *self)-{- int r;-- r = __archive_read_program(self, "lzop -d");- /* Note: We set the format here even if __archive_read_program()- * above fails. We do, after all, know what the format is- * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_LZOP;- self->name = "lzop";- return (r);-}-#else--static const struct archive_read_filter_vtable-lzop_reader_vtable = {- .read = lzop_filter_read,- .close = lzop_filter_close-};--/*- * Initialize the filter object.- */-static int-lzop_bidder_init(struct archive_read_filter *self)-{- struct read_lzop *state;-- self->code = ARCHIVE_FILTER_LZOP;- self->name = "lzop";-- state = (struct read_lzop *)calloc(sizeof(*state), 1);- if (state == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for lzop decompression");- return (ARCHIVE_FATAL);- }-- self->data = state;- self->vtable = &lzop_reader_vtable;-- return (ARCHIVE_OK);-}--static int-consume_header(struct archive_read_filter *self)-{- struct read_lzop *state = (struct read_lzop *)self->data;- const unsigned char *p, *_p;- unsigned checksum, flags, len, method, version;-- /*- * Check LZOP magic code.- */- p = __archive_read_filter_ahead(self->upstream,- LZOP_HEADER_MAGIC_LEN, NULL);- if (p == NULL)- return (ARCHIVE_EOF);-- if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))- return (ARCHIVE_EOF);- __archive_read_filter_consume(self->upstream,- LZOP_HEADER_MAGIC_LEN);-- p = __archive_read_filter_ahead(self->upstream, 29, NULL);- if (p == NULL)- goto truncated;- _p = p;- version = archive_be16dec(p);- p += 4;/* version(2 bytes) + library version(2 bytes) */-- if (version >= 0x940) {- unsigned reqversion = archive_be16dec(p); p += 2;- if (reqversion < 0x900) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC, "Invalid required version");- return (ARCHIVE_FAILED);- }- }-- method = *p++;- if (method < 1 || method > 3) {- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "Unsupported method");- return (ARCHIVE_FAILED);- }-- if (version >= 0x940) {- unsigned level = *p++;-#if 0- unsigned default_level[] = {0, 3, 1, 9};-#endif- if (level == 0)- /* Method is 1..3 here due to check above. */-#if 0 /* Avoid an error Clang Static Analyzer claims- "Value stored to 'level' is never read". */- level = default_level[method];-#else- ;/* NOP */-#endif- else if (level > 9) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC, "Invalid level");- return (ARCHIVE_FAILED);- }- }-- flags = archive_be32dec(p); p += 4;-- if (flags & FILTER)- p += 4; /* Skip filter */- p += 4; /* Skip mode */- if (version >= 0x940)- p += 8; /* Skip mtime */- else- p += 4; /* Skip mtime */- len = *p++; /* Read filename length */- len += p - _p;- /* Make sure we have all bytes we need to calculate checksum. */- p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);- if (p == NULL)- goto truncated;- if (flags & CRC32_HEADER)- checksum = crc32(crc32(0, NULL, 0), p, len);- else- checksum = adler32(adler32(0, NULL, 0), p, len);- if (archive_be32dec(p + len) != checksum)-#ifndef DONT_FAIL_ON_CRC_ERROR- goto corrupted;-#endif- __archive_read_filter_consume(self->upstream, len + 4);- if (flags & EXTRA_FIELD) {- /* Skip extra field */- p = __archive_read_filter_ahead(self->upstream, 4, NULL);- if (p == NULL)- goto truncated;- len = archive_be32dec(p);- __archive_read_filter_consume(self->upstream, len + 4 + 4);- }- state->flags = flags;- state->in_stream = 1;- return (ARCHIVE_OK);-truncated:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");- return (ARCHIVE_FAILED);-corrupted:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");- return (ARCHIVE_FAILED);-}--static int-consume_block_info(struct archive_read_filter *self)-{- struct read_lzop *state = (struct read_lzop *)self->data;- const unsigned char *p;- unsigned flags = state->flags;-- p = __archive_read_filter_ahead(self->upstream, 4, NULL);- if (p == NULL)- goto truncated;- state->uncompressed_size = archive_be32dec(p);- __archive_read_filter_consume(self->upstream, 4);- if (state->uncompressed_size == 0)- return (ARCHIVE_EOF);- if (state->uncompressed_size > MAX_BLOCK_SIZE)- goto corrupted;-- p = __archive_read_filter_ahead(self->upstream, 4, NULL);- if (p == NULL)- goto truncated;- state->compressed_size = archive_be32dec(p);- __archive_read_filter_consume(self->upstream, 4);- if (state->compressed_size > state->uncompressed_size)- goto corrupted;-- if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {- p = __archive_read_filter_ahead(self->upstream, 4, NULL);- if (p == NULL)- goto truncated;- state->compressed_cksum = state->uncompressed_cksum =- archive_be32dec(p);- __archive_read_filter_consume(self->upstream, 4);- }- if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&- state->compressed_size < state->uncompressed_size) {- p = __archive_read_filter_ahead(self->upstream, 4, NULL);- if (p == NULL)- goto truncated;- state->compressed_cksum = archive_be32dec(p);- __archive_read_filter_consume(self->upstream, 4);- }- return (ARCHIVE_OK);-truncated:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");- return (ARCHIVE_FAILED);-corrupted:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");- return (ARCHIVE_FAILED);-}--static ssize_t-lzop_filter_read(struct archive_read_filter *self, const void **p)-{- struct read_lzop *state = (struct read_lzop *)self->data;- const void *b;- lzo_uint out_size;- uint32_t cksum;- int ret, r;-- if (state->unconsumed_bytes) {- __archive_read_filter_consume(self->upstream,- state->unconsumed_bytes);- state->unconsumed_bytes = 0;- }- if (state->eof)- return (0);-- for (;;) {- if (!state->in_stream) {- ret = consume_header(self);- if (ret < ARCHIVE_OK)- return (ret);- if (ret == ARCHIVE_EOF) {- state->eof = 1;- return (0);- }- }- ret = consume_block_info(self);- if (ret < ARCHIVE_OK)- return (ret);- if (ret == ARCHIVE_EOF)- state->in_stream = 0;- else- break;- }-- if (state->out_block == NULL ||- state->out_block_size < state->uncompressed_size) {- void *new_block;-- new_block = realloc(state->out_block, state->uncompressed_size);- if (new_block == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for lzop decompression");- return (ARCHIVE_FATAL);- }- state->out_block = new_block;- state->out_block_size = state->uncompressed_size;- }-- b = __archive_read_filter_ahead(self->upstream,- state->compressed_size, NULL);- if (b == NULL) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");- return (ARCHIVE_FATAL);- }- if (state->flags & CRC32_COMPRESSED)- cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);- else if (state->flags & ADLER32_COMPRESSED)- cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);- else- cksum = state->compressed_cksum;- if (cksum != state->compressed_cksum) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC, "Corrupted data");- return (ARCHIVE_FATAL);- }-- /*- * If the both uncompressed size and compressed size are the same,- * we do not decompress this block.- */- if (state->uncompressed_size == state->compressed_size) {- *p = b;- state->total_out += state->compressed_size;- state->unconsumed_bytes = state->compressed_size;- return ((ssize_t)state->uncompressed_size);- }-- /*- * Drive lzo uncompression.- */- out_size = (lzo_uint)state->uncompressed_size;- r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,- state->out_block, &out_size, NULL);- switch (r) {- case LZO_E_OK:- if (out_size == state->uncompressed_size)- break;- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC, "Corrupted data");- return (ARCHIVE_FATAL);- case LZO_E_OUT_OF_MEMORY:- archive_set_error(&self->archive->archive, ENOMEM,- "lzop decompression failed: out of memory");- return (ARCHIVE_FATAL);- default:- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "lzop decompression failed: %d", r);- return (ARCHIVE_FATAL);- }-- if (state->flags & CRC32_UNCOMPRESSED)- cksum = crc32(crc32(0, NULL, 0), state->out_block,- state->uncompressed_size);- else if (state->flags & ADLER32_UNCOMPRESSED)- cksum = adler32(adler32(0, NULL, 0), state->out_block,- state->uncompressed_size);- else- cksum = state->uncompressed_cksum;- if (cksum != state->uncompressed_cksum) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC, "Corrupted data");- return (ARCHIVE_FATAL);- }-- __archive_read_filter_consume(self->upstream, state->compressed_size);- *p = state->out_block;- state->total_out += out_size;- return ((ssize_t)out_size);-}--/*- * Clean up the decompressor.- */-static int-lzop_filter_close(struct archive_read_filter *self)-{- struct read_lzop *state = (struct read_lzop *)self->data;-- free(state->out_block);- free(state);- return (ARCHIVE_OK);-}--#endif
− c/archive_read_support_filter_none.c
@@ -1,52 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#include "archive.h"-#include "archive_private.h"--#if ARCHIVE_VERSION_NUMBER < 4000000-/* Deprecated; remove in libarchive 4.0 */-int-archive_read_support_compression_none(struct archive *a)-{- return archive_read_support_filter_none(a);-}-#endif--/*- * Uncompressed streams are handled implicitly by the read core,- * so this is now a no-op.- */-int-archive_read_support_filter_none(struct archive *a)-{- archive_check_magic(a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_filter_none");-- return (ARCHIVE_OK);-}
− c/archive_read_support_filter_program.c
@@ -1,496 +0,0 @@-/*-- * Copyright (c) 2007 Joerg Sonnenberger- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#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_LIMITS_H-# include <limits.h>-#endif-#ifdef HAVE_SIGNAL_H-# include <signal.h>-#endif-#ifdef HAVE_STDLIB_H-# include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-# include <string.h>-#endif-#ifdef HAVE_UNISTD_H-# include <unistd.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_string.h"-#include "archive_read_private.h"-#include "filter_fork.h"---#if ARCHIVE_VERSION_NUMBER < 4000000-/* Deprecated; remove in libarchive 4.0 */-int-archive_read_support_compression_program(struct archive *a, const char *cmd)-{- return archive_read_support_filter_program(a, cmd);-}--int-archive_read_support_compression_program_signature(struct archive *a,- const char *cmd, const void *signature, size_t signature_len)-{- return archive_read_support_filter_program_signature(a,- cmd, signature, signature_len);-}-#endif--int-archive_read_support_filter_program(struct archive *a, const char *cmd)-{- return (archive_read_support_filter_program_signature(a, cmd, NULL, 0));-}--/*- * The bidder object stores the command and the signature to watch for.- * The 'inhibit' entry here is used to ensure that unchecked filters never- * bid twice in the same pipeline.- */-struct program_bidder {- char *description;- char *cmd;- void *signature;- size_t signature_len;- int inhibit;-};--static int program_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *upstream);-static int program_bidder_init(struct archive_read_filter *);-static void program_bidder_free(struct archive_read_filter_bidder *);--/*- * The actual filter needs to track input and output data.- */-struct program_filter {- struct archive_string description;-#if defined(_WIN32) && !defined(__CYGWIN__)- HANDLE child;-#else- pid_t child;-#endif- int exit_status;- int waitpid_return;- int child_stdin, child_stdout;-- char *out_buf;- size_t out_buf_len;-};--static ssize_t program_filter_read(struct archive_read_filter *,- const void **);-static int program_filter_close(struct archive_read_filter *);-static void free_state(struct program_bidder *);--static const struct archive_read_filter_bidder_vtable-program_bidder_vtable = {- .bid = program_bidder_bid,- .init = program_bidder_init,- .free = program_bidder_free,-};--int-archive_read_support_filter_program_signature(struct archive *_a,- const char *cmd, const void *signature, size_t signature_len)-{- struct archive_read *a = (struct archive_read *)_a;- struct program_bidder *state;-- /*- * Allocate our private state.- */- state = (struct program_bidder *)calloc(1, sizeof (*state));- if (state == NULL)- goto memerr;- state->cmd = strdup(cmd);- if (state->cmd == NULL)- goto memerr;-- if (signature != NULL && signature_len > 0) {- state->signature_len = signature_len;- state->signature = malloc(signature_len);- memcpy(state->signature, signature, signature_len);- }-- if (__archive_read_register_bidder(a, state, NULL,- &program_bidder_vtable) != ARCHIVE_OK) {- free_state(state);- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);--memerr:- free_state(state);- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);-}--static void-program_bidder_free(struct archive_read_filter_bidder *self)-{- struct program_bidder *state = (struct program_bidder *)self->data;-- free_state(state);-}--static void-free_state(struct program_bidder *state)-{-- if (state) {- free(state->cmd);- free(state->signature);- free(state);- }-}--/*- * If we do have a signature, bid only if that matches.- *- * If there's no signature, we bid INT_MAX the first time- * we're called, then never bid again.- */-static int-program_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *upstream)-{- struct program_bidder *state = self->data;- const char *p;-- /* If we have a signature, use that to match. */- if (state->signature_len > 0) {- p = __archive_read_filter_ahead(upstream,- state->signature_len, NULL);- if (p == NULL)- return (0);- /* No match, so don't bid. */- if (memcmp(p, state->signature, state->signature_len) != 0)- return (0);- return ((int)state->signature_len * 8);- }-- /* Otherwise, bid once and then never bid again. */- if (state->inhibit)- return (0);- state->inhibit = 1;- return (INT_MAX);-}--/*- * Shut down the child, return ARCHIVE_OK if it exited normally.- *- * Note that the return value is sticky; if we're called again,- * we won't reap the child again, but we will return the same status- * (including error message if the child came to a bad end).- */-static int-child_stop(struct archive_read_filter *self, struct program_filter *state)-{- /* Close our side of the I/O with the child. */- if (state->child_stdin != -1) {- close(state->child_stdin);- state->child_stdin = -1;- }- if (state->child_stdout != -1) {- close(state->child_stdout);- state->child_stdout = -1;- }-- if (state->child != 0) {- /* Reap the child. */- do {- state->waitpid_return- = waitpid(state->child, &state->exit_status, 0);- } while (state->waitpid_return == -1 && errno == EINTR);-#if defined(_WIN32) && !defined(__CYGWIN__)- CloseHandle(state->child);-#endif- state->child = 0;- }-- if (state->waitpid_return < 0) {- /* waitpid() failed? This is ugly. */- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "Child process exited badly");- return (ARCHIVE_WARN);- }--#if !defined(_WIN32) || defined(__CYGWIN__)- if (WIFSIGNALED(state->exit_status)) {-#ifdef SIGPIPE- /* If the child died because we stopped reading before- * it was done, that's okay. Some archive formats- * have padding at the end that we routinely ignore. */- /* The alternative to this would be to add a step- * before close(child_stdout) above to read from the- * child until the child has no more to write. */- if (WTERMSIG(state->exit_status) == SIGPIPE)- return (ARCHIVE_OK);-#endif- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "Child process exited with signal %d",- WTERMSIG(state->exit_status));- return (ARCHIVE_WARN);- }-#endif /* !_WIN32 || __CYGWIN__ */-- if (WIFEXITED(state->exit_status)) {- if (WEXITSTATUS(state->exit_status) == 0)- return (ARCHIVE_OK);-- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Child process exited with status %d",- WEXITSTATUS(state->exit_status));- return (ARCHIVE_WARN);- }-- return (ARCHIVE_WARN);-}--/*- * Use select() to decide whether the child is ready for read or write.- */-static ssize_t-child_read(struct archive_read_filter *self, char *buf, size_t buf_len)-{- struct program_filter *state = self->data;- ssize_t ret, requested, avail;- const char *p;-#if defined(_WIN32) && !defined(__CYGWIN__)- HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout);-#endif-- requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;-- for (;;) {- do {-#if defined(_WIN32) && !defined(__CYGWIN__)- /* Avoid infinity wait.- * Note: If there is no data in the pipe, ReadFile()- * called in read() never returns and so we won't- * write remaining encoded data to the pipe.- * Note: This way may cause performance problem.- * we are looking forward to great code to resolve- * this. */- DWORD pipe_avail = -1;- int cnt = 2;-- while (PeekNamedPipe(handle, NULL, 0, NULL,- &pipe_avail, NULL) != 0 && pipe_avail == 0 &&- cnt--)- Sleep(5);- if (pipe_avail == 0) {- ret = -1;- errno = EAGAIN;- break;- }-#endif- ret = read(state->child_stdout, buf, requested);- } while (ret == -1 && errno == EINTR);-- if (ret > 0)- return (ret);- if (ret == 0 || (ret == -1 && errno == EPIPE))- /* Child has closed its output; reap the child- * and return the status. */- return (child_stop(self, state));- if (ret == -1 && errno != EAGAIN)- return (-1);-- if (state->child_stdin == -1) {- /* Block until child has some I/O ready. */- __archive_check_child(state->child_stdin,- state->child_stdout);- continue;- }-- /* Get some more data from upstream. */- p = __archive_read_filter_ahead(self->upstream, 1, &avail);- if (p == NULL) {- close(state->child_stdin);- state->child_stdin = -1;- fcntl(state->child_stdout, F_SETFL, 0);- if (avail < 0)- return (avail);- continue;- }-- do {- ret = write(state->child_stdin, p, avail);- } while (ret == -1 && errno == EINTR);-- if (ret > 0) {- /* Consume whatever we managed to write. */- __archive_read_filter_consume(self->upstream, ret);- } else if (ret == -1 && errno == EAGAIN) {- /* Block until child has some I/O ready. */- __archive_check_child(state->child_stdin,- state->child_stdout);- } else {- /* Write failed. */- close(state->child_stdin);- state->child_stdin = -1;- fcntl(state->child_stdout, F_SETFL, 0);- /* If it was a bad error, we're done; otherwise- * it was EPIPE or EOF, and we can still read- * from the child. */- if (ret == -1 && errno != EPIPE)- return (-1);- }- }-}--static const struct archive_read_filter_vtable-program_reader_vtable = {- .read = program_filter_read,- .close = program_filter_close,-};--int-__archive_read_program(struct archive_read_filter *self, const char *cmd)-{- struct program_filter *state;- static const size_t out_buf_len = 65536;- char *out_buf;- const char *prefix = "Program: ";- int ret;- size_t l;-- l = strlen(prefix) + strlen(cmd) + 1;- state = (struct program_filter *)calloc(1, sizeof(*state));- out_buf = (char *)malloc(out_buf_len);- if (state == NULL || out_buf == NULL ||- archive_string_ensure(&state->description, l) == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate input data");- if (state != NULL) {- archive_string_free(&state->description);- free(state);- }- free(out_buf);- return (ARCHIVE_FATAL);- }- archive_strcpy(&state->description, prefix);- archive_strcat(&state->description, cmd);-- self->code = ARCHIVE_FILTER_PROGRAM;- self->name = state->description.s;-- state->out_buf = out_buf;- state->out_buf_len = out_buf_len;-- ret = __archive_create_child(cmd, &state->child_stdin,- &state->child_stdout, &state->child);- if (ret != ARCHIVE_OK) {- free(state->out_buf);- archive_string_free(&state->description);- free(state);- archive_set_error(&self->archive->archive, EINVAL,- "Can't initialize filter; unable to run program \"%s\"",- cmd);- return (ARCHIVE_FATAL);- }-- self->data = state;- self->vtable = &program_reader_vtable;-- /* XXX Check that we can read at least one byte? */- return (ARCHIVE_OK);-}--static int-program_bidder_init(struct archive_read_filter *self)-{- struct program_bidder *bidder_state;-- bidder_state = (struct program_bidder *)self->bidder->data;- return (__archive_read_program(self, bidder_state->cmd));-}--static ssize_t-program_filter_read(struct archive_read_filter *self, const void **buff)-{- struct program_filter *state;- ssize_t bytes;- size_t total;- char *p;-- state = (struct program_filter *)self->data;-- total = 0;- p = state->out_buf;- while (state->child_stdout != -1 && total < state->out_buf_len) {- bytes = child_read(self, p, state->out_buf_len - total);- if (bytes < 0)- /* No recovery is possible if we can no longer- * read from the child. */- return (ARCHIVE_FATAL);- if (bytes == 0)- /* We got EOF from the child. */- break;- total += bytes;- p += bytes;- }-- *buff = state->out_buf;- return (total);-}--static int-program_filter_close(struct archive_read_filter *self)-{- struct program_filter *state;- int e;-- state = (struct program_filter *)self->data;- e = child_stop(self, state);-- /* Release our private data. */- free(state->out_buf);- archive_string_free(&state->description);- free(state);-- return (e);-}
− c/archive_read_support_filter_rpm.c
@@ -1,287 +0,0 @@-/*-- * Copyright (c) 2009 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif--#include "archive.h"-#include "archive_endian.h"-#include "archive_private.h"-#include "archive_read_private.h"--struct rpm {- int64_t total_in;- size_t hpos;- size_t hlen;- unsigned char header[16];- enum {- ST_LEAD, /* Skipping 'Lead' section. */- ST_HEADER, /* Reading 'Header' section;- * first 16 bytes. */- ST_HEADER_DATA, /* Skipping 'Header' section. */- ST_PADDING, /* Skipping padding data after the- * 'Header' section. */- ST_ARCHIVE /* Reading 'Archive' section. */- } state;- int first_header;-};-#define RPM_LEAD_SIZE 96 /* Size of 'Lead' section. */--static int rpm_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *);-static int rpm_bidder_init(struct archive_read_filter *);--static ssize_t rpm_filter_read(struct archive_read_filter *,- const void **);-static int rpm_filter_close(struct archive_read_filter *);--#if ARCHIVE_VERSION_NUMBER < 4000000-/* Deprecated; remove in libarchive 4.0 */-int-archive_read_support_compression_rpm(struct archive *a)-{- return archive_read_support_filter_rpm(a);-}-#endif--static const struct archive_read_filter_bidder_vtable-rpm_bidder_vtable = {- .bid = rpm_bidder_bid,- .init = rpm_bidder_init,-};--int-archive_read_support_filter_rpm(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- return __archive_read_register_bidder(a, NULL, "rpm",- &rpm_bidder_vtable);-}--static int-rpm_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- const unsigned char *b;- ssize_t avail;- int bits_checked;-- (void)self; /* UNUSED */-- b = __archive_read_filter_ahead(filter, 8, &avail);- if (b == NULL)- return (0);-- bits_checked = 0;- /*- * Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB- */- if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)- return (0);- bits_checked += 32;- /*- * Check major version.- */- if (b[4] != 3 && b[4] != 4)- return (0);- bits_checked += 8;- /*- * Check package type; binary or source.- */- if (b[6] != 0)- return (0);- bits_checked += 8;- if (b[7] != 0 && b[7] != 1)- return (0);- bits_checked += 8;-- return (bits_checked);-}--static const struct archive_read_filter_vtable-rpm_reader_vtable = {- .read = rpm_filter_read,- .close = rpm_filter_close,-};--static int-rpm_bidder_init(struct archive_read_filter *self)-{- struct rpm *rpm;-- self->code = ARCHIVE_FILTER_RPM;- self->name = "rpm";-- rpm = (struct rpm *)calloc(sizeof(*rpm), 1);- if (rpm == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for rpm");- return (ARCHIVE_FATAL);- }-- self->data = rpm;- rpm->state = ST_LEAD;- self->vtable = &rpm_reader_vtable;-- return (ARCHIVE_OK);-}--static ssize_t-rpm_filter_read(struct archive_read_filter *self, const void **buff)-{- struct rpm *rpm;- const unsigned char *b;- ssize_t avail_in, total;- size_t used, n;- uint32_t section;- uint32_t bytes;-- rpm = (struct rpm *)self->data;- *buff = NULL;- total = avail_in = 0;- b = NULL;- used = 0;- do {- if (b == NULL) {- b = __archive_read_filter_ahead(self->upstream, 1,- &avail_in);- if (b == NULL) {- if (avail_in < 0)- return (ARCHIVE_FATAL);- else- break;- }- }-- switch (rpm->state) {- case ST_LEAD:- if (rpm->total_in + avail_in < RPM_LEAD_SIZE)- used += avail_in;- else {- n = (size_t)(RPM_LEAD_SIZE - rpm->total_in);- used += n;- b += n;- rpm->state = ST_HEADER;- rpm->hpos = 0;- rpm->hlen = 0;- rpm->first_header = 1;- }- break;- case ST_HEADER:- n = 16 - rpm->hpos;- if (n > avail_in - used)- n = avail_in - used;- memcpy(rpm->header+rpm->hpos, b, n);- b += n;- used += n;- rpm->hpos += n;-- if (rpm->hpos == 16) {- if (rpm->header[0] != 0x8e ||- rpm->header[1] != 0xad ||- rpm->header[2] != 0xe8 ||- rpm->header[3] != 0x01) {- if (rpm->first_header) {- archive_set_error(- &self->archive->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unrecognized rpm header");- return (ARCHIVE_FATAL);- }- rpm->state = ST_ARCHIVE;- *buff = rpm->header;- total = rpm->hpos;- break;- }- /* Calculate 'Header' length. */- section = archive_be32dec(rpm->header+8);- bytes = archive_be32dec(rpm->header+12);- rpm->hlen = 16 + section * 16 + bytes;- rpm->state = ST_HEADER_DATA;- rpm->first_header = 0;- }- break;- case ST_HEADER_DATA:- n = rpm->hlen - rpm->hpos;- if (n > avail_in - used)- n = avail_in - used;- b += n;- used += n;- rpm->hpos += n;- if (rpm->hpos == rpm->hlen)- rpm->state = ST_PADDING;- break;- case ST_PADDING:- while (used < (size_t)avail_in) {- if (*b != 0) {- /* Read next header. */- rpm->state = ST_HEADER;- rpm->hpos = 0;- rpm->hlen = 0;- break;- }- b++;- used++;- }- break;- case ST_ARCHIVE:- *buff = b;- total = avail_in;- used = avail_in;- break;- }- if (used == (size_t)avail_in) {- rpm->total_in += used;- __archive_read_filter_consume(self->upstream, used);- b = NULL;- used = 0;- }- } while (total == 0 && avail_in > 0);-- if (used > 0 && b != NULL) {- rpm->total_in += used;- __archive_read_filter_consume(self->upstream, used);- }- return (total);-}--static int-rpm_filter_close(struct archive_read_filter *self)-{- struct rpm *rpm;-- rpm = (struct rpm *)self->data;- free(rpm);-- return (ARCHIVE_OK);-}-
− c/archive_read_support_filter_uu.c
@@ -1,683 +0,0 @@-/*-- * Copyright (c) 2009-2011 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_read_private.h"--/* Maximum lookahead during bid phase */-#define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */--struct uudecode {- int64_t total;- unsigned char *in_buff;-#define IN_BUFF_SIZE (1024)- int in_cnt;- size_t in_allocated;- unsigned char *out_buff;-#define OUT_BUFF_SIZE (64 * 1024)- int state;-#define ST_FIND_HEAD 0-#define ST_READ_UU 1-#define ST_UUEND 2-#define ST_READ_BASE64 3-#define ST_IGNORE 4-};--static int uudecode_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *filter);-static int uudecode_bidder_init(struct archive_read_filter *);--static ssize_t uudecode_filter_read(struct archive_read_filter *,- const void **);-static int uudecode_filter_close(struct archive_read_filter *);--#if ARCHIVE_VERSION_NUMBER < 4000000-/* Deprecated; remove in libarchive 4.0 */-int-archive_read_support_compression_uu(struct archive *a)-{- return archive_read_support_filter_uu(a);-}-#endif--static const struct archive_read_filter_bidder_vtable-uudecode_bidder_vtable = {- .bid = uudecode_bidder_bid,- .init = uudecode_bidder_init,-};--int-archive_read_support_filter_uu(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- return __archive_read_register_bidder(a, NULL, "uu",- &uudecode_bidder_vtable);-}--static const unsigned char ascii[256] = {- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, 0, '\r', 0, 0, /* 00 - 0F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */-};--static const unsigned char uuchar[256] = {- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */-};--static const unsigned char base64[256] = {- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, /* 20 - 2F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 30 - 3F */- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 50 - 5F */- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 - 7F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */-};--static const int base64num[128] = {- 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */- 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */- 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 62, 0, 0, 0, 63, /* 20 - 2F */- 52, 53, 54, 55, 56, 57, 58, 59,- 60, 61, 0, 0, 0, 0, 0, 0, /* 30 - 3F */- 0, 0, 1, 2, 3, 4, 5, 6,- 7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */- 15, 16, 17, 18, 19, 20, 21, 22,- 23, 24, 25, 0, 0, 0, 0, 0, /* 50 - 5F */- 0, 26, 27, 28, 29, 30, 31, 32,- 33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */- 41, 42, 43, 44, 45, 46, 47, 48,- 49, 50, 51, 0, 0, 0, 0, 0, /* 70 - 7F */-};--static ssize_t-get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)-{- ssize_t len;-- len = 0;- while (len < avail) {- switch (ascii[*b]) {- case 0: /* Non-ascii character or control character. */- if (nlsize != NULL)- *nlsize = 0;- return (-1);- case '\r':- if (avail-len > 1 && b[1] == '\n') {- if (nlsize != NULL)- *nlsize = 2;- return (len+2);- }- /* FALL THROUGH */- case '\n':- if (nlsize != NULL)- *nlsize = 1;- return (len+1);- case 1:- b++;- len++;- break;- }- }- if (nlsize != NULL)- *nlsize = 0;- return (avail);-}--static ssize_t-bid_get_line(struct archive_read_filter *filter,- const unsigned char **b, ssize_t *avail, ssize_t *ravail,- ssize_t *nl, size_t* nbytes_read)-{- ssize_t len;- int quit;- - quit = 0;- if (*avail == 0) {- *nl = 0;- len = 0;- } else- len = get_line(*b, *avail, nl);-- /*- * Read bytes more while it does not reach the end of line.- */- while (*nl == 0 && len == *avail && !quit &&- *nbytes_read < UUENCODE_BID_MAX_READ) {- ssize_t diff = *ravail - *avail;- size_t nbytes_req = (*ravail+1023) & ~1023U;- ssize_t tested;-- /* Increase reading bytes if it is not enough to at least- * new two lines. */- if (nbytes_req < (size_t)*ravail + 160)- nbytes_req <<= 1;-- *b = __archive_read_filter_ahead(filter, nbytes_req, avail);- if (*b == NULL) {- if (*ravail >= *avail)- return (0);- /* Reading bytes reaches the end of a stream. */- *b = __archive_read_filter_ahead(filter, *avail, avail);- quit = 1;- }- *nbytes_read = *avail;- *ravail = *avail;- *b += diff;- *avail -= diff;- tested = len;/* Skip some bytes we already determined. */- len = get_line(*b + tested, *avail - tested, nl);- if (len >= 0)- len += tested;- }- return (len);-}--#define UUDECODE(c) (((c) - 0x20) & 0x3f)--static int-uudecode_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- const unsigned char *b;- ssize_t avail, ravail;- ssize_t len, nl;- int l;- int firstline;- size_t nbytes_read;-- (void)self; /* UNUSED */-- b = __archive_read_filter_ahead(filter, 1, &avail);- if (b == NULL)- return (0);-- firstline = 20;- ravail = avail;- nbytes_read = avail;- for (;;) {- len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);- if (len < 0 || nl == 0)- return (0); /* No match found. */- if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)- l = 6;- else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0)- l = 13;- else- l = 0;-- if (l > 0 && (b[l] < '0' || b[l] > '7' ||- b[l+1] < '0' || b[l+1] > '7' ||- b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))- l = 0;-- b += len;- avail -= len;- if (l)- break;- firstline = 0;-- /* Do not read more than UUENCODE_BID_MAX_READ bytes */- if (nbytes_read >= UUENCODE_BID_MAX_READ)- return (0);- }- if (!avail)- return (0);- len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);- if (len < 0 || nl == 0)- return (0);/* There are non-ascii characters. */- avail -= len;-- if (l == 6) {- /* "begin " */- if (!uuchar[*b])- return (0);- /* Get a length of decoded bytes. */- l = UUDECODE(*b++); len--;- if (l > 45)- /* Normally, maximum length is 45(character 'M'). */- return (0);- if (l > len - nl)- return (0); /* Line too short. */- while (l) {- if (!uuchar[*b++])- return (0);- --len;- --l;- }- if (len-nl == 1 &&- (uuchar[*b] || /* Check sum. */- (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */- ++b;- --len;- }- b += nl;- if (avail && uuchar[*b])- return (firstline+30);- } else if (l == 13) {- /* "begin-base64 " */- while (len-nl > 0) {- if (!base64[*b++])- return (0);- --len;- }- b += nl;-- if (avail >= 5 && memcmp(b, "====\n", 5) == 0)- return (firstline+40);- if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)- return (firstline+40);- if (avail > 0 && base64[*b])- return (firstline+30);- }-- return (0);-}--static const struct archive_read_filter_vtable-uudecode_reader_vtable = {- .read = uudecode_filter_read,- .close = uudecode_filter_close,-};--static int-uudecode_bidder_init(struct archive_read_filter *self)-{- struct uudecode *uudecode;- void *out_buff;- void *in_buff;-- self->code = ARCHIVE_FILTER_UU;- self->name = "uu";-- uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1);- out_buff = malloc(OUT_BUFF_SIZE);- in_buff = malloc(IN_BUFF_SIZE);- if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for uudecode");- free(uudecode);- free(out_buff);- free(in_buff);- return (ARCHIVE_FATAL);- }-- self->data = uudecode;- uudecode->in_buff = in_buff;- uudecode->in_cnt = 0;- uudecode->in_allocated = IN_BUFF_SIZE;- uudecode->out_buff = out_buff;- uudecode->state = ST_FIND_HEAD;- self->vtable = &uudecode_reader_vtable;-- return (ARCHIVE_OK);-}--static int-ensure_in_buff_size(struct archive_read_filter *self,- struct uudecode *uudecode, size_t size)-{-- if (size > uudecode->in_allocated) {- unsigned char *ptr;- size_t newsize;-- /*- * Calculate a new buffer size for in_buff.- * Increase its value until it has enough size we need.- */- newsize = uudecode->in_allocated;- do {- if (newsize < IN_BUFF_SIZE*32)- newsize <<= 1;- else- newsize += IN_BUFF_SIZE;- } while (size > newsize);- /* Allocate the new buffer. */- ptr = malloc(newsize);- if (ptr == NULL) {- free(ptr);- archive_set_error(&self->archive->archive,- ENOMEM,- "Can't allocate data for uudecode");- return (ARCHIVE_FATAL);- }- /* Move the remaining data in in_buff into the new buffer. */- if (uudecode->in_cnt)- memmove(ptr, uudecode->in_buff, uudecode->in_cnt);- /* Replace in_buff with the new buffer. */- free(uudecode->in_buff);- uudecode->in_buff = ptr;- uudecode->in_allocated = newsize;- }- return (ARCHIVE_OK);-}--static ssize_t-uudecode_filter_read(struct archive_read_filter *self, const void **buff)-{- struct uudecode *uudecode;- const unsigned char *b, *d;- unsigned char *out;- ssize_t avail_in, ravail;- ssize_t used;- ssize_t total;- ssize_t len, llen, nl;-- uudecode = (struct uudecode *)self->data;--read_more:- d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);- if (d == NULL && avail_in < 0)- return (ARCHIVE_FATAL);- /* Quiet a code analyzer; make sure avail_in must be zero- * when d is NULL. */- if (d == NULL)- avail_in = 0;- used = 0;- total = 0;- out = uudecode->out_buff;- ravail = avail_in;- if (uudecode->state == ST_IGNORE) {- used = avail_in;- goto finish;- }- if (uudecode->in_cnt) {- /*- * If there is remaining data which is saved by- * previous calling, use it first.- */- if (ensure_in_buff_size(self, uudecode,- avail_in + uudecode->in_cnt) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- memcpy(uudecode->in_buff + uudecode->in_cnt,- d, avail_in);- d = uudecode->in_buff;- avail_in += uudecode->in_cnt;- uudecode->in_cnt = 0;- }- for (;used < avail_in; d += llen, used += llen) {- int64_t l, body;-- b = d;- len = get_line(b, avail_in - used, &nl);- if (len < 0) {- /* Non-ascii character is found. */- if (uudecode->state == ST_FIND_HEAD &&- (uudecode->total > 0 || total > 0)) {- uudecode->state = ST_IGNORE;- used = avail_in;- goto finish;- }- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Insufficient compressed data");- return (ARCHIVE_FATAL);- }- llen = len;- if ((nl == 0) && (uudecode->state != ST_UUEND)) {- if (total == 0 && ravail <= 0) {- /* There is nothing more to read, fail */- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Missing format data");- return (ARCHIVE_FATAL);- }- /*- * Save remaining data which does not contain- * NL('\n','\r').- */- if (ensure_in_buff_size(self, uudecode, len)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- if (uudecode->in_buff != b)- memmove(uudecode->in_buff, b, len);- uudecode->in_cnt = (int)len;- if (total == 0) {- /* Do not return 0; it means end-of-file.- * We should try to read bytes more. */- __archive_read_filter_consume(- self->upstream, ravail);- goto read_more;- }- used += len;- break;- }- switch (uudecode->state) {- default:- case ST_FIND_HEAD:- /* Do not read more than UUENCODE_BID_MAX_READ bytes */- if (total + len >= UUENCODE_BID_MAX_READ) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid format data");- return (ARCHIVE_FATAL);- }- if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)- l = 6;- else if (len - nl >= 18 &&- memcmp(b, "begin-base64 ", 13) == 0)- l = 13;- else- l = 0;- if (l != 0 && b[l] >= '0' && b[l] <= '7' &&- b[l+1] >= '0' && b[l+1] <= '7' &&- b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {- if (l == 6)- uudecode->state = ST_READ_UU;- else- uudecode->state = ST_READ_BASE64;- }- break;- case ST_READ_UU:- if (total + len * 2 > OUT_BUFF_SIZE)- goto finish;- body = len - nl;- if (!uuchar[*b] || body <= 0) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Insufficient compressed data");- return (ARCHIVE_FATAL);- }- /* Get length of undecoded bytes of current line. */- l = UUDECODE(*b++);- body--;- if (l > body) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Insufficient compressed data");- return (ARCHIVE_FATAL);- }- if (l == 0) {- uudecode->state = ST_UUEND;- break;- }- while (l > 0) {- int n = 0;-- if (!uuchar[b[0]] || !uuchar[b[1]])- break;- n = UUDECODE(*b++) << 18;- n |= UUDECODE(*b++) << 12;- *out++ = n >> 16; total++;- --l;-- if (l > 0) {- if (!uuchar[b[0]])- break;- n |= UUDECODE(*b++) << 6;- *out++ = (n >> 8) & 0xFF; total++;- --l;- }- if (l > 0) {- if (!uuchar[b[0]])- break;- n |= UUDECODE(*b++);- *out++ = n & 0xFF; total++;- --l;- }- }- if (l) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Insufficient compressed data");- return (ARCHIVE_FATAL);- }- break;- case ST_UUEND:- if (len - nl == 3 && memcmp(b, "end ", 3) == 0)- uudecode->state = ST_FIND_HEAD;- else {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Insufficient compressed data");- return (ARCHIVE_FATAL);- }- break;- case ST_READ_BASE64:- if (total + len * 2 > OUT_BUFF_SIZE)- goto finish;- l = len - nl;- if (l >= 3 && b[0] == '=' && b[1] == '=' &&- b[2] == '=') {- uudecode->state = ST_FIND_HEAD;- break;- }- while (l > 0) {- int n = 0;-- if (!base64[b[0]] || !base64[b[1]])- break;- n = base64num[*b++] << 18;- n |= base64num[*b++] << 12;- *out++ = n >> 16; total++;- l -= 2;-- if (l > 0) {- if (*b == '=')- break;- if (!base64[*b])- break;- n |= base64num[*b++] << 6;- *out++ = (n >> 8) & 0xFF; total++;- --l;- }- if (l > 0) {- if (*b == '=')- break;- if (!base64[*b])- break;- n |= base64num[*b++];- *out++ = n & 0xFF; total++;- --l;- }- }- if (l && *b != '=') {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Insufficient compressed data");- return (ARCHIVE_FATAL);- }- break;- }- }-finish:- if (ravail < avail_in)- used -= avail_in - ravail;- __archive_read_filter_consume(self->upstream, used);-- *buff = uudecode->out_buff;- uudecode->total += total;- return (total);-}--static int-uudecode_filter_close(struct archive_read_filter *self)-{- struct uudecode *uudecode;-- uudecode = (struct uudecode *)self->data;- free(uudecode->in_buff);- free(uudecode->out_buff);- free(uudecode);-- return (ARCHIVE_OK);-}-
− c/archive_read_support_filter_xz.c
@@ -1,793 +0,0 @@-/*-- * Copyright (c) 2009-2011 Michihiro NAKAJIMA- * Copyright (c) 2003-2008 Tim Kientzle and Miklos Vajna- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#ifdef HAVE_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_UNISTD_H-#include <unistd.h>-#endif-#if HAVE_LZMA_H-#include <lzma.h>-#endif--#include "archive.h"-#include "archive_endian.h"-#include "archive_private.h"-#include "archive_read_private.h"--#if HAVE_LZMA_H && HAVE_LIBLZMA--struct private_data {- lzma_stream stream;- unsigned char *out_block;- size_t out_block_size;- int64_t total_out;- char eof; /* True = found end of compressed data. */- char in_stream;-- /* Following variables are used for lzip only. */- char lzip_ver;- uint32_t crc32;- int64_t member_in;- int64_t member_out;-};--#if LZMA_VERSION_MAJOR >= 5-/* Effectively disable the limiter. */-#define LZMA_MEMLIMIT UINT64_MAX-#else-/* NOTE: This needs to check memory size which running system has. */-#define LZMA_MEMLIMIT (1U << 30)-#endif--/* Combined lzip/lzma/xz filter */-static ssize_t xz_filter_read(struct archive_read_filter *, const void **);-static int xz_filter_close(struct archive_read_filter *);-static int xz_lzma_bidder_init(struct archive_read_filter *);--#endif--/*- * Note that we can detect xz and lzma compressed files even if we- * can't decompress them. (In fact, we like detecting them because we- * can give better error messages.) So the bid framework here gets- * compiled even if no lzma library is available.- */-static int xz_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *);-static int xz_bidder_init(struct archive_read_filter *);-static int lzma_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *);-static int lzma_bidder_init(struct archive_read_filter *);-static int lzip_has_member(struct archive_read_filter *);-static int lzip_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *);-static int lzip_bidder_init(struct archive_read_filter *);--#if ARCHIVE_VERSION_NUMBER < 4000000-/* Deprecated; remove in libarchive 4.0 */-int-archive_read_support_compression_xz(struct archive *a)-{- return archive_read_support_filter_xz(a);-}-#endif--static const struct archive_read_filter_bidder_vtable-xz_bidder_vtable = {- .bid = xz_bidder_bid,- .init = xz_bidder_init,-};--int-archive_read_support_filter_xz(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- if (__archive_read_register_bidder(a, NULL, "xz",- &xz_bidder_vtable) != ARCHIVE_OK)- return (ARCHIVE_FATAL);--#if HAVE_LZMA_H && HAVE_LIBLZMA- return (ARCHIVE_OK);-#else- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external xz program for xz decompression");- return (ARCHIVE_WARN);-#endif-}--#if ARCHIVE_VERSION_NUMBER < 4000000-int-archive_read_support_compression_lzma(struct archive *a)-{- return archive_read_support_filter_lzma(a);-}-#endif--static const struct archive_read_filter_bidder_vtable-lzma_bidder_vtable = {- .bid = lzma_bidder_bid,- .init = lzma_bidder_init,-};--int-archive_read_support_filter_lzma(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- if (__archive_read_register_bidder(a, NULL, "lzma",- &lzma_bidder_vtable) != ARCHIVE_OK)- return (ARCHIVE_FATAL);--#if HAVE_LZMA_H && HAVE_LIBLZMA- return (ARCHIVE_OK);-#else- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external lzma program for lzma decompression");- return (ARCHIVE_WARN);-#endif-}---#if ARCHIVE_VERSION_NUMBER < 4000000-int-archive_read_support_compression_lzip(struct archive *a)-{- return archive_read_support_filter_lzip(a);-}-#endif--static const struct archive_read_filter_bidder_vtable-lzip_bidder_vtable = {- .bid = lzip_bidder_bid,- .init = lzip_bidder_init,-};--int-archive_read_support_filter_lzip(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- if (__archive_read_register_bidder(a, NULL, "lzip",- &lzip_bidder_vtable) != ARCHIVE_OK)- return (ARCHIVE_FATAL);--#if HAVE_LZMA_H && HAVE_LIBLZMA- return (ARCHIVE_OK);-#else- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external lzip program for lzip decompression");- return (ARCHIVE_WARN);-#endif-}--/*- * Test whether we can handle this data.- */-static int-xz_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- const unsigned char *buffer;- ssize_t avail;-- (void)self; /* UNUSED */-- buffer = __archive_read_filter_ahead(filter, 6, &avail);- if (buffer == NULL)- return (0);-- /*- * Verify Header Magic Bytes : FD 37 7A 58 5A 00- */- if (memcmp(buffer, "\xFD\x37\x7A\x58\x5A\x00", 6) != 0)- return (0);-- return (48);-}--/*- * Test whether we can handle this data.- *- * <sigh> LZMA has a rather poor file signature. Zeros do not- * make good signature bytes as a rule, and the only non-zero byte- * here is an ASCII character. For example, an uncompressed tar- * archive whose first file is ']' would satisfy this check. It may- * be necessary to exclude LZMA from compression_all() because of- * this. Clients of libarchive would then have to explicitly enable- * LZMA checking instead of (or in addition to) compression_all() when- * they have other evidence (file name, command-line option) to go on.- */-static int-lzma_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- const unsigned char *buffer;- ssize_t avail;- uint32_t dicsize;- uint64_t uncompressed_size;- int bits_checked;-- (void)self; /* UNUSED */-- buffer = __archive_read_filter_ahead(filter, 14, &avail);- if (buffer == NULL)- return (0);-- /* First byte of raw LZMA stream is commonly 0x5d.- * The first byte is a special number, which consists of- * three parameters of LZMA compression, a number of literal- * context bits(which is from 0 to 8, default is 3), a number- * of literal pos bits(which is from 0 to 4, default is 0),- * a number of pos bits(which is from 0 to 4, default is 2).- * The first byte is made by- * (pos bits * 5 + literal pos bit) * 9 + * literal contest bit,- * and so the default value in this field is- * (2 * 5 + 0) * 9 + 3 = 0x5d.- * lzma of LZMA SDK has options to change those parameters.- * It means a range of this field is from 0 to 224. And lzma of- * XZ Utils with option -e records 0x5e in this field. */- /* NOTE: If this checking of the first byte increases false- * recognition, we should allow only 0x5d and 0x5e for the first- * byte of LZMA stream. */- bits_checked = 0;- if (buffer[0] > (4 * 5 + 4) * 9 + 8)- return (0);- /* Most likely value in the first byte of LZMA stream. */- if (buffer[0] == 0x5d || buffer[0] == 0x5e)- bits_checked += 8;-- /* Sixth through fourteenth bytes are uncompressed size,- * stored in little-endian order. `-1' means uncompressed- * size is unknown and lzma of XZ Utils always records `-1'- * in this field. */- uncompressed_size = archive_le64dec(buffer+5);- if (uncompressed_size == (uint64_t)ARCHIVE_LITERAL_LL(-1))- bits_checked += 64;-- /* Second through fifth bytes are dictionary size, stored in- * little-endian order. The minimum dictionary size is- * 1 << 12(4KiB) which the lzma of LZMA SDK uses with option- * -d12 and the maximum dictionary size is 1 << 29(512MiB)- * which the one uses with option -d29.- * NOTE: A comment of LZMA SDK source code says this dictionary- * range is from 1 << 12 to 1 << 30. */- dicsize = archive_le32dec(buffer+1);- switch (dicsize) {- case 0x00001000:/* lzma of LZMA SDK option -d12. */- case 0x00002000:/* lzma of LZMA SDK option -d13. */- case 0x00004000:/* lzma of LZMA SDK option -d14. */- case 0x00008000:/* lzma of LZMA SDK option -d15. */- case 0x00010000:/* lzma of XZ Utils option -0 and -1.- * lzma of LZMA SDK option -d16. */- case 0x00020000:/* lzma of LZMA SDK option -d17. */- case 0x00040000:/* lzma of LZMA SDK option -d18. */- case 0x00080000:/* lzma of XZ Utils option -2.- * lzma of LZMA SDK option -d19. */- case 0x00100000:/* lzma of XZ Utils option -3.- * lzma of LZMA SDK option -d20. */- case 0x00200000:/* lzma of XZ Utils option -4.- * lzma of LZMA SDK option -d21. */- case 0x00400000:/* lzma of XZ Utils option -5.- * lzma of LZMA SDK option -d22. */- case 0x00800000:/* lzma of XZ Utils option -6.- * lzma of LZMA SDK option -d23. */- case 0x01000000:/* lzma of XZ Utils option -7.- * lzma of LZMA SDK option -d24. */- case 0x02000000:/* lzma of XZ Utils option -8.- * lzma of LZMA SDK option -d25. */- case 0x04000000:/* lzma of XZ Utils option -9.- * lzma of LZMA SDK option -d26. */- case 0x08000000:/* lzma of LZMA SDK option -d27. */- bits_checked += 32;- break;- default:- /* If a memory usage for encoding was not enough on- * the platform where LZMA stream was made, lzma of- * XZ Utils automatically decreased the dictionary- * size to enough memory for encoding by 1Mi bytes- * (1 << 20).*/- if (dicsize <= 0x03F00000 && dicsize >= 0x00300000 &&- (dicsize & ((1 << 20)-1)) == 0 &&- bits_checked == 8 + 64) {- bits_checked += 32;- break;- }- /* Otherwise dictionary size is unlikely. But it is- * possible that someone makes lzma stream with- * liblzma/LZMA SDK in one's dictionary size. */- return (0);- }-- /* TODO: The above test is still very weak. It would be- * good to do better. */-- return (bits_checked);-}--static int-lzip_has_member(struct archive_read_filter *filter)-{- const unsigned char *buffer;- ssize_t avail;- int bits_checked;- int log2dic;-- buffer = __archive_read_filter_ahead(filter, 6, &avail);- if (buffer == NULL)- return (0);-- /*- * Verify Header Magic Bytes : 4C 5A 49 50 (`LZIP')- */- bits_checked = 0;- if (memcmp(buffer, "LZIP", 4) != 0)- return (0);- bits_checked += 32;-- /* A version number must be 0 or 1 */- if (buffer[4] != 0 && buffer[4] != 1)- return (0);- bits_checked += 8;-- /* Dictionary size. */- log2dic = buffer[5] & 0x1f;- if (log2dic < 12 || log2dic > 29)- return (0);- bits_checked += 8;-- return (bits_checked);-}--static int-lzip_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{-- (void)self; /* UNUSED */- return (lzip_has_member(filter));-}--#if HAVE_LZMA_H && HAVE_LIBLZMA--/*- * liblzma 4.999.7 and later support both lzma and xz streams.- */-static int-xz_bidder_init(struct archive_read_filter *self)-{- self->code = ARCHIVE_FILTER_XZ;- self->name = "xz";- return (xz_lzma_bidder_init(self));-}--static int-lzma_bidder_init(struct archive_read_filter *self)-{- self->code = ARCHIVE_FILTER_LZMA;- self->name = "lzma";- return (xz_lzma_bidder_init(self));-}--static int-lzip_bidder_init(struct archive_read_filter *self)-{- self->code = ARCHIVE_FILTER_LZIP;- self->name = "lzip";- return (xz_lzma_bidder_init(self));-}--/*- * Set an error code and choose an error message- */-static void-set_error(struct archive_read_filter *self, int ret)-{-- switch (ret) {- case LZMA_STREAM_END: /* Found end of stream. */- case LZMA_OK: /* Decompressor made some progress. */- break;- case LZMA_MEM_ERROR:- archive_set_error(&self->archive->archive, ENOMEM,- "Lzma library error: Cannot allocate memory");- break;- case LZMA_MEMLIMIT_ERROR:- archive_set_error(&self->archive->archive, ENOMEM,- "Lzma library error: Out of memory");- break;- case LZMA_FORMAT_ERROR:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Lzma library error: format not recognized");- break;- case LZMA_OPTIONS_ERROR:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Lzma library error: Invalid options");- break;- case LZMA_DATA_ERROR:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Lzma library error: Corrupted input data");- break;- case LZMA_BUF_ERROR:- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Lzma library error: No progress is possible");- break;- default:- /* Return an error. */- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Lzma decompression failed: Unknown error");- break;- }-}--static const struct archive_read_filter_vtable-xz_lzma_reader_vtable = {- .read = xz_filter_read,- .close = xz_filter_close,-};--/*- * Setup the callbacks.- */-static int-xz_lzma_bidder_init(struct archive_read_filter *self)-{- static const size_t out_block_size = 64 * 1024;- void *out_block;- struct private_data *state;- int ret;-- state = (struct private_data *)calloc(sizeof(*state), 1);- out_block = (unsigned char *)malloc(out_block_size);- if (state == NULL || out_block == NULL) {- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for xz decompression");- free(out_block);- free(state);- return (ARCHIVE_FATAL);- }-- self->data = state;- state->out_block_size = out_block_size;- state->out_block = out_block;- self->vtable = &xz_lzma_reader_vtable;-- state->stream.avail_in = 0;-- state->stream.next_out = state->out_block;- state->stream.avail_out = state->out_block_size;-- state->crc32 = 0;- if (self->code == ARCHIVE_FILTER_LZIP) {- /*- * We have to read a lzip header and use it to initialize- * compression library, thus we cannot initialize the- * library for lzip here.- */- state->in_stream = 0;- return (ARCHIVE_OK);- } else- state->in_stream = 1;-- /* Initialize compression library. */- if (self->code == ARCHIVE_FILTER_XZ)- ret = lzma_stream_decoder(&(state->stream),- LZMA_MEMLIMIT,/* memlimit */- LZMA_CONCATENATED);- else- ret = lzma_alone_decoder(&(state->stream),- LZMA_MEMLIMIT);/* memlimit */-- if (ret == LZMA_OK)- return (ARCHIVE_OK);-- /* Library setup failed: Choose an error message and clean up. */- set_error(self, ret);-- free(state->out_block);- free(state);- self->data = NULL;- return (ARCHIVE_FATAL);-}--static int-lzip_init(struct archive_read_filter *self)-{- struct private_data *state;- const unsigned char *h;- lzma_filter filters[2];- unsigned char props[5];- ssize_t avail_in;- uint32_t dicsize;- int log2dic, ret;-- state = (struct private_data *)self->data;- h = __archive_read_filter_ahead(self->upstream, 6, &avail_in);- if (h == NULL)- return (ARCHIVE_FATAL);-- /* Get a version number. */- state->lzip_ver = h[4];-- /*- * Setup lzma property.- */- props[0] = 0x5d;-- /* Get dictionary size. */- log2dic = h[5] & 0x1f;- if (log2dic < 12 || log2dic > 29)- return (ARCHIVE_FATAL);- dicsize = 1U << log2dic;- if (log2dic > 12)- dicsize -= (dicsize / 16) * (h[5] >> 5);- archive_le32enc(props+1, dicsize);-- /* Consume lzip header. */- __archive_read_filter_consume(self->upstream, 6);- state->member_in = 6;-- filters[0].id = LZMA_FILTER_LZMA1;- filters[0].options = NULL;- filters[1].id = LZMA_VLI_UNKNOWN;- filters[1].options = NULL;-- ret = lzma_properties_decode(&filters[0], NULL, props, sizeof(props));- if (ret != LZMA_OK) {- set_error(self, ret);- return (ARCHIVE_FATAL);- }- ret = lzma_raw_decoder(&(state->stream), filters);- free(filters[0].options);- if (ret != LZMA_OK) {- set_error(self, ret);- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}--static int-lzip_tail(struct archive_read_filter *self)-{- struct private_data *state;- const unsigned char *f;- ssize_t avail_in;- int tail;-- state = (struct private_data *)self->data;- if (state->lzip_ver == 0)- tail = 12;- else- tail = 20;- f = __archive_read_filter_ahead(self->upstream, tail, &avail_in);- if (f == NULL && avail_in < 0)- return (ARCHIVE_FATAL);- if (f == NULL || avail_in < tail) {- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "Lzip: Remaining data is less bytes");- return (ARCHIVE_FAILED);- }-- /* Check the crc32 value of the uncompressed data of the current- * member */- if (state->crc32 != archive_le32dec(f)) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "Lzip: CRC32 error");- return (ARCHIVE_FAILED);-#endif- }-- /* Check the uncompressed size of the current member */- if ((uint64_t)state->member_out != archive_le64dec(f + 4)) {- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "Lzip: Uncompressed size error");- return (ARCHIVE_FAILED);- }-- /* Check the total size of the current member */- if (state->lzip_ver == 1 &&- (uint64_t)state->member_in + tail != archive_le64dec(f + 12)) {- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,- "Lzip: Member size error");- return (ARCHIVE_FAILED);- }- __archive_read_filter_consume(self->upstream, tail);-- /* If current lzip data consists of multi member, try decompressing- * a next member. */- if (lzip_has_member(self->upstream) != 0) {- state->in_stream = 0;- state->crc32 = 0;- state->member_out = 0;- state->member_in = 0;- state->eof = 0;- }- return (ARCHIVE_OK);-}--/*- * Return the next block of decompressed data.- */-static ssize_t-xz_filter_read(struct archive_read_filter *self, const void **p)-{- struct private_data *state;- size_t decompressed;- ssize_t avail_in;- int ret;-- state = (struct private_data *)self->data;-- /* Empty our output buffer. */- state->stream.next_out = state->out_block;- state->stream.avail_out = state->out_block_size;-- /* Try to fill the output buffer. */- while (state->stream.avail_out > 0 && !state->eof) {- if (!state->in_stream) {- /*- * Initialize liblzma for lzip- */- ret = lzip_init(self);- if (ret != ARCHIVE_OK)- return (ret);- state->in_stream = 1;- }- state->stream.next_in =- __archive_read_filter_ahead(self->upstream, 1, &avail_in);- if (state->stream.next_in == NULL && avail_in < 0) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "truncated input");- return (ARCHIVE_FATAL);- }- state->stream.avail_in = avail_in;-- /* Decompress as much as we can in one pass. */- ret = lzma_code(&(state->stream),- (state->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN);- switch (ret) {- case LZMA_STREAM_END: /* Found end of stream. */- state->eof = 1;- /* FALL THROUGH */- case LZMA_OK: /* Decompressor made some progress. */- __archive_read_filter_consume(self->upstream,- avail_in - state->stream.avail_in);- state->member_in +=- avail_in - state->stream.avail_in;- break;- default:- set_error(self, ret);- return (ARCHIVE_FATAL);- }- }-- decompressed = state->stream.next_out - state->out_block;- state->total_out += decompressed;- state->member_out += decompressed;- if (decompressed == 0)- *p = NULL;- else {- *p = state->out_block;- if (self->code == ARCHIVE_FILTER_LZIP) {- state->crc32 = lzma_crc32(state->out_block,- decompressed, state->crc32);- if (state->eof) {- ret = lzip_tail(self);- if (ret != ARCHIVE_OK)- return (ret);- }- }- }- return (decompressed);-}--/*- * Clean up the decompressor.- */-static int-xz_filter_close(struct archive_read_filter *self)-{- struct private_data *state;-- state = (struct private_data *)self->data;- lzma_end(&(state->stream));- free(state->out_block);- free(state);- return (ARCHIVE_OK);-}--#else--/*- *- * If we have no suitable library on this system, we can't actually do- * the decompression. We can, however, still detect compressed- * archives and emit a useful message.- *- */-static int-lzma_bidder_init(struct archive_read_filter *self)-{- int r;-- r = __archive_read_program(self, "lzma -d -qq");- /* Note: We set the format here even if __archive_read_program()- * above fails. We do, after all, know what the format is- * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_LZMA;- self->name = "lzma";- return (r);-}--static int-xz_bidder_init(struct archive_read_filter *self)-{- int r;-- r = __archive_read_program(self, "xz -d -qq");- /* Note: We set the format here even if __archive_read_program()- * above fails. We do, after all, know what the format is- * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_XZ;- self->name = "xz";- return (r);-}--static int-lzip_bidder_init(struct archive_read_filter *self)-{- int r;-- r = __archive_read_program(self, "lzip -d -q");- /* Note: We set the format here even if __archive_read_program()- * above fails. We do, after all, know what the format is- * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_LZIP;- self->name = "lzip";- return (r);-}--#endif /* HAVE_LZMA_H */
− c/archive_read_support_filter_zstd.c
@@ -1,297 +0,0 @@-/*-- * Copyright (c) 2009-2011 Sean Purcell- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif--#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_UNISTD_H-#include <unistd.h>-#endif-#if HAVE_ZSTD_H-#include <zstd.h>-#endif--#include "archive.h"-#include "archive_endian.h"-#include "archive_private.h"-#include "archive_read_private.h"--#if HAVE_ZSTD_H && HAVE_LIBZSTD--struct private_data {- ZSTD_DStream *dstream;- unsigned char *out_block;- size_t out_block_size;- int64_t total_out;- char in_frame; /* True = in the middle of a zstd frame. */- char eof; /* True = found end of compressed data. */-};--/* Zstd Filter. */-static ssize_t zstd_filter_read(struct archive_read_filter *, const void**);-static int zstd_filter_close(struct archive_read_filter *);-#endif--/*- * Note that we can detect zstd compressed files even if we can't decompress- * them. (In fact, we like detecting them because we can give better error- * messages.) So the bid framework here gets compiled even if no zstd library- * is available.- */-static int zstd_bidder_bid(struct archive_read_filter_bidder *,- struct archive_read_filter *);-static int zstd_bidder_init(struct archive_read_filter *);--static const struct archive_read_filter_bidder_vtable-zstd_bidder_vtable = {- .bid = zstd_bidder_bid,- .init = zstd_bidder_init,-};--int-archive_read_support_filter_zstd(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;-- if (__archive_read_register_bidder(a, NULL, "zstd",- &zstd_bidder_vtable) != ARCHIVE_OK)- return (ARCHIVE_FATAL);--#if HAVE_ZSTD_H && HAVE_LIBZSTD- return (ARCHIVE_OK);-#else- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external zstd program for zstd decompression");- return (ARCHIVE_WARN);-#endif-}--/*- * Test whether we can handle this data.- */-static int-zstd_bidder_bid(struct archive_read_filter_bidder *self,- struct archive_read_filter *filter)-{- const unsigned char *buffer;- ssize_t avail;- unsigned prefix;-- /* Zstd frame magic values */- unsigned zstd_magic = 0xFD2FB528U;- unsigned zstd_magic_skippable_start = 0x184D2A50U;- unsigned zstd_magic_skippable_mask = 0xFFFFFFF0;-- (void) self; /* UNUSED */-- buffer = __archive_read_filter_ahead(filter, 4, &avail);- if (buffer == NULL)- return (0);-- prefix = archive_le32dec(buffer);- if (prefix == zstd_magic)- return (32);- if ((prefix & zstd_magic_skippable_mask) == zstd_magic_skippable_start)- return (32);-- return (0);-}--#if !(HAVE_ZSTD_H && HAVE_LIBZSTD)--/*- * If we don't have the library on this system, we can't do the- * decompression directly. We can, however, try to run "zstd -d"- * in case that's available.- */-static int-zstd_bidder_init(struct archive_read_filter *self)-{- int r;-- r = __archive_read_program(self, "zstd -d -qq");- /* Note: We set the format here even if __archive_read_program()- * above fails. We do, after all, know what the format is- * even if we weren't able to read it. */- self->code = ARCHIVE_FILTER_ZSTD;- self->name = "zstd";- return (r);-}--#else--static const struct archive_read_filter_vtable-zstd_reader_vtable = {- .read = zstd_filter_read,- .close = zstd_filter_close,-};--/*- * Initialize the filter object- */-static int-zstd_bidder_init(struct archive_read_filter *self)-{- struct private_data *state;- size_t out_block_size = ZSTD_DStreamOutSize();- void *out_block;- ZSTD_DStream *dstream;-- self->code = ARCHIVE_FILTER_ZSTD;- self->name = "zstd";-- state = (struct private_data *)calloc(sizeof(*state), 1);- out_block = (unsigned char *)malloc(out_block_size);- dstream = ZSTD_createDStream();-- if (state == NULL || out_block == NULL || dstream == NULL) {- free(out_block);- free(state);- ZSTD_freeDStream(dstream); /* supports free on NULL */- archive_set_error(&self->archive->archive, ENOMEM,- "Can't allocate data for zstd decompression");- return (ARCHIVE_FATAL);- }-- self->data = state;-- state->out_block_size = out_block_size;- state->out_block = out_block;- state->dstream = dstream;- self->vtable = &zstd_reader_vtable;-- state->eof = 0;- state->in_frame = 0;-- return (ARCHIVE_OK);-}--static ssize_t-zstd_filter_read(struct archive_read_filter *self, const void **p)-{- struct private_data *state;- size_t decompressed;- ssize_t avail_in;- ZSTD_outBuffer out;- ZSTD_inBuffer in;- size_t ret;-- state = (struct private_data *)self->data;-- out = (ZSTD_outBuffer) { state->out_block, state->out_block_size, 0 };-- /* Try to fill the output buffer. */- while (out.pos < out.size && !state->eof) {- if (!state->in_frame) {- ret = ZSTD_initDStream(state->dstream);- if (ZSTD_isError(ret)) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Error initializing zstd decompressor: %s",- ZSTD_getErrorName(ret));- return (ARCHIVE_FATAL);- }- }- in.src = __archive_read_filter_ahead(self->upstream, 1,- &avail_in);- if (avail_in < 0) {- return avail_in;- }- if (in.src == NULL && avail_in == 0) {- if (!state->in_frame) {- /* end of stream */- state->eof = 1;- break;- } else {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Truncated zstd input");- return (ARCHIVE_FATAL);- }- }- in.size = avail_in;- in.pos = 0;-- {- ret = ZSTD_decompressStream(state->dstream, &out, &in);-- if (ZSTD_isError(ret)) {- archive_set_error(&self->archive->archive,- ARCHIVE_ERRNO_MISC,- "Zstd decompression failed: %s",- ZSTD_getErrorName(ret));- return (ARCHIVE_FATAL);- }-- /* Decompressor made some progress */- __archive_read_filter_consume(self->upstream, in.pos);-- /* ret guaranteed to be > 0 if frame isn't done yet */- state->in_frame = (ret != 0);- }- }-- decompressed = out.pos;- state->total_out += decompressed;- if (decompressed == 0)- *p = NULL;- else- *p = state->out_block;- return (decompressed);-}--/*- * Clean up the decompressor.- */-static int-zstd_filter_close(struct archive_read_filter *self)-{- struct private_data *state;-- state = (struct private_data *)self->data;-- ZSTD_freeDStream(state->dstream);- free(state->out_block);- free(state);-- return (ARCHIVE_OK);-}--#endif /* HAVE_ZLIB_H && HAVE_LIBZSTD */
− c/archive_read_support_format_7zip.c
@@ -1,4074 +0,0 @@-/*-- * Copyright (c) 2011 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_BZLIB_H-#include <bzlib.h>-#endif-#ifdef HAVE_LZMA_H-#include <lzma.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif-#ifdef HAVE_ZSTD_H-#include <zstd.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_ppmd7_private.h"-#include "archive_private.h"-#include "archive_read_private.h"-#include "archive_endian.h"--#ifndef HAVE_ZLIB_H-#include "archive_crc32.h"-#endif--#define _7ZIP_SIGNATURE "7z\xBC\xAF\x27\x1C"-#define SFX_MIN_ADDR 0x27000-#define SFX_MAX_ADDR 0x60000---/*- * Codec ID- */-#define _7Z_COPY 0-#define _7Z_LZMA 0x030101-#define _7Z_LZMA2 0x21-#define _7Z_DEFLATE 0x040108-#define _7Z_BZ2 0x040202-#define _7Z_PPMD 0x030401-#define _7Z_DELTA 0x03-#define _7Z_CRYPTO_MAIN_ZIP 0x06F10101 /* Main Zip crypto algo */-#define _7Z_CRYPTO_RAR_29 0x06F10303 /* Rar29 AES-128 + (modified SHA-1) */-#define _7Z_CRYPTO_AES_256_SHA_256 0x06F10701 /* AES-256 + SHA-256 */---#define _7Z_X86 0x03030103-#define _7Z_X86_BCJ2 0x0303011B-#define _7Z_POWERPC 0x03030205-#define _7Z_IA64 0x03030401-#define _7Z_ARM 0x03030501-#define _7Z_ARMTHUMB 0x03030701-#define _7Z_ARM64 0xa-#define _7Z_SPARC 0x03030805--#define _7Z_ZSTD 0x4F71101 /* Copied from https://github.com/mcmilk/7-Zip-zstd.git */--/*- * 7-Zip header property IDs.- */-#define kEnd 0x00-#define kHeader 0x01-#define kArchiveProperties 0x02-#define kAdditionalStreamsInfo 0x03-#define kMainStreamsInfo 0x04-#define kFilesInfo 0x05-#define kPackInfo 0x06-#define kUnPackInfo 0x07-#define kSubStreamsInfo 0x08-#define kSize 0x09-#define kCRC 0x0A-#define kFolder 0x0B-#define kCodersUnPackSize 0x0C-#define kNumUnPackStream 0x0D-#define kEmptyStream 0x0E-#define kEmptyFile 0x0F-#define kAnti 0x10-#define kName 0x11-#define kCTime 0x12-#define kATime 0x13-#define kMTime 0x14-#define kAttributes 0x15-#define kEncodedHeader 0x17-#define kDummy 0x19--struct _7z_digests {- unsigned char *defineds;- uint32_t *digests;-};---struct _7z_folder {- uint64_t numCoders;- struct _7z_coder {- unsigned long codec;- uint64_t numInStreams;- uint64_t numOutStreams;- uint64_t propertiesSize;- unsigned char *properties;- } *coders;- uint64_t numBindPairs;- struct {- uint64_t inIndex;- uint64_t outIndex;- } *bindPairs;- uint64_t numPackedStreams;- uint64_t *packedStreams;- uint64_t numInStreams;- uint64_t numOutStreams;- uint64_t *unPackSize;- unsigned char digest_defined;- uint32_t digest;- uint64_t numUnpackStreams;- uint32_t packIndex;- /* Unoperated bytes. */- uint64_t skipped_bytes;-};--struct _7z_coders_info {- uint64_t numFolders;- struct _7z_folder *folders;- uint64_t dataStreamIndex;-};--struct _7z_pack_info {- uint64_t pos;- uint64_t numPackStreams;- uint64_t *sizes;- struct _7z_digests digest;- /* Calculated from pos and numPackStreams. */- uint64_t *positions;-};--struct _7z_substream_info {- size_t unpack_streams;- uint64_t *unpackSizes;- unsigned char *digestsDefined;- uint32_t *digests;-};--struct _7z_stream_info {- struct _7z_pack_info pi;- struct _7z_coders_info ci;- struct _7z_substream_info ss;-};--struct _7z_header_info {- uint64_t dataIndex;-- unsigned char *emptyStreamBools;- unsigned char *emptyFileBools;- unsigned char *antiBools;- unsigned char *attrBools;-};--struct _7zip_entry {- size_t name_len;- unsigned char *utf16name;-#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)- const wchar_t *wname;-#endif- uint32_t folderIndex;- uint32_t ssIndex;- unsigned flg;-#define MTIME_IS_SET (1<<0)-#define ATIME_IS_SET (1<<1)-#define CTIME_IS_SET (1<<2)-#define CRC32_IS_SET (1<<3)-#define HAS_STREAM (1<<4)-- time_t mtime;- time_t atime;- time_t ctime;- long mtime_ns;- long atime_ns;- long ctime_ns;- uint32_t mode;- uint32_t attr;-};--struct _7zip {- /* Structural information about the archive. */- struct _7z_stream_info si;-- int header_is_being_read;- int header_is_encoded;- uint64_t header_bytes_remaining;- unsigned long header_crc32;- /* Header offset to check that reading points of the file contents- * will not exceed the header. */- uint64_t header_offset;- /* Base offset of the archive file for a seek in case reading SFX. */- uint64_t seek_base;-- /* List of entries */- size_t entries_remaining;- uint64_t numFiles;- struct _7zip_entry *entries;- struct _7zip_entry *entry;- unsigned char *entry_names;-- /* entry_bytes_remaining is the number of bytes we expect. */- int64_t entry_offset;- uint64_t entry_bytes_remaining;-- /* Running CRC32 of the decompressed data */- unsigned long entry_crc32;-- /* Flags to mark progress of decompression. */- char end_of_entry;-- /* Uncompressed buffer control. */-#define UBUFF_SIZE (64 * 1024)- unsigned char *uncompressed_buffer;- unsigned char *uncompressed_buffer_pointer;- size_t uncompressed_buffer_size;- size_t uncompressed_buffer_bytes_remaining;-- /* Offset of the compressed data. */- int64_t stream_offset;-- /*- * Decompressing control data.- */- unsigned folder_index;- uint64_t folder_outbytes_remaining;- unsigned pack_stream_index;- unsigned pack_stream_remaining;- uint64_t pack_stream_inbytes_remaining;- size_t pack_stream_bytes_unconsumed;-- /* The codec information of a folder. */- unsigned long codec;- unsigned long codec2;-- /*- * Decompressor controllers.- */- /* Decoding LZMA1 and LZMA2 data. */-#ifdef HAVE_LZMA_H- lzma_stream lzstream;- int lzstream_valid;-#endif- /* Decoding bzip2 data. */-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- bz_stream bzstream;- int bzstream_valid;-#endif- /* Decoding deflate data. */-#ifdef HAVE_ZLIB_H- z_stream stream;- int stream_valid;-#endif- /* Decoding Zstandard data. */-#if HAVE_ZSTD_H- ZSTD_DStream *zstd_dstream;- int zstdstream_valid;-#endif- /* Decoding PPMd data. */- int ppmd7_stat;- CPpmd7 ppmd7_context;- CPpmd7z_RangeDec range_dec;- IByteIn bytein;- struct {- const unsigned char *next_in;- int64_t avail_in;- int64_t total_in;- int64_t stream_in;- unsigned char *next_out;- int64_t avail_out;- int64_t total_out;- int overconsumed;- } ppstream;- int ppmd7_valid;-- /* Decoding BCJ and BCJ2 data. */- uint32_t bcj_state;- size_t odd_bcj_size;- unsigned char odd_bcj[4];- /* Decoding BCJ data. */- size_t bcj_prevPosT;- uint32_t bcj_prevMask;- uint32_t bcj_ip;-- /* Decoding BCJ2 data. */- size_t main_stream_bytes_remaining;- unsigned char *sub_stream_buff[3];- size_t sub_stream_size[3];- size_t sub_stream_bytes_remaining[3];- unsigned char *tmp_stream_buff;- size_t tmp_stream_buff_size;- size_t tmp_stream_bytes_avail;- size_t tmp_stream_bytes_remaining;-#ifdef _LZMA_PROB32-#define CProb uint32_t-#else-#define CProb uint16_t-#endif- CProb bcj2_p[256 + 2];- uint8_t bcj2_prevByte;- uint32_t bcj2_range;- uint32_t bcj2_code;- uint64_t bcj2_outPos;-- /* Filename character-set conversion data. */- struct archive_string_conv *sconv;-- char format_name[64];-- /* Custom value that is non-zero if this archive contains encrypted entries. */- int has_encrypted_entries;-};--/* Maximum entry size. This limitation prevents reading intentional- * corrupted 7-zip files on assuming there are not so many entries in- * the files. */-#define UMAX_ENTRY ARCHIVE_LITERAL_ULL(100000000)--static int archive_read_format_7zip_has_encrypted_entries(struct archive_read *);-static int archive_read_support_format_7zip_capabilities(struct archive_read *a);-static int archive_read_format_7zip_bid(struct archive_read *, int);-static int archive_read_format_7zip_cleanup(struct archive_read *);-static int archive_read_format_7zip_read_data(struct archive_read *,- const void **, size_t *, int64_t *);-static int archive_read_format_7zip_read_data_skip(struct archive_read *);-static int archive_read_format_7zip_read_header(struct archive_read *,- struct archive_entry *);-static int check_7zip_header_in_sfx(const char *);-static unsigned long decode_codec_id(const unsigned char *, size_t);-static int decode_encoded_header_info(struct archive_read *,- struct _7z_stream_info *);-static int decompress(struct archive_read *, struct _7zip *,- void *, size_t *, const void *, size_t *);-static ssize_t extract_pack_stream(struct archive_read *, size_t);-static void fileTimeToUtc(uint64_t, time_t *, long *);-static uint64_t folder_uncompressed_size(struct _7z_folder *);-static void free_CodersInfo(struct _7z_coders_info *);-static void free_Digest(struct _7z_digests *);-static void free_Folder(struct _7z_folder *);-static void free_Header(struct _7z_header_info *);-static void free_PackInfo(struct _7z_pack_info *);-static void free_StreamsInfo(struct _7z_stream_info *);-static void free_SubStreamsInfo(struct _7z_substream_info *);-static int free_decompression(struct archive_read *, struct _7zip *);-static ssize_t get_uncompressed_data(struct archive_read *, const void **,- size_t, size_t);-static const unsigned char * header_bytes(struct archive_read *, size_t);-static int init_decompression(struct archive_read *, struct _7zip *,- const struct _7z_coder *, const struct _7z_coder *);-static int parse_7zip_uint64(struct archive_read *, uint64_t *);-static int read_Bools(struct archive_read *, unsigned char *, size_t);-static int read_CodersInfo(struct archive_read *,- struct _7z_coders_info *);-static int read_Digests(struct archive_read *, struct _7z_digests *,- size_t);-static int read_Folder(struct archive_read *, struct _7z_folder *);-static int read_Header(struct archive_read *, struct _7z_header_info *,- int);-static int read_PackInfo(struct archive_read *, struct _7z_pack_info *);-static int read_StreamsInfo(struct archive_read *,- struct _7z_stream_info *);-static int read_SubStreamsInfo(struct archive_read *,- struct _7z_substream_info *, struct _7z_folder *, size_t);-static int read_Times(struct archive_read *, struct _7z_header_info *,- int);-static void read_consume(struct archive_read *);-static ssize_t read_stream(struct archive_read *, const void **, size_t,- size_t);-static int seek_pack(struct archive_read *);-static int64_t skip_stream(struct archive_read *, size_t);-static int skip_sfx(struct archive_read *, ssize_t);-static int slurp_central_directory(struct archive_read *, struct _7zip *,- struct _7z_header_info *);-static int setup_decode_folder(struct archive_read *, struct _7z_folder *,- int);-static void x86_Init(struct _7zip *);-static size_t x86_Convert(struct _7zip *, uint8_t *, size_t);-static void arm_Init(struct _7zip *);-static size_t arm_Convert(struct _7zip *, uint8_t *, size_t);-static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t);-static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);---int-archive_read_support_format_7zip(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct _7zip *zip;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_7zip");-- zip = calloc(1, sizeof(*zip));- if (zip == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate 7zip data");- return (ARCHIVE_FATAL);- }-- /*- * Until enough data has been read, we cannot tell about- * any encrypted entries yet.- */- zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;--- r = __archive_read_register_format(a,- zip,- "7zip",- archive_read_format_7zip_bid,- NULL,- archive_read_format_7zip_read_header,- archive_read_format_7zip_read_data,- archive_read_format_7zip_read_data_skip,- NULL,- archive_read_format_7zip_cleanup,- archive_read_support_format_7zip_capabilities,- archive_read_format_7zip_has_encrypted_entries);-- if (r != ARCHIVE_OK)- free(zip);- return (ARCHIVE_OK);-}--static int-archive_read_support_format_7zip_capabilities(struct archive_read * a)-{- (void)a; /* UNUSED */- return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA |- ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);-}---static int-archive_read_format_7zip_has_encrypted_entries(struct archive_read *_a)-{- if (_a && _a->format) {- struct _7zip * zip = (struct _7zip *)_a->format->data;- if (zip) {- return zip->has_encrypted_entries;- }- }- return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;-}--static int-archive_read_format_7zip_bid(struct archive_read *a, int best_bid)-{- const char *p;-- /* If someone has already bid more than 32, then avoid- trashing the look-ahead buffers with a seek. */- if (best_bid > 32)- return (-1);-- if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)- return (0);-- /* If first six bytes are the 7-Zip signature,- * return the bid right now. */- if (memcmp(p, _7ZIP_SIGNATURE, 6) == 0)- return (48);-- /*- * It may a 7-Zip SFX archive file. If first two bytes are- * 'M' and 'Z' available on Windows or first four bytes are- * "\x7F\x45LF" available on posix like system, seek the 7-Zip- * signature. Although we will perform a seek when reading- * a header, what we do not use __archive_read_seek() here is- * due to a bidding performance.- */- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {- ssize_t offset = SFX_MIN_ADDR;- ssize_t window = 4096;- ssize_t bytes_avail;- while (offset + window <= (SFX_MAX_ADDR)) {- const char *buff = __archive_read_ahead(a,- offset + window, &bytes_avail);- if (buff == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < 0x40)- return (0);- continue;- }- p = buff + offset;- while (p + 32 < buff + bytes_avail) {- int step = check_7zip_header_in_sfx(p);- if (step == 0)- return (48);- p += step;- }- offset = p - buff;- }- }- return (0);-}--static int-check_7zip_header_in_sfx(const char *p)-{- switch ((unsigned char)p[5]) {- case 0x1C:- if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0)- return (6);- /*- * Test the CRC because its extraction code has 7-Zip- * Magic Code, so we should do this in order not to- * make a mis-detection.- */- if (crc32(0, (const unsigned char *)p + 12, 20)- != archive_le32dec(p + 8))- return (6);- /* Hit the header! */- return (0);- case 0x37: return (5);- case 0x7A: return (4);- case 0xBC: return (3);- case 0xAF: return (2);- case 0x27: return (1);- default: return (6);- }-}--static int-skip_sfx(struct archive_read *a, ssize_t bytes_avail)-{- const void *h;- const char *p, *q;- size_t skip, offset;- ssize_t bytes, window;-- /*- * If bytes_avail > SFX_MIN_ADDR we do not have to call- * __archive_read_seek() at this time since we have- * already had enough data.- */- if (bytes_avail > SFX_MIN_ADDR)- __archive_read_consume(a, SFX_MIN_ADDR);- else if (__archive_read_seek(a, SFX_MIN_ADDR, SEEK_SET) < 0)- return (ARCHIVE_FATAL);-- offset = 0;- window = 1;- while (offset + window <= SFX_MAX_ADDR - SFX_MIN_ADDR) {- h = __archive_read_ahead(a, window, &bytes);- if (h == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < 0x40)- goto fatal;- continue;- }- if (bytes < 6) {- /* This case might happen when window == 1. */- window = 4096;- continue;- }- p = (const char *)h;- q = p + bytes;-- /*- * Scan ahead until we find something that looks- * like the 7-Zip header.- */- while (p + 32 < q) {- int step = check_7zip_header_in_sfx(p);- if (step == 0) {- struct _7zip *zip =- (struct _7zip *)a->format->data;- skip = p - (const char *)h;- __archive_read_consume(a, skip);- zip->seek_base = SFX_MIN_ADDR + offset + skip;- return (ARCHIVE_OK);- }- p += step;- }- skip = p - (const char *)h;- __archive_read_consume(a, skip);- offset += skip;- if (window == 1)- window = 4096;- }-fatal:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Couldn't find out 7-Zip header");- return (ARCHIVE_FATAL);-}--static int-archive_read_format_7zip_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- struct _7zip_entry *zip_entry;- int r, ret = ARCHIVE_OK;- struct _7z_folder *folder = 0;- uint64_t fidx = 0;-- /*- * It should be sufficient to call archive_read_next_header() for- * a reader to determine if an entry is encrypted or not. If the- * encryption of an entry is only detectable when calling- * archive_read_data(), so be it. We'll do the same check there- * as well.- */- if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {- zip->has_encrypted_entries = 0;- }-- a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;- if (a->archive.archive_format_name == NULL)- a->archive.archive_format_name = "7-Zip";-- if (zip->entries == NULL) {- struct _7z_header_info header;-- memset(&header, 0, sizeof(header));- r = slurp_central_directory(a, zip, &header);- free_Header(&header);- if (r != ARCHIVE_OK)- return (r);- zip->entries_remaining = (size_t)zip->numFiles;- zip->entry = zip->entries;- } else {- ++zip->entry;- }- zip_entry = zip->entry;-- if (zip->entries_remaining <= 0 || zip_entry == NULL)- return ARCHIVE_EOF;- --zip->entries_remaining;-- zip->entry_offset = 0;- zip->end_of_entry = 0;- zip->entry_crc32 = crc32(0, NULL, 0);-- /* Setup a string conversion for a filename. */- if (zip->sconv == NULL) {- zip->sconv = archive_string_conversion_from_charset(- &a->archive, "UTF-16LE", 1);- if (zip->sconv == NULL)- return (ARCHIVE_FATAL);- }-- /* Figure out if the entry is encrypted by looking at the folder- that is associated to the current 7zip entry. If the folder- has a coder with a _7Z_CRYPTO codec then the folder is encrypted.- Hence the entry must also be encrypted. */- if (zip_entry && zip_entry->folderIndex < zip->si.ci.numFolders) {- folder = &(zip->si.ci.folders[zip_entry->folderIndex]);- for (fidx=0; folder && fidx<folder->numCoders; fidx++) {- switch(folder->coders[fidx].codec) {- case _7Z_CRYPTO_MAIN_ZIP:- case _7Z_CRYPTO_RAR_29:- case _7Z_CRYPTO_AES_256_SHA_256: {- archive_entry_set_is_data_encrypted(entry, 1);- zip->has_encrypted_entries = 1;- break;- }- }- }- }-- /* Now that we've checked for encryption, if there were still no- * encrypted entries found we can say for sure that there are none.- */- if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {- zip->has_encrypted_entries = 0;- }-- if (archive_entry_copy_pathname_l(entry,- (const char *)zip_entry->utf16name,- zip_entry->name_len, zip->sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname cannot be converted "- "from %s to current locale.",- archive_string_conversion_charset_name(zip->sconv));- ret = ARCHIVE_WARN;- }-- /* Populate some additional entry fields: */- archive_entry_set_mode(entry, zip_entry->mode);- if (zip_entry->flg & MTIME_IS_SET)- archive_entry_set_mtime(entry, zip_entry->mtime,- zip_entry->mtime_ns);- if (zip_entry->flg & CTIME_IS_SET)- archive_entry_set_ctime(entry, zip_entry->ctime,- zip_entry->ctime_ns);- if (zip_entry->flg & ATIME_IS_SET)- archive_entry_set_atime(entry, zip_entry->atime,- zip_entry->atime_ns);- if (zip_entry->ssIndex != (uint32_t)-1) {- zip->entry_bytes_remaining =- zip->si.ss.unpackSizes[zip_entry->ssIndex];- archive_entry_set_size(entry, zip->entry_bytes_remaining);- } else {- zip->entry_bytes_remaining = 0;- archive_entry_set_size(entry, 0);- }-- /* If there's no body, force read_data() to return EOF immediately. */- if (zip->entry_bytes_remaining < 1)- zip->end_of_entry = 1;-- if ((zip_entry->mode & AE_IFMT) == AE_IFLNK) {- unsigned char *symname = NULL;- size_t symsize = 0;-- /*- * Symbolic-name is recorded as its contents. We have to- * read the contents at this time.- */- while (zip->entry_bytes_remaining > 0) {- const void *buff;- unsigned char *mem;- size_t size;- int64_t offset;-- r = archive_read_format_7zip_read_data(a, &buff,- &size, &offset);- if (r < ARCHIVE_WARN) {- free(symname);- return (r);- }- mem = realloc(symname, symsize + size + 1);- if (mem == NULL) {- free(symname);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Symname");- return (ARCHIVE_FATAL);- }- symname = mem;- memcpy(symname+symsize, buff, size);- symsize += size;- }- if (symsize == 0) {- /* If there is no symname, handle it as a regular- * file. */- zip_entry->mode &= ~AE_IFMT;- zip_entry->mode |= AE_IFREG;- archive_entry_set_mode(entry, zip_entry->mode);- } else {- symname[symsize] = '\0';- archive_entry_copy_symlink(entry,- (const char *)symname);- }- free(symname);- archive_entry_set_size(entry, 0);- }-- /* Set up a more descriptive format name. */- snprintf(zip->format_name, sizeof(zip->format_name), "7-Zip");- a->archive.archive_format_name = zip->format_name;-- return (ret);-}--static int-archive_read_format_7zip_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- struct _7zip *zip;- ssize_t bytes;- int ret = ARCHIVE_OK;-- zip = (struct _7zip *)(a->format->data);-- if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {- zip->has_encrypted_entries = 0;- }-- if (zip->pack_stream_bytes_unconsumed)- read_consume(a);-- *offset = zip->entry_offset;- *size = 0;- *buff = NULL;- /*- * If we hit end-of-entry last time, clean up and return- * ARCHIVE_EOF this time.- */- if (zip->end_of_entry)- return (ARCHIVE_EOF);-- const uint64_t max_read_size = 16 * 1024 * 1024; // Don't try to read more than 16 MB at a time- size_t bytes_to_read = max_read_size;- if ((uint64_t)bytes_to_read > zip->entry_bytes_remaining) {- bytes_to_read = zip->entry_bytes_remaining;- }- bytes = read_stream(a, buff, bytes_to_read, 0);- if (bytes < 0)- return ((int)bytes);- if (bytes == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated 7-Zip file body");- return (ARCHIVE_FATAL);- }- zip->entry_bytes_remaining -= bytes;- if (zip->entry_bytes_remaining == 0)- zip->end_of_entry = 1;-- /* Update checksum */- if ((zip->entry->flg & CRC32_IS_SET) && bytes)- zip->entry_crc32 = crc32(zip->entry_crc32, *buff,- (unsigned)bytes);-- /* If we hit the end, swallow any end-of-data marker. */- if (zip->end_of_entry) {- /* Check computed CRC against file contents. */- if ((zip->entry->flg & CRC32_IS_SET) &&- zip->si.ss.digests[zip->entry->ssIndex] !=- zip->entry_crc32) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "7-Zip bad CRC: 0x%lx should be 0x%lx",- (unsigned long)zip->entry_crc32,- (unsigned long)zip->si.ss.digests[- zip->entry->ssIndex]);- ret = ARCHIVE_WARN;- }- }-- *size = bytes;- *offset = zip->entry_offset;- zip->entry_offset += bytes;-- return (ret);-}--static int-archive_read_format_7zip_read_data_skip(struct archive_read *a)-{- struct _7zip *zip;- int64_t bytes_skipped;-- zip = (struct _7zip *)(a->format->data);-- if (zip->pack_stream_bytes_unconsumed)- read_consume(a);-- /* If we've already read to end of data, we're done. */- if (zip->end_of_entry)- return (ARCHIVE_OK);-- /*- * If the length is at the beginning, we can skip the- * compressed data much more quickly.- */- bytes_skipped = skip_stream(a, (size_t)zip->entry_bytes_remaining);- if (bytes_skipped < 0)- return (ARCHIVE_FATAL);- zip->entry_bytes_remaining = 0;-- /* This entry is finished and done. */- zip->end_of_entry = 1;- return (ARCHIVE_OK);-}--static int-archive_read_format_7zip_cleanup(struct archive_read *a)-{- struct _7zip *zip;-- zip = (struct _7zip *)(a->format->data);- free_StreamsInfo(&(zip->si));- free(zip->entries);- free(zip->entry_names);- free_decompression(a, zip);- free(zip->uncompressed_buffer);- free(zip->sub_stream_buff[0]);- free(zip->sub_stream_buff[1]);- free(zip->sub_stream_buff[2]);- free(zip->tmp_stream_buff);- free(zip);- (a->format->data) = NULL;- return (ARCHIVE_OK);-}--static void-read_consume(struct archive_read *a)-{- struct _7zip *zip = (struct _7zip *)a->format->data;-- if (zip->pack_stream_bytes_unconsumed) {- __archive_read_consume(a, zip->pack_stream_bytes_unconsumed);- zip->stream_offset += zip->pack_stream_bytes_unconsumed;- zip->pack_stream_bytes_unconsumed = 0;- }-}--#ifdef HAVE_LZMA_H--/*- * Set an error code and choose an error message for liblzma.- */-static void-set_error(struct archive_read *a, int ret)-{-- switch (ret) {- case LZMA_STREAM_END: /* Found end of stream. */- case LZMA_OK: /* Decompressor made some progress. */- break;- case LZMA_MEM_ERROR:- archive_set_error(&a->archive, ENOMEM,- "Lzma library error: Cannot allocate memory");- break;- case LZMA_MEMLIMIT_ERROR:- archive_set_error(&a->archive, ENOMEM,- "Lzma library error: Out of memory");- break;- case LZMA_FORMAT_ERROR:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Lzma library error: format not recognized");- break;- case LZMA_OPTIONS_ERROR:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Lzma library error: Invalid options");- break;- case LZMA_DATA_ERROR:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Lzma library error: Corrupted input data");- break;- case LZMA_BUF_ERROR:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Lzma library error: No progress is possible");- break;- default:- /* Return an error. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Lzma decompression failed: Unknown error");- break;- }-}--#endif--static unsigned long-decode_codec_id(const unsigned char *codecId, size_t id_size)-{- unsigned i;- unsigned long id = 0;-- for (i = 0; i < id_size; i++) {- id <<= 8;- id += codecId[i];- }- return (id);-}--static Byte-ppmd_read(void *p)-{- struct archive_read *a = ((IByteIn*)p)->a;- struct _7zip *zip = (struct _7zip *)(a->format->data);- Byte b;-- if (zip->ppstream.avail_in <= 0) {- /*- * Ppmd7_DecodeSymbol might require reading multiple bytes- * and we are on boundary;- * last resort to read using __archive_read_ahead.- */- ssize_t bytes_avail = 0;- const uint8_t* data = __archive_read_ahead(a,- zip->ppstream.stream_in+1, &bytes_avail);- if(bytes_avail < zip->ppstream.stream_in+1) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated 7z file data");- zip->ppstream.overconsumed = 1;- return (0);- }- zip->ppstream.next_in++;- b = data[zip->ppstream.stream_in];- } else {- b = *zip->ppstream.next_in++;- }- zip->ppstream.avail_in--;- zip->ppstream.total_in++;- zip->ppstream.stream_in++;- return (b);-}--static int-init_decompression(struct archive_read *a, struct _7zip *zip,- const struct _7z_coder *coder1, const struct _7z_coder *coder2)-{- int r;-- zip->codec = coder1->codec;- zip->codec2 = -1;-- switch (zip->codec) {- case _7Z_COPY:- case _7Z_BZ2:- case _7Z_DEFLATE:- case _7Z_ZSTD:- case _7Z_PPMD:- if (coder2 != NULL) {- if (coder2->codec != _7Z_X86 &&- coder2->codec != _7Z_X86_BCJ2 &&- coder2->codec != _7Z_ARM &&- coder2->codec != _7Z_ARM64) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Unsupported filter %lx for %lx",- coder2->codec, coder1->codec);- return (ARCHIVE_FAILED);- }- zip->codec2 = coder2->codec;- zip->bcj_state = 0;- if (coder2->codec == _7Z_X86)- x86_Init(zip);- else if (coder2->codec == _7Z_ARM)- arm_Init(zip);- }- break;- default:- break;- }-- switch (zip->codec) {- case _7Z_COPY:- break;-- case _7Z_LZMA: case _7Z_LZMA2:-#ifdef HAVE_LZMA_H-#if LZMA_VERSION_MAJOR >= 5-/* Effectively disable the limiter. */-#define LZMA_MEMLIMIT UINT64_MAX-#else-/* NOTE: This needs to check memory size which running system has. */-#define LZMA_MEMLIMIT (1U << 30)-#endif- {- lzma_options_delta delta_opt;- lzma_filter filters[LZMA_FILTERS_MAX], *ff;- int fi = 0;-- if (zip->lzstream_valid) {- lzma_end(&(zip->lzstream));- zip->lzstream_valid = 0;- }-- /*- * NOTE: liblzma incompletely handle the BCJ+LZMA compressed- * data made by 7-Zip because 7-Zip does not add End-Of-- * Payload Marker(EOPM) at the end of LZMA compressed data,- * and so liblzma cannot know the end of the compressed data- * without EOPM. So consequently liblzma will not return last- * three or four bytes of uncompressed data because- * LZMA_FILTER_X86 filter does not handle input data if its- * data size is less than five bytes. If liblzma detect EOPM- * or know the uncompressed data size, liblzma will flush out- * the remaining that three or four bytes of uncompressed- * data. That is why we have to use our converting program- * for BCJ+LZMA. If we were able to tell the uncompressed- * size to liblzma when using lzma_raw_decoder() liblzma- * could correctly deal with BCJ+LZMA. But unfortunately- * there is no way to do that.- * Discussion about this can be found at XZ Utils forum.- */- if (coder2 != NULL) {- zip->codec2 = coder2->codec;-- filters[fi].options = NULL;- switch (zip->codec2) {- case _7Z_X86:- if (zip->codec == _7Z_LZMA2) {- filters[fi].id = LZMA_FILTER_X86;- fi++;- } else- /* Use our filter. */- x86_Init(zip);- break;- case _7Z_X86_BCJ2:- /* Use our filter. */- zip->bcj_state = 0;- break;- case _7Z_DELTA:- if (coder2->propertiesSize != 1) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Invalid Delta parameter");- return (ARCHIVE_FAILED);- }- filters[fi].id = LZMA_FILTER_DELTA;- memset(&delta_opt, 0, sizeof(delta_opt));- delta_opt.type = LZMA_DELTA_TYPE_BYTE;- delta_opt.dist =- (uint32_t)coder2->properties[0] + 1;- filters[fi].options = &delta_opt;- fi++;- break;- /* Following filters have not been tested yet. */- case _7Z_POWERPC:- filters[fi].id = LZMA_FILTER_POWERPC;- fi++;- break;- case _7Z_IA64:- filters[fi].id = LZMA_FILTER_IA64;- fi++;- break;- case _7Z_ARM:- filters[fi].id = LZMA_FILTER_ARM;- fi++;- break;- case _7Z_ARMTHUMB:- filters[fi].id = LZMA_FILTER_ARMTHUMB;- fi++;- break;-#ifdef LZMA_FILTER_ARM64- case _7Z_ARM64:- filters[fi].id = LZMA_FILTER_ARM64;- fi++;- break;-#endif- case _7Z_SPARC:- filters[fi].id = LZMA_FILTER_SPARC;- fi++;- break;- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Unexpected codec ID: %lX", zip->codec2);- return (ARCHIVE_FAILED);- }- }-- if (zip->codec == _7Z_LZMA2)- filters[fi].id = LZMA_FILTER_LZMA2;- else- filters[fi].id = LZMA_FILTER_LZMA1;- filters[fi].options = NULL;- ff = &filters[fi];- r = lzma_properties_decode(&filters[fi], NULL,- coder1->properties, (size_t)coder1->propertiesSize);- if (r != LZMA_OK) {- set_error(a, r);- return (ARCHIVE_FAILED);- }- fi++;-- filters[fi].id = LZMA_VLI_UNKNOWN;- filters[fi].options = NULL;- r = lzma_raw_decoder(&(zip->lzstream), filters);- free(ff->options);- if (r != LZMA_OK) {- set_error(a, r);- return (ARCHIVE_FAILED);- }- zip->lzstream_valid = 1;- zip->lzstream.total_in = 0;- zip->lzstream.total_out = 0;- break;- }-#else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "LZMA codec is unsupported");- return (ARCHIVE_FAILED);-#endif- case _7Z_BZ2:-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- if (zip->bzstream_valid) {- BZ2_bzDecompressEnd(&(zip->bzstream));- zip->bzstream_valid = 0;- }- r = BZ2_bzDecompressInit(&(zip->bzstream), 0, 0);- if (r == BZ_MEM_ERROR)- r = BZ2_bzDecompressInit(&(zip->bzstream), 0, 1);- if (r != BZ_OK) {- int err = ARCHIVE_ERRNO_MISC;- const char *detail = NULL;- switch (r) {- case BZ_PARAM_ERROR:- detail = "invalid setup parameter";- break;- case BZ_MEM_ERROR:- err = ENOMEM;- detail = "out of memory";- break;- case BZ_CONFIG_ERROR:- detail = "mis-compiled library";- break;- }- archive_set_error(&a->archive, err,- "Internal error initializing decompressor: %s",- detail != NULL ? detail : "??");- zip->bzstream_valid = 0;- return (ARCHIVE_FAILED);- }- zip->bzstream_valid = 1;- zip->bzstream.total_in_lo32 = 0;- zip->bzstream.total_in_hi32 = 0;- zip->bzstream.total_out_lo32 = 0;- zip->bzstream.total_out_hi32 = 0;- break;-#else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "BZ2 codec is unsupported");- return (ARCHIVE_FAILED);-#endif- case _7Z_ZSTD:- {-#if defined(HAVE_ZSTD_H)- if (zip->zstdstream_valid) {- ZSTD_freeDStream(zip->zstd_dstream);- zip->zstdstream_valid = 0;- }- zip->zstd_dstream = ZSTD_createDStream();- zip->zstdstream_valid = 1;- break;-#else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "ZSTD codec is unsupported");- return (ARCHIVE_FAILED);-#endif- }- case _7Z_DEFLATE:-#ifdef HAVE_ZLIB_H- if (zip->stream_valid)- r = inflateReset(&(zip->stream));- else- r = inflateInit2(&(zip->stream),- -15 /* Don't check for zlib header */);- if (r != Z_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Couldn't initialize zlib stream.");- return (ARCHIVE_FAILED);- }- zip->stream_valid = 1;- zip->stream.total_in = 0;- zip->stream.total_out = 0;- break;-#else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "DEFLATE codec is unsupported");- return (ARCHIVE_FAILED);-#endif- case _7Z_PPMD:- {- unsigned order;- uint32_t msize;-- if (zip->ppmd7_valid) {- __archive_ppmd7_functions.Ppmd7_Free(- &zip->ppmd7_context);- zip->ppmd7_valid = 0;- }-- if (coder1->propertiesSize < 5) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Malformed PPMd parameter");- return (ARCHIVE_FAILED);- }- order = coder1->properties[0];- msize = archive_le32dec(&(coder1->properties[1]));- if (order < PPMD7_MIN_ORDER || order > PPMD7_MAX_ORDER ||- msize < PPMD7_MIN_MEM_SIZE || msize > PPMD7_MAX_MEM_SIZE) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Malformed PPMd parameter");- return (ARCHIVE_FAILED);- }- __archive_ppmd7_functions.Ppmd7_Construct(&zip->ppmd7_context);- r = __archive_ppmd7_functions.Ppmd7_Alloc(- &zip->ppmd7_context, msize);- if (r == 0) {- archive_set_error(&a->archive, ENOMEM,- "Coludn't allocate memory for PPMd");- return (ARCHIVE_FATAL);- }- __archive_ppmd7_functions.Ppmd7_Init(- &zip->ppmd7_context, order);- __archive_ppmd7_functions.Ppmd7z_RangeDec_CreateVTable(- &zip->range_dec);- zip->ppmd7_valid = 1;- zip->ppmd7_stat = 0;- zip->ppstream.overconsumed = 0;- zip->ppstream.total_in = 0;- zip->ppstream.total_out = 0;- break;- }- case _7Z_X86:- case _7Z_X86_BCJ2:- case _7Z_POWERPC:- case _7Z_IA64:- case _7Z_ARM:- case _7Z_ARMTHUMB:- case _7Z_SPARC:- case _7Z_DELTA:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Unexpected codec ID: %lX", zip->codec);- return (ARCHIVE_FAILED);- case _7Z_CRYPTO_MAIN_ZIP:- case _7Z_CRYPTO_RAR_29:- case _7Z_CRYPTO_AES_256_SHA_256:- if (a->entry) {- archive_entry_set_is_metadata_encrypted(a->entry, 1);- archive_entry_set_is_data_encrypted(a->entry, 1);- zip->has_encrypted_entries = 1;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Crypto codec not supported yet (ID: 0x%lX)", zip->codec);- return (ARCHIVE_FAILED);- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Unknown codec ID: %lX", zip->codec);- return (ARCHIVE_FAILED);- }-- return (ARCHIVE_OK);-}--static int-decompress(struct archive_read *a, struct _7zip *zip,- void *buff, size_t *outbytes, const void *b, size_t *used)-{- const uint8_t *t_next_in;- uint8_t *t_next_out;- size_t o_avail_in, o_avail_out;- size_t t_avail_in, t_avail_out;- uint8_t *bcj2_next_out;- size_t bcj2_avail_out;- int r, ret = ARCHIVE_OK;-- t_avail_in = o_avail_in = *used;- t_avail_out = o_avail_out = *outbytes;- t_next_in = b;- t_next_out = buff;-- if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) {- int i;-- /* Do not copy out the BCJ remaining bytes when the output- * buffer size is less than five bytes. */- if (o_avail_in != 0 && t_avail_out < 5 && zip->odd_bcj_size) {- *used = 0;- *outbytes = 0;- return (ret);- }- for (i = 0; zip->odd_bcj_size > 0 && t_avail_out; i++) {- *t_next_out++ = zip->odd_bcj[i];- t_avail_out--;- zip->odd_bcj_size--;- }- if (o_avail_in == 0 || t_avail_out == 0) {- *used = o_avail_in - t_avail_in;- *outbytes = o_avail_out - t_avail_out;- if (o_avail_in == 0)- ret = ARCHIVE_EOF;- return (ret);- }- }-- bcj2_next_out = t_next_out;- bcj2_avail_out = t_avail_out;- if (zip->codec2 == _7Z_X86_BCJ2) {- /*- * Decord a remaining decompressed main stream for BCJ2.- */- if (zip->tmp_stream_bytes_remaining) {- ssize_t bytes;- size_t remaining = zip->tmp_stream_bytes_remaining;- bytes = Bcj2_Decode(zip, t_next_out, t_avail_out);- if (bytes < 0) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "BCJ2 conversion Failed");- return (ARCHIVE_FAILED);- }- zip->main_stream_bytes_remaining -=- remaining - zip->tmp_stream_bytes_remaining;- t_avail_out -= bytes;- if (o_avail_in == 0 || t_avail_out == 0) {- *used = 0;- *outbytes = o_avail_out - t_avail_out;- if (o_avail_in == 0 &&- zip->tmp_stream_bytes_remaining)- ret = ARCHIVE_EOF;- return (ret);- }- t_next_out += bytes;- bcj2_next_out = t_next_out;- bcj2_avail_out = t_avail_out;- }- t_next_out = zip->tmp_stream_buff;- t_avail_out = zip->tmp_stream_buff_size;- }-- switch (zip->codec) {- case _7Z_COPY:- {- size_t bytes =- (t_avail_in > t_avail_out)?t_avail_out:t_avail_in;-- memcpy(t_next_out, t_next_in, bytes);- t_avail_in -= bytes;- t_avail_out -= bytes;- if (o_avail_in == 0)- ret = ARCHIVE_EOF;- break;- }-#ifdef HAVE_LZMA_H- case _7Z_LZMA: case _7Z_LZMA2:- zip->lzstream.next_in = t_next_in;- zip->lzstream.avail_in = t_avail_in;- zip->lzstream.next_out = t_next_out;- zip->lzstream.avail_out = t_avail_out;-- r = lzma_code(&(zip->lzstream), LZMA_RUN);- switch (r) {- case LZMA_STREAM_END: /* Found end of stream. */- lzma_end(&(zip->lzstream));- zip->lzstream_valid = 0;- ret = ARCHIVE_EOF;- break;- case LZMA_OK: /* Decompressor made some progress. */- break;- default:- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Decompression failed(%d)",- r);- return (ARCHIVE_FAILED);- }- t_avail_in = zip->lzstream.avail_in;- t_avail_out = zip->lzstream.avail_out;- break;-#endif-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- case _7Z_BZ2:- zip->bzstream.next_in = (char *)(uintptr_t)t_next_in;- zip->bzstream.avail_in = (uint32_t)t_avail_in;- zip->bzstream.next_out = (char *)(uintptr_t)t_next_out;- zip->bzstream.avail_out = (uint32_t)t_avail_out;- r = BZ2_bzDecompress(&(zip->bzstream));- switch (r) {- case BZ_STREAM_END: /* Found end of stream. */- switch (BZ2_bzDecompressEnd(&(zip->bzstream))) {- case BZ_OK:- break;- default:- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Failed to clean up decompressor");- return (ARCHIVE_FAILED);- }- zip->bzstream_valid = 0;- ret = ARCHIVE_EOF;- break;- case BZ_OK: /* Decompressor made some progress. */- break;- default:- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "bzip decompression failed");- return (ARCHIVE_FAILED);- }- t_avail_in = zip->bzstream.avail_in;- t_avail_out = zip->bzstream.avail_out;- break;-#endif-#ifdef HAVE_ZLIB_H- case _7Z_DEFLATE:- zip->stream.next_in = (Bytef *)(uintptr_t)t_next_in;- zip->stream.avail_in = (uInt)t_avail_in;- zip->stream.next_out = t_next_out;- zip->stream.avail_out = (uInt)t_avail_out;- r = inflate(&(zip->stream), 0);- switch (r) {- case Z_STREAM_END: /* Found end of stream. */- ret = ARCHIVE_EOF;- break;- case Z_OK: /* Decompressor made some progress.*/- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "File decompression failed (%d)", r);- return (ARCHIVE_FAILED);- }- t_avail_in = zip->stream.avail_in;- t_avail_out = zip->stream.avail_out;- break;-#endif-#ifdef HAVE_ZSTD_H- case _7Z_ZSTD:- {- ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 }; // src, size, pos- ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 }; // dst, size, pos-- size_t const zret = ZSTD_decompressStream(zip->zstd_dstream, &output, &input);- if (ZSTD_isError(zret)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Zstd decompression failed: %s", ZSTD_getErrorName(zret));- return ARCHIVE_FAILED;- }- t_avail_in -= input.pos;- t_avail_out -= output.pos;- break;- }-#endif- case _7Z_PPMD:- {- uint64_t flush_bytes;-- if (!zip->ppmd7_valid || zip->ppmd7_stat < 0 ||- t_avail_out <= 0) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Decompression internal error");- return (ARCHIVE_FAILED);- }- zip->ppstream.next_in = t_next_in;- zip->ppstream.avail_in = t_avail_in;- zip->ppstream.stream_in = 0;- zip->ppstream.next_out = t_next_out;- zip->ppstream.avail_out = t_avail_out;- if (zip->ppmd7_stat == 0) {- zip->bytein.a = a;- zip->bytein.Read = &ppmd_read;- zip->range_dec.Stream = &zip->bytein;- r = __archive_ppmd7_functions.Ppmd7z_RangeDec_Init(- &(zip->range_dec));- if (r == 0) {- zip->ppmd7_stat = -1;- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to initialize PPMd range decoder");- return (ARCHIVE_FAILED);- }- if (zip->ppstream.overconsumed) {- zip->ppmd7_stat = -1;- return (ARCHIVE_FAILED);- }- zip->ppmd7_stat = 1;- }-- if (t_avail_in == 0)- /* XXX Flush out remaining decoded data XXX */- flush_bytes = zip->folder_outbytes_remaining;- else- flush_bytes = 0;-- do {- int sym;-- sym = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(- &(zip->ppmd7_context), &(zip->range_dec.p));- if (sym < 0) {- zip->ppmd7_stat = -1;- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Failed to decode PPMd");- return (ARCHIVE_FAILED);- }- if (zip->ppstream.overconsumed) {- zip->ppmd7_stat = -1;- return (ARCHIVE_FAILED);- }- *zip->ppstream.next_out++ = (unsigned char)sym;- zip->ppstream.avail_out--;- zip->ppstream.total_out++;- if (flush_bytes)- flush_bytes--;- } while (zip->ppstream.avail_out &&- (zip->ppstream.avail_in || flush_bytes));-- t_avail_in = (size_t)zip->ppstream.avail_in;- t_avail_out = (size_t)zip->ppstream.avail_out;- break;- }- default:- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,- "Decompression internal error");- return (ARCHIVE_FAILED);- }- if (ret != ARCHIVE_OK && ret != ARCHIVE_EOF)- return (ret);-- *used = o_avail_in - t_avail_in;- *outbytes = o_avail_out - t_avail_out;-- /*- * Decord BCJ.- */- if (zip->codec != _7Z_LZMA2) {- if (zip->codec2 == _7Z_X86) {- size_t l = x86_Convert(zip, buff, *outbytes);-- zip->odd_bcj_size = *outbytes - l;- if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 &&- o_avail_in && ret != ARCHIVE_EOF) {- memcpy(zip->odd_bcj, ((unsigned char *)buff) + l,- zip->odd_bcj_size);- *outbytes = l;- } else- zip->odd_bcj_size = 0;- } else if (zip->codec2 == _7Z_ARM) {- *outbytes = arm_Convert(zip, buff, *outbytes);- } else if (zip->codec2 == _7Z_ARM64) {- *outbytes = arm64_Convert(zip, buff, *outbytes);- }- }-- /*- * Decord BCJ2 with a decompressed main stream.- */- if (zip->codec2 == _7Z_X86_BCJ2) {- ssize_t bytes;-- zip->tmp_stream_bytes_avail =- zip->tmp_stream_buff_size - t_avail_out;- if (zip->tmp_stream_bytes_avail >- zip->main_stream_bytes_remaining)- zip->tmp_stream_bytes_avail =- zip->main_stream_bytes_remaining;- zip->tmp_stream_bytes_remaining = zip->tmp_stream_bytes_avail;- bytes = Bcj2_Decode(zip, bcj2_next_out, bcj2_avail_out);- if (bytes < 0) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC, "BCJ2 conversion Failed");- return (ARCHIVE_FAILED);- }- zip->main_stream_bytes_remaining -=- zip->tmp_stream_bytes_avail- - zip->tmp_stream_bytes_remaining;- bcj2_avail_out -= bytes;- *outbytes = o_avail_out - bcj2_avail_out;- }-- return (ret);-}--static int-free_decompression(struct archive_read *a, struct _7zip *zip)-{- int r = ARCHIVE_OK;--#if !defined(HAVE_ZLIB_H) &&\- !(defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR))- (void)a;/* UNUSED */-#endif-#ifdef HAVE_LZMA_H- if (zip->lzstream_valid)- lzma_end(&(zip->lzstream));-#endif-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- if (zip->bzstream_valid) {- if (BZ2_bzDecompressEnd(&(zip->bzstream)) != BZ_OK) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to clean up bzip2 decompressor");- r = ARCHIVE_FATAL;- }- zip->bzstream_valid = 0;- }-#endif-#ifdef HAVE_ZLIB_H- if (zip->stream_valid) {- if (inflateEnd(&(zip->stream)) != Z_OK) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to clean up zlib decompressor");- r = ARCHIVE_FATAL;- }- zip->stream_valid = 0;- }-#endif- if (zip->ppmd7_valid) {- __archive_ppmd7_functions.Ppmd7_Free(- &zip->ppmd7_context);- zip->ppmd7_valid = 0;- }- return (r);-}--static int-parse_7zip_uint64(struct archive_read *a, uint64_t *val)-{- const unsigned char *p;- unsigned char avail, mask;- int i;-- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- avail = *p;- mask = 0x80;- *val = 0;- for (i = 0; i < 8; i++) {- if (avail & mask) {- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- *val |= ((uint64_t)*p) << (8 * i);- mask >>= 1;- continue;- }- *val += ((uint64_t)(avail & (mask -1))) << (8 * i);- break;- }- return (0);-}--static int-read_Bools(struct archive_read *a, unsigned char *data, size_t num)-{- const unsigned char *p;- unsigned i, mask = 0, avail = 0;-- for (i = 0; i < num; i++) {- if (mask == 0) {- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- avail = *p;- mask = 0x80;- }- data[i] = (avail & mask)?1:0;- mask >>= 1;- }- return (0);-}--static void-free_Digest(struct _7z_digests *d)-{- free(d->defineds);- free(d->digests);-}--static int-read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num)-{- const unsigned char *p;- unsigned i;-- if (num == 0)- return (-1);- memset(d, 0, sizeof(*d));-- d->defineds = malloc(num);- if (d->defineds == NULL)- return (-1);- /*- * Read Bools.- */- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- if (*p == 0) {- if (read_Bools(a, d->defineds, num) < 0)- return (-1);- } else- /* All are defined */- memset(d->defineds, 1, num);-- d->digests = calloc(num, sizeof(*d->digests));- if (d->digests == NULL)- return (-1);- for (i = 0; i < num; i++) {- if (d->defineds[i]) {- if ((p = header_bytes(a, 4)) == NULL)- return (-1);- d->digests[i] = archive_le32dec(p);- }- }-- return (0);-}--static void-free_PackInfo(struct _7z_pack_info *pi)-{- free(pi->sizes);- free(pi->positions);- free_Digest(&(pi->digest));-}--static int-read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)-{- const unsigned char *p;- unsigned i;-- memset(pi, 0, sizeof(*pi));-- /*- * Read PackPos.- */- if (parse_7zip_uint64(a, &(pi->pos)) < 0)- return (-1);-- /*- * Read NumPackStreams.- */- if (parse_7zip_uint64(a, &(pi->numPackStreams)) < 0)- return (-1);- if (pi->numPackStreams == 0)- return (-1);- if (UMAX_ENTRY < pi->numPackStreams)- return (-1);-- /*- * Read PackSizes[num]- */- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- if (*p == kEnd)- /* PackSizes[num] are not present. */- return (0);- if (*p != kSize)- return (-1);- pi->sizes = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));- pi->positions = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));- if (pi->sizes == NULL || pi->positions == NULL)- return (-1);-- for (i = 0; i < pi->numPackStreams; i++) {- if (parse_7zip_uint64(a, &(pi->sizes[i])) < 0)- return (-1);- }-- /*- * Read PackStreamDigests[num]- */- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- if (*p == kEnd) {- /* PackStreamDigests[num] are not present. */- pi->digest.defineds =- calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));- pi->digest.digests =- calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests));- if (pi->digest.defineds == NULL || pi->digest.digests == NULL)- return (-1);- return (0);- }-- if (*p != kCRC)- return (-1);-- if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)- return (-1);-- /*- * Must be marked by kEnd.- */- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- if (*p != kEnd)- return (-1);- return (0);-}--static void-free_Folder(struct _7z_folder *f)-{- unsigned i;-- if (f->coders) {- for (i = 0; i< f->numCoders; i++) {- free(f->coders[i].properties);- }- free(f->coders);- }- free(f->bindPairs);- free(f->packedStreams);- free(f->unPackSize);-}--static int-read_Folder(struct archive_read *a, struct _7z_folder *f)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- const unsigned char *p;- uint64_t numInStreamsTotal = 0;- uint64_t numOutStreamsTotal = 0;- unsigned i;-- memset(f, 0, sizeof(*f));-- /*- * Read NumCoders.- */- if (parse_7zip_uint64(a, &(f->numCoders)) < 0)- return (-1);- if (f->numCoders > 4)- /* Too many coders. */- return (-1);-- f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders));- if (f->coders == NULL)- return (-1);- for (i = 0; i< f->numCoders; i++) {- size_t codec_size;- int simple, attr;-- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- /*- * 0:3 CodecIdSize- * 4: 0 - IsSimple- * 1 - Is not Simple- * 5: 0 - No Attributes- * 1 - There are Attributes;- * 7: Must be zero.- */- codec_size = *p & 0xf;- simple = (*p & 0x10)?0:1;- attr = *p & 0x20;- if (*p & 0x80)- return (-1);/* Not supported. */-- /*- * Read Decompression Method IDs.- */- if ((p = header_bytes(a, codec_size)) == NULL)- return (-1);-- f->coders[i].codec = decode_codec_id(p, codec_size);-- if (simple) {- f->coders[i].numInStreams = 1;- f->coders[i].numOutStreams = 1;- } else {- if (parse_7zip_uint64(- a, &(f->coders[i].numInStreams)) < 0)- return (-1);- if (UMAX_ENTRY < f->coders[i].numInStreams)- return (-1);- if (parse_7zip_uint64(- a, &(f->coders[i].numOutStreams)) < 0)- return (-1);- if (UMAX_ENTRY < f->coders[i].numOutStreams)- return (-1);- }-- if (attr) {- if (parse_7zip_uint64(- a, &(f->coders[i].propertiesSize)) < 0)- return (-1);- if ((p = header_bytes(- a, (size_t)f->coders[i].propertiesSize)) == NULL)- return (-1);- f->coders[i].properties =- malloc((size_t)f->coders[i].propertiesSize);- if (f->coders[i].properties == NULL)- return (-1);- memcpy(f->coders[i].properties, p,- (size_t)f->coders[i].propertiesSize);- }-- numInStreamsTotal += f->coders[i].numInStreams;- numOutStreamsTotal += f->coders[i].numOutStreams;- }-- if (numOutStreamsTotal == 0 ||- numInStreamsTotal < numOutStreamsTotal-1)- return (-1);-- f->numBindPairs = numOutStreamsTotal - 1;- if (zip->header_bytes_remaining < f->numBindPairs)- return (-1);- if (f->numBindPairs > 0) {- f->bindPairs =- calloc((size_t)f->numBindPairs, sizeof(*f->bindPairs));- if (f->bindPairs == NULL)- return (-1);- } else- f->bindPairs = NULL;- for (i = 0; i < f->numBindPairs; i++) {- if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)- return (-1);- if (UMAX_ENTRY < f->bindPairs[i].inIndex)- return (-1);- if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)- return (-1);- if (UMAX_ENTRY < f->bindPairs[i].outIndex)- return (-1);- }-- f->numPackedStreams = numInStreamsTotal - f->numBindPairs;- f->packedStreams =- calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams));- if (f->packedStreams == NULL)- return (-1);- if (f->numPackedStreams == 1) {- for (i = 0; i < numInStreamsTotal; i++) {- unsigned j;- for (j = 0; j < f->numBindPairs; j++) {- if (f->bindPairs[j].inIndex == i)- break;- }- if (j == f->numBindPairs)- break;- }- if (i == numInStreamsTotal)- return (-1);- f->packedStreams[0] = i;- } else {- for (i = 0; i < f->numPackedStreams; i++) {- if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)- return (-1);- if (UMAX_ENTRY < f->packedStreams[i])- return (-1);- }- }- f->numInStreams = numInStreamsTotal;- f->numOutStreams = numOutStreamsTotal;-- return (0);-}--static void-free_CodersInfo(struct _7z_coders_info *ci)-{- unsigned i;-- if (ci->folders) {- for (i = 0; i < ci->numFolders; i++)- free_Folder(&(ci->folders[i]));- free(ci->folders);- }-}--static int-read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)-{- const unsigned char *p;- struct _7z_digests digest;- unsigned i;-- memset(ci, 0, sizeof(*ci));- memset(&digest, 0, sizeof(digest));-- if ((p = header_bytes(a, 1)) == NULL)- goto failed;- if (*p != kFolder)- goto failed;-- /*- * Read NumFolders.- */- if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)- goto failed;- if (UMAX_ENTRY < ci->numFolders)- return (-1);-- /*- * Read External.- */- if ((p = header_bytes(a, 1)) == NULL)- goto failed;- switch (*p) {- case 0:- ci->folders =- calloc((size_t)ci->numFolders, sizeof(*ci->folders));- if (ci->folders == NULL)- return (-1);- for (i = 0; i < ci->numFolders; i++) {- if (read_Folder(a, &(ci->folders[i])) < 0)- goto failed;- }- break;- case 1:- if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)- return (-1);- if (UMAX_ENTRY < ci->dataStreamIndex)- return (-1);- if (ci->numFolders > 0) {- archive_set_error(&a->archive, -1,- "Malformed 7-Zip archive");- goto failed;- }- break;- default:- archive_set_error(&a->archive, -1,- "Malformed 7-Zip archive");- goto failed;- }-- if ((p = header_bytes(a, 1)) == NULL)- goto failed;- if (*p != kCodersUnPackSize)- goto failed;-- for (i = 0; i < ci->numFolders; i++) {- struct _7z_folder *folder = &(ci->folders[i]);- unsigned j;-- folder->unPackSize =- calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));- if (folder->unPackSize == NULL)- goto failed;- for (j = 0; j < folder->numOutStreams; j++) {- if (parse_7zip_uint64(a, &(folder->unPackSize[j])) < 0)- goto failed;- }- }-- /*- * Read CRCs.- */- if ((p = header_bytes(a, 1)) == NULL)- goto failed;- if (*p == kEnd)- return (0);- if (*p != kCRC)- goto failed;- if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)- goto failed;- for (i = 0; i < ci->numFolders; i++) {- ci->folders[i].digest_defined = digest.defineds[i];- ci->folders[i].digest = digest.digests[i];- }-- /*- * Must be kEnd.- */- if ((p = header_bytes(a, 1)) == NULL)- goto failed;- if (*p != kEnd)- goto failed;- free_Digest(&digest);- return (0);-failed:- free_Digest(&digest);- return (-1);-}--static uint64_t-folder_uncompressed_size(struct _7z_folder *f)-{- int n = (int)f->numOutStreams;- unsigned pairs = (unsigned)f->numBindPairs;-- while (--n >= 0) {- unsigned i;- for (i = 0; i < pairs; i++) {- if (f->bindPairs[i].outIndex == (uint64_t)n)- break;- }- if (i >= pairs)- return (f->unPackSize[n]);- }- return (0);-}--static void-free_SubStreamsInfo(struct _7z_substream_info *ss)-{- free(ss->unpackSizes);- free(ss->digestsDefined);- free(ss->digests);-}--static int-read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,- struct _7z_folder *f, size_t numFolders)-{- const unsigned char *p;- uint64_t *usizes;- size_t unpack_streams;- int type;- unsigned i;- uint32_t numDigests;-- memset(ss, 0, sizeof(*ss));-- for (i = 0; i < numFolders; i++)- f[i].numUnpackStreams = 1;-- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- type = *p;-- if (type == kNumUnPackStream) {- unpack_streams = 0;- for (i = 0; i < numFolders; i++) {- if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)- return (-1);- if (UMAX_ENTRY < f[i].numUnpackStreams)- return (-1);- if (unpack_streams > SIZE_MAX - UMAX_ENTRY) {- return (-1);- }- unpack_streams += (size_t)f[i].numUnpackStreams;- }- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- type = *p;- } else- unpack_streams = numFolders;-- ss->unpack_streams = unpack_streams;- if (unpack_streams) {- ss->unpackSizes = calloc(unpack_streams,- sizeof(*ss->unpackSizes));- ss->digestsDefined = calloc(unpack_streams,- sizeof(*ss->digestsDefined));- ss->digests = calloc(unpack_streams,- sizeof(*ss->digests));- if (ss->unpackSizes == NULL || ss->digestsDefined == NULL ||- ss->digests == NULL)- return (-1);- }-- usizes = ss->unpackSizes;- for (i = 0; i < numFolders; i++) {- unsigned pack;- uint64_t sum;-- if (f[i].numUnpackStreams == 0)- continue;-- sum = 0;- if (type == kSize) {- for (pack = 1; pack < f[i].numUnpackStreams; pack++) {- if (parse_7zip_uint64(a, usizes) < 0)- return (-1);- sum += *usizes++;- }- }- *usizes++ = folder_uncompressed_size(&f[i]) - sum;- }-- if (type == kSize) {- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- type = *p;- }-- for (i = 0; i < unpack_streams; i++) {- ss->digestsDefined[i] = 0;- ss->digests[i] = 0;- }-- numDigests = 0;- for (i = 0; i < numFolders; i++) {- if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)- numDigests += (uint32_t)f[i].numUnpackStreams;- }-- if (type == kCRC) {- struct _7z_digests tmpDigests;- unsigned char *digestsDefined = ss->digestsDefined;- uint32_t * digests = ss->digests;- int di = 0;-- memset(&tmpDigests, 0, sizeof(tmpDigests));- if (read_Digests(a, &(tmpDigests), numDigests) < 0) {- free_Digest(&tmpDigests);- return (-1);- }- for (i = 0; i < numFolders; i++) {- if (f[i].numUnpackStreams == 1 && f[i].digest_defined) {- *digestsDefined++ = 1;- *digests++ = f[i].digest;- } else {- unsigned j;-- for (j = 0; j < f[i].numUnpackStreams;- j++, di++) {- *digestsDefined++ =- tmpDigests.defineds[di];- *digests++ =- tmpDigests.digests[di];- }- }- }- free_Digest(&tmpDigests);- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- type = *p;- }-- /*- * Must be kEnd.- */- if (type != kEnd)- return (-1);- return (0);-}--static void-free_StreamsInfo(struct _7z_stream_info *si)-{- free_PackInfo(&(si->pi));- free_CodersInfo(&(si->ci));- free_SubStreamsInfo(&(si->ss));-}--static int-read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- const unsigned char *p;- unsigned i;-- memset(si, 0, sizeof(*si));-- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- if (*p == kPackInfo) {- uint64_t packPos;-- if (read_PackInfo(a, &(si->pi)) < 0)- return (-1);-- if (si->pi.positions == NULL || si->pi.sizes == NULL)- return (-1);- /*- * Calculate packed stream positions.- */- packPos = si->pi.pos;- for (i = 0; i < si->pi.numPackStreams; i++) {- si->pi.positions[i] = packPos;- packPos += si->pi.sizes[i];- if (packPos > zip->header_offset)- return (-1);- }- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- }- if (*p == kUnPackInfo) {- uint32_t packIndex;- struct _7z_folder *f;-- if (read_CodersInfo(a, &(si->ci)) < 0)- return (-1);-- /*- * Calculate packed stream indexes.- */- packIndex = 0;- f = si->ci.folders;- for (i = 0; i < si->ci.numFolders; i++) {- f[i].packIndex = packIndex;- packIndex += (uint32_t)f[i].numPackedStreams;- if (packIndex > si->pi.numPackStreams)- return (-1);- }- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- }-- if (*p == kSubStreamsInfo) {- if (read_SubStreamsInfo(a, &(si->ss),- si->ci.folders, (size_t)si->ci.numFolders) < 0)- return (-1);- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- }-- /*- * Must be kEnd.- */- if (*p != kEnd)- return (-1);- return (0);-}--static void-free_Header(struct _7z_header_info *h)-{- free(h->emptyStreamBools);- free(h->emptyFileBools);- free(h->antiBools);- free(h->attrBools);-}--static int-read_Header(struct archive_read *a, struct _7z_header_info *h,- int check_header_id)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- const unsigned char *p;- struct _7z_folder *folders;- struct _7z_stream_info *si = &(zip->si);- struct _7zip_entry *entries;- uint32_t folderIndex, indexInFolder;- unsigned i;- int eindex, empty_streams, sindex;-- if (check_header_id) {- /*- * Read Header.- */- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- if (*p != kHeader)- return (-1);- }-- /*- * Read ArchiveProperties.- */- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- if (*p == kArchiveProperties) {- for (;;) {- uint64_t size;- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- if (*p == 0)- break;- if (parse_7zip_uint64(a, &size) < 0)- return (-1);- }- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- }-- /*- * Read MainStreamsInfo.- */- if (*p == kMainStreamsInfo) {- if (read_StreamsInfo(a, &(zip->si)) < 0)- return (-1);- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- }- if (*p == kEnd)- return (0);-- /*- * Read FilesInfo.- */- if (*p != kFilesInfo)- return (-1);-- if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)- return (-1);- if (UMAX_ENTRY < zip->numFiles)- return (-1);-- zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));- if (zip->entries == NULL)- return (-1);- entries = zip->entries;-- empty_streams = 0;- for (;;) {- int type;- uint64_t size;- size_t ll;-- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- type = *p;- if (type == kEnd)- break;-- if (parse_7zip_uint64(a, &size) < 0)- return (-1);- if (zip->header_bytes_remaining < size)- return (-1);- ll = (size_t)size;-- switch (type) {- case kEmptyStream:- if (h->emptyStreamBools != NULL)- return (-1);- h->emptyStreamBools = calloc((size_t)zip->numFiles,- sizeof(*h->emptyStreamBools));- if (h->emptyStreamBools == NULL)- return (-1);- if (read_Bools(- a, h->emptyStreamBools, (size_t)zip->numFiles) < 0)- return (-1);- empty_streams = 0;- for (i = 0; i < zip->numFiles; i++) {- if (h->emptyStreamBools[i])- empty_streams++;- }- break;- case kEmptyFile:- if (empty_streams <= 0) {- /* Unexcepted sequence. Skip this. */- if (header_bytes(a, ll) == NULL)- return (-1);- break;- }- if (h->emptyFileBools != NULL)- return (-1);- h->emptyFileBools = calloc(empty_streams,- sizeof(*h->emptyFileBools));- if (h->emptyFileBools == NULL)- return (-1);- if (read_Bools(a, h->emptyFileBools, empty_streams) < 0)- return (-1);- break;- case kAnti:- if (empty_streams <= 0) {- /* Unexcepted sequence. Skip this. */- if (header_bytes(a, ll) == NULL)- return (-1);- break;- }- if (h->antiBools != NULL)- return (-1);- h->antiBools = calloc(empty_streams,- sizeof(*h->antiBools));- if (h->antiBools == NULL)- return (-1);- if (read_Bools(a, h->antiBools, empty_streams) < 0)- return (-1);- break;- case kCTime:- case kATime:- case kMTime:- if (read_Times(a, h, type) < 0)- return (-1);- break;- case kName:- {- unsigned char *np;- size_t nl, nb;-- /* Skip one byte. */- if ((p = header_bytes(a, 1)) == NULL)- return (-1);- ll--;-- if ((ll & 1) || ll < zip->numFiles * 4)- return (-1);-- if (zip->entry_names != NULL)- return (-1);- zip->entry_names = malloc(ll);- if (zip->entry_names == NULL)- return (-1);- np = zip->entry_names;- nb = ll;- /*- * Copy whole file names.- * NOTE: This loop prevents from expanding- * the uncompressed buffer in order not to- * use extra memory resource.- */- while (nb) {- size_t b;- if (nb > UBUFF_SIZE)- b = UBUFF_SIZE;- else- b = nb;- if ((p = header_bytes(a, b)) == NULL)- return (-1);- memcpy(np, p, b);- np += b;- nb -= b;- }- np = zip->entry_names;- nl = ll;-- for (i = 0; i < zip->numFiles; i++) {- entries[i].utf16name = np;-#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)- entries[i].wname = (wchar_t *)np;-#endif-- /* Find a terminator. */- while (nl >= 2 && (np[0] || np[1])) {- np += 2;- nl -= 2;- }- if (nl < 2)- return (-1);/* Terminator not found */- entries[i].name_len = np - entries[i].utf16name;- np += 2;- nl -= 2;- }- break;- }- case kAttributes:- {- int allAreDefined;-- if ((p = header_bytes(a, 2)) == NULL)- return (-1);- allAreDefined = *p;- if (h->attrBools != NULL)- return (-1);- h->attrBools = calloc((size_t)zip->numFiles,- sizeof(*h->attrBools));- if (h->attrBools == NULL)- return (-1);- if (allAreDefined)- memset(h->attrBools, 1, (size_t)zip->numFiles);- else {- if (read_Bools(a, h->attrBools,- (size_t)zip->numFiles) < 0)- return (-1);- }- for (i = 0; i < zip->numFiles; i++) {- if (h->attrBools[i]) {- if ((p = header_bytes(a, 4)) == NULL)- return (-1);- entries[i].attr = archive_le32dec(p);- }- }- break;- }- case kDummy:- if (ll == 0)- break;- __LA_FALLTHROUGH;- default:- if (header_bytes(a, ll) == NULL)- return (-1);- break;- }- }-- /*- * Set up entry's attributes.- */- folders = si->ci.folders;- eindex = sindex = 0;- folderIndex = indexInFolder = 0;- for (i = 0; i < zip->numFiles; i++) {- if (h->emptyStreamBools == NULL || h->emptyStreamBools[i] == 0)- entries[i].flg |= HAS_STREAM;- /* The high 16 bits of attributes is a posix file mode. */- entries[i].mode = entries[i].attr >> 16;- if (entries[i].flg & HAS_STREAM) {- if ((size_t)sindex >= si->ss.unpack_streams)- return (-1);- if (entries[i].mode == 0)- entries[i].mode = AE_IFREG | 0666;- if (si->ss.digestsDefined[sindex])- entries[i].flg |= CRC32_IS_SET;- entries[i].ssIndex = sindex;- sindex++;- } else {- int dir;- if (h->emptyFileBools == NULL)- dir = 1;- else {- if (h->emptyFileBools[eindex])- dir = 0;- else- dir = 1;- eindex++;- }- if (entries[i].mode == 0) {- if (dir)- entries[i].mode = AE_IFDIR | 0777;- else- entries[i].mode = AE_IFREG | 0666;- } else if (dir &&- (entries[i].mode & AE_IFMT) != AE_IFDIR) {- entries[i].mode &= ~AE_IFMT;- entries[i].mode |= AE_IFDIR;- }- if ((entries[i].mode & AE_IFMT) == AE_IFDIR &&- entries[i].name_len >= 2 &&- (entries[i].utf16name[entries[i].name_len-2] != '/' ||- entries[i].utf16name[entries[i].name_len-1] != 0)) {- entries[i].utf16name[entries[i].name_len] = '/';- entries[i].utf16name[entries[i].name_len+1] = 0;- entries[i].name_len += 2;- }- entries[i].ssIndex = -1;- }- if (entries[i].attr & 0x01)- entries[i].mode &= ~0222;/* Read only. */-- if ((entries[i].flg & HAS_STREAM) == 0 && indexInFolder == 0) {- /*- * The entry is an empty file or a directory file,- * those both have no contents.- */- entries[i].folderIndex = -1;- continue;- }- if (indexInFolder == 0) {- for (;;) {- if (folderIndex >= si->ci.numFolders)- return (-1);- if (folders[folderIndex].numUnpackStreams)- break;- folderIndex++;- }- }- entries[i].folderIndex = folderIndex;- if ((entries[i].flg & HAS_STREAM) == 0)- continue;- indexInFolder++;- if (indexInFolder >= folders[folderIndex].numUnpackStreams) {- folderIndex++;- indexInFolder = 0;- }- }-- return (0);-}--#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)-static void-fileTimeToUtc(uint64_t fileTime, time_t *timep, long *ns)-{-- if (fileTime >= EPOC_TIME) {- fileTime -= EPOC_TIME;- /* milli seconds base */- *timep = (time_t)(fileTime / 10000000);- /* nano seconds base */- *ns = (long)(fileTime % 10000000) * 100;- } else {- *timep = 0;- *ns = 0;- }-}--static int-read_Times(struct archive_read *a, struct _7z_header_info *h, int type)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- const unsigned char *p;- struct _7zip_entry *entries = zip->entries;- unsigned char *timeBools;- int allAreDefined;- unsigned i;-- timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools));- if (timeBools == NULL)- return (-1);-- /* Read allAreDefined. */- if ((p = header_bytes(a, 1)) == NULL)- goto failed;- allAreDefined = *p;- if (allAreDefined)- memset(timeBools, 1, (size_t)zip->numFiles);- else {- if (read_Bools(a, timeBools, (size_t)zip->numFiles) < 0)- goto failed;- }-- /* Read external. */- if ((p = header_bytes(a, 1)) == NULL)- goto failed;- if (*p) {- if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)- goto failed;- if (UMAX_ENTRY < h->dataIndex)- goto failed;- }-- for (i = 0; i < zip->numFiles; i++) {- if (!timeBools[i])- continue;- if ((p = header_bytes(a, 8)) == NULL)- goto failed;- switch (type) {- case kCTime:- fileTimeToUtc(archive_le64dec(p),- &(entries[i].ctime),- &(entries[i].ctime_ns));- entries[i].flg |= CTIME_IS_SET;- break;- case kATime:- fileTimeToUtc(archive_le64dec(p),- &(entries[i].atime),- &(entries[i].atime_ns));- entries[i].flg |= ATIME_IS_SET;- break;- case kMTime:- fileTimeToUtc(archive_le64dec(p),- &(entries[i].mtime),- &(entries[i].mtime_ns));- entries[i].flg |= MTIME_IS_SET;- break;- }- }-- free(timeBools);- return (0);-failed:- free(timeBools);- return (-1);-}--static int-decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)-{- struct _7zip *zip = (struct _7zip *)a->format->data;-- errno = 0;- if (read_StreamsInfo(a, si) < 0) {- if (errno == ENOMEM)- archive_set_error(&a->archive, -1,- "Couldn't allocate memory");- else- archive_set_error(&a->archive, -1,- "Malformed 7-Zip archive");- return (ARCHIVE_FATAL);- }-- if (si->pi.numPackStreams == 0 || si->ci.numFolders == 0) {- archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");- return (ARCHIVE_FATAL);- }-- if (zip->header_offset < si->pi.pos + si->pi.sizes[0] ||- (int64_t)(si->pi.pos + si->pi.sizes[0]) < 0 ||- si->pi.sizes[0] == 0 || (int64_t)si->pi.pos < 0) {- archive_set_error(&a->archive, -1, "Malformed Header offset");- return (ARCHIVE_FATAL);- }-- return (ARCHIVE_OK);-}--static const unsigned char *-header_bytes(struct archive_read *a, size_t rbytes)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- const unsigned char *p;-- if (zip->header_bytes_remaining < rbytes)- return (NULL);- if (zip->pack_stream_bytes_unconsumed)- read_consume(a);-- if (zip->header_is_encoded == 0) {- p = __archive_read_ahead(a, rbytes, NULL);- if (p == NULL)- return (NULL);- zip->header_bytes_remaining -= rbytes;- zip->pack_stream_bytes_unconsumed = rbytes;- } else {- const void *buff;- ssize_t bytes;-- bytes = read_stream(a, &buff, rbytes, rbytes);- if (bytes <= 0)- return (NULL);- zip->header_bytes_remaining -= bytes;- p = buff;- }-- /* Update checksum */- zip->header_crc32 = crc32(zip->header_crc32, p, (unsigned)rbytes);- return (p);-}--static int-slurp_central_directory(struct archive_read *a, struct _7zip *zip,- struct _7z_header_info *header)-{- const unsigned char *p;- uint64_t next_header_offset;- uint64_t next_header_size;- uint32_t next_header_crc;- ssize_t bytes_avail;- int check_header_crc, r;-- if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)- return (ARCHIVE_FATAL);-- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {- /* This is an executable ? Must be self-extracting... */- r = skip_sfx(a, bytes_avail);- if (r < ARCHIVE_WARN)- return (r);- if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)- return (ARCHIVE_FATAL);- }- zip->seek_base += 32;-- if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0) {- archive_set_error(&a->archive, -1, "Not 7-Zip archive file");- return (ARCHIVE_FATAL);- }-- /* CRC check. */- if (crc32(0, (const unsigned char *)p + 12, 20)- != archive_le32dec(p + 8)) {-#ifdef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, -1, "Header CRC error");- return (ARCHIVE_FATAL);-#endif- }-- next_header_offset = archive_le64dec(p + 12);- next_header_size = archive_le64dec(p + 20);- next_header_crc = archive_le32dec(p + 28);-- if (next_header_size == 0)- /* There is no entry in an archive file. */- return (ARCHIVE_EOF);-- if (((int64_t)next_header_offset) < 0) {- archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");- return (ARCHIVE_FATAL);- }- __archive_read_consume(a, 32);- if (next_header_offset != 0) {- if (bytes_avail >= (ssize_t)next_header_offset)- __archive_read_consume(a, next_header_offset);- else if (__archive_read_seek(a,- next_header_offset + zip->seek_base, SEEK_SET) < 0)- return (ARCHIVE_FATAL);- }- zip->stream_offset = next_header_offset;- zip->header_offset = next_header_offset;- zip->header_bytes_remaining = next_header_size;- zip->header_crc32 = 0;- zip->header_is_encoded = 0;- zip->header_is_being_read = 1;- zip->has_encrypted_entries = 0;- check_header_crc = 1;-- if ((p = header_bytes(a, 1)) == NULL) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated 7-Zip file body");- return (ARCHIVE_FATAL);- }- /* Parse ArchiveProperties. */- switch (p[0]) {- case kEncodedHeader:- /*- * The archive has an encoded header and we have to decode it- * in order to parse the header correctly.- */- r = decode_encoded_header_info(a, &(zip->si));-- /* Check the EncodedHeader CRC.*/- if (r == 0 && zip->header_crc32 != next_header_crc) {- archive_set_error(&a->archive, -1,-#ifndef DONT_FAIL_ON_CRC_ERROR- "Damaged 7-Zip archive");- r = -1;-#endif- }- if (r == 0) {- if (zip->si.ci.folders[0].digest_defined)- next_header_crc = zip->si.ci.folders[0].digest;- else- check_header_crc = 0;- if (zip->pack_stream_bytes_unconsumed)- read_consume(a);- r = setup_decode_folder(a, zip->si.ci.folders, 1);- if (r == 0) {- zip->header_bytes_remaining =- zip->folder_outbytes_remaining;- r = seek_pack(a);- }- }- /* Clean up StreamsInfo. */- free_StreamsInfo(&(zip->si));- memset(&(zip->si), 0, sizeof(zip->si));- if (r < 0)- return (ARCHIVE_FATAL);- zip->header_is_encoded = 1;- zip->header_crc32 = 0;- /* FALL THROUGH */- case kHeader:- /*- * Parse the header.- */- errno = 0;- r = read_Header(a, header, zip->header_is_encoded);- if (r < 0) {- if (errno == ENOMEM)- archive_set_error(&a->archive, -1,- "Couldn't allocate memory");- else- archive_set_error(&a->archive, -1,- "Damaged 7-Zip archive");- return (ARCHIVE_FATAL);- }-- /*- * Must be kEnd.- */- if ((p = header_bytes(a, 1)) == NULL ||*p != kEnd) {- archive_set_error(&a->archive, -1,- "Malformed 7-Zip archive");- return (ARCHIVE_FATAL);- }-- /* Check the Header CRC.*/- if (check_header_crc && zip->header_crc32 != next_header_crc) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, -1,- "Malformed 7-Zip archive");- return (ARCHIVE_FATAL);-#endif- }- break;- default:- archive_set_error(&a->archive, -1,- "Unexpected Property ID = %X", p[0]);- return (ARCHIVE_FATAL);- }-- /* Clean up variables be used for decoding the archive header */- zip->pack_stream_remaining = 0;- zip->pack_stream_index = 0;- zip->folder_outbytes_remaining = 0;- zip->uncompressed_buffer_bytes_remaining = 0;- zip->pack_stream_bytes_unconsumed = 0;- zip->header_is_being_read = 0;-- return (ARCHIVE_OK);-}--static ssize_t-get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,- size_t minimum)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- ssize_t bytes_avail;-- if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {- /* Copy mode. */-- *buff = __archive_read_ahead(a, minimum, &bytes_avail);- if (bytes_avail <= 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated 7-Zip file data");- return (ARCHIVE_FATAL);- }- if ((size_t)bytes_avail >- zip->uncompressed_buffer_bytes_remaining)- bytes_avail = (ssize_t)- zip->uncompressed_buffer_bytes_remaining;- if ((size_t)bytes_avail > size)- bytes_avail = (ssize_t)size;-- zip->pack_stream_bytes_unconsumed = bytes_avail;- } else if (zip->uncompressed_buffer_pointer == NULL) {- /* Decompression has failed. */- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");- return (ARCHIVE_FATAL);- } else {- /* Packed mode. */- if (minimum > zip->uncompressed_buffer_bytes_remaining) {- /*- * If remaining uncompressed data size is less than- * the minimum size, fill the buffer up to the- * minimum size.- */- if (extract_pack_stream(a, minimum) < 0)- return (ARCHIVE_FATAL);- }- if (size > zip->uncompressed_buffer_bytes_remaining)- bytes_avail = (ssize_t)- zip->uncompressed_buffer_bytes_remaining;- else- bytes_avail = (ssize_t)size;- *buff = zip->uncompressed_buffer_pointer;- zip->uncompressed_buffer_pointer += bytes_avail;- }- zip->uncompressed_buffer_bytes_remaining -= bytes_avail;- return (bytes_avail);-}--static ssize_t-extract_pack_stream(struct archive_read *a, size_t minimum)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- ssize_t bytes_avail;- int r;-- if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {- if (minimum == 0)- minimum = 1;- if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL- || bytes_avail <= 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated 7-Zip file body");- return (ARCHIVE_FATAL);- }- if ((uint64_t)bytes_avail > zip->pack_stream_inbytes_remaining)- bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining;- zip->pack_stream_inbytes_remaining -= bytes_avail;- if ((uint64_t)bytes_avail > zip->folder_outbytes_remaining)- bytes_avail = (ssize_t)zip->folder_outbytes_remaining;- zip->folder_outbytes_remaining -= bytes_avail;- zip->uncompressed_buffer_bytes_remaining = bytes_avail;- return (ARCHIVE_OK);- }-- /* If the buffer hasn't been allocated, allocate it now. */- if (zip->uncompressed_buffer == NULL) {- zip->uncompressed_buffer_size = UBUFF_SIZE;- if (zip->uncompressed_buffer_size < minimum) {- zip->uncompressed_buffer_size = minimum + 1023;- zip->uncompressed_buffer_size &= ~0x3ff;- }- zip->uncompressed_buffer =- malloc(zip->uncompressed_buffer_size);- if (zip->uncompressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for 7-Zip decompression");- return (ARCHIVE_FATAL);- }- zip->uncompressed_buffer_bytes_remaining = 0;- } else if (zip->uncompressed_buffer_size < minimum ||- zip->uncompressed_buffer_bytes_remaining < minimum) {- /*- * Make sure the uncompressed buffer can have bytes- * at least `minimum' bytes.- * NOTE: This case happen when reading the header.- */- size_t used;- if (zip->uncompressed_buffer_pointer != 0)- used = zip->uncompressed_buffer_pointer -- zip->uncompressed_buffer;- else- used = 0;- if (zip->uncompressed_buffer_size < minimum) {- /*- * Expand the uncompressed buffer up to- * the minimum size.- */- void *p;- size_t new_size;-- new_size = minimum + 1023;- new_size &= ~0x3ff;- p = realloc(zip->uncompressed_buffer, new_size);- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for 7-Zip decompression");- return (ARCHIVE_FATAL);- }- zip->uncompressed_buffer = (unsigned char *)p;- zip->uncompressed_buffer_size = new_size;- }- /*- * Move unconsumed bytes to the head.- */- if (used) {- memmove(zip->uncompressed_buffer,- zip->uncompressed_buffer + used,- zip->uncompressed_buffer_bytes_remaining);- }- } else- zip->uncompressed_buffer_bytes_remaining = 0;- zip->uncompressed_buffer_pointer = NULL;- for (;;) {- size_t bytes_in, bytes_out;- const void *buff_in;- unsigned char *buff_out;- int end_of_data;-- /*- * Note: '1' here is a performance optimization.- * Recall that the decompression layer returns a count of- * available bytes; asking for more than that forces the- * decompressor to combine reads by copying data.- */- buff_in = __archive_read_ahead(a, 1, &bytes_avail);- if (bytes_avail <= 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated 7-Zip file body");- return (ARCHIVE_FATAL);- }-- buff_out = zip->uncompressed_buffer- + zip->uncompressed_buffer_bytes_remaining;- bytes_out = zip->uncompressed_buffer_size- - zip->uncompressed_buffer_bytes_remaining;- bytes_in = bytes_avail;- if (bytes_in > zip->pack_stream_inbytes_remaining)- bytes_in = (size_t)zip->pack_stream_inbytes_remaining;- /* Drive decompression. */- r = decompress(a, zip, buff_out, &bytes_out,- buff_in, &bytes_in);- switch (r) {- case ARCHIVE_OK:- end_of_data = 0;- break;- case ARCHIVE_EOF:- end_of_data = 1;- break;- default:- return (ARCHIVE_FATAL);- }- zip->pack_stream_inbytes_remaining -= bytes_in;- if (bytes_out > zip->folder_outbytes_remaining)- bytes_out = (size_t)zip->folder_outbytes_remaining;- zip->folder_outbytes_remaining -= bytes_out;- zip->uncompressed_buffer_bytes_remaining += bytes_out;- zip->pack_stream_bytes_unconsumed = bytes_in;-- /*- * Continue decompression until uncompressed_buffer is full.- */- if (zip->uncompressed_buffer_bytes_remaining ==- zip->uncompressed_buffer_size)- break;- if (zip->codec2 == _7Z_X86 && zip->odd_bcj_size &&- zip->uncompressed_buffer_bytes_remaining + 5 >- zip->uncompressed_buffer_size)- break;- if (zip->pack_stream_inbytes_remaining == 0 &&- zip->folder_outbytes_remaining == 0)- break;- if (end_of_data || (bytes_in == 0 && bytes_out == 0)) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");- return (ARCHIVE_FATAL);- }- read_consume(a);- }- if (zip->uncompressed_buffer_bytes_remaining < minimum) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");- return (ARCHIVE_FATAL);- }- zip->uncompressed_buffer_pointer = zip->uncompressed_buffer;- return (ARCHIVE_OK);-}--static int-seek_pack(struct archive_read *a)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- int64_t pack_offset;-- if (zip->pack_stream_remaining <= 0) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");- return (ARCHIVE_FATAL);- }- zip->pack_stream_inbytes_remaining =- zip->si.pi.sizes[zip->pack_stream_index];- pack_offset = zip->si.pi.positions[zip->pack_stream_index];- if (zip->stream_offset != pack_offset) {- if (0 > __archive_read_seek(a, pack_offset + zip->seek_base,- SEEK_SET))- return (ARCHIVE_FATAL);- zip->stream_offset = pack_offset;- }- zip->pack_stream_index++;- zip->pack_stream_remaining--;- return (ARCHIVE_OK);-}--static ssize_t-read_stream(struct archive_read *a, const void **buff, size_t size,- size_t minimum)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- uint64_t skip_bytes = 0;- ssize_t r;-- if (zip->uncompressed_buffer_bytes_remaining == 0) {- if (zip->pack_stream_inbytes_remaining > 0) {- r = extract_pack_stream(a, 0);- if (r < 0)- return (r);- return (get_uncompressed_data(a, buff, size, minimum));- } else if (zip->folder_outbytes_remaining > 0) {- /* Extract a remaining pack stream. */- r = extract_pack_stream(a, 0);- if (r < 0)- return (r);- return (get_uncompressed_data(a, buff, size, minimum));- }- } else- return (get_uncompressed_data(a, buff, size, minimum));-- /*- * Current pack stream has been consumed.- */- if (zip->pack_stream_remaining == 0) {- if (zip->header_is_being_read) {- /* Invalid sequence. This might happen when- * reading a malformed archive. */- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC, "Malformed 7-Zip archive");- return (ARCHIVE_FATAL);- }-- /*- * All current folder's pack streams have been- * consumed. Switch to next folder.- */- if (zip->folder_index == 0 &&- (zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes- || zip->folder_index != zip->entry->folderIndex)) {- zip->folder_index = zip->entry->folderIndex;- skip_bytes =- zip->si.ci.folders[zip->folder_index].skipped_bytes;- }-- if (zip->folder_index >= zip->si.ci.numFolders) {- /*- * We have consumed all folders and its pack streams.- */- *buff = NULL;- return (0);- }- r = setup_decode_folder(a,- &(zip->si.ci.folders[zip->folder_index]), 0);- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- zip->folder_index++;- }-- /*- * Switch to next pack stream.- */- r = seek_pack(a);- if (r < 0)- return (r);-- /* Extract a new pack stream. */- r = extract_pack_stream(a, 0);- if (r < 0)- return (r);-- /*- * Skip the bytes we already has skipped in skip_stream().- */- while (skip_bytes) {- ssize_t skipped;-- if (zip->uncompressed_buffer_bytes_remaining == 0) {- if (zip->pack_stream_inbytes_remaining > 0) {- r = extract_pack_stream(a, 0);- if (r < 0)- return (r);- } else if (zip->folder_outbytes_remaining > 0) {- /* Extract a remaining pack stream. */- r = extract_pack_stream(a, 0);- if (r < 0)- return (r);- } else {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated 7-Zip file body");- return (ARCHIVE_FATAL);- }- }- skipped = get_uncompressed_data(- a, buff, (size_t)skip_bytes, 0);- if (skipped < 0)- return (skipped);- skip_bytes -= skipped;- if (zip->pack_stream_bytes_unconsumed)- read_consume(a);- }-- return (get_uncompressed_data(a, buff, size, minimum));-}--static int-setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,- int header)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- const struct _7z_coder *coder1, *coder2;- const char *cname = (header)?"archive header":"file content";- unsigned i;- int r, found_bcj2 = 0;-- /*- * Release the memory which the previous folder used for BCJ2.- */- for (i = 0; i < 3; i++) {- free(zip->sub_stream_buff[i]);- zip->sub_stream_buff[i] = NULL;- }-- /*- * Initialize a stream reader.- */- zip->pack_stream_remaining = (unsigned)folder->numPackedStreams;- zip->pack_stream_index = (unsigned)folder->packIndex;- zip->folder_outbytes_remaining = folder_uncompressed_size(folder);- zip->uncompressed_buffer_bytes_remaining = 0;-- /*- * Check coder types.- */- for (i = 0; i < folder->numCoders; i++) {- switch(folder->coders[i].codec) {- case _7Z_CRYPTO_MAIN_ZIP:- case _7Z_CRYPTO_RAR_29:- case _7Z_CRYPTO_AES_256_SHA_256: {- /* For entry that is associated with this folder, mark- it as encrypted (data+metadata). */- zip->has_encrypted_entries = 1;- if (a->entry) {- archive_entry_set_is_data_encrypted(a->entry, 1);- archive_entry_set_is_metadata_encrypted(a->entry, 1);- }- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "The %s is encrypted, "- "but currently not supported", cname);- return (ARCHIVE_FATAL);- }- case _7Z_X86_BCJ2: {- found_bcj2++;- break;- }- }- }- /* Now that we've checked for encryption, if there were still no- * encrypted entries found we can say for sure that there are none.- */- if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {- zip->has_encrypted_entries = 0;- }-- if ((folder->numCoders > 2 && !found_bcj2) || found_bcj2 > 1) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "The %s is encoded with many filters, "- "but currently not supported", cname);- return (ARCHIVE_FATAL);- }- coder1 = &(folder->coders[0]);- if (folder->numCoders == 2)- coder2 = &(folder->coders[1]);- else- coder2 = NULL;-- if (found_bcj2) {- /*- * Preparation to decode BCJ2.- * Decoding BCJ2 requires four sources. Those are at least,- * as far as I know, two types of the storage form.- */- const struct _7z_coder *fc = folder->coders;- static const struct _7z_coder coder_copy = {0, 1, 1, 0, NULL};- const struct _7z_coder *scoder[3] =- {&coder_copy, &coder_copy, &coder_copy};- const void *buff;- ssize_t bytes;- unsigned char *b[3] = {NULL, NULL, NULL};- uint64_t sunpack[3] ={-1, -1, -1};- size_t s[3] = {0, 0, 0};- int idx[3] = {0, 1, 2};-- if (folder->numCoders == 4 && fc[3].codec == _7Z_X86_BCJ2 &&- folder->numInStreams == 7 && folder->numOutStreams == 4 &&- zip->pack_stream_remaining == 4) {- /* Source type 1 made by 7zr or 7z with -m options. */- if (folder->bindPairs[0].inIndex == 5) {- /* The form made by 7zr */- idx[0] = 1; idx[1] = 2; idx[2] = 0;- scoder[1] = &(fc[1]);- scoder[2] = &(fc[0]);- sunpack[1] = folder->unPackSize[1];- sunpack[2] = folder->unPackSize[0];- coder1 = &(fc[2]);- } else {- /*- * NOTE: Some patterns do not work.- * work:- * 7z a -m0=BCJ2 -m1=COPY -m2=COPY- * -m3=(any)- * 7z a -m0=BCJ2 -m1=COPY -m2=(any)- * -m3=COPY- * 7z a -m0=BCJ2 -m1=(any) -m2=COPY- * -m3=COPY- * not work:- * other patterns.- *- * We have to handle this like `pipe' or- * our libarchive7s filter frame work,- * decoding the BCJ2 main stream sequentially,- * m3 -> m2 -> m1 -> BCJ2.- *- */- if (fc[0].codec == _7Z_COPY &&- fc[1].codec == _7Z_COPY)- coder1 = &(folder->coders[2]);- else if (fc[0].codec == _7Z_COPY &&- fc[2].codec == _7Z_COPY)- coder1 = &(folder->coders[1]);- else if (fc[1].codec == _7Z_COPY &&- fc[2].codec == _7Z_COPY)- coder1 = &(folder->coders[0]);- else {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Unsupported form of "- "BCJ2 streams");- return (ARCHIVE_FATAL);- }- }- coder2 = &(fc[3]);- zip->main_stream_bytes_remaining =- (size_t)folder->unPackSize[2];- } else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 &&- zip->pack_stream_remaining == 4 &&- folder->numInStreams == 5 && folder->numOutStreams == 2) {- /* Source type 0 made by 7z */- zip->main_stream_bytes_remaining =- (size_t)folder->unPackSize[0];- } else {- /* We got an unexpected form. */- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Unsupported form of BCJ2 streams");- return (ARCHIVE_FATAL);- }-- /* Skip the main stream at this time. */- if ((r = seek_pack(a)) < 0)- return (r);- zip->pack_stream_bytes_unconsumed =- (size_t)zip->pack_stream_inbytes_remaining;- read_consume(a);-- /* Read following three sub streams. */- for (i = 0; i < 3; i++) {- const struct _7z_coder *coder = scoder[i];-- if ((r = seek_pack(a)) < 0) {- free(b[0]); free(b[1]); free(b[2]);- return (r);- }-- if (sunpack[i] == (uint64_t)-1)- zip->folder_outbytes_remaining =- zip->pack_stream_inbytes_remaining;- else- zip->folder_outbytes_remaining = sunpack[i];-- r = init_decompression(a, zip, coder, NULL);- if (r != ARCHIVE_OK) {- free(b[0]); free(b[1]); free(b[2]);- return (ARCHIVE_FATAL);- }-- /* Allocate memory for the decoded data of a sub- * stream. */- b[i] = malloc((size_t)zip->folder_outbytes_remaining);- if (b[i] == NULL) {- free(b[0]); free(b[1]); free(b[2]);- archive_set_error(&a->archive, ENOMEM,- "No memory for 7-Zip decompression");- return (ARCHIVE_FATAL);- }-- /* Extract a sub stream. */- while (zip->pack_stream_inbytes_remaining > 0) {- r = (int)extract_pack_stream(a, 0);- if (r < 0) {- free(b[0]); free(b[1]); free(b[2]);- return (r);- }- bytes = get_uncompressed_data(a, &buff,- zip->uncompressed_buffer_bytes_remaining,- 0);- if (bytes < 0) {- free(b[0]); free(b[1]); free(b[2]);- return ((int)bytes);- }- memcpy(b[i]+s[i], buff, bytes);- s[i] += bytes;- if (zip->pack_stream_bytes_unconsumed)- read_consume(a);- }- }-- /* Set the sub streams to the right place. */- for (i = 0; i < 3; i++) {- zip->sub_stream_buff[i] = b[idx[i]];- zip->sub_stream_size[i] = s[idx[i]];- zip->sub_stream_bytes_remaining[i] = s[idx[i]];- }-- /* Allocate memory used for decoded main stream bytes. */- if (zip->tmp_stream_buff == NULL) {- zip->tmp_stream_buff_size = 32 * 1024;- zip->tmp_stream_buff =- malloc(zip->tmp_stream_buff_size);- if (zip->tmp_stream_buff == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for 7-Zip decompression");- return (ARCHIVE_FATAL);- }- }- zip->tmp_stream_bytes_avail = 0;- zip->tmp_stream_bytes_remaining = 0;- zip->odd_bcj_size = 0;- zip->bcj2_outPos = 0;-- /*- * Reset a stream reader in order to read the main stream- * of BCJ2.- */- zip->pack_stream_remaining = 1;- zip->pack_stream_index = (unsigned)folder->packIndex;- zip->folder_outbytes_remaining =- folder_uncompressed_size(folder);- zip->uncompressed_buffer_bytes_remaining = 0;- }-- /*- * Initialize the decompressor for the new folder's pack streams.- */- r = init_decompression(a, zip, coder1, coder2);- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);- return (ARCHIVE_OK);-}--static int64_t-skip_stream(struct archive_read *a, size_t skip_bytes)-{- struct _7zip *zip = (struct _7zip *)a->format->data;- const void *p;- int64_t skipped_bytes;- size_t bytes = skip_bytes;-- if (zip->folder_index == 0) {- /*- * Optimization for a list mode.- * Avoid unnecessary decoding operations.- */- zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes- += skip_bytes;- return (skip_bytes);- }-- while (bytes) {- skipped_bytes = read_stream(a, &p, bytes, 0);- if (skipped_bytes < 0)- return (skipped_bytes);- if (skipped_bytes == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated 7-Zip file body");- return (ARCHIVE_FATAL);- }- bytes -= (size_t)skipped_bytes;- if (zip->pack_stream_bytes_unconsumed)- read_consume(a);- }- return (skip_bytes);-}--/*- * Brought from LZMA SDK.- *- * Bra86.c -- Converter for x86 code (BCJ)- * 2008-10-04 : Igor Pavlov : Public domain- *- */--#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)--static void-x86_Init(struct _7zip *zip)-{- zip->bcj_state = 0;- zip->bcj_prevPosT = (size_t)0 - 1;- zip->bcj_prevMask = 0;- zip->bcj_ip = 5;-}--static size_t-x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)-{- static const uint8_t kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};- static const uint8_t kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};- size_t bufferPos, prevPosT;- uint32_t ip, prevMask;-- if (size < 5)- return 0;-- bufferPos = 0;- prevPosT = zip->bcj_prevPosT;- prevMask = zip->bcj_prevMask;- ip = zip->bcj_ip;-- for (;;) {- uint8_t *p = data + bufferPos;- uint8_t *limit = data + size - 4;-- for (; p < limit; p++)- if ((*p & 0xFE) == 0xE8)- break;- bufferPos = (size_t)(p - data);- if (p >= limit)- break;- prevPosT = bufferPos - prevPosT;- if (prevPosT > 3)- prevMask = 0;- else {- prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;- if (prevMask != 0) {- unsigned char b =- p[4 - kMaskToBitNumber[prevMask]];- if (!kMaskToAllowedStatus[prevMask] ||- Test86MSByte(b)) {- prevPosT = bufferPos;- prevMask = ((prevMask << 1) & 0x7) | 1;- bufferPos++;- continue;- }- }- }- prevPosT = bufferPos;-- if (Test86MSByte(p[4])) {- uint32_t src = ((uint32_t)p[4] << 24) |- ((uint32_t)p[3] << 16) | ((uint32_t)p[2] << 8) |- ((uint32_t)p[1]);- uint32_t dest;- for (;;) {- uint8_t b;- int b_index;-- dest = src - (ip + (uint32_t)bufferPos);- if (prevMask == 0)- break;- b_index = kMaskToBitNumber[prevMask] * 8;- b = (uint8_t)(dest >> (24 - b_index));- if (!Test86MSByte(b))- break;- src = dest ^ ((1 << (32 - b_index)) - 1);- }- p[4] = (uint8_t)(~(((dest >> 24) & 1) - 1));- p[3] = (uint8_t)(dest >> 16);- p[2] = (uint8_t)(dest >> 8);- p[1] = (uint8_t)dest;- bufferPos += 5;- } else {- prevMask = ((prevMask << 1) & 0x7) | 1;- bufferPos++;- }- }- zip->bcj_prevPosT = prevPosT;- zip->bcj_prevMask = prevMask;- zip->bcj_ip += (uint32_t)bufferPos;- return (bufferPos);-}--static void-arm_Init(struct _7zip *zip)-{- zip->bcj_ip = 8;-}--static size_t-arm_Convert(struct _7zip *zip, uint8_t *buf, size_t size)-{- // This function was adapted from- // static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)- // in https://git.tukaani.org/xz-embedded.git-- /*- * Branch/Call/Jump (BCJ) filter decoders- *- * Authors: Lasse Collin <lasse.collin@tukaani.org>- * Igor Pavlov <https://7-zip.org/>- *- * This file has been put into the public domain.- * You can do whatever you want with this file.- */-- size_t i;- uint32_t addr;-- for (i = 0; i + 4 <= size; i += 4) {- if (buf[i + 3] == 0xEB) {- // Calculate the transformed addr.- addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)- | ((uint32_t)buf[i + 2] << 16);- addr <<= 2;- addr -= zip->bcj_ip + (uint32_t)i;- addr >>= 2;-- // Store the transformed addr in buf.- buf[i] = (uint8_t)addr;- buf[i + 1] = (uint8_t)(addr >> 8);- buf[i + 2] = (uint8_t)(addr >> 16);- }- }-- zip->bcj_ip += (uint32_t)i;-- return i;-}--static size_t-arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)-{- // This function was adapted from- // static size_t bcj_arm64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)- // in https://git.tukaani.org/xz-embedded.git-- /*- * Branch/Call/Jump (BCJ) filter decoders- *- * Authors: Lasse Collin <lasse.collin@tukaani.org>- * Igor Pavlov <https://7-zip.org/>- *- * This file has been put into the public domain.- * You can do whatever you want with this file.- */-- size_t i;- uint32_t instr;- uint32_t addr;-- for (i = 0; i + 4 <= size; i += 4) {- instr = (uint32_t)buf[i]- | ((uint32_t)buf[i+1] << 8)- | ((uint32_t)buf[i+2] << 16)- | ((uint32_t)buf[i+3] << 24);-- if ((instr >> 26) == 0x25) {- /* BL instruction */- addr = instr - ((zip->bcj_ip + (uint32_t)i) >> 2);- instr = 0x94000000 | (addr & 0x03FFFFFF);-- buf[i] = (uint8_t)instr;- buf[i+1] = (uint8_t)(instr >> 8);- buf[i+2] = (uint8_t)(instr >> 16);- buf[i+3] = (uint8_t)(instr >> 24);- } else if ((instr & 0x9F000000) == 0x90000000) {- /* ADRP instruction */- addr = ((instr >> 29) & 3) | ((instr >> 3) & 0x1FFFFC);-- /* Only convert values in the range +/-512 MiB. */- if ((addr + 0x020000) & 0x1C0000)- continue;-- addr -= (zip->bcj_ip + (uint32_t)i) >> 12;-- instr &= 0x9000001F;- instr |= (addr & 3) << 29;- instr |= (addr & 0x03FFFC) << 3;- instr |= (0U - (addr & 0x020000)) & 0xE00000;-- buf[i] = (uint8_t)instr;- buf[i+1] = (uint8_t)(instr >> 8);- buf[i+2] = (uint8_t)(instr >> 16);- buf[i+3] = (uint8_t)(instr >> 24);- }- }-- zip->bcj_ip += (uint32_t)i;-- return i;-}--/*- * Brought from LZMA SDK.- *- * Bcj2.c -- Converter for x86 code (BCJ2)- * 2008-10-04 : Igor Pavlov : Public domain- *- */--#define SZ_ERROR_DATA ARCHIVE_FAILED--#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)-#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))--#define kNumTopBits 24-#define kTopValue ((uint32_t)1 << kNumTopBits)--#define kNumBitModelTotalBits 11-#define kBitModelTotal (1 << kNumBitModelTotalBits)-#define kNumMoveBits 5--#define RC_READ_BYTE (*buffer++)-#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }-#define RC_INIT2 zip->bcj2_code = 0; zip->bcj2_range = 0xFFFFFFFF; \- { int ii; for (ii = 0; ii < 5; ii++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}--#define NORMALIZE if (zip->bcj2_range < kTopValue) { RC_TEST; zip->bcj2_range <<= 8; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }--#define IF_BIT_0(p) ttt = *(p); bound = (zip->bcj2_range >> kNumBitModelTotalBits) * ttt; if (zip->bcj2_code < bound)-#define UPDATE_0(p) zip->bcj2_range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE;-#define UPDATE_1(p) zip->bcj2_range -= bound; zip->bcj2_code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE;--static ssize_t-Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)-{- size_t inPos = 0, outPos = 0;- const uint8_t *buf0, *buf1, *buf2, *buf3;- size_t size0, size1, size2, size3;- const uint8_t *buffer, *bufferLim;- unsigned int i, j;-- size0 = zip->tmp_stream_bytes_remaining;- buf0 = zip->tmp_stream_buff + zip->tmp_stream_bytes_avail - size0;- size1 = zip->sub_stream_bytes_remaining[0];- buf1 = zip->sub_stream_buff[0] + zip->sub_stream_size[0] - size1;- size2 = zip->sub_stream_bytes_remaining[1];- buf2 = zip->sub_stream_buff[1] + zip->sub_stream_size[1] - size2;- size3 = zip->sub_stream_bytes_remaining[2];- buf3 = zip->sub_stream_buff[2] + zip->sub_stream_size[2] - size3;-- buffer = buf3;- bufferLim = buffer + size3;-- if (zip->bcj_state == 0) {- /*- * Initialize.- */- zip->bcj2_prevByte = 0;- for (i = 0;- i < sizeof(zip->bcj2_p) / sizeof(zip->bcj2_p[0]); i++)- zip->bcj2_p[i] = kBitModelTotal >> 1;- RC_INIT2;- zip->bcj_state = 1;- }-- /*- * Gather the odd bytes of a previous call.- */- for (i = 0; zip->odd_bcj_size > 0 && outPos < outSize; i++) {- outBuf[outPos++] = zip->odd_bcj[i];- zip->odd_bcj_size--;- }-- if (outSize == 0) {- zip->bcj2_outPos += outPos;- return (outPos);- }-- for (;;) {- uint8_t b;- CProb *prob;- uint32_t bound;- uint32_t ttt;-- size_t limit = size0 - inPos;- if (outSize - outPos < limit)- limit = outSize - outPos;-- if (zip->bcj_state == 1) {- while (limit != 0) {- uint8_t bb = buf0[inPos];- outBuf[outPos++] = bb;- if (IsJ(zip->bcj2_prevByte, bb)) {- zip->bcj_state = 2;- break;- }- inPos++;- zip->bcj2_prevByte = bb;- limit--;- }- }-- if (limit == 0 || outPos == outSize)- break;- zip->bcj_state = 1;-- b = buf0[inPos++];-- if (b == 0xE8)- prob = zip->bcj2_p + zip->bcj2_prevByte;- else if (b == 0xE9)- prob = zip->bcj2_p + 256;- else- prob = zip->bcj2_p + 257;-- IF_BIT_0(prob) {- UPDATE_0(prob)- zip->bcj2_prevByte = b;- } else {- uint32_t dest;- const uint8_t *v;- uint8_t out[4];-- UPDATE_1(prob)- if (b == 0xE8) {- v = buf1;- if (size1 < 4)- return SZ_ERROR_DATA;- buf1 += 4;- size1 -= 4;- } else {- v = buf2;- if (size2 < 4)- return SZ_ERROR_DATA;- buf2 += 4;- size2 -= 4;- }- dest = (((uint32_t)v[0] << 24) |- ((uint32_t)v[1] << 16) |- ((uint32_t)v[2] << 8) |- ((uint32_t)v[3])) -- ((uint32_t)zip->bcj2_outPos + (uint32_t)outPos + 4);- out[0] = (uint8_t)dest;- out[1] = (uint8_t)(dest >> 8);- out[2] = (uint8_t)(dest >> 16);- out[3] = zip->bcj2_prevByte = (uint8_t)(dest >> 24);-- for (i = 0; i < 4 && outPos < outSize; i++)- outBuf[outPos++] = out[i];- if (i < 4) {- /*- * Save odd bytes which we could not add into- * the output buffer because of out of space.- */- zip->odd_bcj_size = 4 -i;- for (; i < 4; i++) {- j = i - 4 + (unsigned)zip->odd_bcj_size;- zip->odd_bcj[j] = out[i];- }- break;- }- }- }- zip->tmp_stream_bytes_remaining -= inPos;- zip->sub_stream_bytes_remaining[0] = size1;- zip->sub_stream_bytes_remaining[1] = size2;- zip->sub_stream_bytes_remaining[2] = bufferLim - buffer;- zip->bcj2_outPos += outPos;-- return ((ssize_t)outPos);-}-
− c/archive_read_support_format_all.c
@@ -1,89 +0,0 @@-/*-- * Copyright (c) 2003-2011 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_read_support_format_all.c 174991 2007-12-30 04:58:22Z kientzle $");--#include "archive.h"-#include "archive_private.h"--int-archive_read_support_format_all(struct archive *a)-{- archive_check_magic(a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_all");-- /* TODO: It would be nice to compute the ordering- * here automatically so that people who enable just- * a few formats can still get the benefits. That- * may just require the format registration to include- * a "maximum read-ahead" value (anything that uses seek- * would be essentially infinite read-ahead). The core- * bid management can then sort the bidders before calling- * them.- *- * If you implement the above, please return the list below- * to alphabetic order.- */-- /*- * These bidders are all pretty cheap; they just examine a- * small initial part of the archive. If one of these bids- * high, we can maybe avoid running any of the more expensive- * bidders below.- */- archive_read_support_format_ar(a);- archive_read_support_format_cpio(a);- archive_read_support_format_empty(a);- archive_read_support_format_lha(a);- archive_read_support_format_mtree(a);- archive_read_support_format_tar(a);- archive_read_support_format_xar(a);- archive_read_support_format_warc(a);-- /*- * Install expensive bidders last. By doing them last, we- * increase the chance that a high bid from someone else will- * make it unnecessary for these to do anything at all.- */- /* These three have potentially large look-ahead. */- archive_read_support_format_7zip(a);- archive_read_support_format_cab(a);- archive_read_support_format_rar(a);- archive_read_support_format_rar5(a);- archive_read_support_format_iso9660(a);- /* Seek is really bad, since it forces the read-ahead- * logic to discard buffered data. */- archive_read_support_format_zip(a);-- /* Note: We always return ARCHIVE_OK here, even if some of the- * above return ARCHIVE_WARN. The intent here is to enable- * "as much as possible." Clients who need specific- * compression should enable those individually so they can- * verify the level of support. */- /* Clear any warning messages set by the above functions. */- archive_clear_error(a);- return (ARCHIVE_OK);-}
− c/archive_read_support_format_ar.c
@@ -1,638 +0,0 @@-/*-- * Copyright (c) 2007 Kai Wang- * Copyright (c) 2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_ar.c 201101 2009-12-28 03:06:27Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_private.h"--struct ar {- int64_t entry_bytes_remaining;- /* unconsumed is purely to track data we've gotten from readahead,- * but haven't yet marked as consumed. Must be paired with- * entry_bytes_remaining usage/modification.- */- size_t entry_bytes_unconsumed;- int64_t entry_offset;- int64_t entry_padding;- char *strtab;- size_t strtab_size;- char read_global_header;-};--/*- * Define structure of the "ar" header.- */-#define AR_name_offset 0-#define AR_name_size 16-#define AR_date_offset 16-#define AR_date_size 12-#define AR_uid_offset 28-#define AR_uid_size 6-#define AR_gid_offset 34-#define AR_gid_size 6-#define AR_mode_offset 40-#define AR_mode_size 8-#define AR_size_offset 48-#define AR_size_size 10-#define AR_fmag_offset 58-#define AR_fmag_size 2--static int archive_read_format_ar_bid(struct archive_read *a, int);-static int archive_read_format_ar_cleanup(struct archive_read *a);-static int archive_read_format_ar_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset);-static int archive_read_format_ar_skip(struct archive_read *a);-static int archive_read_format_ar_read_header(struct archive_read *a,- struct archive_entry *e);-static uint64_t ar_atol8(const char *p, unsigned char_cnt);-static uint64_t ar_atol10(const char *p, unsigned char_cnt);-static int ar_parse_gnu_filename_table(struct archive_read *a);-static int ar_parse_common_header(struct ar *ar, struct archive_entry *,- const char *h);--int-archive_read_support_format_ar(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct ar *ar;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_ar");-- ar = (struct ar *)calloc(1, sizeof(*ar));- if (ar == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ar data");- return (ARCHIVE_FATAL);- }- ar->strtab = NULL;-- r = __archive_read_register_format(a,- ar,- "ar",- archive_read_format_ar_bid,- NULL,- archive_read_format_ar_read_header,- archive_read_format_ar_read_data,- archive_read_format_ar_skip,- NULL,- archive_read_format_ar_cleanup,- NULL,- NULL);-- if (r != ARCHIVE_OK) {- free(ar);- return (r);- }- return (ARCHIVE_OK);-}--static int-archive_read_format_ar_cleanup(struct archive_read *a)-{- struct ar *ar;-- ar = (struct ar *)(a->format->data);- free(ar->strtab);- free(ar);- (a->format->data) = NULL;- return (ARCHIVE_OK);-}--static int-archive_read_format_ar_bid(struct archive_read *a, int best_bid)-{- const void *h;-- (void)best_bid; /* UNUSED */-- /*- * Verify the 8-byte file signature.- * TODO: Do we need to check more than this?- */- if ((h = __archive_read_ahead(a, 8, NULL)) == NULL)- return (-1);- if (memcmp(h, "!<arch>\n", 8) == 0) {- return (64);- }- return (-1);-}--static int-_ar_read_header(struct archive_read *a, struct archive_entry *entry,- struct ar *ar, const char *h, size_t *unconsumed)-{- char filename[AR_name_size + 1];- uint64_t number; /* Used to hold parsed numbers before validation. */- size_t bsd_name_length, entry_size;- char *p, *st;- const void *b;- int r;-- /* Verify the magic signature on the file header. */- if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) {- archive_set_error(&a->archive, EINVAL,- "Incorrect file header signature");- return (ARCHIVE_FATAL);- }-- /* Copy filename into work buffer. */- strncpy(filename, h + AR_name_offset, AR_name_size);- filename[AR_name_size] = '\0';-- /*- * Guess the format variant based on the filename.- */- if (a->archive.archive_format == ARCHIVE_FORMAT_AR) {- /* We don't already know the variant, so let's guess. */- /*- * Biggest clue is presence of '/': GNU starts special- * filenames with '/', appends '/' as terminator to- * non-special names, so anything with '/' should be- * GNU except for BSD long filenames.- */- if (strncmp(filename, "#1/", 3) == 0)- a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD;- else if (strchr(filename, '/') != NULL)- a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU;- else if (strncmp(filename, "__.SYMDEF", 9) == 0)- a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD;- /*- * XXX Do GNU/SVR4 'ar' programs ever omit trailing '/'- * if name exactly fills 16-byte field? If so, we- * can't assume entries without '/' are BSD. XXX- */- }-- /* Update format name from the code. */- if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU)- a->archive.archive_format_name = "ar (GNU/SVR4)";- else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD)- a->archive.archive_format_name = "ar (BSD)";- else- a->archive.archive_format_name = "ar";-- /*- * Remove trailing spaces from the filename. GNU and BSD- * variants both pad filename area out with spaces.- * This will only be wrong if GNU/SVR4 'ar' implementations- * omit trailing '/' for 16-char filenames and we have- * a 16-char filename that ends in ' '.- */- p = filename + AR_name_size - 1;- while (p >= filename && *p == ' ') {- *p = '\0';- p--;- }-- /*- * Remove trailing slash unless first character is '/'.- * (BSD entries never end in '/', so this will only trim- * GNU-format entries. GNU special entries start with '/'- * and are not terminated in '/', so we don't trim anything- * that starts with '/'.)- */- if (filename[0] != '/' && p > filename && *p == '/') {- *p = '\0';- }-- if (p < filename) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Found entry with empty filename");- return (ARCHIVE_FATAL);- }-- /*- * '//' is the GNU filename table.- * Later entries can refer to names in this table.- */- if (strcmp(filename, "//") == 0) {- /* This must come before any call to _read_ahead. */- ar_parse_common_header(ar, entry, h);- archive_entry_copy_pathname(entry, filename);- archive_entry_set_filetype(entry, AE_IFREG);- /* Get the size of the filename table. */- number = ar_atol10(h + AR_size_offset, AR_size_size);- if (number > SIZE_MAX || number > 1024 * 1024 * 1024) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Filename table too large");- return (ARCHIVE_FATAL);- }- entry_size = (size_t)number;- if (entry_size == 0) {- archive_set_error(&a->archive, EINVAL,- "Invalid string table");- return (ARCHIVE_FATAL);- }- if (ar->strtab != NULL) {- archive_set_error(&a->archive, EINVAL,- "More than one string tables exist");- return (ARCHIVE_FATAL);- }-- /* Read the filename table into memory. */- st = malloc(entry_size);- if (st == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate filename table buffer");- return (ARCHIVE_FATAL);- }- ar->strtab = st;- ar->strtab_size = entry_size;-- if (*unconsumed) {- __archive_read_consume(a, *unconsumed);- *unconsumed = 0;- }-- if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL)- return (ARCHIVE_FATAL);- memcpy(st, b, entry_size);- __archive_read_consume(a, entry_size);- /* All contents are consumed. */- ar->entry_bytes_remaining = 0;- archive_entry_set_size(entry, ar->entry_bytes_remaining);-- /* Parse the filename table. */- return (ar_parse_gnu_filename_table(a));- }-- /*- * GNU variant handles long filenames by storing /<number>- * to indicate a name stored in the filename table.- * XXX TODO: Verify that it's all digits... Don't be fooled- * by "/9xyz" XXX- */- if (filename[0] == '/' && filename[1] >= '0' && filename[1] <= '9') {- number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1);- /*- * If we can't look up the real name, warn and return- * the entry with the wrong name.- */- if (ar->strtab == NULL || number >= ar->strtab_size) {- archive_set_error(&a->archive, EINVAL,- "Can't find long filename for GNU/SVR4 archive entry");- archive_entry_copy_pathname(entry, filename);- /* Parse the time, owner, mode, size fields. */- ar_parse_common_header(ar, entry, h);- return (ARCHIVE_FATAL);- }-- archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]);- /* Parse the time, owner, mode, size fields. */- return (ar_parse_common_header(ar, entry, h));- }-- /*- * BSD handles long filenames by storing "#1/" followed by the- * length of filename as a decimal number, then prepends the- * the filename to the file contents.- */- if (strncmp(filename, "#1/", 3) == 0) {- /* Parse the time, owner, mode, size fields. */- /* This must occur before _read_ahead is called again. */- ar_parse_common_header(ar, entry, h);-- /* Parse the size of the name, adjust the file size. */- number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3);- /* Sanity check the filename length:- * = Must be <= SIZE_MAX - 1- * = Must be <= 1MB- * = Cannot be bigger than the entire entry- */- if (number > SIZE_MAX - 1- || number > 1024 * 1024- || (int64_t)number > ar->entry_bytes_remaining) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Bad input file size");- return (ARCHIVE_FATAL);- }- bsd_name_length = (size_t)number;- ar->entry_bytes_remaining -= bsd_name_length;- /* Adjust file size reported to client. */- archive_entry_set_size(entry, ar->entry_bytes_remaining);-- if (*unconsumed) {- __archive_read_consume(a, *unconsumed);- *unconsumed = 0;- }-- /* Read the long name into memory. */- if ((b = __archive_read_ahead(a, bsd_name_length, NULL)) == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Truncated input file");- return (ARCHIVE_FATAL);- }- /* Store it in the entry. */- p = (char *)malloc(bsd_name_length + 1);- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate fname buffer");- return (ARCHIVE_FATAL);- }- strncpy(p, b, bsd_name_length);- p[bsd_name_length] = '\0';-- __archive_read_consume(a, bsd_name_length);-- archive_entry_copy_pathname(entry, p);- free(p);- return (ARCHIVE_OK);- }-- /*- * "/" is the SVR4/GNU archive symbol table.- * "/SYM64/" is the SVR4/GNU 64-bit variant archive symbol table.- */- if (strcmp(filename, "/") == 0 || strcmp(filename, "/SYM64/") == 0) {- archive_entry_copy_pathname(entry, filename);- /* Parse the time, owner, mode, size fields. */- r = ar_parse_common_header(ar, entry, h);- /* Force the file type to a regular file. */- archive_entry_set_filetype(entry, AE_IFREG);- return (r);- }-- /*- * "__.SYMDEF" is a BSD archive symbol table.- */- if (strcmp(filename, "__.SYMDEF") == 0) {- archive_entry_copy_pathname(entry, filename);- /* Parse the time, owner, mode, size fields. */- return (ar_parse_common_header(ar, entry, h));- }-- /*- * Otherwise, this is a standard entry. The filename- * has already been trimmed as much as possible, based- * on our current knowledge of the format.- */- archive_entry_copy_pathname(entry, filename);- return (ar_parse_common_header(ar, entry, h));-}--static int-archive_read_format_ar_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct ar *ar = (struct ar*)(a->format->data);- size_t unconsumed;- const void *header_data;- int ret;-- 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;- }-- /* Read the header for the next file entry. */- if ((header_data = __archive_read_ahead(a, 60, NULL)) == NULL)- /* Broken header. */- return (ARCHIVE_EOF);- - unconsumed = 60;- - ret = _ar_read_header(a, entry, ar, (const char *)header_data, &unconsumed);-- if (unconsumed)- __archive_read_consume(a, unconsumed);-- return ret;-}---static int-ar_parse_common_header(struct ar *ar, struct archive_entry *entry,- const char *h)-{- uint64_t n;-- /* Copy remaining header */- archive_entry_set_filetype(entry, AE_IFREG);- archive_entry_set_mtime(entry,- (time_t)ar_atol10(h + AR_date_offset, AR_date_size), 0L);- archive_entry_set_uid(entry,- (uid_t)ar_atol10(h + AR_uid_offset, AR_uid_size));- archive_entry_set_gid(entry,- (gid_t)ar_atol10(h + AR_gid_offset, AR_gid_size));- archive_entry_set_mode(entry,- (mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size));- n = ar_atol10(h + AR_size_offset, AR_size_size);-- ar->entry_offset = 0;- ar->entry_padding = n % 2;- archive_entry_set_size(entry, n);- ar->entry_bytes_remaining = n;- return (ARCHIVE_OK);-}--static int-archive_read_format_ar_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- ssize_t bytes_read;- struct ar *ar;-- ar = (struct ar *)(a->format->data);-- if (ar->entry_bytes_unconsumed) {- __archive_read_consume(a, ar->entry_bytes_unconsumed);- ar->entry_bytes_unconsumed = 0;- }-- if (ar->entry_bytes_remaining > 0) {- *buff = __archive_read_ahead(a, 1, &bytes_read);- if (bytes_read == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Truncated ar archive");- return (ARCHIVE_FATAL);- }- if (bytes_read < 0)- return (ARCHIVE_FATAL);- if (bytes_read > ar->entry_bytes_remaining)- bytes_read = (ssize_t)ar->entry_bytes_remaining;- *size = bytes_read;- ar->entry_bytes_unconsumed = bytes_read;- *offset = ar->entry_offset;- ar->entry_offset += bytes_read;- ar->entry_bytes_remaining -= bytes_read;- return (ARCHIVE_OK);- } else {- int64_t skipped = __archive_read_consume(a, ar->entry_padding);- if (skipped >= 0) {- ar->entry_padding -= skipped;- }- if (ar->entry_padding) {- if (skipped >= 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Truncated ar archive- failed consuming padding");- }- return (ARCHIVE_FATAL);- }- *buff = NULL;- *size = 0;- *offset = ar->entry_offset;- return (ARCHIVE_EOF);- }-}--static int-archive_read_format_ar_skip(struct archive_read *a)-{- int64_t bytes_skipped;- struct ar* ar;-- ar = (struct ar *)(a->format->data);-- bytes_skipped = __archive_read_consume(a,- ar->entry_bytes_remaining + ar->entry_padding- + ar->entry_bytes_unconsumed);- if (bytes_skipped < 0)- return (ARCHIVE_FATAL);-- ar->entry_bytes_remaining = 0;- ar->entry_bytes_unconsumed = 0;- ar->entry_padding = 0;-- return (ARCHIVE_OK);-}--static int-ar_parse_gnu_filename_table(struct archive_read *a)-{- struct ar *ar;- char *p;- size_t size;-- ar = (struct ar*)(a->format->data);- size = ar->strtab_size;-- for (p = ar->strtab; p < ar->strtab + size - 1; ++p) {- if (*p == '/') {- *p++ = '\0';- if (*p != '\n')- goto bad_string_table;- *p = '\0';- }- }- /*- * GNU ar always pads the table to an even size.- * The pad character is either '\n' or '`'.- */- if (p != ar->strtab + size && *p != '\n' && *p != '`')- goto bad_string_table;-- /* Enforce zero termination. */- ar->strtab[size - 1] = '\0';-- return (ARCHIVE_OK);--bad_string_table:- archive_set_error(&a->archive, EINVAL,- "Invalid string table");- free(ar->strtab);- ar->strtab = NULL;- return (ARCHIVE_FATAL);-}--static uint64_t-ar_atol8(const char *p, unsigned char_cnt)-{- uint64_t l, limit, last_digit_limit;- unsigned int digit, base;-- base = 8;- limit = UINT64_MAX / base;- last_digit_limit = UINT64_MAX % base;-- while ((*p == ' ' || *p == '\t') && char_cnt-- > 0)- p++;-- l = 0;- digit = *p - '0';- while (*p >= '0' && digit < base && char_cnt-- > 0) {- if (l>limit || (l == limit && digit > last_digit_limit)) {- l = UINT64_MAX; /* Truncate on overflow. */- break;- }- l = (l * base) + digit;- digit = *++p - '0';- }- return (l);-}--static uint64_t-ar_atol10(const char *p, unsigned char_cnt)-{- uint64_t l, limit, last_digit_limit;- unsigned int base, digit;-- base = 10;- limit = UINT64_MAX / base;- last_digit_limit = UINT64_MAX % base;-- while ((*p == ' ' || *p == '\t') && char_cnt-- > 0)- p++;- l = 0;- digit = *p - '0';- while (*p >= '0' && digit < base && char_cnt-- > 0) {- if (l > limit || (l == limit && digit > last_digit_limit)) {- l = UINT64_MAX; /* Truncate on overflow. */- break;- }- l = (l * base) + digit;- digit = *++p - '0';- }- return (l);-}
− c/archive_read_support_format_by_code.c
@@ -1,92 +0,0 @@-/*-- * Copyright (c) 2003-2011 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif--#include "archive.h"-#include "archive_private.h"--int-archive_read_support_format_by_code(struct archive *a, int format_code)-{- archive_check_magic(a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_by_code");-- switch (format_code & ARCHIVE_FORMAT_BASE_MASK) {- case ARCHIVE_FORMAT_7ZIP:- return archive_read_support_format_7zip(a);- break;- case ARCHIVE_FORMAT_AR:- return archive_read_support_format_ar(a);- break;- case ARCHIVE_FORMAT_CAB:- return archive_read_support_format_cab(a);- break;- case ARCHIVE_FORMAT_CPIO:- return archive_read_support_format_cpio(a);- break;- case ARCHIVE_FORMAT_EMPTY:- return archive_read_support_format_empty(a);- break;- case ARCHIVE_FORMAT_ISO9660:- return archive_read_support_format_iso9660(a);- break;- case ARCHIVE_FORMAT_LHA:- return archive_read_support_format_lha(a);- break;- case ARCHIVE_FORMAT_MTREE:- return archive_read_support_format_mtree(a);- break;- case ARCHIVE_FORMAT_RAR:- return archive_read_support_format_rar(a);- break;- case ARCHIVE_FORMAT_RAR_V5:- return archive_read_support_format_rar5(a);- break;- case ARCHIVE_FORMAT_RAW:- return archive_read_support_format_raw(a);- break;- case ARCHIVE_FORMAT_TAR:- return archive_read_support_format_tar(a);- break;- case ARCHIVE_FORMAT_WARC:- return archive_read_support_format_warc(a);- break;- case ARCHIVE_FORMAT_XAR:- return archive_read_support_format_xar(a);- break;- case ARCHIVE_FORMAT_ZIP:- return archive_read_support_format_zip(a);- break;- }- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,- "Invalid format code specified");- return (ARCHIVE_FATAL);-}
− c/archive_read_support_format_cab.c
@@ -1,3228 +0,0 @@-/*-- * Copyright (c) 2010-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_read_private.h"-#include "archive_endian.h"---struct lzx_dec {- /* Decoding status. */- int state;-- /*- * Window to see last decoded data, from 32KBi to 2MBi.- */- int w_size;- int w_mask;- /* Window buffer, which is a loop buffer. */- unsigned char *w_buff;- /* The insert position to the window. */- int w_pos;- /* The position where we can copy decoded code from the window. */- int copy_pos;- /* The length how many bytes we can copy decoded code from- * the window. */- int copy_len;- /* Translation reversal for x86 processor CALL byte sequence(E8).- * This is used for LZX only. */- uint32_t translation_size;- char translation;- char block_type;-#define VERBATIM_BLOCK 1-#define ALIGNED_OFFSET_BLOCK 2-#define UNCOMPRESSED_BLOCK 3- size_t block_size;- size_t block_bytes_avail;- /* Repeated offset. */- int r0, r1, r2;- unsigned char rbytes[4];- int rbytes_avail;- int length_header;- int position_slot;- int offset_bits;-- struct lzx_pos_tbl {- int base;- int footer_bits;- } *pos_tbl;- /*- * Bit stream reader.- */- struct lzx_br {-#define CACHE_TYPE uint64_t-#define CACHE_BITS (8 * sizeof(CACHE_TYPE))- /* Cache buffer. */- CACHE_TYPE cache_buffer;- /* Indicates how many bits avail in cache_buffer. */- int cache_avail;- unsigned char odd;- char have_odd;- } br;-- /*- * Huffman coding.- */- struct huffman {- int len_size;- int freq[17];- unsigned char *bitlen;-- /*- * Use a index table. It's faster than searching a huffman- * coding tree, which is a binary tree. But a use of a large- * index table causes L1 cache read miss many times.- */- int max_bits;- int tbl_bits;- int tree_used;- /* Direct access table. */- uint16_t *tbl;- } at, lt, mt, pt;-- int loop;- int error;-};--static const int slots[] = {- 30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290-};-#define SLOT_BASE 15-#define SLOT_MAX 21/*->25*/--struct lzx_stream {- const unsigned char *next_in;- int64_t avail_in;- int64_t total_in;- unsigned char *next_out;- int64_t avail_out;- int64_t total_out;- struct lzx_dec *ds;-};--/*- * Cabinet file definitions.- */-/* CFHEADER offset */-#define CFHEADER_signature 0-#define CFHEADER_cbCabinet 8-#define CFHEADER_coffFiles 16-#define CFHEADER_versionMinor 24-#define CFHEADER_versionMajor 25-#define CFHEADER_cFolders 26-#define CFHEADER_cFiles 28-#define CFHEADER_flags 30-#define CFHEADER_setID 32-#define CFHEADER_iCabinet 34-#define CFHEADER_cbCFHeader 36-#define CFHEADER_cbCFFolder 38-#define CFHEADER_cbCFData 39--/* CFFOLDER offset */-#define CFFOLDER_coffCabStart 0-#define CFFOLDER_cCFData 4-#define CFFOLDER_typeCompress 6-#define CFFOLDER_abReserve 8--/* CFFILE offset */-#define CFFILE_cbFile 0-#define CFFILE_uoffFolderStart 4-#define CFFILE_iFolder 8-#define CFFILE_date_time 10-#define CFFILE_attribs 14--/* CFDATA offset */-#define CFDATA_csum 0-#define CFDATA_cbData 4-#define CFDATA_cbUncomp 6--static const char * const compression_name[] = {- "NONE",- "MSZIP",- "Quantum",- "LZX",-};--struct cfdata {- /* Sum value of this CFDATA. */- uint32_t sum;- uint16_t compressed_size;- uint16_t compressed_bytes_remaining;- uint16_t uncompressed_size;- uint16_t uncompressed_bytes_remaining;- /* To know how many bytes we have decompressed. */- uint16_t uncompressed_avail;- /* Offset from the beginning of compressed data of this CFDATA */- uint16_t read_offset;- int64_t unconsumed;- /* To keep memory image of this CFDATA to compute the sum. */- size_t memimage_size;- unsigned char *memimage;- /* Result of calculation of sum. */- uint32_t sum_calculated;- unsigned char sum_extra[4];- int sum_extra_avail;- const void *sum_ptr;-};--struct cffolder {- uint32_t cfdata_offset_in_cab;- uint16_t cfdata_count;- uint16_t comptype;-#define COMPTYPE_NONE 0x0000-#define COMPTYPE_MSZIP 0x0001-#define COMPTYPE_QUANTUM 0x0002-#define COMPTYPE_LZX 0x0003- uint16_t compdata;- const char *compname;- /* At the time reading CFDATA */- struct cfdata cfdata;- int cfdata_index;- /* Flags to mark progress of decompression. */- char decompress_init;-};--struct cffile {- uint32_t uncompressed_size;- uint32_t offset;- time_t mtime;- uint16_t folder;-#define iFoldCONTINUED_FROM_PREV 0xFFFD-#define iFoldCONTINUED_TO_NEXT 0xFFFE-#define iFoldCONTINUED_PREV_AND_NEXT 0xFFFF- unsigned char attr;-#define ATTR_RDONLY 0x01-#define ATTR_NAME_IS_UTF 0x80- struct archive_string pathname;-};--struct cfheader {- /* Total bytes of all file size in a Cabinet. */- uint32_t total_bytes;- uint32_t files_offset;- uint16_t folder_count;- uint16_t file_count;- uint16_t flags;-#define PREV_CABINET 0x0001-#define NEXT_CABINET 0x0002-#define RESERVE_PRESENT 0x0004- uint16_t setid;- uint16_t cabinet;- /* Version number. */- unsigned char major;- unsigned char minor;- unsigned char cffolder;- unsigned char cfdata;- /* All folders in a cabinet. */- struct cffolder *folder_array;- /* All files in a cabinet. */- struct cffile *file_array;- int file_index;-};--struct cab {- /* entry_bytes_remaining is the number of bytes we expect. */- int64_t entry_offset;- int64_t entry_bytes_remaining;- int64_t entry_unconsumed;- int64_t entry_compressed_bytes_read;- int64_t entry_uncompressed_bytes_read;- struct cffolder *entry_cffolder;- struct cffile *entry_cffile;- struct cfdata *entry_cfdata;-- /* Offset from beginning of a cabinet file. */- int64_t cab_offset;- struct cfheader cfheader;- struct archive_wstring ws;-- /* Flag to mark progress that an archive was read their first header.*/- char found_header;- char end_of_archive;- char end_of_entry;- char end_of_entry_cleanup;- char read_data_invoked;- int64_t bytes_skipped;-- unsigned char *uncompressed_buffer;- size_t uncompressed_buffer_size;-- int init_default_conversion;- struct archive_string_conv *sconv;- struct archive_string_conv *sconv_default;- struct archive_string_conv *sconv_utf8;- char format_name[64];--#ifdef HAVE_ZLIB_H- z_stream stream;- char stream_valid;-#endif- struct lzx_stream xstrm;-};--static int archive_read_format_cab_bid(struct archive_read *, int);-static int archive_read_format_cab_options(struct archive_read *,- const char *, const char *);-static int archive_read_format_cab_read_header(struct archive_read *,- struct archive_entry *);-static int archive_read_format_cab_read_data(struct archive_read *,- const void **, size_t *, int64_t *);-static int archive_read_format_cab_read_data_skip(struct archive_read *);-static int archive_read_format_cab_cleanup(struct archive_read *);--static int cab_skip_sfx(struct archive_read *);-static time_t cab_dos_time(const unsigned char *);-static int cab_read_data(struct archive_read *, const void **,- size_t *, int64_t *);-static int cab_read_header(struct archive_read *);-static uint32_t cab_checksum_cfdata_4(const void *, size_t bytes, uint32_t);-static uint32_t cab_checksum_cfdata(const void *, size_t bytes, uint32_t);-static void cab_checksum_update(struct archive_read *, size_t);-static int cab_checksum_finish(struct archive_read *);-static int cab_next_cfdata(struct archive_read *);-static const void *cab_read_ahead_cfdata(struct archive_read *, ssize_t *);-static const void *cab_read_ahead_cfdata_none(struct archive_read *, ssize_t *);-static const void *cab_read_ahead_cfdata_deflate(struct archive_read *,- ssize_t *);-static const void *cab_read_ahead_cfdata_lzx(struct archive_read *,- ssize_t *);-static int64_t cab_consume_cfdata(struct archive_read *, int64_t);-static int64_t cab_minimum_consume_cfdata(struct archive_read *, int64_t);-static int lzx_decode_init(struct lzx_stream *, int);-static int lzx_read_blocks(struct lzx_stream *, int);-static int lzx_decode_blocks(struct lzx_stream *, int);-static void lzx_decode_free(struct lzx_stream *);-static void lzx_translation(struct lzx_stream *, void *, size_t, uint32_t);-static void lzx_cleanup_bitstream(struct lzx_stream *);-static int lzx_decode(struct lzx_stream *, int);-static int lzx_read_pre_tree(struct lzx_stream *);-static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);-static int lzx_huffman_init(struct huffman *, size_t, int);-static void lzx_huffman_free(struct huffman *);-static int lzx_make_huffman_table(struct huffman *);-static inline int lzx_decode_huffman(struct huffman *, unsigned);---int-archive_read_support_format_cab(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct cab *cab;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_cab");-- cab = (struct cab *)calloc(1, sizeof(*cab));- if (cab == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate CAB data");- return (ARCHIVE_FATAL);- }- archive_string_init(&cab->ws);- archive_wstring_ensure(&cab->ws, 256);-- r = __archive_read_register_format(a,- cab,- "cab",- archive_read_format_cab_bid,- archive_read_format_cab_options,- archive_read_format_cab_read_header,- archive_read_format_cab_read_data,- archive_read_format_cab_read_data_skip,- NULL,- archive_read_format_cab_cleanup,- NULL,- NULL);-- if (r != ARCHIVE_OK)- free(cab);- return (ARCHIVE_OK);-}--static int-find_cab_magic(const char *p)-{- switch (p[4]) {- case 0:- /*- * Note: Self-Extraction program has 'MSCF' string in their- * program. If we were finding 'MSCF' string only, we got- * wrong place for Cabinet header, thus, we have to check- * following four bytes which are reserved and must be set- * to zero.- */- if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)- return 0;- return 5;- case 'F': return 1;- case 'C': return 2;- case 'S': return 3;- case 'M': return 4;- default: return 5;- }-}--static int-archive_read_format_cab_bid(struct archive_read *a, int best_bid)-{- const char *p;- ssize_t bytes_avail, offset, window;-- /* If there's already a better bid than we can ever- make, don't bother testing. */- if (best_bid > 64)- return (-1);-- if ((p = __archive_read_ahead(a, 8, NULL)) == NULL)- return (-1);-- if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)- return (64);-- /*- * Attempt to handle self-extracting archives- * by noting a PE header and searching forward- * up to 128k for a 'MSCF' marker.- */- if (p[0] == 'M' && p[1] == 'Z') {- offset = 0;- window = 4096;- while (offset < (1024 * 128)) {- const char *h = __archive_read_ahead(a, offset + window,- &bytes_avail);- if (h == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < 128)- return (0);- continue;- }- p = h + offset;- while (p + 8 < h + bytes_avail) {- int next;- if ((next = find_cab_magic(p)) == 0)- return (64);- p += next;- }- offset = p - h;- }- }- return (0);-}--static int-archive_read_format_cab_options(struct archive_read *a,- const char *key, const char *val)-{- struct cab *cab;- int ret = ARCHIVE_FAILED;-- cab = (struct cab *)(a->format->data);- if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "cab: hdrcharset option needs a character-set name");- else {- cab->sconv = archive_string_conversion_from_charset(- &a->archive, val, 0);- if (cab->sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-cab_skip_sfx(struct archive_read *a)-{- const char *p, *q;- size_t skip;- ssize_t bytes, window;-- window = 4096;- for (;;) {- const char *h = __archive_read_ahead(a, window, &bytes);- if (h == NULL) {- /* Remaining size are less than window. */- window >>= 1;- if (window < 128) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Couldn't find out CAB header");- return (ARCHIVE_FATAL);- }- continue;- }- p = h;- q = p + bytes;-- /*- * Scan ahead until we find something that looks- * like the cab header.- */- while (p + 8 < q) {- int next;- if ((next = find_cab_magic(p)) == 0) {- skip = p - h;- __archive_read_consume(a, skip);- return (ARCHIVE_OK);- }- p += next;- }- skip = p - h;- __archive_read_consume(a, skip);- }-}--static int-truncated_error(struct archive_read *a)-{- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated CAB header");- return (ARCHIVE_FATAL);-}--static ssize_t-cab_strnlen(const unsigned char *p, size_t maxlen)-{- size_t i;-- for (i = 0; i <= maxlen; i++) {- if (p[i] == 0)- break;- }- if (i > maxlen)- return (-1);/* invalid */- return ((ssize_t)i);-}--/* Read bytes as much as remaining. */-static const void *-cab_read_ahead_remaining(struct archive_read *a, size_t min, ssize_t *avail)-{- const void *p;-- while (min > 0) {- p = __archive_read_ahead(a, min, avail);- if (p != NULL)- return (p);- min--;- }- return (NULL);-}--/* Convert a path separator '\' -> '/' */-static int-cab_convert_path_separator_1(struct archive_string *fn, unsigned char attr)-{- size_t i;- int mb;-- /* Easy check if we have '\' in multi-byte string. */- mb = 0;- for (i = 0; i < archive_strlen(fn); i++) {- if (fn->s[i] == '\\') {- if (mb) {- /* This may be second byte of multi-byte- * character. */- break;- }- fn->s[i] = '/';- mb = 0;- } else if ((fn->s[i] & 0x80) && !(attr & ATTR_NAME_IS_UTF))- mb = 1;- else- mb = 0;- }- if (i == archive_strlen(fn))- return (0);- return (-1);-}--/*- * Replace a character '\' with '/' in wide character.- */-static void-cab_convert_path_separator_2(struct cab *cab, struct archive_entry *entry)-{- const wchar_t *wp;- size_t i;-- /* If a conversion to wide character failed, force the replacement. */- if ((wp = archive_entry_pathname_w(entry)) != NULL) {- archive_wstrcpy(&(cab->ws), wp);- for (i = 0; i < archive_strlen(&(cab->ws)); i++) {- if (cab->ws.s[i] == L'\\')- cab->ws.s[i] = L'/';- }- archive_entry_copy_pathname_w(entry, cab->ws.s);- }-}--/*- * Read CFHEADER, CFFOLDER and CFFILE.- */-static int-cab_read_header(struct archive_read *a)-{- const unsigned char *p;- struct cab *cab;- struct cfheader *hd;- size_t bytes, used;- ssize_t len;- int64_t skip;- int err, i;- int cur_folder, prev_folder;- uint32_t offset32;- - a->archive.archive_format = ARCHIVE_FORMAT_CAB;- if (a->archive.archive_format_name == NULL)- a->archive.archive_format_name = "CAB";-- if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)- return (truncated_error(a));-- cab = (struct cab *)(a->format->data);- if (cab->found_header == 0 &&- p[0] == 'M' && p[1] == 'Z') {- /* This is an executable? Must be self-extracting... */- err = cab_skip_sfx(a);- if (err < ARCHIVE_WARN)- return (err);-- /* Re-read header after processing the SFX. */- if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)- return (truncated_error(a));- }-- cab->cab_offset = 0;- /*- * Read CFHEADER.- */- hd = &cab->cfheader;- if (p[CFHEADER_signature+0] != 'M' || p[CFHEADER_signature+1] != 'S' ||- p[CFHEADER_signature+2] != 'C' || p[CFHEADER_signature+3] != 'F') {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Couldn't find out CAB header");- return (ARCHIVE_FATAL);- }- hd->total_bytes = archive_le32dec(p + CFHEADER_cbCabinet);- hd->files_offset = archive_le32dec(p + CFHEADER_coffFiles);- hd->minor = p[CFHEADER_versionMinor];- hd->major = p[CFHEADER_versionMajor];- hd->folder_count = archive_le16dec(p + CFHEADER_cFolders);- if (hd->folder_count == 0)- goto invalid;- hd->file_count = archive_le16dec(p + CFHEADER_cFiles);- if (hd->file_count == 0)- goto invalid;- hd->flags = archive_le16dec(p + CFHEADER_flags);- hd->setid = archive_le16dec(p + CFHEADER_setID);- hd->cabinet = archive_le16dec(p + CFHEADER_iCabinet);- used = CFHEADER_iCabinet + 2;- if (hd->flags & RESERVE_PRESENT) {- uint16_t cfheader;- cfheader = archive_le16dec(p + CFHEADER_cbCFHeader);- if (cfheader > 60000U)- goto invalid;- hd->cffolder = p[CFHEADER_cbCFFolder];- hd->cfdata = p[CFHEADER_cbCFData];- used += 4;/* cbCFHeader, cbCFFolder and cbCFData */- used += cfheader;/* abReserve */- } else- hd->cffolder = 0;/* Avoid compiling warning. */- if (hd->flags & PREV_CABINET) {- /* How many bytes are used for szCabinetPrev. */- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)- return (truncated_error(a));- if ((len = cab_strnlen(p + used, 255)) <= 0)- goto invalid;- used += len + 1;- /* How many bytes are used for szDiskPrev. */- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)- return (truncated_error(a));- if ((len = cab_strnlen(p + used, 255)) <= 0)- goto invalid;- used += len + 1;- }- if (hd->flags & NEXT_CABINET) {- /* How many bytes are used for szCabinetNext. */- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)- return (truncated_error(a));- if ((len = cab_strnlen(p + used, 255)) <= 0)- goto invalid;- used += len + 1;- /* How many bytes are used for szDiskNext. */- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)- return (truncated_error(a));- if ((len = cab_strnlen(p + used, 255)) <= 0)- goto invalid;- used += len + 1;- }- __archive_read_consume(a, used);- cab->cab_offset += used;- used = 0;-- /*- * Read CFFOLDER.- */- hd->folder_array = (struct cffolder *)calloc(- hd->folder_count, sizeof(struct cffolder));- if (hd->folder_array == NULL)- goto nomem;- - bytes = 8;- if (hd->flags & RESERVE_PRESENT)- bytes += hd->cffolder;- bytes *= hd->folder_count;- if ((p = __archive_read_ahead(a, bytes, NULL)) == NULL)- return (truncated_error(a));- offset32 = 0;- for (i = 0; i < hd->folder_count; i++) {- struct cffolder *folder = &(hd->folder_array[i]);- folder->cfdata_offset_in_cab =- archive_le32dec(p + CFFOLDER_coffCabStart);- folder->cfdata_count = archive_le16dec(p+CFFOLDER_cCFData);- folder->comptype =- archive_le16dec(p+CFFOLDER_typeCompress) & 0x0F;- folder->compdata =- archive_le16dec(p+CFFOLDER_typeCompress) >> 8;- /* Get a compression name. */- if (folder->comptype <- sizeof(compression_name) / sizeof(compression_name[0]))- folder->compname = compression_name[folder->comptype];- else- folder->compname = "UNKNOWN";- p += 8;- used += 8;- if (hd->flags & RESERVE_PRESENT) {- p += hd->cffolder;/* abReserve */- used += hd->cffolder;- }- /*- * Sanity check if each data is acceptable.- */- if (offset32 >= folder->cfdata_offset_in_cab)- goto invalid;- offset32 = folder->cfdata_offset_in_cab;-- /* Set a request to initialize zlib for the CFDATA of- * this folder. */- folder->decompress_init = 0;- }- __archive_read_consume(a, used);- cab->cab_offset += used;-- /*- * Read CFFILE.- */- /* Seek read pointer to the offset of CFFILE if needed. */- skip = (int64_t)hd->files_offset - cab->cab_offset;- if (skip < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid offset of CFFILE %jd < %jd",- (intmax_t)hd->files_offset, (intmax_t)cab->cab_offset);- return (ARCHIVE_FATAL);- }- if (skip) {- __archive_read_consume(a, skip);- cab->cab_offset += skip;- }- /* Allocate memory for CFDATA */- hd->file_array = (struct cffile *)calloc(- hd->file_count, sizeof(struct cffile));- if (hd->file_array == NULL)- goto nomem;-- prev_folder = -1;- for (i = 0; i < hd->file_count; i++) {- struct cffile *file = &(hd->file_array[i]);- ssize_t avail;-- if ((p = __archive_read_ahead(a, 16, NULL)) == NULL)- return (truncated_error(a));- file->uncompressed_size = archive_le32dec(p + CFFILE_cbFile);- file->offset = archive_le32dec(p + CFFILE_uoffFolderStart);- file->folder = archive_le16dec(p + CFFILE_iFolder);- file->mtime = cab_dos_time(p + CFFILE_date_time);- file->attr = (uint8_t)archive_le16dec(p + CFFILE_attribs);- __archive_read_consume(a, 16);-- cab->cab_offset += 16;- if ((p = cab_read_ahead_remaining(a, 256, &avail)) == NULL)- return (truncated_error(a));- if ((len = cab_strnlen(p, avail-1)) <= 0)- goto invalid;-- /* Copy a pathname. */- archive_string_init(&(file->pathname));- archive_strncpy(&(file->pathname), p, len);- __archive_read_consume(a, len + 1);- cab->cab_offset += len + 1;-- /*- * Sanity check if each data is acceptable.- */- if (file->uncompressed_size > 0x7FFF8000)- goto invalid;/* Too large */- if ((int64_t)file->offset + (int64_t)file->uncompressed_size- > ARCHIVE_LITERAL_LL(0x7FFF8000))- goto invalid;/* Too large */- switch (file->folder) {- case iFoldCONTINUED_TO_NEXT:- /* This must be last file in a folder. */- if (i != hd->file_count -1)- goto invalid;- cur_folder = hd->folder_count -1;- break;- case iFoldCONTINUED_PREV_AND_NEXT:- /* This must be only one file in a folder. */- if (hd->file_count != 1)- goto invalid;- /* FALL THROUGH */- case iFoldCONTINUED_FROM_PREV:- /* This must be first file in a folder. */- if (i != 0)- goto invalid;- prev_folder = cur_folder = 0;- offset32 = file->offset;- break;- default:- if (file->folder >= hd->folder_count)- goto invalid;- cur_folder = file->folder;- break;- }- /* Dot not back track. */- if (cur_folder < prev_folder)- goto invalid;- if (cur_folder != prev_folder)- offset32 = 0;- prev_folder = cur_folder;-- /* Make sure there are not any blanks from last file- * contents. */- if (offset32 != file->offset)- goto invalid;- offset32 += file->uncompressed_size;-- /* CFDATA is available for file contents. */- if (file->uncompressed_size > 0 &&- hd->folder_array[cur_folder].cfdata_count == 0)- goto invalid;- }-- if (hd->cabinet != 0 || hd->flags & (PREV_CABINET | NEXT_CABINET)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Multivolume cabinet file is unsupported");- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-invalid:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid CAB header");- return (ARCHIVE_FATAL);-nomem:- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for CAB data");- return (ARCHIVE_FATAL);-}--static int-archive_read_format_cab_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct cab *cab;- struct cfheader *hd;- struct cffolder *prev_folder;- struct cffile *file;- struct archive_string_conv *sconv;- int err = ARCHIVE_OK, r;- - cab = (struct cab *)(a->format->data);- if (cab->found_header == 0) {- err = cab_read_header(a); - if (err < ARCHIVE_WARN)- return (err);- /* We've found the header. */- cab->found_header = 1;- }- hd = &cab->cfheader;-- if (hd->file_index >= hd->file_count) {- cab->end_of_archive = 1;- return (ARCHIVE_EOF);- }- file = &hd->file_array[hd->file_index++];-- cab->end_of_entry = 0;- cab->end_of_entry_cleanup = 0;- cab->entry_compressed_bytes_read = 0;- cab->entry_uncompressed_bytes_read = 0;- cab->entry_unconsumed = 0;- cab->entry_cffile = file;-- /*- * Choose a proper folder.- */- prev_folder = cab->entry_cffolder;- switch (file->folder) {- case iFoldCONTINUED_FROM_PREV:- case iFoldCONTINUED_PREV_AND_NEXT:- cab->entry_cffolder = &hd->folder_array[0];- break;- case iFoldCONTINUED_TO_NEXT:- cab->entry_cffolder = &hd->folder_array[hd->folder_count-1];- break;- default:- cab->entry_cffolder = &hd->folder_array[file->folder];- break;- }- /* If a cffolder of this file is changed, reset a cfdata to read- * file contents from next cfdata. */- if (prev_folder != cab->entry_cffolder)- cab->entry_cfdata = NULL;-- /* If a pathname is UTF-8, prepare a string conversion object- * for UTF-8 and use it. */- if (file->attr & ATTR_NAME_IS_UTF) {- if (cab->sconv_utf8 == NULL) {- cab->sconv_utf8 =- archive_string_conversion_from_charset(- &(a->archive), "UTF-8", 1);- if (cab->sconv_utf8 == NULL)- return (ARCHIVE_FATAL);- }- sconv = cab->sconv_utf8;- } else if (cab->sconv != NULL) {- /* Choose the conversion specified by the option. */- sconv = cab->sconv;- } else {- /* Choose the default conversion. */- if (!cab->init_default_conversion) {- cab->sconv_default =- archive_string_default_conversion_for_read(- &(a->archive));- cab->init_default_conversion = 1;- }- sconv = cab->sconv_default;- }-- /*- * Set a default value and common data- */- r = cab_convert_path_separator_1(&(file->pathname), file->attr);- if (archive_entry_copy_pathname_l(entry, file->pathname.s,- archive_strlen(&(file->pathname)), sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname cannot be converted "- "from %s to current locale.",- archive_string_conversion_charset_name(sconv));- err = ARCHIVE_WARN;- }- if (r < 0) {- /* Convert a path separator '\' -> '/' */- cab_convert_path_separator_2(cab, entry);- }-- archive_entry_set_size(entry, file->uncompressed_size);- if (file->attr & ATTR_RDONLY)- archive_entry_set_mode(entry, AE_IFREG | 0555);- else- archive_entry_set_mode(entry, AE_IFREG | 0666);- archive_entry_set_mtime(entry, file->mtime, 0);-- cab->entry_bytes_remaining = file->uncompressed_size;- cab->entry_offset = 0;- /* We don't need compress data. */- if (file->uncompressed_size == 0)- cab->end_of_entry_cleanup = cab->end_of_entry = 1;-- /* Set up a more descriptive format name. */- snprintf(cab->format_name, sizeof(cab->format_name), "CAB %d.%d (%s)",- hd->major, hd->minor, cab->entry_cffolder->compname);- a->archive.archive_format_name = cab->format_name;-- return (err);-}--static int-archive_read_format_cab_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- struct cab *cab = (struct cab *)(a->format->data);- int r;-- switch (cab->entry_cffile->folder) {- case iFoldCONTINUED_FROM_PREV:- case iFoldCONTINUED_TO_NEXT:- case iFoldCONTINUED_PREV_AND_NEXT:- *buff = NULL;- *size = 0;- *offset = 0;- archive_clear_error(&a->archive);- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Cannot restore this file split in multivolume.");- return (ARCHIVE_FAILED);- default:- break;- }- if (cab->read_data_invoked == 0) {- if (cab->bytes_skipped) {- if (cab->entry_cfdata == NULL) {- r = cab_next_cfdata(a);- if (r < 0)- return (r);- }- if (cab_consume_cfdata(a, cab->bytes_skipped) < 0)- return (ARCHIVE_FATAL);- cab->bytes_skipped = 0;- }- cab->read_data_invoked = 1;- }- if (cab->entry_unconsumed) {- /* Consume as much as the compressor actually used. */- r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);- cab->entry_unconsumed = 0;- if (r < 0)- return (r);- }- if (cab->end_of_archive || cab->end_of_entry) {- if (!cab->end_of_entry_cleanup) {- /* End-of-entry cleanup done. */- cab->end_of_entry_cleanup = 1;- }- *offset = cab->entry_offset;- *size = 0;- *buff = NULL;- return (ARCHIVE_EOF);- }-- return (cab_read_data(a, buff, size, offset));-}--static uint32_t-cab_checksum_cfdata_4(const void *p, size_t bytes, uint32_t seed)-{- const unsigned char *b;- unsigned u32num;- uint32_t sum;-- u32num = (unsigned)bytes / 4;- sum = seed;- b = p;- for (;u32num > 0; --u32num) {- sum ^= archive_le32dec(b);- b += 4;- }- return (sum);-}--static uint32_t-cab_checksum_cfdata(const void *p, size_t bytes, uint32_t seed)-{- const unsigned char *b;- uint32_t sum;- uint32_t t;-- sum = cab_checksum_cfdata_4(p, bytes, seed);- b = p;- b += bytes & ~3;- t = 0;- switch (bytes & 3) {- case 3:- t |= ((uint32_t)(*b++)) << 16;- /* FALL THROUGH */- case 2:- t |= ((uint32_t)(*b++)) << 8;- /* FALL THROUGH */- case 1:- t |= *b;- /* FALL THROUGH */- default:- break;- }- sum ^= t;-- return (sum);-}--static void-cab_checksum_update(struct archive_read *a, size_t bytes)-{- struct cab *cab = (struct cab *)(a->format->data);- struct cfdata *cfdata = cab->entry_cfdata;- const unsigned char *p;- size_t sumbytes;-- if (cfdata->sum == 0 || cfdata->sum_ptr == NULL)- return;- /*- * Calculate the sum of this CFDATA.- * Make sure CFDATA must be calculated in four bytes.- */- p = cfdata->sum_ptr;- sumbytes = bytes;- if (cfdata->sum_extra_avail) {- while (cfdata->sum_extra_avail < 4 && sumbytes > 0) {- cfdata->sum_extra[- cfdata->sum_extra_avail++] = *p++;- sumbytes--;- }- if (cfdata->sum_extra_avail == 4) {- cfdata->sum_calculated = cab_checksum_cfdata_4(- cfdata->sum_extra, 4, cfdata->sum_calculated);- cfdata->sum_extra_avail = 0;- }- }- if (sumbytes) {- int odd = sumbytes & 3;- if ((int)(sumbytes - odd) > 0)- cfdata->sum_calculated = cab_checksum_cfdata_4(- p, sumbytes - odd, cfdata->sum_calculated);- if (odd)- memcpy(cfdata->sum_extra, p + sumbytes - odd, odd);- cfdata->sum_extra_avail = odd;- }- cfdata->sum_ptr = NULL;-}--static int-cab_checksum_finish(struct archive_read *a)-{- struct cab *cab = (struct cab *)(a->format->data);- struct cfdata *cfdata = cab->entry_cfdata;- int l;-- /* Do not need to compute a sum. */- if (cfdata->sum == 0)- return (ARCHIVE_OK);-- /*- * Calculate the sum of remaining CFDATA.- */- if (cfdata->sum_extra_avail) {- cfdata->sum_calculated =- cab_checksum_cfdata(cfdata->sum_extra,- cfdata->sum_extra_avail, cfdata->sum_calculated);- cfdata->sum_extra_avail = 0;- }-- l = 4;- if (cab->cfheader.flags & RESERVE_PRESENT)- l += cab->cfheader.cfdata;- cfdata->sum_calculated = cab_checksum_cfdata(- cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);- if (cfdata->sum_calculated != cfdata->sum) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Checksum error CFDATA[%d] %" PRIx32 ":%" PRIx32 " in %d bytes",- cab->entry_cffolder->cfdata_index -1,- cfdata->sum, cfdata->sum_calculated,- cfdata->compressed_size);- return (ARCHIVE_FAILED);-#endif- }- return (ARCHIVE_OK);-}--/*- * Read CFDATA if needed.- */-static int-cab_next_cfdata(struct archive_read *a)-{- struct cab *cab = (struct cab *)(a->format->data);- struct cfdata *cfdata = cab->entry_cfdata;-- /* There are remaining bytes in current CFDATA, use it first. */- if (cfdata != NULL && cfdata->uncompressed_bytes_remaining > 0)- return (ARCHIVE_OK);-- if (cfdata == NULL) {- int64_t skip;-- cab->entry_cffolder->cfdata_index = 0;-- /* Seek read pointer to the offset of CFDATA if needed. */- skip = cab->entry_cffolder->cfdata_offset_in_cab- - cab->cab_offset;- if (skip < 0) {- int folder_index;- switch (cab->entry_cffile->folder) {- case iFoldCONTINUED_FROM_PREV:- case iFoldCONTINUED_PREV_AND_NEXT:- folder_index = 0;- break;- case iFoldCONTINUED_TO_NEXT:- folder_index = cab->cfheader.folder_count-1;- break;- default:- folder_index = cab->entry_cffile->folder;- break;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid offset of CFDATA in folder(%d) %jd < %jd",- folder_index,- (intmax_t)cab->entry_cffolder->cfdata_offset_in_cab,- (intmax_t)cab->cab_offset);- return (ARCHIVE_FATAL);- }- if (skip > 0) {- if (__archive_read_consume(a, skip) < 0)- return (ARCHIVE_FATAL);- cab->cab_offset =- cab->entry_cffolder->cfdata_offset_in_cab;- }- }-- /*- * Read a CFDATA.- */- if (cab->entry_cffolder->cfdata_index <- cab->entry_cffolder->cfdata_count) {- const unsigned char *p;- int l;-- cfdata = &(cab->entry_cffolder->cfdata);- cab->entry_cffolder->cfdata_index++;- cab->entry_cfdata = cfdata;- cfdata->sum_calculated = 0;- cfdata->sum_extra_avail = 0;- cfdata->sum_ptr = NULL;- l = 8;- if (cab->cfheader.flags & RESERVE_PRESENT)- l += cab->cfheader.cfdata;- if ((p = __archive_read_ahead(a, l, NULL)) == NULL)- return (truncated_error(a));- cfdata->sum = archive_le32dec(p + CFDATA_csum);- cfdata->compressed_size = archive_le16dec(p + CFDATA_cbData);- cfdata->compressed_bytes_remaining = cfdata->compressed_size;- cfdata->uncompressed_size =- archive_le16dec(p + CFDATA_cbUncomp);- cfdata->uncompressed_bytes_remaining =- cfdata->uncompressed_size;- cfdata->uncompressed_avail = 0;- cfdata->read_offset = 0;- cfdata->unconsumed = 0;-- /*- * Sanity check if data size is acceptable.- */- if (cfdata->compressed_size == 0 ||- cfdata->compressed_size > (0x8000+6144))- goto invalid;- if (cfdata->uncompressed_size > 0x8000)- goto invalid;- if (cfdata->uncompressed_size == 0) {- switch (cab->entry_cffile->folder) {- case iFoldCONTINUED_PREV_AND_NEXT:- case iFoldCONTINUED_TO_NEXT:- break;- case iFoldCONTINUED_FROM_PREV:- default:- goto invalid;- }- }- /* If CFDATA is not last in a folder, an uncompressed- * size must be 0x8000(32KBi) */- if ((cab->entry_cffolder->cfdata_index <- cab->entry_cffolder->cfdata_count) &&- cfdata->uncompressed_size != 0x8000)- goto invalid;-- /* A compressed data size and an uncompressed data size must- * be the same in no compression mode. */- if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&- cfdata->compressed_size != cfdata->uncompressed_size)- goto invalid;-- /*- * Save CFDATA image for sum check.- */- if (cfdata->memimage_size < (size_t)l) {- free(cfdata->memimage);- cfdata->memimage = malloc(l);- if (cfdata->memimage == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for CAB data");- return (ARCHIVE_FATAL);- }- cfdata->memimage_size = l;- }- memcpy(cfdata->memimage, p, l);-- /* Consume bytes as much as we used. */- __archive_read_consume(a, l);- cab->cab_offset += l;- } else if (cab->entry_cffolder->cfdata_count > 0) {- /* Run out of all CFDATA in a folder. */- cfdata->compressed_size = 0;- cfdata->uncompressed_size = 0;- cfdata->compressed_bytes_remaining = 0;- cfdata->uncompressed_bytes_remaining = 0;- } else {- /* Current folder does not have any CFDATA. */- cfdata = &(cab->entry_cffolder->cfdata);- cab->entry_cfdata = cfdata;- memset(cfdata, 0, sizeof(*cfdata));- }- return (ARCHIVE_OK);-invalid:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid CFDATA");- return (ARCHIVE_FATAL);-}--/*- * Read ahead CFDATA.- */-static const void *-cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)-{- struct cab *cab = (struct cab *)(a->format->data);- int err;-- err = cab_next_cfdata(a);- if (err < ARCHIVE_OK) {- *avail = err;- return (NULL);- }-- switch (cab->entry_cffolder->comptype) {- case COMPTYPE_NONE:- return (cab_read_ahead_cfdata_none(a, avail));- case COMPTYPE_MSZIP:- return (cab_read_ahead_cfdata_deflate(a, avail));- case COMPTYPE_LZX:- return (cab_read_ahead_cfdata_lzx(a, avail));- default: /* Unsupported compression. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported CAB compression : %s",- cab->entry_cffolder->compname);- *avail = ARCHIVE_FAILED;- return (NULL);- }-}--/*- * Read ahead CFDATA as uncompressed data.- */-static const void *-cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)-{- struct cab *cab = (struct cab *)(a->format->data);- struct cfdata *cfdata;- const void *d;-- cfdata = cab->entry_cfdata;-- /*- * Note: '1' here is a performance optimization.- * Recall that the decompression layer returns a count of- * available bytes; asking for more than that forces the- * decompressor to combine reads by copying data.- */- d = __archive_read_ahead(a, 1, avail);- if (*avail <= 0) {- *avail = truncated_error(a);- return (NULL);- }- if (*avail > cfdata->uncompressed_bytes_remaining)- *avail = cfdata->uncompressed_bytes_remaining;- cfdata->uncompressed_avail = cfdata->uncompressed_size;- cfdata->unconsumed = *avail;- cfdata->sum_ptr = d;- return (d);-}--/*- * Read ahead CFDATA as deflate data.- */-#ifdef HAVE_ZLIB_H-static const void *-cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)-{- struct cab *cab = (struct cab *)(a->format->data);- struct cfdata *cfdata;- const void *d;- int r, mszip;- uint16_t uavail;- char eod = 0;-- cfdata = cab->entry_cfdata;- /* If the buffer hasn't been allocated, allocate it now. */- if (cab->uncompressed_buffer == NULL) {- cab->uncompressed_buffer_size = 0x8000;- cab->uncompressed_buffer- = (unsigned char *)malloc(cab->uncompressed_buffer_size);- if (cab->uncompressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for CAB reader");- *avail = ARCHIVE_FATAL;- return (NULL);- }- }-- uavail = cfdata->uncompressed_avail;- if (uavail == cfdata->uncompressed_size) {- d = cab->uncompressed_buffer + cfdata->read_offset;- *avail = uavail - cfdata->read_offset;- return (d);- }-- if (!cab->entry_cffolder->decompress_init) {- cab->stream.next_in = NULL;- cab->stream.avail_in = 0;- cab->stream.total_in = 0;- cab->stream.next_out = NULL;- cab->stream.avail_out = 0;- cab->stream.total_out = 0;- if (cab->stream_valid)- r = inflateReset(&cab->stream);- else- r = inflateInit2(&cab->stream,- -15 /* Don't check for zlib header */);- if (r != Z_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't initialize deflate decompression.");- *avail = ARCHIVE_FATAL;- return (NULL);- }- /* Stream structure has been set up. */- cab->stream_valid = 1;- /* We've initialized decompression for this stream. */- cab->entry_cffolder->decompress_init = 1;- }-- if (cfdata->compressed_bytes_remaining == cfdata->compressed_size)- mszip = 2;- else- mszip = 0;- eod = 0;- cab->stream.total_out = uavail;- /*- * We always uncompress all data in current CFDATA.- */- while (!eod && cab->stream.total_out < cfdata->uncompressed_size) {- ssize_t bytes_avail;-- cab->stream.next_out =- cab->uncompressed_buffer + cab->stream.total_out;- cab->stream.avail_out =- cfdata->uncompressed_size - cab->stream.total_out;-- d = __archive_read_ahead(a, 1, &bytes_avail);- if (bytes_avail <= 0) {- *avail = truncated_error(a);- return (NULL);- }- if (bytes_avail > cfdata->compressed_bytes_remaining)- bytes_avail = cfdata->compressed_bytes_remaining;- /*- * A bug in zlib.h: stream.next_in should be marked 'const'- * but isn't (the library never alters data through the- * next_in pointer, only reads it). The result: this ugly- * cast to remove 'const'.- */- cab->stream.next_in = (Bytef *)(uintptr_t)d;- cab->stream.avail_in = (uInt)bytes_avail;- cab->stream.total_in = 0;-- /* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */- if (mszip > 0) {- if (bytes_avail <= 0)- goto nomszip;- if (bytes_avail <= mszip) {- if (mszip == 2) {- if (cab->stream.next_in[0] != 0x43)- goto nomszip;- if (bytes_avail > 1 &&- cab->stream.next_in[1] != 0x4b)- goto nomszip;- } else if (cab->stream.next_in[0] != 0x4b)- goto nomszip;- cfdata->unconsumed = bytes_avail;- cfdata->sum_ptr = d;- if (cab_minimum_consume_cfdata(- a, cfdata->unconsumed) < 0) {- *avail = ARCHIVE_FATAL;- return (NULL);- }- mszip -= (int)bytes_avail;- continue;- }- if (mszip == 1 && cab->stream.next_in[0] != 0x4b)- goto nomszip;- else if (mszip == 2 && (cab->stream.next_in[0] != 0x43 ||- cab->stream.next_in[1] != 0x4b))- goto nomszip;- cab->stream.next_in += mszip;- cab->stream.avail_in -= mszip;- cab->stream.total_in += mszip;- mszip = 0;- }-- r = inflate(&cab->stream, 0);- switch (r) {- case Z_OK:- break;- case Z_STREAM_END:- eod = 1;- break;- default:- goto zlibfailed;- }- cfdata->unconsumed = cab->stream.total_in;- cfdata->sum_ptr = d;- if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {- *avail = ARCHIVE_FATAL;- return (NULL);- }- }- uavail = (uint16_t)cab->stream.total_out;-- if (uavail < cfdata->uncompressed_size) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid uncompressed size (%d < %d)",- uavail, cfdata->uncompressed_size);- *avail = ARCHIVE_FATAL;- return (NULL);- }-- /*- * Note: I suspect there is a bug in makecab.exe because, in rare- * case, compressed bytes are still remaining regardless we have- * gotten all uncompressed bytes, which size is recorded in CFDATA,- * as much as we need, and we have to use the garbage so as to- * correctly compute the sum of CFDATA accordingly.- */- if (cfdata->compressed_bytes_remaining > 0) {- ssize_t bytes_avail;-- d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,- &bytes_avail);- if (bytes_avail <= 0) {- *avail = truncated_error(a);- return (NULL);- }- cfdata->unconsumed = cfdata->compressed_bytes_remaining;- cfdata->sum_ptr = d;- if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {- *avail = ARCHIVE_FATAL;- return (NULL);- }- }-- /*- * Set dictionary data for decompressing of next CFDATA, which- * in the same folder. This is why we always do decompress CFDATA- * even if beginning CFDATA or some of CFDATA are not used in- * skipping file data.- */- if (cab->entry_cffolder->cfdata_index <- cab->entry_cffolder->cfdata_count) {- r = inflateReset(&cab->stream);- if (r != Z_OK)- goto zlibfailed;- r = inflateSetDictionary(&cab->stream,- cab->uncompressed_buffer, cfdata->uncompressed_size);- if (r != Z_OK)- goto zlibfailed;- }-- d = cab->uncompressed_buffer + cfdata->read_offset;- *avail = uavail - cfdata->read_offset;- cfdata->uncompressed_avail = uavail;-- return (d);--zlibfailed:- switch (r) {- case Z_MEM_ERROR:- archive_set_error(&a->archive, ENOMEM,- "Out of memory for deflate decompression");- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Deflate decompression failed (%d)", r);- break;- }- *avail = ARCHIVE_FATAL;- return (NULL);-nomszip:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "CFDATA incorrect(no MSZIP signature)");- *avail = ARCHIVE_FATAL;- return (NULL);-}--#else /* HAVE_ZLIB_H */--static const void *-cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)-{- *avail = ARCHIVE_FATAL;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "libarchive compiled without deflate support (no libz)");- return (NULL);-}--#endif /* HAVE_ZLIB_H */--static const void *-cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)-{- struct cab *cab = (struct cab *)(a->format->data);- struct cfdata *cfdata;- const void *d;- int r;- uint16_t uavail;-- cfdata = cab->entry_cfdata;- /* If the buffer hasn't been allocated, allocate it now. */- if (cab->uncompressed_buffer == NULL) {- cab->uncompressed_buffer_size = 0x8000;- cab->uncompressed_buffer- = (unsigned char *)malloc(cab->uncompressed_buffer_size);- if (cab->uncompressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for CAB reader");- *avail = ARCHIVE_FATAL;- return (NULL);- }- }-- uavail = cfdata->uncompressed_avail;- if (uavail == cfdata->uncompressed_size) {- d = cab->uncompressed_buffer + cfdata->read_offset;- *avail = uavail - cfdata->read_offset;- return (d);- }-- if (!cab->entry_cffolder->decompress_init) {- r = lzx_decode_init(&cab->xstrm,- cab->entry_cffolder->compdata);- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't initialize LZX decompression.");- *avail = ARCHIVE_FATAL;- return (NULL);- }- /* We've initialized decompression for this stream. */- cab->entry_cffolder->decompress_init = 1;- }-- /* Clean up remaining bits of previous CFDATA. */- lzx_cleanup_bitstream(&cab->xstrm);- cab->xstrm.total_out = uavail;- while (cab->xstrm.total_out < cfdata->uncompressed_size) {- ssize_t bytes_avail;-- cab->xstrm.next_out =- cab->uncompressed_buffer + cab->xstrm.total_out;- cab->xstrm.avail_out =- cfdata->uncompressed_size - cab->xstrm.total_out;-- d = __archive_read_ahead(a, 1, &bytes_avail);- if (bytes_avail <= 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated CAB file data");- *avail = ARCHIVE_FATAL;- return (NULL);- }- if (bytes_avail > cfdata->compressed_bytes_remaining)- bytes_avail = cfdata->compressed_bytes_remaining;-- cab->xstrm.next_in = d;- cab->xstrm.avail_in = bytes_avail;- cab->xstrm.total_in = 0;- r = lzx_decode(&cab->xstrm,- cfdata->compressed_bytes_remaining == bytes_avail);- switch (r) {- case ARCHIVE_OK:- case ARCHIVE_EOF:- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "LZX decompression failed (%d)", r);- *avail = ARCHIVE_FATAL;- return (NULL);- }- cfdata->unconsumed = cab->xstrm.total_in;- cfdata->sum_ptr = d;- if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {- *avail = ARCHIVE_FATAL;- return (NULL);- }- }-- uavail = (uint16_t)cab->xstrm.total_out;- /*- * Make sure a read pointer advances to next CFDATA.- */- if (cfdata->compressed_bytes_remaining > 0) {- ssize_t bytes_avail;-- d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,- &bytes_avail);- if (bytes_avail <= 0) {- *avail = truncated_error(a);- return (NULL);- }- cfdata->unconsumed = cfdata->compressed_bytes_remaining;- cfdata->sum_ptr = d;- if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {- *avail = ARCHIVE_FATAL;- return (NULL);- }- }-- /*- * Translation reversal of x86 processor CALL byte sequence(E8).- */- lzx_translation(&cab->xstrm, cab->uncompressed_buffer,- cfdata->uncompressed_size,- (cab->entry_cffolder->cfdata_index-1) * 0x8000);-- d = cab->uncompressed_buffer + cfdata->read_offset;- *avail = uavail - cfdata->read_offset;- cfdata->uncompressed_avail = uavail;-- return (d);-}--/*- * Consume CFDATA.- * We always decompress CFDATA to consume CFDATA as much as we need- * in uncompressed bytes because all CFDATA in a folder are related- * so we do not skip any CFDATA without decompressing.- * Note: If the folder of a CFFILE is iFoldCONTINUED_PREV_AND_NEXT or- * iFoldCONTINUED_FROM_PREV, we won't decompress because a CFDATA for- * the CFFILE is remaining bytes of previous Multivolume CAB file.- */-static int64_t-cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)-{- struct cab *cab = (struct cab *)(a->format->data);- struct cfdata *cfdata;- int64_t cbytes, rbytes;- int err;-- rbytes = cab_minimum_consume_cfdata(a, consumed_bytes);- if (rbytes < 0)- return (ARCHIVE_FATAL);-- cfdata = cab->entry_cfdata;- while (rbytes > 0) {- ssize_t avail;-- if (cfdata->compressed_size == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid CFDATA");- return (ARCHIVE_FATAL);- }- cbytes = cfdata->uncompressed_bytes_remaining;- if (cbytes > rbytes)- cbytes = rbytes;- rbytes -= cbytes;-- if (cfdata->uncompressed_avail == 0 &&- (cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||- cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {- /* We have not read any data yet. */- if (cbytes == cfdata->uncompressed_bytes_remaining) {- /* Skip whole current CFDATA. */- __archive_read_consume(a,- cfdata->compressed_size);- cab->cab_offset += cfdata->compressed_size;- cfdata->compressed_bytes_remaining = 0;- cfdata->uncompressed_bytes_remaining = 0;- err = cab_next_cfdata(a);- if (err < 0)- return (err);- cfdata = cab->entry_cfdata;- if (cfdata->uncompressed_size == 0) {- switch (cab->entry_cffile->folder) {- case iFoldCONTINUED_PREV_AND_NEXT:- case iFoldCONTINUED_TO_NEXT:- case iFoldCONTINUED_FROM_PREV:- rbytes = 0;- break;- default:- break;- }- }- continue;- }- cfdata->read_offset += (uint16_t)cbytes;- cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;- break;- } else if (cbytes == 0) {- err = cab_next_cfdata(a);- if (err < 0)- return (err);- cfdata = cab->entry_cfdata;- if (cfdata->uncompressed_size == 0) {- switch (cab->entry_cffile->folder) {- case iFoldCONTINUED_PREV_AND_NEXT:- case iFoldCONTINUED_TO_NEXT:- case iFoldCONTINUED_FROM_PREV:- return (ARCHIVE_FATAL);- default:- break;- }- }- continue;- }- while (cbytes > 0) {- (void)cab_read_ahead_cfdata(a, &avail);- if (avail <= 0)- return (ARCHIVE_FATAL);- if (avail > cbytes)- avail = (ssize_t)cbytes;- if (cab_minimum_consume_cfdata(a, avail) < 0)- return (ARCHIVE_FATAL);- cbytes -= avail;- }- }- return (consumed_bytes);-}--/*- * Consume CFDATA as much as we have already gotten and- * compute the sum of CFDATA.- */-static int64_t-cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)-{- struct cab *cab = (struct cab *)(a->format->data);- struct cfdata *cfdata;- int64_t cbytes, rbytes;- int err;-- cfdata = cab->entry_cfdata;- rbytes = consumed_bytes;- if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {- if (consumed_bytes < cfdata->unconsumed)- cbytes = consumed_bytes;- else- cbytes = cfdata->unconsumed;- rbytes -= cbytes; - cfdata->read_offset += (uint16_t)cbytes;- cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;- cfdata->unconsumed -= cbytes;- } else {- cbytes = cfdata->uncompressed_avail - cfdata->read_offset;- if (cbytes > 0) {- if (consumed_bytes < cbytes)- cbytes = consumed_bytes;- rbytes -= cbytes;- cfdata->read_offset += (uint16_t)cbytes;- cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;- }-- if (cfdata->unconsumed) {- cbytes = cfdata->unconsumed;- cfdata->unconsumed = 0;- } else- cbytes = 0;- }- if (cbytes) {- /* Compute the sum. */- cab_checksum_update(a, (size_t)cbytes);-- /* Consume as much as the compressor actually used. */- __archive_read_consume(a, cbytes);- cab->cab_offset += cbytes;- cfdata->compressed_bytes_remaining -= (uint16_t)cbytes;- if (cfdata->compressed_bytes_remaining == 0) {- err = cab_checksum_finish(a);- if (err < 0)- return (err);- }- }- return (rbytes);-}--/*- * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets- * cab->end_of_entry if it consumes all of the data.- */-static int-cab_read_data(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset)-{- struct cab *cab = (struct cab *)(a->format->data);- ssize_t bytes_avail;-- if (cab->entry_bytes_remaining == 0) {- *buff = NULL;- *size = 0;- *offset = cab->entry_offset;- cab->end_of_entry = 1;- return (ARCHIVE_OK);- }-- *buff = cab_read_ahead_cfdata(a, &bytes_avail);- if (bytes_avail <= 0) {- *buff = NULL;- *size = 0;- *offset = 0;- if (bytes_avail == 0 &&- cab->entry_cfdata->uncompressed_size == 0) {- /* All of CFDATA in a folder has been handled. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA");- return (ARCHIVE_FATAL);- } else- return ((int)bytes_avail);- }- if (bytes_avail > cab->entry_bytes_remaining)- bytes_avail = (ssize_t)cab->entry_bytes_remaining;-- *size = bytes_avail;- *offset = cab->entry_offset;- cab->entry_offset += bytes_avail;- cab->entry_bytes_remaining -= bytes_avail;- if (cab->entry_bytes_remaining == 0)- cab->end_of_entry = 1;- cab->entry_unconsumed = bytes_avail;- if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {- /* Don't consume more than current entry used. */- if (cab->entry_cfdata->unconsumed > cab->entry_unconsumed)- cab->entry_cfdata->unconsumed = cab->entry_unconsumed;- }- return (ARCHIVE_OK);-}--static int-archive_read_format_cab_read_data_skip(struct archive_read *a)-{- struct cab *cab;- int64_t bytes_skipped;- int r;-- cab = (struct cab *)(a->format->data);-- if (cab->end_of_archive)- return (ARCHIVE_EOF);-- if (!cab->read_data_invoked) {- cab->bytes_skipped += cab->entry_bytes_remaining;- cab->entry_bytes_remaining = 0;- /* This entry is finished and done. */- cab->end_of_entry_cleanup = cab->end_of_entry = 1;- return (ARCHIVE_OK);- }-- if (cab->entry_unconsumed) {- /* Consume as much as the compressor actually used. */- r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);- cab->entry_unconsumed = 0;- if (r < 0)- return (r);- } else if (cab->entry_cfdata == NULL) {- r = cab_next_cfdata(a);- if (r < 0)- return (r);- }-- /* if we've already read to end of data, we're done. */- if (cab->end_of_entry_cleanup)- return (ARCHIVE_OK);-- /*- * If the length is at the beginning, we can skip the- * compressed data much more quickly.- */- bytes_skipped = cab_consume_cfdata(a, cab->entry_bytes_remaining);- if (bytes_skipped < 0)- return (ARCHIVE_FATAL);-- /* If the compression type is none(uncompressed), we've already- * consumed data as much as the current entry size. */- if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&- cab->entry_cfdata != NULL)- cab->entry_cfdata->unconsumed = 0;-- /* This entry is finished and done. */- cab->end_of_entry_cleanup = cab->end_of_entry = 1;- return (ARCHIVE_OK);-}--static int-archive_read_format_cab_cleanup(struct archive_read *a)-{- struct cab *cab = (struct cab *)(a->format->data);- struct cfheader *hd = &cab->cfheader;- int i;-- if (hd->folder_array != NULL) {- for (i = 0; i < hd->folder_count; i++)- free(hd->folder_array[i].cfdata.memimage);- free(hd->folder_array);- }- if (hd->file_array != NULL) {- for (i = 0; i < cab->cfheader.file_count; i++)- archive_string_free(&(hd->file_array[i].pathname));- free(hd->file_array);- }-#ifdef HAVE_ZLIB_H- if (cab->stream_valid)- inflateEnd(&cab->stream);-#endif- lzx_decode_free(&cab->xstrm);- archive_wstring_free(&cab->ws);- free(cab->uncompressed_buffer);- free(cab);- (a->format->data) = NULL;- return (ARCHIVE_OK);-}--/* Convert an MSDOS-style date/time into Unix-style time. */-static time_t-cab_dos_time(const unsigned char *p)-{- int msTime, msDate;- struct tm ts;-- msDate = archive_le16dec(p);- msTime = archive_le16dec(p+2);-- memset(&ts, 0, sizeof(ts));- ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */- ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */- ts.tm_mday = msDate & 0x1f; /* Day of month. */- ts.tm_hour = (msTime >> 11) & 0x1f;- ts.tm_min = (msTime >> 5) & 0x3f;- ts.tm_sec = (msTime << 1) & 0x3e;- ts.tm_isdst = -1;- return (mktime(&ts));-}--/*****************************************************************- *- * LZX decompression code.- *- *****************************************************************/--/*- * Initialize LZX decoder.- *- * Returns ARCHIVE_OK if initialization was successful.- * Returns ARCHIVE_FAILED if w_bits has unsupported value.- * Returns ARCHIVE_FATAL if initialization failed; memory allocation- * error occurred.- */-static int-lzx_decode_init(struct lzx_stream *strm, int w_bits)-{- struct lzx_dec *ds;- int slot, w_size, w_slot;- int base, footer;- int base_inc[18];-- if (strm->ds == NULL) {- strm->ds = calloc(1, sizeof(*strm->ds));- if (strm->ds == NULL)- return (ARCHIVE_FATAL);- }- ds = strm->ds;- ds->error = ARCHIVE_FAILED;-- /* Allow bits from 15(32KBi) up to 21(2MBi) */- if (w_bits < SLOT_BASE || w_bits > SLOT_MAX)- return (ARCHIVE_FAILED);-- ds->error = ARCHIVE_FATAL;-- /*- * Alloc window- */- w_size = ds->w_size;- w_slot = slots[w_bits - SLOT_BASE];- ds->w_size = 1U << w_bits;- ds->w_mask = ds->w_size -1;- if (ds->w_buff == NULL || w_size != ds->w_size) {- free(ds->w_buff);- ds->w_buff = malloc(ds->w_size);- if (ds->w_buff == NULL)- return (ARCHIVE_FATAL);- free(ds->pos_tbl);- ds->pos_tbl = malloc(sizeof(ds->pos_tbl[0]) * w_slot);- if (ds->pos_tbl == NULL)- return (ARCHIVE_FATAL);- }-- for (footer = 0; footer < 18; footer++)- base_inc[footer] = 1 << footer;- base = footer = 0;- for (slot = 0; slot < w_slot; slot++) {- int n;- if (footer == 0)- base = slot;- else- base += base_inc[footer];- if (footer < 17) {- footer = -2;- for (n = base; n; n >>= 1)- footer++;- if (footer <= 0)- footer = 0;- }- ds->pos_tbl[slot].base = base;- ds->pos_tbl[slot].footer_bits = footer;- }-- ds->w_pos = 0;- ds->state = 0;- ds->br.cache_buffer = 0;- ds->br.cache_avail = 0;- ds->r0 = ds->r1 = ds->r2 = 1;-- /* Initialize aligned offset tree. */- if (lzx_huffman_init(&(ds->at), 8, 8) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Initialize pre-tree. */- if (lzx_huffman_init(&(ds->pt), 20, 10) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Initialize Main tree. */- if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Initialize Length tree. */- if (lzx_huffman_init(&(ds->lt), 249, 16) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- ds->error = 0;-- return (ARCHIVE_OK);-}--/*- * Release LZX decoder.- */-static void-lzx_decode_free(struct lzx_stream *strm)-{-- if (strm->ds == NULL)- return;- free(strm->ds->w_buff);- free(strm->ds->pos_tbl);- lzx_huffman_free(&(strm->ds->at));- lzx_huffman_free(&(strm->ds->pt));- lzx_huffman_free(&(strm->ds->mt));- lzx_huffman_free(&(strm->ds->lt));- free(strm->ds);- strm->ds = NULL;-}--/*- * E8 Call Translation reversal.- */-static void-lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)-{- struct lzx_dec *ds = strm->ds;- unsigned char *b, *end;-- if (!ds->translation || size <= 10)- return;- b = p;- end = b + size - 10;- while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {- size_t i = b - (unsigned char *)p;- int32_t cp, displacement, value;-- cp = (int32_t)(offset + (uint32_t)i);- value = archive_le32dec(&b[1]);- if (value >= -cp && value < (int32_t)ds->translation_size) {- if (value >= 0)- displacement = value - cp;- else- displacement = value + ds->translation_size;- archive_le32enc(&b[1], (uint32_t)displacement);- }- b += 5;- }-}--/*- * Bit stream reader.- */-/* Check that the cache buffer has enough bits. */-#define lzx_br_has(br, n) ((br)->cache_avail >= n)-/* Get compressed data by bit. */-#define lzx_br_bits(br, n) \- (((uint32_t)((br)->cache_buffer >> \- ((br)->cache_avail - (n)))) & cache_masks[n])-#define lzx_br_bits_forced(br, n) \- (((uint32_t)((br)->cache_buffer << \- ((n) - (br)->cache_avail))) & cache_masks[n])-/* Read ahead to make sure the cache buffer has enough compressed data we- * will use.- * True : completed, there is enough data in the cache buffer.- * False : we met that strm->next_in is empty, we have to get following- * bytes. */-#define lzx_br_read_ahead_0(strm, br, n) \- (lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))-/* True : the cache buffer has some bits as much as we need.- * False : there are no enough bits in the cache buffer to be used,- * we have to get following bytes if we could. */-#define lzx_br_read_ahead(strm, br, n) \- (lzx_br_read_ahead_0((strm), (br), (n)) || lzx_br_has((br), (n)))--/* Notify how many bits we consumed. */-#define lzx_br_consume(br, n) ((br)->cache_avail -= (n))-#define lzx_br_consume_unaligned_bits(br) ((br)->cache_avail &= ~0x0f)--#define lzx_br_is_unaligned(br) ((br)->cache_avail & 0x0f)--static const uint32_t cache_masks[] = {- 0x00000000, 0x00000001, 0x00000003, 0x00000007,- 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,- 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,- 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,- 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,- 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,- 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,- 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF-};--/*- * Shift away used bits in the cache data and fill it up with following bits.- * Call this when cache buffer does not have enough bits you need.- *- * Returns 1 if the cache buffer is full.- * Returns 0 if the cache buffer is not full; input buffer is empty.- */-static int-lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)-{-/*- * x86 processor family can read misaligned data without an access error.- */- int n = CACHE_BITS - br->cache_avail;-- for (;;) {- switch (n >> 4) {- case 4:- if (strm->avail_in >= 8) {- br->cache_buffer =- ((uint64_t)strm->next_in[1]) << 56 |- ((uint64_t)strm->next_in[0]) << 48 |- ((uint64_t)strm->next_in[3]) << 40 |- ((uint64_t)strm->next_in[2]) << 32 |- ((uint32_t)strm->next_in[5]) << 24 |- ((uint32_t)strm->next_in[4]) << 16 |- ((uint32_t)strm->next_in[7]) << 8 |- (uint32_t)strm->next_in[6];- strm->next_in += 8;- strm->avail_in -= 8;- br->cache_avail += 8 * 8;- return (1);- }- break;- case 3:- if (strm->avail_in >= 6) {- br->cache_buffer =- (br->cache_buffer << 48) |- ((uint64_t)strm->next_in[1]) << 40 |- ((uint64_t)strm->next_in[0]) << 32 |- ((uint64_t)strm->next_in[3]) << 24 |- ((uint64_t)strm->next_in[2]) << 16 |- ((uint64_t)strm->next_in[5]) << 8 |- (uint64_t)strm->next_in[4];- strm->next_in += 6;- strm->avail_in -= 6;- br->cache_avail += 6 * 8;- return (1);- }- break;- case 0:- /* We have enough compressed data in- * the cache buffer.*/- return (1);- default:- break;- }- if (strm->avail_in < 2) {- /* There is not enough compressed data to- * fill up the cache buffer. */- if (strm->avail_in == 1) {- br->odd = *strm->next_in++;- strm->avail_in--;- br->have_odd = 1;- }- return (0);- }- br->cache_buffer =- (br->cache_buffer << 16) |- archive_le16dec(strm->next_in);- strm->next_in += 2;- strm->avail_in -= 2;- br->cache_avail += 16;- n -= 16;- }-}--static void-lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br)-{- int n = CACHE_BITS - br->cache_avail;-- if (br->have_odd && n >= 16 && strm->avail_in > 0) {- br->cache_buffer =- (br->cache_buffer << 16) |- ((uint16_t)(*strm->next_in)) << 8 | br->odd;- strm->next_in++;- strm->avail_in--;- br->cache_avail += 16;- br->have_odd = 0;- }-}--static void-lzx_cleanup_bitstream(struct lzx_stream *strm)-{- strm->ds->br.cache_avail = 0;- strm->ds->br.have_odd = 0;-}--/*- * Decode LZX.- *- * 1. Returns ARCHIVE_OK if output buffer or input buffer are empty.- * Please set available buffer and call this function again.- * 2. Returns ARCHIVE_EOF if decompression has been completed.- * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data- * is broken or you do not set 'last' flag properly.- */-#define ST_RD_TRANSLATION 0-#define ST_RD_TRANSLATION_SIZE 1-#define ST_RD_BLOCK_TYPE 2-#define ST_RD_BLOCK_SIZE 3-#define ST_RD_ALIGNMENT 4-#define ST_RD_R0 5-#define ST_RD_R1 6-#define ST_RD_R2 7-#define ST_COPY_UNCOMP1 8-#define ST_COPY_UNCOMP2 9-#define ST_RD_ALIGNED_OFFSET 10-#define ST_RD_VERBATIM 11-#define ST_RD_PRE_MAIN_TREE_256 12-#define ST_MAIN_TREE_256 13-#define ST_RD_PRE_MAIN_TREE_REM 14-#define ST_MAIN_TREE_REM 15-#define ST_RD_PRE_LENGTH_TREE 16-#define ST_LENGTH_TREE 17-#define ST_MAIN 18-#define ST_LENGTH 19-#define ST_OFFSET 20-#define ST_REAL_POS 21-#define ST_COPY 22--static int-lzx_decode(struct lzx_stream *strm, int last)-{- struct lzx_dec *ds = strm->ds;- int64_t avail_in;- int r;-- if (ds->error)- return (ds->error);-- avail_in = strm->avail_in;- lzx_br_fixup(strm, &(ds->br));- do {- if (ds->state < ST_MAIN)- r = lzx_read_blocks(strm, last);- else {- int64_t bytes_written = strm->avail_out;- r = lzx_decode_blocks(strm, last);- bytes_written -= strm->avail_out;- strm->next_out += bytes_written;- strm->total_out += bytes_written;- }- } while (r == 100);- strm->total_in += avail_in - strm->avail_in;- return (r);-}--static int-lzx_read_blocks(struct lzx_stream *strm, int last)-{- struct lzx_dec *ds = strm->ds;- struct lzx_br *br = &(ds->br);- int i, r;-- for (;;) {- switch (ds->state) {- case ST_RD_TRANSLATION:- if (!lzx_br_read_ahead(strm, br, 1)) {- ds->state = ST_RD_TRANSLATION;- if (last)- goto failed;- return (ARCHIVE_OK);- }- ds->translation = lzx_br_bits(br, 1);- lzx_br_consume(br, 1);- /* FALL THROUGH */- case ST_RD_TRANSLATION_SIZE:- if (ds->translation) {- if (!lzx_br_read_ahead(strm, br, 32)) {- ds->state = ST_RD_TRANSLATION_SIZE;- if (last)- goto failed;- return (ARCHIVE_OK);- }- ds->translation_size = lzx_br_bits(br, 16);- lzx_br_consume(br, 16);- ds->translation_size <<= 16;- ds->translation_size |= lzx_br_bits(br, 16);- lzx_br_consume(br, 16);- }- /* FALL THROUGH */- case ST_RD_BLOCK_TYPE:- if (!lzx_br_read_ahead(strm, br, 3)) {- ds->state = ST_RD_BLOCK_TYPE;- if (last)- goto failed;- return (ARCHIVE_OK);- }- ds->block_type = lzx_br_bits(br, 3);- lzx_br_consume(br, 3);- /* Check a block type. */- switch (ds->block_type) {- case VERBATIM_BLOCK:- case ALIGNED_OFFSET_BLOCK:- case UNCOMPRESSED_BLOCK:- break;- default:- goto failed;/* Invalid */- }- /* FALL THROUGH */- case ST_RD_BLOCK_SIZE:- if (!lzx_br_read_ahead(strm, br, 24)) {- ds->state = ST_RD_BLOCK_SIZE;- if (last)- goto failed;- return (ARCHIVE_OK);- }- ds->block_size = lzx_br_bits(br, 8);- lzx_br_consume(br, 8);- ds->block_size <<= 16;- ds->block_size |= lzx_br_bits(br, 16);- lzx_br_consume(br, 16);- if (ds->block_size == 0)- goto failed;- ds->block_bytes_avail = ds->block_size;- if (ds->block_type != UNCOMPRESSED_BLOCK) {- if (ds->block_type == VERBATIM_BLOCK)- ds->state = ST_RD_VERBATIM;- else- ds->state = ST_RD_ALIGNED_OFFSET;- break;- }- /* FALL THROUGH */- case ST_RD_ALIGNMENT:- /*- * Handle an Uncompressed Block.- */- /* Skip padding to align following field on- * 16-bit boundary. */- if (lzx_br_is_unaligned(br))- lzx_br_consume_unaligned_bits(br);- else {- if (lzx_br_read_ahead(strm, br, 16))- lzx_br_consume(br, 16);- else {- ds->state = ST_RD_ALIGNMENT;- if (last)- goto failed;- return (ARCHIVE_OK);- }- }- /* Preparation to read repeated offsets R0,R1 and R2. */- ds->rbytes_avail = 0;- ds->state = ST_RD_R0;- /* FALL THROUGH */- case ST_RD_R0:- case ST_RD_R1:- case ST_RD_R2:- do {- uint16_t u16;- /* Drain bits in the cache buffer of- * bit-stream. */- if (lzx_br_has(br, 32)) {- u16 = lzx_br_bits(br, 16);- lzx_br_consume(br, 16);- archive_le16enc(ds->rbytes, u16);- u16 = lzx_br_bits(br, 16);- lzx_br_consume(br, 16);- archive_le16enc(ds->rbytes+2, u16);- ds->rbytes_avail = 4;- } else if (lzx_br_has(br, 16)) {- u16 = lzx_br_bits(br, 16);- lzx_br_consume(br, 16);- archive_le16enc(ds->rbytes, u16);- ds->rbytes_avail = 2;- }- if (ds->rbytes_avail < 4 && ds->br.have_odd) {- ds->rbytes[ds->rbytes_avail++] =- ds->br.odd;- ds->br.have_odd = 0;- }- while (ds->rbytes_avail < 4) {- if (strm->avail_in <= 0) {- if (last)- goto failed;- return (ARCHIVE_OK);- }- ds->rbytes[ds->rbytes_avail++] =- *strm->next_in++;- strm->avail_in--;- }- ds->rbytes_avail = 0;- if (ds->state == ST_RD_R0) {- ds->r0 = archive_le32dec(ds->rbytes);- if (ds->r0 < 0)- goto failed;- ds->state = ST_RD_R1;- } else if (ds->state == ST_RD_R1) {- ds->r1 = archive_le32dec(ds->rbytes);- if (ds->r1 < 0)- goto failed;- ds->state = ST_RD_R2;- } else if (ds->state == ST_RD_R2) {- ds->r2 = archive_le32dec(ds->rbytes);- if (ds->r2 < 0)- goto failed;- /* We've gotten all repeated offsets. */- ds->state = ST_COPY_UNCOMP1;- }- } while (ds->state != ST_COPY_UNCOMP1);- /* FALL THROUGH */- case ST_COPY_UNCOMP1:- /*- * Copy bytes form next_in to next_out directly.- */- while (ds->block_bytes_avail) {- int l;-- if (strm->avail_out <= 0)- /* Output buffer is empty. */- return (ARCHIVE_OK);- if (strm->avail_in <= 0) {- /* Input buffer is empty. */- if (last)- goto failed;- return (ARCHIVE_OK);- }- l = (int)ds->block_bytes_avail;- if (l > ds->w_size - ds->w_pos)- l = ds->w_size - ds->w_pos;- if (l > strm->avail_out)- l = (int)strm->avail_out;- if (l > strm->avail_in)- l = (int)strm->avail_in;- memcpy(strm->next_out, strm->next_in, l);- memcpy(&(ds->w_buff[ds->w_pos]),- strm->next_in, l);- strm->next_in += l;- strm->avail_in -= l;- strm->next_out += l;- strm->avail_out -= l;- strm->total_out += l;- ds->w_pos = (ds->w_pos + l) & ds->w_mask;- ds->block_bytes_avail -= l;- }- /* FALL THROUGH */- case ST_COPY_UNCOMP2:- /* Re-align; skip padding byte. */- if (ds->block_size & 1) {- if (strm->avail_in <= 0) {- /* Input buffer is empty. */- ds->state = ST_COPY_UNCOMP2;- if (last)- goto failed;- return (ARCHIVE_OK);- }- strm->next_in++;- strm->avail_in --;- }- /* This block ended. */- ds->state = ST_RD_BLOCK_TYPE;- return (ARCHIVE_EOF);- /********************/- case ST_RD_ALIGNED_OFFSET:- /*- * Read Aligned offset tree.- */- if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {- ds->state = ST_RD_ALIGNED_OFFSET;- if (last)- goto failed;- return (ARCHIVE_OK);- }- memset(ds->at.freq, 0, sizeof(ds->at.freq));- for (i = 0; i < ds->at.len_size; i++) {- ds->at.bitlen[i] = lzx_br_bits(br, 3);- ds->at.freq[ds->at.bitlen[i]]++;- lzx_br_consume(br, 3);- }- if (!lzx_make_huffman_table(&ds->at))- goto failed;- /* FALL THROUGH */- case ST_RD_VERBATIM:- ds->loop = 0;- /* FALL THROUGH */- case ST_RD_PRE_MAIN_TREE_256:- /*- * Read Pre-tree for first 256 elements of main tree.- */- if (!lzx_read_pre_tree(strm)) {- ds->state = ST_RD_PRE_MAIN_TREE_256;- if (last)- goto failed;- return (ARCHIVE_OK);- }- if (!lzx_make_huffman_table(&ds->pt))- goto failed;- ds->loop = 0;- /* FALL THROUGH */- case ST_MAIN_TREE_256:- /*- * Get path lengths of first 256 elements of main tree.- */- r = lzx_read_bitlen(strm, &ds->mt, 256);- if (r < 0)- goto failed;- else if (!r) {- ds->state = ST_MAIN_TREE_256;- if (last)- goto failed;- return (ARCHIVE_OK);- }- ds->loop = 0;- /* FALL THROUGH */- case ST_RD_PRE_MAIN_TREE_REM:- /*- * Read Pre-tree for remaining elements of main tree.- */- if (!lzx_read_pre_tree(strm)) {- ds->state = ST_RD_PRE_MAIN_TREE_REM;- if (last)- goto failed;- return (ARCHIVE_OK);- }- if (!lzx_make_huffman_table(&ds->pt))- goto failed;- ds->loop = 256;- /* FALL THROUGH */- case ST_MAIN_TREE_REM:- /*- * Get path lengths of remaining elements of main tree.- */- r = lzx_read_bitlen(strm, &ds->mt, -1);- if (r < 0)- goto failed;- else if (!r) {- ds->state = ST_MAIN_TREE_REM;- if (last)- goto failed;- return (ARCHIVE_OK);- }- if (!lzx_make_huffman_table(&ds->mt))- goto failed;- ds->loop = 0;- /* FALL THROUGH */- case ST_RD_PRE_LENGTH_TREE:- /*- * Read Pre-tree for remaining elements of main tree.- */- if (!lzx_read_pre_tree(strm)) {- ds->state = ST_RD_PRE_LENGTH_TREE;- if (last)- goto failed;- return (ARCHIVE_OK);- }- if (!lzx_make_huffman_table(&ds->pt))- goto failed;- ds->loop = 0;- /* FALL THROUGH */- case ST_LENGTH_TREE:- /*- * Get path lengths of remaining elements of main tree.- */- r = lzx_read_bitlen(strm, &ds->lt, -1);- if (r < 0)- goto failed;- else if (!r) {- ds->state = ST_LENGTH_TREE;- if (last)- goto failed;- return (ARCHIVE_OK);- }- if (!lzx_make_huffman_table(&ds->lt))- goto failed;- ds->state = ST_MAIN;- return (100);- }- }-failed:- return (ds->error = ARCHIVE_FAILED);-}--static int-lzx_decode_blocks(struct lzx_stream *strm, int last)-{- struct lzx_dec *ds = strm->ds;- struct lzx_br bre = ds->br;- struct huffman *at = &(ds->at), *lt = &(ds->lt), *mt = &(ds->mt);- const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;- unsigned char *noutp = strm->next_out;- unsigned char *endp = noutp + strm->avail_out;- unsigned char *w_buff = ds->w_buff;- unsigned char *at_bitlen = at->bitlen;- unsigned char *lt_bitlen = lt->bitlen;- unsigned char *mt_bitlen = mt->bitlen;- size_t block_bytes_avail = ds->block_bytes_avail;- int at_max_bits = at->max_bits;- int lt_max_bits = lt->max_bits;- int mt_max_bits = mt->max_bits;- int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;- int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;- int length_header = ds->length_header;- int offset_bits = ds->offset_bits;- int position_slot = ds->position_slot;- int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;- int state = ds->state;- char block_type = ds->block_type;-- for (;;) {- switch (state) {- case ST_MAIN:- for (;;) {- if (block_bytes_avail == 0) {- /* This block ended. */- ds->state = ST_RD_BLOCK_TYPE;- ds->br = bre;- ds->block_bytes_avail =- block_bytes_avail;- ds->copy_len = copy_len;- ds->copy_pos = copy_pos;- ds->length_header = length_header;- ds->position_slot = position_slot;- ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;- ds->w_pos = w_pos;- strm->avail_out = endp - noutp;- return (ARCHIVE_EOF);- }- if (noutp >= endp)- /* Output buffer is empty. */- goto next_data;-- if (!lzx_br_read_ahead(strm, &bre,- mt_max_bits)) {- if (!last)- goto next_data;- /* Remaining bits are less than- * maximum bits(mt.max_bits) but maybe- * it still remains as much as we need,- * so we should try to use it with- * dummy bits. */- c = lzx_decode_huffman(mt,- lzx_br_bits_forced(- &bre, mt_max_bits));- lzx_br_consume(&bre, mt_bitlen[c]);- if (!lzx_br_has(&bre, 0))- goto failed;/* Over read. */- } else {- c = lzx_decode_huffman(mt,- lzx_br_bits(&bre, mt_max_bits));- lzx_br_consume(&bre, mt_bitlen[c]);- }- if (c > UCHAR_MAX)- break;- /*- * 'c' is exactly literal code.- */- /* Save a decoded code to reference it- * afterward. */- w_buff[w_pos] = c;- w_pos = (w_pos + 1) & w_mask;- /* Store the decoded code to output buffer. */- *noutp++ = c;- block_bytes_avail--;- }- /*- * Get a match code, its length and offset.- */- c -= UCHAR_MAX + 1;- length_header = c & 7;- position_slot = c >> 3;- /* FALL THROUGH */- case ST_LENGTH:- /*- * Get a length.- */- if (length_header == 7) {- if (!lzx_br_read_ahead(strm, &bre,- lt_max_bits)) {- if (!last) {- state = ST_LENGTH;- goto next_data;- }- c = lzx_decode_huffman(lt,- lzx_br_bits_forced(- &bre, lt_max_bits));- lzx_br_consume(&bre, lt_bitlen[c]);- if (!lzx_br_has(&bre, 0))- goto failed;/* Over read. */- } else {- c = lzx_decode_huffman(lt,- lzx_br_bits(&bre, lt_max_bits));- lzx_br_consume(&bre, lt_bitlen[c]);- }- copy_len = c + 7 + 2;- } else- copy_len = length_header + 2;- if ((size_t)copy_len > block_bytes_avail)- goto failed;- /*- * Get an offset.- */- switch (position_slot) {- case 0: /* Use repeated offset 0. */- copy_pos = r0;- state = ST_REAL_POS;- continue;- case 1: /* Use repeated offset 1. */- copy_pos = r1;- /* Swap repeated offset. */- r1 = r0;- r0 = copy_pos;- state = ST_REAL_POS;- continue;- case 2: /* Use repeated offset 2. */- copy_pos = r2;- /* Swap repeated offset. */- r2 = r0;- r0 = copy_pos;- state = ST_REAL_POS;- continue;- default:- offset_bits =- pos_tbl[position_slot].footer_bits;- break;- }- /* FALL THROUGH */- case ST_OFFSET:- /*- * Get the offset, which is a distance from- * current window position.- */- if (block_type == ALIGNED_OFFSET_BLOCK &&- offset_bits >= 3) {- int offbits = offset_bits - 3;-- if (!lzx_br_read_ahead(strm, &bre, offbits)) {- state = ST_OFFSET;- if (last)- goto failed;- goto next_data;- }- copy_pos = lzx_br_bits(&bre, offbits) << 3;-- /* Get an aligned number. */- if (!lzx_br_read_ahead(strm, &bre,- offbits + at_max_bits)) {- if (!last) {- state = ST_OFFSET;- goto next_data;- }- lzx_br_consume(&bre, offbits);- c = lzx_decode_huffman(at,- lzx_br_bits_forced(&bre,- at_max_bits));- lzx_br_consume(&bre, at_bitlen[c]);- if (!lzx_br_has(&bre, 0))- goto failed;/* Over read. */- } else {- lzx_br_consume(&bre, offbits);- c = lzx_decode_huffman(at,- lzx_br_bits(&bre, at_max_bits));- lzx_br_consume(&bre, at_bitlen[c]);- }- /* Add an aligned number. */- copy_pos += c;- } else {- if (!lzx_br_read_ahead(strm, &bre,- offset_bits)) {- state = ST_OFFSET;- if (last)- goto failed;- goto next_data;- }- copy_pos = lzx_br_bits(&bre, offset_bits);- lzx_br_consume(&bre, offset_bits);- }- copy_pos += pos_tbl[position_slot].base -2;-- /* Update repeated offset LRU queue. */- r2 = r1;- r1 = r0;- r0 = copy_pos;- /* FALL THROUGH */- case ST_REAL_POS:- /*- * Compute a real position in window.- */- copy_pos = (w_pos - copy_pos) & w_mask;- /* FALL THROUGH */- case ST_COPY:- /*- * Copy several bytes as extracted data from the window- * into the output buffer.- */- for (;;) {- const unsigned char *s;- int l;-- l = copy_len;- if (copy_pos > w_pos) {- if (l > w_size - copy_pos)- l = w_size - copy_pos;- } else {- if (l > w_size - w_pos)- l = w_size - w_pos;- }- if (noutp + l >= endp)- l = (int)(endp - noutp);- s = w_buff + copy_pos;- if (l >= 8 && ((copy_pos + l < w_pos)- || (w_pos + l < copy_pos))) {- memcpy(w_buff + w_pos, s, l);- memcpy(noutp, s, l);- } else {- unsigned char *d;- int li;-- d = w_buff + w_pos;- for (li = 0; li < l; li++)- noutp[li] = d[li] = s[li];- }- noutp += l;- copy_pos = (copy_pos + l) & w_mask;- w_pos = (w_pos + l) & w_mask;- block_bytes_avail -= l;- if (copy_len <= l)- /* A copy of current pattern ended. */- break;- copy_len -= l;- if (noutp >= endp) {- /* Output buffer is empty. */- state = ST_COPY;- goto next_data;- }- }- state = ST_MAIN;- break;- }- }-failed:- return (ds->error = ARCHIVE_FAILED);-next_data:- ds->br = bre;- ds->block_bytes_avail = block_bytes_avail;- ds->copy_len = copy_len;- ds->copy_pos = copy_pos;- ds->length_header = length_header;- ds->offset_bits = offset_bits;- ds->position_slot = position_slot;- ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;- ds->state = state;- ds->w_pos = w_pos;- strm->avail_out = endp - noutp;- return (ARCHIVE_OK);-}--static int-lzx_read_pre_tree(struct lzx_stream *strm)-{- struct lzx_dec *ds = strm->ds;- struct lzx_br *br = &(ds->br);- int i;-- if (ds->loop == 0)- memset(ds->pt.freq, 0, sizeof(ds->pt.freq));- for (i = ds->loop; i < ds->pt.len_size; i++) {- if (!lzx_br_read_ahead(strm, br, 4)) {- ds->loop = i;- return (0);- }- ds->pt.bitlen[i] = lzx_br_bits(br, 4);- ds->pt.freq[ds->pt.bitlen[i]]++;- lzx_br_consume(br, 4);- }- ds->loop = i;- return (1);-}--/*- * Read a bunch of bit-lengths from pre-tree.- */-static int-lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)-{- struct lzx_dec *ds = strm->ds;- struct lzx_br *br = &(ds->br);- int c, i, j, ret, same;- unsigned rbits;-- i = ds->loop;- if (i == 0)- memset(d->freq, 0, sizeof(d->freq));- ret = 0;- if (end < 0)- end = d->len_size;- while (i < end) {- ds->loop = i;- if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))- goto getdata;- rbits = lzx_br_bits(br, ds->pt.max_bits);- c = lzx_decode_huffman(&(ds->pt), rbits);- switch (c) {- case 17:/* several zero lengths, from 4 to 19. */- if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))- goto getdata;- lzx_br_consume(br, ds->pt.bitlen[c]);- same = lzx_br_bits(br, 4) + 4;- if (i + same > end)- return (-1);/* Invalid */- lzx_br_consume(br, 4);- for (j = 0; j < same; j++)- d->bitlen[i++] = 0;- break;- case 18:/* many zero lengths, from 20 to 51. */- if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))- goto getdata;- lzx_br_consume(br, ds->pt.bitlen[c]);- same = lzx_br_bits(br, 5) + 20;- if (i + same > end)- return (-1);/* Invalid */- lzx_br_consume(br, 5);- memset(d->bitlen + i, 0, same);- i += same;- break;- case 19:/* a few same lengths. */- if (!lzx_br_read_ahead(strm, br,- ds->pt.bitlen[c]+1+ds->pt.max_bits))- goto getdata;- lzx_br_consume(br, ds->pt.bitlen[c]);- same = lzx_br_bits(br, 1) + 4;- if (i + same > end)- return (-1);- lzx_br_consume(br, 1);- rbits = lzx_br_bits(br, ds->pt.max_bits);- c = lzx_decode_huffman(&(ds->pt), rbits);- lzx_br_consume(br, ds->pt.bitlen[c]);- c = (d->bitlen[i] - c + 17) % 17;- if (c < 0)- return (-1);/* Invalid */- for (j = 0; j < same; j++)- d->bitlen[i++] = c;- d->freq[c] += same;- break;- default:- lzx_br_consume(br, ds->pt.bitlen[c]);- c = (d->bitlen[i] - c + 17) % 17;- if (c < 0)- return (-1);/* Invalid */- d->freq[c]++;- d->bitlen[i++] = c;- break;- }- }- ret = 1;-getdata:- ds->loop = i;- return (ret);-}--static int-lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)-{-- if (hf->bitlen == NULL || hf->len_size != (int)len_size) {- free(hf->bitlen);- hf->bitlen = calloc(len_size, sizeof(hf->bitlen[0]));- if (hf->bitlen == NULL)- return (ARCHIVE_FATAL);- hf->len_size = (int)len_size;- } else- memset(hf->bitlen, 0, len_size * sizeof(hf->bitlen[0]));- if (hf->tbl == NULL) {- hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0]));- if (hf->tbl == NULL)- return (ARCHIVE_FATAL);- hf->tbl_bits = tbl_bits;- }- return (ARCHIVE_OK);-}--static void-lzx_huffman_free(struct huffman *hf)-{- free(hf->bitlen);- free(hf->tbl);-}--/*- * Make a huffman coding table.- */-static int-lzx_make_huffman_table(struct huffman *hf)-{- uint16_t *tbl;- const unsigned char *bitlen;- int bitptn[17], weight[17];- int i, maxbits = 0, ptn, tbl_size, w;- int len_avail;-- /*- * Initialize bit patterns.- */- ptn = 0;- for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {- bitptn[i] = ptn;- weight[i] = w;- if (hf->freq[i]) {- ptn += hf->freq[i] * w;- maxbits = i;- }- }- if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)- return (0);/* Invalid */-- hf->max_bits = maxbits;-- /*- * Cut out extra bits which we won't house in the table.- * This preparation reduces the same calculation in the for-loop- * making the table.- */- if (maxbits < 16) {- int ebits = 16 - maxbits;- for (i = 1; i <= maxbits; i++) {- bitptn[i] >>= ebits;- weight[i] >>= ebits;- }- }-- /*- * Make the table.- */- tbl_size = 1 << hf->tbl_bits;- tbl = hf->tbl;- bitlen = hf->bitlen;- len_avail = hf->len_size;- hf->tree_used = 0;- for (i = 0; i < len_avail; i++) {- uint16_t *p;- int len, cnt;-- if (bitlen[i] == 0)- continue;- /* Get a bit pattern */- len = bitlen[i];- if (len > tbl_size)- return (0);- ptn = bitptn[len];- cnt = weight[len];- /* Calculate next bit pattern */- if ((bitptn[len] = ptn + cnt) > tbl_size)- return (0);/* Invalid */- /* Update the table */- p = &(tbl[ptn]);- while (--cnt >= 0)- p[cnt] = (uint16_t)i;- }- return (1);-}--static inline int-lzx_decode_huffman(struct huffman *hf, unsigned rbits)-{- int c;- c = hf->tbl[rbits];- if (c < hf->len_size)- return (c);- return (0);-}
− c/archive_read_support_format_cpio.c
@@ -1,1104 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2010-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_cpio.c 201163 2009-12-29 05:50:34Z kientzle $");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-/* #include <stdint.h> */ /* See archive_platform.h */-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_read_private.h"--#define bin_magic_offset 0-#define bin_magic_size 2-#define bin_dev_offset 2-#define bin_dev_size 2-#define bin_ino_offset 4-#define bin_ino_size 2-#define bin_mode_offset 6-#define bin_mode_size 2-#define bin_uid_offset 8-#define bin_uid_size 2-#define bin_gid_offset 10-#define bin_gid_size 2-#define bin_nlink_offset 12-#define bin_nlink_size 2-#define bin_rdev_offset 14-#define bin_rdev_size 2-#define bin_mtime_offset 16-#define bin_mtime_size 4-#define bin_namesize_offset 20-#define bin_namesize_size 2-#define bin_filesize_offset 22-#define bin_filesize_size 4-#define bin_header_size 26--#define odc_magic_offset 0-#define odc_magic_size 6-#define odc_dev_offset 6-#define odc_dev_size 6-#define odc_ino_offset 12-#define odc_ino_size 6-#define odc_mode_offset 18-#define odc_mode_size 6-#define odc_uid_offset 24-#define odc_uid_size 6-#define odc_gid_offset 30-#define odc_gid_size 6-#define odc_nlink_offset 36-#define odc_nlink_size 6-#define odc_rdev_offset 42-#define odc_rdev_size 6-#define odc_mtime_offset 48-#define odc_mtime_size 11-#define odc_namesize_offset 59-#define odc_namesize_size 6-#define odc_filesize_offset 65-#define odc_filesize_size 11-#define odc_header_size 76--#define newc_magic_offset 0-#define newc_magic_size 6-#define newc_ino_offset 6-#define newc_ino_size 8-#define newc_mode_offset 14-#define newc_mode_size 8-#define newc_uid_offset 22-#define newc_uid_size 8-#define newc_gid_offset 30-#define newc_gid_size 8-#define newc_nlink_offset 38-#define newc_nlink_size 8-#define newc_mtime_offset 46-#define newc_mtime_size 8-#define newc_filesize_offset 54-#define newc_filesize_size 8-#define newc_devmajor_offset 62-#define newc_devmajor_size 8-#define newc_devminor_offset 70-#define newc_devminor_size 8-#define newc_rdevmajor_offset 78-#define newc_rdevmajor_size 8-#define newc_rdevminor_offset 86-#define newc_rdevminor_size 8-#define newc_namesize_offset 94-#define newc_namesize_size 8-#define newc_checksum_offset 102-#define newc_checksum_size 8-#define newc_header_size 110--/*- * An afio large ASCII header, which they named itself.- * afio utility uses this header, if a file size is larger than 2G bytes- * or inode/uid/gid is bigger than 65535(0xFFFF) or mtime is bigger than- * 0x7fffffff, which we cannot record to odc header because of its limit.- * If not, uses odc header.- */-#define afiol_magic_offset 0-#define afiol_magic_size 6-#define afiol_dev_offset 6-#define afiol_dev_size 8 /* hex */-#define afiol_ino_offset 14-#define afiol_ino_size 16 /* hex */-#define afiol_ino_m_offset 30 /* 'm' */-#define afiol_mode_offset 31-#define afiol_mode_size 6 /* oct */-#define afiol_uid_offset 37-#define afiol_uid_size 8 /* hex */-#define afiol_gid_offset 45-#define afiol_gid_size 8 /* hex */-#define afiol_nlink_offset 53-#define afiol_nlink_size 8 /* hex */-#define afiol_rdev_offset 61-#define afiol_rdev_size 8 /* hex */-#define afiol_mtime_offset 69-#define afiol_mtime_size 16 /* hex */-#define afiol_mtime_n_offset 85 /* 'n' */-#define afiol_namesize_offset 86-#define afiol_namesize_size 4 /* hex */-#define afiol_flag_offset 90-#define afiol_flag_size 4 /* hex */-#define afiol_xsize_offset 94-#define afiol_xsize_size 4 /* hex */-#define afiol_xsize_s_offset 98 /* 's' */-#define afiol_filesize_offset 99-#define afiol_filesize_size 16 /* hex */-#define afiol_filesize_c_offset 115 /* ':' */-#define afiol_header_size 116---struct links_entry {- struct links_entry *next;- struct links_entry *previous;- unsigned int links;- dev_t dev;- int64_t ino;- char *name;-};--#define CPIO_MAGIC 0x13141516-struct cpio {- int magic;- int (*read_header)(struct archive_read *, struct cpio *,- struct archive_entry *, size_t *, size_t *);- struct links_entry *links_head;- int64_t entry_bytes_remaining;- int64_t entry_bytes_unconsumed;- int64_t entry_offset;- int64_t entry_padding;-- struct archive_string_conv *opt_sconv;- struct archive_string_conv *sconv_default;- int init_default_conversion;-- int option_pwb;-};--static int64_t atol16(const char *, unsigned);-static int64_t atol8(const char *, unsigned);-static int archive_read_format_cpio_bid(struct archive_read *, int);-static int archive_read_format_cpio_options(struct archive_read *,- const char *, const char *);-static int archive_read_format_cpio_cleanup(struct archive_read *);-static int archive_read_format_cpio_read_data(struct archive_read *,- const void **, size_t *, int64_t *);-static int archive_read_format_cpio_read_header(struct archive_read *,- struct archive_entry *);-static int archive_read_format_cpio_skip(struct archive_read *);-static int64_t be4(const unsigned char *);-static int find_odc_header(struct archive_read *);-static int find_newc_header(struct archive_read *);-static int header_bin_be(struct archive_read *, struct cpio *,- struct archive_entry *, size_t *, size_t *);-static int header_bin_le(struct archive_read *, struct cpio *,- struct archive_entry *, size_t *, size_t *);-static int header_newc(struct archive_read *, struct cpio *,- struct archive_entry *, size_t *, size_t *);-static int header_odc(struct archive_read *, struct cpio *,- struct archive_entry *, size_t *, size_t *);-static int header_afiol(struct archive_read *, struct cpio *,- struct archive_entry *, size_t *, size_t *);-static int is_octal(const char *, size_t);-static int is_hex(const char *, size_t);-static int64_t le4(const unsigned char *);-static int record_hardlink(struct archive_read *a,- struct cpio *cpio, struct archive_entry *entry);--int-archive_read_support_format_cpio(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct cpio *cpio;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_cpio");-- cpio = (struct cpio *)calloc(1, sizeof(*cpio));- if (cpio == NULL) {- archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");- return (ARCHIVE_FATAL);- }- cpio->magic = CPIO_MAGIC;-- r = __archive_read_register_format(a,- cpio,- "cpio",- archive_read_format_cpio_bid,- archive_read_format_cpio_options,- archive_read_format_cpio_read_header,- archive_read_format_cpio_read_data,- archive_read_format_cpio_skip,- NULL,- archive_read_format_cpio_cleanup,- NULL,- NULL);-- if (r != ARCHIVE_OK)- free(cpio);- return (ARCHIVE_OK);-}---static int-archive_read_format_cpio_bid(struct archive_read *a, int best_bid)-{- const unsigned char *p;- struct cpio *cpio;- int bid;-- (void)best_bid; /* UNUSED */-- cpio = (struct cpio *)(a->format->data);-- if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)- return (-1);-- bid = 0;- if (memcmp(p, "070707", 6) == 0) {- /* ASCII cpio archive (odc, POSIX.1) */- cpio->read_header = header_odc;- bid += 48;- /*- * XXX TODO: More verification; Could check that only octal- * digits appear in appropriate header locations. XXX- */- } else if (memcmp(p, "070727", 6) == 0) {- /* afio large ASCII cpio archive */- cpio->read_header = header_odc;- bid += 48;- /*- * XXX TODO: More verification; Could check that almost hex- * digits appear in appropriate header locations. XXX- */- } else if (memcmp(p, "070701", 6) == 0) {- /* ASCII cpio archive (SVR4 without CRC) */- cpio->read_header = header_newc;- bid += 48;- /*- * XXX TODO: More verification; Could check that only hex- * digits appear in appropriate header locations. XXX- */- } else if (memcmp(p, "070702", 6) == 0) {- /* ASCII cpio archive (SVR4 with CRC) */- /* XXX TODO: Flag that we should check the CRC. XXX */- cpio->read_header = header_newc;- bid += 48;- /*- * XXX TODO: More verification; Could check that only hex- * digits appear in appropriate header locations. XXX- */- } else if (p[0] * 256 + p[1] == 070707) {- /* big-endian binary cpio archives */- cpio->read_header = header_bin_be;- bid += 16;- /* Is more verification possible here? */- } else if (p[0] + p[1] * 256 == 070707) {- /* little-endian binary cpio archives */- cpio->read_header = header_bin_le;- bid += 16;- /* Is more verification possible here? */- } else- return (ARCHIVE_WARN);-- return (bid);-}--static int-archive_read_format_cpio_options(struct archive_read *a,- const char *key, const char *val)-{- struct cpio *cpio;- int ret = ARCHIVE_FAILED;-- cpio = (struct cpio *)(a->format->data);- if (strcmp(key, "compat-2x") == 0) {- /* Handle filenames as libarchive 2.x */- cpio->init_default_conversion = (val != NULL)?1:0;- return (ARCHIVE_OK);- } else if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "cpio: hdrcharset option needs a character-set name");- else {- cpio->opt_sconv =- archive_string_conversion_from_charset(- &a->archive, val, 0);- if (cpio->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- } else if (strcmp(key, "pwb") == 0) {- if (val != NULL && val[0] != 0)- cpio->option_pwb = 1;- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-archive_read_format_cpio_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct cpio *cpio;- const void *h, *hl;- struct archive_string_conv *sconv;- size_t namelength;- size_t name_pad;- int r;-- cpio = (struct cpio *)(a->format->data);- sconv = cpio->opt_sconv;- if (sconv == NULL) {- if (!cpio->init_default_conversion) {- cpio->sconv_default =- archive_string_default_conversion_for_read(- &(a->archive));- cpio->init_default_conversion = 1;- }- sconv = cpio->sconv_default;- }- - r = (cpio->read_header(a, cpio, entry, &namelength, &name_pad));-- if (r < ARCHIVE_WARN)- return (r);-- /* Read name from buffer. */- h = __archive_read_ahead(a, namelength + name_pad, NULL);- if (h == NULL)- return (ARCHIVE_FATAL);- if (archive_entry_copy_pathname_l(entry,- (const char *)h, namelength, sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname can't be converted from %s to current locale.",- archive_string_conversion_charset_name(sconv));- r = ARCHIVE_WARN;- }- cpio->entry_offset = 0;-- __archive_read_consume(a, namelength + name_pad);-- /* If this is a symlink, read the link contents. */- if (archive_entry_filetype(entry) == AE_IFLNK) {- if (cpio->entry_bytes_remaining > 1024 * 1024) {- archive_set_error(&a->archive, ENOMEM,- "Rejecting malformed cpio archive: symlink contents exceed 1 megabyte");- return (ARCHIVE_FATAL);- }- hl = __archive_read_ahead(a,- (size_t)cpio->entry_bytes_remaining, NULL);- if (hl == NULL)- return (ARCHIVE_FATAL);- if (archive_entry_copy_symlink_l(entry, (const char *)hl,- (size_t)cpio->entry_bytes_remaining, sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Linkname can't be converted from %s to "- "current locale.",- archive_string_conversion_charset_name(sconv));- r = ARCHIVE_WARN;- }- __archive_read_consume(a, cpio->entry_bytes_remaining);- cpio->entry_bytes_remaining = 0;- }-- /* XXX TODO: If the full mode is 0160200, then this is a Solaris- * ACL description for the following entry. Read this body- * and parse it as a Solaris-style ACL, then read the next- * header. XXX */-- /* Compare name to "TRAILER!!!" to test for end-of-archive. */- if (namelength == 11 && strncmp((const char *)h, "TRAILER!!!",- 10) == 0) {- /* TODO: Store file location of start of block. */- archive_clear_error(&a->archive);- return (ARCHIVE_EOF);- }-- /* Detect and record hardlinks to previously-extracted entries. */- if (record_hardlink(a, cpio, entry) != ARCHIVE_OK) {- return (ARCHIVE_FATAL);- }-- return (r);-}--static int-archive_read_format_cpio_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- ssize_t bytes_read;- struct cpio *cpio;-- cpio = (struct cpio *)(a->format->data);-- if (cpio->entry_bytes_unconsumed) {- __archive_read_consume(a, cpio->entry_bytes_unconsumed);- cpio->entry_bytes_unconsumed = 0;- }-- if (cpio->entry_bytes_remaining > 0) {- *buff = __archive_read_ahead(a, 1, &bytes_read);- if (bytes_read <= 0)- return (ARCHIVE_FATAL);- if (bytes_read > cpio->entry_bytes_remaining)- bytes_read = (ssize_t)cpio->entry_bytes_remaining;- *size = bytes_read;- cpio->entry_bytes_unconsumed = bytes_read;- *offset = cpio->entry_offset;- cpio->entry_offset += bytes_read;- cpio->entry_bytes_remaining -= bytes_read;- return (ARCHIVE_OK);- } else {- if (cpio->entry_padding !=- __archive_read_consume(a, cpio->entry_padding)) {- return (ARCHIVE_FATAL);- }- cpio->entry_padding = 0;- *buff = NULL;- *size = 0;- *offset = cpio->entry_offset;- return (ARCHIVE_EOF);- }-}--static int-archive_read_format_cpio_skip(struct archive_read *a)-{- struct cpio *cpio = (struct cpio *)(a->format->data);- int64_t to_skip = cpio->entry_bytes_remaining + cpio->entry_padding +- cpio->entry_bytes_unconsumed;-- if (to_skip != __archive_read_consume(a, to_skip)) {- return (ARCHIVE_FATAL);- }- cpio->entry_bytes_remaining = 0;- cpio->entry_padding = 0;- cpio->entry_bytes_unconsumed = 0;- return (ARCHIVE_OK);-}--/*- * Skip forward to the next cpio newc header by searching for the- * 07070[12] string. This should be generalized and merged with- * find_odc_header below.- */-static int-is_hex(const char *p, size_t len)-{- while (len-- > 0) {- if ((*p >= '0' && *p <= '9')- || (*p >= 'a' && *p <= 'f')- || (*p >= 'A' && *p <= 'F'))- ++p;- else- return (0);- }- return (1);-}--static int-find_newc_header(struct archive_read *a)-{- const void *h;- const char *p, *q;- size_t skip, skipped = 0;- ssize_t bytes;-- for (;;) {- h = __archive_read_ahead(a, newc_header_size, &bytes);- if (h == NULL)- return (ARCHIVE_FATAL);- p = h;- q = p + bytes;-- /* Try the typical case first, then go into the slow search.*/- if (memcmp("07070", p, 5) == 0- && (p[5] == '1' || p[5] == '2')- && is_hex(p, newc_header_size))- return (ARCHIVE_OK);-- /*- * Scan ahead until we find something that looks- * like a newc header.- */- while (p + newc_header_size <= q) {- switch (p[5]) {- case '1':- case '2':- if (memcmp("07070", p, 5) == 0- && is_hex(p, newc_header_size)) {- skip = p - (const char *)h;- __archive_read_consume(a, skip);- skipped += skip;- if (skipped > 0) {- archive_set_error(&a->archive,- 0,- "Skipped %d bytes before "- "finding valid header",- (int)skipped);- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);- }- p += 2;- break;- case '0':- p++;- break;- default:- p += 6;- break;- }- }- skip = p - (const char *)h;- __archive_read_consume(a, skip);- skipped += skip;- }-}--static int-header_newc(struct archive_read *a, struct cpio *cpio,- struct archive_entry *entry, size_t *namelength, size_t *name_pad)-{- const void *h;- const char *header;- int r;-- r = find_newc_header(a);- if (r < ARCHIVE_WARN)- return (r);-- /* Read fixed-size portion of header. */- h = __archive_read_ahead(a, newc_header_size, NULL);- if (h == NULL)- return (ARCHIVE_FATAL);-- /* Parse out hex fields. */- header = (const char *)h;-- if (memcmp(header + newc_magic_offset, "070701", 6) == 0) {- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;- a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)";- } else if (memcmp(header + newc_magic_offset, "070702", 6) == 0) {- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC;- a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)";- } else {- /* TODO: Abort here? */- }-- archive_entry_set_devmajor(entry,- (dev_t)atol16(header + newc_devmajor_offset, newc_devmajor_size));- archive_entry_set_devminor(entry, - (dev_t)atol16(header + newc_devminor_offset, newc_devminor_size));- archive_entry_set_ino(entry, atol16(header + newc_ino_offset, newc_ino_size));- archive_entry_set_mode(entry, - (mode_t)atol16(header + newc_mode_offset, newc_mode_size));- archive_entry_set_uid(entry, atol16(header + newc_uid_offset, newc_uid_size));- archive_entry_set_gid(entry, atol16(header + newc_gid_offset, newc_gid_size));- archive_entry_set_nlink(entry,- (unsigned int)atol16(header + newc_nlink_offset, newc_nlink_size));- archive_entry_set_rdevmajor(entry,- (dev_t)atol16(header + newc_rdevmajor_offset, newc_rdevmajor_size));- archive_entry_set_rdevminor(entry,- (dev_t)atol16(header + newc_rdevminor_offset, newc_rdevminor_size));- archive_entry_set_mtime(entry, atol16(header + newc_mtime_offset, newc_mtime_size), 0);- *namelength = (size_t)atol16(header + newc_namesize_offset, newc_namesize_size);- /* Pad name to 2 more than a multiple of 4. */- *name_pad = (2 - *namelength) & 3;-- /* Make sure that the padded name length fits into size_t. */- if (*name_pad > SIZE_MAX - *namelength) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "cpio archive has invalid namelength");- return (ARCHIVE_FATAL);- }-- /*- * Note: entry_bytes_remaining is at least 64 bits and- * therefore guaranteed to be big enough for a 33-bit file- * size.- */- cpio->entry_bytes_remaining =- atol16(header + newc_filesize_offset, newc_filesize_size);- archive_entry_set_size(entry, cpio->entry_bytes_remaining);- /* Pad file contents to a multiple of 4. */- cpio->entry_padding = 3 & -cpio->entry_bytes_remaining;- __archive_read_consume(a, newc_header_size);- return (r);-}--/*- * Skip forward to the next cpio odc header by searching for the- * 070707 string. This is a hand-optimized search that could- * probably be easily generalized to handle all character-based- * cpio variants.- */-static int-is_octal(const char *p, size_t len)-{- while (len-- > 0) {- if (*p < '0' || *p > '7')- return (0);- ++p;- }- return (1);-}--static int-is_afio_large(const char *h, size_t len)-{- if (len < afiol_header_size)- return (0);- if (h[afiol_ino_m_offset] != 'm'- || h[afiol_mtime_n_offset] != 'n'- || h[afiol_xsize_s_offset] != 's'- || h[afiol_filesize_c_offset] != ':')- return (0);- if (!is_hex(h + afiol_dev_offset, afiol_ino_m_offset - afiol_dev_offset))- return (0);- if (!is_hex(h + afiol_mode_offset, afiol_mtime_n_offset - afiol_mode_offset))- return (0);- if (!is_hex(h + afiol_namesize_offset, afiol_xsize_s_offset - afiol_namesize_offset))- return (0);- if (!is_hex(h + afiol_filesize_offset, afiol_filesize_size))- return (0);- return (1);-}--static int-find_odc_header(struct archive_read *a)-{- const void *h;- const char *p, *q;- size_t skip, skipped = 0;- ssize_t bytes;-- for (;;) {- h = __archive_read_ahead(a, odc_header_size, &bytes);- if (h == NULL)- return (ARCHIVE_FATAL);- p = h;- q = p + bytes;-- /* Try the typical case first, then go into the slow search.*/- if (memcmp("070707", p, 6) == 0 && is_octal(p, odc_header_size))- return (ARCHIVE_OK);- if (memcmp("070727", p, 6) == 0 && is_afio_large(p, bytes)) {- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE;- return (ARCHIVE_OK);- }-- /*- * Scan ahead until we find something that looks- * like an odc header.- */- while (p + odc_header_size <= q) {- switch (p[5]) {- case '7':- if ((memcmp("070707", p, 6) == 0- && is_octal(p, odc_header_size))- || (memcmp("070727", p, 6) == 0- && is_afio_large(p, q - p))) {- skip = p - (const char *)h;- __archive_read_consume(a, skip);- skipped += skip;- if (p[4] == '2')- a->archive.archive_format =- ARCHIVE_FORMAT_CPIO_AFIO_LARGE;- if (skipped > 0) {- archive_set_error(&a->archive,- 0,- "Skipped %d bytes before "- "finding valid header",- (int)skipped);- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);- }- p += 2;- break;- case '0':- p++;- break;- default:- p += 6;- break;- }- }- skip = p - (const char *)h;- __archive_read_consume(a, skip);- skipped += skip;- }-}--static int-header_odc(struct archive_read *a, struct cpio *cpio,- struct archive_entry *entry, size_t *namelength, size_t *name_pad)-{- const void *h;- int r;- const char *header;-- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;- a->archive.archive_format_name = "POSIX octet-oriented cpio";-- /* Find the start of the next header. */- r = find_odc_header(a);- if (r < ARCHIVE_WARN)- return (r);-- if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_AFIO_LARGE) {- int r2 = (header_afiol(a, cpio, entry, namelength, name_pad));- if (r2 == ARCHIVE_OK)- return (r);- else- return (r2);- }-- /* Read fixed-size portion of header. */- h = __archive_read_ahead(a, odc_header_size, NULL);- if (h == NULL)- return (ARCHIVE_FATAL);-- /* Parse out octal fields. */- header = (const char *)h;-- archive_entry_set_dev(entry, - (dev_t)atol8(header + odc_dev_offset, odc_dev_size));- archive_entry_set_ino(entry, atol8(header + odc_ino_offset, odc_ino_size));- archive_entry_set_mode(entry, - (mode_t)atol8(header + odc_mode_offset, odc_mode_size));- archive_entry_set_uid(entry, atol8(header + odc_uid_offset, odc_uid_size));- archive_entry_set_gid(entry, atol8(header + odc_gid_offset, odc_gid_size));- archive_entry_set_nlink(entry, - (unsigned int)atol8(header + odc_nlink_offset, odc_nlink_size));- archive_entry_set_rdev(entry,- (dev_t)atol8(header + odc_rdev_offset, odc_rdev_size));- archive_entry_set_mtime(entry, atol8(header + odc_mtime_offset, odc_mtime_size), 0);- *namelength = (size_t)atol8(header + odc_namesize_offset, odc_namesize_size);- *name_pad = 0; /* No padding of filename. */-- /*- * Note: entry_bytes_remaining is at least 64 bits and- * therefore guaranteed to be big enough for a 33-bit file- * size.- */- cpio->entry_bytes_remaining =- atol8(header + odc_filesize_offset, odc_filesize_size);- archive_entry_set_size(entry, cpio->entry_bytes_remaining);- cpio->entry_padding = 0;- __archive_read_consume(a, odc_header_size);- return (r);-}--/*- * NOTE: if a filename suffix is ".z", it is the file gziped by afio.- * it would be nice that we can show uncompressed file size and we can- * uncompressed file contents automatically, unfortunately we have nothing- * to get a uncompressed file size while reading each header. It means- * we also cannot uncompress file contents under our framework.- */-static int-header_afiol(struct archive_read *a, struct cpio *cpio,- struct archive_entry *entry, size_t *namelength, size_t *name_pad)-{- const void *h;- const char *header;-- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE;- a->archive.archive_format_name = "afio large ASCII";-- /* Read fixed-size portion of header. */- h = __archive_read_ahead(a, afiol_header_size, NULL);- if (h == NULL)- return (ARCHIVE_FATAL);-- /* Parse out octal fields. */- header = (const char *)h;-- archive_entry_set_dev(entry, - (dev_t)atol16(header + afiol_dev_offset, afiol_dev_size));- archive_entry_set_ino(entry, atol16(header + afiol_ino_offset, afiol_ino_size));- archive_entry_set_mode(entry,- (mode_t)atol8(header + afiol_mode_offset, afiol_mode_size));- archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size));- archive_entry_set_gid(entry, atol16(header + afiol_gid_offset, afiol_gid_size));- archive_entry_set_nlink(entry,- (unsigned int)atol16(header + afiol_nlink_offset, afiol_nlink_size));- archive_entry_set_rdev(entry,- (dev_t)atol16(header + afiol_rdev_offset, afiol_rdev_size));- archive_entry_set_mtime(entry, atol16(header + afiol_mtime_offset, afiol_mtime_size), 0);- *namelength = (size_t)atol16(header + afiol_namesize_offset, afiol_namesize_size);- *name_pad = 0; /* No padding of filename. */-- cpio->entry_bytes_remaining =- atol16(header + afiol_filesize_offset, afiol_filesize_size);- archive_entry_set_size(entry, cpio->entry_bytes_remaining);- cpio->entry_padding = 0;- __archive_read_consume(a, afiol_header_size);- return (ARCHIVE_OK);-}---static int-header_bin_le(struct archive_read *a, struct cpio *cpio,- struct archive_entry *entry, size_t *namelength, size_t *name_pad)-{- const void *h;- const unsigned char *header;-- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;- a->archive.archive_format_name = "cpio (little-endian binary)";-- /* Read fixed-size portion of header. */- h = __archive_read_ahead(a, bin_header_size, NULL);- if (h == NULL) {- archive_set_error(&a->archive, 0,- "End of file trying to read next cpio header");- return (ARCHIVE_FATAL);- }-- /* Parse out binary fields. */- header = (const unsigned char *)h;-- archive_entry_set_dev(entry, header[bin_dev_offset] + header[bin_dev_offset + 1] * 256);- archive_entry_set_ino(entry, header[bin_ino_offset] + header[bin_ino_offset + 1] * 256);- archive_entry_set_mode(entry, header[bin_mode_offset] + header[bin_mode_offset + 1] * 256);- if (cpio->option_pwb) {- /* turn off random bits left over from V6 inode */- archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);- if ((archive_entry_mode(entry) & AE_IFMT) == 0)- archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);- }- archive_entry_set_uid(entry, header[bin_uid_offset] + header[bin_uid_offset + 1] * 256);- archive_entry_set_gid(entry, header[bin_gid_offset] + header[bin_gid_offset + 1] * 256);- archive_entry_set_nlink(entry, header[bin_nlink_offset] + header[bin_nlink_offset + 1] * 256);- archive_entry_set_rdev(entry, header[bin_rdev_offset] + header[bin_rdev_offset + 1] * 256);- archive_entry_set_mtime(entry, le4(header + bin_mtime_offset), 0);- *namelength = header[bin_namesize_offset] + header[bin_namesize_offset + 1] * 256;- *name_pad = *namelength & 1; /* Pad to even. */-- cpio->entry_bytes_remaining = le4(header + bin_filesize_offset);- archive_entry_set_size(entry, cpio->entry_bytes_remaining);- cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */- __archive_read_consume(a, bin_header_size);- return (ARCHIVE_OK);-}--static int-header_bin_be(struct archive_read *a, struct cpio *cpio,- struct archive_entry *entry, size_t *namelength, size_t *name_pad)-{- const void *h;- const unsigned char *header;-- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;- a->archive.archive_format_name = "cpio (big-endian binary)";-- /* Read fixed-size portion of header. */- h = __archive_read_ahead(a, bin_header_size, NULL);- if (h == NULL) {- archive_set_error(&a->archive, 0,- "End of file trying to read next cpio header");- return (ARCHIVE_FATAL);- }-- /* Parse out binary fields. */- header = (const unsigned char *)h;-- archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]);- archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]);- archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]);- if (cpio->option_pwb) {- /* turn off random bits left over from V6 inode */- archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);- if ((archive_entry_mode(entry) & AE_IFMT) == 0)- archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);- }- archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]);- archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]);- archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]);- archive_entry_set_rdev(entry, header[bin_rdev_offset] * 256 + header[bin_rdev_offset + 1]);- archive_entry_set_mtime(entry, be4(header + bin_mtime_offset), 0);- *namelength = header[bin_namesize_offset] * 256 + header[bin_namesize_offset + 1];- *name_pad = *namelength & 1; /* Pad to even. */-- cpio->entry_bytes_remaining = be4(header + bin_filesize_offset);- archive_entry_set_size(entry, cpio->entry_bytes_remaining);- cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */- __archive_read_consume(a, bin_header_size);- return (ARCHIVE_OK);-}--static int-archive_read_format_cpio_cleanup(struct archive_read *a)-{- struct cpio *cpio;-- cpio = (struct cpio *)(a->format->data);- /* Free inode->name map */- while (cpio->links_head != NULL) {- struct links_entry *lp = cpio->links_head->next;-- free(cpio->links_head->name);- free(cpio->links_head);- cpio->links_head = lp;- }- free(cpio);- (a->format->data) = NULL;- return (ARCHIVE_OK);-}--static int64_t-le4(const unsigned char *p)-{- return ((p[0] << 16) | (((int64_t)p[1]) << 24) | (p[2] << 0) | (p[3] << 8));-}---static int64_t-be4(const unsigned char *p)-{- return ((((int64_t)p[0]) << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));-}--/*- * Note that this implementation does not (and should not!) obey- * locale settings; you cannot simply substitute strtol here, since- * it does obey locale.- */-static int64_t-atol8(const char *p, unsigned char_cnt)-{- int64_t l;- int digit;-- l = 0;- while (char_cnt-- > 0) {- if (*p >= '0' && *p <= '7')- digit = *p - '0';- else- return (l);- p++;- l <<= 3;- l |= digit;- }- return (l);-}--static int64_t-atol16(const char *p, unsigned char_cnt)-{- int64_t l;- int digit;-- l = 0;- while (char_cnt-- > 0) {- if (*p >= 'a' && *p <= 'f')- digit = *p - 'a' + 10;- else if (*p >= 'A' && *p <= 'F')- digit = *p - 'A' + 10;- else if (*p >= '0' && *p <= '9')- digit = *p - '0';- else- return (l);- p++;- l <<= 4;- l |= digit;- }- return (l);-}--static int-record_hardlink(struct archive_read *a,- struct cpio *cpio, struct archive_entry *entry)-{- struct links_entry *le;- dev_t dev;- int64_t ino;-- if (archive_entry_nlink(entry) <= 1)- return (ARCHIVE_OK);-- dev = archive_entry_dev(entry);- ino = archive_entry_ino64(entry);-- /*- * First look in the list of multiply-linked files. If we've- * already dumped it, convert this entry to a hard link entry.- */- for (le = cpio->links_head; le; le = le->next) {- if (le->dev == dev && le->ino == ino) {- archive_entry_copy_hardlink(entry, le->name);-- if (--le->links <= 0) {- if (le->previous != NULL)- le->previous->next = le->next;- if (le->next != NULL)- le->next->previous = le->previous;- if (cpio->links_head == le)- cpio->links_head = le->next;- free(le->name);- free(le);- }-- return (ARCHIVE_OK);- }- }-- le = (struct links_entry *)malloc(sizeof(struct links_entry));- if (le == NULL) {- archive_set_error(&a->archive,- ENOMEM, "Out of memory adding file to list");- return (ARCHIVE_FATAL);- }- if (cpio->links_head != NULL)- cpio->links_head->previous = le;- le->next = cpio->links_head;- le->previous = NULL;- cpio->links_head = le;- le->dev = dev;- le->ino = ino;- le->links = archive_entry_nlink(entry) - 1;- le->name = strdup(archive_entry_pathname(entry));- if (le->name == NULL) {- archive_set_error(&a->archive,- ENOMEM, "Out of memory adding file to list");- return (ARCHIVE_FATAL);- }-- return (ARCHIVE_OK);-}
− c/archive_read_support_format_empty.c
@@ -1,96 +0,0 @@-/*-- * 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_read_support_format_empty.c 191524 2009-04-26 18:24:14Z kientzle $");--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_private.h"--static int archive_read_format_empty_bid(struct archive_read *, int);-static int archive_read_format_empty_read_data(struct archive_read *,- const void **, size_t *, int64_t *);-static int archive_read_format_empty_read_header(struct archive_read *,- struct archive_entry *);-int-archive_read_support_format_empty(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_empty");-- r = __archive_read_register_format(a,- NULL,- "empty",- archive_read_format_empty_bid,- NULL,- archive_read_format_empty_read_header,- archive_read_format_empty_read_data,- NULL,- NULL,- NULL,- NULL,- NULL);-- return (r);-}---static int-archive_read_format_empty_bid(struct archive_read *a, int best_bid)-{- if (best_bid < 1 && __archive_read_ahead(a, 1, NULL) == NULL)- return (1);- return (-1);-}--static int-archive_read_format_empty_read_header(struct archive_read *a,- struct archive_entry *entry)-{- (void)a; /* UNUSED */- (void)entry; /* UNUSED */-- a->archive.archive_format = ARCHIVE_FORMAT_EMPTY;- a->archive.archive_format_name = "Empty file";-- return (ARCHIVE_EOF);-}--static int-archive_read_format_empty_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- (void)a; /* UNUSED */- (void)buff; /* UNUSED */- (void)size; /* UNUSED */- (void)offset; /* UNUSED */-- return (ARCHIVE_EOF);-}
− c/archive_read_support_format_iso9660.c
@@ -1,3279 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2009 Andreas Henriksson <andreas@fatal.se>- * Copyright (c) 2009-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_iso9660.c 201246 2009-12-30 05:30:35Z kientzle $");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-/* #include <stdint.h> */ /* See archive_platform.h */-#include <stdio.h>-#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_endian.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_read_private.h"-#include "archive_string.h"--/*- * An overview of ISO 9660 format:- *- * Each disk is laid out as follows:- * * 32k reserved for private use- * * Volume descriptor table. Each volume descriptor- * is 2k and specifies basic format information.- * The "Primary Volume Descriptor" (PVD) is defined by the- * standard and should always be present; other volume- * descriptors include various vendor-specific extensions.- * * Files and directories. Each file/dir is specified by- * an "extent" (starting sector and length in bytes).- * Dirs are just files with directory records packed one- * after another. The PVD contains a single dir entry- * specifying the location of the root directory. Everything- * else follows from there.- *- * This module works by first reading the volume descriptors, then- * building a list of directory entries, sorted by starting- * sector. At each step, I look for the earliest dir entry that- * hasn't yet been read, seek forward to that location and read- * that entry. If it's a dir, I slurp in the new dir entries and- * add them to the heap; if it's a regular file, I return the- * corresponding archive_entry and wait for the client to request- * the file body. This strategy allows us to read most compliant- * CDs with a single pass through the data, as required by libarchive.- */-#define LOGICAL_BLOCK_SIZE 2048-#define SYSTEM_AREA_BLOCK 16--/* Structure of on-disk primary volume descriptor. */-#define PVD_type_offset 0-#define PVD_type_size 1-#define PVD_id_offset (PVD_type_offset + PVD_type_size)-#define PVD_id_size 5-#define PVD_version_offset (PVD_id_offset + PVD_id_size)-#define PVD_version_size 1-#define PVD_reserved1_offset (PVD_version_offset + PVD_version_size)-#define PVD_reserved1_size 1-#define PVD_system_id_offset (PVD_reserved1_offset + PVD_reserved1_size)-#define PVD_system_id_size 32-#define PVD_volume_id_offset (PVD_system_id_offset + PVD_system_id_size)-#define PVD_volume_id_size 32-#define PVD_reserved2_offset (PVD_volume_id_offset + PVD_volume_id_size)-#define PVD_reserved2_size 8-#define PVD_volume_space_size_offset (PVD_reserved2_offset + PVD_reserved2_size)-#define PVD_volume_space_size_size 8-#define PVD_reserved3_offset (PVD_volume_space_size_offset + PVD_volume_space_size_size)-#define PVD_reserved3_size 32-#define PVD_volume_set_size_offset (PVD_reserved3_offset + PVD_reserved3_size)-#define PVD_volume_set_size_size 4-#define PVD_volume_sequence_number_offset (PVD_volume_set_size_offset + PVD_volume_set_size_size)-#define PVD_volume_sequence_number_size 4-#define PVD_logical_block_size_offset (PVD_volume_sequence_number_offset + PVD_volume_sequence_number_size)-#define PVD_logical_block_size_size 4-#define PVD_path_table_size_offset (PVD_logical_block_size_offset + PVD_logical_block_size_size)-#define PVD_path_table_size_size 8-#define PVD_type_1_path_table_offset (PVD_path_table_size_offset + PVD_path_table_size_size)-#define PVD_type_1_path_table_size 4-#define PVD_opt_type_1_path_table_offset (PVD_type_1_path_table_offset + PVD_type_1_path_table_size)-#define PVD_opt_type_1_path_table_size 4-#define PVD_type_m_path_table_offset (PVD_opt_type_1_path_table_offset + PVD_opt_type_1_path_table_size)-#define PVD_type_m_path_table_size 4-#define PVD_opt_type_m_path_table_offset (PVD_type_m_path_table_offset + PVD_type_m_path_table_size)-#define PVD_opt_type_m_path_table_size 4-#define PVD_root_directory_record_offset (PVD_opt_type_m_path_table_offset + PVD_opt_type_m_path_table_size)-#define PVD_root_directory_record_size 34-#define PVD_volume_set_id_offset (PVD_root_directory_record_offset + PVD_root_directory_record_size)-#define PVD_volume_set_id_size 128-#define PVD_publisher_id_offset (PVD_volume_set_id_offset + PVD_volume_set_id_size)-#define PVD_publisher_id_size 128-#define PVD_preparer_id_offset (PVD_publisher_id_offset + PVD_publisher_id_size)-#define PVD_preparer_id_size 128-#define PVD_application_id_offset (PVD_preparer_id_offset + PVD_preparer_id_size)-#define PVD_application_id_size 128-#define PVD_copyright_file_id_offset (PVD_application_id_offset + PVD_application_id_size)-#define PVD_copyright_file_id_size 37-#define PVD_abstract_file_id_offset (PVD_copyright_file_id_offset + PVD_copyright_file_id_size)-#define PVD_abstract_file_id_size 37-#define PVD_bibliographic_file_id_offset (PVD_abstract_file_id_offset + PVD_abstract_file_id_size)-#define PVD_bibliographic_file_id_size 37-#define PVD_creation_date_offset (PVD_bibliographic_file_id_offset + PVD_bibliographic_file_id_size)-#define PVD_creation_date_size 17-#define PVD_modification_date_offset (PVD_creation_date_offset + PVD_creation_date_size)-#define PVD_modification_date_size 17-#define PVD_expiration_date_offset (PVD_modification_date_offset + PVD_modification_date_size)-#define PVD_expiration_date_size 17-#define PVD_effective_date_offset (PVD_expiration_date_offset + PVD_expiration_date_size)-#define PVD_effective_date_size 17-#define PVD_file_structure_version_offset (PVD_effective_date_offset + PVD_effective_date_size)-#define PVD_file_structure_version_size 1-#define PVD_reserved4_offset (PVD_file_structure_version_offset + PVD_file_structure_version_size)-#define PVD_reserved4_size 1-#define PVD_application_data_offset (PVD_reserved4_offset + PVD_reserved4_size)-#define PVD_application_data_size 512-#define PVD_reserved5_offset (PVD_application_data_offset + PVD_application_data_size)-#define PVD_reserved5_size (2048 - PVD_reserved5_offset)--/* TODO: It would make future maintenance easier to just hardcode the- * above values. In particular, ECMA119 states the offsets as part of- * the standard. That would eliminate the need for the following check.*/-#if PVD_reserved5_offset != 1395-#error PVD offset and size definitions are wrong.-#endif---/* Structure of optional on-disk supplementary volume descriptor. */-#define SVD_type_offset 0-#define SVD_type_size 1-#define SVD_id_offset (SVD_type_offset + SVD_type_size)-#define SVD_id_size 5-#define SVD_version_offset (SVD_id_offset + SVD_id_size)-#define SVD_version_size 1-/* ... */-#define SVD_reserved1_offset 72-#define SVD_reserved1_size 8-#define SVD_volume_space_size_offset 80-#define SVD_volume_space_size_size 8-#define SVD_escape_sequences_offset (SVD_volume_space_size_offset + SVD_volume_space_size_size)-#define SVD_escape_sequences_size 32-/* ... */-#define SVD_logical_block_size_offset 128-#define SVD_logical_block_size_size 4-#define SVD_type_L_path_table_offset 140-#define SVD_type_M_path_table_offset 148-/* ... */-#define SVD_root_directory_record_offset 156-#define SVD_root_directory_record_size 34-#define SVD_file_structure_version_offset 881-#define SVD_reserved2_offset 882-#define SVD_reserved2_size 1-#define SVD_reserved3_offset 1395-#define SVD_reserved3_size 653-/* ... */-/* FIXME: validate correctness of last SVD entry offset. */--/* Structure of an on-disk directory record. */-/* Note: ISO9660 stores each multi-byte integer twice, once in- * each byte order. The sizes here are the size of just one- * of the two integers. (This is why the offset of a field isn't- * the same as the offset+size of the previous field.) */-#define DR_length_offset 0-#define DR_length_size 1-#define DR_ext_attr_length_offset 1-#define DR_ext_attr_length_size 1-#define DR_extent_offset 2-#define DR_extent_size 4-#define DR_size_offset 10-#define DR_size_size 4-#define DR_date_offset 18-#define DR_date_size 7-#define DR_flags_offset 25-#define DR_flags_size 1-#define DR_file_unit_size_offset 26-#define DR_file_unit_size_size 1-#define DR_interleave_offset 27-#define DR_interleave_size 1-#define DR_volume_sequence_number_offset 28-#define DR_volume_sequence_number_size 2-#define DR_name_len_offset 32-#define DR_name_len_size 1-#define DR_name_offset 33--#ifdef HAVE_ZLIB_H-static const unsigned char zisofs_magic[8] = {- 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07-};--struct zisofs {- /* Set 1 if this file compressed by paged zlib */- int pz;- int pz_log2_bs; /* Log2 of block size */- uint64_t pz_uncompressed_size;-- int initialized;- unsigned char *uncompressed_buffer;- size_t uncompressed_buffer_size;-- uint32_t pz_offset;- unsigned char header[16];- size_t header_avail;- int header_passed;- unsigned char *block_pointers;- size_t block_pointers_alloc;- size_t block_pointers_size;- size_t block_pointers_avail;- size_t block_off;- uint32_t block_avail;-- z_stream stream;- int stream_valid;-};-#else-struct zisofs {- /* Set 1 if this file compressed by paged zlib */- int pz;-};-#endif--struct content {- uint64_t offset;/* Offset on disk. */- uint64_t size; /* File size in bytes. */- struct content *next;-};--/* In-memory storage for a directory record. */-struct file_info {- struct file_info *use_next;- struct file_info *parent;- struct file_info *next;- struct file_info *re_next;- int subdirs;- uint64_t key; /* Heap Key. */- uint64_t offset; /* Offset on disk. */- uint64_t size; /* File size in bytes. */- uint32_t ce_offset; /* Offset of CE. */- uint32_t ce_size; /* Size of CE. */- char rr_moved; /* Flag to rr_moved. */- char rr_moved_has_re_only;- char re; /* Having RRIP "RE" extension. */- char re_descendant;- uint64_t cl_offset; /* Having RRIP "CL" extension. */- int birthtime_is_set;- time_t birthtime; /* File created time. */- time_t mtime; /* File last modified time. */- time_t atime; /* File last accessed time. */- time_t ctime; /* File attribute change time. */- uint64_t rdev; /* Device number. */- mode_t mode;- uid_t uid;- gid_t gid;- int64_t number;- int nlinks;- struct archive_string name; /* Pathname */- unsigned char *utf16be_name;- size_t utf16be_bytes;- char name_continues; /* Non-zero if name continues */- struct archive_string symlink;- char symlink_continues; /* Non-zero if link continues */- /* Set 1 if this file compressed by paged zlib(zisofs) */- int pz;- int pz_log2_bs; /* Log2 of block size */- uint64_t pz_uncompressed_size;- /* Set 1 if this file is multi extent. */- int multi_extent;- struct {- struct content *first;- struct content **last;- } contents;- struct {- struct file_info *first;- struct file_info **last;- } rede_files;-};--struct heap_queue {- struct file_info **files;- int allocated;- int used;-};--struct iso9660 {- int magic;-#define ISO9660_MAGIC 0x96609660-- int opt_support_joliet;- int opt_support_rockridge;-- struct archive_string pathname;- char seenRockridge; /* Set true if RR extensions are used. */- char seenSUSP; /* Set true if SUSP is being used. */- char seenJoliet;-- unsigned char suspOffset;- struct file_info *rr_moved;- struct read_ce_queue {- struct read_ce_req {- uint64_t offset;/* Offset of CE on disk. */- struct file_info *file;- } *reqs;- int cnt;- int allocated;- } read_ce_req;-- int64_t previous_number;- struct archive_string previous_pathname;-- struct file_info *use_files;- struct heap_queue pending_files;- struct {- struct file_info *first;- struct file_info **last;- } cache_files;- struct {- struct file_info *first;- struct file_info **last;- } re_files;-- uint64_t current_position;- ssize_t logical_block_size;- uint64_t volume_size; /* Total size of volume in bytes. */- int32_t volume_block;/* Total size of volume in logical blocks. */-- struct vd {- int location; /* Location of Extent. */- uint32_t size;- } primary, joliet;-- int64_t entry_sparse_offset;- int64_t entry_bytes_remaining;- size_t entry_bytes_unconsumed;- struct zisofs entry_zisofs;- struct content *entry_content;- struct archive_string_conv *sconv_utf16be;- /*- * Buffers for a full pathname in UTF-16BE in Joliet extensions.- */-#define UTF16_NAME_MAX 1024- unsigned char *utf16be_path;- size_t utf16be_path_len;- unsigned char *utf16be_previous_path;- size_t utf16be_previous_path_len;- /* Null buffer used in bidder to improve its performance. */- unsigned char null[2048];-};--static int archive_read_format_iso9660_bid(struct archive_read *, int);-static int archive_read_format_iso9660_options(struct archive_read *,- const char *, const char *);-static int archive_read_format_iso9660_cleanup(struct archive_read *);-static int archive_read_format_iso9660_read_data(struct archive_read *,- const void **, size_t *, int64_t *);-static int archive_read_format_iso9660_read_data_skip(struct archive_read *);-static int archive_read_format_iso9660_read_header(struct archive_read *,- struct archive_entry *);-static const char *build_pathname(struct archive_string *, struct file_info *, int);-static int build_pathname_utf16be(unsigned char *, size_t, size_t *,- struct file_info *);-#if DEBUG-static void dump_isodirrec(FILE *, const unsigned char *isodirrec);-#endif-static time_t time_from_tm(struct tm *);-static time_t isodate17(const unsigned char *);-static time_t isodate7(const unsigned char *);-static int isBootRecord(struct iso9660 *, const unsigned char *);-static int isVolumePartition(struct iso9660 *, const unsigned char *);-static int isVDSetTerminator(struct iso9660 *, const unsigned char *);-static int isJolietSVD(struct iso9660 *, const unsigned char *);-static int isSVD(struct iso9660 *, const unsigned char *);-static int isEVD(struct iso9660 *, const unsigned char *);-static int isPVD(struct iso9660 *, const unsigned char *);-static int next_cache_entry(struct archive_read *, struct iso9660 *,- struct file_info **);-static int next_entry_seek(struct archive_read *, struct iso9660 *,- struct file_info **);-static struct file_info *- parse_file_info(struct archive_read *a,- struct file_info *parent, const unsigned char *isodirrec,- size_t reclen);-static int parse_rockridge(struct archive_read *a,- struct file_info *file, const unsigned char *start,- const unsigned char *end);-static int register_CE(struct archive_read *a, int32_t location,- struct file_info *file);-static int read_CE(struct archive_read *a, struct iso9660 *iso9660);-static void parse_rockridge_NM1(struct file_info *,- const unsigned char *, int);-static void parse_rockridge_SL1(struct file_info *,- const unsigned char *, int);-static void parse_rockridge_TF1(struct file_info *,- const unsigned char *, int);-static void parse_rockridge_ZF1(struct file_info *,- const unsigned char *, int);-static void register_file(struct iso9660 *, struct file_info *);-static void release_files(struct iso9660 *);-static unsigned toi(const void *p, int n);-static inline void re_add_entry(struct iso9660 *, struct file_info *);-static inline struct file_info * re_get_entry(struct iso9660 *);-static inline int rede_add_entry(struct file_info *);-static inline struct file_info * rede_get_entry(struct file_info *);-static inline void cache_add_entry(struct iso9660 *iso9660,- struct file_info *file);-static inline struct file_info *cache_get_entry(struct iso9660 *iso9660);-static int heap_add_entry(struct archive_read *a, struct heap_queue *heap,- struct file_info *file, uint64_t key);-static struct file_info *heap_get_entry(struct heap_queue *heap);--#define add_entry(arch, iso9660, file) \- heap_add_entry(arch, &((iso9660)->pending_files), file, file->offset)-#define next_entry(iso9660) \- heap_get_entry(&((iso9660)->pending_files))--int-archive_read_support_format_iso9660(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct iso9660 *iso9660;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_iso9660");-- iso9660 = (struct iso9660 *)calloc(1, sizeof(*iso9660));- if (iso9660 == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate iso9660 data");- return (ARCHIVE_FATAL);- }- iso9660->magic = ISO9660_MAGIC;- iso9660->cache_files.first = NULL;- iso9660->cache_files.last = &(iso9660->cache_files.first);- iso9660->re_files.first = NULL;- iso9660->re_files.last = &(iso9660->re_files.first);- /* Enable to support Joliet extensions by default. */- iso9660->opt_support_joliet = 1;- /* Enable to support Rock Ridge extensions by default. */- iso9660->opt_support_rockridge = 1;-- r = __archive_read_register_format(a,- iso9660,- "iso9660",- archive_read_format_iso9660_bid,- archive_read_format_iso9660_options,- archive_read_format_iso9660_read_header,- archive_read_format_iso9660_read_data,- archive_read_format_iso9660_read_data_skip,- NULL,- archive_read_format_iso9660_cleanup,- NULL,- NULL);-- if (r != ARCHIVE_OK) {- free(iso9660);- return (r);- }- return (ARCHIVE_OK);-}---static int-archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)-{- struct iso9660 *iso9660;- ssize_t bytes_read;- const unsigned char *p;- int seenTerminator;-- /* If there's already a better bid than we can ever- make, don't bother testing. */- if (best_bid > 48)- return (-1);-- iso9660 = (struct iso9660 *)(a->format->data);-- /*- * Skip the first 32k (reserved area) and get the first- * 8 sectors of the volume descriptor table. Of course,- * if the I/O layer gives us more, we'll take it.- */-#define RESERVED_AREA (SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE)- p = __archive_read_ahead(a,- RESERVED_AREA + 8 * LOGICAL_BLOCK_SIZE,- &bytes_read);- if (p == NULL)- return (-1);-- /* Skip the reserved area. */- bytes_read -= RESERVED_AREA;- p += RESERVED_AREA;-- /* Check each volume descriptor. */- seenTerminator = 0;- for (; bytes_read > LOGICAL_BLOCK_SIZE;- bytes_read -= LOGICAL_BLOCK_SIZE, p += LOGICAL_BLOCK_SIZE) {- /* Do not handle undefined Volume Descriptor Type. */- if (p[0] >= 4 && p[0] <= 254)- return (0);- /* Standard Identifier must be "CD001" */- if (memcmp(p + 1, "CD001", 5) != 0)- return (0);- if (isPVD(iso9660, p))- continue;- if (!iso9660->joliet.location) {- if (isJolietSVD(iso9660, p))- continue;- }- if (isBootRecord(iso9660, p))- continue;- if (isEVD(iso9660, p))- continue;- if (isSVD(iso9660, p))- continue;- if (isVolumePartition(iso9660, p))- continue;- if (isVDSetTerminator(iso9660, p)) {- seenTerminator = 1;- break;- }- return (0);- }- /*- * ISO 9660 format must have Primary Volume Descriptor and- * Volume Descriptor Set Terminator.- */- if (seenTerminator && iso9660->primary.location > 16)- return (48);-- /* We didn't find a valid PVD; return a bid of zero. */- return (0);-}--static int-archive_read_format_iso9660_options(struct archive_read *a,- const char *key, const char *val)-{- struct iso9660 *iso9660;-- iso9660 = (struct iso9660 *)(a->format->data);-- if (strcmp(key, "joliet") == 0) {- if (val == NULL || strcmp(val, "off") == 0 ||- strcmp(val, "ignore") == 0 ||- strcmp(val, "disable") == 0 ||- strcmp(val, "0") == 0)- iso9660->opt_support_joliet = 0;- else- iso9660->opt_support_joliet = 1;- return (ARCHIVE_OK);- }- if (strcmp(key, "rockridge") == 0 ||- strcmp(key, "Rockridge") == 0) {- iso9660->opt_support_rockridge = val != NULL;- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-isNull(struct iso9660 *iso9660, const unsigned char *h, unsigned offset,-unsigned bytes)-{-- while (bytes >= sizeof(iso9660->null)) {- if (!memcmp(iso9660->null, h + offset, sizeof(iso9660->null)))- return (0);- offset += sizeof(iso9660->null);- bytes -= sizeof(iso9660->null);- }- if (bytes)- return memcmp(iso9660->null, h + offset, bytes) == 0;- else- return (1);-}--static int-isBootRecord(struct iso9660 *iso9660, const unsigned char *h)-{- (void)iso9660; /* UNUSED */-- /* Type of the Volume Descriptor Boot Record must be 0. */- if (h[0] != 0)- return (0);-- /* Volume Descriptor Version must be 1. */- if (h[6] != 1)- return (0);-- return (1);-}--static int-isVolumePartition(struct iso9660 *iso9660, const unsigned char *h)-{- int32_t location;-- /* Type of the Volume Partition Descriptor must be 3. */- if (h[0] != 3)- return (0);-- /* Volume Descriptor Version must be 1. */- if (h[6] != 1)- return (0);- /* Unused Field */- if (h[7] != 0)- return (0);-- location = archive_le32dec(h + 72);- if (location <= SYSTEM_AREA_BLOCK ||- location >= iso9660->volume_block)- return (0);- if ((uint32_t)location != archive_be32dec(h + 76))- return (0);-- return (1);-}--static int-isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)-{- (void)iso9660; /* UNUSED */-- /* Type of the Volume Descriptor Set Terminator must be 255. */- if (h[0] != 255)- return (0);-- /* Volume Descriptor Version must be 1. */- if (h[6] != 1)- return (0);-- /* Reserved field must be 0. */- if (!isNull(iso9660, h, 7, 2048-7))- return (0);-- return (1);-}--static int-isJolietSVD(struct iso9660 *iso9660, const unsigned char *h)-{- const unsigned char *p;- ssize_t logical_block_size;- int32_t volume_block;-- /* Check if current sector is a kind of Supplementary Volume- * Descriptor. */- if (!isSVD(iso9660, h))- return (0);-- /* FIXME: do more validations according to joliet spec. */-- /* check if this SVD contains joliet extension! */- p = h + SVD_escape_sequences_offset;- /* N.B. Joliet spec says p[1] == '\\', but.... */- if (p[0] == '%' && p[1] == '/') {- int level = 0;-- if (p[2] == '@')- level = 1;- else if (p[2] == 'C')- level = 2;- else if (p[2] == 'E')- level = 3;- else /* not joliet */- return (0);-- iso9660->seenJoliet = level;-- } else /* not joliet */- return (0);-- logical_block_size =- archive_le16dec(h + SVD_logical_block_size_offset);- volume_block = archive_le32dec(h + SVD_volume_space_size_offset);-- iso9660->logical_block_size = logical_block_size;- iso9660->volume_block = volume_block;- iso9660->volume_size = logical_block_size * (uint64_t)volume_block;- /* Read Root Directory Record in Volume Descriptor. */- p = h + SVD_root_directory_record_offset;- iso9660->joliet.location = archive_le32dec(p + DR_extent_offset);- iso9660->joliet.size = archive_le32dec(p + DR_size_offset);-- return (48);-}--static int-isSVD(struct iso9660 *iso9660, const unsigned char *h)-{- const unsigned char *p;- ssize_t logical_block_size;- int32_t volume_block;- int32_t location;-- (void)iso9660; /* UNUSED */-- /* Type 2 means it's a SVD. */- if (h[SVD_type_offset] != 2)- return (0);-- /* Reserved field must be 0. */- if (!isNull(iso9660, h, SVD_reserved1_offset, SVD_reserved1_size))- return (0);- if (!isNull(iso9660, h, SVD_reserved2_offset, SVD_reserved2_size))- return (0);- if (!isNull(iso9660, h, SVD_reserved3_offset, SVD_reserved3_size))- return (0);-- /* File structure version must be 1 for ISO9660/ECMA119. */- if (h[SVD_file_structure_version_offset] != 1)- return (0);-- logical_block_size =- archive_le16dec(h + SVD_logical_block_size_offset);- if (logical_block_size <= 0)- return (0);-- volume_block = archive_le32dec(h + SVD_volume_space_size_offset);- if (volume_block <= SYSTEM_AREA_BLOCK+4)- return (0);-- /* Location of Occurrence of Type L Path Table must be- * available location,- * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */- location = archive_le32dec(h+SVD_type_L_path_table_offset);- if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)- return (0);-- /* The Type M Path Table must be at a valid location (WinISO- * and probably other programs omit this, so we allow zero)- *- * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */- location = archive_be32dec(h+SVD_type_M_path_table_offset);- if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)- || location >= volume_block)- return (0);-- /* Read Root Directory Record in Volume Descriptor. */- p = h + SVD_root_directory_record_offset;- if (p[DR_length_offset] != 34)- return (0);-- return (48);-}--static int-isEVD(struct iso9660 *iso9660, const unsigned char *h)-{- const unsigned char *p;- ssize_t logical_block_size;- int32_t volume_block;- int32_t location;-- (void)iso9660; /* UNUSED */-- /* Type of the Enhanced Volume Descriptor must be 2. */- if (h[PVD_type_offset] != 2)- return (0);-- /* EVD version must be 2. */- if (h[PVD_version_offset] != 2)- return (0);-- /* Reserved field must be 0. */- if (h[PVD_reserved1_offset] != 0)- return (0);-- /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))- return (0);-- /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))- return (0);-- /* Logical block size must be > 0. */- /* I've looked at Ecma 119 and can't find any stronger- * restriction on this field. */- logical_block_size =- archive_le16dec(h + PVD_logical_block_size_offset);- if (logical_block_size <= 0)- return (0);-- volume_block =- archive_le32dec(h + PVD_volume_space_size_offset);- if (volume_block <= SYSTEM_AREA_BLOCK+4)- return (0);-- /* File structure version must be 2 for ISO9660:1999. */- if (h[PVD_file_structure_version_offset] != 2)- return (0);-- /* Location of Occurrence of Type L Path Table must be- * available location,- * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */- location = archive_le32dec(h+PVD_type_1_path_table_offset);- if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)- return (0);-- /* Location of Occurrence of Type M Path Table must be- * available location,- * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */- location = archive_be32dec(h+PVD_type_m_path_table_offset);- if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)- || location >= volume_block)- return (0);-- /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved4_offset, PVD_reserved4_size))- return (0);-- /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))- return (0);-- /* Read Root Directory Record in Volume Descriptor. */- p = h + PVD_root_directory_record_offset;- if (p[DR_length_offset] != 34)- return (0);-- return (48);-}--static int-isPVD(struct iso9660 *iso9660, const unsigned char *h)-{- const unsigned char *p;- ssize_t logical_block_size;- int32_t volume_block;- int32_t location;- int i;-- /* Type of the Primary Volume Descriptor must be 1. */- if (h[PVD_type_offset] != 1)- return (0);-- /* PVD version must be 1. */- if (h[PVD_version_offset] != 1)- return (0);-- /* Reserved field must be 0. */- if (h[PVD_reserved1_offset] != 0)- return (0);-- /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))- return (0);-- /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))- return (0);-- /* Logical block size must be > 0. */- /* I've looked at Ecma 119 and can't find any stronger- * restriction on this field. */- logical_block_size =- archive_le16dec(h + PVD_logical_block_size_offset);- if (logical_block_size <= 0)- return (0);-- volume_block = archive_le32dec(h + PVD_volume_space_size_offset);- if (volume_block <= SYSTEM_AREA_BLOCK+4)- return (0);-- /* File structure version must be 1 for ISO9660/ECMA119. */- if (h[PVD_file_structure_version_offset] != 1)- return (0);-- /* Location of Occurrence of Type L Path Table must be- * available location,- * > SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */- location = archive_le32dec(h+PVD_type_1_path_table_offset);- if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)- return (0);-- /* The Type M Path Table must also be at a valid location- * (although ECMA 119 requires a Type M Path Table, WinISO and- * probably other programs omit it, so we permit a zero here)- *- * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */- location = archive_be32dec(h+PVD_type_m_path_table_offset);- if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)- || location >= volume_block)- return (0);-- /* Reserved field must be 0. */- /* But accept NetBSD/FreeBSD "makefs" images with 0x20 here. */- for (i = 0; i < PVD_reserved4_size; ++i)- if (h[PVD_reserved4_offset + i] != 0- && h[PVD_reserved4_offset + i] != 0x20)- return (0);-- /* Reserved field must be 0. */- if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))- return (0);-- /* XXX TODO: Check other values for sanity; reject more- * malformed PVDs. XXX */-- /* Read Root Directory Record in Volume Descriptor. */- p = h + PVD_root_directory_record_offset;- if (p[DR_length_offset] != 34)- return (0);-- if (!iso9660->primary.location) {- iso9660->logical_block_size = logical_block_size;- iso9660->volume_block = volume_block;- iso9660->volume_size =- logical_block_size * (uint64_t)volume_block;- iso9660->primary.location =- archive_le32dec(p + DR_extent_offset);- iso9660->primary.size = archive_le32dec(p + DR_size_offset);- }-- return (48);-}--static int-read_children(struct archive_read *a, struct file_info *parent)-{- struct iso9660 *iso9660;- const unsigned char *b, *p;- struct file_info *multi;- size_t step, skip_size;-- iso9660 = (struct iso9660 *)(a->format->data);- /* flush any remaining bytes from the last round to ensure- * we're positioned */- if (iso9660->entry_bytes_unconsumed) {- __archive_read_consume(a, iso9660->entry_bytes_unconsumed);- iso9660->entry_bytes_unconsumed = 0;- }- if (iso9660->current_position > parent->offset) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Ignoring out-of-order directory (%s) %jd > %jd",- parent->name.s,- (intmax_t)iso9660->current_position,- (intmax_t)parent->offset);- return (ARCHIVE_WARN);- }- if (parent->offset + parent->size > iso9660->volume_size) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Directory is beyond end-of-media: %s",- parent->name.s);- return (ARCHIVE_WARN);- }- if (iso9660->current_position < parent->offset) {- int64_t skipsize;-- skipsize = parent->offset - iso9660->current_position;- skipsize = __archive_read_consume(a, skipsize);- if (skipsize < 0)- return ((int)skipsize);- iso9660->current_position = parent->offset;- }-- step = (size_t)(((parent->size + iso9660->logical_block_size -1) /- iso9660->logical_block_size) * iso9660->logical_block_size);- b = __archive_read_ahead(a, step, NULL);- if (b == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to read full block when scanning "- "ISO9660 directory list");- return (ARCHIVE_FATAL);- }- iso9660->current_position += step;- multi = NULL;- skip_size = step;- while (step) {- p = b;- b += iso9660->logical_block_size;- step -= iso9660->logical_block_size;- for (; *p != 0 && p + DR_name_offset < b && p + *p <= b;- p += *p) {- struct file_info *child;-- /* N.B.: these special directory identifiers- * are 8 bit "values" even on a- * Joliet CD with UCS-2 (16bit) encoding.- */-- /* Skip '.' entry. */- if (*(p + DR_name_len_offset) == 1- && *(p + DR_name_offset) == '\0')- continue;- /* Skip '..' entry. */- if (*(p + DR_name_len_offset) == 1- && *(p + DR_name_offset) == '\001')- continue;- child = parse_file_info(a, parent, p, b - p);- if (child == NULL) {- __archive_read_consume(a, skip_size);- return (ARCHIVE_FATAL);- }- if (child->cl_offset == 0 &&- (child->multi_extent || multi != NULL)) {- struct content *con;-- if (multi == NULL) {- multi = child;- multi->contents.first = NULL;- multi->contents.last =- &(multi->contents.first);- }- con = malloc(sizeof(struct content));- if (con == NULL) {- archive_set_error(- &a->archive, ENOMEM,- "No memory for multi extent");- __archive_read_consume(a, skip_size);- return (ARCHIVE_FATAL);- }- con->offset = child->offset;- con->size = child->size;- con->next = NULL;- *multi->contents.last = con;- multi->contents.last = &(con->next);- if (multi == child) {- if (add_entry(a, iso9660, child)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- } else {- multi->size += child->size;- if (!child->multi_extent)- multi = NULL;- }- } else- if (add_entry(a, iso9660, child) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }- }-- __archive_read_consume(a, skip_size);-- /* Read data which recorded by RRIP "CE" extension. */- if (read_CE(a, iso9660) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- return (ARCHIVE_OK);-}--static int-choose_volume(struct archive_read *a, struct iso9660 *iso9660)-{- struct file_info *file;- int64_t skipsize;- struct vd *vd;- const void *block;- char seenJoliet;-- vd = &(iso9660->primary);- if (!iso9660->opt_support_joliet)- iso9660->seenJoliet = 0;- if (iso9660->seenJoliet &&- vd->location > iso9660->joliet.location)- /* This condition is unlikely; by way of caution. */- vd = &(iso9660->joliet);-- skipsize = LOGICAL_BLOCK_SIZE * (int64_t)vd->location;- skipsize = __archive_read_consume(a, skipsize);- if (skipsize < 0)- return ((int)skipsize);- iso9660->current_position = skipsize;-- block = __archive_read_ahead(a, vd->size, NULL);- if (block == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to read full block when scanning "- "ISO9660 directory list");- return (ARCHIVE_FATAL);- }-- /*- * While reading Root Directory, flag seenJoliet must be zero to- * avoid converting special name 0x00(Current Directory) and- * next byte to UCS2.- */- seenJoliet = iso9660->seenJoliet;/* Save flag. */- iso9660->seenJoliet = 0;- file = parse_file_info(a, NULL, block, vd->size);- if (file == NULL)- return (ARCHIVE_FATAL);- iso9660->seenJoliet = seenJoliet;-- /*- * If the iso image has both RockRidge and Joliet, we preferentially- * use RockRidge Extensions rather than Joliet ones.- */- if (vd == &(iso9660->primary) && iso9660->seenRockridge- && iso9660->seenJoliet)- iso9660->seenJoliet = 0;-- if (vd == &(iso9660->primary) && !iso9660->seenRockridge- && iso9660->seenJoliet) {- /* Switch reading data from primary to joliet. */- vd = &(iso9660->joliet);- skipsize = LOGICAL_BLOCK_SIZE * (int64_t)vd->location;- skipsize -= iso9660->current_position;- skipsize = __archive_read_consume(a, skipsize);- if (skipsize < 0)- return ((int)skipsize);- iso9660->current_position += skipsize;-- block = __archive_read_ahead(a, vd->size, NULL);- if (block == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to read full block when scanning "- "ISO9660 directory list");- return (ARCHIVE_FATAL);- }- iso9660->seenJoliet = 0;- file = parse_file_info(a, NULL, block, vd->size);- if (file == NULL)- return (ARCHIVE_FATAL);- iso9660->seenJoliet = seenJoliet;- }-- /* Store the root directory in the pending list. */- if (add_entry(a, iso9660, file) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- if (iso9660->seenRockridge) {- a->archive.archive_format = ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;- a->archive.archive_format_name =- "ISO9660 with Rockridge extensions";- }-- return (ARCHIVE_OK);-}--static int-archive_read_format_iso9660_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct iso9660 *iso9660;- struct file_info *file;- int r, rd_r = ARCHIVE_OK;-- iso9660 = (struct iso9660 *)(a->format->data);-- if (!a->archive.archive_format) {- a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;- a->archive.archive_format_name = "ISO9660";- }-- if (iso9660->current_position == 0) {- r = choose_volume(a, iso9660);- if (r != ARCHIVE_OK)- return (r);- }-- file = NULL;/* Eliminate a warning. */- /* Get the next entry that appears after the current offset. */- r = next_entry_seek(a, iso9660, &file);- if (r != ARCHIVE_OK)- return (r);-- if (iso9660->seenJoliet) {- /*- * Convert UTF-16BE of a filename to local locale MBS- * and store the result into a filename field.- */- if (iso9660->sconv_utf16be == NULL) {- iso9660->sconv_utf16be =- archive_string_conversion_from_charset(- &(a->archive), "UTF-16BE", 1);- if (iso9660->sconv_utf16be == NULL)- /* Couldn't allocate memory */- return (ARCHIVE_FATAL);- }- if (iso9660->utf16be_path == NULL) {- iso9660->utf16be_path = malloc(UTF16_NAME_MAX);- if (iso9660->utf16be_path == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory");- return (ARCHIVE_FATAL);- }- }- if (iso9660->utf16be_previous_path == NULL) {- iso9660->utf16be_previous_path = malloc(UTF16_NAME_MAX);- if (iso9660->utf16be_previous_path == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory");- return (ARCHIVE_FATAL);- }- }-- iso9660->utf16be_path_len = 0;- if (build_pathname_utf16be(iso9660->utf16be_path,- UTF16_NAME_MAX, &(iso9660->utf16be_path_len), file) != 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname is too long");- return (ARCHIVE_FATAL);- }-- r = archive_entry_copy_pathname_l(entry,- (const char *)iso9660->utf16be_path,- iso9660->utf16be_path_len,- iso9660->sconv_utf16be);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "No memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname cannot be converted "- "from %s to current locale.",- archive_string_conversion_charset_name(- iso9660->sconv_utf16be));-- rd_r = ARCHIVE_WARN;- }- } else {- const char *path = build_pathname(&iso9660->pathname, file, 0);- if (path == NULL) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname is too long");- return (ARCHIVE_FATAL);- } else {- archive_string_empty(&iso9660->pathname);- archive_entry_set_pathname(entry, path);- }- }-- iso9660->entry_bytes_remaining = file->size;- /* Offset for sparse-file-aware clients. */- iso9660->entry_sparse_offset = 0;-- if (file->offset + file->size > iso9660->volume_size) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "File is beyond end-of-media: %s",- archive_entry_pathname(entry));- iso9660->entry_bytes_remaining = 0;- return (ARCHIVE_WARN);- }-- /* Set up the entry structure with information about this entry. */- archive_entry_set_mode(entry, file->mode);- archive_entry_set_uid(entry, file->uid);- archive_entry_set_gid(entry, file->gid);- archive_entry_set_nlink(entry, file->nlinks);- if (file->birthtime_is_set)- archive_entry_set_birthtime(entry, file->birthtime, 0);- else- archive_entry_unset_birthtime(entry);- archive_entry_set_mtime(entry, file->mtime, 0);- archive_entry_set_ctime(entry, file->ctime, 0);- archive_entry_set_atime(entry, file->atime, 0);- /* N.B.: Rock Ridge supports 64-bit device numbers. */- archive_entry_set_rdev(entry, (dev_t)file->rdev);- archive_entry_set_size(entry, iso9660->entry_bytes_remaining);- if (file->symlink.s != NULL)- archive_entry_copy_symlink(entry, file->symlink.s);-- /* Note: If the input isn't seekable, we can't rewind to- * return the same body again, so if the next entry refers to- * the same data, we have to return it as a hardlink to the- * original entry. */- if (file->number != -1 &&- file->number == iso9660->previous_number) {- if (iso9660->seenJoliet) {- r = archive_entry_copy_hardlink_l(entry,- (const char *)iso9660->utf16be_previous_path,- iso9660->utf16be_previous_path_len,- iso9660->sconv_utf16be);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "No memory for Linkname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Linkname cannot be converted "- "from %s to current locale.",- archive_string_conversion_charset_name(- iso9660->sconv_utf16be));- rd_r = ARCHIVE_WARN;- }- } else- archive_entry_set_hardlink(entry,- iso9660->previous_pathname.s);- archive_entry_unset_size(entry);- iso9660->entry_bytes_remaining = 0;- return (rd_r);- }-- if ((file->mode & AE_IFMT) != AE_IFDIR &&- file->offset < iso9660->current_position) {- int64_t r64;-- r64 = __archive_read_seek(a, file->offset, SEEK_SET);- if (r64 != (int64_t)file->offset) {- /* We can't seek backwards to extract it, so issue- * a warning. Note that this can only happen if- * this entry was added to the heap after we passed- * this offset, that is, only if the directory- * mentioning this entry is later than the body of- * the entry. Such layouts are very unusual; most- * ISO9660 writers lay out and record all directory- * information first, then store all file bodies. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Ignoring out-of-order file @%jx (%s) %jd < %jd",- (intmax_t)file->number,- iso9660->pathname.s,- (intmax_t)file->offset,- (intmax_t)iso9660->current_position);- iso9660->entry_bytes_remaining = 0;- return (ARCHIVE_WARN);- }- iso9660->current_position = (uint64_t)r64;- }-- /* Initialize zisofs variables. */- iso9660->entry_zisofs.pz = file->pz;- if (file->pz) {-#ifdef HAVE_ZLIB_H- struct zisofs *zisofs;-- zisofs = &iso9660->entry_zisofs;- zisofs->initialized = 0;- zisofs->pz_log2_bs = file->pz_log2_bs;- zisofs->pz_uncompressed_size = file->pz_uncompressed_size;- zisofs->pz_offset = 0;- zisofs->header_avail = 0;- zisofs->header_passed = 0;- zisofs->block_pointers_avail = 0;-#endif- archive_entry_set_size(entry, file->pz_uncompressed_size);- }-- iso9660->previous_number = file->number;- if (iso9660->seenJoliet) {- memcpy(iso9660->utf16be_previous_path, iso9660->utf16be_path,- iso9660->utf16be_path_len);- iso9660->utf16be_previous_path_len = iso9660->utf16be_path_len;- } else- archive_strcpy(- &iso9660->previous_pathname, iso9660->pathname.s);-- /* Reset entry_bytes_remaining if the file is multi extent. */- iso9660->entry_content = file->contents.first;- if (iso9660->entry_content != NULL)- iso9660->entry_bytes_remaining = iso9660->entry_content->size;-- if (archive_entry_filetype(entry) == AE_IFDIR) {- /* Overwrite nlinks by proper link number which is- * calculated from number of sub directories. */- archive_entry_set_nlink(entry, 2 + file->subdirs);- /* Directory data has been read completely. */- iso9660->entry_bytes_remaining = 0;- }-- if (rd_r != ARCHIVE_OK)- return (rd_r);- return (ARCHIVE_OK);-}--static int-archive_read_format_iso9660_read_data_skip(struct archive_read *a)-{- /* Because read_next_header always does an explicit skip- * to the next entry, we don't need to do anything here. */- (void)a; /* UNUSED */- return (ARCHIVE_OK);-}--#ifdef HAVE_ZLIB_H--static int-zisofs_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- struct iso9660 *iso9660;- struct zisofs *zisofs;- const unsigned char *p;- size_t avail;- ssize_t bytes_read;- size_t uncompressed_size;- int r;-- iso9660 = (struct iso9660 *)(a->format->data);- zisofs = &iso9660->entry_zisofs;-- p = __archive_read_ahead(a, 1, &bytes_read);- if (bytes_read <= 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated zisofs file body");- return (ARCHIVE_FATAL);- }- if (bytes_read > iso9660->entry_bytes_remaining)- bytes_read = (ssize_t)iso9660->entry_bytes_remaining;- avail = bytes_read;- uncompressed_size = 0;-- if (!zisofs->initialized) {- size_t ceil, xsize;-- /* Allocate block pointers buffer. */- ceil = (size_t)((zisofs->pz_uncompressed_size +- (((int64_t)1) << zisofs->pz_log2_bs) - 1)- >> zisofs->pz_log2_bs);- xsize = (ceil + 1) * 4;- if (zisofs->block_pointers_alloc < xsize) {- size_t alloc;-- if (zisofs->block_pointers != NULL)- free(zisofs->block_pointers);- alloc = ((xsize >> 10) + 1) << 10;- zisofs->block_pointers = malloc(alloc);- if (zisofs->block_pointers == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for zisofs decompression");- return (ARCHIVE_FATAL);- }- zisofs->block_pointers_alloc = alloc;- }- zisofs->block_pointers_size = xsize;-- /* Allocate uncompressed data buffer. */- xsize = (size_t)1UL << zisofs->pz_log2_bs;- if (zisofs->uncompressed_buffer_size < xsize) {- if (zisofs->uncompressed_buffer != NULL)- free(zisofs->uncompressed_buffer);- zisofs->uncompressed_buffer = malloc(xsize);- if (zisofs->uncompressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for zisofs decompression");- return (ARCHIVE_FATAL);- }- }- zisofs->uncompressed_buffer_size = xsize;-- /*- * Read the file header, and check the magic code of zisofs.- */- if (zisofs->header_avail < sizeof(zisofs->header)) {- xsize = sizeof(zisofs->header) - zisofs->header_avail;- if (avail < xsize)- xsize = avail;- memcpy(zisofs->header + zisofs->header_avail, p, xsize);- zisofs->header_avail += xsize;- avail -= xsize;- p += xsize;- }- if (!zisofs->header_passed &&- zisofs->header_avail == sizeof(zisofs->header)) {- int err = 0;-- if (memcmp(zisofs->header, zisofs_magic,- sizeof(zisofs_magic)) != 0)- err = 1;- if (archive_le32dec(zisofs->header + 8)- != zisofs->pz_uncompressed_size)- err = 1;- if (zisofs->header[12] != 4)- err = 1;- if (zisofs->header[13] != zisofs->pz_log2_bs)- err = 1;- if (err) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Illegal zisofs file body");- return (ARCHIVE_FATAL);- }- zisofs->header_passed = 1;- }- /*- * Read block pointers.- */- if (zisofs->header_passed &&- zisofs->block_pointers_avail < zisofs->block_pointers_size) {- xsize = zisofs->block_pointers_size- - zisofs->block_pointers_avail;- if (avail < xsize)- xsize = avail;- memcpy(zisofs->block_pointers- + zisofs->block_pointers_avail, p, xsize);- zisofs->block_pointers_avail += xsize;- avail -= xsize;- p += xsize;- if (zisofs->block_pointers_avail- == zisofs->block_pointers_size) {- /* We've got all block pointers and initialize- * related variables. */- zisofs->block_off = 0;- zisofs->block_avail = 0;- /* Complete a initialization */- zisofs->initialized = 1;- }- }-- if (!zisofs->initialized)- goto next_data; /* We need more data. */- }-- /*- * Get block offsets from block pointers.- */- if (zisofs->block_avail == 0) {- uint32_t bst, bed;-- if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {- /* There isn't a pair of offsets. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Illegal zisofs block pointers");- return (ARCHIVE_FATAL);- }- bst = archive_le32dec(- zisofs->block_pointers + zisofs->block_off);- if (bst != zisofs->pz_offset + (bytes_read - avail)) {- /* TODO: Should we seek offset of current file- * by bst ? */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Illegal zisofs block pointers(cannot seek)");- return (ARCHIVE_FATAL);- }- bed = archive_le32dec(- zisofs->block_pointers + zisofs->block_off + 4);- if (bed < bst) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Illegal zisofs block pointers");- return (ARCHIVE_FATAL);- }- zisofs->block_avail = bed - bst;- zisofs->block_off += 4;-- /* Initialize compression library for new block. */- if (zisofs->stream_valid)- r = inflateReset(&zisofs->stream);- else- r = inflateInit(&zisofs->stream);- if (r != Z_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't initialize zisofs decompression.");- return (ARCHIVE_FATAL);- }- zisofs->stream_valid = 1;- zisofs->stream.total_in = 0;- zisofs->stream.total_out = 0;- }-- /*- * Make uncompressed data.- */- if (zisofs->block_avail == 0) {- memset(zisofs->uncompressed_buffer, 0,- zisofs->uncompressed_buffer_size);- uncompressed_size = zisofs->uncompressed_buffer_size;- } else {- zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;- if (avail > zisofs->block_avail)- zisofs->stream.avail_in = zisofs->block_avail;- else- zisofs->stream.avail_in = (uInt)avail;- zisofs->stream.next_out = zisofs->uncompressed_buffer;- zisofs->stream.avail_out =- (uInt)zisofs->uncompressed_buffer_size;-- r = inflate(&zisofs->stream, 0);- switch (r) {- case Z_OK: /* Decompressor made some progress.*/- case Z_STREAM_END: /* Found end of stream. */- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "zisofs decompression failed (%d)", r);- return (ARCHIVE_FATAL);- }- uncompressed_size =- zisofs->uncompressed_buffer_size - zisofs->stream.avail_out;- avail -= zisofs->stream.next_in - p;- zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);- }-next_data:- bytes_read -= avail;- *buff = zisofs->uncompressed_buffer;- *size = uncompressed_size;- *offset = iso9660->entry_sparse_offset;- iso9660->entry_sparse_offset += uncompressed_size;- iso9660->entry_bytes_remaining -= bytes_read;- iso9660->current_position += bytes_read;- zisofs->pz_offset += (uint32_t)bytes_read;- iso9660->entry_bytes_unconsumed += bytes_read;-- return (ARCHIVE_OK);-}--#else /* HAVE_ZLIB_H */--static int-zisofs_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{-- (void)buff;/* UNUSED */- (void)size;/* UNUSED */- (void)offset;/* UNUSED */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "zisofs is not supported on this platform.");- return (ARCHIVE_FAILED);-}--#endif /* HAVE_ZLIB_H */--static int-archive_read_format_iso9660_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- ssize_t bytes_read;- struct iso9660 *iso9660;-- iso9660 = (struct iso9660 *)(a->format->data);-- if (iso9660->entry_bytes_unconsumed) {- __archive_read_consume(a, iso9660->entry_bytes_unconsumed);- iso9660->entry_bytes_unconsumed = 0;- }-- if (iso9660->entry_bytes_remaining <= 0) {- if (iso9660->entry_content != NULL)- iso9660->entry_content = iso9660->entry_content->next;- if (iso9660->entry_content == NULL) {- *buff = NULL;- *size = 0;- *offset = iso9660->entry_sparse_offset;- return (ARCHIVE_EOF);- }- /* Seek forward to the start of the entry. */- if (iso9660->current_position < iso9660->entry_content->offset) {- int64_t step;-- step = iso9660->entry_content->offset -- iso9660->current_position;- step = __archive_read_consume(a, step);- if (step < 0)- return ((int)step);- iso9660->current_position =- iso9660->entry_content->offset;- }- if (iso9660->entry_content->offset < iso9660->current_position) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Ignoring out-of-order file (%s) %jd < %jd",- iso9660->pathname.s,- (intmax_t)iso9660->entry_content->offset,- (intmax_t)iso9660->current_position);- *buff = NULL;- *size = 0;- *offset = iso9660->entry_sparse_offset;- return (ARCHIVE_WARN);- }- iso9660->entry_bytes_remaining = iso9660->entry_content->size;- }- if (iso9660->entry_zisofs.pz)- return (zisofs_read_data(a, buff, size, offset));-- *buff = __archive_read_ahead(a, 1, &bytes_read);- if (bytes_read == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Truncated input file");- if (*buff == NULL)- return (ARCHIVE_FATAL);- if (bytes_read > iso9660->entry_bytes_remaining)- bytes_read = (ssize_t)iso9660->entry_bytes_remaining;- *size = bytes_read;- *offset = iso9660->entry_sparse_offset;- iso9660->entry_sparse_offset += bytes_read;- iso9660->entry_bytes_remaining -= bytes_read;- iso9660->entry_bytes_unconsumed = bytes_read;- iso9660->current_position += bytes_read;- return (ARCHIVE_OK);-}--static int-archive_read_format_iso9660_cleanup(struct archive_read *a)-{- struct iso9660 *iso9660;- int r = ARCHIVE_OK;-- iso9660 = (struct iso9660 *)(a->format->data);- release_files(iso9660);- free(iso9660->read_ce_req.reqs);- archive_string_free(&iso9660->pathname);- archive_string_free(&iso9660->previous_pathname);- free(iso9660->pending_files.files);-#ifdef HAVE_ZLIB_H- free(iso9660->entry_zisofs.uncompressed_buffer);- free(iso9660->entry_zisofs.block_pointers);- if (iso9660->entry_zisofs.stream_valid) {- if (inflateEnd(&iso9660->entry_zisofs.stream) != Z_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to clean up zlib decompressor");- r = ARCHIVE_FATAL;- }- }-#endif- free(iso9660->utf16be_path);- free(iso9660->utf16be_previous_path);- free(iso9660);- (a->format->data) = NULL;- return (r);-}--/*- * This routine parses a single ISO directory record, makes sense- * of any extensions, and stores the result in memory.- */-static struct file_info *-parse_file_info(struct archive_read *a, struct file_info *parent,- const unsigned char *isodirrec, size_t reclen)-{- struct iso9660 *iso9660;- struct file_info *file, *filep;- size_t name_len;- const unsigned char *rr_start, *rr_end;- const unsigned char *p;- size_t dr_len = 0;- uint64_t fsize, offset;- int32_t location;- int flags;-- iso9660 = (struct iso9660 *)(a->format->data);-- if (reclen != 0)- dr_len = (size_t)isodirrec[DR_length_offset];- /*- * Sanity check that reclen is not zero and dr_len is greater than- * reclen but at least 34- */- if (reclen == 0 || reclen < dr_len || dr_len < 34) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid length of directory record");- return (NULL);- }- name_len = (size_t)isodirrec[DR_name_len_offset];- location = archive_le32dec(isodirrec + DR_extent_offset);- fsize = toi(isodirrec + DR_size_offset, DR_size_size);- /* Sanity check that name_len doesn't exceed dr_len. */- if (dr_len - 33 < name_len || name_len == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid length of file identifier");- return (NULL);- }- /* Sanity check that location doesn't exceed volume block.- * Don't check lower limit of location; it's possibility- * the location has negative value when file type is symbolic- * link or file size is zero. As far as I know latest mkisofs- * do that.- */- if (location > 0 &&- (location + ((fsize + iso9660->logical_block_size -1)- / iso9660->logical_block_size))- > (uint32_t)iso9660->volume_block) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid location of extent of file");- return (NULL);- }- /* Sanity check that location doesn't have a negative value- * when the file is not empty. it's too large. */- if (fsize != 0 && location < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid location of extent of file");- return (NULL);- }-- /* Sanity check that this entry does not create a cycle. */- offset = iso9660->logical_block_size * (uint64_t)location;- for (filep = parent; filep != NULL; filep = filep->parent) {- if (filep->offset == offset) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Directory structure contains loop");- return (NULL);- }- }-- /* Create a new file entry and copy data from the ISO dir record. */- file = (struct file_info *)calloc(1, sizeof(*file));- if (file == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for file entry");- return (NULL);- }- file->parent = parent;- file->offset = offset;- file->size = fsize;- file->mtime = isodate7(isodirrec + DR_date_offset);- file->ctime = file->atime = file->mtime;- file->rede_files.first = NULL;- file->rede_files.last = &(file->rede_files.first);-- p = isodirrec + DR_name_offset;- /* Rockridge extensions (if any) follow name. Compute this- * before fidgeting the name_len below. */- rr_start = p + name_len + (name_len & 1 ? 0 : 1);- rr_end = isodirrec + dr_len;-- if (iso9660->seenJoliet) {- /* Joliet names are max 64 chars (128 bytes) according to spec,- * but genisoimage/mkisofs allows recording longer Joliet- * names which are 103 UCS2 characters(206 bytes) by their- * option '-joliet-long'.- */- if (name_len > 206)- name_len = 206;- name_len &= ~1;-- /* trim trailing first version and dot from filename.- *- * Remember we were in UTF-16BE land!- * SEPARATOR 1 (.) and SEPARATOR 2 (;) are both- * 16 bits big endian characters on Joliet.- *- * TODO: sanitize filename?- * Joliet allows any UCS-2 char except:- * *, /, :, ;, ? and \.- */- /* Chop off trailing ';1' from files. */- if (name_len > 4 && p[name_len-4] == 0 && p[name_len-3] == ';'- && p[name_len-2] == 0 && p[name_len-1] == '1')- name_len -= 4;-#if 0 /* XXX: this somehow manages to strip of single-character file extensions, like '.c'. */- /* Chop off trailing '.' from filenames. */- if (name_len > 2 && p[name_len-2] == 0 && p[name_len-1] == '.')- name_len -= 2;-#endif- if ((file->utf16be_name = malloc(name_len)) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for file name");- goto fail;- }- memcpy(file->utf16be_name, p, name_len);- file->utf16be_bytes = name_len;- } else {- /* Chop off trailing ';1' from files. */- if (name_len > 2 && p[name_len - 2] == ';' &&- p[name_len - 1] == '1')- name_len -= 2;- /* Chop off trailing '.' from filenames. */- if (name_len > 1 && p[name_len - 1] == '.')- --name_len;-- archive_strncpy(&file->name, (const char *)p, name_len);- }-- flags = isodirrec[DR_flags_offset];- if (flags & 0x02)- file->mode = AE_IFDIR | 0700;- else- file->mode = AE_IFREG | 0400;- if (flags & 0x80)- file->multi_extent = 1;- else- file->multi_extent = 0;- /*- * Use a location for the file number, which is treated as an inode- * number to find out hardlink target. If Rockridge extensions is- * being used, the file number will be overwritten by FILE SERIAL- * NUMBER of RRIP "PX" extension.- * Note: Old mkisofs did not record that FILE SERIAL NUMBER- * in ISO images.- * Note2: xorriso set 0 to the location of a symlink file.- */- if (file->size == 0 && location >= 0) {- /* If file->size is zero, its location points wrong place,- * and so we should not use it for the file number.- * When the location has negative value, it can be used- * for the file number.- */- file->number = -1;- /* Do not appear before any directory entries. */- file->offset = -1;- } else- file->number = (int64_t)(uint32_t)location;-- /* Rockridge extensions overwrite information from above. */- if (iso9660->opt_support_rockridge) {- if (parent == NULL && rr_end - rr_start >= 7) {- p = rr_start;- if (memcmp(p, "SP\x07\x01\xbe\xef", 6) == 0) {- /*- * SP extension stores the suspOffset- * (Number of bytes to skip between- * filename and SUSP records.)- * It is mandatory by the SUSP standard- * (IEEE 1281).- *- * It allows SUSP to coexist with- * non-SUSP uses of the System- * Use Area by placing non-SUSP data- * before SUSP data.- *- * SP extension must be in the root- * directory entry, disable all SUSP- * processing if not found.- */- iso9660->suspOffset = p[6];- iso9660->seenSUSP = 1;- rr_start += 7;- }- }- if (iso9660->seenSUSP) {- int r;-- file->name_continues = 0;- file->symlink_continues = 0;- rr_start += iso9660->suspOffset;- r = parse_rockridge(a, file, rr_start, rr_end);- if (r != ARCHIVE_OK)- goto fail;- /*- * A file size of symbolic link files in ISO images- * made by makefs is not zero and its location is- * the same as those of next regular file. That is- * the same as hard like file and it causes unexpected- * error.- */- if (file->size > 0 &&- (file->mode & AE_IFMT) == AE_IFLNK) {- file->size = 0;- file->number = -1;- file->offset = -1;- }- } else- /* If there isn't SUSP, disable parsing- * rock ridge extensions. */- iso9660->opt_support_rockridge = 0;- }-- file->nlinks = 1;/* Reset nlink. we'll calculate it later. */- /* Tell file's parent how many children that parent has. */- if (parent != NULL && (flags & 0x02))- parent->subdirs++;-- if (iso9660->seenRockridge) {- if (parent != NULL && parent->parent == NULL &&- (flags & 0x02) && iso9660->rr_moved == NULL &&- file->name.s &&- (strcmp(file->name.s, "rr_moved") == 0 ||- strcmp(file->name.s, ".rr_moved") == 0)) {- iso9660->rr_moved = file;- file->rr_moved = 1;- file->rr_moved_has_re_only = 1;- file->re = 0;- parent->subdirs--;- } else if (file->re) {- /*- * Sanity check: file's parent is rr_moved.- */- if (parent == NULL || parent->rr_moved == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Invalid Rockridge RE");- goto fail;- }- /*- * Sanity check: file does not have "CL" extension.- */- if (file->cl_offset) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Invalid Rockridge RE and CL");- goto fail;- }- /*- * Sanity check: The file type must be a directory.- */- if ((flags & 0x02) == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Invalid Rockridge RE");- goto fail;- }- } else if (parent != NULL && parent->rr_moved)- file->rr_moved_has_re_only = 0;- else if (parent != NULL && (flags & 0x02) &&- (parent->re || parent->re_descendant))- file->re_descendant = 1;- if (file->cl_offset) {- struct file_info *r;-- if (parent == NULL || parent->parent == NULL) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Invalid Rockridge CL");- goto fail;- }- /*- * Sanity check: The file type must be a regular file.- */- if ((flags & 0x02) != 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Invalid Rockridge CL");- goto fail;- }- parent->subdirs++;- /* Overwrite an offset and a number of this "CL" entry- * to appear before other dirs. "+1" to those is to- * make sure to appear after "RE" entry which this- * "CL" entry should be connected with. */- file->offset = file->number = file->cl_offset + 1;-- /*- * Sanity check: cl_offset does not point at its- * the parents or itself.- */- for (r = parent; r; r = r->parent) {- if (r->offset == file->cl_offset) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Invalid Rockridge CL");- goto fail;- }- }- if (file->cl_offset == file->offset ||- parent->rr_moved) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Invalid Rockridge CL");- goto fail;- }- }- }--#if DEBUG- /* DEBUGGING: Warn about attributes I don't yet fully support. */- if ((flags & ~0x02) != 0) {- fprintf(stderr, "\n ** Unrecognized flag: ");- dump_isodirrec(stderr, isodirrec);- fprintf(stderr, "\n");- } else if (toi(isodirrec + DR_volume_sequence_number_offset, 2) != 1) {- fprintf(stderr, "\n ** Unrecognized sequence number: ");- dump_isodirrec(stderr, isodirrec);- fprintf(stderr, "\n");- } else if (*(isodirrec + DR_file_unit_size_offset) != 0) {- fprintf(stderr, "\n ** Unexpected file unit size: ");- dump_isodirrec(stderr, isodirrec);- fprintf(stderr, "\n");- } else if (*(isodirrec + DR_interleave_offset) != 0) {- fprintf(stderr, "\n ** Unexpected interleave: ");- dump_isodirrec(stderr, isodirrec);- fprintf(stderr, "\n");- } else if (*(isodirrec + DR_ext_attr_length_offset) != 0) {- fprintf(stderr, "\n ** Unexpected extended attribute length: ");- dump_isodirrec(stderr, isodirrec);- fprintf(stderr, "\n");- }-#endif- register_file(iso9660, file);- return (file);-fail:- archive_string_free(&file->name);- free(file);- return (NULL);-}--static int-parse_rockridge(struct archive_read *a, struct file_info *file,- const unsigned char *p, const unsigned char *end)-{- struct iso9660 *iso9660;- int entry_seen = 0;-- iso9660 = (struct iso9660 *)(a->format->data);-- while (p + 4 <= end /* Enough space for another entry. */- && p[0] >= 'A' && p[0] <= 'Z' /* Sanity-check 1st char of name. */- && p[1] >= 'A' && p[1] <= 'Z' /* Sanity-check 2nd char of name. */- && p[2] >= 4 /* Sanity-check length. */- && p + p[2] <= end) { /* Sanity-check length. */- const unsigned char *data = p + 4;- int data_length = p[2] - 4;- int version = p[3];-- switch(p[0]) {- case 'C':- if (p[1] == 'E') {- if (version == 1 && data_length == 24) {- /*- * CE extension comprises:- * 8 byte sector containing extension- * 8 byte offset w/in above sector- * 8 byte length of continuation- */- int32_t location =- archive_le32dec(data);- file->ce_offset =- archive_le32dec(data+8);- file->ce_size =- archive_le32dec(data+16);- if (register_CE(a, location, file)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }- }- else if (p[1] == 'L') {- if (version == 1 && data_length == 8) {- file->cl_offset = (uint64_t)- iso9660->logical_block_size *- (uint64_t)archive_le32dec(data);- iso9660->seenRockridge = 1;- }- }- break;- case 'N':- if (p[1] == 'M') {- if (version == 1) {- parse_rockridge_NM1(file,- data, data_length);- iso9660->seenRockridge = 1;- }- }- break;- case 'P':- /*- * PD extension is padding;- * contents are always ignored.- *- * PL extension won't appear;- * contents are always ignored.- */- if (p[1] == 'N') {- if (version == 1 && data_length == 16) {- file->rdev = toi(data,4);- file->rdev <<= 32;- file->rdev |= toi(data + 8, 4);- iso9660->seenRockridge = 1;- }- }- else if (p[1] == 'X') {- /*- * PX extension comprises:- * 8 bytes for mode,- * 8 bytes for nlinks,- * 8 bytes for uid,- * 8 bytes for gid,- * 8 bytes for inode.- */- if (version == 1) {- if (data_length >= 8)- file->mode- = toi(data, 4);- if (data_length >= 16)- file->nlinks- = toi(data + 8, 4);- if (data_length >= 24)- file->uid- = toi(data + 16, 4);- if (data_length >= 32)- file->gid- = toi(data + 24, 4);- if (data_length >= 40)- file->number- = toi(data + 32, 4);- iso9660->seenRockridge = 1;- }- }- break;- case 'R':- if (p[1] == 'E' && version == 1) {- file->re = 1;- iso9660->seenRockridge = 1;- }- else if (p[1] == 'R' && version == 1) {- /*- * RR extension comprises:- * one byte flag value- * This extension is obsolete,- * so contents are always ignored.- */- }- break;- case 'S':- if (p[1] == 'L') {- if (version == 1) {- parse_rockridge_SL1(file,- data, data_length);- iso9660->seenRockridge = 1;- }- }- else if (p[1] == 'T'- && data_length == 0 && version == 1) {- /*- * ST extension marks end of this- * block of SUSP entries.- *- * It allows SUSP to coexist with- * non-SUSP uses of the System- * Use Area by placing non-SUSP data- * after SUSP data.- */- iso9660->seenSUSP = 0;- iso9660->seenRockridge = 0;- return (ARCHIVE_OK);- }- break;- case 'T':- if (p[1] == 'F') {- if (version == 1) {- parse_rockridge_TF1(file,- data, data_length);- iso9660->seenRockridge = 1;- }- }- break;- case 'Z':- if (p[1] == 'F') {- if (version == 1)- parse_rockridge_ZF1(file,- data, data_length);- }- break;- default:- break;- }-- p += p[2];- entry_seen = 1;- }-- if (entry_seen)- return (ARCHIVE_OK);- else {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Tried to parse Rockridge extensions, but none found");- return (ARCHIVE_WARN);- }-}--static int-register_CE(struct archive_read *a, int32_t location,- struct file_info *file)-{- struct iso9660 *iso9660;- struct read_ce_queue *heap;- struct read_ce_req *p;- uint64_t offset, parent_offset;- int hole, parent;-- iso9660 = (struct iso9660 *)(a->format->data);- offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size;- if (((file->mode & AE_IFMT) == AE_IFREG &&- offset >= file->offset) ||- offset < iso9660->current_position ||- (((uint64_t)file->ce_offset) + file->ce_size)- > (uint64_t)iso9660->logical_block_size ||- offset + file->ce_offset + file->ce_size- > iso9660->volume_size) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid parameter in SUSP \"CE\" extension");- return (ARCHIVE_FATAL);- }-- /* Expand our CE list as necessary. */- heap = &(iso9660->read_ce_req);- if (heap->cnt >= heap->allocated) {- int new_size;-- if (heap->allocated < 16)- new_size = 16;- else- new_size = heap->allocated * 2;- /* Overflow might keep us from growing the list. */- if (new_size <= heap->allocated) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- p = calloc(new_size, sizeof(p[0]));- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- if (heap->reqs != NULL) {- memcpy(p, heap->reqs, heap->cnt * sizeof(*p));- free(heap->reqs);- }- heap->reqs = p;- heap->allocated = new_size;- }-- /*- * Start with hole at end, walk it up tree to find insertion point.- */- hole = heap->cnt++;- while (hole > 0) {- parent = (hole - 1)/2;- parent_offset = heap->reqs[parent].offset;- if (offset >= parent_offset) {- heap->reqs[hole].offset = offset;- heap->reqs[hole].file = file;- return (ARCHIVE_OK);- }- /* Move parent into hole <==> move hole up tree. */- heap->reqs[hole] = heap->reqs[parent];- hole = parent;- }- heap->reqs[0].offset = offset;- heap->reqs[0].file = file;- return (ARCHIVE_OK);-}--static void-next_CE(struct read_ce_queue *heap)-{- uint64_t a_offset, b_offset, c_offset;- int a, b, c;- struct read_ce_req tmp;-- if (heap->cnt < 1)- return;-- /*- * Move the last item in the heap to the root of the tree- */- heap->reqs[0] = heap->reqs[--(heap->cnt)];-- /*- * Rebalance the heap.- */- a = 0; /* Starting element and its offset */- a_offset = heap->reqs[a].offset;- for (;;) {- b = a + a + 1; /* First child */- if (b >= heap->cnt)- return;- b_offset = heap->reqs[b].offset;- c = b + 1; /* Use second child if it is smaller. */- if (c < heap->cnt) {- c_offset = heap->reqs[c].offset;- if (c_offset < b_offset) {- b = c;- b_offset = c_offset;- }- }- if (a_offset <= b_offset)- return;- tmp = heap->reqs[a];- heap->reqs[a] = heap->reqs[b];- heap->reqs[b] = tmp;- a = b;- }-}---static int-read_CE(struct archive_read *a, struct iso9660 *iso9660)-{- struct read_ce_queue *heap;- const unsigned char *b, *p, *end;- struct file_info *file;- size_t step;- int r;-- /* Read data which RRIP "CE" extension points. */- heap = &(iso9660->read_ce_req);- step = iso9660->logical_block_size;- while (heap->cnt &&- heap->reqs[0].offset == iso9660->current_position) {- b = __archive_read_ahead(a, step, NULL);- if (b == NULL) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to read full block when scanning "- "ISO9660 directory list");- return (ARCHIVE_FATAL);- }- do {- file = heap->reqs[0].file;- if (file->ce_offset + file->ce_size > step) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Malformed CE information");- return (ARCHIVE_FATAL);- }- p = b + file->ce_offset;- end = p + file->ce_size;- next_CE(heap);- r = parse_rockridge(a, file, p, end);- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);- } while (heap->cnt &&- heap->reqs[0].offset == iso9660->current_position);- /* NOTE: Do not move this consume's code to front of- * do-while loop. Registration of nested CE extension- * might cause error because of current position. */- __archive_read_consume(a, step);- iso9660->current_position += step;- }- return (ARCHIVE_OK);-}--static void-parse_rockridge_NM1(struct file_info *file,- const unsigned char *data, int data_length)-{- if (!file->name_continues)- archive_string_empty(&file->name);- file->name_continues = 0;- if (data_length < 1)- return;- /*- * NM version 1 extension comprises:- * 1 byte flag, value is one of:- * = 0: remainder is name- * = 1: remainder is name, next NM entry continues name- * = 2: "."- * = 4: ".."- * = 32: Implementation specific- * All other values are reserved.- */- switch(data[0]) {- case 0:- if (data_length < 2)- return;- archive_strncat(&file->name,- (const char *)data + 1, data_length - 1);- break;- case 1:- if (data_length < 2)- return;- archive_strncat(&file->name,- (const char *)data + 1, data_length - 1);- file->name_continues = 1;- break;- case 2:- archive_strcat(&file->name, ".");- break;- case 4:- archive_strcat(&file->name, "..");- break;- default:- return;- }--}--static void-parse_rockridge_TF1(struct file_info *file, const unsigned char *data,- int data_length)-{- char flag;- /*- * TF extension comprises:- * one byte flag- * create time (optional)- * modify time (optional)- * access time (optional)- * attribute time (optional)- * Time format and presence of fields- * is controlled by flag bits.- */- if (data_length < 1)- return;- flag = data[0];- ++data;- --data_length;- if (flag & 0x80) {- /* Use 17-byte time format. */- if ((flag & 1) && data_length >= 17) {- /* Create time. */- file->birthtime_is_set = 1;- file->birthtime = isodate17(data);- data += 17;- data_length -= 17;- }- if ((flag & 2) && data_length >= 17) {- /* Modify time. */- file->mtime = isodate17(data);- data += 17;- data_length -= 17;- }- if ((flag & 4) && data_length >= 17) {- /* Access time. */- file->atime = isodate17(data);- data += 17;- data_length -= 17;- }- if ((flag & 8) && data_length >= 17) {- /* Attribute change time. */- file->ctime = isodate17(data);- }- } else {- /* Use 7-byte time format. */- if ((flag & 1) && data_length >= 7) {- /* Create time. */- file->birthtime_is_set = 1;- file->birthtime = isodate7(data);- data += 7;- data_length -= 7;- }- if ((flag & 2) && data_length >= 7) {- /* Modify time. */- file->mtime = isodate7(data);- data += 7;- data_length -= 7;- }- if ((flag & 4) && data_length >= 7) {- /* Access time. */- file->atime = isodate7(data);- data += 7;- data_length -= 7;- }- if ((flag & 8) && data_length >= 7) {- /* Attribute change time. */- file->ctime = isodate7(data);- }- }-}--static void-parse_rockridge_SL1(struct file_info *file, const unsigned char *data,- int data_length)-{- const char *separator = "";-- if (!file->symlink_continues || file->symlink.length < 1)- archive_string_empty(&file->symlink);- file->symlink_continues = 0;-- /*- * Defined flag values:- * 0: This is the last SL record for this symbolic link- * 1: this symbolic link field continues in next SL entry- * All other values are reserved.- */- if (data_length < 1)- return;- switch(*data) {- case 0:- break;- case 1:- file->symlink_continues = 1;- break;- default:- return;- }- ++data; /* Skip flag byte. */- --data_length;-- /*- * SL extension body stores "components".- * Basically, this is a complicated way of storing- * a POSIX path. It also interferes with using- * symlinks for storing non-path data. <sigh>- *- * Each component is 2 bytes (flag and length)- * possibly followed by name data.- */- while (data_length >= 2) {- unsigned char flag = *data++;- unsigned char nlen = *data++;- data_length -= 2;-- archive_strcat(&file->symlink, separator);- separator = "/";-- switch(flag) {- case 0: /* Usual case, this is text. */- if (data_length < nlen)- return;- archive_strncat(&file->symlink,- (const char *)data, nlen);- break;- case 0x01: /* Text continues in next component. */- if (data_length < nlen)- return;- archive_strncat(&file->symlink,- (const char *)data, nlen);- separator = "";- break;- case 0x02: /* Current dir. */- archive_strcat(&file->symlink, ".");- break;- case 0x04: /* Parent dir. */- archive_strcat(&file->symlink, "..");- break;- case 0x08: /* Root of filesystem. */- archive_strcat(&file->symlink, "/");- separator = "";- break;- case 0x10: /* Undefined (historically "volume root" */- archive_string_empty(&file->symlink);- archive_strcat(&file->symlink, "ROOT");- break;- case 0x20: /* Undefined (historically "hostname") */- archive_strcat(&file->symlink, "hostname");- break;- default:- /* TODO: issue a warning ? */- return;- }- data += nlen;- data_length -= nlen;- }-}--static void-parse_rockridge_ZF1(struct file_info *file, const unsigned char *data,- int data_length)-{-- if (data[0] == 0x70 && data[1] == 0x7a && data_length == 12) {- /* paged zlib */- file->pz = 1;- file->pz_log2_bs = data[3];- file->pz_uncompressed_size = archive_le32dec(&data[4]);- }-}--static void-register_file(struct iso9660 *iso9660, struct file_info *file)-{-- file->use_next = iso9660->use_files;- iso9660->use_files = file;-}--static void-release_files(struct iso9660 *iso9660)-{- struct content *con, *connext;- struct file_info *file;-- file = iso9660->use_files;- while (file != NULL) {- struct file_info *next = file->use_next;-- archive_string_free(&file->name);- archive_string_free(&file->symlink);- free(file->utf16be_name);- con = file->contents.first;- while (con != NULL) {- connext = con->next;- free(con);- con = connext;- }- free(file);- file = next;- }-}--static int-next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,- struct file_info **pfile)-{- struct file_info *file;- int r;-- r = next_cache_entry(a, iso9660, pfile);- if (r != ARCHIVE_OK)- return (r);- file = *pfile;-- /* Don't waste time seeking for zero-length bodies. */- if (file->size == 0)- file->offset = iso9660->current_position;-- /* flush any remaining bytes from the last round to ensure- * we're positioned */- if (iso9660->entry_bytes_unconsumed) {- __archive_read_consume(a, iso9660->entry_bytes_unconsumed);- iso9660->entry_bytes_unconsumed = 0;- }-- /* Seek forward to the start of the entry. */- if (iso9660->current_position < file->offset) {- int64_t step;-- step = file->offset - iso9660->current_position;- step = __archive_read_consume(a, step);- if (step < 0)- return ((int)step);- iso9660->current_position = file->offset;- }-- /* We found body of file; handle it now. */- return (ARCHIVE_OK);-}--static int-next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,- struct file_info **pfile)-{- struct file_info *file;- struct {- struct file_info *first;- struct file_info **last;- } empty_files;- int64_t number;- int count;-- file = cache_get_entry(iso9660);- if (file != NULL) {- *pfile = file;- return (ARCHIVE_OK);- }-- for (;;) {- struct file_info *re, *d;-- *pfile = file = next_entry(iso9660);- if (file == NULL) {- /*- * If directory entries all which are descendant of- * rr_moved are still remaining, expose their.- */- if (iso9660->re_files.first != NULL &&- iso9660->rr_moved != NULL &&- iso9660->rr_moved->rr_moved_has_re_only)- /* Expose "rr_moved" entry. */- cache_add_entry(iso9660, iso9660->rr_moved);- while ((re = re_get_entry(iso9660)) != NULL) {- /* Expose its descendant dirs. */- while ((d = rede_get_entry(re)) != NULL)- cache_add_entry(iso9660, d);- }- if (iso9660->cache_files.first != NULL)- return (next_cache_entry(a, iso9660, pfile));- return (ARCHIVE_EOF);- }-- if (file->cl_offset) {- struct file_info *first_re = NULL;- int nexted_re = 0;-- /*- * Find "RE" dir for the current file, which- * has "CL" flag.- */- while ((re = re_get_entry(iso9660))- != first_re) {- if (first_re == NULL)- first_re = re;- if (re->offset == file->cl_offset) {- re->parent->subdirs--;- re->parent = file->parent;- re->re = 0;- if (re->parent->re_descendant) {- nexted_re = 1;- re->re_descendant = 1;- if (rede_add_entry(re) < 0)- goto fatal_rr;- /* Move a list of descendants- * to a new ancestor. */- while ((d = rede_get_entry(- re)) != NULL)- if (rede_add_entry(d)- < 0)- goto fatal_rr;- break;- }- /* Replace the current file- * with "RE" dir */- *pfile = file = re;- /* Expose its descendant */- while ((d = rede_get_entry(- file)) != NULL)- cache_add_entry(- iso9660, d);- break;- } else- re_add_entry(iso9660, re);- }- if (nexted_re) {- /*- * Do not expose this at this time- * because we have not gotten its full-path- * name yet.- */- continue;- }- } else if ((file->mode & AE_IFMT) == AE_IFDIR) {- int r;-- /* Read file entries in this dir. */- r = read_children(a, file);- if (r != ARCHIVE_OK)- return (r);-- /*- * Handle a special dir of Rockridge extensions,- * "rr_moved".- */- if (file->rr_moved) {- /*- * If this has only the subdirectories which- * have "RE" flags, do not expose at this time.- */- if (file->rr_moved_has_re_only)- continue;- /* Otherwise expose "rr_moved" entry. */- } else if (file->re) {- /*- * Do not expose this at this time- * because we have not gotten its full-path- * name yet.- */- re_add_entry(iso9660, file);- continue;- } else if (file->re_descendant) {- /*- * If the top level "RE" entry of this entry- * is not exposed, we, accordingly, should not- * expose this entry at this time because- * we cannot make its proper full-path name.- */- if (rede_add_entry(file) == 0)- continue;- /* Otherwise we can expose this entry because- * it seems its top level "RE" has already been- * exposed. */- }- }- break;- }-- if ((file->mode & AE_IFMT) != AE_IFREG || file->number == -1)- return (ARCHIVE_OK);-- count = 0;- number = file->number;- iso9660->cache_files.first = NULL;- iso9660->cache_files.last = &(iso9660->cache_files.first);- empty_files.first = NULL;- empty_files.last = &empty_files.first;- /* Collect files which has the same file serial number.- * Peek pending_files so that file which number is different- * is not put back. */- while (iso9660->pending_files.used > 0 &&- (iso9660->pending_files.files[0]->number == -1 ||- iso9660->pending_files.files[0]->number == number)) {- if (file->number == -1) {- /* This file has the same offset- * but it's wrong offset which empty files- * and symlink files have.- * NOTE: This wrong offset was recorded by- * old mkisofs utility. If ISO images is- * created by latest mkisofs, this does not- * happen.- */- file->next = NULL;- *empty_files.last = file;- empty_files.last = &(file->next);- } else {- count++;- cache_add_entry(iso9660, file);- }- file = next_entry(iso9660);- }-- if (count == 0) {- *pfile = file;- return ((file == NULL)?ARCHIVE_EOF:ARCHIVE_OK);- }- if (file->number == -1) {- file->next = NULL;- *empty_files.last = file;- empty_files.last = &(file->next);- } else {- count++;- cache_add_entry(iso9660, file);- }-- if (count > 1) {- /* The count is the same as number of hardlink,- * so much so that each nlinks of files in cache_file- * is overwritten by value of the count.- */- for (file = iso9660->cache_files.first;- file != NULL; file = file->next)- file->nlinks = count;- }- /* If there are empty files, that files are added- * to the tail of the cache_files. */- if (empty_files.first != NULL) {- *iso9660->cache_files.last = empty_files.first;- iso9660->cache_files.last = empty_files.last;- }- *pfile = cache_get_entry(iso9660);- return ((*pfile == NULL)?ARCHIVE_EOF:ARCHIVE_OK);--fatal_rr:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to connect 'CL' pointer to 'RE' rr_moved pointer of "- "Rockridge extensions: current position = %jd, CL offset = %jd",- (intmax_t)iso9660->current_position, (intmax_t)file->cl_offset);- return (ARCHIVE_FATAL);-}--static inline void-re_add_entry(struct iso9660 *iso9660, struct file_info *file)-{- file->re_next = NULL;- *iso9660->re_files.last = file;- iso9660->re_files.last = &(file->re_next);-}--static inline struct file_info *-re_get_entry(struct iso9660 *iso9660)-{- struct file_info *file;-- if ((file = iso9660->re_files.first) != NULL) {- iso9660->re_files.first = file->re_next;- if (iso9660->re_files.first == NULL)- iso9660->re_files.last =- &(iso9660->re_files.first);- }- return (file);-}--static inline int-rede_add_entry(struct file_info *file)-{- struct file_info *re;-- /*- * Find "RE" entry.- */- re = file->parent;- while (re != NULL && !re->re)- re = re->parent;- if (re == NULL)- return (-1);-- file->re_next = NULL;- *re->rede_files.last = file;- re->rede_files.last = &(file->re_next);- return (0);-}--static inline struct file_info *-rede_get_entry(struct file_info *re)-{- struct file_info *file;-- if ((file = re->rede_files.first) != NULL) {- re->rede_files.first = file->re_next;- if (re->rede_files.first == NULL)- re->rede_files.last =- &(re->rede_files.first);- }- return (file);-}--static inline void-cache_add_entry(struct iso9660 *iso9660, struct file_info *file)-{- file->next = NULL;- *iso9660->cache_files.last = file;- iso9660->cache_files.last = &(file->next);-}--static inline struct file_info *-cache_get_entry(struct iso9660 *iso9660)-{- struct file_info *file;-- if ((file = iso9660->cache_files.first) != NULL) {- iso9660->cache_files.first = file->next;- if (iso9660->cache_files.first == NULL)- iso9660->cache_files.last =- &(iso9660->cache_files.first);- }- return (file);-}--static int-heap_add_entry(struct archive_read *a, struct heap_queue *heap,- struct file_info *file, uint64_t key)-{- uint64_t file_key, parent_key;- int hole, parent;-- /* Expand our pending files list as necessary. */- if (heap->used >= heap->allocated) {- struct file_info **new_pending_files;- int new_size = heap->allocated * 2;-- if (heap->allocated < 1024)- new_size = 1024;- /* Overflow might keep us from growing the list. */- if (new_size <= heap->allocated) {- archive_set_error(&a->archive,- ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- new_pending_files = (struct file_info **)- malloc(new_size * sizeof(new_pending_files[0]));- if (new_pending_files == NULL) {- archive_set_error(&a->archive,- ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- if (heap->allocated)- memcpy(new_pending_files, heap->files,- heap->allocated * sizeof(new_pending_files[0]));- free(heap->files);- heap->files = new_pending_files;- heap->allocated = new_size;- }-- file_key = file->key = key;-- /*- * Start with hole at end, walk it up tree to find insertion point.- */- hole = heap->used++;- while (hole > 0) {- parent = (hole - 1)/2;- parent_key = heap->files[parent]->key;- if (file_key >= parent_key) {- heap->files[hole] = file;- return (ARCHIVE_OK);- }- /* Move parent into hole <==> move hole up tree. */- heap->files[hole] = heap->files[parent];- hole = parent;- }- heap->files[0] = file;-- return (ARCHIVE_OK);-}--static struct file_info *-heap_get_entry(struct heap_queue *heap)-{- uint64_t a_key, b_key, c_key;- int a, b, c;- struct file_info *r, *tmp;-- if (heap->used < 1)- return (NULL);-- /*- * The first file in the list is the earliest; we'll return this.- */- r = heap->files[0];-- /*- * Move the last item in the heap to the root of the tree- */- heap->files[0] = heap->files[--(heap->used)];-- /*- * Rebalance the heap.- */- a = 0; /* Starting element and its heap key */- a_key = heap->files[a]->key;- for (;;) {- b = a + a + 1; /* First child */- if (b >= heap->used)- return (r);- b_key = heap->files[b]->key;- c = b + 1; /* Use second child if it is smaller. */- if (c < heap->used) {- c_key = heap->files[c]->key;- if (c_key < b_key) {- b = c;- b_key = c_key;- }- }- if (a_key <= b_key)- return (r);- tmp = heap->files[a];- heap->files[a] = heap->files[b];- heap->files[b] = tmp;- a = b;- }-}--static unsigned int-toi(const void *p, int n)-{- const unsigned char *v = (const unsigned char *)p;- if (n > 1)- return v[0] + 256 * toi(v + 1, n - 1);- if (n == 1)- return v[0];- return (0);-}--static time_t-isodate7(const unsigned char *v)-{- struct tm tm;- int offset;- time_t t;-- memset(&tm, 0, sizeof(tm));- tm.tm_year = v[0];- tm.tm_mon = v[1] - 1;- tm.tm_mday = v[2];- tm.tm_hour = v[3];- tm.tm_min = v[4];- tm.tm_sec = v[5];- /* v[6] is the signed timezone offset, in 1/4-hour increments. */- offset = ((const signed char *)v)[6];- if (offset > -48 && offset < 52) {- tm.tm_hour -= offset / 4;- tm.tm_min -= (offset % 4) * 15;- }- t = time_from_tm(&tm);- if (t == (time_t)-1)- return ((time_t)0);- return (t);-}--static time_t-isodate17(const unsigned char *v)-{- struct tm tm;- int offset;- time_t t;-- memset(&tm, 0, sizeof(tm));- tm.tm_year = (v[0] - '0') * 1000 + (v[1] - '0') * 100- + (v[2] - '0') * 10 + (v[3] - '0')- - 1900;- tm.tm_mon = (v[4] - '0') * 10 + (v[5] - '0');- tm.tm_mday = (v[6] - '0') * 10 + (v[7] - '0');- tm.tm_hour = (v[8] - '0') * 10 + (v[9] - '0');- tm.tm_min = (v[10] - '0') * 10 + (v[11] - '0');- tm.tm_sec = (v[12] - '0') * 10 + (v[13] - '0');- /* v[16] is the signed timezone offset, in 1/4-hour increments. */- offset = ((const signed char *)v)[16];- if (offset > -48 && offset < 52) {- tm.tm_hour -= offset / 4;- tm.tm_min -= (offset % 4) * 15;- }- t = time_from_tm(&tm);- if (t == (time_t)-1)- return ((time_t)0);- return (t);-}--static time_t-time_from_tm(struct tm *t)-{-#if HAVE__MKGMTIME- return _mkgmtime(t);-#elif HAVE_TIMEGM- /* Use platform timegm() if available. */- return (timegm(t));-#else- /* Else use direct calculation using POSIX assumptions. */- /* First, fix up tm_yday based on the year/month/day. */- if (mktime(t) == (time_t)-1)- return ((time_t)-1);- /* Then we can compute timegm() from first principles. */- return (t->tm_sec- + t->tm_min * 60- + t->tm_hour * 3600- + t->tm_yday * 86400- + (t->tm_year - 70) * 31536000- + ((t->tm_year - 69) / 4) * 86400- - ((t->tm_year - 1) / 100) * 86400- + ((t->tm_year + 299) / 400) * 86400);-#endif-}--static const char *-build_pathname(struct archive_string *as, struct file_info *file, int depth)-{- // Plain ISO9660 only allows 8 dir levels; if we get- // to 1000, then something is very, very wrong.- if (depth > 1000) {- return NULL;- }- if (file->parent != NULL && archive_strlen(&file->parent->name) > 0) {- if (build_pathname(as, file->parent, depth + 1) == NULL) {- return NULL;- }- archive_strcat(as, "/");- }- if (archive_strlen(&file->name) == 0)- archive_strcat(as, ".");- else- archive_string_concat(as, &file->name);- return (as->s);-}--static int-build_pathname_utf16be(unsigned char *p, size_t max, size_t *len,- struct file_info *file)-{- if (file->parent != NULL && file->parent->utf16be_bytes > 0) {- if (build_pathname_utf16be(p, max, len, file->parent) != 0)- return (-1);- p[*len] = 0;- p[*len + 1] = '/';- *len += 2;- }- if (file->utf16be_bytes == 0) {- if (*len + 2 > max)- return (-1);/* Path is too long! */- p[*len] = 0;- p[*len + 1] = '.';- *len += 2;- } else {- if (*len + file->utf16be_bytes > max)- return (-1);/* Path is too long! */- memcpy(p + *len, file->utf16be_name, file->utf16be_bytes);- *len += file->utf16be_bytes;- }- return (0);-}--#if DEBUG-static void-dump_isodirrec(FILE *out, const unsigned char *isodirrec)-{- fprintf(out, " l %d,",- toi(isodirrec + DR_length_offset, DR_length_size));- fprintf(out, " a %d,",- toi(isodirrec + DR_ext_attr_length_offset, DR_ext_attr_length_size));- fprintf(out, " ext 0x%x,",- toi(isodirrec + DR_extent_offset, DR_extent_size));- fprintf(out, " s %d,",- toi(isodirrec + DR_size_offset, DR_extent_size));- fprintf(out, " f 0x%x,",- toi(isodirrec + DR_flags_offset, DR_flags_size));- fprintf(out, " u %d,",- toi(isodirrec + DR_file_unit_size_offset, DR_file_unit_size_size));- fprintf(out, " ilv %d,",- toi(isodirrec + DR_interleave_offset, DR_interleave_size));- fprintf(out, " seq %d,",- toi(isodirrec + DR_volume_sequence_number_offset,- DR_volume_sequence_number_size));- fprintf(out, " nl %d:",- toi(isodirrec + DR_name_len_offset, DR_name_len_size));- fprintf(out, " `%.*s'",- toi(isodirrec + DR_name_len_offset, DR_name_len_size),- isodirrec + DR_name_offset);-}-#endif
− c/archive_read_support_format_lha.c
@@ -1,2919 +0,0 @@-/*-- * Copyright (c) 2008-2014 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_read_private.h"-#include "archive_endian.h"---#define MAXMATCH 256 /* Maximum match length. */-#define MINMATCH 3 /* Minimum match length. */-/*- * Literal table format:- * +0 +256 +510- * +---------------+-------------------------+- * | literal code | match length |- * | 0 ... 255 | MINMATCH ... MAXMATCH |- * +---------------+-------------------------+- * <--- LT_BITLEN_SIZE --->- */-/* Literal table size. */-#define LT_BITLEN_SIZE (UCHAR_MAX + 1 + MAXMATCH - MINMATCH + 1)-/* Position table size.- * Note: this used for both position table and pre literal table.*/-#define PT_BITLEN_SIZE (3 + 16)--struct lzh_dec {- /* Decoding status. */- int state;-- /*- * Window to see last 8Ki(lh5),32Ki(lh6),64Ki(lh7) bytes of decoded- * data.- */- int w_size;- int w_mask;- /* Window buffer, which is a loop buffer. */- unsigned char *w_buff;- /* The insert position to the window. */- int w_pos;- /* The position where we can copy decoded code from the window. */- int copy_pos;- /* The length how many bytes we can copy decoded code from- * the window. */- int copy_len;-- /*- * Bit stream reader.- */- struct lzh_br {-#define CACHE_TYPE uint64_t-#define CACHE_BITS (8 * sizeof(CACHE_TYPE))- /* Cache buffer. */- CACHE_TYPE cache_buffer;- /* Indicates how many bits avail in cache_buffer. */- int cache_avail;- } br;-- /*- * Huffman coding.- */- struct huffman {- int len_size;- int len_avail;- int len_bits;- int freq[17];- unsigned char *bitlen;-- /*- * Use a index table. It's faster than searching a huffman- * coding tree, which is a binary tree. But a use of a large- * index table causes L1 cache read miss many times.- */-#define HTBL_BITS 10- int max_bits;- int shift_bits;- int tbl_bits;- int tree_used;- int tree_avail;- /* Direct access table. */- uint16_t *tbl;- /* Binary tree table for extra bits over the direct access. */- struct htree_t {- uint16_t left;- uint16_t right;- } *tree;- } lt, pt;-- int blocks_avail;- int pos_pt_len_size;- int pos_pt_len_bits;- int literal_pt_len_size;- int literal_pt_len_bits;- int reading_position;- int loop;- int error;-};--struct lzh_stream {- const unsigned char *next_in;- int avail_in;- int64_t total_in;- const unsigned char *ref_ptr;- int avail_out;- int64_t total_out;- struct lzh_dec *ds;-};--struct lha {- /* entry_bytes_remaining is the number of bytes we expect. */- int64_t entry_offset;- int64_t entry_bytes_remaining;- int64_t entry_unconsumed;- uint16_t entry_crc_calculated;- - size_t header_size; /* header size */- unsigned char level; /* header level */- char method[3]; /* compress type */- int64_t compsize; /* compressed data size */- int64_t origsize; /* original file size */- int setflag;-#define BIRTHTIME_IS_SET 1-#define ATIME_IS_SET 2-#define UNIX_MODE_IS_SET 4-#define CRC_IS_SET 8- time_t birthtime;- long birthtime_tv_nsec;- time_t mtime;- long mtime_tv_nsec;- time_t atime;- long atime_tv_nsec;- mode_t mode;- int64_t uid;- int64_t gid;- struct archive_string uname;- struct archive_string gname;- uint16_t header_crc;- uint16_t crc;- /* dirname and filename could be in different codepages */- struct archive_string_conv *sconv_dir;- struct archive_string_conv *sconv_fname;- struct archive_string_conv *opt_sconv;-- struct archive_string dirname;- struct archive_string filename;- struct archive_wstring ws;-- unsigned char dos_attr;-- /* Flag to mark progress that an archive was read their first header.*/- char found_first_header;- /* Flag to mark that indicates an empty directory. */- char directory;-- /* Flags to mark progress of decompression. */- char decompress_init;- char end_of_entry;- char end_of_entry_cleanup;- char entry_is_compressed;-- char format_name[64];-- struct lzh_stream strm;-};--/*- * LHA header common member offset.- */-#define H_METHOD_OFFSET 2 /* Compress type. */-#define H_ATTR_OFFSET 19 /* DOS attribute. */-#define H_LEVEL_OFFSET 20 /* Header Level. */-#define H_SIZE 22 /* Minimum header size. */--static int archive_read_format_lha_bid(struct archive_read *, int);-static int archive_read_format_lha_options(struct archive_read *,- const char *, const char *);-static int archive_read_format_lha_read_header(struct archive_read *,- struct archive_entry *);-static int archive_read_format_lha_read_data(struct archive_read *,- const void **, size_t *, int64_t *);-static int archive_read_format_lha_read_data_skip(struct archive_read *);-static int archive_read_format_lha_cleanup(struct archive_read *);--static void lha_replace_path_separator(struct lha *,- struct archive_entry *);-static int lha_read_file_header_0(struct archive_read *, struct lha *);-static int lha_read_file_header_1(struct archive_read *, struct lha *);-static int lha_read_file_header_2(struct archive_read *, struct lha *);-static int lha_read_file_header_3(struct archive_read *, struct lha *);-static int lha_read_file_extended_header(struct archive_read *,- struct lha *, uint16_t *, int, size_t, size_t *);-static size_t lha_check_header_format(const void *);-static int lha_skip_sfx(struct archive_read *);-static time_t lha_dos_time(const unsigned char *);-static time_t lha_win_time(uint64_t, long *);-static unsigned char lha_calcsum(unsigned char, const void *,- int, size_t);-static int lha_parse_linkname(struct archive_wstring *,- struct archive_wstring *);-static int lha_read_data_none(struct archive_read *, const void **,- size_t *, int64_t *);-static int lha_read_data_lzh(struct archive_read *, const void **,- size_t *, int64_t *);-static void lha_crc16_init(void);-static uint16_t lha_crc16(uint16_t, const void *, size_t);-static int lzh_decode_init(struct lzh_stream *, const char *);-static void lzh_decode_free(struct lzh_stream *);-static int lzh_decode(struct lzh_stream *, int);-static int lzh_br_fillup(struct lzh_stream *, struct lzh_br *);-static int lzh_huffman_init(struct huffman *, size_t, int);-static void lzh_huffman_free(struct huffman *);-static int lzh_read_pt_bitlen(struct lzh_stream *, int start, int end);-static int lzh_make_fake_table(struct huffman *, uint16_t);-static int lzh_make_huffman_table(struct huffman *);-static inline int lzh_decode_huffman(struct huffman *, unsigned);-static int lzh_decode_huffman_tree(struct huffman *, unsigned, int);---int-archive_read_support_format_lha(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct lha *lha;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_lha");-- lha = (struct lha *)calloc(1, sizeof(*lha));- if (lha == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate lha data");- return (ARCHIVE_FATAL);- }- archive_string_init(&lha->ws);-- r = __archive_read_register_format(a,- lha,- "lha",- archive_read_format_lha_bid,- archive_read_format_lha_options,- archive_read_format_lha_read_header,- archive_read_format_lha_read_data,- archive_read_format_lha_read_data_skip,- NULL,- archive_read_format_lha_cleanup,- NULL,- NULL);-- if (r != ARCHIVE_OK)- free(lha);- return (ARCHIVE_OK);-}--static size_t-lha_check_header_format(const void *h)-{- const unsigned char *p = h;- size_t next_skip_bytes;-- switch (p[H_METHOD_OFFSET+3]) {- /*- * "-lh0-" ... "-lh7-" "-lhd-"- * "-lzs-" "-lz5-"- */- case '0': case '1': case '2': case '3':- case '4': case '5': case '6': case '7':- case 'd':- case 's':- next_skip_bytes = 4;-- /* b0 == 0 means the end of an LHa archive file. */- if (p[0] == 0)- break;- if (p[H_METHOD_OFFSET] != '-' || p[H_METHOD_OFFSET+1] != 'l'- || p[H_METHOD_OFFSET+4] != '-')- break;-- if (p[H_METHOD_OFFSET+2] == 'h') {- /* "-lh?-" */- if (p[H_METHOD_OFFSET+3] == 's')- break;- if (p[H_LEVEL_OFFSET] == 0)- return (0);- if (p[H_LEVEL_OFFSET] <= 3 && p[H_ATTR_OFFSET] == 0x20)- return (0);- }- if (p[H_METHOD_OFFSET+2] == 'z') {- /* LArc extensions: -lzs-,-lz4- and -lz5- */- if (p[H_LEVEL_OFFSET] != 0)- break;- if (p[H_METHOD_OFFSET+3] == 's'- || p[H_METHOD_OFFSET+3] == '4'- || p[H_METHOD_OFFSET+3] == '5')- return (0);- }- break;- case 'h': next_skip_bytes = 1; break;- case 'z': next_skip_bytes = 1; break;- case 'l': next_skip_bytes = 2; break;- case '-': next_skip_bytes = 3; break;- default : next_skip_bytes = 4; break;- }-- return (next_skip_bytes);-}--static int-archive_read_format_lha_bid(struct archive_read *a, int best_bid)-{- const char *p;- const void *buff;- ssize_t bytes_avail, offset, window;- size_t next;-- /* If there's already a better bid than we can ever- make, don't bother testing. */- if (best_bid > 30)- return (-1);-- if ((p = __archive_read_ahead(a, H_SIZE, NULL)) == NULL)- return (-1);-- if (lha_check_header_format(p) == 0)- return (30);-- if (p[0] == 'M' && p[1] == 'Z') {- /* PE file */- offset = 0;- window = 4096;- while (offset < (1024 * 20)) {- buff = __archive_read_ahead(a, offset + window,- &bytes_avail);- if (buff == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < (H_SIZE + 3))- return (0);- continue;- }- p = (const char *)buff + offset;- while (p + H_SIZE < (const char *)buff + bytes_avail) {- if ((next = lha_check_header_format(p)) == 0)- return (30);- p += next;- }- offset = p - (const char *)buff;- }- }- return (0);-}--static int-archive_read_format_lha_options(struct archive_read *a,- const char *key, const char *val)-{- struct lha *lha;- int ret = ARCHIVE_FAILED;-- lha = (struct lha *)(a->format->data);- if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "lha: hdrcharset option needs a character-set name");- else {- lha->opt_sconv =- archive_string_conversion_from_charset(- &a->archive, val, 0);- if (lha->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-lha_skip_sfx(struct archive_read *a)-{- const void *h;- const char *p, *q;- size_t next, skip;- ssize_t bytes, window;-- window = 4096;- for (;;) {- h = __archive_read_ahead(a, window, &bytes);- if (h == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < (H_SIZE + 3))- goto fatal;- continue;- }- if (bytes < H_SIZE)- goto fatal;- p = h;- q = p + bytes;-- /*- * Scan ahead until we find something that looks- * like the lha header.- */- while (p + H_SIZE < q) {- if ((next = lha_check_header_format(p)) == 0) {- skip = p - (const char *)h;- __archive_read_consume(a, skip);- return (ARCHIVE_OK);- }- p += next;- }- skip = p - (const char *)h;- __archive_read_consume(a, skip);- }-fatal:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Couldn't find out LHa header");- return (ARCHIVE_FATAL);-}--static int-truncated_error(struct archive_read *a)-{- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated LHa header");- return (ARCHIVE_FATAL);-}--static int-archive_read_format_lha_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct archive_wstring linkname;- struct archive_wstring pathname;- struct lha *lha;- const unsigned char *p;- const char *signature;- int err;- struct archive_mstring conv_buffer;- const wchar_t *conv_buffer_p;-- lha_crc16_init();-- a->archive.archive_format = ARCHIVE_FORMAT_LHA;- if (a->archive.archive_format_name == NULL)- a->archive.archive_format_name = "lha";-- lha = (struct lha *)(a->format->data);- lha->decompress_init = 0;- lha->end_of_entry = 0;- lha->end_of_entry_cleanup = 0;- lha->entry_unconsumed = 0;-- if ((p = __archive_read_ahead(a, H_SIZE, NULL)) == NULL) {- /*- * LHa archiver added 0 to the tail of its archive file as- * the mark of the end of the archive.- */- signature = __archive_read_ahead(a, sizeof(signature[0]), NULL);- if (signature == NULL || signature[0] == 0)- return (ARCHIVE_EOF);- return (truncated_error(a));- }-- signature = (const char *)p;- if (lha->found_first_header == 0 &&- signature[0] == 'M' && signature[1] == 'Z') {- /* This is an executable? Must be self-extracting... */- err = lha_skip_sfx(a);- if (err < ARCHIVE_WARN)- return (err);-- if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL)- return (truncated_error(a));- signature = (const char *)p;- }- /* signature[0] == 0 means the end of an LHa archive file. */- if (signature[0] == 0)- return (ARCHIVE_EOF);-- /*- * Check the header format and method type.- */- if (lha_check_header_format(p) != 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Bad LHa file");- return (ARCHIVE_FATAL);- }-- /* We've found the first header. */- lha->found_first_header = 1;- /* Set a default value and common data */- lha->header_size = 0;- lha->level = p[H_LEVEL_OFFSET];- lha->method[0] = p[H_METHOD_OFFSET+1];- lha->method[1] = p[H_METHOD_OFFSET+2];- lha->method[2] = p[H_METHOD_OFFSET+3];- if (memcmp(lha->method, "lhd", 3) == 0)- lha->directory = 1;- else- lha->directory = 0;- if (memcmp(lha->method, "lh0", 3) == 0 ||- memcmp(lha->method, "lz4", 3) == 0)- lha->entry_is_compressed = 0;- else- lha->entry_is_compressed = 1;-- lha->compsize = 0;- lha->origsize = 0;- lha->setflag = 0;- lha->birthtime = 0;- lha->birthtime_tv_nsec = 0;- lha->mtime = 0;- lha->mtime_tv_nsec = 0;- lha->atime = 0;- lha->atime_tv_nsec = 0;- lha->mode = (lha->directory)? 0777 : 0666;- lha->uid = 0;- lha->gid = 0;- archive_string_empty(&lha->dirname);- archive_string_empty(&lha->filename);- lha->dos_attr = 0;- if (lha->opt_sconv != NULL) {- lha->sconv_dir = lha->opt_sconv;- lha->sconv_fname = lha->opt_sconv;- } else {- lha->sconv_dir = NULL;- lha->sconv_fname = NULL;- }-- switch (p[H_LEVEL_OFFSET]) {- case 0:- err = lha_read_file_header_0(a, lha);- break;- case 1:- err = lha_read_file_header_1(a, lha);- break;- case 2:- err = lha_read_file_header_2(a, lha);- break;- case 3:- err = lha_read_file_header_3(a, lha);- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported LHa header level %d", p[H_LEVEL_OFFSET]);- err = ARCHIVE_FATAL;- break;- }- if (err < ARCHIVE_WARN)- return (err);--- if (!lha->directory && archive_strlen(&lha->filename) == 0)- /* The filename has not been set */- return (truncated_error(a));-- /*- * Make a pathname from a dirname and a filename, after converting to Unicode.- * This is because codepages might differ between dirname and filename.- */- archive_string_init(&pathname);- archive_string_init(&linkname);- archive_string_init(&conv_buffer.aes_mbs);- archive_string_init(&conv_buffer.aes_mbs_in_locale);- archive_string_init(&conv_buffer.aes_utf8);- archive_string_init(&conv_buffer.aes_wcs);- if (0 != archive_mstring_copy_mbs_len_l(&conv_buffer, lha->dirname.s, lha->dirname.length, lha->sconv_dir)) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname cannot be converted "- "from %s to Unicode.",- archive_string_conversion_charset_name(lha->sconv_dir));- err = ARCHIVE_FATAL;- } else if (0 != archive_mstring_get_wcs(&a->archive, &conv_buffer, &conv_buffer_p))- err = ARCHIVE_FATAL;- if (err == ARCHIVE_FATAL) {- archive_mstring_clean(&conv_buffer);- archive_wstring_free(&pathname);- archive_wstring_free(&linkname);- return (err);- }- archive_wstring_copy(&pathname, &conv_buffer.aes_wcs);-- archive_string_empty(&conv_buffer.aes_mbs);- archive_string_empty(&conv_buffer.aes_mbs_in_locale);- archive_string_empty(&conv_buffer.aes_utf8);- archive_wstring_empty(&conv_buffer.aes_wcs);- if (0 != archive_mstring_copy_mbs_len_l(&conv_buffer, lha->filename.s, lha->filename.length, lha->sconv_fname)) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname cannot be converted "- "from %s to Unicode.",- archive_string_conversion_charset_name(lha->sconv_fname));- err = ARCHIVE_FATAL;- }- else if (0 != archive_mstring_get_wcs(&a->archive, &conv_buffer, &conv_buffer_p))- err = ARCHIVE_FATAL;- if (err == ARCHIVE_FATAL) {- archive_mstring_clean(&conv_buffer);- archive_wstring_free(&pathname);- archive_wstring_free(&linkname);- return (err);- }- archive_wstring_concat(&pathname, &conv_buffer.aes_wcs);- archive_mstring_clean(&conv_buffer);-- if ((lha->mode & AE_IFMT) == AE_IFLNK) {- /*- * Extract the symlink-name if it's included in the pathname.- */- if (!lha_parse_linkname(&linkname, &pathname)) {- /* We couldn't get the symlink-name. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unknown symlink-name");- archive_wstring_free(&pathname);- archive_wstring_free(&linkname);- return (ARCHIVE_FAILED);- }- } else {- /*- * Make sure a file-type is set.- * The mode has been overridden if it is in the extended data.- */- lha->mode = (lha->mode & ~AE_IFMT) |- ((lha->directory)? AE_IFDIR: AE_IFREG);- }- if ((lha->setflag & UNIX_MODE_IS_SET) == 0 &&- (lha->dos_attr & 1) != 0)- lha->mode &= ~(0222);/* read only. */-- /*- * Set basic file parameters.- */- archive_entry_copy_pathname_w(entry, pathname.s);- archive_wstring_free(&pathname);- if (archive_strlen(&linkname) > 0) {- archive_entry_copy_symlink_w(entry, linkname.s);- } else- archive_entry_set_symlink(entry, NULL);- archive_wstring_free(&linkname);- /*- * When a header level is 0, there is a possibility that- * a pathname and a symlink has '\' character, a directory- * separator in DOS/Windows. So we should convert it to '/'.- */- if (p[H_LEVEL_OFFSET] == 0)- lha_replace_path_separator(lha, entry);-- archive_entry_set_mode(entry, lha->mode);- archive_entry_set_uid(entry, lha->uid);- archive_entry_set_gid(entry, lha->gid);- if (archive_strlen(&lha->uname) > 0)- archive_entry_set_uname(entry, lha->uname.s);- if (archive_strlen(&lha->gname) > 0)- archive_entry_set_gname(entry, lha->gname.s);- if (lha->setflag & BIRTHTIME_IS_SET) {- archive_entry_set_birthtime(entry, lha->birthtime,- lha->birthtime_tv_nsec);- archive_entry_set_ctime(entry, lha->birthtime,- lha->birthtime_tv_nsec);- } else {- archive_entry_unset_birthtime(entry);- archive_entry_unset_ctime(entry);- }- archive_entry_set_mtime(entry, lha->mtime, lha->mtime_tv_nsec);- if (lha->setflag & ATIME_IS_SET)- archive_entry_set_atime(entry, lha->atime,- lha->atime_tv_nsec);- else- archive_entry_unset_atime(entry);- if (lha->directory || archive_entry_symlink(entry) != NULL)- archive_entry_unset_size(entry);- else- archive_entry_set_size(entry, lha->origsize);-- /*- * Prepare variables used to read a file content.- */- lha->entry_bytes_remaining = lha->compsize;- if (lha->entry_bytes_remaining < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid LHa entry size");- return (ARCHIVE_FATAL);- }- lha->entry_offset = 0;- lha->entry_crc_calculated = 0;-- /*- * This file does not have a content.- */- if (lha->directory || lha->compsize == 0)- lha->end_of_entry = 1;-- snprintf(lha->format_name, sizeof(lha->format_name), "lha -%c%c%c-",- lha->method[0], lha->method[1], lha->method[2]);- a->archive.archive_format_name = lha->format_name;-- return (err);-}--/*- * Replace a DOS path separator '\' by a character '/'.- * Some multi-byte character set have a character '\' in its second byte.- */-static void-lha_replace_path_separator(struct lha *lha, struct archive_entry *entry)-{- const wchar_t *wp;- size_t i;-- if ((wp = archive_entry_pathname_w(entry)) != NULL) {- archive_wstrcpy(&(lha->ws), wp);- for (i = 0; i < archive_strlen(&(lha->ws)); i++) {- if (lha->ws.s[i] == L'\\')- lha->ws.s[i] = L'/';- }- archive_entry_copy_pathname_w(entry, lha->ws.s);- }-- if ((wp = archive_entry_symlink_w(entry)) != NULL) {- archive_wstrcpy(&(lha->ws), wp);- for (i = 0; i < archive_strlen(&(lha->ws)); i++) {- if (lha->ws.s[i] == L'\\')- lha->ws.s[i] = L'/';- }- archive_entry_copy_symlink_w(entry, lha->ws.s);- }-}--/*- * Header 0 format- *- * +0 +1 +2 +7 +11- * +---------------+----------+----------------+-------------------+- * |header size(*1)|header sum|compression type|compressed size(*2)|- * +---------------+----------+----------------+-------------------+- * <---------------------(*1)----------*- *- * +11 +15 +17 +19 +20 +21- * +-----------------+---------+---------+--------------+----------------+- * |uncompressed size|time(DOS)|date(DOS)|attribute(DOS)|header level(=0)|- * +-----------------+---------+---------+--------------+----------------+- * *--------------------------------(*1)---------------------------------*- *- * +21 +22 +22+(*3) +22+(*3)+2 +22+(*3)+2+(*4)- * +---------------+---------+----------+----------------+------------------+- * |name length(*3)|file name|file CRC16|extra header(*4)| compressed data |- * +---------------+---------+----------+----------------+------------------+- * <--(*3)-> <------(*2)------>- * *----------------------(*1)-------------------------->- *- */-#define H0_HEADER_SIZE_OFFSET 0-#define H0_HEADER_SUM_OFFSET 1-#define H0_COMP_SIZE_OFFSET 7-#define H0_ORIG_SIZE_OFFSET 11-#define H0_DOS_TIME_OFFSET 15-#define H0_NAME_LEN_OFFSET 21-#define H0_FILE_NAME_OFFSET 22-#define H0_FIXED_SIZE 24-static int-lha_read_file_header_0(struct archive_read *a, struct lha *lha)-{- const unsigned char *p;- int extdsize, namelen;- unsigned char headersum, sum_calculated;-- if ((p = __archive_read_ahead(a, H0_FIXED_SIZE, NULL)) == NULL)- return (truncated_error(a));- lha->header_size = p[H0_HEADER_SIZE_OFFSET] + 2;- headersum = p[H0_HEADER_SUM_OFFSET];- lha->compsize = archive_le32dec(p + H0_COMP_SIZE_OFFSET);- lha->origsize = archive_le32dec(p + H0_ORIG_SIZE_OFFSET);- lha->mtime = lha_dos_time(p + H0_DOS_TIME_OFFSET);- namelen = p[H0_NAME_LEN_OFFSET];- extdsize = (int)lha->header_size - H0_FIXED_SIZE - namelen;- if ((namelen > 221 || extdsize < 0) && extdsize != -2) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid LHa header");- return (ARCHIVE_FATAL);- }- if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL)- return (truncated_error(a));-- archive_strncpy(&lha->filename, p + H0_FILE_NAME_OFFSET, namelen);- /* When extdsize == -2, A CRC16 value is not present in the header. */- if (extdsize >= 0) {- lha->crc = archive_le16dec(p + H0_FILE_NAME_OFFSET + namelen);- lha->setflag |= CRC_IS_SET;- }- sum_calculated = lha_calcsum(0, p, 2, lha->header_size - 2);-- /* Read an extended header */- if (extdsize > 0) {- /* This extended data is set by 'LHa for UNIX' only.- * Maybe fixed size.- */- p += H0_FILE_NAME_OFFSET + namelen + 2;- if (p[0] == 'U' && extdsize == 12) {- /* p[1] is a minor version. */- lha->mtime = archive_le32dec(&p[2]);- lha->mode = archive_le16dec(&p[6]);- lha->uid = archive_le16dec(&p[8]);- lha->gid = archive_le16dec(&p[10]);- lha->setflag |= UNIX_MODE_IS_SET;- }- }- __archive_read_consume(a, lha->header_size);-- if (sum_calculated != headersum) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "LHa header sum error");- return (ARCHIVE_FATAL);- }-- return (ARCHIVE_OK);-}--/*- * Header 1 format- *- * +0 +1 +2 +7 +11- * +---------------+----------+----------------+-------------+- * |header size(*1)|header sum|compression type|skip size(*2)|- * +---------------+----------+----------------+-------------+- * <---------------(*1)----------*- *- * +11 +15 +17 +19 +20 +21- * +-----------------+---------+---------+--------------+----------------+- * |uncompressed size|time(DOS)|date(DOS)|attribute(DOS)|header level(=1)|- * +-----------------+---------+---------+--------------+----------------+- * *-------------------------------(*1)----------------------------------*- *- * +21 +22 +22+(*3) +22+(*3)+2 +22+(*3)+3 +22+(*3)+3+(*4)- * +---------------+---------+----------+-----------+-----------+- * |name length(*3)|file name|file CRC16| creator |padding(*4)|- * +---------------+---------+----------+-----------+-----------+- * <--(*3)->- * *----------------------------(*1)----------------------------*- *- * +22+(*3)+3+(*4) +22+(*3)+3+(*4)+2 +22+(*3)+3+(*4)+2+(*5)- * +----------------+---------------------+------------------------+- * |next header size| extended header(*5) | compressed data |- * +----------------+---------------------+------------------------+- * *------(*1)-----> <--------------------(*2)-------------------->- */-#define H1_HEADER_SIZE_OFFSET 0-#define H1_HEADER_SUM_OFFSET 1-#define H1_COMP_SIZE_OFFSET 7-#define H1_ORIG_SIZE_OFFSET 11-#define H1_DOS_TIME_OFFSET 15-#define H1_NAME_LEN_OFFSET 21-#define H1_FILE_NAME_OFFSET 22-#define H1_FIXED_SIZE 27-static int-lha_read_file_header_1(struct archive_read *a, struct lha *lha)-{- const unsigned char *p;- size_t extdsize;- int i, err, err2;- int namelen, padding;- unsigned char headersum, sum_calculated;-- err = ARCHIVE_OK;-- if ((p = __archive_read_ahead(a, H1_FIXED_SIZE, NULL)) == NULL)- return (truncated_error(a));-- lha->header_size = p[H1_HEADER_SIZE_OFFSET] + 2;- headersum = p[H1_HEADER_SUM_OFFSET];- /* Note: An extended header size is included in a compsize. */- lha->compsize = archive_le32dec(p + H1_COMP_SIZE_OFFSET);- lha->origsize = archive_le32dec(p + H1_ORIG_SIZE_OFFSET);- lha->mtime = lha_dos_time(p + H1_DOS_TIME_OFFSET);- namelen = p[H1_NAME_LEN_OFFSET];- /* Calculate a padding size. The result will be normally 0 only(?) */- padding = ((int)lha->header_size) - H1_FIXED_SIZE - namelen;-- if (namelen > 230 || padding < 0)- goto invalid;-- if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL)- return (truncated_error(a));-- for (i = 0; i < namelen; i++) {- if (p[i + H1_FILE_NAME_OFFSET] == 0xff)- goto invalid;/* Invalid filename. */- }- archive_strncpy(&lha->filename, p + H1_FILE_NAME_OFFSET, namelen);- lha->crc = archive_le16dec(p + H1_FILE_NAME_OFFSET + namelen);- lha->setflag |= CRC_IS_SET;-- sum_calculated = lha_calcsum(0, p, 2, lha->header_size - 2);- /* Consume used bytes but not include `next header size' data- * since it will be consumed in lha_read_file_extended_header(). */- __archive_read_consume(a, lha->header_size - 2);-- /* Read extended headers */- err2 = lha_read_file_extended_header(a, lha, NULL, 2,- (size_t)(lha->compsize + 2), &extdsize);- if (err2 < ARCHIVE_WARN)- return (err2);- if (err2 < err)- err = err2;- /* Get a real compressed file size. */- lha->compsize -= extdsize - 2;-- if (lha->compsize < 0)- goto invalid; /* Invalid compressed file size */-- if (sum_calculated != headersum) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "LHa header sum error");- return (ARCHIVE_FATAL);- }- return (err);-invalid:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid LHa header");- return (ARCHIVE_FATAL);-}--/*- * Header 2 format- *- * +0 +2 +7 +11 +15- * +---------------+----------------+-------------------+-----------------+- * |header size(*1)|compression type|compressed size(*2)|uncompressed size|- * +---------------+----------------+-------------------+-----------------+- * <--------------------------------(*1)---------------------------------*- *- * +15 +19 +20 +21 +23 +24- * +-----------------+------------+----------------+----------+-----------+- * |data/time(time_t)| 0x20 fixed |header level(=2)|file CRC16| creator |- * +-----------------+------------+----------------+----------+-----------+- * *---------------------------------(*1)---------------------------------*- *- * +24 +26 +26+(*3) +26+(*3)+(*4)- * +----------------+-------------------+-------------+-------------------+- * |next header size|extended header(*3)| padding(*4) | compressed data |- * +----------------+-------------------+-------------+-------------------+- * *--------------------------(*1)-------------------> <------(*2)------->- *- */-#define H2_HEADER_SIZE_OFFSET 0-#define H2_COMP_SIZE_OFFSET 7-#define H2_ORIG_SIZE_OFFSET 11-#define H2_TIME_OFFSET 15-#define H2_CRC_OFFSET 21-#define H2_FIXED_SIZE 24-static int-lha_read_file_header_2(struct archive_read *a, struct lha *lha)-{- const unsigned char *p;- size_t extdsize;- int err, padding;- uint16_t header_crc;-- if ((p = __archive_read_ahead(a, H2_FIXED_SIZE, NULL)) == NULL)- return (truncated_error(a));-- lha->header_size =archive_le16dec(p + H2_HEADER_SIZE_OFFSET);- lha->compsize = archive_le32dec(p + H2_COMP_SIZE_OFFSET);- lha->origsize = archive_le32dec(p + H2_ORIG_SIZE_OFFSET);- lha->mtime = archive_le32dec(p + H2_TIME_OFFSET);- lha->crc = archive_le16dec(p + H2_CRC_OFFSET);- lha->setflag |= CRC_IS_SET;-- if (lha->header_size < H2_FIXED_SIZE) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid LHa header size");- return (ARCHIVE_FATAL);- }-- header_crc = lha_crc16(0, p, H2_FIXED_SIZE);- __archive_read_consume(a, H2_FIXED_SIZE);-- /* Read extended headers */- err = lha_read_file_extended_header(a, lha, &header_crc, 2,- lha->header_size - H2_FIXED_SIZE, &extdsize);- if (err < ARCHIVE_WARN)- return (err);-- /* Calculate a padding size. The result will be normally 0 or 1. */- padding = (int)lha->header_size - (int)(H2_FIXED_SIZE + extdsize);- if (padding > 0) {- if ((p = __archive_read_ahead(a, padding, NULL)) == NULL)- return (truncated_error(a));- header_crc = lha_crc16(header_crc, p, padding);- __archive_read_consume(a, padding);- }-- if (header_crc != lha->header_crc) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "LHa header CRC error");- return (ARCHIVE_FATAL);-#endif- }- return (err);-}--/*- * Header 3 format- *- * +0 +2 +7 +11 +15- * +------------+----------------+-------------------+-----------------+- * | 0x04 fixed |compression type|compressed size(*2)|uncompressed size|- * +------------+----------------+-------------------+-----------------+- * <-------------------------------(*1)-------------------------------*- *- * +15 +19 +20 +21 +23 +24- * +-----------------+------------+----------------+----------+-----------+- * |date/time(time_t)| 0x20 fixed |header level(=3)|file CRC16| creator |- * +-----------------+------------+----------------+----------+-----------+- * *--------------------------------(*1)----------------------------------*- *- * +24 +28 +32 +32+(*3)- * +---------------+----------------+-------------------+-----------------+- * |header size(*1)|next header size|extended header(*3)| compressed data |- * +---------------+----------------+-------------------+-----------------+- * *------------------------(*1)-----------------------> <------(*2)----->- *- */-#define H3_FIELD_LEN_OFFSET 0-#define H3_COMP_SIZE_OFFSET 7-#define H3_ORIG_SIZE_OFFSET 11-#define H3_TIME_OFFSET 15-#define H3_CRC_OFFSET 21-#define H3_HEADER_SIZE_OFFSET 24-#define H3_FIXED_SIZE 28-static int-lha_read_file_header_3(struct archive_read *a, struct lha *lha)-{- const unsigned char *p;- size_t extdsize;- int err;- uint16_t header_crc;-- if ((p = __archive_read_ahead(a, H3_FIXED_SIZE, NULL)) == NULL)- return (truncated_error(a));-- if (archive_le16dec(p + H3_FIELD_LEN_OFFSET) != 4)- goto invalid;- lha->header_size =archive_le32dec(p + H3_HEADER_SIZE_OFFSET);- lha->compsize = archive_le32dec(p + H3_COMP_SIZE_OFFSET);- lha->origsize = archive_le32dec(p + H3_ORIG_SIZE_OFFSET);- lha->mtime = archive_le32dec(p + H3_TIME_OFFSET);- lha->crc = archive_le16dec(p + H3_CRC_OFFSET);- lha->setflag |= CRC_IS_SET;-- if (lha->header_size < H3_FIXED_SIZE + 4)- goto invalid;- header_crc = lha_crc16(0, p, H3_FIXED_SIZE);- __archive_read_consume(a, H3_FIXED_SIZE);-- /* Read extended headers */- err = lha_read_file_extended_header(a, lha, &header_crc, 4,- lha->header_size - H3_FIXED_SIZE, &extdsize);- if (err < ARCHIVE_WARN)- return (err);-- if (header_crc != lha->header_crc) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "LHa header CRC error");- return (ARCHIVE_FATAL);-#endif- }- return (err);-invalid:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid LHa header");- return (ARCHIVE_FATAL);-}--/*- * Extended header format- *- * +0 +2 +3 -- used in header 1 and 2- * +0 +4 +5 -- used in header 3- * +--------------+---------+-------------------+--------------+--- * |ex-header size|header id| data |ex-header size| .......- * +--------------+---------+-------------------+--------------+--- * <-------------( ex-header size)------------> <-- next extended header --*- *- * If the ex-header size is zero, it is the make of the end of extended- * headers.- *- */-static int-lha_read_file_extended_header(struct archive_read *a, struct lha *lha,- uint16_t *crc, int sizefield_length, size_t limitsize, size_t *total_size)-{- const void *h;- const unsigned char *extdheader;- size_t extdsize;- size_t datasize;- unsigned int i;- unsigned char extdtype;--#define EXT_HEADER_CRC 0x00 /* Header CRC and information*/-#define EXT_FILENAME 0x01 /* Filename */-#define EXT_DIRECTORY 0x02 /* Directory name */-#define EXT_DOS_ATTR 0x40 /* MS-DOS attribute */-#define EXT_TIMESTAMP 0x41 /* Windows time stamp */-#define EXT_FILESIZE 0x42 /* Large file size */-#define EXT_TIMEZONE 0x43 /* Time zone */-#define EXT_UTF16_FILENAME 0x44 /* UTF-16 filename */-#define EXT_UTF16_DIRECTORY 0x45 /* UTF-16 directory name */-#define EXT_CODEPAGE 0x46 /* Codepage */-#define EXT_UNIX_MODE 0x50 /* File permission */-#define EXT_UNIX_GID_UID 0x51 /* gid,uid */-#define EXT_UNIX_GNAME 0x52 /* Group name */-#define EXT_UNIX_UNAME 0x53 /* User name */-#define EXT_UNIX_MTIME 0x54 /* Modified time */-#define EXT_OS2_NEW_ATTR 0x7f /* new attribute(OS/2 only) */-#define EXT_NEW_ATTR 0xff /* new attribute */-- *total_size = sizefield_length;-- for (;;) {- /* Read an extended header size. */- if ((h =- __archive_read_ahead(a, sizefield_length, NULL)) == NULL)- return (truncated_error(a));- /* Check if the size is the zero indicates the end of the- * extended header. */- if (sizefield_length == sizeof(uint16_t))- extdsize = archive_le16dec(h);- else- extdsize = archive_le32dec(h);- if (extdsize == 0) {- /* End of extended header */- if (crc != NULL)- *crc = lha_crc16(*crc, h, sizefield_length);- __archive_read_consume(a, sizefield_length);- return (ARCHIVE_OK);- }-- /* Sanity check to the extended header size. */- if (((uint64_t)*total_size + extdsize) >- (uint64_t)limitsize ||- extdsize <= (size_t)sizefield_length)- goto invalid;-- /* Read the extended header. */- if ((h = __archive_read_ahead(a, extdsize, NULL)) == NULL)- return (truncated_error(a));- *total_size += extdsize;-- extdheader = (const unsigned char *)h;- /* Get the extended header type. */- extdtype = extdheader[sizefield_length];- /* Calculate an extended data size. */- datasize = extdsize - (1 + sizefield_length);- /* Skip an extended header size field and type field. */- extdheader += sizefield_length + 1;-- if (crc != NULL && extdtype != EXT_HEADER_CRC)- *crc = lha_crc16(*crc, h, extdsize);- switch (extdtype) {- case EXT_HEADER_CRC:- /* We only use a header CRC. Following data will not- * be used. */- if (datasize >= 2) {- lha->header_crc = archive_le16dec(extdheader);- if (crc != NULL) {- static const char zeros[2] = {0, 0};- *crc = lha_crc16(*crc, h,- extdsize - datasize);- /* CRC value itself as zero */- *crc = lha_crc16(*crc, zeros, 2);- *crc = lha_crc16(*crc,- extdheader+2, datasize - 2);- }- }- break;- case EXT_FILENAME:- if (datasize == 0) {- /* maybe directory header */- archive_string_empty(&lha->filename);- break;- }- if (extdheader[0] == '\0')- goto invalid;- archive_strncpy(&lha->filename,- (const char *)extdheader, datasize);- break;- case EXT_UTF16_FILENAME:- if (datasize == 0) {- /* maybe directory header */- archive_string_empty(&lha->filename);- break;- } else if (datasize & 1) {- /* UTF-16 characters take always 2 or 4 bytes */- goto invalid;- }- if (extdheader[0] == '\0')- goto invalid;- archive_string_empty(&lha->filename);- archive_array_append(&lha->filename,- (const char *)extdheader, datasize);- /* Setup a string conversion for a filename. */- lha->sconv_fname =- archive_string_conversion_from_charset(&a->archive,- "UTF-16LE", 1);- if (lha->sconv_fname == NULL)- return (ARCHIVE_FATAL);- break;- case EXT_DIRECTORY:- if (datasize == 0 || extdheader[0] == '\0')- /* no directory name data. exit this case. */- goto invalid;-- archive_strncpy(&lha->dirname,- (const char *)extdheader, datasize);- /*- * Convert directory delimiter from 0xFF- * to '/' for local system.- */- for (i = 0; i < lha->dirname.length; i++) {- if ((unsigned char)lha->dirname.s[i] == 0xFF)- lha->dirname.s[i] = '/';- }- /* Is last character directory separator? */- if (lha->dirname.s[lha->dirname.length-1] != '/')- /* invalid directory data */- goto invalid;- break;- case EXT_UTF16_DIRECTORY:- /* UTF-16 characters take always 2 or 4 bytes */- if (datasize == 0 || (datasize & 1) ||- extdheader[0] == '\0') {- /* no directory name data. exit this case. */- goto invalid;- }-- archive_string_empty(&lha->dirname);- archive_array_append(&lha->dirname,- (const char *)extdheader, datasize);- lha->sconv_dir =- archive_string_conversion_from_charset(&a->archive,- "UTF-16LE", 1);- if (lha->sconv_dir == NULL)- return (ARCHIVE_FATAL);- else {- /*- * Convert directory delimiter from 0xFFFF- * to '/' for local system.- */- uint16_t dirSep;- uint16_t d = 1;- if (archive_be16dec(&d) == 1)- dirSep = 0x2F00;- else- dirSep = 0x002F;-- /* UTF-16LE character */- uint16_t *utf16name =- (uint16_t *)lha->dirname.s;- for (i = 0; i < lha->dirname.length / 2; i++) {- if (utf16name[i] == 0xFFFF) {- utf16name[i] = dirSep;- }- }- /* Is last character directory separator? */- if (utf16name[lha->dirname.length / 2 - 1] !=- dirSep) {- /* invalid directory data */- goto invalid;- }- }- break;- case EXT_DOS_ATTR:- if (datasize == 2)- lha->dos_attr = (unsigned char)- (archive_le16dec(extdheader) & 0xff);- break;- case EXT_TIMESTAMP:- if (datasize == (sizeof(uint64_t) * 3)) {- lha->birthtime = lha_win_time(- archive_le64dec(extdheader),- &lha->birthtime_tv_nsec);- extdheader += sizeof(uint64_t);- lha->mtime = lha_win_time(- archive_le64dec(extdheader),- &lha->mtime_tv_nsec);- extdheader += sizeof(uint64_t);- lha->atime = lha_win_time(- archive_le64dec(extdheader),- &lha->atime_tv_nsec);- lha->setflag |= BIRTHTIME_IS_SET |- ATIME_IS_SET;- }- break;- case EXT_FILESIZE:- if (datasize == sizeof(uint64_t) * 2) {- lha->compsize = archive_le64dec(extdheader);- extdheader += sizeof(uint64_t);- lha->origsize = archive_le64dec(extdheader);- }- break;- case EXT_CODEPAGE:- /* Get an archived filename charset from codepage.- * This overwrites the charset specified by- * hdrcharset option. */- if (datasize == sizeof(uint32_t)) {- struct archive_string cp;- const char *charset;-- archive_string_init(&cp);- switch (archive_le32dec(extdheader)) {- case 65001: /* UTF-8 */- charset = "UTF-8";- break;- default:- archive_string_sprintf(&cp, "CP%d",- (int)archive_le32dec(extdheader));- charset = cp.s;- break;- }- lha->sconv_dir =- archive_string_conversion_from_charset(- &(a->archive), charset, 1);- lha->sconv_fname =- archive_string_conversion_from_charset(- &(a->archive), charset, 1);- archive_string_free(&cp);- if (lha->sconv_dir == NULL)- return (ARCHIVE_FATAL);- if (lha->sconv_fname == NULL)- return (ARCHIVE_FATAL);- }- break;- case EXT_UNIX_MODE:- if (datasize == sizeof(uint16_t)) {- lha->mode = archive_le16dec(extdheader);- lha->setflag |= UNIX_MODE_IS_SET;- }- break;- case EXT_UNIX_GID_UID:- if (datasize == (sizeof(uint16_t) * 2)) {- lha->gid = archive_le16dec(extdheader);- lha->uid = archive_le16dec(extdheader+2);- }- break;- case EXT_UNIX_GNAME:- if (datasize > 0)- archive_strncpy(&lha->gname,- (const char *)extdheader, datasize);- break;- case EXT_UNIX_UNAME:- if (datasize > 0)- archive_strncpy(&lha->uname,- (const char *)extdheader, datasize);- break;- case EXT_UNIX_MTIME:- if (datasize == sizeof(uint32_t))- lha->mtime = archive_le32dec(extdheader);- break;- case EXT_OS2_NEW_ATTR:- /* This extended header is OS/2 depend. */- if (datasize == 16) {- lha->dos_attr = (unsigned char)- (archive_le16dec(extdheader) & 0xff);- lha->mode = archive_le16dec(extdheader+2);- lha->gid = archive_le16dec(extdheader+4);- lha->uid = archive_le16dec(extdheader+6);- lha->birthtime = archive_le32dec(extdheader+8);- lha->atime = archive_le32dec(extdheader+12);- lha->setflag |= UNIX_MODE_IS_SET- | BIRTHTIME_IS_SET | ATIME_IS_SET;- }- break;- case EXT_NEW_ATTR:- if (datasize == 20) {- lha->mode = (mode_t)archive_le32dec(extdheader);- lha->gid = archive_le32dec(extdheader+4);- lha->uid = archive_le32dec(extdheader+8);- lha->birthtime = archive_le32dec(extdheader+12);- lha->atime = archive_le32dec(extdheader+16);- lha->setflag |= UNIX_MODE_IS_SET- | BIRTHTIME_IS_SET | ATIME_IS_SET;- }- break;- case EXT_TIMEZONE: /* Not supported */- break;- default:- break;- }-- __archive_read_consume(a, extdsize);- }-invalid:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid extended LHa header");- return (ARCHIVE_FATAL);-}--static int-lha_end_of_entry(struct archive_read *a)-{- struct lha *lha = (struct lha *)(a->format->data);- int r = ARCHIVE_EOF;-- if (!lha->end_of_entry_cleanup) {- if ((lha->setflag & CRC_IS_SET) &&- lha->crc != lha->entry_crc_calculated) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "LHa data CRC error");- r = ARCHIVE_WARN;- }-- /* End-of-entry cleanup done. */- lha->end_of_entry_cleanup = 1;- }- return (r);-}--static int-archive_read_format_lha_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- struct lha *lha = (struct lha *)(a->format->data);- int r;-- if (lha->entry_unconsumed) {- /* Consume as much as the decompressor actually used. */- __archive_read_consume(a, lha->entry_unconsumed);- lha->entry_unconsumed = 0;- }- if (lha->end_of_entry) {- *offset = lha->entry_offset;- *size = 0;- *buff = NULL;- return (lha_end_of_entry(a));- }-- if (lha->entry_is_compressed)- r = lha_read_data_lzh(a, buff, size, offset);- else- /* No compression. */- r = lha_read_data_none(a, buff, size, offset);- return (r);-}--/*- * Read a file content in no compression.- *- * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets- * lha->end_of_entry if it consumes all of the data.- */-static int-lha_read_data_none(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset)-{- struct lha *lha = (struct lha *)(a->format->data);- ssize_t bytes_avail;-- if (lha->entry_bytes_remaining == 0) {- *buff = NULL;- *size = 0;- *offset = lha->entry_offset;- lha->end_of_entry = 1;- return (ARCHIVE_OK);- }- /*- * Note: '1' here is a performance optimization.- * Recall that the decompression layer returns a count of- * available bytes; asking for more than that forces the- * decompressor to combine reads by copying data.- */- *buff = __archive_read_ahead(a, 1, &bytes_avail);- if (bytes_avail <= 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated LHa file data");- return (ARCHIVE_FATAL);- }- if (bytes_avail > lha->entry_bytes_remaining)- bytes_avail = (ssize_t)lha->entry_bytes_remaining;- lha->entry_crc_calculated =- lha_crc16(lha->entry_crc_calculated, *buff, bytes_avail);- *size = bytes_avail;- *offset = lha->entry_offset;- lha->entry_offset += bytes_avail;- lha->entry_bytes_remaining -= bytes_avail;- if (lha->entry_bytes_remaining == 0)- lha->end_of_entry = 1;- lha->entry_unconsumed = bytes_avail;- return (ARCHIVE_OK);-}--/*- * Read a file content in LZHUFF encoding.- *- * Returns ARCHIVE_OK if successful, returns ARCHIVE_WARN if compression is- * unsupported, ARCHIVE_FATAL otherwise, sets lha->end_of_entry if it consumes- * all of the data.- */-static int-lha_read_data_lzh(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset)-{- struct lha *lha = (struct lha *)(a->format->data);- ssize_t bytes_avail;- int r;-- /* If we haven't yet read any data, initialize the decompressor. */- if (!lha->decompress_init) {- r = lzh_decode_init(&(lha->strm), lha->method);- switch (r) {- case ARCHIVE_OK:- break;- case ARCHIVE_FAILED:- /* Unsupported compression. */- *buff = NULL;- *size = 0;- *offset = 0;- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported lzh compression method -%c%c%c-",- lha->method[0], lha->method[1], lha->method[2]);- /* We know compressed size; just skip it. */- archive_read_format_lha_read_data_skip(a);- return (ARCHIVE_WARN);- default:- archive_set_error(&a->archive, ENOMEM,- "Couldn't allocate memory "- "for lzh decompression");- return (ARCHIVE_FATAL);- }- /* We've initialized decompression for this stream. */- lha->decompress_init = 1;- lha->strm.avail_out = 0;- lha->strm.total_out = 0;- }-- /*- * Note: '1' here is a performance optimization.- * Recall that the decompression layer returns a count of- * available bytes; asking for more than that forces the- * decompressor to combine reads by copying data.- */- lha->strm.next_in = __archive_read_ahead(a, 1, &bytes_avail);- if (bytes_avail <= 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated LHa file body");- return (ARCHIVE_FATAL);- }- if (bytes_avail > lha->entry_bytes_remaining)- bytes_avail = (ssize_t)lha->entry_bytes_remaining;-- lha->strm.avail_in = (int)bytes_avail;- lha->strm.total_in = 0;- lha->strm.avail_out = 0;-- r = lzh_decode(&(lha->strm), bytes_avail == lha->entry_bytes_remaining);- switch (r) {- case ARCHIVE_OK:- break;- case ARCHIVE_EOF:- lha->end_of_entry = 1;- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Bad lzh data");- return (ARCHIVE_FAILED);- }- lha->entry_unconsumed = lha->strm.total_in;- lha->entry_bytes_remaining -= lha->strm.total_in;-- if (lha->strm.avail_out) {- *offset = lha->entry_offset;- *size = lha->strm.avail_out;- *buff = lha->strm.ref_ptr;- lha->entry_crc_calculated =- lha_crc16(lha->entry_crc_calculated, *buff, *size);- lha->entry_offset += *size;- } else {- *offset = lha->entry_offset;- *size = 0;- *buff = NULL;- if (lha->end_of_entry)- return (lha_end_of_entry(a));- }- return (ARCHIVE_OK);-}--/*- * Skip a file content.- */-static int-archive_read_format_lha_read_data_skip(struct archive_read *a)-{- struct lha *lha;- int64_t bytes_skipped;-- lha = (struct lha *)(a->format->data);-- if (lha->entry_unconsumed) {- /* Consume as much as the decompressor actually used. */- __archive_read_consume(a, lha->entry_unconsumed);- lha->entry_unconsumed = 0;- }-- /* if we've already read to end of data, we're done. */- if (lha->end_of_entry_cleanup)- return (ARCHIVE_OK);-- /*- * If the length is at the beginning, we can skip the- * compressed data much more quickly.- */- bytes_skipped = __archive_read_consume(a, lha->entry_bytes_remaining);- if (bytes_skipped < 0)- return (ARCHIVE_FATAL);-- /* This entry is finished and done. */- lha->end_of_entry_cleanup = lha->end_of_entry = 1;- return (ARCHIVE_OK);-}--static int-archive_read_format_lha_cleanup(struct archive_read *a)-{- struct lha *lha = (struct lha *)(a->format->data);-- lzh_decode_free(&(lha->strm));- archive_string_free(&(lha->dirname));- archive_string_free(&(lha->filename));- archive_string_free(&(lha->uname));- archive_string_free(&(lha->gname));- archive_wstring_free(&(lha->ws));- free(lha);- (a->format->data) = NULL;- return (ARCHIVE_OK);-}--/*- * 'LHa for UNIX' utility has archived a symbolic-link name after- * a pathname with '|' character.- * This function extracts the symbolic-link name from the pathname.- *- * example.- * 1. a symbolic-name is 'aaa/bb/cc'- * 2. a filename is 'xxx/bbb'- * then a archived pathname is 'xxx/bbb|aaa/bb/cc'- */-static int-lha_parse_linkname(struct archive_wstring *linkname,- struct archive_wstring *pathname)-{- wchar_t * linkptr;- size_t symlen;-- linkptr = wcschr(pathname->s, L'|');- if (linkptr != NULL) {- symlen = wcslen(linkptr + 1);- archive_wstrncpy(linkname, linkptr+1, symlen);-- *linkptr = 0;- pathname->length = wcslen(pathname->s);-- return (1);- }- return (0);-}--/* Convert an MSDOS-style date/time into Unix-style time. */-static time_t-lha_dos_time(const unsigned char *p)-{- int msTime, msDate;- struct tm ts;-- msTime = archive_le16dec(p);- msDate = archive_le16dec(p+2);-- memset(&ts, 0, sizeof(ts));- ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */- ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */- ts.tm_mday = msDate & 0x1f; /* Day of month. */- ts.tm_hour = (msTime >> 11) & 0x1f;- ts.tm_min = (msTime >> 5) & 0x3f;- ts.tm_sec = (msTime << 1) & 0x3e;- ts.tm_isdst = -1;- return (mktime(&ts));-}--/* Convert an MS-Windows-style date/time into Unix-style time. */-static time_t-lha_win_time(uint64_t wintime, long *ns)-{-#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)-- if (wintime >= EPOC_TIME) {- wintime -= EPOC_TIME; /* 1970-01-01 00:00:00 (UTC) */- if (ns != NULL)- *ns = (long)(wintime % 10000000) * 100;- return (wintime / 10000000);- } else {- if (ns != NULL)- *ns = 0;- return (0);- }-}--static unsigned char-lha_calcsum(unsigned char sum, const void *pp, int offset, size_t size)-{- unsigned char const *p = (unsigned char const *)pp;-- p += offset;- for (;size > 0; --size)- sum += *p++;- return (sum);-}--static uint16_t crc16tbl[2][256];-static void-lha_crc16_init(void)-{- unsigned int i;- static int crc16init = 0;-- if (crc16init)- return;- crc16init = 1;-- for (i = 0; i < 256; i++) {- unsigned int j;- uint16_t crc = (uint16_t)i;- for (j = 8; j; j--)- crc = (crc >> 1) ^ ((crc & 1) * 0xA001);- crc16tbl[0][i] = crc;- }-- for (i = 0; i < 256; i++) {- crc16tbl[1][i] = (crc16tbl[0][i] >> 8)- ^ crc16tbl[0][crc16tbl[0][i] & 0xff];- }-}--static uint16_t-lha_crc16(uint16_t crc, const void *pp, size_t len)-{- const unsigned char *p = (const unsigned char *)pp;- const uint16_t *buff;- const union {- uint32_t i;- char c[4];- } u = { 0x01020304 };-- if (len == 0)- return crc;-- /* Process unaligned address. */- if (((uintptr_t)p) & (uintptr_t)0x1) {- crc = (crc >> 8) ^ crc16tbl[0][(crc ^ *p++) & 0xff];- len--;- }- buff = (const uint16_t *)p;- /*- * Modern C compiler such as GCC does not unroll automatically yet- * without unrolling pragma, and Clang is so. So we should- * unroll this loop for its performance.- */- for (;len >= 8; len -= 8) {- /* This if statement expects compiler optimization will- * remove the statement which will not be executed. */-#undef bswap16-#ifndef __has_builtin-#define __has_builtin(x) 0-#endif-#if defined(_MSC_VER) && _MSC_VER >= 1400 /* Visual Studio */-# define bswap16(x) _byteswap_ushort(x)-#elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ > 4)-/* GCC 4.8 and later has __builtin_bswap16() */-# define bswap16(x) __builtin_bswap16(x)-#elif defined(__clang__) && __has_builtin(__builtin_bswap16)-/* Newer clang versions have __builtin_bswap16() */-# define bswap16(x) __builtin_bswap16(x)-#else-# define bswap16(x) ((((x) >> 8) & 0xff) | ((x) << 8))-#endif-#define CRC16W do { \- if(u.c[0] == 1) { /* Big endian */ \- crc ^= bswap16(*buff); buff++; \- } else \- crc ^= *buff++; \- crc = crc16tbl[1][crc & 0xff] ^ crc16tbl[0][crc >> 8];\-} while (0)- CRC16W;- CRC16W;- CRC16W;- CRC16W;-#undef CRC16W-#undef bswap16- }-- p = (const unsigned char *)buff;- for (;len; len--) {- crc = (crc >> 8) ^ crc16tbl[0][(crc ^ *p++) & 0xff];- }- return crc;-}--/*- * Initialize LZHUF decoder.- *- * Returns ARCHIVE_OK if initialization was successful.- * Returns ARCHIVE_FAILED if method is unsupported.- * Returns ARCHIVE_FATAL if initialization failed; memory allocation- * error occurred.- */-static int-lzh_decode_init(struct lzh_stream *strm, const char *method)-{- struct lzh_dec *ds;- int w_bits, w_size;-- if (strm->ds == NULL) {- strm->ds = calloc(1, sizeof(*strm->ds));- if (strm->ds == NULL)- return (ARCHIVE_FATAL);- }- ds = strm->ds;- ds->error = ARCHIVE_FAILED;- if (method == NULL || method[0] != 'l' || method[1] != 'h')- return (ARCHIVE_FAILED);- switch (method[2]) {- case '5':- w_bits = 13;/* 8KiB for window */- break;- case '6':- w_bits = 15;/* 32KiB for window */- break;- case '7':- w_bits = 16;/* 64KiB for window */- break;- default:- return (ARCHIVE_FAILED);/* Not supported. */- }- ds->error = ARCHIVE_FATAL;- /* Expand a window size up to 128 KiB for decompressing process- * performance whatever its original window size is. */- ds->w_size = 1U << 17;- ds->w_mask = ds->w_size -1;- if (ds->w_buff == NULL) {- ds->w_buff = malloc(ds->w_size);- if (ds->w_buff == NULL)- return (ARCHIVE_FATAL);- }- w_size = 1U << w_bits;- memset(ds->w_buff + ds->w_size - w_size, 0x20, w_size);- ds->w_pos = 0;- ds->state = 0;- ds->pos_pt_len_size = w_bits + 1;- ds->pos_pt_len_bits = (w_bits == 15 || w_bits == 16)? 5: 4;- ds->literal_pt_len_size = PT_BITLEN_SIZE;- ds->literal_pt_len_bits = 5;- ds->br.cache_buffer = 0;- ds->br.cache_avail = 0;-- if (lzh_huffman_init(&(ds->lt), LT_BITLEN_SIZE, 16)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- ds->lt.len_bits = 9;- if (lzh_huffman_init(&(ds->pt), PT_BITLEN_SIZE, 16)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- ds->error = 0;-- return (ARCHIVE_OK);-}--/*- * Release LZHUF decoder.- */-static void-lzh_decode_free(struct lzh_stream *strm)-{-- if (strm->ds == NULL)- return;- free(strm->ds->w_buff);- lzh_huffman_free(&(strm->ds->lt));- lzh_huffman_free(&(strm->ds->pt));- free(strm->ds);- strm->ds = NULL;-}--/*- * Bit stream reader.- */-/* Check that the cache buffer has enough bits. */-#define lzh_br_has(br, n) ((br)->cache_avail >= n)-/* Get compressed data by bit. */-#define lzh_br_bits(br, n) \- (((uint16_t)((br)->cache_buffer >> \- ((br)->cache_avail - (n)))) & cache_masks[n])-#define lzh_br_bits_forced(br, n) \- (((uint16_t)((br)->cache_buffer << \- ((n) - (br)->cache_avail))) & cache_masks[n])-/* Read ahead to make sure the cache buffer has enough compressed data we- * will use.- * True : completed, there is enough data in the cache buffer.- * False : we met that strm->next_in is empty, we have to get following- * bytes. */-#define lzh_br_read_ahead_0(strm, br, n) \- (lzh_br_has(br, (n)) || lzh_br_fillup(strm, br))-/* True : the cache buffer has some bits as much as we need.- * False : there are no enough bits in the cache buffer to be used,- * we have to get following bytes if we could. */-#define lzh_br_read_ahead(strm, br, n) \- (lzh_br_read_ahead_0((strm), (br), (n)) || lzh_br_has((br), (n)))--/* Notify how many bits we consumed. */-#define lzh_br_consume(br, n) ((br)->cache_avail -= (n))-#define lzh_br_unconsume(br, n) ((br)->cache_avail += (n))--static const uint16_t cache_masks[] = {- 0x0000, 0x0001, 0x0003, 0x0007,- 0x000F, 0x001F, 0x003F, 0x007F,- 0x00FF, 0x01FF, 0x03FF, 0x07FF,- 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF,- 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF-};--/*- * Shift away used bits in the cache data and fill it up with following bits.- * Call this when cache buffer does not have enough bits you need.- *- * Returns 1 if the cache buffer is full.- * Returns 0 if the cache buffer is not full; input buffer is empty.- */-static int-lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br)-{- int n = CACHE_BITS - br->cache_avail;-- for (;;) {- const int x = n >> 3;- if (strm->avail_in >= x) {- switch (x) {- case 8:- br->cache_buffer =- ((uint64_t)strm->next_in[0]) << 56 |- ((uint64_t)strm->next_in[1]) << 48 |- ((uint64_t)strm->next_in[2]) << 40 |- ((uint64_t)strm->next_in[3]) << 32 |- ((uint32_t)strm->next_in[4]) << 24 |- ((uint32_t)strm->next_in[5]) << 16 |- ((uint32_t)strm->next_in[6]) << 8 |- (uint32_t)strm->next_in[7];- strm->next_in += 8;- strm->avail_in -= 8;- br->cache_avail += 8 * 8;- return (1);- case 7:- br->cache_buffer =- (br->cache_buffer << 56) |- ((uint64_t)strm->next_in[0]) << 48 |- ((uint64_t)strm->next_in[1]) << 40 |- ((uint64_t)strm->next_in[2]) << 32 |- ((uint64_t)strm->next_in[3]) << 24 |- ((uint64_t)strm->next_in[4]) << 16 |- ((uint64_t)strm->next_in[5]) << 8 |- (uint64_t)strm->next_in[6];- strm->next_in += 7;- strm->avail_in -= 7;- br->cache_avail += 7 * 8;- return (1);- case 6:- br->cache_buffer =- (br->cache_buffer << 48) |- ((uint64_t)strm->next_in[0]) << 40 |- ((uint64_t)strm->next_in[1]) << 32 |- ((uint64_t)strm->next_in[2]) << 24 |- ((uint64_t)strm->next_in[3]) << 16 |- ((uint64_t)strm->next_in[4]) << 8 |- (uint64_t)strm->next_in[5];- strm->next_in += 6;- strm->avail_in -= 6;- br->cache_avail += 6 * 8;- return (1);- case 0:- /* We have enough compressed data in- * the cache buffer.*/- return (1);- default:- break;- }- }- if (strm->avail_in == 0) {- /* There is not enough compressed data to fill up the- * cache buffer. */- return (0);- }- br->cache_buffer =- (br->cache_buffer << 8) | *strm->next_in++;- strm->avail_in--;- br->cache_avail += 8;- n -= 8;- }-}--/*- * Decode LZHUF.- *- * 1. Returns ARCHIVE_OK if output buffer or input buffer are empty.- * Please set available buffer and call this function again.- * 2. Returns ARCHIVE_EOF if decompression has been completed.- * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data- * is broken or you do not set 'last' flag properly.- * 4. 'last' flag is very important, you must set 1 to the flag if there- * is no input data. The lha compressed data format does not provide how- * to know the compressed data is really finished.- * Note: lha command utility check if the total size of output bytes is- * reached the uncompressed size recorded in its header. it does not mind- * that the decoding process is properly finished.- * GNU ZIP can decompress another compressed file made by SCO LZH compress.- * it handles EOF as null to fill read buffer with zero until the decoding- * process meet 2 bytes of zeros at reading a size of a next chunk, so the- * zeros are treated as the mark of the end of the data although the zeros- * is dummy, not the file data.- */-static int lzh_read_blocks(struct lzh_stream *, int);-static int lzh_decode_blocks(struct lzh_stream *, int);-#define ST_RD_BLOCK 0-#define ST_RD_PT_1 1-#define ST_RD_PT_2 2-#define ST_RD_PT_3 3-#define ST_RD_PT_4 4-#define ST_RD_LITERAL_1 5-#define ST_RD_LITERAL_2 6-#define ST_RD_LITERAL_3 7-#define ST_RD_POS_DATA_1 8-#define ST_GET_LITERAL 9-#define ST_GET_POS_1 10-#define ST_GET_POS_2 11-#define ST_COPY_DATA 12--static int-lzh_decode(struct lzh_stream *strm, int last)-{- struct lzh_dec *ds = strm->ds;- int avail_in;- int r;-- if (ds->error)- return (ds->error);-- avail_in = strm->avail_in;- do {- if (ds->state < ST_GET_LITERAL)- r = lzh_read_blocks(strm, last);- else- r = lzh_decode_blocks(strm, last);- } while (r == 100);- strm->total_in += avail_in - strm->avail_in;- return (r);-}--static void-lzh_emit_window(struct lzh_stream *strm, size_t s)-{- strm->ref_ptr = strm->ds->w_buff;- strm->avail_out = (int)s;- strm->total_out += s;-}--static int-lzh_read_blocks(struct lzh_stream *strm, int last)-{- struct lzh_dec *ds = strm->ds;- struct lzh_br *br = &(ds->br);- int c = 0, i;- unsigned rbits;-- for (;;) {- switch (ds->state) {- case ST_RD_BLOCK:- /*- * Read a block number indicates how many blocks- * we will handle. The block is composed of a- * literal and a match, sometimes a literal only- * in particular, there are no reference data at- * the beginning of the decompression.- */- if (!lzh_br_read_ahead_0(strm, br, 16)) {- if (!last)- /* We need following data. */- return (ARCHIVE_OK);- if (lzh_br_has(br, 8)) {- /*- * It seems there are extra bits.- * 1. Compressed data is broken.- * 2. `last' flag does not properly- * set.- */- goto failed;- }- if (ds->w_pos > 0) {- lzh_emit_window(strm, ds->w_pos);- ds->w_pos = 0;- return (ARCHIVE_OK);- }- /* End of compressed data; we have completely- * handled all compressed data. */- return (ARCHIVE_EOF);- }- ds->blocks_avail = lzh_br_bits(br, 16);- if (ds->blocks_avail == 0)- goto failed;- lzh_br_consume(br, 16);- /*- * Read a literal table compressed in huffman- * coding.- */- ds->pt.len_size = ds->literal_pt_len_size;- ds->pt.len_bits = ds->literal_pt_len_bits;- ds->reading_position = 0;- /* FALL THROUGH */- case ST_RD_PT_1:- /* Note: ST_RD_PT_1, ST_RD_PT_2 and ST_RD_PT_4 are- * used in reading both a literal table and a- * position table. */- if (!lzh_br_read_ahead(strm, br, ds->pt.len_bits)) {- if (last)- goto failed;/* Truncated data. */- ds->state = ST_RD_PT_1;- return (ARCHIVE_OK);- }- ds->pt.len_avail = lzh_br_bits(br, ds->pt.len_bits);- lzh_br_consume(br, ds->pt.len_bits);- /* FALL THROUGH */- case ST_RD_PT_2:- if (ds->pt.len_avail == 0) {- /* There is no bitlen. */- if (!lzh_br_read_ahead(strm, br,- ds->pt.len_bits)) {- if (last)- goto failed;/* Truncated data.*/- ds->state = ST_RD_PT_2;- return (ARCHIVE_OK);- }- if (!lzh_make_fake_table(&(ds->pt),- lzh_br_bits(br, ds->pt.len_bits)))- goto failed;/* Invalid data. */- lzh_br_consume(br, ds->pt.len_bits);- if (ds->reading_position)- ds->state = ST_GET_LITERAL;- else- ds->state = ST_RD_LITERAL_1;- break;- } else if (ds->pt.len_avail > ds->pt.len_size)- goto failed;/* Invalid data. */- ds->loop = 0;- memset(ds->pt.freq, 0, sizeof(ds->pt.freq));- if (ds->pt.len_avail < 3 ||- ds->pt.len_size == ds->pos_pt_len_size) {- ds->state = ST_RD_PT_4;- break;- }- /* FALL THROUGH */- case ST_RD_PT_3:- ds->loop = lzh_read_pt_bitlen(strm, ds->loop, 3);- if (ds->loop < 3) {- if (ds->loop < 0 || last)- goto failed;/* Invalid data. */- /* Not completed, get following data. */- ds->state = ST_RD_PT_3;- return (ARCHIVE_OK);- }- /* There are some null in bitlen of the literal. */- if (!lzh_br_read_ahead(strm, br, 2)) {- if (last)- goto failed;/* Truncated data. */- ds->state = ST_RD_PT_3;- return (ARCHIVE_OK);- }- c = lzh_br_bits(br, 2);- lzh_br_consume(br, 2);- if (c > ds->pt.len_avail - 3)- goto failed;/* Invalid data. */- for (i = 3; c-- > 0 ;)- ds->pt.bitlen[i++] = 0;- ds->loop = i;- /* FALL THROUGH */- case ST_RD_PT_4:- ds->loop = lzh_read_pt_bitlen(strm, ds->loop,- ds->pt.len_avail);- if (ds->loop < ds->pt.len_avail) {- if (ds->loop < 0 || last)- goto failed;/* Invalid data. */- /* Not completed, get following data. */- ds->state = ST_RD_PT_4;- return (ARCHIVE_OK);- }- if (!lzh_make_huffman_table(&(ds->pt)))- goto failed;/* Invalid data */- if (ds->reading_position) {- ds->state = ST_GET_LITERAL;- break;- }- /* FALL THROUGH */- case ST_RD_LITERAL_1:- if (!lzh_br_read_ahead(strm, br, ds->lt.len_bits)) {- if (last)- goto failed;/* Truncated data. */- ds->state = ST_RD_LITERAL_1;- return (ARCHIVE_OK);- }- ds->lt.len_avail = lzh_br_bits(br, ds->lt.len_bits);- lzh_br_consume(br, ds->lt.len_bits);- /* FALL THROUGH */- case ST_RD_LITERAL_2:- if (ds->lt.len_avail == 0) {- /* There is no bitlen. */- if (!lzh_br_read_ahead(strm, br,- ds->lt.len_bits)) {- if (last)- goto failed;/* Truncated data.*/- ds->state = ST_RD_LITERAL_2;- return (ARCHIVE_OK);- }- if (!lzh_make_fake_table(&(ds->lt),- lzh_br_bits(br, ds->lt.len_bits)))- goto failed;/* Invalid data */- lzh_br_consume(br, ds->lt.len_bits);- ds->state = ST_RD_POS_DATA_1;- break;- } else if (ds->lt.len_avail > ds->lt.len_size)- goto failed;/* Invalid data */- ds->loop = 0;- memset(ds->lt.freq, 0, sizeof(ds->lt.freq));- /* FALL THROUGH */- case ST_RD_LITERAL_3:- i = ds->loop;- while (i < ds->lt.len_avail) {- if (!lzh_br_read_ahead(strm, br,- ds->pt.max_bits)) {- if (last)- goto failed;/* Truncated data.*/- ds->loop = i;- ds->state = ST_RD_LITERAL_3;- return (ARCHIVE_OK);- }- rbits = lzh_br_bits(br, ds->pt.max_bits);- c = lzh_decode_huffman(&(ds->pt), rbits);- if (c > 2) {- /* Note: 'c' will never be more than- * eighteen since it's limited by- * PT_BITLEN_SIZE, which is being set- * to ds->pt.len_size through- * ds->literal_pt_len_size. */- lzh_br_consume(br, ds->pt.bitlen[c]);- c -= 2;- ds->lt.freq[c]++;- ds->lt.bitlen[i++] = c;- } else if (c == 0) {- lzh_br_consume(br, ds->pt.bitlen[c]);- ds->lt.bitlen[i++] = 0;- } else {- /* c == 1 or c == 2 */- int n = (c == 1)?4:9;- if (!lzh_br_read_ahead(strm, br,- ds->pt.bitlen[c] + n)) {- if (last) /* Truncated data. */- goto failed;- ds->loop = i;- ds->state = ST_RD_LITERAL_3;- return (ARCHIVE_OK);- }- lzh_br_consume(br, ds->pt.bitlen[c]);- c = lzh_br_bits(br, n);- lzh_br_consume(br, n);- c += (n == 4)?3:20;- if (i + c > ds->lt.len_avail)- goto failed;/* Invalid data */- memset(&(ds->lt.bitlen[i]), 0, c);- i += c;- }- }- if (i > ds->lt.len_avail ||- !lzh_make_huffman_table(&(ds->lt)))- goto failed;/* Invalid data */- /* FALL THROUGH */- case ST_RD_POS_DATA_1:- /*- * Read a position table compressed in huffman- * coding.- */- ds->pt.len_size = ds->pos_pt_len_size;- ds->pt.len_bits = ds->pos_pt_len_bits;- ds->reading_position = 1;- ds->state = ST_RD_PT_1;- break;- case ST_GET_LITERAL:- return (100);- }- }-failed:- return (ds->error = ARCHIVE_FAILED);-}--static int-lzh_decode_blocks(struct lzh_stream *strm, int last)-{- struct lzh_dec *ds = strm->ds;- struct lzh_br bre = ds->br;- struct huffman *lt = &(ds->lt);- struct huffman *pt = &(ds->pt);- unsigned char *w_buff = ds->w_buff;- unsigned char *lt_bitlen = lt->bitlen;- unsigned char *pt_bitlen = pt->bitlen;- int blocks_avail = ds->blocks_avail, c = 0;- int copy_len = ds->copy_len, copy_pos = ds->copy_pos;- int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;- int lt_max_bits = lt->max_bits, pt_max_bits = pt->max_bits;- int state = ds->state;-- for (;;) {- switch (state) {- case ST_GET_LITERAL:- for (;;) {- if (blocks_avail == 0) {- /* We have decoded all blocks.- * Let's handle next blocks. */- ds->state = ST_RD_BLOCK;- ds->br = bre;- ds->blocks_avail = 0;- ds->w_pos = w_pos;- ds->copy_pos = 0;- return (100);- }-- /* lzh_br_read_ahead() always try to fill the- * cache buffer up. In specific situation we- * are close to the end of the data, the cache- * buffer will not be full and thus we have to- * determine if the cache buffer has some bits- * as much as we need after lzh_br_read_ahead()- * failed. */- if (!lzh_br_read_ahead(strm, &bre,- lt_max_bits)) {- if (!last)- goto next_data;- /* Remaining bits are less than- * maximum bits(lt.max_bits) but maybe- * it still remains as much as we need,- * so we should try to use it with- * dummy bits. */- c = lzh_decode_huffman(lt,- lzh_br_bits_forced(&bre,- lt_max_bits));- lzh_br_consume(&bre, lt_bitlen[c]);- if (!lzh_br_has(&bre, 0))- goto failed;/* Over read. */- } else {- c = lzh_decode_huffman(lt,- lzh_br_bits(&bre, lt_max_bits));- lzh_br_consume(&bre, lt_bitlen[c]);- }- blocks_avail--;- if (c > UCHAR_MAX)- /* Current block is a match data. */- break;- /*- * 'c' is exactly a literal code.- */- /* Save a decoded code to reference it- * afterward. */- w_buff[w_pos] = c;- if (++w_pos >= w_size) {- w_pos = 0;- lzh_emit_window(strm, w_size);- goto next_data;- }- }- /* 'c' is the length of a match pattern we have- * already extracted, which has be stored in- * window(ds->w_buff). */- copy_len = c - (UCHAR_MAX + 1) + MINMATCH;- /* FALL THROUGH */- case ST_GET_POS_1:- /*- * Get a reference position. - */- if (!lzh_br_read_ahead(strm, &bre, pt_max_bits)) {- if (!last) {- state = ST_GET_POS_1;- ds->copy_len = copy_len;- goto next_data;- }- copy_pos = lzh_decode_huffman(pt,- lzh_br_bits_forced(&bre, pt_max_bits));- lzh_br_consume(&bre, pt_bitlen[copy_pos]);- if (!lzh_br_has(&bre, 0))- goto failed;/* Over read. */- } else {- copy_pos = lzh_decode_huffman(pt,- lzh_br_bits(&bre, pt_max_bits));- lzh_br_consume(&bre, pt_bitlen[copy_pos]);- }- /* FALL THROUGH */- case ST_GET_POS_2:- if (copy_pos > 1) {- /* We need an additional adjustment number to- * the position. */- int p = copy_pos - 1;- if (!lzh_br_read_ahead(strm, &bre, p)) {- if (last)- goto failed;/* Truncated data.*/- state = ST_GET_POS_2;- ds->copy_len = copy_len;- ds->copy_pos = copy_pos;- goto next_data;- }- copy_pos = (1 << p) + lzh_br_bits(&bre, p);- lzh_br_consume(&bre, p);- }- /* The position is actually a distance from the last- * code we had extracted and thus we have to convert- * it to a position of the window. */- copy_pos = (w_pos - copy_pos - 1) & w_mask;- /* FALL THROUGH */- case ST_COPY_DATA:- /*- * Copy `copy_len' bytes as extracted data from- * the window into the output buffer.- */- for (;;) {- int l;-- l = copy_len;- if (copy_pos > w_pos) {- if (l > w_size - copy_pos)- l = w_size - copy_pos;- } else {- if (l > w_size - w_pos)- l = w_size - w_pos;- }- if ((copy_pos + l < w_pos)- || (w_pos + l < copy_pos)) {- /* No overlap. */- memcpy(w_buff + w_pos,- w_buff + copy_pos, l);- } else {- const unsigned char *s;- unsigned char *d;- int li;-- d = w_buff + w_pos;- s = w_buff + copy_pos;- for (li = 0; li < l-1;) {- d[li] = s[li];li++;- d[li] = s[li];li++;- }- if (li < l)- d[li] = s[li];- }- w_pos += l;- if (w_pos == w_size) {- w_pos = 0;- lzh_emit_window(strm, w_size);- if (copy_len <= l)- state = ST_GET_LITERAL;- else {- state = ST_COPY_DATA;- ds->copy_len = copy_len - l;- ds->copy_pos =- (copy_pos + l) & w_mask;- }- goto next_data;- }- if (copy_len <= l)- /* A copy of current pattern ended. */- break;- copy_len -= l;- copy_pos = (copy_pos + l) & w_mask;- }- state = ST_GET_LITERAL;- break;- }- }-failed:- return (ds->error = ARCHIVE_FAILED);-next_data:- ds->br = bre;- ds->blocks_avail = blocks_avail;- ds->state = state;- ds->w_pos = w_pos;- return (ARCHIVE_OK);-}--static int-lzh_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)-{- int bits;-- if (hf->bitlen == NULL) {- hf->bitlen = malloc(len_size * sizeof(hf->bitlen[0]));- if (hf->bitlen == NULL)- return (ARCHIVE_FATAL);- }- if (hf->tbl == NULL) {- if (tbl_bits < HTBL_BITS)- bits = tbl_bits;- else- bits = HTBL_BITS;- hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0]));- if (hf->tbl == NULL)- return (ARCHIVE_FATAL);- }- if (hf->tree == NULL && tbl_bits > HTBL_BITS) {- hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4);- hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0]));- if (hf->tree == NULL)- return (ARCHIVE_FATAL);- }- hf->len_size = (int)len_size;- hf->tbl_bits = tbl_bits;- return (ARCHIVE_OK);-}--static void-lzh_huffman_free(struct huffman *hf)-{- free(hf->bitlen);- free(hf->tbl);- free(hf->tree);-}--static const char bitlen_tbl[0x400] = {- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,- 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,- 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,- 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 16, 0-};-static int-lzh_read_pt_bitlen(struct lzh_stream *strm, int start, int end)-{- struct lzh_dec *ds = strm->ds;- struct lzh_br *br = &(ds->br);- int c, i;-- for (i = start; i < end; ) {- /*- * bit pattern the number we need- * 000 -> 0- * 001 -> 1- * 010 -> 2- * ...- * 110 -> 6- * 1110 -> 7- * 11110 -> 8- * ...- * 1111111111110 -> 16- */- if (!lzh_br_read_ahead(strm, br, 3))- return (i);- if ((c = lzh_br_bits(br, 3)) == 7) {- if (!lzh_br_read_ahead(strm, br, 13))- return (i);- c = bitlen_tbl[lzh_br_bits(br, 13) & 0x3FF];- if (c)- lzh_br_consume(br, c - 3);- else- return (-1);/* Invalid data. */- } else- lzh_br_consume(br, 3);- ds->pt.bitlen[i++] = c;- ds->pt.freq[c]++;- }- return (i);-}--static int-lzh_make_fake_table(struct huffman *hf, uint16_t c)-{- if (c >= hf->len_size)- return (0);- hf->tbl[0] = c;- hf->max_bits = 0;- hf->shift_bits = 0;- hf->bitlen[hf->tbl[0]] = 0;- return (1);-}--/*- * Make a huffman coding table.- */-static int-lzh_make_huffman_table(struct huffman *hf)-{- uint16_t *tbl;- const unsigned char *bitlen;- int bitptn[17], weight[17];- int i, maxbits = 0, ptn, tbl_size, w;- int diffbits, len_avail;-- /*- * Initialize bit patterns.- */- ptn = 0;- for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {- bitptn[i] = ptn;- weight[i] = w;- if (hf->freq[i]) {- ptn += hf->freq[i] * w;- maxbits = i;- }- }- if (ptn != 0x10000 || maxbits > hf->tbl_bits)- return (0);/* Invalid */-- hf->max_bits = maxbits;-- /*- * Cut out extra bits which we won't house in the table.- * This preparation reduces the same calculation in the for-loop- * making the table.- */- if (maxbits < 16) {- int ebits = 16 - maxbits;- for (i = 1; i <= maxbits; i++) {- bitptn[i] >>= ebits;- weight[i] >>= ebits;- }- }- if (maxbits > HTBL_BITS) {- unsigned htbl_max;- uint16_t *p;-- diffbits = maxbits - HTBL_BITS;- for (i = 1; i <= HTBL_BITS; i++) {- bitptn[i] >>= diffbits;- weight[i] >>= diffbits;- }- htbl_max = bitptn[HTBL_BITS] +- weight[HTBL_BITS] * hf->freq[HTBL_BITS];- p = &(hf->tbl[htbl_max]);- while (p < &hf->tbl[1U<<HTBL_BITS])- *p++ = 0;- } else- diffbits = 0;- hf->shift_bits = diffbits;-- /*- * Make the table.- */- tbl_size = 1 << HTBL_BITS;- tbl = hf->tbl;- bitlen = hf->bitlen;- len_avail = hf->len_avail;- hf->tree_used = 0;- for (i = 0; i < len_avail; i++) {- uint16_t *p;- int len, cnt;- uint16_t bit;- int extlen;- struct htree_t *ht;-- if (bitlen[i] == 0)- continue;- /* Get a bit pattern */- len = bitlen[i];- ptn = bitptn[len];- cnt = weight[len];- if (len <= HTBL_BITS) {- /* Calculate next bit pattern */- if ((bitptn[len] = ptn + cnt) > tbl_size)- return (0);/* Invalid */- /* Update the table */- p = &(tbl[ptn]);- if (cnt > 7) {- uint16_t *pc;-- cnt -= 8;- pc = &p[cnt];- pc[0] = (uint16_t)i;- pc[1] = (uint16_t)i;- pc[2] = (uint16_t)i;- pc[3] = (uint16_t)i;- pc[4] = (uint16_t)i;- pc[5] = (uint16_t)i;- pc[6] = (uint16_t)i;- pc[7] = (uint16_t)i;- if (cnt > 7) {- cnt -= 8;- memcpy(&p[cnt], pc,- 8 * sizeof(uint16_t));- pc = &p[cnt];- while (cnt > 15) {- cnt -= 16;- memcpy(&p[cnt], pc,- 16 * sizeof(uint16_t));- }- }- if (cnt)- memcpy(p, pc, cnt * sizeof(uint16_t));- } else {- while (cnt > 1) {- p[--cnt] = (uint16_t)i;- p[--cnt] = (uint16_t)i;- }- if (cnt)- p[--cnt] = (uint16_t)i;- }- continue;- }-- /*- * A bit length is too big to be housed to a direct table,- * so we use a tree model for its extra bits.- */- bitptn[len] = ptn + cnt;- bit = 1U << (diffbits -1);- extlen = len - HTBL_BITS;- - p = &(tbl[ptn >> diffbits]);- if (*p == 0) {- *p = len_avail + hf->tree_used;- ht = &(hf->tree[hf->tree_used++]);- if (hf->tree_used > hf->tree_avail)- return (0);/* Invalid */- ht->left = 0;- ht->right = 0;- } else {- if (*p < len_avail ||- *p >= (len_avail + hf->tree_used))- return (0);/* Invalid */- ht = &(hf->tree[*p - len_avail]);- }- while (--extlen > 0) {- if (ptn & bit) {- if (ht->left < len_avail) {- ht->left = len_avail + hf->tree_used;- ht = &(hf->tree[hf->tree_used++]);- if (hf->tree_used > hf->tree_avail)- return (0);/* Invalid */- ht->left = 0;- ht->right = 0;- } else {- ht = &(hf->tree[ht->left - len_avail]);- }- } else {- if (ht->right < len_avail) {- ht->right = len_avail + hf->tree_used;- ht = &(hf->tree[hf->tree_used++]);- if (hf->tree_used > hf->tree_avail)- return (0);/* Invalid */- ht->left = 0;- ht->right = 0;- } else {- ht = &(hf->tree[ht->right - len_avail]);- }- }- bit >>= 1;- }- if (ptn & bit) {- if (ht->left != 0)- return (0);/* Invalid */- ht->left = (uint16_t)i;- } else {- if (ht->right != 0)- return (0);/* Invalid */- ht->right = (uint16_t)i;- }- }- return (1);-}--static int-lzh_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c)-{- struct htree_t *ht;- int extlen;-- ht = hf->tree;- extlen = hf->shift_bits;- while (c >= hf->len_avail) {- c -= hf->len_avail;- if (extlen-- <= 0 || c >= hf->tree_used)- return (0);- if (rbits & (1U << extlen))- c = ht[c].left;- else- c = ht[c].right;- }- return (c);-}--static inline int-lzh_decode_huffman(struct huffman *hf, unsigned rbits)-{- int c;- /*- * At first search an index table for a bit pattern.- * If it fails, search a huffman tree for.- */- c = hf->tbl[rbits >> hf->shift_bits];- if (c < hf->len_avail || hf->len_avail == 0)- return (c);- /* This bit pattern needs to be found out at a huffman tree. */- return (lzh_decode_huffman_tree(hf, rbits, c));-}-
− c/archive_read_support_format_mtree.c
@@ -1,2156 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2008 Joerg Sonnenberger- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 201165 2009-12-29 05:52:13Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#include <stddef.h>-/* #include <stdint.h> */ /* See archive_platform.h */-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_CTYPE_H-#include <ctype.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_private.h"-#include "archive_private.h"-#include "archive_rb.h"-#include "archive_read_private.h"-#include "archive_string.h"-#include "archive_pack_dev.h"--#ifndef O_BINARY-#define O_BINARY 0-#endif-#ifndef O_CLOEXEC-#define O_CLOEXEC 0-#endif--#define MTREE_HAS_DEVICE 0x0001-#define MTREE_HAS_FFLAGS 0x0002-#define MTREE_HAS_GID 0x0004-#define MTREE_HAS_GNAME 0x0008-#define MTREE_HAS_MTIME 0x0010-#define MTREE_HAS_NLINK 0x0020-#define MTREE_HAS_PERM 0x0040-#define MTREE_HAS_SIZE 0x0080-#define MTREE_HAS_TYPE 0x0100-#define MTREE_HAS_UID 0x0200-#define MTREE_HAS_UNAME 0x0400--#define MTREE_HAS_OPTIONAL 0x0800-#define MTREE_HAS_NOCHANGE 0x1000 /* FreeBSD specific */--#define MAX_LINE_LEN (1024 * 1024)--struct mtree_option {- struct mtree_option *next;- char *value;-};--struct mtree_entry {- struct archive_rb_node rbnode;- struct mtree_entry *next_dup;- struct mtree_entry *next;- struct mtree_option *options;- char *name;- char full;- char used;-};--struct mtree {- struct archive_string line;- size_t buffsize;- char *buff;- int64_t offset;- int fd;- int archive_format;- const char *archive_format_name;- struct mtree_entry *entries;- struct mtree_entry *this_entry;- struct archive_rb_tree entry_rbtree;- struct archive_string current_dir;- struct archive_string contents_name;-- struct archive_entry_linkresolver *resolver;- struct archive_rb_tree rbtree;-- int64_t cur_size;- char checkfs;-};--static int bid_keycmp(const char *, const char *, ssize_t);-static int cleanup(struct archive_read *);-static int detect_form(struct archive_read *, int *);-static int mtree_bid(struct archive_read *, int);-static int parse_file(struct archive_read *, struct archive_entry *,- struct mtree *, struct mtree_entry *, int *);-static void parse_escapes(char *, struct mtree_entry *);-static int parse_line(struct archive_read *, struct archive_entry *,- struct mtree *, struct mtree_entry *, int *);-static int parse_keyword(struct archive_read *, struct mtree *,- struct archive_entry *, struct mtree_option *, int *);-static int read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset);-static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t);-static int skip(struct archive_read *a);-static int read_header(struct archive_read *,- struct archive_entry *);-static int64_t mtree_atol(char **, int base);-#ifndef HAVE_STRNLEN-static size_t mtree_strnlen(const char *, size_t);-#endif--/*- * There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them- * here. TODO: Move this to configure time, but be careful- * about cross-compile environments.- */-static int64_t-get_time_t_max(void)-{-#if defined(TIME_T_MAX)- return TIME_T_MAX;-#else- /* ISO C allows time_t to be a floating-point type,- but POSIX requires an integer type. The following- should work on any system that follows the POSIX- conventions. */- if (((time_t)0) < ((time_t)-1)) {- /* Time_t is unsigned */- return (~(time_t)0);- } else {- /* Time_t is signed. */- /* Assume it's the same as int64_t or int32_t */- if (sizeof(time_t) == sizeof(int64_t)) {- return (time_t)INT64_MAX;- } else {- return (time_t)INT32_MAX;- }- }-#endif-}--static int64_t-get_time_t_min(void)-{-#if defined(TIME_T_MIN)- return TIME_T_MIN;-#else- if (((time_t)0) < ((time_t)-1)) {- /* Time_t is unsigned */- return (time_t)0;- } else {- /* Time_t is signed. */- if (sizeof(time_t) == sizeof(int64_t)) {- return (time_t)INT64_MIN;- } else {- return (time_t)INT32_MIN;- }- }-#endif-}--#ifdef HAVE_STRNLEN-#define mtree_strnlen(a,b) strnlen(a,b)-#else-static size_t-mtree_strnlen(const char *p, size_t maxlen)-{- size_t i;-- for (i = 0; i <= maxlen; i++) {- if (p[i] == 0)- break;- }- if (i > maxlen)- return (-1);/* invalid */- return (i);-}-#endif--static int-archive_read_format_mtree_options(struct archive_read *a,- const char *key, const char *val)-{- struct mtree *mtree;-- mtree = (struct mtree *)(a->format->data);- if (strcmp(key, "checkfs") == 0) {- /* Allows to read information missing from the mtree from the file system */- if (val == NULL || val[0] == 0) {- mtree->checkfs = 0;- } else {- mtree->checkfs = 1;- }- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static void-free_options(struct mtree_option *head)-{- struct mtree_option *next;-- for (; head != NULL; head = next) {- next = head->next;- free(head->value);- free(head);- }-}--static int-mtree_cmp_node(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- const struct mtree_entry *e1 = (const struct mtree_entry *)n1;- const struct mtree_entry *e2 = (const struct mtree_entry *)n2;-- return (strcmp(e1->name, e2->name));-}--static int-mtree_cmp_key(const struct archive_rb_node *n, const void *key)-{- const struct mtree_entry *e = (const struct mtree_entry *)n;-- return (strcmp(e->name, key));-}--int-archive_read_support_format_mtree(struct archive *_a)-{- static const struct archive_rb_tree_ops rb_ops = {- mtree_cmp_node, mtree_cmp_key,- };- struct archive_read *a = (struct archive_read *)_a;- struct mtree *mtree;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_mtree");-- mtree = (struct mtree *)calloc(1, sizeof(*mtree));- if (mtree == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate mtree data");- return (ARCHIVE_FATAL);- }- mtree->checkfs = 0;- mtree->fd = -1;-- __archive_rb_tree_init(&mtree->rbtree, &rb_ops);-- r = __archive_read_register_format(a, mtree, "mtree",- mtree_bid, archive_read_format_mtree_options, read_header, read_data, skip, NULL, cleanup, NULL, NULL);-- if (r != ARCHIVE_OK)- free(mtree);- return (ARCHIVE_OK);-}--static int-cleanup(struct archive_read *a)-{- struct mtree *mtree;- struct mtree_entry *p, *q;-- mtree = (struct mtree *)(a->format->data);-- p = mtree->entries;- while (p != NULL) {- q = p->next;- free(p->name);- free_options(p->options);- free(p);- p = q;- }- archive_string_free(&mtree->line);- archive_string_free(&mtree->current_dir);- archive_string_free(&mtree->contents_name);- archive_entry_linkresolver_free(mtree->resolver);-- free(mtree->buff);- free(mtree);- (a->format->data) = NULL;- return (ARCHIVE_OK);-}--static ssize_t-get_line_size(const char *b, ssize_t avail, ssize_t *nlsize)-{- ssize_t len;-- len = 0;- while (len < avail) {- switch (*b) {- case '\0':/* Non-ascii character or control character. */- if (nlsize != NULL)- *nlsize = 0;- return (-1);- case '\r':- if (avail-len > 1 && b[1] == '\n') {- if (nlsize != NULL)- *nlsize = 2;- return (len+2);- }- /* FALL THROUGH */- case '\n':- if (nlsize != NULL)- *nlsize = 1;- return (len+1);- default:- b++;- len++;- break;- }- }- if (nlsize != NULL)- *nlsize = 0;- return (avail);-}--/*- * <---------------- ravail --------------------->- * <-- diff ------> <--- avail ----------------->- * <---- len ----------->- * | Previous lines | line being parsed nl extra |- * ^- * b- *- */-static ssize_t-next_line(struct archive_read *a,- const char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl)-{- ssize_t len;- int quit;- - quit = 0;- if (*avail == 0) {- *nl = 0;- len = 0;- } else- len = get_line_size(*b, *avail, nl);- /*- * Read bytes more while it does not reach the end of line.- */- while (*nl == 0 && len == *avail && !quit) {- ssize_t diff = *ravail - *avail;- size_t nbytes_req = (*ravail+1023) & ~1023U;- ssize_t tested;-- /*- * Place an arbitrary limit on the line length.- * mtree is almost free-form input and without line length limits,- * it can consume a lot of memory.- */- if (len >= MAX_LINE_LEN)- return (-1);-- /* Increase reading bytes if it is not enough to at least- * new two lines. */- if (nbytes_req < (size_t)*ravail + 160)- nbytes_req <<= 1;-- *b = __archive_read_ahead(a, nbytes_req, avail);- if (*b == NULL) {- if (*ravail >= *avail)- return (0);- /* Reading bytes reaches the end of file. */- *b = __archive_read_ahead(a, *avail, avail);- quit = 1;- }- *ravail = *avail;- *b += diff;- *avail -= diff;- tested = len;/* Skip some bytes we already determined. */- len = get_line_size(*b + len, *avail - len, nl);- if (len >= 0)- len += tested;- }- return (len);-}--/*- * Compare characters with a mtree keyword.- * Returns the length of a mtree keyword if matched.- * Returns 0 if not matched.- */-static int-bid_keycmp(const char *p, const char *key, ssize_t len)-{- int match_len = 0;-- while (len > 0 && *p && *key) {- if (*p == *key) {- --len;- ++p;- ++key;- ++match_len;- continue;- }- return (0);/* Not match */- }- if (*key != '\0')- return (0);/* Not match */-- /* A following character should be specified characters */- if (p[0] == '=' || p[0] == ' ' || p[0] == '\t' ||- p[0] == '\n' || p[0] == '\r' ||- (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r')))- return (match_len);- return (0);/* Not match */-}--/*- * Test whether the characters 'p' has is mtree keyword.- * Returns the length of a detected keyword.- * Returns 0 if any keywords were not found.- */-static int-bid_keyword(const char *p, ssize_t len)-{- static const char * const keys_c[] = {- "content", "contents", "cksum", NULL- };- static const char * const keys_df[] = {- "device", "flags", NULL- };- static const char * const keys_g[] = {- "gid", "gname", NULL- };- static const char * const keys_il[] = {- "ignore", "inode", "link", NULL- };- static const char * const keys_m[] = {- "md5", "md5digest", "mode", NULL- };- static const char * const keys_no[] = {- "nlink", "nochange", "optional", NULL- };- static const char * const keys_r[] = {- "resdevice", "rmd160", "rmd160digest", NULL- };- static const char * const keys_s[] = {- "sha1", "sha1digest",- "sha256", "sha256digest",- "sha384", "sha384digest",- "sha512", "sha512digest",- "size", NULL- };- static const char * const keys_t[] = {- "tags", "time", "type", NULL- };- static const char * const keys_u[] = {- "uid", "uname", NULL- };- const char * const *keys;- int i;-- switch (*p) {- case 'c': keys = keys_c; break;- case 'd': case 'f': keys = keys_df; break;- case 'g': keys = keys_g; break;- case 'i': case 'l': keys = keys_il; break;- case 'm': keys = keys_m; break;- case 'n': case 'o': keys = keys_no; break;- case 'r': keys = keys_r; break;- case 's': keys = keys_s; break;- case 't': keys = keys_t; break;- case 'u': keys = keys_u; break;- default: return (0);/* Unknown key */- }-- for (i = 0; keys[i] != NULL; i++) {- int l = bid_keycmp(p, keys[i], len);- if (l > 0)- return (l);- }- return (0);/* Unknown key */-}--/*- * Test whether there is a set of mtree keywords.- * Returns the number of keyword.- * Returns -1 if we got incorrect sequence.- * This function expects a set of "<space characters>keyword=value".- * When "unset" is specified, expects a set of "<space characters>keyword".- */-static int-bid_keyword_list(const char *p, ssize_t len, int unset, int last_is_path)-{- int l;- int keycnt = 0;-- while (len > 0 && *p) {- int blank = 0;-- /* Test whether there are blank characters in the line. */- while (len >0 && (*p == ' ' || *p == '\t')) {- ++p;- --len;- blank = 1;- }- if (*p == '\n' || *p == '\r')- break;- if (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r'))- break;- if (!blank && !last_is_path) /* No blank character. */- return (-1);- if (last_is_path && len == 0)- return (keycnt);-- if (unset) {- l = bid_keycmp(p, "all", len);- if (l > 0)- return (1);- }- /* Test whether there is a correct key in the line. */- l = bid_keyword(p, len);- if (l == 0)- return (-1);/* Unknown keyword was found. */- p += l;- len -= l;- keycnt++;-- /* Skip value */- if (*p == '=') {- int value = 0;- ++p;- --len;- while (len > 0 && *p != ' ' && *p != '\t') {- ++p;- --len;- value = 1;- }- /* A keyword should have a its value unless- * "/unset" operation. */ - if (!unset && value == 0)- return (-1);- }- }- return (keycnt);-}--static int-bid_entry(const char *p, ssize_t len, ssize_t nl, int *last_is_path)-{- int f = 0;- static const unsigned char safe_char[256] = {- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */- /* !"$%&'()*+,-./ EXCLUSION:( )(#) */- 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */- /* 0123456789:;<>? EXCLUSION:(=) */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */- /* @ABCDEFGHIJKLMNO */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */- /* PQRSTUVWXYZ[\]^_ */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */- /* `abcdefghijklmno */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */- /* pqrstuvwxyz{|}~ */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */- };- ssize_t ll;- const char *pp = p;- const char * const pp_end = pp + len;-- *last_is_path = 0;- /*- * Skip the path-name which is quoted.- */- for (;pp < pp_end; ++pp) {- if (!safe_char[*(const unsigned char *)pp]) {- if (*pp != ' ' && *pp != '\t' && *pp != '\r'- && *pp != '\n')- f = 0;- break;- }- f = 1;- }- ll = pp_end - pp;-- /* If a path-name was not found at the first, try to check- * a mtree format(a.k.a form D) ``NetBSD's mtree -D'' creates,- * which places the path-name at the last. */- if (f == 0) {- const char *pb = p + len - nl;- int name_len = 0;- int slash;-- /* The form D accepts only a single line for an entry. */- if (pb-2 >= p &&- pb[-1] == '\\' && (pb[-2] == ' ' || pb[-2] == '\t'))- return (-1);- if (pb-1 >= p && pb[-1] == '\\')- return (-1);-- slash = 0;- while (p <= --pb && *pb != ' ' && *pb != '\t') {- if (!safe_char[*(const unsigned char *)pb])- return (-1);- name_len++;- /* The pathname should have a slash in this- * format. */- if (*pb == '/')- slash = 1;- }- if (name_len == 0 || slash == 0)- return (-1);- /* If '/' is placed at the first in this field, this is not- * a valid filename. */- if (pb[1] == '/')- return (-1);- ll = len - nl - name_len;- pp = p;- *last_is_path = 1;- }-- return (bid_keyword_list(pp, ll, 0, *last_is_path));-}--#define MAX_BID_ENTRY 3--static int-mtree_bid(struct archive_read *a, int best_bid)-{- const char *signature = "#mtree";- const char *p;-- (void)best_bid; /* UNUSED */-- /* Now let's look at the actual header and see if it matches. */- p = __archive_read_ahead(a, strlen(signature), NULL);- if (p == NULL)- return (-1);-- if (memcmp(p, signature, strlen(signature)) == 0)- return (8 * (int)strlen(signature));-- /*- * There is not a mtree signature. Let's try to detect mtree format.- */- return (detect_form(a, NULL));-}--static int-detect_form(struct archive_read *a, int *is_form_d)-{- const char *p;- ssize_t avail, ravail;- ssize_t len, nl;- int entry_cnt = 0, multiline = 0;- int form_D = 0;/* The archive is generated by `NetBSD mtree -D'- * (In this source we call it `form D') . */-- if (is_form_d != NULL)- *is_form_d = 0;- p = __archive_read_ahead(a, 1, &avail);- if (p == NULL)- return (-1);- ravail = avail;- for (;;) {- len = next_line(a, &p, &avail, &ravail, &nl);- /* The terminal character of the line should be- * a new line character, '\r\n' or '\n'. */- if (len <= 0 || nl == 0)- break;- if (!multiline) {- /* Leading whitespace is never significant,- * ignore it. */- while (len > 0 && (*p == ' ' || *p == '\t')) {- ++p;- --avail;- --len;- }- /* Skip comment or empty line. */ - if (p[0] == '#' || p[0] == '\n' || p[0] == '\r') {- p += len;- avail -= len;- continue;- }- } else {- /* A continuance line; the terminal- * character of previous line was '\' character. */- if (bid_keyword_list(p, len, 0, 0) <= 0)- break;- if (p[len-nl-1] != '\\') {- if (multiline == 1 &&- ++entry_cnt >= MAX_BID_ENTRY)- break;- multiline = 0;- }- p += len;- avail -= len;- continue;- }- if (p[0] != '/') {- int last_is_path, keywords;-- keywords = bid_entry(p, len, nl, &last_is_path);- if (keywords >= 0) {- if (form_D == 0) {- if (last_is_path)- form_D = 1;- else if (keywords > 0)- /* This line is not `form D'. */- form_D = -1;- } else if (form_D == 1) {- if (!last_is_path && keywords > 0)- /* This this is not `form D'- * and We cannot accept mixed- * format. */- break;- }- if (!last_is_path && p[len-nl-1] == '\\')- /* This line continues. */- multiline = 1;- else {- /* We've got plenty of correct lines- * to assume that this file is a mtree- * format. */- if (++entry_cnt >= MAX_BID_ENTRY)- break;- }- } else- break;- } else if (len > 4 && strncmp(p, "/set", 4) == 0) {- if (bid_keyword_list(p+4, len-4, 0, 0) <= 0)- break;- /* This line continues. */- if (p[len-nl-1] == '\\')- multiline = 2;- } else if (len > 6 && strncmp(p, "/unset", 6) == 0) {- if (bid_keyword_list(p+6, len-6, 1, 0) <= 0)- break;- /* This line continues. */- if (p[len-nl-1] == '\\')- multiline = 2;- } else- break;-- /* Test next line. */- p += len;- avail -= len;- }- if (entry_cnt >= MAX_BID_ENTRY || (entry_cnt > 0 && len == 0)) {- if (is_form_d != NULL) {- if (form_D == 1)- *is_form_d = 1;- }- return (32);- }-- return (0);-}--/*- * The extended mtree format permits multiple lines specifying- * attributes for each file. For those entries, only the last line- * is actually used. Practically speaking, that means we have- * to read the entire mtree file into memory up front.- *- * The parsing is done in two steps. First, it is decided if a line- * changes the global defaults and if it is, processed accordingly.- * Otherwise, the options of the line are merged with the current- * global options.- */-static int-add_option(struct archive_read *a, struct mtree_option **global,- const char *value, size_t len)-{- struct mtree_option *opt;-- if ((opt = malloc(sizeof(*opt))) == NULL) {- archive_set_error(&a->archive, errno, "Can't allocate memory");- return (ARCHIVE_FATAL);- }- if ((opt->value = malloc(len + 1)) == NULL) {- free(opt);- archive_set_error(&a->archive, errno, "Can't allocate memory");- return (ARCHIVE_FATAL);- }- memcpy(opt->value, value, len);- opt->value[len] = '\0';- opt->next = *global;- *global = opt;- return (ARCHIVE_OK);-}--static void-remove_option(struct mtree_option **global, const char *value, size_t len)-{- struct mtree_option *iter, *last;-- last = NULL;- for (iter = *global; iter != NULL; last = iter, iter = iter->next) {- if (strncmp(iter->value, value, len) == 0 &&- (iter->value[len] == '\0' ||- iter->value[len] == '='))- break;- }- if (iter == NULL)- return;- if (last == NULL)- *global = iter->next;- else- last->next = iter->next;-- free(iter->value);- free(iter);-}--static int-process_global_set(struct archive_read *a,- struct mtree_option **global, const char *line)-{- const char *next, *eq;- size_t len;- int r;-- line += 4;- for (;;) {- next = line + strspn(line, " \t\r\n");- if (*next == '\0')- return (ARCHIVE_OK);- line = next;- next = line + strcspn(line, " \t\r\n");- eq = strchr(line, '=');- if (eq > next)- len = next - line;- else- len = eq - line;-- remove_option(global, line, len);- r = add_option(a, global, line, next - line);- if (r != ARCHIVE_OK)- return (r);- line = next;- }-}--static int-process_global_unset(struct archive_read *a,- struct mtree_option **global, const char *line)-{- const char *next;- size_t len;-- line += 6;- if (strchr(line, '=') != NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "/unset shall not contain `='");- return ARCHIVE_FATAL;- }-- for (;;) {- next = line + strspn(line, " \t\r\n");- if (*next == '\0')- return (ARCHIVE_OK);- line = next;- len = strcspn(line, " \t\r\n");-- if (len == 3 && strncmp(line, "all", 3) == 0) {- free_options(*global);- *global = NULL;- } else {- remove_option(global, line, len);- }-- line += len;- }-}--static int-process_add_entry(struct archive_read *a, struct mtree *mtree,- struct mtree_option **global, const char *line, ssize_t line_len,- struct mtree_entry **last_entry, int is_form_d)-{- struct mtree_entry *entry;- struct mtree_option *iter;- const char *next, *eq, *name, *end;- size_t name_len, len;- int r, i;-- if ((entry = malloc(sizeof(*entry))) == NULL) {- archive_set_error(&a->archive, errno, "Can't allocate memory");- return (ARCHIVE_FATAL);- }- entry->next = NULL;- entry->options = NULL;- entry->name = NULL;- entry->used = 0;- entry->full = 0;-- /* Add this entry to list. */- if (*last_entry == NULL)- mtree->entries = entry;- else- (*last_entry)->next = entry;- *last_entry = entry;-- if (is_form_d) {- /* Filename is last item on line. */- /* Adjust line_len to trim trailing whitespace */- while (line_len > 0) {- char last_character = line[line_len - 1];- if (last_character == '\r'- || last_character == '\n'- || last_character == '\t'- || last_character == ' ') {- line_len--;- } else {- break;- }- }- /* Name starts after the last whitespace separator */- name = line;- for (i = 0; i < line_len; i++) {- if (line[i] == '\r'- || line[i] == '\n'- || line[i] == '\t'- || line[i] == ' ') {- name = line + i + 1;- }- }- name_len = line + line_len - name;- end = name;- } else {- /* Filename is first item on line */- name_len = strcspn(line, " \t\r\n");- name = line;- line += name_len;- end = line + line_len;- }- /* name/name_len is the name within the line. */- /* line..end brackets the entire line except the name */-- if ((entry->name = malloc(name_len + 1)) == NULL) {- archive_set_error(&a->archive, errno, "Can't allocate memory");- return (ARCHIVE_FATAL);- }-- memcpy(entry->name, name, name_len);- entry->name[name_len] = '\0';- parse_escapes(entry->name, entry);-- entry->next_dup = NULL;- if (entry->full) {- if (!__archive_rb_tree_insert_node(&mtree->rbtree, &entry->rbnode)) {- struct mtree_entry *alt;- alt = (struct mtree_entry *)__archive_rb_tree_find_node(- &mtree->rbtree, entry->name);- if (alt != NULL) {- while (alt->next_dup)- alt = alt->next_dup;- alt->next_dup = entry;- }- }- }-- for (iter = *global; iter != NULL; iter = iter->next) {- r = add_option(a, &entry->options, iter->value,- strlen(iter->value));- if (r != ARCHIVE_OK)- return (r);- }-- for (;;) {- next = line + strspn(line, " \t\r\n");- if (*next == '\0')- return (ARCHIVE_OK);- if (next >= end)- return (ARCHIVE_OK);- line = next;- next = line + strcspn(line, " \t\r\n");- eq = strchr(line, '=');- if (eq == NULL || eq > next)- len = next - line;- else- len = eq - line;-- remove_option(&entry->options, line, len);- r = add_option(a, &entry->options, line, next - line);- if (r != ARCHIVE_OK)- return (r);- line = next;- }-}--static int-read_mtree(struct archive_read *a, struct mtree *mtree)-{- ssize_t len;- uintmax_t counter;- char *p, *s;- struct mtree_option *global;- struct mtree_entry *last_entry;- int r, is_form_d;-- mtree->archive_format = ARCHIVE_FORMAT_MTREE;- mtree->archive_format_name = "mtree";-- global = NULL;- last_entry = NULL;-- (void)detect_form(a, &is_form_d);-- for (counter = 1; ; ++counter) {- r = ARCHIVE_OK;- len = readline(a, mtree, &p, 65536);- if (len == 0) {- mtree->this_entry = mtree->entries;- free_options(global);- return (ARCHIVE_OK);- }- if (len < 0) {- free_options(global);- return ((int)len);- }- /* Leading whitespace is never significant, ignore it. */- while (*p == ' ' || *p == '\t') {- ++p;- --len;- }- /* Skip content lines and blank lines. */- if (*p == '#')- continue;- if (*p == '\r' || *p == '\n' || *p == '\0')- continue;- /* Non-printable characters are not allowed */- for (s = p;s < p + len - 1; s++) {- if (!isprint((unsigned char)*s) && *s != '\t') {- r = ARCHIVE_FATAL;- break;- }- }- if (r != ARCHIVE_OK)- break;- if (*p != '/') {- r = process_add_entry(a, mtree, &global, p, len,- &last_entry, is_form_d);- } else if (len > 4 && strncmp(p, "/set", 4) == 0) {- if (p[4] != ' ' && p[4] != '\t')- break;- r = process_global_set(a, &global, p);- } else if (len > 6 && strncmp(p, "/unset", 6) == 0) {- if (p[6] != ' ' && p[6] != '\t')- break;- r = process_global_unset(a, &global, p);- } else- break;-- if (r != ARCHIVE_OK) {- free_options(global);- return r;- }- }-- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't parse line %ju", counter);- free_options(global);- return (ARCHIVE_FATAL);-}--/*- * Read in the entire mtree file into memory on the first request.- * Then use the next unused file to satisfy each header request.- */-static int-read_header(struct archive_read *a, struct archive_entry *entry)-{- struct mtree *mtree;- char *p;- int r, use_next;-- mtree = (struct mtree *)(a->format->data);-- if (mtree->fd >= 0) {- close(mtree->fd);- mtree->fd = -1;- }-- if (mtree->entries == NULL) {- mtree->resolver = archive_entry_linkresolver_new();- if (mtree->resolver == NULL)- return ARCHIVE_FATAL;- archive_entry_linkresolver_set_strategy(mtree->resolver,- ARCHIVE_FORMAT_MTREE);- r = read_mtree(a, mtree);- if (r != ARCHIVE_OK)- return (r);- }-- a->archive.archive_format = mtree->archive_format;- a->archive.archive_format_name = mtree->archive_format_name;-- for (;;) {- if (mtree->this_entry == NULL)- return (ARCHIVE_EOF);- if (strcmp(mtree->this_entry->name, "..") == 0) {- mtree->this_entry->used = 1;- if (archive_strlen(&mtree->current_dir) > 0) {- /* Roll back current path. */- p = mtree->current_dir.s- + mtree->current_dir.length - 1;- while (p >= mtree->current_dir.s && *p != '/')- --p;- if (p >= mtree->current_dir.s)- --p;- mtree->current_dir.length- = p - mtree->current_dir.s + 1;- }- }- if (!mtree->this_entry->used) {- use_next = 0;- r = parse_file(a, entry, mtree, mtree->this_entry,- &use_next);- if (use_next == 0)- return (r);- }- mtree->this_entry = mtree->this_entry->next;- }-}--/*- * A single file can have multiple lines contribute specifications.- * Parse as many lines as necessary, then pull additional information- * from a backing file on disk as necessary.- */-static int-parse_file(struct archive_read *a, struct archive_entry *entry,- struct mtree *mtree, struct mtree_entry *mentry, int *use_next)-{- const char *path;- struct stat st_storage, *st;- struct mtree_entry *mp;- struct archive_entry *sparse_entry;- int r = ARCHIVE_OK, r1, parsed_kws;-- mentry->used = 1;-- /* Initialize reasonable defaults. */- archive_entry_set_filetype(entry, AE_IFREG);- archive_entry_set_size(entry, 0);- archive_string_empty(&mtree->contents_name);-- /* Parse options from this line. */- parsed_kws = 0;- r = parse_line(a, entry, mtree, mentry, &parsed_kws);-- if (mentry->full) {- archive_entry_copy_pathname(entry, mentry->name);- /*- * "Full" entries are allowed to have multiple lines- * and those lines aren't required to be adjacent. We- * don't support multiple lines for "relative" entries- * nor do we make any attempt to merge data from- * separate "relative" and "full" entries. (Merging- * "relative" and "full" entries would require dealing- * with pathname canonicalization, which is a very- * tricky subject.)- */- mp = (struct mtree_entry *)__archive_rb_tree_find_node(- &mtree->rbtree, mentry->name);- for (; mp; mp = mp->next_dup) {- if (mp->full && !mp->used) {- /* Later lines override earlier ones. */- mp->used = 1;- r1 = parse_line(a, entry, mtree, mp, &parsed_kws);- if (r1 < r)- r = r1;- }- }- } else {- /*- * Relative entries require us to construct- * the full path and possibly update the- * current directory.- */- size_t n = archive_strlen(&mtree->current_dir);- if (n > 0)- archive_strcat(&mtree->current_dir, "/");- archive_strcat(&mtree->current_dir, mentry->name);- archive_entry_copy_pathname(entry, mtree->current_dir.s);- if (archive_entry_filetype(entry) != AE_IFDIR)- mtree->current_dir.length = n;- }-- if (mtree->checkfs) {- /*- * Try to open and stat the file to get the real size- * and other file info. It would be nice to avoid- * this here so that getting a listing of an mtree- * wouldn't require opening every referenced contents- * file. But then we wouldn't know the actual- * contents size, so I don't see a really viable way- * around this. (Also, we may want to someday pull- * other unspecified info from the contents file on- * disk.)- */- mtree->fd = -1;- if (archive_strlen(&mtree->contents_name) > 0)- path = mtree->contents_name.s;- else- path = archive_entry_pathname(entry);-- if (archive_entry_filetype(entry) == AE_IFREG ||- archive_entry_filetype(entry) == AE_IFDIR) {- mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC);- __archive_ensure_cloexec_flag(mtree->fd);- if (mtree->fd == -1 && (-#if defined(_WIN32) && !defined(__CYGWIN__)- /*- * On Windows, attempting to open a file with an- * invalid name result in EINVAL (Error 22)- */- (errno != ENOENT && errno != EINVAL)-#else- errno != ENOENT-#endif- || archive_strlen(&mtree->contents_name) > 0)) {- archive_set_error(&a->archive, errno,- "Can't open %s", path);- r = ARCHIVE_WARN;- }- }-- st = &st_storage;- if (mtree->fd >= 0) {- if (fstat(mtree->fd, st) == -1) {- archive_set_error(&a->archive, errno,- "Could not fstat %s", path);- r = ARCHIVE_WARN;- /* If we can't stat it, don't keep it open. */- close(mtree->fd);- mtree->fd = -1;- st = NULL;- }- }-#ifdef HAVE_LSTAT- else if (lstat(path, st) == -1)-#else- else if (la_stat(path, st) == -1)-#endif- {- st = NULL;- }-- /*- * Check for a mismatch between the type in the specification- * and the type of the contents object on disk.- */- if (st != NULL) {- if (((st->st_mode & S_IFMT) == S_IFREG &&- archive_entry_filetype(entry) == AE_IFREG)-#ifdef S_IFLNK- ||((st->st_mode & S_IFMT) == S_IFLNK &&- archive_entry_filetype(entry) == AE_IFLNK)-#endif-#ifdef S_IFSOCK- ||((st->st_mode & S_IFSOCK) == S_IFSOCK &&- archive_entry_filetype(entry) == AE_IFSOCK)-#endif-#ifdef S_IFCHR- ||((st->st_mode & S_IFMT) == S_IFCHR &&- archive_entry_filetype(entry) == AE_IFCHR)-#endif-#ifdef S_IFBLK- ||((st->st_mode & S_IFMT) == S_IFBLK &&- archive_entry_filetype(entry) == AE_IFBLK)-#endif- ||((st->st_mode & S_IFMT) == S_IFDIR &&- archive_entry_filetype(entry) == AE_IFDIR)-#ifdef S_IFIFO- ||((st->st_mode & S_IFMT) == S_IFIFO &&- archive_entry_filetype(entry) == AE_IFIFO)-#endif- ) {- /* Types match. */- } else {- /* Types don't match; bail out gracefully. */- if (mtree->fd >= 0)- close(mtree->fd);- mtree->fd = -1;- if (parsed_kws & MTREE_HAS_OPTIONAL) {- /* It's not an error for an optional- * entry to not match disk. */- *use_next = 1;- } else if (r == ARCHIVE_OK) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "mtree specification has different"- " type for %s",- archive_entry_pathname(entry));- r = ARCHIVE_WARN;- }- return (r);- }- }-- /*- * If there is a contents file on disk, pick some of the- * metadata from that file. For most of these, we only- * set it from the contents if it wasn't already parsed- * from the specification.- */- if (st != NULL) {- if (((parsed_kws & MTREE_HAS_DEVICE) == 0 ||- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) &&- (archive_entry_filetype(entry) == AE_IFCHR ||- archive_entry_filetype(entry) == AE_IFBLK))- archive_entry_set_rdev(entry, st->st_rdev);- if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME))- == 0 ||- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)- archive_entry_set_gid(entry, st->st_gid);- if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME))- == 0 ||- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)- archive_entry_set_uid(entry, st->st_uid);- if ((parsed_kws & MTREE_HAS_MTIME) == 0 ||- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) {-#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC- archive_entry_set_mtime(entry, st->st_mtime,- st->st_mtimespec.tv_nsec);-#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC- archive_entry_set_mtime(entry, st->st_mtime,- st->st_mtim.tv_nsec);-#elif HAVE_STRUCT_STAT_ST_MTIME_N- archive_entry_set_mtime(entry, st->st_mtime,- st->st_mtime_n);-#elif HAVE_STRUCT_STAT_ST_UMTIME- archive_entry_set_mtime(entry, st->st_mtime,- st->st_umtime*1000);-#elif HAVE_STRUCT_STAT_ST_MTIME_USEC- archive_entry_set_mtime(entry, st->st_mtime,- st->st_mtime_usec*1000);-#else- archive_entry_set_mtime(entry, st->st_mtime, 0);-#endif- }- if ((parsed_kws & MTREE_HAS_NLINK) == 0 ||- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)- archive_entry_set_nlink(entry, st->st_nlink);- if ((parsed_kws & MTREE_HAS_PERM) == 0 ||- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)- archive_entry_set_perm(entry, st->st_mode);- if ((parsed_kws & MTREE_HAS_SIZE) == 0 ||- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)- archive_entry_set_size(entry, st->st_size);- archive_entry_set_ino(entry, st->st_ino);- archive_entry_set_dev(entry, st->st_dev);-- archive_entry_linkify(mtree->resolver, &entry,- &sparse_entry);- } else if (parsed_kws & MTREE_HAS_OPTIONAL) {- /*- * Couldn't open the entry, stat it or the on-disk type- * didn't match. If this entry is optional, just- * ignore it and read the next header entry.- */- *use_next = 1;- return ARCHIVE_OK;- }- }-- mtree->cur_size = archive_entry_size(entry);- mtree->offset = 0;-- return r;-}--/*- * Each line contains a sequence of keywords.- */-static int-parse_line(struct archive_read *a, struct archive_entry *entry,- struct mtree *mtree, struct mtree_entry *mp, int *parsed_kws)-{- struct mtree_option *iter;- int r = ARCHIVE_OK, r1;-- for (iter = mp->options; iter != NULL; iter = iter->next) {- r1 = parse_keyword(a, mtree, entry, iter, parsed_kws);- if (r1 < r)- r = r1;- }- if (r == ARCHIVE_OK && (*parsed_kws & MTREE_HAS_TYPE) == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Missing type keyword in mtree specification");- return (ARCHIVE_WARN);- }- return (r);-}--/*- * Device entries have one of the following forms:- * - raw dev_t- * - format,major,minor[,subdevice]- * When parsing succeeded, `pdev' will contain the appropriate dev_t value.- */--/* strsep() is not in C90, but strcspn() is. */-/* Taken from http://unixpapa.com/incnote/string.html */-static char *-la_strsep(char **sp, const char *sep)-{- char *p, *s;- if (sp == NULL || *sp == NULL || **sp == '\0')- return(NULL);- s = *sp;- p = s + strcspn(s, sep);- if (*p != '\0')- *p++ = '\0';- *sp = p;- return(s);-}--static int-parse_device(dev_t *pdev, struct archive *a, char *val)-{-#define MAX_PACK_ARGS 3- unsigned long numbers[MAX_PACK_ARGS];- char *p, *dev;- int argc;- pack_t *pack;- dev_t result;- const char *error = NULL;-- memset(pdev, 0, sizeof(*pdev));- if ((dev = strchr(val, ',')) != NULL) {- /*- * Device's major/minor are given in a specified format.- * Decode and pack it accordingly.- */- *dev++ = '\0';- if ((pack = pack_find(val)) == NULL) {- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,- "Unknown format `%s'", val);- return ARCHIVE_WARN;- }- argc = 0;- while ((p = la_strsep(&dev, ",")) != NULL) {- if (*p == '\0') {- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,- "Missing number");- return ARCHIVE_WARN;- }- if (argc >= MAX_PACK_ARGS) {- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,- "Too many arguments");- return ARCHIVE_WARN;- }- numbers[argc++] = (unsigned long)mtree_atol(&p, 0);- }- if (argc < 2) {- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,- "Not enough arguments");- return ARCHIVE_WARN;- }- result = (*pack)(argc, numbers, &error);- if (error != NULL) {- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,- "%s", error);- return ARCHIVE_WARN;- }- } else {- /* file system raw value. */- result = (dev_t)mtree_atol(&val, 0);- }- *pdev = result;- return ARCHIVE_OK;-#undef MAX_PACK_ARGS-}--static int-parse_hex_nibble(char c)-{- if (c >= '0' && c <= '9')- return c - '0';- if (c >= 'a' && c <= 'f')- return 10 + c - 'a';-#if 0- /* XXX: Is uppercase something we should support? */- if (c >= 'A' && c <= 'F')- return 10 + c - 'A';-#endif-- return -1;-}--static int-parse_digest(struct archive_read *a, struct archive_entry *entry,- const char *digest, int type)-{- unsigned char digest_buf[64];- int high, low;- size_t i, j, len;-- switch (type) {- case ARCHIVE_ENTRY_DIGEST_MD5:- len = sizeof(entry->digest.md5);- break;- case ARCHIVE_ENTRY_DIGEST_RMD160:- len = sizeof(entry->digest.rmd160);- break;- case ARCHIVE_ENTRY_DIGEST_SHA1:- len = sizeof(entry->digest.sha1);- break;- case ARCHIVE_ENTRY_DIGEST_SHA256:- len = sizeof(entry->digest.sha256);- break;- case ARCHIVE_ENTRY_DIGEST_SHA384:- len = sizeof(entry->digest.sha384);- break;- case ARCHIVE_ENTRY_DIGEST_SHA512:- len = sizeof(entry->digest.sha512);- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Internal error: Unknown digest type");- return ARCHIVE_FATAL;- }-- if (len > sizeof(digest_buf)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Internal error: Digest storage too large");- return ARCHIVE_FATAL;- }-- len *= 2;-- if (mtree_strnlen(digest, len+1) != len) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "incorrect digest length, ignoring");- return ARCHIVE_WARN;- }-- for (i = 0, j = 0; i < len; i += 2, j++) {- high = parse_hex_nibble(digest[i]);- low = parse_hex_nibble(digest[i+1]);- if (high == -1 || low == -1) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "invalid digest data, ignoring");- return ARCHIVE_WARN;- }-- digest_buf[j] = high << 4 | low;- }-- return archive_entry_set_digest(entry, type, digest_buf);-}--/*- * Parse a single keyword and its value.- */-static int-parse_keyword(struct archive_read *a, struct mtree *mtree,- struct archive_entry *entry, struct mtree_option *opt, int *parsed_kws)-{- char *val, *key;-- key = opt->value;-- if (*key == '\0')- return (ARCHIVE_OK);-- if (strcmp(key, "nochange") == 0) {- *parsed_kws |= MTREE_HAS_NOCHANGE;- return (ARCHIVE_OK);- }- if (strcmp(key, "optional") == 0) {- *parsed_kws |= MTREE_HAS_OPTIONAL;- return (ARCHIVE_OK);- }- if (strcmp(key, "ignore") == 0) {- /*- * The mtree processing is not recursive, so- * recursion will only happen for explicitly listed- * entries.- */- return (ARCHIVE_OK);- }-- val = strchr(key, '=');- if (val == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Malformed attribute \"%s\" (%d)", key, key[0]);- return (ARCHIVE_WARN);- }-- *val = '\0';- ++val;-- switch (key[0]) {- case 'c':- if (strcmp(key, "content") == 0- || strcmp(key, "contents") == 0) {- parse_escapes(val, NULL);- archive_strcpy(&mtree->contents_name, val);- return (ARCHIVE_OK);- }- if (strcmp(key, "cksum") == 0)- return (ARCHIVE_OK);- break;- case 'd':- if (strcmp(key, "device") == 0) {- /* stat(2) st_rdev field, e.g. the major/minor IDs- * of a char/block special file */- int r;- dev_t dev;-- *parsed_kws |= MTREE_HAS_DEVICE;- r = parse_device(&dev, &a->archive, val);- if (r == ARCHIVE_OK)- archive_entry_set_rdev(entry, dev);- return r;- }- break;- case 'f':- if (strcmp(key, "flags") == 0) {- *parsed_kws |= MTREE_HAS_FFLAGS;- archive_entry_copy_fflags_text(entry, val);- return (ARCHIVE_OK);- }- break;- case 'g':- if (strcmp(key, "gid") == 0) {- *parsed_kws |= MTREE_HAS_GID;- archive_entry_set_gid(entry, mtree_atol(&val, 10));- return (ARCHIVE_OK);- }- if (strcmp(key, "gname") == 0) {- *parsed_kws |= MTREE_HAS_GNAME;- archive_entry_copy_gname(entry, val);- return (ARCHIVE_OK);- }- break;- case 'i':- if (strcmp(key, "inode") == 0) {- archive_entry_set_ino(entry, mtree_atol(&val, 10));- return (ARCHIVE_OK);- }- break;- case 'l':- if (strcmp(key, "link") == 0) {- parse_escapes(val, NULL);- archive_entry_copy_symlink(entry, val);- return (ARCHIVE_OK);- }- break;- case 'm':- if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) {- return parse_digest(a, entry, val,- ARCHIVE_ENTRY_DIGEST_MD5);- }- if (strcmp(key, "mode") == 0) {- if (val[0] < '0' || val[0] > '7') {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Symbolic or non-octal mode \"%s\" unsupported", val);- return (ARCHIVE_WARN);- }- *parsed_kws |= MTREE_HAS_PERM;- archive_entry_set_perm(entry, (mode_t)mtree_atol(&val, 8));- return (ARCHIVE_OK);- }- break;- case 'n':- if (strcmp(key, "nlink") == 0) {- *parsed_kws |= MTREE_HAS_NLINK;- archive_entry_set_nlink(entry,- (unsigned int)mtree_atol(&val, 10));- return (ARCHIVE_OK);- }- break;- case 'r':- if (strcmp(key, "resdevice") == 0) {- /* stat(2) st_dev field, e.g. the device ID where the- * inode resides */- int r;- dev_t dev;-- r = parse_device(&dev, &a->archive, val);- if (r == ARCHIVE_OK)- archive_entry_set_dev(entry, dev);- return r;- }- if (strcmp(key, "rmd160") == 0 ||- strcmp(key, "rmd160digest") == 0) {- return parse_digest(a, entry, val,- ARCHIVE_ENTRY_DIGEST_RMD160);- }- break;- case 's':- if (strcmp(key, "sha1") == 0 ||- strcmp(key, "sha1digest") == 0) {- return parse_digest(a, entry, val,- ARCHIVE_ENTRY_DIGEST_SHA1);- }- if (strcmp(key, "sha256") == 0 ||- strcmp(key, "sha256digest") == 0) {- return parse_digest(a, entry, val,- ARCHIVE_ENTRY_DIGEST_SHA256);- }- if (strcmp(key, "sha384") == 0 ||- strcmp(key, "sha384digest") == 0) {- return parse_digest(a, entry, val,- ARCHIVE_ENTRY_DIGEST_SHA384);- }- if (strcmp(key, "sha512") == 0 ||- strcmp(key, "sha512digest") == 0) {- return parse_digest(a, entry, val,- ARCHIVE_ENTRY_DIGEST_SHA512);- }- if (strcmp(key, "size") == 0) {- archive_entry_set_size(entry, mtree_atol(&val, 10));- return (ARCHIVE_OK);- }- break;- case 't':- if (strcmp(key, "tags") == 0) {- /*- * Comma delimited list of tags.- * Ignore the tags for now, but the interface- * should be extended to allow inclusion/exclusion.- */- return (ARCHIVE_OK);- }- if (strcmp(key, "time") == 0) {- int64_t m;- int64_t my_time_t_max = get_time_t_max();- int64_t my_time_t_min = get_time_t_min();- long ns = 0;-- *parsed_kws |= MTREE_HAS_MTIME;- m = mtree_atol(&val, 10);- /* Replicate an old mtree bug:- * 123456789.1 represents 123456789- * seconds and 1 nanosecond. */- if (*val == '.') {- ++val;- ns = (long)mtree_atol(&val, 10);- if (ns < 0)- ns = 0;- else if (ns > 999999999)- ns = 999999999;- }- if (m > my_time_t_max)- m = my_time_t_max;- else if (m < my_time_t_min)- m = my_time_t_min;- archive_entry_set_mtime(entry, (time_t)m, ns);- return (ARCHIVE_OK);- }- if (strcmp(key, "type") == 0) {- switch (val[0]) {- case 'b':- if (strcmp(val, "block") == 0) {- *parsed_kws |= MTREE_HAS_TYPE;- archive_entry_set_filetype(entry,- AE_IFBLK);- return (ARCHIVE_OK);- }- break;- case 'c':- if (strcmp(val, "char") == 0) {- *parsed_kws |= MTREE_HAS_TYPE;- archive_entry_set_filetype(entry,- AE_IFCHR);- return (ARCHIVE_OK);- }- break;- case 'd':- if (strcmp(val, "dir") == 0) {- *parsed_kws |= MTREE_HAS_TYPE;- archive_entry_set_filetype(entry,- AE_IFDIR);- return (ARCHIVE_OK);- }- break;- case 'f':- if (strcmp(val, "fifo") == 0) {- *parsed_kws |= MTREE_HAS_TYPE;- archive_entry_set_filetype(entry,- AE_IFIFO);- return (ARCHIVE_OK);- }- if (strcmp(val, "file") == 0) {- *parsed_kws |= MTREE_HAS_TYPE;- archive_entry_set_filetype(entry,- AE_IFREG);- return (ARCHIVE_OK);- }- break;- case 'l':- if (strcmp(val, "link") == 0) {- *parsed_kws |= MTREE_HAS_TYPE;- archive_entry_set_filetype(entry,- AE_IFLNK);- return (ARCHIVE_OK);- }- break;- default:- break;- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unrecognized file type \"%s\"; "- "assuming \"file\"", val);- archive_entry_set_filetype(entry, AE_IFREG);- return (ARCHIVE_WARN);- }- break;- case 'u':- if (strcmp(key, "uid") == 0) {- *parsed_kws |= MTREE_HAS_UID;- archive_entry_set_uid(entry, mtree_atol(&val, 10));- return (ARCHIVE_OK);- }- if (strcmp(key, "uname") == 0) {- *parsed_kws |= MTREE_HAS_UNAME;- archive_entry_copy_uname(entry, val);- return (ARCHIVE_OK);- }- break;- default:- break;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unrecognized key %s=%s", key, val);- return (ARCHIVE_WARN);-}--static int-read_data(struct archive_read *a, const void **buff, size_t *size,- int64_t *offset)-{- size_t bytes_to_read;- ssize_t bytes_read;- struct mtree *mtree;-- mtree = (struct mtree *)(a->format->data);- if (mtree->fd < 0) {- *buff = NULL;- *offset = 0;- *size = 0;- return (ARCHIVE_EOF);- }- if (mtree->buff == NULL) {- mtree->buffsize = 64 * 1024;- mtree->buff = malloc(mtree->buffsize);- if (mtree->buff == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- }-- *buff = mtree->buff;- *offset = mtree->offset;- if ((int64_t)mtree->buffsize > mtree->cur_size - mtree->offset)- bytes_to_read = (size_t)(mtree->cur_size - mtree->offset);- else- bytes_to_read = mtree->buffsize;- bytes_read = read(mtree->fd, mtree->buff, bytes_to_read);- if (bytes_read < 0) {- archive_set_error(&a->archive, errno, "Can't read");- return (ARCHIVE_WARN);- }- if (bytes_read == 0) {- *size = 0;- return (ARCHIVE_EOF);- }- mtree->offset += bytes_read;- *size = bytes_read;- return (ARCHIVE_OK);-}--/* Skip does nothing except possibly close the contents file. */-static int-skip(struct archive_read *a)-{- struct mtree *mtree;-- mtree = (struct mtree *)(a->format->data);- if (mtree->fd >= 0) {- close(mtree->fd);- mtree->fd = -1;- }- return (ARCHIVE_OK);-}--/*- * Since parsing backslash sequences always makes strings shorter,- * we can always do this conversion in-place.- */-static void-parse_escapes(char *src, struct mtree_entry *mentry)-{- char *dest = src;- char c;-- if (mentry != NULL && strcmp(src, ".") == 0)- mentry->full = 1;-- while (*src != '\0') {- c = *src++;- if (c == '/' && mentry != NULL)- mentry->full = 1;- if (c == '\\') {- switch (src[0]) {- case '0':- if (src[1] < '0' || src[1] > '7') {- c = 0;- ++src;- break;- }- /* FALLTHROUGH */- case '1':- case '2':- case '3':- if (src[1] >= '0' && src[1] <= '7' &&- src[2] >= '0' && src[2] <= '7') {- c = (src[0] - '0') << 6;- c |= (src[1] - '0') << 3;- c |= (src[2] - '0');- src += 3;- }- break;- case 'a':- c = '\a';- ++src;- break;- case 'b':- c = '\b';- ++src;- break;- case 'f':- c = '\f';- ++src;- break;- case 'n':- c = '\n';- ++src;- break;- case 'r':- c = '\r';- ++src;- break;- case 's':- c = ' ';- ++src;- break;- case 't':- c = '\t';- ++src;- break;- case 'v':- c = '\v';- ++src;- break;- case '\\':- c = '\\';- ++src;- break;- }- }- *dest++ = c;- }- *dest = '\0';-}--/* Parse a hex digit. */-static int-parsedigit(char c)-{- if (c >= '0' && c <= '9')- return c - '0';- else if (c >= 'a' && c <= 'f')- return c - 'a';- else if (c >= 'A' && c <= 'F')- return c - 'A';- else- return -1;-}--/*- * Note that this implementation does not (and should not!) obey- * locale settings; you cannot simply substitute strtol here, since- * it does obey locale.- */-static int64_t-mtree_atol(char **p, int base)-{- int64_t l, limit;- int digit, last_digit_limit;-- if (base == 0) {- if (**p != '0')- base = 10;- else if ((*p)[1] == 'x' || (*p)[1] == 'X') {- *p += 2;- base = 16;- } else {- base = 8;- }- }-- if (**p == '-') {- limit = INT64_MIN / base;- last_digit_limit = -(INT64_MIN % base);- ++(*p);-- l = 0;- digit = parsedigit(**p);- while (digit >= 0 && digit < base) {- if (l < limit || (l == limit && digit >= last_digit_limit))- return INT64_MIN;- l = (l * base) - digit;- digit = parsedigit(*++(*p));- }- return l;- } else {- limit = INT64_MAX / base;- last_digit_limit = INT64_MAX % base;-- l = 0;- digit = parsedigit(**p);- while (digit >= 0 && digit < base) {- if (l > limit || (l == limit && digit > last_digit_limit))- return INT64_MAX;- l = (l * base) + digit;- digit = parsedigit(*++(*p));- }- return l;- }-}--/*- * Returns length of line (including trailing newline)- * or negative on error. 'start' argument is updated to- * point to first character of line.- */-static ssize_t-readline(struct archive_read *a, struct mtree *mtree, char **start,- ssize_t limit)-{- ssize_t bytes_read;- ssize_t total_size = 0;- ssize_t find_off = 0;- const void *t;- void *nl;- char *u;-- /* Accumulate line in a line buffer. */- for (;;) {- /* Read some more. */- t = __archive_read_ahead(a, 1, &bytes_read);- if (t == NULL)- return (0);- if (bytes_read < 0)- return (ARCHIVE_FATAL);- nl = memchr(t, '\n', bytes_read);- /* If we found '\n', trim the read to end exactly there. */- if (nl != NULL) {- bytes_read = ((const char *)nl) - ((const char *)t) + 1;- }- if (total_size + bytes_read + 1 > limit) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Line too long");- return (ARCHIVE_FATAL);- }- if (archive_string_ensure(&mtree->line,- total_size + bytes_read + 1) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate working buffer");- return (ARCHIVE_FATAL);- }- /* Append new bytes to string. */- memcpy(mtree->line.s + total_size, t, bytes_read);- __archive_read_consume(a, bytes_read);- total_size += bytes_read;- mtree->line.s[total_size] = '\0';-- for (u = mtree->line.s + find_off; *u; ++u) {- if (u[0] == '\n') {- /* Ends with unescaped newline. */- *start = mtree->line.s;- return total_size;- } else if (u[0] == '#') {- /* Ends with comment sequence #...\n */- if (nl == NULL) {- /* But we've not found the \n yet */- break;- }- } else if (u[0] == '\\') {- if (u[1] == '\n') {- /* Trim escaped newline. */- total_size -= 2;- mtree->line.s[total_size] = '\0';- break;- } else if (u[1] != '\0') {- /* Skip the two-char escape sequence */- ++u;- }- }- }- find_off = u - mtree->line.s;- }-}
− c/archive_read_support_format_rar.c
@@ -1,3788 +0,0 @@-/*--* Copyright (c) 2003-2007 Tim Kientzle-* Copyright (c) 2011 Andres Mejia-* 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"--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#include <time.h>-#include <limits.h>-#ifdef HAVE_ZLIB_H-#include <zlib.h> /* crc32 */-#endif--#include "archive.h"-#ifndef HAVE_ZLIB_H-#include "archive_crc32.h"-#endif-#include "archive_endian.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_ppmd7_private.h"-#include "archive_private.h"-#include "archive_read_private.h"--/* RAR signature, also known as the mark header */-#define RAR_SIGNATURE "\x52\x61\x72\x21\x1A\x07\x00"--/* Header types */-#define MARK_HEAD 0x72-#define MAIN_HEAD 0x73-#define FILE_HEAD 0x74-#define COMM_HEAD 0x75-#define AV_HEAD 0x76-#define SUB_HEAD 0x77-#define PROTECT_HEAD 0x78-#define SIGN_HEAD 0x79-#define NEWSUB_HEAD 0x7a-#define ENDARC_HEAD 0x7b--/* Main Header Flags */-#define MHD_VOLUME 0x0001-#define MHD_COMMENT 0x0002-#define MHD_LOCK 0x0004-#define MHD_SOLID 0x0008-#define MHD_NEWNUMBERING 0x0010-#define MHD_AV 0x0020-#define MHD_PROTECT 0x0040-#define MHD_PASSWORD 0x0080-#define MHD_FIRSTVOLUME 0x0100-#define MHD_ENCRYPTVER 0x0200--/* Flags common to all headers */-#define HD_MARKDELETION 0x4000-#define HD_ADD_SIZE_PRESENT 0x8000--/* File Header Flags */-#define FHD_SPLIT_BEFORE 0x0001-#define FHD_SPLIT_AFTER 0x0002-#define FHD_PASSWORD 0x0004-#define FHD_COMMENT 0x0008-#define FHD_SOLID 0x0010-#define FHD_LARGE 0x0100-#define FHD_UNICODE 0x0200-#define FHD_SALT 0x0400-#define FHD_VERSION 0x0800-#define FHD_EXTTIME 0x1000-#define FHD_EXTFLAGS 0x2000--/* File dictionary sizes */-#define DICTIONARY_SIZE_64 0x00-#define DICTIONARY_SIZE_128 0x20-#define DICTIONARY_SIZE_256 0x40-#define DICTIONARY_SIZE_512 0x60-#define DICTIONARY_SIZE_1024 0x80-#define DICTIONARY_SIZE_2048 0xA0-#define DICTIONARY_SIZE_4096 0xC0-#define FILE_IS_DIRECTORY 0xE0-#define DICTIONARY_MASK FILE_IS_DIRECTORY--/* OS Flags */-#define OS_MSDOS 0-#define OS_OS2 1-#define OS_WIN32 2-#define OS_UNIX 3-#define OS_MAC_OS 4-#define OS_BEOS 5--/* Compression Methods */-#define COMPRESS_METHOD_STORE 0x30-/* LZSS */-#define COMPRESS_METHOD_FASTEST 0x31-#define COMPRESS_METHOD_FAST 0x32-#define COMPRESS_METHOD_NORMAL 0x33-/* PPMd Variant H */-#define COMPRESS_METHOD_GOOD 0x34-#define COMPRESS_METHOD_BEST 0x35--#define CRC_POLYNOMIAL 0xEDB88320--#define NS_UNIT 10000000--#define DICTIONARY_MAX_SIZE 0x400000--#define MAINCODE_SIZE 299-#define OFFSETCODE_SIZE 60-#define LOWOFFSETCODE_SIZE 17-#define LENGTHCODE_SIZE 28-#define HUFFMAN_TABLE_SIZE \- MAINCODE_SIZE + OFFSETCODE_SIZE + LOWOFFSETCODE_SIZE + LENGTHCODE_SIZE--#define MAX_SYMBOL_LENGTH 0xF-#define MAX_SYMBOLS 20--/* Virtual Machine Properties */-#define VM_MEMORY_SIZE 0x40000-#define VM_MEMORY_MASK (VM_MEMORY_SIZE - 1)-#define PROGRAM_WORK_SIZE 0x3C000-#define PROGRAM_GLOBAL_SIZE 0x2000-#define PROGRAM_SYSTEM_GLOBAL_ADDRESS PROGRAM_WORK_SIZE-#define PROGRAM_SYSTEM_GLOBAL_SIZE 0x40-#define PROGRAM_USER_GLOBAL_ADDRESS (PROGRAM_SYSTEM_GLOBAL_ADDRESS + PROGRAM_SYSTEM_GLOBAL_SIZE)-#define PROGRAM_USER_GLOBAL_SIZE (PROGRAM_GLOBAL_SIZE - PROGRAM_SYSTEM_GLOBAL_SIZE)--/*- * Considering L1,L2 cache miss and a calling of write system-call,- * the best size of the output buffer(uncompressed buffer) is 128K.- * If the structure of extracting process is changed, this value- * might be researched again.- */-#define UNP_BUFFER_SIZE (128 * 1024)--/* Define this here for non-Windows platforms */-#if !((defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__))-#define FILE_ATTRIBUTE_DIRECTORY 0x10-#endif--#undef minimum-#define minimum(a, b) ((a)<(b)?(a):(b))--/* Stack overflow check */-#define MAX_COMPRESS_DEPTH 1024--/* Fields common to all headers */-struct rar_header-{- char crc[2];- char type;- char flags[2];- char size[2];-};--/* Fields common to all file headers */-struct rar_file_header-{- char pack_size[4];- char unp_size[4];- char host_os;- char file_crc[4];- char file_time[4];- char unp_ver;- char method;- char name_size[2];- char file_attr[4];-};--struct huffman_tree_node-{- int branches[2];-};--struct huffman_table_entry-{- unsigned int length;- int value;-};--struct huffman_code-{- struct huffman_tree_node *tree;- int numentries;- int numallocatedentries;- int minlength;- int maxlength;- int tablesize;- struct huffman_table_entry *table;-};--struct lzss-{- unsigned char *window;- int mask;- int64_t position;-};--struct data_block_offsets-{- int64_t header_size;- int64_t start_offset;- int64_t end_offset;-};--struct rar_program_code-{- uint8_t *staticdata;- uint32_t staticdatalen;- uint8_t *globalbackup;- uint32_t globalbackuplen;- uint64_t fingerprint;- uint32_t usagecount;- uint32_t oldfilterlength;- struct rar_program_code *next;-};--struct rar_filter-{- struct rar_program_code *prog;- uint32_t initialregisters[8];- uint8_t *globaldata;- uint32_t globaldatalen;- size_t blockstartpos;- uint32_t blocklength;- uint32_t filteredblockaddress;- uint32_t filteredblocklength;- struct rar_filter *next;-};--struct memory_bit_reader-{- const uint8_t *bytes;- size_t length;- size_t offset;- uint64_t bits;- int available;- int at_eof;-};--struct rar_virtual_machine-{- uint32_t registers[8];- uint8_t memory[VM_MEMORY_SIZE + sizeof(uint32_t)];-};--struct rar_filters-{- struct rar_virtual_machine *vm;- struct rar_program_code *progs;- struct rar_filter *stack;- int64_t filterstart;- uint32_t lastfilternum;- int64_t lastend;- uint8_t *bytes;- size_t bytes_ready;-};--struct audio_state-{- int8_t weight[5];- int16_t delta[4];- int8_t lastdelta;- int error[11];- int count;- uint8_t lastbyte;-};--struct rar-{- /* Entries from main RAR header */- unsigned main_flags;- unsigned long file_crc;- char reserved1[2];- char reserved2[4];- char encryptver;-- /* File header entries */- char compression_method;- unsigned file_flags;- int64_t packed_size;- int64_t unp_size;- time_t mtime;- long mnsec;- mode_t mode;- char *filename;- char *filename_save;- size_t filename_save_size;- size_t filename_allocated;-- /* File header optional entries */- char salt[8];- time_t atime;- long ansec;- time_t ctime;- long cnsec;- time_t arctime;- long arcnsec;-- /* Fields to help with tracking decompression of files. */- int64_t bytes_unconsumed;- int64_t bytes_remaining;- int64_t bytes_uncopied;- int64_t offset;- int64_t offset_outgoing;- int64_t offset_seek;- char valid;- unsigned int unp_offset;- unsigned int unp_buffer_size;- unsigned char *unp_buffer;- unsigned int dictionary_size;- char start_new_block;- char entry_eof;- unsigned long crc_calculated;- int found_first_header;- char has_endarc_header;- struct data_block_offsets *dbo;- unsigned int cursor;- unsigned int nodes;- char filename_must_match;-- /* LZSS members */- struct huffman_code maincode;- struct huffman_code offsetcode;- struct huffman_code lowoffsetcode;- struct huffman_code lengthcode;- unsigned char lengthtable[HUFFMAN_TABLE_SIZE];- struct lzss lzss;- unsigned int lastlength;- unsigned int lastoffset;- unsigned int oldoffset[4];- unsigned int lastlowoffset;- unsigned int numlowoffsetrepeats;- char start_new_table;-- /* Filters */- struct rar_filters filters;-- /* PPMd Variant H members */- char ppmd_valid;- char ppmd_eod;- char is_ppmd_block;- int ppmd_escape;- CPpmd7 ppmd7_context;- CPpmd7z_RangeDec range_dec;- IByteIn bytein;-- /*- * String conversion object.- */- int init_default_conversion;- struct archive_string_conv *sconv_default;- struct archive_string_conv *opt_sconv;- struct archive_string_conv *sconv_utf8;- struct archive_string_conv *sconv_utf16be;-- /*- * Bit stream reader.- */- struct rar_br {-#define CACHE_TYPE uint64_t-#define CACHE_BITS (8 * sizeof(CACHE_TYPE))- /* Cache buffer. */- CACHE_TYPE cache_buffer;- /* Indicates how many bits avail in cache_buffer. */- int cache_avail;- ssize_t avail_in;- const unsigned char *next_in;- } br;-- /*- * Custom field to denote that this archive contains encrypted entries- */- int has_encrypted_entries;-};--static int archive_read_support_format_rar_capabilities(struct archive_read *);-static int archive_read_format_rar_has_encrypted_entries(struct archive_read *);-static int archive_read_format_rar_bid(struct archive_read *, int);-static int archive_read_format_rar_options(struct archive_read *,- const char *, const char *);-static int archive_read_format_rar_read_header(struct archive_read *,- struct archive_entry *);-static int archive_read_format_rar_read_data(struct archive_read *,- const void **, size_t *, int64_t *);-static int archive_read_format_rar_read_data_skip(struct archive_read *a);-static int64_t archive_read_format_rar_seek_data(struct archive_read *, int64_t,- int);-static int archive_read_format_rar_cleanup(struct archive_read *);--/* Support functions */-static int read_header(struct archive_read *, struct archive_entry *, char);-static time_t get_time(int);-static int read_exttime(const char *, struct rar *, const char *);-static int read_symlink_stored(struct archive_read *, struct archive_entry *,- struct archive_string_conv *);-static int read_data_stored(struct archive_read *, const void **, size_t *,- int64_t *);-static int read_data_compressed(struct archive_read *, const void **, size_t *,- int64_t *, size_t);-static int rar_br_preparation(struct archive_read *, struct rar_br *);-static int parse_codes(struct archive_read *);-static void free_codes(struct archive_read *);-static int read_next_symbol(struct archive_read *, struct huffman_code *);-static int create_code(struct archive_read *, struct huffman_code *,- unsigned char *, int, char);-static int add_value(struct archive_read *, struct huffman_code *, int, int,- int);-static int new_node(struct huffman_code *);-static int make_table(struct archive_read *, struct huffman_code *);-static int make_table_recurse(struct archive_read *, struct huffman_code *, int,- struct huffman_table_entry *, int, int);-static int expand(struct archive_read *, int64_t *);-static int copy_from_lzss_window_to_unp(struct archive_read *, const void **,- int64_t, int);-static const void *rar_read_ahead(struct archive_read *, size_t, ssize_t *);-static int parse_filter(struct archive_read *, const uint8_t *, uint16_t,- uint8_t);-static int run_filters(struct archive_read *);-static void clear_filters(struct rar_filters *);-static struct rar_filter *create_filter(struct rar_program_code *,- const uint8_t *, uint32_t,- uint32_t[8], size_t, uint32_t);-static void delete_filter(struct rar_filter *filter);-static struct rar_program_code *compile_program(const uint8_t *, size_t);-static void delete_program_code(struct rar_program_code *prog);-static uint32_t membr_next_rarvm_number(struct memory_bit_reader *br);-static inline uint32_t membr_bits(struct memory_bit_reader *br, int bits);-static int membr_fill(struct memory_bit_reader *br, int bits);-static int read_filter(struct archive_read *, int64_t *);-static int rar_decode_byte(struct archive_read*, uint8_t *);-static int execute_filter(struct archive_read*, struct rar_filter *,- struct rar_virtual_machine *, size_t);-static int copy_from_lzss_window(struct archive_read *, void *, int64_t, int);-static inline void vm_write_32(struct rar_virtual_machine*, size_t, uint32_t);-static inline uint32_t vm_read_32(struct rar_virtual_machine*, size_t);--/*- * Bit stream reader.- */-/* Check that the cache buffer has enough bits. */-#define rar_br_has(br, n) ((br)->cache_avail >= n)-/* Get compressed data by bit. */-#define rar_br_bits(br, n) \- (((uint32_t)((br)->cache_buffer >> \- ((br)->cache_avail - (n)))) & cache_masks[n])-#define rar_br_bits_forced(br, n) \- (((uint32_t)((br)->cache_buffer << \- ((n) - (br)->cache_avail))) & cache_masks[n])-/* Read ahead to make sure the cache buffer has enough compressed data we- * will use.- * True : completed, there is enough data in the cache buffer.- * False : there is no data in the stream. */-#define rar_br_read_ahead(a, br, n) \- ((rar_br_has(br, (n)) || rar_br_fillup(a, br)) || rar_br_has(br, (n)))-/* Notify how many bits we consumed. */-#define rar_br_consume(br, n) ((br)->cache_avail -= (n))-#define rar_br_consume_unalined_bits(br) ((br)->cache_avail &= ~7)--static const uint32_t cache_masks[] = {- 0x00000000, 0x00000001, 0x00000003, 0x00000007,- 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,- 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,- 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,- 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,- 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,- 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,- 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF-};--/*- * Shift away used bits in the cache data and fill it up with following bits.- * Call this when cache buffer does not have enough bits you need.- *- * Returns 1 if the cache buffer is full.- * Returns 0 if the cache buffer is not full; input buffer is empty.- */-static int-rar_br_fillup(struct archive_read *a, struct rar_br *br)-{- struct rar *rar = (struct rar *)(a->format->data);- int n = CACHE_BITS - br->cache_avail;-- for (;;) {- switch (n >> 3) {- case 8:- if (br->avail_in >= 8) {- br->cache_buffer =- ((uint64_t)br->next_in[0]) << 56 |- ((uint64_t)br->next_in[1]) << 48 |- ((uint64_t)br->next_in[2]) << 40 |- ((uint64_t)br->next_in[3]) << 32 |- ((uint32_t)br->next_in[4]) << 24 |- ((uint32_t)br->next_in[5]) << 16 |- ((uint32_t)br->next_in[6]) << 8 |- (uint32_t)br->next_in[7];- br->next_in += 8;- br->avail_in -= 8;- br->cache_avail += 8 * 8;- rar->bytes_unconsumed += 8;- rar->bytes_remaining -= 8;- return (1);- }- break;- case 7:- if (br->avail_in >= 7) {- br->cache_buffer =- (br->cache_buffer << 56) |- ((uint64_t)br->next_in[0]) << 48 |- ((uint64_t)br->next_in[1]) << 40 |- ((uint64_t)br->next_in[2]) << 32 |- ((uint32_t)br->next_in[3]) << 24 |- ((uint32_t)br->next_in[4]) << 16 |- ((uint32_t)br->next_in[5]) << 8 |- (uint32_t)br->next_in[6];- br->next_in += 7;- br->avail_in -= 7;- br->cache_avail += 7 * 8;- rar->bytes_unconsumed += 7;- rar->bytes_remaining -= 7;- return (1);- }- break;- case 6:- if (br->avail_in >= 6) {- br->cache_buffer =- (br->cache_buffer << 48) |- ((uint64_t)br->next_in[0]) << 40 |- ((uint64_t)br->next_in[1]) << 32 |- ((uint32_t)br->next_in[2]) << 24 |- ((uint32_t)br->next_in[3]) << 16 |- ((uint32_t)br->next_in[4]) << 8 |- (uint32_t)br->next_in[5];- br->next_in += 6;- br->avail_in -= 6;- br->cache_avail += 6 * 8;- rar->bytes_unconsumed += 6;- rar->bytes_remaining -= 6;- return (1);- }- break;- case 0:- /* We have enough compressed data in- * the cache buffer.*/- return (1);- default:- break;- }- if (br->avail_in <= 0) {-- if (rar->bytes_unconsumed > 0) {- /* Consume as much as the decompressor- * actually used. */- __archive_read_consume(a, rar->bytes_unconsumed);- rar->bytes_unconsumed = 0;- }- br->next_in = rar_read_ahead(a, 1, &(br->avail_in));- if (br->next_in == NULL)- return (0);- if (br->avail_in == 0)- return (0);- }- br->cache_buffer =- (br->cache_buffer << 8) | *br->next_in++;- br->avail_in--;- br->cache_avail += 8;- n -= 8;- rar->bytes_unconsumed++;- rar->bytes_remaining--;- }-}--static int-rar_br_preparation(struct archive_read *a, struct rar_br *br)-{- struct rar *rar = (struct rar *)(a->format->data);-- if (rar->bytes_remaining > 0) {- br->next_in = rar_read_ahead(a, 1, &(br->avail_in));- if (br->next_in == NULL) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated RAR file data");- return (ARCHIVE_FATAL);- }- if (br->cache_avail == 0)- (void)rar_br_fillup(a, br);- }- return (ARCHIVE_OK);-}--/* Find last bit set */-static inline int-rar_fls(unsigned int word)-{- word |= (word >> 1);- word |= (word >> 2);- word |= (word >> 4);- word |= (word >> 8);- word |= (word >> 16);- return word - (word >> 1);-}--/* LZSS functions */-static inline int64_t-lzss_position(struct lzss *lzss)-{- return lzss->position;-}--static inline int-lzss_mask(struct lzss *lzss)-{- return lzss->mask;-}--static inline int-lzss_size(struct lzss *lzss)-{- return lzss->mask + 1;-}--static inline int-lzss_offset_for_position(struct lzss *lzss, int64_t pos)-{- return (int)(pos & lzss->mask);-}--static inline unsigned char *-lzss_pointer_for_position(struct lzss *lzss, int64_t pos)-{- return &lzss->window[lzss_offset_for_position(lzss, pos)];-}--static inline int-lzss_current_offset(struct lzss *lzss)-{- return lzss_offset_for_position(lzss, lzss->position);-}--static inline uint8_t *-lzss_current_pointer(struct lzss *lzss)-{- return lzss_pointer_for_position(lzss, lzss->position);-}--static inline void-lzss_emit_literal(struct rar *rar, uint8_t literal)-{- *lzss_current_pointer(&rar->lzss) = literal;- rar->lzss.position++;-}--static inline void-lzss_emit_match(struct rar *rar, int offset, int length)-{- int dstoffs = lzss_current_offset(&rar->lzss);- int srcoffs = (dstoffs - offset) & lzss_mask(&rar->lzss);- int l, li, remaining;- unsigned char *d, *s;-- remaining = length;- while (remaining > 0) {- l = remaining;- if (dstoffs > srcoffs) {- if (l > lzss_size(&rar->lzss) - dstoffs)- l = lzss_size(&rar->lzss) - dstoffs;- } else {- if (l > lzss_size(&rar->lzss) - srcoffs)- l = lzss_size(&rar->lzss) - srcoffs;- }- d = &(rar->lzss.window[dstoffs]);- s = &(rar->lzss.window[srcoffs]);- if ((dstoffs + l < srcoffs) || (srcoffs + l < dstoffs))- memcpy(d, s, l);- else {- for (li = 0; li < l; li++)- d[li] = s[li];- }- remaining -= l;- dstoffs = (dstoffs + l) & lzss_mask(&(rar->lzss));- srcoffs = (srcoffs + l) & lzss_mask(&(rar->lzss));- }- rar->lzss.position += length;-}--static Byte-ppmd_read(void *p)-{- struct archive_read *a = ((IByteIn*)p)->a;- struct rar *rar = (struct rar *)(a->format->data);- struct rar_br *br = &(rar->br);- Byte b;- if (!rar_br_read_ahead(a, br, 8))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated RAR file data");- rar->valid = 0;- return 0;- }- b = rar_br_bits(br, 8);- rar_br_consume(br, 8);- return b;-}--int-archive_read_support_format_rar(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct rar *rar;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_support_format_rar");-- rar = (struct rar *)calloc(sizeof(*rar), 1);- if (rar == NULL)- {- archive_set_error(&a->archive, ENOMEM, "Can't allocate rar data");- return (ARCHIVE_FATAL);- }-- /*- * Until enough data has been read, we cannot tell about- * any encrypted entries yet.- */- rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;-- r = __archive_read_register_format(a,- rar,- "rar",- archive_read_format_rar_bid,- archive_read_format_rar_options,- archive_read_format_rar_read_header,- archive_read_format_rar_read_data,- archive_read_format_rar_read_data_skip,- archive_read_format_rar_seek_data,- archive_read_format_rar_cleanup,- archive_read_support_format_rar_capabilities,- archive_read_format_rar_has_encrypted_entries);-- if (r != ARCHIVE_OK)- free(rar);- return (r);-}--static int-archive_read_support_format_rar_capabilities(struct archive_read * a)-{- (void)a; /* UNUSED */- return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA- | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);-}--static int-archive_read_format_rar_has_encrypted_entries(struct archive_read *_a)-{- if (_a && _a->format) {- struct rar * rar = (struct rar *)_a->format->data;- if (rar) {- return rar->has_encrypted_entries;- }- }- return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;-}---static int-archive_read_format_rar_bid(struct archive_read *a, int best_bid)-{- const char *p;-- /* If there's already a bid > 30, we'll never win. */- if (best_bid > 30)- return (-1);-- if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)- return (-1);-- if (memcmp(p, RAR_SIGNATURE, 7) == 0)- return (30);-- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {- /* This is a PE file */- ssize_t offset = 0x10000;- ssize_t window = 4096;- ssize_t bytes_avail;- while (offset + window <= (1024 * 128)) {- const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail);- if (buff == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < 0x40)- return (0);- continue;- }- p = buff + offset;- while (p + 7 < buff + bytes_avail) {- if (memcmp(p, RAR_SIGNATURE, 7) == 0)- return (30);- p += 0x10;- }- offset = p - buff;- }- }- return (0);-}--static int-skip_sfx(struct archive_read *a)-{- const void *h;- const char *p, *q;- size_t skip, total;- ssize_t bytes, window;-- total = 0;- window = 4096;- while (total + window <= (1024 * 128)) {- h = __archive_read_ahead(a, window, &bytes);- if (h == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < 0x40)- goto fatal;- continue;- }- if (bytes < 0x40)- goto fatal;- p = h;- q = p + bytes;-- /*- * Scan ahead until we find something that looks- * like the RAR header.- */- while (p + 7 < q) {- if (memcmp(p, RAR_SIGNATURE, 7) == 0) {- skip = p - (const char *)h;- __archive_read_consume(a, skip);- return (ARCHIVE_OK);- }- p += 0x10;- }- skip = p - (const char *)h;- __archive_read_consume(a, skip);- total += skip;- }-fatal:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Couldn't find out RAR header");- return (ARCHIVE_FATAL);-}--static int-archive_read_format_rar_options(struct archive_read *a,- const char *key, const char *val)-{- struct rar *rar;- int ret = ARCHIVE_FAILED;-- rar = (struct rar *)(a->format->data);- if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "rar: hdrcharset option needs a character-set name");- else {- rar->opt_sconv =- archive_string_conversion_from_charset(- &a->archive, val, 0);- if (rar->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-archive_read_format_rar_read_header(struct archive_read *a,- struct archive_entry *entry)-{- const void *h;- const char *p;- struct rar *rar;- size_t skip;- char head_type;- int ret;- unsigned flags;- unsigned long crc32_expected;-- a->archive.archive_format = ARCHIVE_FORMAT_RAR;- if (a->archive.archive_format_name == NULL)- a->archive.archive_format_name = "RAR";-- rar = (struct rar *)(a->format->data);-- /*- * It should be sufficient to call archive_read_next_header() for- * a reader to determine if an entry is encrypted or not. If the- * encryption of an entry is only detectable when calling- * archive_read_data(), so be it. We'll do the same check there- * as well.- */- if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {- rar->has_encrypted_entries = 0;- }-- /* RAR files can be generated without EOF headers, so return ARCHIVE_EOF if- * this fails.- */- if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)- return (ARCHIVE_EOF);-- p = h;- if (rar->found_first_header == 0 &&- ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0)) {- /* This is an executable ? Must be self-extracting... */- ret = skip_sfx(a);- if (ret < ARCHIVE_WARN)- return (ret);- }- rar->found_first_header = 1;-- while (1)- {- unsigned long crc32_val;-- if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)- return (ARCHIVE_FATAL);- p = h;-- head_type = p[2];- switch(head_type)- {- case MARK_HEAD:- if (memcmp(p, RAR_SIGNATURE, 7) != 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid marker header");- return (ARCHIVE_FATAL);- }- __archive_read_consume(a, 7);- break;-- case MAIN_HEAD:- rar->main_flags = archive_le16dec(p + 3);- skip = archive_le16dec(p + 5);- if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid header size");- return (ARCHIVE_FATAL);- }- if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)- return (ARCHIVE_FATAL);- p = h;- memcpy(rar->reserved1, p + 7, sizeof(rar->reserved1));- memcpy(rar->reserved2, p + 7 + sizeof(rar->reserved1),- sizeof(rar->reserved2));- if (rar->main_flags & MHD_ENCRYPTVER) {- if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)+1) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid header size");- return (ARCHIVE_FATAL);- }- rar->encryptver = *(p + 7 + sizeof(rar->reserved1) +- sizeof(rar->reserved2));- }-- /* Main header is password encrypted, so we cannot read any- file names or any other info about files from the header. */- if (rar->main_flags & MHD_PASSWORD)- {- archive_entry_set_is_metadata_encrypted(entry, 1);- archive_entry_set_is_data_encrypted(entry, 1);- rar->has_encrypted_entries = 1;- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "RAR encryption support unavailable.");- return (ARCHIVE_FATAL);- }-- crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);- if ((crc32_val & 0xffff) != archive_le16dec(p)) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Header CRC error");- return (ARCHIVE_FATAL);-#endif- }- __archive_read_consume(a, skip);- break;-- case FILE_HEAD:- return read_header(a, entry, head_type);-- case COMM_HEAD:- case AV_HEAD:- case SUB_HEAD:- case PROTECT_HEAD:- case SIGN_HEAD:- case ENDARC_HEAD:- flags = archive_le16dec(p + 3);- skip = archive_le16dec(p + 5);- if (skip < 7) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid header size too small");- return (ARCHIVE_FATAL);- }- if (flags & HD_ADD_SIZE_PRESENT)- {- if (skip < 7 + 4) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid header size too small");- return (ARCHIVE_FATAL);- }- if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)- return (ARCHIVE_FATAL);- p = h;- skip += archive_le32dec(p + 7);- }-- /* Skip over the 2-byte CRC at the beginning of the header. */- crc32_expected = archive_le16dec(p);- __archive_read_consume(a, 2);- skip -= 2;-- /* Skim the entire header and compute the CRC. */- crc32_val = 0;- while (skip > 0) {- size_t to_read = skip;- if (to_read > 32 * 1024)- to_read = 32 * 1024;- if ((h = __archive_read_ahead(a, to_read, NULL)) == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Bad RAR file");- return (ARCHIVE_FATAL);- }- p = h;- crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned int)to_read);- __archive_read_consume(a, to_read);- skip -= to_read;- }- if ((crc32_val & 0xffff) != crc32_expected) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Header CRC error");- return (ARCHIVE_FATAL);-#endif- }- if (head_type == ENDARC_HEAD)- return (ARCHIVE_EOF);- break;-- case NEWSUB_HEAD:- if ((ret = read_header(a, entry, head_type)) < ARCHIVE_WARN)- return ret;- break;-- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Bad RAR file");- return (ARCHIVE_FATAL);- }- }-}--static int-archive_read_format_rar_read_data(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset)-{- struct rar *rar = (struct rar *)(a->format->data);- int ret;-- if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {- rar->has_encrypted_entries = 0;- }-- if (rar->bytes_unconsumed > 0) {- /* Consume as much as the decompressor actually used. */- __archive_read_consume(a, rar->bytes_unconsumed);- rar->bytes_unconsumed = 0;- }-- *buff = NULL;- if (rar->entry_eof || rar->offset_seek >= rar->unp_size) {- *size = 0;- *offset = rar->offset;- if (*offset < rar->unp_size)- *offset = rar->unp_size;- return (ARCHIVE_EOF);- }-- switch (rar->compression_method)- {- case COMPRESS_METHOD_STORE:- ret = read_data_stored(a, buff, size, offset);- break;-- case COMPRESS_METHOD_FASTEST:- case COMPRESS_METHOD_FAST:- case COMPRESS_METHOD_NORMAL:- case COMPRESS_METHOD_GOOD:- case COMPRESS_METHOD_BEST:- ret = read_data_compressed(a, buff, size, offset, 0);- if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN) {- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);- rar->start_new_table = 1;- rar->ppmd_valid = 0;- }- break;-- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported compression method for RAR file.");- ret = ARCHIVE_FATAL;- break;- }- return (ret);-}--static int-archive_read_format_rar_read_data_skip(struct archive_read *a)-{- struct rar *rar;- int64_t bytes_skipped;- int ret;-- rar = (struct rar *)(a->format->data);-- if (rar->bytes_unconsumed > 0) {- /* Consume as much as the decompressor actually used. */- __archive_read_consume(a, rar->bytes_unconsumed);- rar->bytes_unconsumed = 0;- }-- if (rar->bytes_remaining > 0) {- bytes_skipped = __archive_read_consume(a, rar->bytes_remaining);- if (bytes_skipped < 0)- return (ARCHIVE_FATAL);- }-- /* Compressed data to skip must be read from each header in a multivolume- * archive.- */- if (rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER)- {- ret = archive_read_format_rar_read_header(a, a->entry);- if (ret == (ARCHIVE_EOF))- ret = archive_read_format_rar_read_header(a, a->entry);- if (ret != (ARCHIVE_OK))- return ret;- return archive_read_format_rar_read_data_skip(a);- }-- return (ARCHIVE_OK);-}--static int64_t-archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,- int whence)-{- int64_t client_offset, ret;- unsigned int i;- struct rar *rar = (struct rar *)(a->format->data);-- if (rar->compression_method == COMPRESS_METHOD_STORE)- {- /* Modify the offset for use with SEEK_SET */- switch (whence)- {- case SEEK_CUR:- client_offset = rar->offset_seek;- break;- case SEEK_END:- client_offset = rar->unp_size;- break;- case SEEK_SET:- default:- client_offset = 0;- }- client_offset += offset;- if (client_offset < 0)- {- /* Can't seek past beginning of data block */- return -1;- }- else if (client_offset > rar->unp_size)- {- /*- * Set the returned offset but only seek to the end of- * the data block.- */- rar->offset_seek = client_offset;- client_offset = rar->unp_size;- }-- client_offset += rar->dbo[0].start_offset;- i = 0;- while (i < rar->cursor)- {- i++;- client_offset += rar->dbo[i].start_offset - rar->dbo[i-1].end_offset;- }- if (rar->main_flags & MHD_VOLUME)- {- /* Find the appropriate offset among the multivolume archive */- while (1)- {- if (client_offset < rar->dbo[rar->cursor].start_offset &&- rar->file_flags & FHD_SPLIT_BEFORE)- {- /* Search backwards for the correct data block */- if (rar->cursor == 0)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Attempt to seek past beginning of RAR data block");- return (ARCHIVE_FAILED);- }- rar->cursor--;- client_offset -= rar->dbo[rar->cursor+1].start_offset -- rar->dbo[rar->cursor].end_offset;- if (client_offset < rar->dbo[rar->cursor].start_offset)- continue;- ret = __archive_read_seek(a, rar->dbo[rar->cursor].start_offset -- rar->dbo[rar->cursor].header_size, SEEK_SET);- if (ret < (ARCHIVE_OK))- return ret;- ret = archive_read_format_rar_read_header(a, a->entry);- if (ret != (ARCHIVE_OK))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Error during seek of RAR file");- return (ARCHIVE_FAILED);- }- rar->cursor--;- break;- }- else if (client_offset > rar->dbo[rar->cursor].end_offset &&- rar->file_flags & FHD_SPLIT_AFTER)- {- /* Search forward for the correct data block */- rar->cursor++;- if (rar->cursor < rar->nodes &&- client_offset > rar->dbo[rar->cursor].end_offset)- {- client_offset += rar->dbo[rar->cursor].start_offset -- rar->dbo[rar->cursor-1].end_offset;- continue;- }- rar->cursor--;- ret = __archive_read_seek(a, rar->dbo[rar->cursor].end_offset,- SEEK_SET);- if (ret < (ARCHIVE_OK))- return ret;- ret = archive_read_format_rar_read_header(a, a->entry);- if (ret == (ARCHIVE_EOF))- {- rar->has_endarc_header = 1;- ret = archive_read_format_rar_read_header(a, a->entry);- }- if (ret != (ARCHIVE_OK))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Error during seek of RAR file");- return (ARCHIVE_FAILED);- }- client_offset += rar->dbo[rar->cursor].start_offset -- rar->dbo[rar->cursor-1].end_offset;- continue;- }- break;- }- }-- ret = __archive_read_seek(a, client_offset, SEEK_SET);- if (ret < (ARCHIVE_OK))- return ret;- rar->bytes_remaining = rar->dbo[rar->cursor].end_offset - ret;- i = rar->cursor;- while (i > 0)- {- i--;- ret -= rar->dbo[i+1].start_offset - rar->dbo[i].end_offset;- }- ret -= rar->dbo[0].start_offset;-- /* Always restart reading the file after a seek */- __archive_reset_read_data(&a->archive);-- rar->bytes_unconsumed = 0;- rar->offset = 0;-- /*- * If a seek past the end of file was requested, return the requested- * offset.- */- if (ret == rar->unp_size && rar->offset_seek > rar->unp_size)- return rar->offset_seek;-- /* Return the new offset */- rar->offset_seek = ret;- return rar->offset_seek;- }- else- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Seeking of compressed RAR files is unsupported");- }- return (ARCHIVE_FAILED);-}--static int-archive_read_format_rar_cleanup(struct archive_read *a)-{- struct rar *rar;-- rar = (struct rar *)(a->format->data);- free_codes(a);- clear_filters(&rar->filters);- free(rar->filename);- free(rar->filename_save);- free(rar->dbo);- free(rar->unp_buffer);- free(rar->lzss.window);- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);- free(rar);- (a->format->data) = NULL;- return (ARCHIVE_OK);-}--static int-read_header(struct archive_read *a, struct archive_entry *entry,- char head_type)-{- const void *h;- const char *p, *endp;- struct rar *rar;- struct rar_header rar_header;- struct rar_file_header file_header;- int64_t header_size;- unsigned filename_size, end;- char *filename;- char *strp;- char packed_size[8];- char unp_size[8];- int ttime;- struct archive_string_conv *sconv, *fn_sconv;- unsigned long crc32_val;- int ret = (ARCHIVE_OK), ret2;-- rar = (struct rar *)(a->format->data);-- /* Setup a string conversion object for non-rar-unicode filenames. */- sconv = rar->opt_sconv;- if (sconv == NULL) {- if (!rar->init_default_conversion) {- rar->sconv_default =- archive_string_default_conversion_for_read(- &(a->archive));- rar->init_default_conversion = 1;- }- sconv = rar->sconv_default;- }--- if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)- return (ARCHIVE_FATAL);- p = h;- memcpy(&rar_header, p, sizeof(rar_header));- rar->file_flags = archive_le16dec(rar_header.flags);- header_size = archive_le16dec(rar_header.size);- if (header_size < (int64_t)sizeof(file_header) + 7) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid header size");- return (ARCHIVE_FATAL);- }- crc32_val = crc32(0, (const unsigned char *)p + 2, 7 - 2);- __archive_read_consume(a, 7);-- if (!(rar->file_flags & FHD_SOLID))- {- rar->compression_method = 0;- rar->packed_size = 0;- rar->unp_size = 0;- rar->mtime = 0;- rar->ctime = 0;- rar->atime = 0;- rar->arctime = 0;- rar->mode = 0;- memset(&rar->salt, 0, sizeof(rar->salt));- rar->atime = 0;- rar->ansec = 0;- rar->ctime = 0;- rar->cnsec = 0;- rar->mtime = 0;- rar->mnsec = 0;- rar->arctime = 0;- rar->arcnsec = 0;- }- else- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "RAR solid archive support unavailable.");- return (ARCHIVE_FATAL);- }-- if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)- return (ARCHIVE_FATAL);-- /* File Header CRC check. */- crc32_val = crc32(crc32_val, h, (unsigned)(header_size - 7));- if ((crc32_val & 0xffff) != archive_le16dec(rar_header.crc)) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Header CRC error");- return (ARCHIVE_FATAL);-#endif- }- /* If no CRC error, Go on parsing File Header. */- p = h;- endp = p + header_size - 7;- memcpy(&file_header, p, sizeof(file_header));- p += sizeof(file_header);-- rar->compression_method = file_header.method;-- ttime = archive_le32dec(file_header.file_time);- rar->mtime = get_time(ttime);-- rar->file_crc = archive_le32dec(file_header.file_crc);-- if (rar->file_flags & FHD_PASSWORD)- {- archive_entry_set_is_data_encrypted(entry, 1);- rar->has_encrypted_entries = 1;- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "RAR encryption support unavailable.");- /* Since it is only the data part itself that is encrypted we can at least- extract information about the currently processed entry and don't need- to return ARCHIVE_FATAL here. */- /*return (ARCHIVE_FATAL);*/- }-- if (rar->file_flags & FHD_LARGE)- {- memcpy(packed_size, file_header.pack_size, 4);- memcpy(packed_size + 4, p, 4); /* High pack size */- p += 4;- memcpy(unp_size, file_header.unp_size, 4);- memcpy(unp_size + 4, p, 4); /* High unpack size */- p += 4;- rar->packed_size = archive_le64dec(&packed_size);- rar->unp_size = archive_le64dec(&unp_size);- }- else- {- rar->packed_size = archive_le32dec(file_header.pack_size);- rar->unp_size = archive_le32dec(file_header.unp_size);- }-- if (rar->packed_size < 0 || rar->unp_size < 0)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid sizes specified.");- return (ARCHIVE_FATAL);- }-- rar->bytes_remaining = rar->packed_size;-- /* TODO: RARv3 subblocks contain comments. For now the complete block is- * consumed at the end.- */- if (head_type == NEWSUB_HEAD) {- size_t distance = p - (const char *)h;- header_size += rar->packed_size;- /* Make sure we have the extended data. */- if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)- return (ARCHIVE_FATAL);- p = h;- endp = p + header_size - 7;- p += distance;- }-- filename_size = archive_le16dec(file_header.name_size);- if (p + filename_size > endp) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid filename size");- return (ARCHIVE_FATAL);- }- if (rar->filename_allocated < filename_size * 2 + 2) {- char *newptr;- size_t newsize = filename_size * 2 + 2;- newptr = realloc(rar->filename, newsize);- if (newptr == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Couldn't allocate memory.");- return (ARCHIVE_FATAL);- }- rar->filename = newptr;- rar->filename_allocated = newsize;- }- filename = rar->filename;- memcpy(filename, p, filename_size);- filename[filename_size] = '\0';- if (rar->file_flags & FHD_UNICODE)- {- if (filename_size != strlen(filename))- {- unsigned char highbyte, flagbits, flagbyte;- unsigned fn_end, offset;-- end = filename_size;- fn_end = filename_size * 2;- filename_size = 0;- offset = (unsigned)strlen(filename) + 1;- highbyte = *(p + offset++);- flagbits = 0;- flagbyte = 0;- while (offset < end && filename_size < fn_end)- {- if (!flagbits)- {- flagbyte = *(p + offset++);- flagbits = 8;- }-- flagbits -= 2;- switch((flagbyte >> flagbits) & 3)- {- case 0:- filename[filename_size++] = '\0';- filename[filename_size++] = *(p + offset++);- break;- case 1:- filename[filename_size++] = highbyte;- filename[filename_size++] = *(p + offset++);- break;- case 2:- filename[filename_size++] = *(p + offset + 1);- filename[filename_size++] = *(p + offset);- offset += 2;- break;- case 3:- {- char extra, high;- uint8_t length = *(p + offset++);-- if (length & 0x80) {- extra = *(p + offset++);- high = (char)highbyte;- } else- extra = high = 0;- length = (length & 0x7f) + 2;- while (length && filename_size < fn_end) {- unsigned cp = filename_size >> 1;- filename[filename_size++] = high;- filename[filename_size++] = p[cp] + extra;- length--;- }- }- break;- }- }- if (filename_size > fn_end) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid filename");- return (ARCHIVE_FATAL);- }- filename[filename_size++] = '\0';- /*- * Do not increment filename_size here as the computations below- * add the space for the terminating NUL explicitly.- */- filename[filename_size] = '\0';-- /* Decoded unicode form is UTF-16BE, so we have to update a string- * conversion object for it. */- if (rar->sconv_utf16be == NULL) {- rar->sconv_utf16be = archive_string_conversion_from_charset(- &a->archive, "UTF-16BE", 1);- if (rar->sconv_utf16be == NULL)- return (ARCHIVE_FATAL);- }- fn_sconv = rar->sconv_utf16be;-- strp = filename;- while (memcmp(strp, "\x00\x00", 2))- {- if (!memcmp(strp, "\x00\\", 2))- *(strp + 1) = '/';- strp += 2;- }- p += offset;- } else {- /*- * If FHD_UNICODE is set but no unicode data, this file name form- * is UTF-8, so we have to update a string conversion object for- * it accordingly.- */- if (rar->sconv_utf8 == NULL) {- rar->sconv_utf8 = archive_string_conversion_from_charset(- &a->archive, "UTF-8", 1);- if (rar->sconv_utf8 == NULL)- return (ARCHIVE_FATAL);- }- fn_sconv = rar->sconv_utf8;- while ((strp = strchr(filename, '\\')) != NULL)- *strp = '/';- p += filename_size;- }- }- else- {- fn_sconv = sconv;- while ((strp = strchr(filename, '\\')) != NULL)- *strp = '/';- p += filename_size;- }-- /* Split file in multivolume RAR. No more need to process header. */- if (rar->filename_save &&- filename_size == rar->filename_save_size &&- !memcmp(rar->filename, rar->filename_save, filename_size + 1))- {- __archive_read_consume(a, header_size - 7);- rar->cursor++;- if (rar->cursor >= rar->nodes)- {- rar->nodes++;- if ((rar->dbo =- realloc(rar->dbo, sizeof(*rar->dbo) * rar->nodes)) == NULL)- {- archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");- return (ARCHIVE_FATAL);- }- rar->dbo[rar->cursor].header_size = header_size;- rar->dbo[rar->cursor].start_offset = -1;- rar->dbo[rar->cursor].end_offset = -1;- }- if (rar->dbo[rar->cursor].start_offset < 0)- {- rar->dbo[rar->cursor].start_offset = a->filter->position;- rar->dbo[rar->cursor].end_offset = rar->dbo[rar->cursor].start_offset +- rar->packed_size;- }- return ret;- }- else if (rar->filename_must_match)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Mismatch of file parts split across multi-volume archive");- return (ARCHIVE_FATAL);- }-- rar->filename_save = (char*)realloc(rar->filename_save,- filename_size + 1);- memcpy(rar->filename_save, rar->filename, filename_size + 1);- rar->filename_save_size = filename_size;-- /* Set info for seeking */- free(rar->dbo);- if ((rar->dbo = calloc(1, sizeof(*rar->dbo))) == NULL)- {- archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");- return (ARCHIVE_FATAL);- }- rar->dbo[0].header_size = header_size;- rar->dbo[0].start_offset = -1;- rar->dbo[0].end_offset = -1;- rar->cursor = 0;- rar->nodes = 1;-- if (rar->file_flags & FHD_SALT)- {- if (p + 8 > endp) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid header size");- return (ARCHIVE_FATAL);- }- memcpy(rar->salt, p, 8);- p += 8;- }-- if (rar->file_flags & FHD_EXTTIME) {- if (read_exttime(p, rar, endp) < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid header size");- return (ARCHIVE_FATAL);- }- }-- __archive_read_consume(a, header_size - 7);- rar->dbo[0].start_offset = a->filter->position;- rar->dbo[0].end_offset = rar->dbo[0].start_offset + rar->packed_size;-- switch(file_header.host_os)- {- case OS_MSDOS:- case OS_OS2:- case OS_WIN32:- rar->mode = archive_le32dec(file_header.file_attr);- if (rar->mode & FILE_ATTRIBUTE_DIRECTORY)- rar->mode = AE_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;- else- rar->mode = AE_IFREG;- rar->mode |= S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;- break;-- case OS_UNIX:- case OS_MAC_OS:- case OS_BEOS:- rar->mode = archive_le32dec(file_header.file_attr);- break;-- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unknown file attributes from RAR file's host OS");- return (ARCHIVE_FATAL);- }-- rar->bytes_uncopied = rar->bytes_unconsumed = 0;- rar->lzss.position = rar->offset = 0;- rar->offset_seek = 0;- rar->dictionary_size = 0;- rar->offset_outgoing = 0;- rar->br.cache_avail = 0;- rar->br.avail_in = 0;- rar->crc_calculated = 0;- rar->entry_eof = 0;- rar->valid = 1;- rar->is_ppmd_block = 0;- rar->start_new_table = 1;- free(rar->unp_buffer);- rar->unp_buffer = NULL;- rar->unp_offset = 0;- rar->unp_buffer_size = UNP_BUFFER_SIZE;- memset(rar->lengthtable, 0, sizeof(rar->lengthtable));- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);- rar->ppmd_valid = rar->ppmd_eod = 0;- rar->filters.filterstart = INT64_MAX;-- /* Don't set any archive entries for non-file header types */- if (head_type == NEWSUB_HEAD)- return ret;-- archive_entry_set_mtime(entry, rar->mtime, rar->mnsec);- archive_entry_set_ctime(entry, rar->ctime, rar->cnsec);- archive_entry_set_atime(entry, rar->atime, rar->ansec);- archive_entry_set_size(entry, rar->unp_size);- archive_entry_set_mode(entry, rar->mode);-- if (archive_entry_copy_pathname_l(entry, filename, filename_size, fn_sconv))- {- if (errno == ENOMEM)- {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname cannot be converted from %s to current locale.",- archive_string_conversion_charset_name(fn_sconv));- ret = (ARCHIVE_WARN);- }-- if (((rar->mode) & AE_IFMT) == AE_IFLNK)- {- /* Make sure a symbolic-link file does not have its body. */- rar->bytes_remaining = 0;- archive_entry_set_size(entry, 0);-- /* Read a symbolic-link name. */- if ((ret2 = read_symlink_stored(a, entry, sconv)) < (ARCHIVE_WARN))- return ret2;- if (ret > ret2)- ret = ret2;- }-- if (rar->bytes_remaining == 0)- rar->entry_eof = 1;-- return ret;-}--static time_t-get_time(int ttime)-{- struct tm tm;- tm.tm_sec = 2 * (ttime & 0x1f);- tm.tm_min = (ttime >> 5) & 0x3f;- tm.tm_hour = (ttime >> 11) & 0x1f;- tm.tm_mday = (ttime >> 16) & 0x1f;- tm.tm_mon = ((ttime >> 21) & 0x0f) - 1;- tm.tm_year = ((ttime >> 25) & 0x7f) + 80;- tm.tm_isdst = -1;- return mktime(&tm);-}--static int-read_exttime(const char *p, struct rar *rar, const char *endp)-{- unsigned rmode, flags, rem, j, count;- int ttime, i;- struct tm *tm;- time_t t;- long nsec;-#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)- struct tm tmbuf;-#endif-- if (p + 2 > endp)- return (-1);- flags = archive_le16dec(p);- p += 2;-- for (i = 3; i >= 0; i--)- {- t = 0;- if (i == 3)- t = rar->mtime;- rmode = flags >> i * 4;- if (rmode & 8)- {- if (!t)- {- if (p + 4 > endp)- return (-1);- ttime = archive_le32dec(p);- t = get_time(ttime);- p += 4;- }- rem = 0;- count = rmode & 3;- if (p + count > endp)- return (-1);- for (j = 0; j < count; j++)- {- rem = (((unsigned)(unsigned char)*p) << 16) | (rem >> 8);- p++;- }-#if defined(HAVE_LOCALTIME_S)- tm = localtime_s(&tmbuf, &t) ? NULL : &tmbuf;-#elif defined(HAVE_LOCALTIME_R)- tm = localtime_r(&t, &tmbuf);-#else- tm = localtime(&t);-#endif- nsec = tm->tm_sec + rem / NS_UNIT;- if (rmode & 4)- {- tm->tm_sec++;- t = mktime(tm);- }- if (i == 3)- {- rar->mtime = t;- rar->mnsec = nsec;- }- else if (i == 2)- {- rar->ctime = t;- rar->cnsec = nsec;- }- else if (i == 1)- {- rar->atime = t;- rar->ansec = nsec;- }- else- {- rar->arctime = t;- rar->arcnsec = nsec;- }- }- }- return (0);-}--static int-read_symlink_stored(struct archive_read *a, struct archive_entry *entry,- struct archive_string_conv *sconv)-{- const void *h;- const char *p;- struct rar *rar;- int ret = (ARCHIVE_OK);-- rar = (struct rar *)(a->format->data);- if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL)- return (ARCHIVE_FATAL);- p = h;-- if (archive_entry_copy_symlink_l(entry,- p, (size_t)rar->packed_size, sconv))- {- if (errno == ENOMEM)- {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for link");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "link cannot be converted from %s to current locale.",- archive_string_conversion_charset_name(sconv));- ret = (ARCHIVE_WARN);- }- __archive_read_consume(a, rar->packed_size);- return ret;-}--static int-read_data_stored(struct archive_read *a, const void **buff, size_t *size,- int64_t *offset)-{- struct rar *rar;- ssize_t bytes_avail;-- rar = (struct rar *)(a->format->data);- if (rar->bytes_remaining == 0 &&- !(rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER))- {- *buff = NULL;- *size = 0;- *offset = rar->offset;- if (rar->file_crc != rar->crc_calculated) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "File CRC error");- return (ARCHIVE_FATAL);-#endif- }- rar->entry_eof = 1;- return (ARCHIVE_EOF);- }-- *buff = rar_read_ahead(a, 1, &bytes_avail);- if (bytes_avail <= 0)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated RAR file data");- return (ARCHIVE_FATAL);- }-- *size = bytes_avail;- *offset = rar->offset;- rar->offset += bytes_avail;- rar->offset_seek += bytes_avail;- rar->bytes_remaining -= bytes_avail;- rar->bytes_unconsumed = bytes_avail;- /* Calculate File CRC. */- rar->crc_calculated = crc32(rar->crc_calculated, *buff,- (unsigned)bytes_avail);- return (ARCHIVE_OK);-}--static int-read_data_compressed(struct archive_read *a, const void **buff, size_t *size,- int64_t *offset, size_t looper)-{- if (looper++ > MAX_COMPRESS_DEPTH)- return (ARCHIVE_FATAL);-- struct rar *rar;- int64_t start, end;- size_t bs;- int ret = (ARCHIVE_OK), sym, code, lzss_offset, length, i;-- rar = (struct rar *)(a->format->data);-- do {- if (!rar->valid)- return (ARCHIVE_FATAL);-- if (rar->filters.bytes_ready > 0)- {- /* Flush unp_buffer first */- if (rar->unp_offset > 0)- {- *buff = rar->unp_buffer;- *size = rar->unp_offset;- rar->unp_offset = 0;- *offset = rar->offset_outgoing;- rar->offset_outgoing += *size;- }- else- {- *buff = rar->filters.bytes;- *size = rar->filters.bytes_ready;-- rar->offset += *size;- *offset = rar->offset_outgoing;- rar->offset_outgoing += *size;-- rar->filters.bytes_ready -= *size;- rar->filters.bytes += *size;- }- goto ending_block;- }-- if (rar->ppmd_eod ||- (rar->dictionary_size && rar->offset >= rar->unp_size))- {- if (rar->unp_offset > 0) {- /*- * We have unprocessed extracted data. write it out.- */- *buff = rar->unp_buffer;- *size = rar->unp_offset;- *offset = rar->offset_outgoing;- rar->offset_outgoing += *size;- /* Calculate File CRC. */- rar->crc_calculated = crc32(rar->crc_calculated, *buff,- (unsigned)*size);- rar->unp_offset = 0;- return (ARCHIVE_OK);- }- *buff = NULL;- *size = 0;- *offset = rar->offset;- if (rar->file_crc != rar->crc_calculated) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "File CRC error");- return (ARCHIVE_FATAL);-#endif- }- rar->entry_eof = 1;- return (ARCHIVE_EOF);- }-- if (!rar->is_ppmd_block && rar->dictionary_size && rar->bytes_uncopied > 0)- {- if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))- bs = rar->unp_buffer_size - rar->unp_offset;- else- bs = (size_t)rar->bytes_uncopied;- ret = copy_from_lzss_window_to_unp(a, buff, rar->offset, (int)bs);- if (ret != ARCHIVE_OK)- return (ret);- rar->offset += bs;- rar->bytes_uncopied -= bs;- if (*buff != NULL) {- rar->unp_offset = 0;- *size = rar->unp_buffer_size;- *offset = rar->offset_outgoing;- rar->offset_outgoing += *size;- /* Calculate File CRC. */- rar->crc_calculated = crc32(rar->crc_calculated, *buff,- (unsigned)*size);- return (ret);- }- continue;- }-- if (rar->filters.lastend == rar->filters.filterstart)- {- if (!run_filters(a))- return (ARCHIVE_FATAL);- continue;- }-- if (!rar->br.next_in &&- (ret = rar_br_preparation(a, &(rar->br))) < ARCHIVE_WARN)- return (ret);- if (rar->start_new_table && ((ret = parse_codes(a)) < (ARCHIVE_WARN)))- return (ret);-- if (rar->is_ppmd_block)- {- if ((sym = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(- &rar->ppmd7_context, &rar->range_dec.p)) < 0)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid symbol");- return (ARCHIVE_FATAL);- }- if(sym != rar->ppmd_escape)- {- lzss_emit_literal(rar, sym);- rar->bytes_uncopied++;- }- else- {- if ((code = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(- &rar->ppmd7_context, &rar->range_dec.p)) < 0)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid symbol");- return (ARCHIVE_FATAL);- }-- switch(code)- {- case 0:- rar->start_new_table = 1;- return read_data_compressed(a, buff, size, offset, looper);-- case 2:- rar->ppmd_eod = 1;/* End Of ppmd Data. */- continue;-- case 3:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Parsing filters is unsupported.");- return (ARCHIVE_FAILED);-- case 4:- lzss_offset = 0;- for (i = 2; i >= 0; i--)- {- if ((code = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(- &rar->ppmd7_context, &rar->range_dec.p)) < 0)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid symbol");- return (ARCHIVE_FATAL);- }- lzss_offset |= code << (i * 8);- }- if ((length = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(- &rar->ppmd7_context, &rar->range_dec.p)) < 0)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid symbol");- return (ARCHIVE_FATAL);- }- lzss_emit_match(rar, lzss_offset + 2, length + 32);- rar->bytes_uncopied += length + 32;- break;-- case 5:- if ((length = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(- &rar->ppmd7_context, &rar->range_dec.p)) < 0)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid symbol");- return (ARCHIVE_FATAL);- }- lzss_emit_match(rar, 1, length + 4);- rar->bytes_uncopied += length + 4;- break;-- default:- lzss_emit_literal(rar, sym);- rar->bytes_uncopied++;- }- }- }- else- {- start = rar->offset;- end = start + rar->dictionary_size;- if (rar->filters.filterstart < end) {- end = rar->filters.filterstart;- }-- ret = expand(a, &end);- if (ret != ARCHIVE_OK)- return (ret);-- rar->bytes_uncopied = end - start;- rar->filters.lastend = end;- if (rar->filters.lastend != rar->filters.filterstart && rar->bytes_uncopied == 0) {- /* Broken RAR files cause this case.- * NOTE: If this case were possible on a normal RAR file- * we would find out where it was actually bad and- * what we would do to solve it. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Internal error extracting RAR file");- return (ARCHIVE_FATAL);- }- }- if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))- bs = rar->unp_buffer_size - rar->unp_offset;- else- bs = (size_t)rar->bytes_uncopied;- ret = copy_from_lzss_window_to_unp(a, buff, rar->offset, (int)bs);- if (ret != ARCHIVE_OK)- return (ret);- rar->offset += bs;- rar->bytes_uncopied -= bs;- /*- * If *buff is NULL, it means unp_buffer is not full.- * So we have to continue extracting a RAR file.- */- } while (*buff == NULL);-- rar->unp_offset = 0;- *size = rar->unp_buffer_size;- *offset = rar->offset_outgoing;- rar->offset_outgoing += *size;-ending_block:- /* Calculate File CRC. */- rar->crc_calculated = crc32(rar->crc_calculated, *buff, (unsigned)*size);- return ret;-}--static int-parse_codes(struct archive_read *a)-{- int i, j, val, n, r;- unsigned char bitlengths[MAX_SYMBOLS], zerocount, ppmd_flags;- unsigned int maxorder;- struct huffman_code precode;- struct rar *rar = (struct rar *)(a->format->data);- struct rar_br *br = &(rar->br);-- free_codes(a);-- /* Skip to the next byte */- rar_br_consume_unalined_bits(br);-- /* PPMd block flag */- if (!rar_br_read_ahead(a, br, 1))- goto truncated_data;- if ((rar->is_ppmd_block = rar_br_bits(br, 1)) != 0)- {- rar_br_consume(br, 1);- if (!rar_br_read_ahead(a, br, 7))- goto truncated_data;- ppmd_flags = rar_br_bits(br, 7);- rar_br_consume(br, 7);-- /* Memory is allocated in MB */- if (ppmd_flags & 0x20)- {- if (!rar_br_read_ahead(a, br, 8))- goto truncated_data;- rar->dictionary_size = (rar_br_bits(br, 8) + 1) << 20;- rar_br_consume(br, 8);- }-- if (ppmd_flags & 0x40)- {- if (!rar_br_read_ahead(a, br, 8))- goto truncated_data;- rar->ppmd_escape = rar->ppmd7_context.InitEsc = rar_br_bits(br, 8);- rar_br_consume(br, 8);- }- else- rar->ppmd_escape = 2;-- if (ppmd_flags & 0x20)- {- maxorder = (ppmd_flags & 0x1F) + 1;- if(maxorder > 16)- maxorder = 16 + (maxorder - 16) * 3;-- if (maxorder == 1)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated RAR file data");- return (ARCHIVE_FATAL);- }-- /* Make sure ppmd7_contest is freed before Ppmd7_Construct- * because reading a broken file cause this abnormal sequence. */- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);-- rar->bytein.a = a;- rar->bytein.Read = &ppmd_read;- __archive_ppmd7_functions.PpmdRAR_RangeDec_CreateVTable(&rar->range_dec);- rar->range_dec.Stream = &rar->bytein;- __archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context);-- if (rar->dictionary_size == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid zero dictionary size");- return (ARCHIVE_FATAL);- }-- if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,- rar->dictionary_size))- {- archive_set_error(&a->archive, ENOMEM,- "Out of memory");- return (ARCHIVE_FATAL);- }- if (!__archive_ppmd7_functions.PpmdRAR_RangeDec_Init(&rar->range_dec))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unable to initialize PPMd range decoder");- return (ARCHIVE_FATAL);- }- __archive_ppmd7_functions.Ppmd7_Init(&rar->ppmd7_context, maxorder);- rar->ppmd_valid = 1;- }- else- {- if (!rar->ppmd_valid) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid PPMd sequence");- return (ARCHIVE_FATAL);- }- if (!__archive_ppmd7_functions.PpmdRAR_RangeDec_Init(&rar->range_dec))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unable to initialize PPMd range decoder");- return (ARCHIVE_FATAL);- }- }- }- else- {- rar_br_consume(br, 1);-- /* Keep existing table flag */- if (!rar_br_read_ahead(a, br, 1))- goto truncated_data;- if (!rar_br_bits(br, 1))- memset(rar->lengthtable, 0, sizeof(rar->lengthtable));- rar_br_consume(br, 1);-- memset(&bitlengths, 0, sizeof(bitlengths));- for (i = 0; i < MAX_SYMBOLS;)- {- if (!rar_br_read_ahead(a, br, 4))- goto truncated_data;- bitlengths[i++] = rar_br_bits(br, 4);- rar_br_consume(br, 4);- if (bitlengths[i-1] == 0xF)- {- if (!rar_br_read_ahead(a, br, 4))- goto truncated_data;- zerocount = rar_br_bits(br, 4);- rar_br_consume(br, 4);- if (zerocount)- {- i--;- for (j = 0; j < zerocount + 2 && i < MAX_SYMBOLS; j++)- bitlengths[i++] = 0;- }- }- }-- memset(&precode, 0, sizeof(precode));- r = create_code(a, &precode, bitlengths, MAX_SYMBOLS, MAX_SYMBOL_LENGTH);- if (r != ARCHIVE_OK) {- free(precode.tree);- free(precode.table);- return (r);- }-- for (i = 0; i < HUFFMAN_TABLE_SIZE;)- {- if ((val = read_next_symbol(a, &precode)) < 0) {- free(precode.tree);- free(precode.table);- return (ARCHIVE_FATAL);- }- if (val < 16)- {- rar->lengthtable[i] = (rar->lengthtable[i] + val) & 0xF;- i++;- }- else if (val < 18)- {- if (i == 0)- {- free(precode.tree);- free(precode.table);- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Internal error extracting RAR file.");- return (ARCHIVE_FATAL);- }-- if(val == 16) {- if (!rar_br_read_ahead(a, br, 3)) {- free(precode.tree);- free(precode.table);- goto truncated_data;- }- n = rar_br_bits(br, 3) + 3;- rar_br_consume(br, 3);- } else {- if (!rar_br_read_ahead(a, br, 7)) {- free(precode.tree);- free(precode.table);- goto truncated_data;- }- n = rar_br_bits(br, 7) + 11;- rar_br_consume(br, 7);- }-- for (j = 0; j < n && i < HUFFMAN_TABLE_SIZE; j++)- {- rar->lengthtable[i] = rar->lengthtable[i-1];- i++;- }- }- else- {- if(val == 18) {- if (!rar_br_read_ahead(a, br, 3)) {- free(precode.tree);- free(precode.table);- goto truncated_data;- }- n = rar_br_bits(br, 3) + 3;- rar_br_consume(br, 3);- } else {- if (!rar_br_read_ahead(a, br, 7)) {- free(precode.tree);- free(precode.table);- goto truncated_data;- }- n = rar_br_bits(br, 7) + 11;- rar_br_consume(br, 7);- }-- for(j = 0; j < n && i < HUFFMAN_TABLE_SIZE; j++)- rar->lengthtable[i++] = 0;- }- }- free(precode.tree);- free(precode.table);-- r = create_code(a, &rar->maincode, &rar->lengthtable[0], MAINCODE_SIZE,- MAX_SYMBOL_LENGTH);- if (r != ARCHIVE_OK)- return (r);- r = create_code(a, &rar->offsetcode, &rar->lengthtable[MAINCODE_SIZE],- OFFSETCODE_SIZE, MAX_SYMBOL_LENGTH);- if (r != ARCHIVE_OK)- return (r);- r = create_code(a, &rar->lowoffsetcode,- &rar->lengthtable[MAINCODE_SIZE + OFFSETCODE_SIZE],- LOWOFFSETCODE_SIZE, MAX_SYMBOL_LENGTH);- if (r != ARCHIVE_OK)- return (r);- r = create_code(a, &rar->lengthcode,- &rar->lengthtable[MAINCODE_SIZE + OFFSETCODE_SIZE +- LOWOFFSETCODE_SIZE], LENGTHCODE_SIZE, MAX_SYMBOL_LENGTH);- if (r != ARCHIVE_OK)- return (r);- }-- if (!rar->dictionary_size || !rar->lzss.window)- {- /* Seems as though dictionary sizes are not used. Even so, minimize- * memory usage as much as possible.- */- void *new_window;- unsigned int new_size;-- if (rar->unp_size >= DICTIONARY_MAX_SIZE)- new_size = DICTIONARY_MAX_SIZE;- else- new_size = rar_fls((unsigned int)rar->unp_size) << 1;- if (new_size == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Zero window size is invalid.");- return (ARCHIVE_FATAL);- }- new_window = realloc(rar->lzss.window, new_size);- if (new_window == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Unable to allocate memory for uncompressed data.");- return (ARCHIVE_FATAL);- }- rar->lzss.window = (unsigned char *)new_window;- rar->dictionary_size = new_size;- memset(rar->lzss.window, 0, rar->dictionary_size);- rar->lzss.mask = rar->dictionary_size - 1;- }-- rar->start_new_table = 0;- return (ARCHIVE_OK);-truncated_data:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated RAR file data");- rar->valid = 0;- return (ARCHIVE_FATAL);-}--static void-free_codes(struct archive_read *a)-{- struct rar *rar = (struct rar *)(a->format->data);- free(rar->maincode.tree);- free(rar->offsetcode.tree);- free(rar->lowoffsetcode.tree);- free(rar->lengthcode.tree);- free(rar->maincode.table);- free(rar->offsetcode.table);- free(rar->lowoffsetcode.table);- free(rar->lengthcode.table);- memset(&rar->maincode, 0, sizeof(rar->maincode));- memset(&rar->offsetcode, 0, sizeof(rar->offsetcode));- memset(&rar->lowoffsetcode, 0, sizeof(rar->lowoffsetcode));- memset(&rar->lengthcode, 0, sizeof(rar->lengthcode));-}---static int-read_next_symbol(struct archive_read *a, struct huffman_code *code)-{- unsigned char bit;- unsigned int bits;- int length, value, node;- struct rar *rar;- struct rar_br *br;-- if (!code->table)- {- if (make_table(a, code) != (ARCHIVE_OK))- return -1;- }-- rar = (struct rar *)(a->format->data);- br = &(rar->br);-- /* Look ahead (peek) at bits */- if (!rar_br_read_ahead(a, br, code->tablesize)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated RAR file data");- rar->valid = 0;- return -1;- }- bits = rar_br_bits(br, code->tablesize);-- length = code->table[bits].length;- value = code->table[bits].value;-- if (length < 0)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid prefix code in bitstream");- return -1;- }-- if (length <= code->tablesize)- {- /* Skip length bits */- rar_br_consume(br, length);- return value;- }-- /* Skip tablesize bits */- rar_br_consume(br, code->tablesize);-- node = value;- while (!(code->tree[node].branches[0] ==- code->tree[node].branches[1]))- {- if (!rar_br_read_ahead(a, br, 1)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated RAR file data");- rar->valid = 0;- return -1;- }- bit = rar_br_bits(br, 1);- rar_br_consume(br, 1);-- if (code->tree[node].branches[bit] < 0)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid prefix code in bitstream");- return -1;- }- node = code->tree[node].branches[bit];- }-- return code->tree[node].branches[0];-}--static int-create_code(struct archive_read *a, struct huffman_code *code,- unsigned char *lengths, int numsymbols, char maxlength)-{- int i, j, codebits = 0, symbolsleft = numsymbols;-- code->numentries = 0;- code->numallocatedentries = 0;- if (new_node(code) < 0) {- archive_set_error(&a->archive, ENOMEM,- "Unable to allocate memory for node data.");- return (ARCHIVE_FATAL);- }- code->numentries = 1;- code->minlength = INT_MAX;- code->maxlength = INT_MIN;- codebits = 0;- for(i = 1; i <= maxlength; i++)- {- for(j = 0; j < numsymbols; j++)- {- if (lengths[j] != i) continue;- if (add_value(a, code, j, codebits, i) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- codebits++;- if (--symbolsleft <= 0)- break;- }- if (symbolsleft <= 0)- break;- codebits <<= 1;- }- return (ARCHIVE_OK);-}--static int-add_value(struct archive_read *a, struct huffman_code *code, int value,- int codebits, int length)-{- int lastnode, bitpos, bit;- /* int repeatpos, repeatnode, nextnode; */-- free(code->table);- code->table = NULL;-- if(length > code->maxlength)- code->maxlength = length;- if(length < code->minlength)- code->minlength = length;-- /*- * Dead code, repeatpos was is -1- *- repeatpos = -1;- if (repeatpos == 0 || (repeatpos >= 0- && (((codebits >> (repeatpos - 1)) & 3) == 0- || ((codebits >> (repeatpos - 1)) & 3) == 3)))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid repeat position");- return (ARCHIVE_FATAL);- }- */-- lastnode = 0;- for (bitpos = length - 1; bitpos >= 0; bitpos--)- {- bit = (codebits >> bitpos) & 1;-- /* Leaf node check */- if (code->tree[lastnode].branches[0] ==- code->tree[lastnode].branches[1])- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Prefix found");- return (ARCHIVE_FATAL);- }-- /*- * Dead code, repeatpos was -1, bitpos >=0- *- if (bitpos == repeatpos)- {- * Open branch check *- if (!(code->tree[lastnode].branches[bit] < 0))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid repeating code");- return (ARCHIVE_FATAL);- }-- if ((repeatnode = new_node(code)) < 0) {- archive_set_error(&a->archive, ENOMEM,- "Unable to allocate memory for node data.");- return (ARCHIVE_FATAL);- }- if ((nextnode = new_node(code)) < 0) {- archive_set_error(&a->archive, ENOMEM,- "Unable to allocate memory for node data.");- return (ARCHIVE_FATAL);- }-- * Set branches *- code->tree[lastnode].branches[bit] = repeatnode;- code->tree[repeatnode].branches[bit] = repeatnode;- code->tree[repeatnode].branches[bit^1] = nextnode;- lastnode = nextnode;-- bitpos++; * terminating bit already handled, skip it *- }- else- {- */- /* Open branch check */- if (code->tree[lastnode].branches[bit] < 0)- {- if (new_node(code) < 0) {- archive_set_error(&a->archive, ENOMEM,- "Unable to allocate memory for node data.");- return (ARCHIVE_FATAL);- }- code->tree[lastnode].branches[bit] = code->numentries++;- }-- /* set to branch */- lastnode = code->tree[lastnode].branches[bit];- /* } */- }-- if (!(code->tree[lastnode].branches[0] == -1- && code->tree[lastnode].branches[1] == -2))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Prefix found");- return (ARCHIVE_FATAL);- }-- /* Set leaf value */- code->tree[lastnode].branches[0] = value;- code->tree[lastnode].branches[1] = value;-- return (ARCHIVE_OK);-}--static int-new_node(struct huffman_code *code)-{- void *new_tree;- if (code->numallocatedentries == code->numentries) {- int new_num_entries = 256;- if (code->numentries > 0) {- new_num_entries = code->numentries * 2;- }- new_tree = realloc(code->tree, new_num_entries * sizeof(*code->tree));- if (new_tree == NULL)- return (-1);- code->tree = (struct huffman_tree_node *)new_tree;- code->numallocatedentries = new_num_entries;- }- code->tree[code->numentries].branches[0] = -1;- code->tree[code->numentries].branches[1] = -2;- return 1;-}--static int-make_table(struct archive_read *a, struct huffman_code *code)-{- if (code->maxlength < code->minlength || code->maxlength > 10)- code->tablesize = 10;- else- code->tablesize = code->maxlength;-- code->table =- (struct huffman_table_entry *)calloc(1, sizeof(*code->table)- * ((size_t)1 << code->tablesize));-- return make_table_recurse(a, code, 0, code->table, 0, code->tablesize);-}--static int-make_table_recurse(struct archive_read *a, struct huffman_code *code, int node,- struct huffman_table_entry *table, int depth,- int maxdepth)-{- int currtablesize, i, ret = (ARCHIVE_OK);-- if (!code->tree)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Huffman tree was not created.");- return (ARCHIVE_FATAL);- }- if (node < 0 || node >= code->numentries)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid location to Huffman tree specified.");- return (ARCHIVE_FATAL);- }-- currtablesize = 1 << (maxdepth - depth);-- if (code->tree[node].branches[0] ==- code->tree[node].branches[1])- {- for(i = 0; i < currtablesize; i++)- {- table[i].length = depth;- table[i].value = code->tree[node].branches[0];- }- }- /*- * Dead code, node >= 0- *- else if (node < 0)- {- for(i = 0; i < currtablesize; i++)- table[i].length = -1;- }- */- else- {- if(depth == maxdepth)- {- table[0].length = maxdepth + 1;- table[0].value = node;- }- else- {- ret |= make_table_recurse(a, code, code->tree[node].branches[0], table,- depth + 1, maxdepth);- ret |= make_table_recurse(a, code, code->tree[node].branches[1],- table + currtablesize / 2, depth + 1, maxdepth);- }- }- return ret;-}--static int-expand(struct archive_read *a, int64_t *end)-{- static const unsigned char lengthbases[] =- { 0, 1, 2, 3, 4, 5, 6,- 7, 8, 10, 12, 14, 16, 20,- 24, 28, 32, 40, 48, 56, 64,- 80, 96, 112, 128, 160, 192, 224 };- static const unsigned char lengthbits[] =- { 0, 0, 0, 0, 0, 0, 0,- 0, 1, 1, 1, 1, 2, 2,- 2, 2, 3, 3, 3, 3, 4,- 4, 4, 4, 5, 5, 5, 5 };- static const int lengthb_min = minimum(- (int)(sizeof(lengthbases)/sizeof(lengthbases[0])),- (int)(sizeof(lengthbits)/sizeof(lengthbits[0]))- );- static const unsigned int offsetbases[] =- { 0, 1, 2, 3, 4, 6,- 8, 12, 16, 24, 32, 48,- 64, 96, 128, 192, 256, 384,- 512, 768, 1024, 1536, 2048, 3072,- 4096, 6144, 8192, 12288, 16384, 24576,- 32768, 49152, 65536, 98304, 131072, 196608,- 262144, 327680, 393216, 458752, 524288, 589824,- 655360, 720896, 786432, 851968, 917504, 983040,- 1048576, 1310720, 1572864, 1835008, 2097152, 2359296,- 2621440, 2883584, 3145728, 3407872, 3670016, 3932160 };- static const unsigned char offsetbits[] =- { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,- 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,- 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 };- static const int offsetb_min = minimum(- (int)(sizeof(offsetbases)/sizeof(offsetbases[0])),- (int)(sizeof(offsetbits)/sizeof(offsetbits[0]))- );- static const unsigned char shortbases[] =- { 0, 4, 8, 16, 32, 64, 128, 192 };- static const unsigned char shortbits[] =- { 2, 2, 3, 4, 5, 6, 6, 6 };-- int symbol, offs, len, offsindex, lensymbol, i, offssymbol, lowoffsetsymbol;- unsigned char newfile;- struct rar *rar = (struct rar *)(a->format->data);- struct rar_br *br = &(rar->br);-- if (rar->filters.filterstart < *end)- *end = rar->filters.filterstart;-- while (1)- {- if(lzss_position(&rar->lzss) >= *end) {- return (ARCHIVE_OK);- }-- if(rar->is_ppmd_block) {- *end = lzss_position(&rar->lzss);- return (ARCHIVE_OK);- }-- if ((symbol = read_next_symbol(a, &rar->maincode)) < 0)- return (ARCHIVE_FATAL);-- if (symbol < 256)- {- lzss_emit_literal(rar, symbol);- continue;- }- else if (symbol == 256)- {- if (!rar_br_read_ahead(a, br, 1))- goto truncated_data;- newfile = !rar_br_bits(br, 1);- rar_br_consume(br, 1);-- if(newfile)- {- rar->start_new_block = 1;- if (!rar_br_read_ahead(a, br, 1))- goto truncated_data;- rar->start_new_table = rar_br_bits(br, 1);- rar_br_consume(br, 1);- *end = lzss_position(&rar->lzss);- return (ARCHIVE_OK);- }- else- {- if (parse_codes(a) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- continue;- }- }- else if(symbol==257)- {- if (!read_filter(a, end))- return (ARCHIVE_FATAL);- continue;- }- else if(symbol==258)- {- if(rar->lastlength == 0)- continue;-- offs = rar->lastoffset;- len = rar->lastlength;- }- else if (symbol <= 262)- {- offsindex = symbol - 259;- offs = rar->oldoffset[offsindex];-- if ((lensymbol = read_next_symbol(a, &rar->lengthcode)) < 0)- goto bad_data;- if (lensymbol > lengthb_min)- goto bad_data;- len = lengthbases[lensymbol] + 2;- if (lengthbits[lensymbol] > 0) {- if (!rar_br_read_ahead(a, br, lengthbits[lensymbol]))- goto truncated_data;- len += rar_br_bits(br, lengthbits[lensymbol]);- rar_br_consume(br, lengthbits[lensymbol]);- }-- for (i = offsindex; i > 0; i--)- rar->oldoffset[i] = rar->oldoffset[i-1];- rar->oldoffset[0] = offs;- }- else if(symbol<=270)- {- offs = shortbases[symbol-263] + 1;- if(shortbits[symbol-263] > 0) {- if (!rar_br_read_ahead(a, br, shortbits[symbol-263]))- goto truncated_data;- offs += rar_br_bits(br, shortbits[symbol-263]);- rar_br_consume(br, shortbits[symbol-263]);- }-- len = 2;-- for(i = 3; i > 0; i--)- rar->oldoffset[i] = rar->oldoffset[i-1];- rar->oldoffset[0] = offs;- }- else- {- if (symbol-271 > lengthb_min)- goto bad_data;- len = lengthbases[symbol-271]+3;- if(lengthbits[symbol-271] > 0) {- if (!rar_br_read_ahead(a, br, lengthbits[symbol-271]))- goto truncated_data;- len += rar_br_bits(br, lengthbits[symbol-271]);- rar_br_consume(br, lengthbits[symbol-271]);- }-- if ((offssymbol = read_next_symbol(a, &rar->offsetcode)) < 0)- goto bad_data;- if (offssymbol > offsetb_min)- goto bad_data;- offs = offsetbases[offssymbol]+1;- if(offsetbits[offssymbol] > 0)- {- if(offssymbol > 9)- {- if(offsetbits[offssymbol] > 4) {- if (!rar_br_read_ahead(a, br, offsetbits[offssymbol] - 4))- goto truncated_data;- offs += rar_br_bits(br, offsetbits[offssymbol] - 4) << 4;- rar_br_consume(br, offsetbits[offssymbol] - 4);- }-- if(rar->numlowoffsetrepeats > 0)- {- rar->numlowoffsetrepeats--;- offs += rar->lastlowoffset;- }- else- {- if ((lowoffsetsymbol =- read_next_symbol(a, &rar->lowoffsetcode)) < 0)- return (ARCHIVE_FATAL);- if(lowoffsetsymbol == 16)- {- rar->numlowoffsetrepeats = 15;- offs += rar->lastlowoffset;- }- else- {- offs += lowoffsetsymbol;- rar->lastlowoffset = lowoffsetsymbol;- }- }- }- else {- if (!rar_br_read_ahead(a, br, offsetbits[offssymbol]))- goto truncated_data;- offs += rar_br_bits(br, offsetbits[offssymbol]);- rar_br_consume(br, offsetbits[offssymbol]);- }- }-- if (offs >= 0x40000)- len++;- if (offs >= 0x2000)- len++;-- for(i = 3; i > 0; i--)- rar->oldoffset[i] = rar->oldoffset[i-1];- rar->oldoffset[0] = offs;- }-- rar->lastoffset = offs;- rar->lastlength = len;-- lzss_emit_match(rar, rar->lastoffset, rar->lastlength);- }-truncated_data:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated RAR file data");- rar->valid = 0;- return (ARCHIVE_FATAL);-bad_data:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Bad RAR file data");- return (ARCHIVE_FATAL);-}--static int-copy_from_lzss_window(struct archive_read *a, void *buffer,- int64_t startpos, int length)-{- int windowoffs, firstpart;- struct rar *rar = (struct rar *)(a->format->data);-- windowoffs = lzss_offset_for_position(&rar->lzss, startpos);- firstpart = lzss_size(&rar->lzss) - windowoffs;- if (firstpart < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Bad RAR file data");- return (ARCHIVE_FATAL);- }- if (firstpart < length) {- memcpy(buffer, &rar->lzss.window[windowoffs], firstpart);- memcpy(buffer, &rar->lzss.window[0], length - firstpart);- } else {- memcpy(buffer, &rar->lzss.window[windowoffs], length);- }- return (ARCHIVE_OK);-}--static int-copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,- int64_t startpos, int length)-{- int windowoffs, firstpart;- struct rar *rar = (struct rar *)(a->format->data);-- if (!rar->unp_buffer)- {- if ((rar->unp_buffer = malloc(rar->unp_buffer_size)) == NULL)- {- archive_set_error(&a->archive, ENOMEM,- "Unable to allocate memory for uncompressed data.");- return (ARCHIVE_FATAL);- }- }-- windowoffs = lzss_offset_for_position(&rar->lzss, startpos);- if(windowoffs + length <= lzss_size(&rar->lzss)) {- memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs],- length);- } else if (length <= lzss_size(&rar->lzss)) {- firstpart = lzss_size(&rar->lzss) - windowoffs;- if (firstpart < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Bad RAR file data");- return (ARCHIVE_FATAL);- }- if (firstpart < length) {- memcpy(&rar->unp_buffer[rar->unp_offset],- &rar->lzss.window[windowoffs], firstpart);- memcpy(&rar->unp_buffer[rar->unp_offset + firstpart],- &rar->lzss.window[0], length - firstpart);- } else {- memcpy(&rar->unp_buffer[rar->unp_offset],- &rar->lzss.window[windowoffs], length);- }- } else {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Bad RAR file data");- return (ARCHIVE_FATAL);- }- rar->unp_offset += length;- if (rar->unp_offset >= rar->unp_buffer_size)- *buffer = rar->unp_buffer;- else- *buffer = NULL;- return (ARCHIVE_OK);-}--static const void *-rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)-{- struct rar *rar = (struct rar *)(a->format->data);- const void *h = __archive_read_ahead(a, min, avail);- int ret;- if (avail)- {- if (a->archive.read_data_is_posix_read && *avail > (ssize_t)a->archive.read_data_requested)- *avail = a->archive.read_data_requested;- if (*avail > rar->bytes_remaining)- *avail = (ssize_t)rar->bytes_remaining;- if (*avail < 0)- return NULL;- else if (*avail == 0 && rar->main_flags & MHD_VOLUME &&- rar->file_flags & FHD_SPLIT_AFTER)- {- rar->filename_must_match = 1;- ret = archive_read_format_rar_read_header(a, a->entry);- if (ret == (ARCHIVE_EOF))- {- rar->has_endarc_header = 1;- ret = archive_read_format_rar_read_header(a, a->entry);- }- rar->filename_must_match = 0;- if (ret != (ARCHIVE_OK))- return NULL;- return rar_read_ahead(a, min, avail);- }- }- return h;-}--static int-parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint8_t flags)-{- struct rar *rar = (struct rar *)(a->format->data);- struct rar_filters *filters = &rar->filters;-- struct memory_bit_reader br = { 0 };- struct rar_program_code *prog;- struct rar_filter *filter, **nextfilter;-- uint32_t numprogs, num, blocklength, globaldatalen;- uint8_t *globaldata;- size_t blockstartpos;- uint32_t registers[8] = { 0 };- uint32_t i;-- br.bytes = bytes;- br.length = length;-- numprogs = 0;- for (prog = filters->progs; prog; prog = prog->next)- numprogs++;-- if ((flags & 0x80))- {- num = membr_next_rarvm_number(&br);- if (num == 0)- {- delete_filter(filters->stack);- filters->stack = NULL;- delete_program_code(filters->progs);- filters->progs = NULL;- }- else- num--;- if (num > numprogs) {- return 0;- }- filters->lastfilternum = num;- }- else- num = filters->lastfilternum;-- prog = filters->progs;- for (i = 0; i < num; i++)- prog = prog->next;- if (prog)- prog->usagecount++;-- blockstartpos = membr_next_rarvm_number(&br) + (size_t)lzss_position(&rar->lzss);- if ((flags & 0x40))- blockstartpos += 258;- if ((flags & 0x20))- blocklength = membr_next_rarvm_number(&br);- else- blocklength = prog ? prog->oldfilterlength : 0;-- registers[3] = PROGRAM_SYSTEM_GLOBAL_ADDRESS;- registers[4] = blocklength;- registers[5] = prog ? prog->usagecount : 0;- registers[7] = VM_MEMORY_SIZE;-- if ((flags & 0x10))- {- uint8_t mask = (uint8_t)membr_bits(&br, 7);- for (i = 0; i < 7; i++)- if ((mask & (1 << i)))- registers[i] = membr_next_rarvm_number(&br);- }-- if (!prog)- {- uint32_t len = membr_next_rarvm_number(&br);- uint8_t *bytecode;- struct rar_program_code **next;-- if (len == 0 || len > 0x10000)- return 0;- bytecode = malloc(len);- if (!bytecode)- return 0;- for (i = 0; i < len; i++)- bytecode[i] = (uint8_t)membr_bits(&br, 8);- prog = compile_program(bytecode, len);- if (!prog) {- free(bytecode);- return 0;- }- free(bytecode);- next = &filters->progs;- while (*next)- next = &(*next)->next;- *next = prog;- }- prog->oldfilterlength = blocklength;-- globaldata = NULL;- globaldatalen = 0;- if ((flags & 0x08))- {- globaldatalen = membr_next_rarvm_number(&br);- if (globaldatalen > PROGRAM_USER_GLOBAL_SIZE)- return 0;- globaldata = malloc(globaldatalen + PROGRAM_SYSTEM_GLOBAL_SIZE);- if (!globaldata)- return 0;- for (i = 0; i < globaldatalen; i++)- globaldata[i + PROGRAM_SYSTEM_GLOBAL_SIZE] = (uint8_t)membr_bits(&br, 8);- }-- if (br.at_eof)- {- free(globaldata);- return 0;- }-- filter = create_filter(prog, globaldata, globaldatalen, registers, blockstartpos, blocklength);- free(globaldata);- if (!filter)- return 0;-- for (i = 0; i < 7; i++)- archive_le32enc(&filter->globaldata[i * 4], registers[i]);- archive_le32enc(&filter->globaldata[0x1C], blocklength);- archive_le32enc(&filter->globaldata[0x20], 0);- archive_le32enc(&filter->globaldata[0x2C], prog->usagecount);-- nextfilter = &filters->stack;- while (*nextfilter)- nextfilter = &(*nextfilter)->next;- *nextfilter = filter;-- if (!filters->stack->next)- filters->filterstart = blockstartpos;-- return 1;-}--static struct rar_filter *-create_filter(struct rar_program_code *prog, const uint8_t *globaldata, uint32_t globaldatalen, uint32_t registers[8], size_t startpos, uint32_t length)-{- struct rar_filter *filter;-- filter = calloc(1, sizeof(*filter));- if (!filter)- return NULL;- filter->prog = prog;- filter->globaldatalen = globaldatalen > PROGRAM_SYSTEM_GLOBAL_SIZE ? globaldatalen : PROGRAM_SYSTEM_GLOBAL_SIZE;- filter->globaldata = calloc(1, filter->globaldatalen);- if (!filter->globaldata)- return NULL;- if (globaldata)- memcpy(filter->globaldata, globaldata, globaldatalen);- if (registers)- memcpy(filter->initialregisters, registers, sizeof(filter->initialregisters));- filter->blockstartpos = startpos;- filter->blocklength = length;-- return filter;-}--static int-run_filters(struct archive_read *a)-{- struct rar *rar = (struct rar *)(a->format->data);- struct rar_filters *filters = &rar->filters;- struct rar_filter *filter = filters->stack;- struct rar_filter *f;- size_t start, end;- int64_t tend;- uint32_t lastfilteraddress;- uint32_t lastfilterlength;- int ret;-- if (filters == NULL || filter == NULL)- return (0);-- start = filters->filterstart;- end = start + filter->blocklength;-- filters->filterstart = INT64_MAX;- tend = (int64_t)end;- ret = expand(a, &tend);- if (ret != ARCHIVE_OK)- return 0;-- /* Check if filter stack was modified in expand() */- ret = ARCHIVE_FATAL;- f = filters->stack;- while (f)- {- if (f == filter)- {- ret = ARCHIVE_OK;- break;- }- f = f->next;- }- if (ret != ARCHIVE_OK)- return 0;-- if (tend < 0)- return 0;- end = (size_t)tend;- if (end != start + filter->blocklength)- return 0;-- if (!filters->vm)- {- filters->vm = calloc(1, sizeof(*filters->vm));- if (!filters->vm)- return 0;- }-- ret = copy_from_lzss_window(a, filters->vm->memory, start, filter->blocklength);- if (ret != ARCHIVE_OK)- return 0;- if (!execute_filter(a, filter, filters->vm, rar->offset))- return 0;-- lastfilteraddress = filter->filteredblockaddress;- lastfilterlength = filter->filteredblocklength;- filters->stack = filter->next;- filter->next = NULL;- delete_filter(filter);-- while ((filter = filters->stack) != NULL && (int64_t)filter->blockstartpos == filters->filterstart && filter->blocklength == lastfilterlength)- {- memmove(&filters->vm->memory[0], &filters->vm->memory[lastfilteraddress], lastfilterlength);- if (!execute_filter(a, filter, filters->vm, rar->offset))- return 0;-- lastfilteraddress = filter->filteredblockaddress;- lastfilterlength = filter->filteredblocklength;- filters->stack = filter->next;- filter->next = NULL;- delete_filter(filter);- }-- if (filters->stack)- {- if (filters->stack->blockstartpos < end)- return 0;- filters->filterstart = filters->stack->blockstartpos;- }-- filters->lastend = end;- filters->bytes = &filters->vm->memory[lastfilteraddress];- filters->bytes_ready = lastfilterlength;-- return 1;-}--static struct rar_program_code *-compile_program(const uint8_t *bytes, size_t length)-{- struct memory_bit_reader br = { 0 };- struct rar_program_code *prog;- // uint32_t instrcount = 0;- uint8_t xor;- size_t i;-- xor = 0;- for (i = 1; i < length; i++)- xor ^= bytes[i];- if (!length || xor != bytes[0])- return NULL;-- br.bytes = bytes;- br.length = length;- br.offset = 1;-- prog = calloc(1, sizeof(*prog));- if (!prog)- return NULL;- prog->fingerprint = crc32(0, bytes, (unsigned int)length) | ((uint64_t)length << 32);-- if (membr_bits(&br, 1))- {- prog->staticdatalen = membr_next_rarvm_number(&br) + 1;- prog->staticdata = malloc(prog->staticdatalen);- if (!prog->staticdata)- {- delete_program_code(prog);- return NULL;- }- for (i = 0; i < prog->staticdatalen; i++)- prog->staticdata[i] = (uint8_t)membr_bits(&br, 8);- }-- return prog;-}--static void-delete_filter(struct rar_filter *filter)-{- while (filter)- {- struct rar_filter *next = filter->next;- free(filter->globaldata);- free(filter);- filter = next;- }-}--static void-clear_filters(struct rar_filters *filters)-{- delete_filter(filters->stack);- delete_program_code(filters->progs);- free(filters->vm);-}--static void-delete_program_code(struct rar_program_code *prog)-{- while (prog)- {- struct rar_program_code *next = prog->next;- free(prog->staticdata);- free(prog->globalbackup);- free(prog);- prog = next;- }-}--static uint32_t-membr_next_rarvm_number(struct memory_bit_reader *br)-{- uint32_t val;- switch (membr_bits(br, 2))- {- case 0:- return membr_bits(br, 4);- case 1:- val = membr_bits(br, 8);- if (val >= 16)- return val;- return 0xFFFFFF00 | (val << 4) | membr_bits(br, 4);- case 2:- return membr_bits(br, 16);- default:- return membr_bits(br, 32);- }-}--static inline uint32_t-membr_bits(struct memory_bit_reader *br, int bits)-{- if (bits > br->available && (br->at_eof || !membr_fill(br, bits)))- return 0;- return (uint32_t)((br->bits >> (br->available -= bits)) & (((uint64_t)1 << bits) - 1));-}--static int-membr_fill(struct memory_bit_reader *br, int bits)-{- while (br->available < bits && br->offset < br->length)- {- br->bits = (br->bits << 8) | br->bytes[br->offset++];- br->available += 8;- }- if (bits > br->available)- {- br->at_eof = 1;- return 0;- }- return 1;-}--static int-read_filter(struct archive_read *a, int64_t *end)-{- struct rar *rar = (struct rar *)(a->format->data);- uint8_t flags, val, *code;- uint16_t length, i;-- if (!rar_decode_byte(a, &flags))- return 0;- length = (flags & 0x07) + 1;- if (length == 7)- {- if (!rar_decode_byte(a, &val))- return 0;- length = val + 7;- }- else if (length == 8)- {- if (!rar_decode_byte(a, &val))- return 0;- length = val << 8;- if (!rar_decode_byte(a, &val))- return 0;- length |= val;- }-- code = malloc(length);- if (!code)- return 0;- for (i = 0; i < length; i++)- {- if (!rar_decode_byte(a, &code[i]))- {- free(code);- return 0;- }- }- if (!parse_filter(a, code, length, flags))- {- free(code);- return 0;- }- free(code);-- if (rar->filters.filterstart < *end)- *end = rar->filters.filterstart;-- return 1;-}--static int-execute_filter_delta(struct rar_filter *filter, struct rar_virtual_machine *vm)-{- uint32_t length = filter->initialregisters[4];- uint32_t numchannels = filter->initialregisters[0];- uint8_t *src, *dst;- uint32_t i, idx;-- if (length > PROGRAM_WORK_SIZE / 2)- return 0;-- src = &vm->memory[0];- dst = &vm->memory[length];- for (i = 0; i < numchannels; i++)- {- uint8_t lastbyte = 0;- for (idx = i; idx < length; idx += numchannels)- lastbyte = dst[idx] = lastbyte - *src++;- }-- filter->filteredblockaddress = length;- filter->filteredblocklength = length;-- return 1;-}--static int-execute_filter_e8(struct rar_filter *filter, struct rar_virtual_machine *vm, size_t pos, int e9also)-{- uint32_t length = filter->initialregisters[4];- uint32_t filesize = 0x1000000;- uint32_t i;-- if (length > PROGRAM_WORK_SIZE || length < 4)- return 0;-- for (i = 0; i <= length - 5; i++)- {- if (vm->memory[i] == 0xE8 || (e9also && vm->memory[i] == 0xE9))- {- uint32_t currpos = (uint32_t)pos + i + 1;- int32_t address = (int32_t)vm_read_32(vm, i + 1);- if (address < 0 && currpos >= (uint32_t)-address)- vm_write_32(vm, i + 1, address + filesize);- else if (address >= 0 && (uint32_t)address < filesize)- vm_write_32(vm, i + 1, address - currpos);- i += 4;- }- }-- filter->filteredblockaddress = 0;- filter->filteredblocklength = length;-- return 1;-}--static int-execute_filter_rgb(struct rar_filter *filter, struct rar_virtual_machine *vm)-{- uint32_t stride = filter->initialregisters[0];- uint32_t byteoffset = filter->initialregisters[1];- uint32_t blocklength = filter->initialregisters[4];- uint8_t *src, *dst;- uint32_t i, j;-- if (blocklength > PROGRAM_WORK_SIZE / 2 || stride > blocklength)- return 0;-- src = &vm->memory[0];- dst = &vm->memory[blocklength];- for (i = 0; i < 3; i++) {- uint8_t byte = 0;- uint8_t *prev = dst + i - stride;- for (j = i; j < blocklength; j += 3)- {- if (prev >= dst)- {- uint32_t delta1 = abs(prev[3] - prev[0]);- uint32_t delta2 = abs(byte - prev[0]);- uint32_t delta3 = abs(prev[3] - prev[0] + byte - prev[0]);- if (delta1 > delta2 || delta1 > delta3)- byte = delta2 <= delta3 ? prev[3] : prev[0];- }- byte -= *src++;- dst[j] = byte;- prev += 3;- }- }- for (i = byteoffset; i < blocklength - 2; i += 3)- {- dst[i] += dst[i + 1];- dst[i + 2] += dst[i + 1];- }-- filter->filteredblockaddress = blocklength;- filter->filteredblocklength = blocklength;-- return 1;-}--static int-execute_filter_audio(struct rar_filter *filter, struct rar_virtual_machine *vm)-{- uint32_t length = filter->initialregisters[4];- uint32_t numchannels = filter->initialregisters[0];- uint8_t *src, *dst;- uint32_t i, j;-- if (length > PROGRAM_WORK_SIZE / 2)- return 0;-- src = &vm->memory[0];- dst = &vm->memory[length];- for (i = 0; i < numchannels; i++)- {- struct audio_state state;- memset(&state, 0, sizeof(state));- for (j = i; j < length; j += numchannels)- {- int8_t delta = (int8_t)*src++;- uint8_t predbyte, byte;- int prederror;- state.delta[2] = state.delta[1];- state.delta[1] = state.lastdelta - state.delta[0];- state.delta[0] = state.lastdelta;- predbyte = ((8 * state.lastbyte + state.weight[0] * state.delta[0] + state.weight[1] * state.delta[1] + state.weight[2] * state.delta[2]) >> 3) & 0xFF;- byte = (predbyte - delta) & 0xFF;- prederror = delta << 3;- state.error[0] += abs(prederror);- state.error[1] += abs(prederror - state.delta[0]); state.error[2] += abs(prederror + state.delta[0]);- state.error[3] += abs(prederror - state.delta[1]); state.error[4] += abs(prederror + state.delta[1]);- state.error[5] += abs(prederror - state.delta[2]); state.error[6] += abs(prederror + state.delta[2]);- state.lastdelta = (int8_t)(byte - state.lastbyte);- dst[j] = state.lastbyte = byte;- if (!(state.count++ & 0x1F))- {- uint8_t k, idx = 0;- for (k = 1; k < 7; k++)- {- if (state.error[k] < state.error[idx])- idx = k;- }- memset(state.error, 0, sizeof(state.error));- switch (idx)- {- case 1: if (state.weight[0] >= -16) state.weight[0]--; break;- case 2: if (state.weight[0] < 16) state.weight[0]++; break;- case 3: if (state.weight[1] >= -16) state.weight[1]--; break;- case 4: if (state.weight[1] < 16) state.weight[1]++; break;- case 5: if (state.weight[2] >= -16) state.weight[2]--; break;- case 6: if (state.weight[2] < 16) state.weight[2]++; break;- }- }- }- }-- filter->filteredblockaddress = length;- filter->filteredblocklength = length;-- return 1;-}---static int-execute_filter(struct archive_read *a, struct rar_filter *filter, struct rar_virtual_machine *vm, size_t pos)-{- if (filter->prog->fingerprint == 0x1D0E06077D)- return execute_filter_delta(filter, vm);- if (filter->prog->fingerprint == 0x35AD576887)- return execute_filter_e8(filter, vm, pos, 0);- if (filter->prog->fingerprint == 0x393CD7E57E)- return execute_filter_e8(filter, vm, pos, 1);- if (filter->prog->fingerprint == 0x951C2C5DC8)- return execute_filter_rgb(filter, vm);- if (filter->prog->fingerprint == 0xD8BC85E701)- return execute_filter_audio(filter, vm);-- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "No support for RAR VM program filter");- return 0;-}--static int-rar_decode_byte(struct archive_read *a, uint8_t *byte)-{- struct rar *rar = (struct rar *)(a->format->data);- struct rar_br *br = &(rar->br);- if (!rar_br_read_ahead(a, br, 8))- return 0;- *byte = (uint8_t)rar_br_bits(br, 8);- rar_br_consume(br, 8);- return 1;-}--static inline void-vm_write_32(struct rar_virtual_machine* vm, size_t offset, uint32_t u32)-{- archive_le32enc(vm->memory + offset, u32);-}--static inline uint32_t-vm_read_32(struct rar_virtual_machine* vm, size_t offset)-{- return archive_le32dec(vm->memory + offset);-}
− c/archive_read_support_format_rar5.c
@@ -1,4251 +0,0 @@-/*--* Copyright (c) 2018 Grzegorz Antoniak (http://antoniak.org)-* 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"-#include "archive_endian.h"--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#include <time.h>-#ifdef HAVE_ZLIB_H-#include <zlib.h> /* crc32 */-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif--#include "archive.h"-#ifndef HAVE_ZLIB_H-#include "archive_crc32.h"-#endif--#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_ppmd7_private.h"-#include "archive_entry_private.h"--#ifdef HAVE_BLAKE2_H-#include <blake2.h>-#else-#include "archive_blake2.h"-#endif--/*#define CHECK_CRC_ON_SOLID_SKIP*/-/*#define DONT_FAIL_ON_CRC_ERROR*/-/*#define DEBUG*/--#define rar5_min(a, b) (((a) > (b)) ? (b) : (a))-#define rar5_max(a, b) (((a) > (b)) ? (a) : (b))-#define rar5_countof(X) ((const ssize_t) (sizeof(X) / sizeof(*X)))--#if defined DEBUG-#define DEBUG_CODE if(1)-#define LOG(...) do { printf("rar5: " __VA_ARGS__); puts(""); } while(0)-#else-#define DEBUG_CODE if(0)-#endif--/* Real RAR5 magic number is:- *- * 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00- * "Rar!→•☺·\x00"- *- * Retrieved with `rar5_signature()` by XOR'ing it with 0xA1, because I don't- * want to put this magic sequence in each binary that uses libarchive, so- * applications that scan through the file for this marker won't trigger on- * this "false" one.- *- * The array itself is decrypted in `rar5_init` function. */--static unsigned char rar5_signature_xor[] = { 243, 192, 211, 128, 187, 166, 160, 161 };-static const size_t g_unpack_window_size = 0x20000;--/* These could have been static const's, but they aren't, because of- * Visual Studio. */-#define MAX_NAME_IN_CHARS 2048-#define MAX_NAME_IN_BYTES (4 * MAX_NAME_IN_CHARS)--struct file_header {- ssize_t bytes_remaining;- ssize_t unpacked_size;- int64_t last_offset; /* Used in sanity checks. */- int64_t last_size; /* Used in sanity checks. */-- uint8_t solid : 1; /* Is this a solid stream? */- uint8_t service : 1; /* Is this file a service data? */- uint8_t eof : 1; /* Did we finish unpacking the file? */- uint8_t dir : 1; /* Is this file entry a directory? */-- /* Optional time fields. */- uint64_t e_mtime;- uint64_t e_ctime;- uint64_t e_atime;- uint32_t e_unix_ns;-- /* Optional hash fields. */- uint32_t stored_crc32;- uint32_t calculated_crc32;- uint8_t blake2sp[32];- blake2sp_state b2state;- char has_blake2;-- /* Optional redir fields */- uint64_t redir_type;- uint64_t redir_flags;-- ssize_t solid_window_size; /* Used in file format check. */-};--enum EXTRA {- EX_CRYPT = 0x01,- EX_HASH = 0x02,- EX_HTIME = 0x03,- EX_VERSION = 0x04,- EX_REDIR = 0x05,- EX_UOWNER = 0x06,- EX_SUBDATA = 0x07-};--#define REDIR_SYMLINK_IS_DIR 1--enum REDIR_TYPE {- REDIR_TYPE_NONE = 0,- REDIR_TYPE_UNIXSYMLINK = 1,- REDIR_TYPE_WINSYMLINK = 2,- REDIR_TYPE_JUNCTION = 3,- REDIR_TYPE_HARDLINK = 4,- REDIR_TYPE_FILECOPY = 5,-};--#define OWNER_USER_NAME 0x01-#define OWNER_GROUP_NAME 0x02-#define OWNER_USER_UID 0x04-#define OWNER_GROUP_GID 0x08-#define OWNER_MAXNAMELEN 256--enum FILTER_TYPE {- FILTER_DELTA = 0, /* Generic pattern. */- FILTER_E8 = 1, /* Intel x86 code. */- FILTER_E8E9 = 2, /* Intel x86 code. */- FILTER_ARM = 3, /* ARM code. */- FILTER_AUDIO = 4, /* Audio filter, not used in RARv5. */- FILTER_RGB = 5, /* Color palette, not used in RARv5. */- FILTER_ITANIUM = 6, /* Intel's Itanium, not used in RARv5. */- FILTER_PPM = 7, /* Predictive pattern matching, not used in- RARv5. */- FILTER_NONE = 8,-};--struct filter_info {- int type;- int channels;- int pos_r;-- int64_t block_start;- ssize_t block_length;- uint16_t width;-};--struct data_ready {- char used;- const uint8_t* buf;- size_t size;- int64_t offset;-};--struct cdeque {- uint16_t beg_pos;- uint16_t end_pos;- uint16_t cap_mask;- uint16_t size;- size_t* arr;-};--struct decode_table {- uint32_t size;- int32_t decode_len[16];- uint32_t decode_pos[16];- uint32_t quick_bits;- uint8_t quick_len[1 << 10];- uint16_t quick_num[1 << 10];- uint16_t decode_num[306];-};--struct comp_state {- /* Flag used to specify if unpacker needs to reinitialize the- uncompression context. */- uint8_t initialized : 1;-- /* Flag used when applying filters. */- uint8_t all_filters_applied : 1;-- /* Flag used to skip file context reinitialization, used when unpacker- is skipping through different multivolume archives. */- uint8_t switch_multivolume : 1;-- /* Flag used to specify if unpacker has processed the whole data block- or just a part of it. */- uint8_t block_parsing_finished : 1;-- signed int notused : 4;-- int flags; /* Uncompression flags. */- int method; /* Uncompression algorithm method. */- int version; /* Uncompression algorithm version. */- ssize_t window_size; /* Size of window_buf. */- uint8_t* window_buf; /* Circular buffer used during- decompression. */- uint8_t* filtered_buf; /* Buffer used when applying filters. */- const uint8_t* block_buf; /* Buffer used when merging blocks. */- size_t window_mask; /* Convenience field; window_size - 1. */- int64_t write_ptr; /* This amount of data has been unpacked- in the window buffer. */- int64_t last_write_ptr; /* This amount of data has been stored in- the output file. */- int64_t last_unstore_ptr; /* Counter of bytes extracted during- unstoring. This is separate from- last_write_ptr because of how SERVICE- base blocks are handled during skipping- in solid multiarchive archives. */- int64_t solid_offset; /* Additional offset inside the window- buffer, used in unpacking solid- archives. */- ssize_t cur_block_size; /* Size of current data block. */- int last_len; /* Flag used in lzss decompression. */-- /* Decode tables used during lzss uncompression. */--#define HUFF_BC 20- struct decode_table bd; /* huffman bit lengths */-#define HUFF_NC 306- struct decode_table ld; /* literals */-#define HUFF_DC 64- struct decode_table dd; /* distances */-#define HUFF_LDC 16- struct decode_table ldd; /* lower bits of distances */-#define HUFF_RC 44- struct decode_table rd; /* repeating distances */-#define HUFF_TABLE_SIZE (HUFF_NC + HUFF_DC + HUFF_RC + HUFF_LDC)-- /* Circular deque for storing filters. */- struct cdeque filters;- int64_t last_block_start; /* Used for sanity checking. */- ssize_t last_block_length; /* Used for sanity checking. */-- /* Distance cache used during lzss uncompression. */- int dist_cache[4];-- /* Data buffer stack. */- struct data_ready dready[2];-};--/* Bit reader state. */-struct bit_reader {- int8_t bit_addr; /* Current bit pointer inside current byte. */- int in_addr; /* Current byte pointer. */-};--/* RARv5 block header structure. Use bf_* functions to get values from- * block_flags_u8 field. I.e. bf_byte_count, etc. */-struct compressed_block_header {- /* block_flags_u8 contain fields encoded in little-endian bitfield:- *- * - table present flag (shr 7, and 1),- * - last block flag (shr 6, and 1),- * - byte_count (shr 3, and 7),- * - bit_size (shr 0, and 7).- */- uint8_t block_flags_u8;- uint8_t block_cksum;-};--/* RARv5 main header structure. */-struct main_header {- /* Does the archive contain solid streams? */- uint8_t solid : 1;-- /* If this a multi-file archive? */- uint8_t volume : 1;- uint8_t endarc : 1;- uint8_t notused : 5;-- unsigned int vol_no;-};--struct generic_header {- uint8_t split_after : 1;- uint8_t split_before : 1;- uint8_t padding : 6;- int size;- int last_header_id;-};--struct multivolume {- unsigned int expected_vol_no;- uint8_t* push_buf;-};--/* Main context structure. */-struct rar5 {- int header_initialized;-- /* Set to 1 if current file is positioned AFTER the magic value- * of the archive file. This is used in header reading functions. */- int skipped_magic;-- /* Set to not zero if we're in skip mode (either by calling- * rar5_data_skip function or when skipping over solid streams).- * Set to 0 when in * extraction mode. This is used during checksum- * calculation functions. */- int skip_mode;-- /* Set to not zero if we're in block merging mode (i.e. when switching- * to another file in multivolume archive, last block from 1st archive- * needs to be merged with 1st block from 2nd archive). This flag- * guards against recursive use of the merging function, which doesn't- * support recursive calls. */- int merge_mode;-- /* An offset to QuickOpen list. This is not supported by this unpacker,- * because we're focusing on streaming interface. QuickOpen is designed- * to make things quicker for non-stream interfaces, so it's not our- * use case. */- uint64_t qlist_offset;-- /* An offset to additional Recovery data. This is not supported by this- * unpacker. Recovery data are additional Reed-Solomon codes that could- * be used to calculate bytes that are missing in archive or are- * corrupted. */- uint64_t rr_offset;-- /* Various context variables grouped to different structures. */- struct generic_header generic;- struct main_header main;- struct comp_state cstate;- struct file_header file;- struct bit_reader bits;- struct multivolume vol;-- /* The header of currently processed RARv5 block. Used in main- * decompression logic loop. */- struct compressed_block_header last_block_hdr;-};--/* Forward function declarations. */--static void rar5_signature(char *buf);-static int verify_global_checksums(struct archive_read* a);-static int rar5_read_data_skip(struct archive_read *a);-static int push_data_ready(struct archive_read* a, struct rar5* rar,- const uint8_t* buf, size_t size, int64_t offset);--/* CDE_xxx = Circular Double Ended (Queue) return values. */-enum CDE_RETURN_VALUES {- CDE_OK, CDE_ALLOC, CDE_PARAM, CDE_OUT_OF_BOUNDS,-};--/* Clears the contents of this circular deque. */-static void cdeque_clear(struct cdeque* d) {- d->size = 0;- d->beg_pos = 0;- d->end_pos = 0;-}--/* Creates a new circular deque object. Capacity must be power of 2: 8, 16, 32,- * 64, 256, etc. When the user will add another item above current capacity,- * the circular deque will overwrite the oldest entry. */-static int cdeque_init(struct cdeque* d, int max_capacity_power_of_2) {- if(d == NULL || max_capacity_power_of_2 == 0)- return CDE_PARAM;-- d->cap_mask = max_capacity_power_of_2 - 1;- d->arr = NULL;-- if((max_capacity_power_of_2 & d->cap_mask) != 0)- return CDE_PARAM;-- cdeque_clear(d);- d->arr = malloc(sizeof(void*) * max_capacity_power_of_2);-- return d->arr ? CDE_OK : CDE_ALLOC;-}--/* Return the current size (not capacity) of circular deque `d`. */-static size_t cdeque_size(struct cdeque* d) {- return d->size;-}--/* Returns the first element of current circular deque. Note that this function- * doesn't perform any bounds checking. If you need bounds checking, use- * `cdeque_front()` function instead. */-static void cdeque_front_fast(struct cdeque* d, void** value) {- *value = (void*) d->arr[d->beg_pos];-}--/* Returns the first element of current circular deque. This function- * performs bounds checking. */-static int cdeque_front(struct cdeque* d, void** value) {- if(d->size > 0) {- cdeque_front_fast(d, value);- return CDE_OK;- } else- return CDE_OUT_OF_BOUNDS;-}--/* Pushes a new element into the end of this circular deque object. If current- * size will exceed capacity, the oldest element will be overwritten. */-static int cdeque_push_back(struct cdeque* d, void* item) {- if(d == NULL)- return CDE_PARAM;-- if(d->size == d->cap_mask + 1)- return CDE_OUT_OF_BOUNDS;-- d->arr[d->end_pos] = (size_t) item;- d->end_pos = (d->end_pos + 1) & d->cap_mask;- d->size++;-- return CDE_OK;-}--/* Pops a front element of this circular deque object and returns its value.- * This function doesn't perform any bounds checking. */-static void cdeque_pop_front_fast(struct cdeque* d, void** value) {- *value = (void*) d->arr[d->beg_pos];- d->beg_pos = (d->beg_pos + 1) & d->cap_mask;- d->size--;-}--/* Pops a front element of this circular deque object and returns its value.- * This function performs bounds checking. */-static int cdeque_pop_front(struct cdeque* d, void** value) {- if(!d || !value)- return CDE_PARAM;-- if(d->size == 0)- return CDE_OUT_OF_BOUNDS;-- cdeque_pop_front_fast(d, value);- return CDE_OK;-}--/* Convenience function to cast filter_info** to void **. */-static void** cdeque_filter_p(struct filter_info** f) {- return (void**) (size_t) f;-}--/* Convenience function to cast filter_info* to void *. */-static void* cdeque_filter(struct filter_info* f) {- return (void**) (size_t) f;-}--/* Destroys this circular deque object. Deallocates the memory of the- * collection buffer, but doesn't deallocate the memory of any pointer passed- * to this deque as a value. */-static void cdeque_free(struct cdeque* d) {- if(!d)- return;-- if(!d->arr)- return;-- free(d->arr);-- d->arr = NULL;- d->beg_pos = -1;- d->end_pos = -1;- d->cap_mask = 0;-}--static inline-uint8_t bf_bit_size(const struct compressed_block_header* hdr) {- return hdr->block_flags_u8 & 7;-}--static inline-uint8_t bf_byte_count(const struct compressed_block_header* hdr) {- return (hdr->block_flags_u8 >> 3) & 7;-}--static inline-uint8_t bf_is_table_present(const struct compressed_block_header* hdr) {- return (hdr->block_flags_u8 >> 7) & 1;-}--static inline struct rar5* get_context(struct archive_read* a) {- return (struct rar5*) a->format->data;-}--/* Convenience functions used by filter implementations. */-static void circular_memcpy(uint8_t* dst, uint8_t* window, const uint64_t mask,- int64_t start, int64_t end)-{- if((start & mask) > (end & mask)) {- ssize_t len1 = mask + 1 - (start & mask);- ssize_t len2 = end & mask;-- memcpy(dst, &window[start & mask], len1);- memcpy(dst + len1, window, len2);- } else {- memcpy(dst, &window[start & mask], (size_t) (end - start));- }-}--static uint32_t read_filter_data(struct rar5* rar, uint32_t offset) {- uint8_t linear_buf[4];- circular_memcpy(linear_buf, rar->cstate.window_buf,- rar->cstate.window_mask, offset, offset + 4);- return archive_le32dec(linear_buf);-}--static void write_filter_data(struct rar5* rar, uint32_t offset,- uint32_t value)-{- archive_le32enc(&rar->cstate.filtered_buf[offset], value);-}--/* Allocates a new filter descriptor and adds it to the filter array. */-static struct filter_info* add_new_filter(struct rar5* rar) {- struct filter_info* f =- (struct filter_info*) calloc(1, sizeof(struct filter_info));-- if(!f) {- return NULL;- }-- cdeque_push_back(&rar->cstate.filters, cdeque_filter(f));- return f;-}--static int run_delta_filter(struct rar5* rar, struct filter_info* flt) {- int i;- ssize_t dest_pos, src_pos = 0;-- for(i = 0; i < flt->channels; i++) {- uint8_t prev_byte = 0;- for(dest_pos = i;- dest_pos < flt->block_length;- dest_pos += flt->channels)- {- uint8_t byte;-- byte = rar->cstate.window_buf[- (rar->cstate.solid_offset + flt->block_start +- src_pos) & rar->cstate.window_mask];-- prev_byte -= byte;- rar->cstate.filtered_buf[dest_pos] = prev_byte;- src_pos++;- }- }-- return ARCHIVE_OK;-}--static int run_e8e9_filter(struct rar5* rar, struct filter_info* flt,- int extended)-{- const uint32_t file_size = 0x1000000;- ssize_t i;-- circular_memcpy(rar->cstate.filtered_buf,- rar->cstate.window_buf, rar->cstate.window_mask,- rar->cstate.solid_offset + flt->block_start,- rar->cstate.solid_offset + flt->block_start + flt->block_length);-- for(i = 0; i < flt->block_length - 4;) {- uint8_t b = rar->cstate.window_buf[- (rar->cstate.solid_offset + flt->block_start +- i++) & rar->cstate.window_mask];-- /*- * 0xE8 = x86's call <relative_addr_uint32> (function call)- * 0xE9 = x86's jmp <relative_addr_uint32> (unconditional jump)- */- if(b == 0xE8 || (extended && b == 0xE9)) {-- uint32_t addr;- uint32_t offset = (i + flt->block_start) % file_size;-- addr = read_filter_data(rar,- (uint32_t)(rar->cstate.solid_offset +- flt->block_start + i) & rar->cstate.window_mask);-- if(addr & 0x80000000) {- if(((addr + offset) & 0x80000000) == 0) {- write_filter_data(rar, (uint32_t)i,- addr + file_size);- }- } else {- if((addr - file_size) & 0x80000000) {- uint32_t naddr = addr - offset;- write_filter_data(rar, (uint32_t)i,- naddr);- }- }-- i += 4;- }- }-- return ARCHIVE_OK;-}--static int run_arm_filter(struct rar5* rar, struct filter_info* flt) {- ssize_t i = 0;- uint32_t offset;-- circular_memcpy(rar->cstate.filtered_buf,- rar->cstate.window_buf, rar->cstate.window_mask,- rar->cstate.solid_offset + flt->block_start,- rar->cstate.solid_offset + flt->block_start + flt->block_length);-- for(i = 0; i < flt->block_length - 3; i += 4) {- uint8_t* b = &rar->cstate.window_buf[- (rar->cstate.solid_offset +- flt->block_start + i + 3) & rar->cstate.window_mask];-- if(*b == 0xEB) {- /* 0xEB = ARM's BL (branch + link) instruction. */- offset = read_filter_data(rar,- (rar->cstate.solid_offset + flt->block_start + i) &- (uint32_t)rar->cstate.window_mask) & 0x00ffffff;-- offset -= (uint32_t) ((i + flt->block_start) / 4);- offset = (offset & 0x00ffffff) | 0xeb000000;- write_filter_data(rar, (uint32_t)i, offset);- }- }-- return ARCHIVE_OK;-}--static int run_filter(struct archive_read* a, struct filter_info* flt) {- int ret;- struct rar5* rar = get_context(a);-- free(rar->cstate.filtered_buf);-- rar->cstate.filtered_buf = malloc(flt->block_length);- if(!rar->cstate.filtered_buf) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for filter data.");- return ARCHIVE_FATAL;- }-- switch(flt->type) {- case FILTER_DELTA:- ret = run_delta_filter(rar, flt);- break;-- case FILTER_E8:- /* fallthrough */- case FILTER_E8E9:- ret = run_e8e9_filter(rar, flt,- flt->type == FILTER_E8E9);- break;-- case FILTER_ARM:- ret = run_arm_filter(rar, flt);- break;-- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported filter type: 0x%x", flt->type);- return ARCHIVE_FATAL;- }-- if(ret != ARCHIVE_OK) {- /* Filter has failed. */- return ret;- }-- if(ARCHIVE_OK != push_data_ready(a, rar, rar->cstate.filtered_buf,- flt->block_length, rar->cstate.last_write_ptr))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Stack overflow when submitting unpacked data");-- return ARCHIVE_FATAL;- }-- rar->cstate.last_write_ptr += flt->block_length;- return ARCHIVE_OK;-}--/* The `push_data` function submits the selected data range to the user.- * Next call of `use_data` will use the pointer, size and offset arguments- * that are specified here. These arguments are pushed to the FIFO stack here,- * and popped from the stack by the `use_data` function. */-static void push_data(struct archive_read* a, struct rar5* rar,- const uint8_t* buf, int64_t idx_begin, int64_t idx_end)-{- const uint64_t wmask = rar->cstate.window_mask;- const ssize_t solid_write_ptr = (rar->cstate.solid_offset +- rar->cstate.last_write_ptr) & wmask;-- idx_begin += rar->cstate.solid_offset;- idx_end += rar->cstate.solid_offset;-- /* Check if our unpacked data is wrapped inside the window circular- * buffer. If it's not wrapped, it can be copied out by using- * a single memcpy, but when it's wrapped, we need to copy the first- * part with one memcpy, and the second part with another memcpy. */-- if((idx_begin & wmask) > (idx_end & wmask)) {- /* The data is wrapped (begin offset sis bigger than end- * offset). */- const ssize_t frag1_size = rar->cstate.window_size -- (idx_begin & wmask);- const ssize_t frag2_size = idx_end & wmask;-- /* Copy the first part of the buffer first. */- push_data_ready(a, rar, buf + solid_write_ptr, frag1_size,- rar->cstate.last_write_ptr);-- /* Copy the second part of the buffer. */- push_data_ready(a, rar, buf, frag2_size,- rar->cstate.last_write_ptr + frag1_size);-- rar->cstate.last_write_ptr += frag1_size + frag2_size;- } else {- /* Data is not wrapped, so we can just use one call to copy the- * data. */- push_data_ready(a, rar,- buf + solid_write_ptr, (idx_end - idx_begin) & wmask,- rar->cstate.last_write_ptr);-- rar->cstate.last_write_ptr += idx_end - idx_begin;- }-}--/* Convenience function that submits the data to the user. It uses the- * unpack window buffer as a source location. */-static void push_window_data(struct archive_read* a, struct rar5* rar,- int64_t idx_begin, int64_t idx_end)-{- push_data(a, rar, rar->cstate.window_buf, idx_begin, idx_end);-}--static int apply_filters(struct archive_read* a) {- struct filter_info* flt;- struct rar5* rar = get_context(a);- int ret;-- rar->cstate.all_filters_applied = 0;-- /* Get the first filter that can be applied to our data. The data- * needs to be fully unpacked before the filter can be run. */- if(CDE_OK == cdeque_front(&rar->cstate.filters,- cdeque_filter_p(&flt))) {- /* Check if our unpacked data fully covers this filter's- * range. */- if(rar->cstate.write_ptr > flt->block_start &&- rar->cstate.write_ptr >= flt->block_start +- flt->block_length) {- /* Check if we have some data pending to be written- * right before the filter's start offset. */- if(rar->cstate.last_write_ptr == flt->block_start) {- /* Run the filter specified by descriptor- * `flt`. */- ret = run_filter(a, flt);- if(ret != ARCHIVE_OK) {- /* Filter failure, return error. */- return ret;- }-- /* Filter descriptor won't be needed anymore- * after it's used, * so remove it from the- * filter list and free its memory. */- (void) cdeque_pop_front(&rar->cstate.filters,- cdeque_filter_p(&flt));-- free(flt);- } else {- /* We can't run filters yet, dump the memory- * right before the filter. */- push_window_data(a, rar,- rar->cstate.last_write_ptr,- flt->block_start);- }-- /* Return 'filter applied or not needed' state to the- * caller. */- return ARCHIVE_RETRY;- }- }-- rar->cstate.all_filters_applied = 1;- return ARCHIVE_OK;-}--static void dist_cache_push(struct rar5* rar, int value) {- int* q = rar->cstate.dist_cache;-- q[3] = q[2];- q[2] = q[1];- q[1] = q[0];- q[0] = value;-}--static int dist_cache_touch(struct rar5* rar, int idx) {- int* q = rar->cstate.dist_cache;- int i, dist = q[idx];-- for(i = idx; i > 0; i--)- q[i] = q[i - 1];-- q[0] = dist;- return dist;-}--static void free_filters(struct rar5* rar) {- struct cdeque* d = &rar->cstate.filters;-- /* Free any remaining filters. All filters should be naturally- * consumed by the unpacking function, so remaining filters after- * unpacking normally mean that unpacking wasn't successful.- * But still of course we shouldn't leak memory in such case. */-- /* cdeque_size() is a fast operation, so we can use it as a loop- * expression. */- while(cdeque_size(d) > 0) {- struct filter_info* f = NULL;-- /* Pop_front will also decrease the collection's size. */- if (CDE_OK == cdeque_pop_front(d, cdeque_filter_p(&f)))- free(f);- }-- cdeque_clear(d);-- /* Also clear out the variables needed for sanity checking. */- rar->cstate.last_block_start = 0;- rar->cstate.last_block_length = 0;-}--static void reset_file_context(struct rar5* rar) {- memset(&rar->file, 0, sizeof(rar->file));- blake2sp_init(&rar->file.b2state, 32);-- if(rar->main.solid) {- rar->cstate.solid_offset += rar->cstate.write_ptr;- } else {- rar->cstate.solid_offset = 0;- }-- rar->cstate.write_ptr = 0;- rar->cstate.last_write_ptr = 0;- rar->cstate.last_unstore_ptr = 0;-- rar->file.redir_type = REDIR_TYPE_NONE;- rar->file.redir_flags = 0;-- free_filters(rar);-}--static inline int get_archive_read(struct archive* a,- struct archive_read** ar)-{- *ar = (struct archive_read*) a;- archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,- "archive_read_support_format_rar5");-- return ARCHIVE_OK;-}--static int read_ahead(struct archive_read* a, size_t how_many,- const uint8_t** ptr)-{- ssize_t avail = -1;- if(!ptr)- return 0;-- *ptr = __archive_read_ahead(a, how_many, &avail);- if(*ptr == NULL) {- return 0;- }-- return 1;-}--static int consume(struct archive_read* a, int64_t how_many) {- int ret;-- ret = how_many == __archive_read_consume(a, how_many)- ? ARCHIVE_OK- : ARCHIVE_FATAL;-- return ret;-}--/**- * Read a RAR5 variable sized numeric value. This value will be stored in- * `pvalue`. The `pvalue_len` argument points to a variable that will receive- * the byte count that was consumed in order to decode the `pvalue` value, plus- * one.- *- * pvalue_len is optional and can be NULL.- *- * NOTE: if `pvalue_len` is NOT NULL, the caller needs to manually consume- * the number of bytes that `pvalue_len` value contains. If the `pvalue_len`- * is NULL, this consuming operation is done automatically.- *- * Returns 1 if *pvalue was successfully read.- * Returns 0 if there was an error. In this case, *pvalue contains an- * invalid value.- */--static int read_var(struct archive_read* a, uint64_t* pvalue,- uint64_t* pvalue_len)-{- uint64_t result = 0;- size_t shift, i;- const uint8_t* p;- uint8_t b;-- /* We will read maximum of 8 bytes. We don't have to handle the- * situation to read the RAR5 variable-sized value stored at the end of- * the file, because such situation will never happen. */- if(!read_ahead(a, 8, &p))- return 0;-- for(shift = 0, i = 0; i < 8; i++, shift += 7) {- b = p[i];-- /* Strip the MSB from the input byte and add the resulting- * number to the `result`. */- result += (b & (uint64_t)0x7F) << shift;-- /* MSB set to 1 means we need to continue decoding process.- * MSB set to 0 means we're done.- *- * This conditional checks for the second case. */- if((b & 0x80) == 0) {- if(pvalue) {- *pvalue = result;- }-- /* If the caller has passed the `pvalue_len` pointer,- * store the number of consumed bytes in it and do NOT- * consume those bytes, since the caller has all the- * information it needs to perform */- if(pvalue_len) {- *pvalue_len = 1 + i;- } else {- /* If the caller did not provide the- * `pvalue_len` pointer, it will not have the- * possibility to advance the file pointer,- * because it will not know how many bytes it- * needs to consume. This is why we handle- * such situation here automatically. */- if(ARCHIVE_OK != consume(a, 1 + i)) {- return 0;- }- }-- /* End of decoding process, return success. */- return 1;- }- }-- /* The decoded value takes the maximum number of 8 bytes.- * It's a maximum number of bytes, so end decoding process here- * even if the first bit of last byte is 1. */- if(pvalue) {- *pvalue = result;- }-- if(pvalue_len) {- *pvalue_len = 9;- } else {- if(ARCHIVE_OK != consume(a, 9)) {- return 0;- }- }-- return 1;-}--static int read_var_sized(struct archive_read* a, size_t* pvalue,- size_t* pvalue_len)-{- uint64_t v;- uint64_t v_size = 0;-- const int ret = pvalue_len ? read_var(a, &v, &v_size)- : read_var(a, &v, NULL);-- if(ret == 1 && pvalue) {- *pvalue = (size_t) v;- }-- if(pvalue_len) {- /* Possible data truncation should be safe. */- *pvalue_len = (size_t) v_size;- }-- return ret;-}--static int read_bits_32(struct archive_read* a, struct rar5* rar,- const uint8_t* p, uint32_t* value)-{- if(rar->bits.in_addr >= rar->cstate.cur_block_size) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Premature end of stream during extraction of data (#1)");- return ARCHIVE_FATAL;- }-- uint32_t bits = ((uint32_t) p[rar->bits.in_addr]) << 24;- bits |= p[rar->bits.in_addr + 1] << 16;- bits |= p[rar->bits.in_addr + 2] << 8;- bits |= p[rar->bits.in_addr + 3];- bits <<= rar->bits.bit_addr;- bits |= p[rar->bits.in_addr + 4] >> (8 - rar->bits.bit_addr);- *value = bits;- return ARCHIVE_OK;-}--static int read_bits_16(struct archive_read* a, struct rar5* rar,- const uint8_t* p, uint16_t* value)-{- if(rar->bits.in_addr >= rar->cstate.cur_block_size) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Premature end of stream during extraction of data (#2)");- return ARCHIVE_FATAL;- }-- int bits = (int) ((uint32_t) p[rar->bits.in_addr]) << 16;- bits |= (int) p[rar->bits.in_addr + 1] << 8;- bits |= (int) p[rar->bits.in_addr + 2];- bits >>= (8 - rar->bits.bit_addr);- *value = bits & 0xffff;- return ARCHIVE_OK;-}--static void skip_bits(struct rar5* rar, int bits) {- const int new_bits = rar->bits.bit_addr + bits;- rar->bits.in_addr += new_bits >> 3;- rar->bits.bit_addr = new_bits & 7;-}--/* n = up to 16 */-static int read_consume_bits(struct archive_read* a, struct rar5* rar,- const uint8_t* p, int n, int* value)-{- uint16_t v;- int ret, num;-- if(n == 0 || n > 16) {- /* This is a programmer error and should never happen- * in runtime. */- return ARCHIVE_FATAL;- }-- ret = read_bits_16(a, rar, p, &v);- if(ret != ARCHIVE_OK)- return ret;-- num = (int) v;- num >>= 16 - n;-- skip_bits(rar, n);-- if(value)- *value = num;-- return ARCHIVE_OK;-}--static int read_u32(struct archive_read* a, uint32_t* pvalue) {- const uint8_t* p;- if(!read_ahead(a, 4, &p))- return 0;-- *pvalue = archive_le32dec(p);- return ARCHIVE_OK == consume(a, 4) ? 1 : 0;-}--static int read_u64(struct archive_read* a, uint64_t* pvalue) {- const uint8_t* p;- if(!read_ahead(a, 8, &p))- return 0;-- *pvalue = archive_le64dec(p);- return ARCHIVE_OK == consume(a, 8) ? 1 : 0;-}--static int bid_standard(struct archive_read* a) {- const uint8_t* p;- char signature[sizeof(rar5_signature_xor)];-- rar5_signature(signature);-- if(!read_ahead(a, sizeof(rar5_signature_xor), &p))- return -1;-- if(!memcmp(signature, p, sizeof(rar5_signature_xor)))- return 30;-- return -1;-}--static int bid_sfx(struct archive_read *a)-{- const char *p;-- if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)- return -1;-- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {- /* This is a PE file */- char signature[sizeof(rar5_signature_xor)];- ssize_t offset = 0x10000;- ssize_t window = 4096;- ssize_t bytes_avail;-- rar5_signature(signature);-- while (offset + window <= (1024 * 512)) {- const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail);- if (buff == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < 0x40)- return 0;- continue;- }- p = buff + offset;- while (p + 8 < buff + bytes_avail) {- if (memcmp(p, signature, sizeof(signature)) == 0)- return 30;- p += 0x10;- }- offset = p - buff;- }- }-- return 0;-}--static int rar5_bid(struct archive_read* a, int best_bid) {- int my_bid;-- if(best_bid > 30)- return -1;-- my_bid = bid_standard(a);- if(my_bid > -1) {- return my_bid;- }- my_bid = bid_sfx(a);- if (my_bid > -1) {- return my_bid;- }-- return -1;-}--static int rar5_options(struct archive_read *a, const char *key,- const char *val) {- (void) a;- (void) key;- (void) val;-- /* No options supported in this version. Return the ARCHIVE_WARN code- * to signal the options supervisor that the unpacker didn't handle- * setting this option. */-- return ARCHIVE_WARN;-}--static void init_header(struct archive_read* a) {- a->archive.archive_format = ARCHIVE_FORMAT_RAR_V5;- a->archive.archive_format_name = "RAR5";-}--static void init_window_mask(struct rar5* rar) {- if (rar->cstate.window_size)- rar->cstate.window_mask = rar->cstate.window_size - 1;- else- rar->cstate.window_mask = 0;-}--enum HEADER_FLAGS {- HFL_EXTRA_DATA = 0x0001,- HFL_DATA = 0x0002,- HFL_SKIP_IF_UNKNOWN = 0x0004,- HFL_SPLIT_BEFORE = 0x0008,- HFL_SPLIT_AFTER = 0x0010,- HFL_CHILD = 0x0020,- HFL_INHERITED = 0x0040-};--static int process_main_locator_extra_block(struct archive_read* a,- struct rar5* rar)-{- uint64_t locator_flags;-- enum LOCATOR_FLAGS {- QLIST = 0x01, RECOVERY = 0x02,- };-- if(!read_var(a, &locator_flags, NULL)) {- return ARCHIVE_EOF;- }-- if(locator_flags & QLIST) {- if(!read_var(a, &rar->qlist_offset, NULL)) {- return ARCHIVE_EOF;- }-- /* qlist is not used */- }-- if(locator_flags & RECOVERY) {- if(!read_var(a, &rar->rr_offset, NULL)) {- return ARCHIVE_EOF;- }-- /* rr is not used */- }-- return ARCHIVE_OK;-}--static int parse_file_extra_hash(struct archive_read* a, struct rar5* rar,- ssize_t* extra_data_size)-{- size_t hash_type = 0;- size_t value_len;-- enum HASH_TYPE {- BLAKE2sp = 0x00- };-- if(!read_var_sized(a, &hash_type, &value_len))- return ARCHIVE_EOF;-- *extra_data_size -= value_len;- if(ARCHIVE_OK != consume(a, value_len)) {- return ARCHIVE_EOF;- }-- /* The file uses BLAKE2sp checksum algorithm instead of plain old- * CRC32. */- if(hash_type == BLAKE2sp) {- const uint8_t* p;- const int hash_size = sizeof(rar->file.blake2sp);-- if(!read_ahead(a, hash_size, &p))- return ARCHIVE_EOF;-- rar->file.has_blake2 = 1;- memcpy(&rar->file.blake2sp, p, hash_size);-- if(ARCHIVE_OK != consume(a, hash_size)) {- return ARCHIVE_EOF;- }-- *extra_data_size -= hash_size;- } else {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported hash type (0x%x)", (int) hash_type);- return ARCHIVE_FATAL;- }-- return ARCHIVE_OK;-}--static uint64_t time_win_to_unix(uint64_t win_time) {- const size_t ns_in_sec = 10000000;- const uint64_t sec_to_unix = 11644473600LL;- return win_time / ns_in_sec - sec_to_unix;-}--static int parse_htime_item(struct archive_read* a, char unix_time,- uint64_t* where, ssize_t* extra_data_size)-{- if(unix_time) {- uint32_t time_val;- if(!read_u32(a, &time_val))- return ARCHIVE_EOF;-- *extra_data_size -= 4;- *where = (uint64_t) time_val;- } else {- uint64_t windows_time;- if(!read_u64(a, &windows_time))- return ARCHIVE_EOF;-- *where = time_win_to_unix(windows_time);- *extra_data_size -= 8;- }-- return ARCHIVE_OK;-}--static int parse_file_extra_version(struct archive_read* a,- struct archive_entry* e, ssize_t* extra_data_size)-{- size_t flags = 0;- size_t version = 0;- size_t value_len = 0;- struct archive_string version_string;- struct archive_string name_utf8_string;- const char* cur_filename;-- /* Flags are ignored. */- if(!read_var_sized(a, &flags, &value_len))- return ARCHIVE_EOF;-- *extra_data_size -= value_len;- if(ARCHIVE_OK != consume(a, value_len))- return ARCHIVE_EOF;-- if(!read_var_sized(a, &version, &value_len))- return ARCHIVE_EOF;-- *extra_data_size -= value_len;- if(ARCHIVE_OK != consume(a, value_len))- return ARCHIVE_EOF;-- /* extra_data_size should be zero here. */-- cur_filename = archive_entry_pathname_utf8(e);- if(cur_filename == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Version entry without file name");- return ARCHIVE_FATAL;- }-- archive_string_init(&version_string);- archive_string_init(&name_utf8_string);-- /* Prepare a ;123 suffix for the filename, where '123' is the version- * value of this file. */- archive_string_sprintf(&version_string, ";%zu", version);-- /* Build the new filename. */- archive_strcat(&name_utf8_string, cur_filename);- archive_strcat(&name_utf8_string, version_string.s);-- /* Apply the new filename into this file's context. */- archive_entry_update_pathname_utf8(e, name_utf8_string.s);-- /* Free buffers. */- archive_string_free(&version_string);- archive_string_free(&name_utf8_string);- return ARCHIVE_OK;-}--static int parse_file_extra_htime(struct archive_read* a,- struct archive_entry* e, struct rar5* rar, ssize_t* extra_data_size)-{- char unix_time = 0;- size_t flags = 0;- size_t value_len;-- enum HTIME_FLAGS {- IS_UNIX = 0x01,- HAS_MTIME = 0x02,- HAS_CTIME = 0x04,- HAS_ATIME = 0x08,- HAS_UNIX_NS = 0x10,- };-- if(!read_var_sized(a, &flags, &value_len))- return ARCHIVE_EOF;-- *extra_data_size -= value_len;- if(ARCHIVE_OK != consume(a, value_len)) {- return ARCHIVE_EOF;- }-- unix_time = flags & IS_UNIX;-- if(flags & HAS_MTIME) {- parse_htime_item(a, unix_time, &rar->file.e_mtime,- extra_data_size);- archive_entry_set_mtime(e, rar->file.e_mtime, 0);- }-- if(flags & HAS_CTIME) {- parse_htime_item(a, unix_time, &rar->file.e_ctime,- extra_data_size);- archive_entry_set_ctime(e, rar->file.e_ctime, 0);- }-- if(flags & HAS_ATIME) {- parse_htime_item(a, unix_time, &rar->file.e_atime,- extra_data_size);- archive_entry_set_atime(e, rar->file.e_atime, 0);- }-- if(flags & HAS_UNIX_NS) {- if(!read_u32(a, &rar->file.e_unix_ns))- return ARCHIVE_EOF;-- *extra_data_size -= 4;- }-- return ARCHIVE_OK;-}--static int parse_file_extra_redir(struct archive_read* a,- struct archive_entry* e, struct rar5* rar, ssize_t* extra_data_size)-{- uint64_t value_size = 0;- size_t target_size = 0;- char target_utf8_buf[MAX_NAME_IN_BYTES];- const uint8_t* p;-- if(!read_var(a, &rar->file.redir_type, &value_size))- return ARCHIVE_EOF;- if(ARCHIVE_OK != consume(a, (int64_t)value_size))- return ARCHIVE_EOF;- *extra_data_size -= value_size;-- if(!read_var(a, &rar->file.redir_flags, &value_size))- return ARCHIVE_EOF;- if(ARCHIVE_OK != consume(a, (int64_t)value_size))- return ARCHIVE_EOF;- *extra_data_size -= value_size;-- if(!read_var_sized(a, &target_size, NULL))- return ARCHIVE_EOF;- *extra_data_size -= target_size + 1;-- if(!read_ahead(a, target_size, &p))- return ARCHIVE_EOF;-- if(target_size > (MAX_NAME_IN_CHARS - 1)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Link target is too long");- return ARCHIVE_FATAL;- }-- if(target_size == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "No link target specified");- return ARCHIVE_FATAL;- }-- memcpy(target_utf8_buf, p, target_size);- target_utf8_buf[target_size] = 0;-- if(ARCHIVE_OK != consume(a, (int64_t)target_size))- return ARCHIVE_EOF;-- switch(rar->file.redir_type) {- case REDIR_TYPE_UNIXSYMLINK:- case REDIR_TYPE_WINSYMLINK:- archive_entry_set_filetype(e, AE_IFLNK);- archive_entry_update_symlink_utf8(e, target_utf8_buf);- if (rar->file.redir_flags & REDIR_SYMLINK_IS_DIR) {- archive_entry_set_symlink_type(e,- AE_SYMLINK_TYPE_DIRECTORY);- } else {- archive_entry_set_symlink_type(e,- AE_SYMLINK_TYPE_FILE);- }- break;-- case REDIR_TYPE_HARDLINK:- archive_entry_set_filetype(e, AE_IFREG);- archive_entry_update_hardlink_utf8(e, target_utf8_buf);- break;-- default:- /* Unknown redir type, skip it. */- break;- }- return ARCHIVE_OK;-}--static int parse_file_extra_owner(struct archive_read* a,- struct archive_entry* e, ssize_t* extra_data_size)-{- uint64_t flags = 0;- uint64_t value_size = 0;- uint64_t id = 0;- size_t name_len = 0;- size_t name_size = 0;- char namebuf[OWNER_MAXNAMELEN];- const uint8_t* p;-- if(!read_var(a, &flags, &value_size))- return ARCHIVE_EOF;- if(ARCHIVE_OK != consume(a, (int64_t)value_size))- return ARCHIVE_EOF;- *extra_data_size -= value_size;-- if ((flags & OWNER_USER_NAME) != 0) {- if(!read_var_sized(a, &name_size, NULL))- return ARCHIVE_EOF;- *extra_data_size -= name_size + 1;-- if(!read_ahead(a, name_size, &p))- return ARCHIVE_EOF;-- if (name_size >= OWNER_MAXNAMELEN) {- name_len = OWNER_MAXNAMELEN - 1;- } else {- name_len = name_size;- }-- memcpy(namebuf, p, name_len);- namebuf[name_len] = 0;- if(ARCHIVE_OK != consume(a, (int64_t)name_size))- return ARCHIVE_EOF;-- archive_entry_set_uname(e, namebuf);- }- if ((flags & OWNER_GROUP_NAME) != 0) {- if(!read_var_sized(a, &name_size, NULL))- return ARCHIVE_EOF;- *extra_data_size -= name_size + 1;-- if(!read_ahead(a, name_size, &p))- return ARCHIVE_EOF;-- if (name_size >= OWNER_MAXNAMELEN) {- name_len = OWNER_MAXNAMELEN - 1;- } else {- name_len = name_size;- }-- memcpy(namebuf, p, name_len);- namebuf[name_len] = 0;- if(ARCHIVE_OK != consume(a, (int64_t)name_size))- return ARCHIVE_EOF;-- archive_entry_set_gname(e, namebuf);- }- if ((flags & OWNER_USER_UID) != 0) {- if(!read_var(a, &id, &value_size))- return ARCHIVE_EOF;- if(ARCHIVE_OK != consume(a, (int64_t)value_size))- return ARCHIVE_EOF;- *extra_data_size -= value_size;-- archive_entry_set_uid(e, (la_int64_t)id);- }- if ((flags & OWNER_GROUP_GID) != 0) {- if(!read_var(a, &id, &value_size))- return ARCHIVE_EOF;- if(ARCHIVE_OK != consume(a, (int64_t)value_size))- return ARCHIVE_EOF;- *extra_data_size -= value_size;-- archive_entry_set_gid(e, (la_int64_t)id);- }- return ARCHIVE_OK;-}--static int process_head_file_extra(struct archive_read* a,- struct archive_entry* e, struct rar5* rar, ssize_t extra_data_size)-{- size_t extra_field_size;- size_t extra_field_id = 0;- int ret = ARCHIVE_FATAL;- size_t var_size;-- while(extra_data_size > 0) {- if(!read_var_sized(a, &extra_field_size, &var_size))- return ARCHIVE_EOF;-- extra_data_size -= var_size;- if(ARCHIVE_OK != consume(a, var_size)) {- return ARCHIVE_EOF;- }-- if(!read_var_sized(a, &extra_field_id, &var_size))- return ARCHIVE_EOF;-- extra_data_size -= var_size;- if(ARCHIVE_OK != consume(a, var_size)) {- return ARCHIVE_EOF;- }-- switch(extra_field_id) {- case EX_HASH:- ret = parse_file_extra_hash(a, rar,- &extra_data_size);- break;- case EX_HTIME:- ret = parse_file_extra_htime(a, e, rar,- &extra_data_size);- break;- case EX_REDIR:- ret = parse_file_extra_redir(a, e, rar,- &extra_data_size);- break;- case EX_UOWNER:- ret = parse_file_extra_owner(a, e,- &extra_data_size);- break;- case EX_VERSION:- ret = parse_file_extra_version(a, e,- &extra_data_size);- break;- case EX_CRYPT:- /* fallthrough */- case EX_SUBDATA:- /* fallthrough */- default:- /* Skip unsupported entry. */- return consume(a, extra_data_size);- }- }-- if(ret != ARCHIVE_OK) {- /* Attribute not implemented. */- return ret;- }-- return ARCHIVE_OK;-}--static int process_head_file(struct archive_read* a, struct rar5* rar,- struct archive_entry* entry, size_t block_flags)-{- ssize_t extra_data_size = 0;- size_t data_size = 0;- size_t file_flags = 0;- size_t file_attr = 0;- size_t compression_info = 0;- size_t host_os = 0;- size_t name_size = 0;- uint64_t unpacked_size, window_size;- uint32_t mtime = 0, crc = 0;- int c_method = 0, c_version = 0;- char name_utf8_buf[MAX_NAME_IN_BYTES];- const uint8_t* p;-- enum FILE_FLAGS {- DIRECTORY = 0x0001, UTIME = 0x0002, CRC32 = 0x0004,- UNKNOWN_UNPACKED_SIZE = 0x0008,- };-- enum FILE_ATTRS {- ATTR_READONLY = 0x1, ATTR_HIDDEN = 0x2, ATTR_SYSTEM = 0x4,- ATTR_DIRECTORY = 0x10,- };-- enum COMP_INFO_FLAGS {- SOLID = 0x0040,- };-- enum HOST_OS {- HOST_WINDOWS = 0,- HOST_UNIX = 1,- };-- archive_entry_clear(entry);-- /* Do not reset file context if we're switching archives. */- if(!rar->cstate.switch_multivolume) {- reset_file_context(rar);- }-- if(block_flags & HFL_EXTRA_DATA) {- size_t edata_size = 0;- if(!read_var_sized(a, &edata_size, NULL))- return ARCHIVE_EOF;-- /* Intentional type cast from unsigned to signed. */- extra_data_size = (ssize_t) edata_size;- }-- if(block_flags & HFL_DATA) {- if(!read_var_sized(a, &data_size, NULL))- return ARCHIVE_EOF;-- rar->file.bytes_remaining = data_size;- } else {- rar->file.bytes_remaining = 0;-- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "no data found in file/service block");- return ARCHIVE_FATAL;- }-- if(!read_var_sized(a, &file_flags, NULL))- return ARCHIVE_EOF;-- if(!read_var(a, &unpacked_size, NULL))- return ARCHIVE_EOF;-- if(file_flags & UNKNOWN_UNPACKED_SIZE) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Files with unknown unpacked size are not supported");- return ARCHIVE_FATAL;- }-- rar->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0);-- if(!read_var_sized(a, &file_attr, NULL))- return ARCHIVE_EOF;-- if(file_flags & UTIME) {- if(!read_u32(a, &mtime))- return ARCHIVE_EOF;- }-- if(file_flags & CRC32) {- if(!read_u32(a, &crc))- return ARCHIVE_EOF;- }-- if(!read_var_sized(a, &compression_info, NULL))- return ARCHIVE_EOF;-- c_method = (int) (compression_info >> 7) & 0x7;- c_version = (int) (compression_info & 0x3f);-- /* RAR5 seems to limit the dictionary size to 64MB. */- window_size = (rar->file.dir > 0) ?- 0 :- g_unpack_window_size << ((compression_info >> 10) & 15);- rar->cstate.method = c_method;- rar->cstate.version = c_version + 50;- rar->file.solid = (compression_info & SOLID) > 0;-- /* Archives which declare solid files without initializing the window- * buffer first are invalid. */-- if(rar->file.solid > 0 && rar->cstate.window_buf == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Declared solid file, but no window buffer "- "initialized yet.");- return ARCHIVE_FATAL;- }-- /* Check if window_size is a sane value. Also, if the file is not- * declared as a directory, disallow window_size == 0. */- if(window_size > (64 * 1024 * 1024) ||- (rar->file.dir == 0 && window_size == 0))- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Declared dictionary size is not supported.");- return ARCHIVE_FATAL;- }-- if(rar->file.solid > 0) {- /* Re-check if current window size is the same as previous- * window size (for solid files only). */- if(rar->file.solid_window_size > 0 &&- rar->file.solid_window_size != (ssize_t) window_size)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Window size for this solid file doesn't match "- "the window size used in previous solid file. ");- return ARCHIVE_FATAL;- }- }-- if(rar->cstate.window_size < (ssize_t) window_size &&- rar->cstate.window_buf)- {- /* If window_buf has been allocated before, reallocate it, so- * that its size will match new window_size. */-- uint8_t* new_window_buf =- realloc(rar->cstate.window_buf, window_size);-- if(!new_window_buf) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Not enough memory when trying to realloc the window "- "buffer.");- return ARCHIVE_FATAL;- }-- rar->cstate.window_buf = new_window_buf;- }-- /* Values up to 64M should fit into ssize_t on every- * architecture. */- rar->cstate.window_size = (ssize_t) window_size;-- if(rar->file.solid > 0 && rar->file.solid_window_size == 0) {- /* Solid files have to have the same window_size across- whole archive. Remember the window_size parameter- for first solid file found. */- rar->file.solid_window_size = rar->cstate.window_size;- }-- init_window_mask(rar);-- rar->file.service = 0;-- if(!read_var_sized(a, &host_os, NULL))- return ARCHIVE_EOF;-- if(host_os == HOST_WINDOWS) {- /* Host OS is Windows */-- __LA_MODE_T mode;-- if(file_attr & ATTR_DIRECTORY) {- if (file_attr & ATTR_READONLY) {- mode = 0555 | AE_IFDIR;- } else {- mode = 0755 | AE_IFDIR;- }- } else {- if (file_attr & ATTR_READONLY) {- mode = 0444 | AE_IFREG;- } else {- mode = 0644 | AE_IFREG;- }- }-- archive_entry_set_mode(entry, mode);-- if (file_attr & (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM)) {- char *fflags_text, *ptr;- /* allocate for "rdonly,hidden,system," */- fflags_text = malloc(22 * sizeof(char));- if (fflags_text != NULL) {- ptr = fflags_text;- if (file_attr & ATTR_READONLY) {- strcpy(ptr, "rdonly,");- ptr = ptr + 7;- }- if (file_attr & ATTR_HIDDEN) {- strcpy(ptr, "hidden,");- ptr = ptr + 7;- }- if (file_attr & ATTR_SYSTEM) {- strcpy(ptr, "system,");- ptr = ptr + 7;- }- if (ptr > fflags_text) {- /* Delete trailing comma */- *(ptr - 1) = '\0';- archive_entry_copy_fflags_text(entry,- fflags_text);- }- free(fflags_text);- }- }- } else if(host_os == HOST_UNIX) {- /* Host OS is Unix */- archive_entry_set_mode(entry, (__LA_MODE_T) file_attr);- } else {- /* Unknown host OS */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported Host OS: 0x%x", (int) host_os);-- return ARCHIVE_FATAL;- }-- if(!read_var_sized(a, &name_size, NULL))- return ARCHIVE_EOF;-- if(!read_ahead(a, name_size, &p))- return ARCHIVE_EOF;-- if(name_size > (MAX_NAME_IN_CHARS - 1)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Filename is too long");-- return ARCHIVE_FATAL;- }-- if(name_size == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "No filename specified");-- return ARCHIVE_FATAL;- }-- memcpy(name_utf8_buf, p, name_size);- name_utf8_buf[name_size] = 0;- if(ARCHIVE_OK != consume(a, name_size)) {- return ARCHIVE_EOF;- }-- archive_entry_update_pathname_utf8(entry, name_utf8_buf);-- if(extra_data_size > 0) {- int ret = process_head_file_extra(a, entry, rar,- extra_data_size);-- /*- * TODO: rewrite or remove useless sanity check- * as extra_data_size is not passed as a pointer- *- if(extra_data_size < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "File extra data size is not zero");- return ARCHIVE_FATAL;- }- */-- if(ret != ARCHIVE_OK)- return ret;- }-- if((file_flags & UNKNOWN_UNPACKED_SIZE) == 0) {- rar->file.unpacked_size = (ssize_t) unpacked_size;- if(rar->file.redir_type == REDIR_TYPE_NONE)- archive_entry_set_size(entry, unpacked_size);- }-- if(file_flags & UTIME) {- archive_entry_set_mtime(entry, (time_t) mtime, 0);- }-- if(file_flags & CRC32) {- rar->file.stored_crc32 = crc;- }-- if(!rar->cstate.switch_multivolume) {- /* Do not reinitialize unpacking state if we're switching- * archives. */- rar->cstate.block_parsing_finished = 1;- rar->cstate.all_filters_applied = 1;- rar->cstate.initialized = 0;- }-- if(rar->generic.split_before > 0) {- /* If now we're standing on a header that has a 'split before'- * mark, it means we're standing on a 'continuation' file- * header. Signal the caller that if it wants to move to- * another file, it must call rar5_read_header() function- * again. */-- return ARCHIVE_RETRY;- } else {- return ARCHIVE_OK;- }-}--static int process_head_service(struct archive_read* a, struct rar5* rar,- struct archive_entry* entry, size_t block_flags)-{- /* Process this SERVICE block the same way as FILE blocks. */- int ret = process_head_file(a, rar, entry, block_flags);- if(ret != ARCHIVE_OK)- return ret;-- rar->file.service = 1;-- /* But skip the data part automatically. It's no use for the user- * anyway. It contains only service data, not even needed to- * properly unpack the file. */- ret = rar5_read_data_skip(a);- if(ret != ARCHIVE_OK)- return ret;-- /* After skipping, try parsing another block automatically. */- return ARCHIVE_RETRY;-}--static int process_head_main(struct archive_read* a, struct rar5* rar,- struct archive_entry* entry, size_t block_flags)-{- int ret;- size_t extra_data_size = 0;- size_t extra_field_size = 0;- size_t extra_field_id = 0;- size_t archive_flags = 0;-- enum MAIN_FLAGS {- VOLUME = 0x0001, /* multi-volume archive */- VOLUME_NUMBER = 0x0002, /* volume number, first vol doesn't- * have it */- SOLID = 0x0004, /* solid archive */- PROTECT = 0x0008, /* contains Recovery info */- LOCK = 0x0010, /* readonly flag, not used */- };-- enum MAIN_EXTRA {- // Just one attribute here.- LOCATOR = 0x01,- };-- (void) entry;-- if(block_flags & HFL_EXTRA_DATA) {- if(!read_var_sized(a, &extra_data_size, NULL))- return ARCHIVE_EOF;- } else {- extra_data_size = 0;- }-- if(!read_var_sized(a, &archive_flags, NULL)) {- return ARCHIVE_EOF;- }-- rar->main.volume = (archive_flags & VOLUME) > 0;- rar->main.solid = (archive_flags & SOLID) > 0;-- if(archive_flags & VOLUME_NUMBER) {- size_t v = 0;- if(!read_var_sized(a, &v, NULL)) {- return ARCHIVE_EOF;- }-- if (v > UINT_MAX) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid volume number");- return ARCHIVE_FATAL;- }-- rar->main.vol_no = (unsigned int) v;- } else {- rar->main.vol_no = 0;- }-- if(rar->vol.expected_vol_no > 0 &&- rar->main.vol_no != rar->vol.expected_vol_no)- {- /* Returning EOF instead of FATAL because of strange- * libarchive behavior. When opening multiple files via- * archive_read_open_filenames(), after reading up the whole- * last file, the __archive_read_ahead function wraps up to- * the first archive instead of returning EOF. */- return ARCHIVE_EOF;- }-- if(extra_data_size == 0) {- /* Early return. */- return ARCHIVE_OK;- }-- if(!read_var_sized(a, &extra_field_size, NULL)) {- return ARCHIVE_EOF;- }-- if(!read_var_sized(a, &extra_field_id, NULL)) {- return ARCHIVE_EOF;- }-- if(extra_field_size == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid extra field size");- return ARCHIVE_FATAL;- }-- switch(extra_field_id) {- case LOCATOR:- ret = process_main_locator_extra_block(a, rar);- if(ret != ARCHIVE_OK) {- /* Error while parsing main locator extra- * block. */- return ret;- }-- break;- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported extra type (0x%x)",- (int) extra_field_id);- return ARCHIVE_FATAL;- }-- return ARCHIVE_OK;-}--static int skip_unprocessed_bytes(struct archive_read* a) {- struct rar5* rar = get_context(a);- int ret;-- if(rar->file.bytes_remaining) {- /* Use different skipping method in block merging mode than in- * normal mode. If merge mode is active, rar5_read_data_skip- * can't be used, because it could allow recursive use of- * merge_block() * function, and this function doesn't support- * recursive use. */- if(rar->merge_mode) {- /* Discard whole merged block. This is valid in solid- * mode as well, because the code will discard blocks- * only if those blocks are safe to discard (i.e.- * they're not FILE blocks). */- ret = consume(a, rar->file.bytes_remaining);- if(ret != ARCHIVE_OK) {- return ret;- }- rar->file.bytes_remaining = 0;- } else {- /* If we're not in merge mode, use safe skipping code.- * This will ensure we'll handle solid archives- * properly. */- ret = rar5_read_data_skip(a);- if(ret != ARCHIVE_OK) {- return ret;- }- }- }-- return ARCHIVE_OK;-}--static int scan_for_signature(struct archive_read* a);--/* Base block processing function. A 'base block' is a RARv5 header block- * that tells the reader what kind of data is stored inside the block.- *- * From the birds-eye view a RAR file looks file this:- *- * <magic><base_block_1><base_block_2>...<base_block_n>- *- * There are a few types of base blocks. Those types are specified inside- * the 'switch' statement in this function. For example purposes, I'll write- * how a standard RARv5 file could look like here:- *- * <magic><MAIN><FILE><FILE><FILE><SERVICE><ENDARC>- *- * The structure above could describe an archive file with 3 files in it,- * one service "QuickOpen" block (that is ignored by this parser), and an- * end of file base block marker.- *- * If the file is stored in multiple archive files ("multiarchive"), it might- * look like this:- *- * .part01.rar: <magic><MAIN><FILE><ENDARC>- * .part02.rar: <magic><MAIN><FILE><ENDARC>- * .part03.rar: <magic><MAIN><FILE><ENDARC>- *- * This example could describe 3 RAR files that contain ONE archived file.- * Or it could describe 3 RAR files that contain 3 different files. Or 3- * RAR files than contain 2 files. It all depends what metadata is stored in- * the headers of <FILE> blocks.- *- * Each <FILE> block contains info about its size, the name of the file it's- * storing inside, and whether this FILE block is a continuation block of- * previous archive ('split before'), and is this FILE block should be- * continued in another archive ('split after'). By parsing the 'split before'- * and 'split after' flags, we're able to tell if multiple <FILE> base blocks- * are describing one file, or multiple files (with the same filename, for- * example).- *- * One thing to note is that if we're parsing the first <FILE> block, and- * we see 'split after' flag, then we need to jump over to another <FILE>- * block to be able to decompress rest of the data. To do this, we need- * to skip the <ENDARC> block, then switch to another file, then skip the- * <magic> block, <MAIN> block, and then we're standing on the proper- * <FILE> block.- */--static int process_base_block(struct archive_read* a,- struct archive_entry* entry)-{- const size_t SMALLEST_RAR5_BLOCK_SIZE = 3;-- struct rar5* rar = get_context(a);- uint32_t hdr_crc, computed_crc;- size_t raw_hdr_size = 0, hdr_size_len, hdr_size;- size_t header_id = 0;- size_t header_flags = 0;- const uint8_t* p;- int ret;-- enum HEADER_TYPE {- HEAD_MARK = 0x00, HEAD_MAIN = 0x01, HEAD_FILE = 0x02,- HEAD_SERVICE = 0x03, HEAD_CRYPT = 0x04, HEAD_ENDARC = 0x05,- HEAD_UNKNOWN = 0xff,- };-- /* Skip any unprocessed data for this file. */- ret = skip_unprocessed_bytes(a);- if(ret != ARCHIVE_OK)- return ret;-- /* Read the expected CRC32 checksum. */- if(!read_u32(a, &hdr_crc)) {- return ARCHIVE_EOF;- }-- /* Read header size. */- if(!read_var_sized(a, &raw_hdr_size, &hdr_size_len)) {- return ARCHIVE_EOF;- }-- hdr_size = raw_hdr_size + hdr_size_len;-- /* Sanity check, maximum header size for RAR5 is 2MB. */- if(hdr_size > (2 * 1024 * 1024)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Base block header is too large");-- return ARCHIVE_FATAL;- }-- /* Additional sanity checks to weed out invalid files. */- if(raw_hdr_size == 0 || hdr_size_len == 0 ||- hdr_size < SMALLEST_RAR5_BLOCK_SIZE)- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Too small block encountered (%zu bytes)",- raw_hdr_size);-- return ARCHIVE_FATAL;- }-- /* Read the whole header data into memory, maximum memory use here is- * 2MB. */- if(!read_ahead(a, hdr_size, &p)) {- return ARCHIVE_EOF;- }-- /* Verify the CRC32 of the header data. */- computed_crc = (uint32_t) crc32(0, p, (int) hdr_size);- if(computed_crc != hdr_crc) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Header CRC error");-- return ARCHIVE_FATAL;- }-- /* If the checksum is OK, we proceed with parsing. */- if(ARCHIVE_OK != consume(a, hdr_size_len)) {- return ARCHIVE_EOF;- }-- if(!read_var_sized(a, &header_id, NULL))- return ARCHIVE_EOF;-- if(!read_var_sized(a, &header_flags, NULL))- return ARCHIVE_EOF;-- rar->generic.split_after = (header_flags & HFL_SPLIT_AFTER) > 0;- rar->generic.split_before = (header_flags & HFL_SPLIT_BEFORE) > 0;- rar->generic.size = (int)hdr_size;- rar->generic.last_header_id = (int)header_id;- rar->main.endarc = 0;-- /* Those are possible header ids in RARv5. */- switch(header_id) {- case HEAD_MAIN:- ret = process_head_main(a, rar, entry, header_flags);-- /* Main header doesn't have any files in it, so it's- * pointless to return to the caller. Retry to next- * header, which should be HEAD_FILE/HEAD_SERVICE. */- if(ret == ARCHIVE_OK)- return ARCHIVE_RETRY;-- return ret;- case HEAD_SERVICE:- ret = process_head_service(a, rar, entry, header_flags);- return ret;- case HEAD_FILE:- ret = process_head_file(a, rar, entry, header_flags);- return ret;- case HEAD_CRYPT:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Encryption is not supported");- return ARCHIVE_FATAL;- case HEAD_ENDARC:- rar->main.endarc = 1;-- /* After encountering an end of file marker, we need- * to take into consideration if this archive is- * continued in another file (i.e. is it part01.rar:- * is there a part02.rar?) */- if(rar->main.volume) {- /* In case there is part02.rar, position the- * read pointer in a proper place, so we can- * resume parsing. */- ret = scan_for_signature(a);- if(ret == ARCHIVE_FATAL) {- return ARCHIVE_EOF;- } else {- if(rar->vol.expected_vol_no ==- UINT_MAX) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Header error");- return ARCHIVE_FATAL;- }-- rar->vol.expected_vol_no =- rar->main.vol_no + 1;- return ARCHIVE_OK;- }- } else {- return ARCHIVE_EOF;- }- case HEAD_MARK:- return ARCHIVE_EOF;- default:- if((header_flags & HFL_SKIP_IF_UNKNOWN) == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Header type error");- return ARCHIVE_FATAL;- } else {- /* If the block is marked as 'skip if unknown',- * do as the flag says: skip the block- * instead on failing on it. */- return ARCHIVE_RETRY;- }- }--#if !defined WIN32- // Not reached.- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Internal unpacker error");- return ARCHIVE_FATAL;-#endif-}--static int skip_base_block(struct archive_read* a) {- int ret;- struct rar5* rar = get_context(a);-- /* Create a new local archive_entry structure that will be operated on- * by header reader; operations on this archive_entry will be discarded.- */- struct archive_entry* entry = archive_entry_new();- ret = process_base_block(a, entry);-- /* Discard operations on this archive_entry structure. */- archive_entry_free(entry);- if(ret == ARCHIVE_FATAL)- return ret;-- if(rar->generic.last_header_id == 2 && rar->generic.split_before > 0)- return ARCHIVE_OK;-- if(ret == ARCHIVE_OK)- return ARCHIVE_RETRY;- else- return ret;-}--static int try_skip_sfx(struct archive_read *a)-{- const char *p;-- if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)- return ARCHIVE_EOF;-- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0)- {- char signature[sizeof(rar5_signature_xor)];- const void *h;- const char *q;- size_t skip, total = 0;- ssize_t bytes, window = 4096;-- rar5_signature(signature);-- while (total + window <= (1024 * 512)) {- h = __archive_read_ahead(a, window, &bytes);- if (h == NULL) {- /* Remaining bytes are less than window. */- window >>= 1;- if (window < 0x40)- goto fatal;- continue;- }- if (bytes < 0x40)- goto fatal;- p = h;- q = p + bytes;-- /*- * Scan ahead until we find something that looks- * like the RAR header.- */- while (p + 8 < q) {- if (memcmp(p, signature, sizeof(signature)) == 0) {- skip = p - (const char *)h;- __archive_read_consume(a, skip);- return (ARCHIVE_OK);- }- p += 0x10;- }- skip = p - (const char *)h;- __archive_read_consume(a, skip);- total += skip;- }- }-- return ARCHIVE_OK;-fatal:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Couldn't find out RAR header");- return (ARCHIVE_FATAL);-}--static int rar5_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct rar5* rar = get_context(a);- int ret;-- if(rar->header_initialized == 0) {- init_header(a);- if ((ret = try_skip_sfx(a)) < ARCHIVE_WARN)- return ret;- rar->header_initialized = 1;- }-- if(rar->skipped_magic == 0) {- if(ARCHIVE_OK != consume(a, sizeof(rar5_signature_xor))) {- return ARCHIVE_EOF;- }-- rar->skipped_magic = 1;- }-- do {- ret = process_base_block(a, entry);- } while(ret == ARCHIVE_RETRY ||- (rar->main.endarc > 0 && ret == ARCHIVE_OK));-- return ret;-}--static void init_unpack(struct rar5* rar) {- rar->file.calculated_crc32 = 0;- init_window_mask(rar);-- free(rar->cstate.window_buf);- free(rar->cstate.filtered_buf);-- if(rar->cstate.window_size > 0) {- rar->cstate.window_buf = calloc(1, rar->cstate.window_size);- rar->cstate.filtered_buf = calloc(1, rar->cstate.window_size);- } else {- rar->cstate.window_buf = NULL;- rar->cstate.filtered_buf = NULL;- }-- rar->cstate.write_ptr = 0;- rar->cstate.last_write_ptr = 0;-- memset(&rar->cstate.bd, 0, sizeof(rar->cstate.bd));- memset(&rar->cstate.ld, 0, sizeof(rar->cstate.ld));- memset(&rar->cstate.dd, 0, sizeof(rar->cstate.dd));- memset(&rar->cstate.ldd, 0, sizeof(rar->cstate.ldd));- memset(&rar->cstate.rd, 0, sizeof(rar->cstate.rd));-}--static void update_crc(struct rar5* rar, const uint8_t* p, size_t to_read) {- int verify_crc;-- if(rar->skip_mode) {-#if defined CHECK_CRC_ON_SOLID_SKIP- verify_crc = 1;-#else- verify_crc = 0;-#endif- } else- verify_crc = 1;-- if(verify_crc) {- /* Don't update CRC32 if the file doesn't have the- * `stored_crc32` info filled in. */- if(rar->file.stored_crc32 > 0) {- rar->file.calculated_crc32 =- crc32(rar->file.calculated_crc32, p, (unsigned int)to_read);- }-- /* Check if the file uses an optional BLAKE2sp checksum- * algorithm. */- if(rar->file.has_blake2 > 0) {- /* Return value of the `update` function is always 0,- * so we can explicitly ignore it here. */- (void) blake2sp_update(&rar->file.b2state, p, to_read);- }- }-}--static int create_decode_tables(uint8_t* bit_length,- struct decode_table* table, int size)-{- int code, upper_limit = 0, i, lc[16];- uint32_t decode_pos_clone[rar5_countof(table->decode_pos)];- ssize_t cur_len, quick_data_size;-- memset(&lc, 0, sizeof(lc));- memset(table->decode_num, 0, sizeof(table->decode_num));- table->size = size;- table->quick_bits = size == HUFF_NC ? 10 : 7;-- for(i = 0; i < size; i++) {- lc[bit_length[i] & 15]++;- }-- lc[0] = 0;- table->decode_pos[0] = 0;- table->decode_len[0] = 0;-- for(i = 1; i < 16; i++) {- upper_limit += lc[i];-- table->decode_len[i] = upper_limit << (16 - i);- table->decode_pos[i] = table->decode_pos[i - 1] + lc[i - 1];-- upper_limit <<= 1;- }-- memcpy(decode_pos_clone, table->decode_pos, sizeof(decode_pos_clone));-- for(i = 0; i < size; i++) {- uint8_t clen = bit_length[i] & 15;- if(clen > 0) {- int last_pos = decode_pos_clone[clen];- table->decode_num[last_pos] = i;- decode_pos_clone[clen]++;- }- }-- quick_data_size = (int64_t)1 << table->quick_bits;- cur_len = 1;- for(code = 0; code < quick_data_size; code++) {- int bit_field = code << (16 - table->quick_bits);- int dist, pos;-- while(cur_len < rar5_countof(table->decode_len) &&- bit_field >= table->decode_len[cur_len]) {- cur_len++;- }-- table->quick_len[code] = (uint8_t) cur_len;-- dist = bit_field - table->decode_len[cur_len - 1];- dist >>= (16 - cur_len);-- pos = table->decode_pos[cur_len & 15] + dist;- if(cur_len < rar5_countof(table->decode_pos) && pos < size) {- table->quick_num[code] = table->decode_num[pos];- } else {- table->quick_num[code] = 0;- }- }-- return ARCHIVE_OK;-}--static int decode_number(struct archive_read* a, struct decode_table* table,- const uint8_t* p, uint16_t* num)-{- int i, bits, dist, ret;- uint16_t bitfield;- uint32_t pos;- struct rar5* rar = get_context(a);-- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &bitfield))) {- return ret;- }-- bitfield &= 0xfffe;-- if(bitfield < table->decode_len[table->quick_bits]) {- int code = bitfield >> (16 - table->quick_bits);- skip_bits(rar, table->quick_len[code]);- *num = table->quick_num[code];- return ARCHIVE_OK;- }-- bits = 15;-- for(i = table->quick_bits + 1; i < 15; i++) {- if(bitfield < table->decode_len[i]) {- bits = i;- break;- }- }-- skip_bits(rar, bits);-- dist = bitfield - table->decode_len[bits - 1];- dist >>= (16 - bits);- pos = table->decode_pos[bits] + dist;-- if(pos >= table->size)- pos = 0;-- *num = table->decode_num[pos];- return ARCHIVE_OK;-}--/* Reads and parses Huffman tables from the beginning of the block. */-static int parse_tables(struct archive_read* a, struct rar5* rar,- const uint8_t* p)-{- int ret, value, i, w, idx = 0;- uint8_t bit_length[HUFF_BC],- table[HUFF_TABLE_SIZE],- nibble_mask = 0xF0,- nibble_shift = 4;-- enum { ESCAPE = 15 };-- /* The data for table generation is compressed using a simple RLE-like- * algorithm when storing zeroes, so we need to unpack it first. */- for(w = 0, i = 0; w < HUFF_BC;) {- if(i >= rar->cstate.cur_block_size) {- /* Truncated data, can't continue. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated data in huffman tables");- return ARCHIVE_FATAL;- }-- value = (p[i] & nibble_mask) >> nibble_shift;-- if(nibble_mask == 0x0F)- ++i;-- nibble_mask ^= 0xFF;- nibble_shift ^= 4;-- /* Values smaller than 15 is data, so we write it directly.- * Value 15 is a flag telling us that we need to unpack more- * bytes. */- if(value == ESCAPE) {- value = (p[i] & nibble_mask) >> nibble_shift;- if(nibble_mask == 0x0F)- ++i;- nibble_mask ^= 0xFF;- nibble_shift ^= 4;-- if(value == 0) {- /* We sometimes need to write the actual value- * of 15, so this case handles that. */- bit_length[w++] = ESCAPE;- } else {- int k;-- /* Fill zeroes. */- for(k = 0; (k < value + 2) && (w < HUFF_BC);- k++) {- bit_length[w++] = 0;- }- }- } else {- bit_length[w++] = value;- }- }-- rar->bits.in_addr = i;- rar->bits.bit_addr = nibble_shift ^ 4;-- ret = create_decode_tables(bit_length, &rar->cstate.bd, HUFF_BC);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Decoding huffman tables failed");- return ARCHIVE_FATAL;- }-- for(i = 0; i < HUFF_TABLE_SIZE;) {- uint16_t num;-- ret = decode_number(a, &rar->cstate.bd, p, &num);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Decoding huffman tables failed");- return ARCHIVE_FATAL;- }-- if(num < 16) {- /* 0..15: store directly */- table[i] = (uint8_t) num;- i++;- } else if(num < 18) {- /* 16..17: repeat previous code */- uint16_t n;-- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))- return ret;-- if(num == 16) {- n >>= 13;- n += 3;- skip_bits(rar, 3);- } else {- n >>= 9;- n += 11;- skip_bits(rar, 7);- }-- if(i > 0) {- while(n-- > 0 && i < HUFF_TABLE_SIZE) {- table[i] = table[i - 1];- i++;- }- } else {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unexpected error when decoding "- "huffman tables");- return ARCHIVE_FATAL;- }- } else {- /* other codes: fill with zeroes `n` times */- uint16_t n;-- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))- return ret;-- if(num == 18) {- n >>= 13;- n += 3;- skip_bits(rar, 3);- } else {- n >>= 9;- n += 11;- skip_bits(rar, 7);- }-- while(n-- > 0 && i < HUFF_TABLE_SIZE)- table[i++] = 0;- }- }-- ret = create_decode_tables(&table[idx], &rar->cstate.ld, HUFF_NC);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Failed to create literal table");- return ARCHIVE_FATAL;- }-- idx += HUFF_NC;-- ret = create_decode_tables(&table[idx], &rar->cstate.dd, HUFF_DC);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Failed to create distance table");- return ARCHIVE_FATAL;- }-- idx += HUFF_DC;-- ret = create_decode_tables(&table[idx], &rar->cstate.ldd, HUFF_LDC);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Failed to create lower bits of distances table");- return ARCHIVE_FATAL;- }-- idx += HUFF_LDC;-- ret = create_decode_tables(&table[idx], &rar->cstate.rd, HUFF_RC);- if(ret != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Failed to create repeating distances table");- return ARCHIVE_FATAL;- }-- return ARCHIVE_OK;-}--/* Parses the block header, verifies its CRC byte, and saves the header- * fields inside the `hdr` pointer. */-static int parse_block_header(struct archive_read* a, const uint8_t* p,- ssize_t* block_size, struct compressed_block_header* hdr)-{- uint8_t calculated_cksum;- memcpy(hdr, p, sizeof(struct compressed_block_header));-- if(bf_byte_count(hdr) > 2) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported block header size (was %d, max is 2)",- bf_byte_count(hdr));- return ARCHIVE_FATAL;- }-- /* This should probably use bit reader interface in order to be more- * future-proof. */- *block_size = 0;- switch(bf_byte_count(hdr)) {- /* 1-byte block size */- case 0:- *block_size = *(const uint8_t*) &p[2];- break;-- /* 2-byte block size */- case 1:- *block_size = archive_le16dec(&p[2]);- break;-- /* 3-byte block size */- case 2:- *block_size = archive_le32dec(&p[2]);- *block_size &= 0x00FFFFFF;- break;-- /* Other block sizes are not supported. This case is not- * reached, because we have an 'if' guard before the switch- * that makes sure of it. */- default:- return ARCHIVE_FATAL;- }-- /* Verify the block header checksum. 0x5A is a magic value and is- * always * constant. */- calculated_cksum = 0x5A- ^ (uint8_t) hdr->block_flags_u8- ^ (uint8_t) *block_size- ^ (uint8_t) (*block_size >> 8)- ^ (uint8_t) (*block_size >> 16);-- if(calculated_cksum != hdr->block_cksum) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Block checksum error: got 0x%x, expected 0x%x",- hdr->block_cksum, calculated_cksum);-- return ARCHIVE_FATAL;-#endif- }-- return ARCHIVE_OK;-}--/* Convenience function used during filter processing. */-static int parse_filter_data(struct archive_read* a, struct rar5* rar,- const uint8_t* p, uint32_t* filter_data)-{- int i, bytes, ret;- uint32_t data = 0;-- if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, p, 2, &bytes)))- return ret;-- bytes++;-- for(i = 0; i < bytes; i++) {- uint16_t byte;-- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &byte))) {- return ret;- }-- /* Cast to uint32_t will ensure the shift operation will not- * produce undefined result. */- data += ((uint32_t) byte >> 8) << (i * 8);- skip_bits(rar, 8);- }-- *filter_data = data;- return ARCHIVE_OK;-}--/* Function is used during sanity checking. */-static int is_valid_filter_block_start(struct rar5* rar,- uint32_t start)-{- const int64_t block_start = (ssize_t) start + rar->cstate.write_ptr;- const int64_t last_bs = rar->cstate.last_block_start;- const ssize_t last_bl = rar->cstate.last_block_length;-- if(last_bs == 0 || last_bl == 0) {- /* We didn't have any filters yet, so accept this offset. */- return 1;- }-- if(block_start >= last_bs + last_bl) {- /* Current offset is bigger than last block's end offset, so- * accept current offset. */- return 1;- }-- /* Any other case is not a normal situation and we should fail. */- return 0;-}--/* The function will create a new filter, read its parameters from the input- * stream and add it to the filter collection. */-static int parse_filter(struct archive_read* ar, const uint8_t* p) {- uint32_t block_start, block_length;- uint16_t filter_type;- struct filter_info* filt = NULL;- struct rar5* rar = get_context(ar);- int ret;-- /* Read the parameters from the input stream. */- if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_start)))- return ret;-- if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_length)))- return ret;-- if(ARCHIVE_OK != (ret = read_bits_16(ar, rar, p, &filter_type)))- return ret;-- filter_type >>= 13;- skip_bits(rar, 3);-- /* Perform some sanity checks on this filter parameters. Note that we- * allow only DELTA, E8/E9 and ARM filters here, because rest of- * filters are not used in RARv5. */-- if(block_length < 4 ||- block_length > 0x400000 ||- filter_type > FILTER_ARM ||- !is_valid_filter_block_start(rar, block_start))- {- archive_set_error(&ar->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid filter encountered");- return ARCHIVE_FATAL;- }-- /* Allocate a new filter. */- filt = add_new_filter(rar);- if(filt == NULL) {- archive_set_error(&ar->archive, ENOMEM,- "Can't allocate memory for a filter descriptor.");- return ARCHIVE_FATAL;- }-- filt->type = filter_type;- filt->block_start = rar->cstate.write_ptr + block_start;- filt->block_length = block_length;-- rar->cstate.last_block_start = filt->block_start;- rar->cstate.last_block_length = filt->block_length;-- /* Read some more data in case this is a DELTA filter. Other filter- * types don't require any additional data over what was already- * read. */- if(filter_type == FILTER_DELTA) {- int channels;-- if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar, p, 5, &channels)))- return ret;-- filt->channels = channels + 1;- }-- return ARCHIVE_OK;-}--static int decode_code_length(struct archive_read* a, struct rar5* rar,- const uint8_t* p, uint16_t code)-{- int lbits, length = 2;-- if(code < 8) {- lbits = 0;- length += code;- } else {- lbits = code / 4 - 1;- length += (4 | (code & 3)) << lbits;- }-- if(lbits > 0) {- int add;-- if(ARCHIVE_OK != read_consume_bits(a, rar, p, lbits, &add))- return -1;-- length += add;- }-- return length;-}--static int copy_string(struct archive_read* a, int len, int dist) {- struct rar5* rar = get_context(a);- const uint64_t cmask = rar->cstate.window_mask;- const uint64_t write_ptr = rar->cstate.write_ptr +- rar->cstate.solid_offset;- int i;-- if (rar->cstate.window_buf == NULL)- return ARCHIVE_FATAL;-- /* The unpacker spends most of the time in this function. It would be- * a good idea to introduce some optimizations here.- *- * Just remember that this loop treats buffers that overlap differently- * than buffers that do not overlap. This is why a simple memcpy(3)- * call will not be enough. */-- for(i = 0; i < len; i++) {- const ssize_t write_idx = (write_ptr + i) & cmask;- const ssize_t read_idx = (write_ptr + i - dist) & cmask;- rar->cstate.window_buf[write_idx] =- rar->cstate.window_buf[read_idx];- }-- rar->cstate.write_ptr += len;- return ARCHIVE_OK;-}--static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {- struct rar5* rar = get_context(a);- uint16_t num;- int ret;-- const uint64_t cmask = rar->cstate.window_mask;- const struct compressed_block_header* hdr = &rar->last_block_hdr;- const uint8_t bit_size = 1 + bf_bit_size(hdr);-- while(1) {- if(rar->cstate.write_ptr - rar->cstate.last_write_ptr >- (rar->cstate.window_size >> 1)) {- /* Don't allow growing data by more than half of the- * window size at a time. In such case, break the loop;- * next call to this function will continue processing- * from this moment. */- break;- }-- if(rar->bits.in_addr > rar->cstate.cur_block_size - 1 ||- (rar->bits.in_addr == rar->cstate.cur_block_size - 1 &&- rar->bits.bit_addr >= bit_size))- {- /* If the program counter is here, it means the- * function has finished processing the block. */- rar->cstate.block_parsing_finished = 1;- break;- }-- /* Decode the next literal. */- if(ARCHIVE_OK != decode_number(a, &rar->cstate.ld, p, &num)) {- return ARCHIVE_EOF;- }-- /* Num holds a decompression literal, or 'command code'.- *- * - Values lower than 256 are just bytes. Those codes- * can be stored in the output buffer directly.- *- * - Code 256 defines a new filter, which is later used to- * ransform the data block accordingly to the filter type.- * The data block needs to be fully uncompressed first.- *- * - Code bigger than 257 and smaller than 262 define- * a repetition pattern that should be copied from- * an already uncompressed chunk of data.- */-- if(num < 256) {- /* Directly store the byte. */- int64_t write_idx = rar->cstate.solid_offset +- rar->cstate.write_ptr++;-- rar->cstate.window_buf[write_idx & cmask] =- (uint8_t) num;- continue;- } else if(num >= 262) {- uint16_t dist_slot;- int len = decode_code_length(a, rar, p, num - 262),- dbits,- dist = 1;-- if(len == -1) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Failed to decode the code length");-- return ARCHIVE_FATAL;- }-- if(ARCHIVE_OK != decode_number(a, &rar->cstate.dd, p,- &dist_slot))- {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Failed to decode the distance slot");-- return ARCHIVE_FATAL;- }-- if(dist_slot < 4) {- dbits = 0;- dist += dist_slot;- } else {- dbits = dist_slot / 2 - 1;-- /* Cast to uint32_t will make sure the shift- * left operation won't produce undefined- * result. Then, the uint32_t type will- * be implicitly casted to int. */- dist += (uint32_t) (2 |- (dist_slot & 1)) << dbits;- }-- if(dbits > 0) {- if(dbits >= 4) {- uint32_t add = 0;- uint16_t low_dist;-- if(dbits > 4) {- if(ARCHIVE_OK != (ret = read_bits_32(- a, rar, p, &add))) {- /* Return EOF if we- * can't read more- * data. */- return ret;- }-- skip_bits(rar, dbits - 4);- add = (add >> (- 36 - dbits)) << 4;- dist += add;- }-- if(ARCHIVE_OK != decode_number(a,- &rar->cstate.ldd, p, &low_dist))- {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Failed to decode the "- "distance slot");-- return ARCHIVE_FATAL;- }-- if(dist >= INT_MAX - low_dist - 1) {- /* This only happens in- * invalid archives. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Distance pointer "- "overflow");- return ARCHIVE_FATAL;- }-- dist += low_dist;- } else {- /* dbits is one of [0,1,2,3] */- int add;-- if(ARCHIVE_OK != (ret = read_consume_bits(a, rar,- p, dbits, &add))) {- /* Return EOF if we can't read- * more data. */- return ret;- }-- dist += add;- }- }-- if(dist > 0x100) {- len++;-- if(dist > 0x2000) {- len++;-- if(dist > 0x40000) {- len++;- }- }- }-- dist_cache_push(rar, dist);- rar->cstate.last_len = len;-- if(ARCHIVE_OK != copy_string(a, len, dist))- return ARCHIVE_FATAL;-- continue;- } else if(num == 256) {- /* Create a filter. */- ret = parse_filter(a, p);- if(ret != ARCHIVE_OK)- return ret;-- continue;- } else if(num == 257) {- if(rar->cstate.last_len != 0) {- if(ARCHIVE_OK != copy_string(a,- rar->cstate.last_len,- rar->cstate.dist_cache[0]))- {- return ARCHIVE_FATAL;- }- }-- continue;- } else {- /* num < 262 */- const int idx = num - 258;- const int dist = dist_cache_touch(rar, idx);-- uint16_t len_slot;- int len;-- if(ARCHIVE_OK != decode_number(a, &rar->cstate.rd, p,- &len_slot)) {- return ARCHIVE_FATAL;- }-- len = decode_code_length(a, rar, p, len_slot);- if (len == -1) {- return ARCHIVE_FATAL;- }-- rar->cstate.last_len = len;-- if(ARCHIVE_OK != copy_string(a, len, dist))- return ARCHIVE_FATAL;-- continue;- }- }-- return ARCHIVE_OK;-}--/* Binary search for the RARv5 signature. */-static int scan_for_signature(struct archive_read* a) {- const uint8_t* p;- const int chunk_size = 512;- ssize_t i;- char signature[sizeof(rar5_signature_xor)];-- /* If we're here, it means we're on an 'unknown territory' data.- * There's no indication what kind of data we're reading here.- * It could be some text comment, any kind of binary data,- * digital sign, dragons, etc.- *- * We want to find a valid RARv5 magic header inside this unknown- * data. */-- /* Is it possible in libarchive to just skip everything until the- * end of the file? If so, it would be a better approach than the- * current implementation of this function. */-- rar5_signature(signature);-- while(1) {- if(!read_ahead(a, chunk_size, &p))- return ARCHIVE_EOF;-- for(i = 0; i < chunk_size - (int)sizeof(rar5_signature_xor);- i++) {- if(memcmp(&p[i], signature,- sizeof(rar5_signature_xor)) == 0) {- /* Consume the number of bytes we've used to- * search for the signature, as well as the- * number of bytes used by the signature- * itself. After this we should be standing- * on a valid base block header. */- (void) consume(a,- i + sizeof(rar5_signature_xor));- return ARCHIVE_OK;- }- }-- consume(a, chunk_size);- }-- return ARCHIVE_FATAL;-}--/* This function will switch the multivolume archive file to another file,- * i.e. from part03 to part 04. */-static int advance_multivolume(struct archive_read* a) {- int lret;- struct rar5* rar = get_context(a);-- /* A small state machine that will skip unnecessary data, needed to- * switch from one multivolume to another. Such skipping is needed if- * we want to be an stream-oriented (instead of file-oriented)- * unpacker.- *- * The state machine starts with `rar->main.endarc` == 0. It also- * assumes that current stream pointer points to some base block- * header.- *- * The `endarc` field is being set when the base block parsing- * function encounters the 'end of archive' marker.- */-- while(1) {- if(rar->main.endarc == 1) {- int looping = 1;-- rar->main.endarc = 0;-- while(looping) {- lret = skip_base_block(a);- switch(lret) {- case ARCHIVE_RETRY:- /* Continue looping. */- break;- case ARCHIVE_OK:- /* Break loop. */- looping = 0;- break;- default:- /* Forward any errors to the- * caller. */- return lret;- }- }-- break;- } else {- /* Skip current base block. In order to properly skip- * it, we really need to simply parse it and discard- * the results. */-- lret = skip_base_block(a);- if(lret == ARCHIVE_FATAL || lret == ARCHIVE_FAILED)- return lret;-- /* The `skip_base_block` function tells us if we- * should continue with skipping, or we should stop- * skipping. We're trying to skip everything up to- * a base FILE block. */-- if(lret != ARCHIVE_RETRY) {- /* If there was an error during skipping, or we- * have just skipped a FILE base block... */-- if(rar->main.endarc == 0) {- return lret;- } else {- continue;- }- }- }- }-- return ARCHIVE_OK;-}--/* Merges the partial block from the first multivolume archive file, and- * partial block from the second multivolume archive file. The result is- * a chunk of memory containing the whole block, and the stream pointer- * is advanced to the next block in the second multivolume archive file. */-static int merge_block(struct archive_read* a, ssize_t block_size,- const uint8_t** p)-{- struct rar5* rar = get_context(a);- ssize_t cur_block_size, partial_offset = 0;- const uint8_t* lp;- int ret;-- if(rar->merge_mode) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Recursive merge is not allowed");-- return ARCHIVE_FATAL;- }-- /* Set a flag that we're in the switching mode. */- rar->cstate.switch_multivolume = 1;-- /* Reallocate the memory which will hold the whole block. */- if(rar->vol.push_buf)- free((void*) rar->vol.push_buf);-- /* Increasing the allocation block by 8 is due to bit reading functions,- * which are using additional 2 or 4 bytes. Allocating the block size- * by exact value would make bit reader perform reads from invalid- * memory block when reading the last byte from the buffer. */- rar->vol.push_buf = malloc(block_size + 8);- if(!rar->vol.push_buf) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for a merge block buffer.");- return ARCHIVE_FATAL;- }-- /* Valgrind complains if the extension block for bit reader is not- * initialized, so initialize it. */- memset(&rar->vol.push_buf[block_size], 0, 8);-- /* A single block can span across multiple multivolume archive files,- * so we use a loop here. This loop will consume enough multivolume- * archive files until the whole block is read. */-- while(1) {- /* Get the size of current block chunk in this multivolume- * archive file and read it. */- cur_block_size = rar5_min(rar->file.bytes_remaining,- block_size - partial_offset);-- if(cur_block_size == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Encountered block size == 0 during block merge");- return ARCHIVE_FATAL;- }-- if(!read_ahead(a, cur_block_size, &lp))- return ARCHIVE_EOF;-- /* Sanity check; there should never be a situation where this- * function reads more data than the block's size. */- if(partial_offset + cur_block_size > block_size) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Consumed too much data when merging blocks.");- return ARCHIVE_FATAL;- }-- /* Merge previous block chunk with current block chunk,- * or create first block chunk if this is our first- * iteration. */- memcpy(&rar->vol.push_buf[partial_offset], lp, cur_block_size);-- /* Advance the stream read pointer by this block chunk size. */- if(ARCHIVE_OK != consume(a, cur_block_size))- return ARCHIVE_EOF;-- /* Update the pointers. `partial_offset` contains information- * about the sum of merged block chunks. */- partial_offset += cur_block_size;- rar->file.bytes_remaining -= cur_block_size;-- /* If `partial_offset` is the same as `block_size`, this means- * we've merged all block chunks and we have a valid full- * block. */- if(partial_offset == block_size) {- break;- }-- /* If we don't have any bytes to read, this means we should- * switch to another multivolume archive file. */- if(rar->file.bytes_remaining == 0) {- rar->merge_mode++;- ret = advance_multivolume(a);- rar->merge_mode--;- if(ret != ARCHIVE_OK) {- return ret;- }- }- }-- *p = rar->vol.push_buf;-- /* If we're here, we can resume unpacking by processing the block- * pointed to by the `*p` memory pointer. */-- return ARCHIVE_OK;-}--static int process_block(struct archive_read* a) {- const uint8_t* p;- struct rar5* rar = get_context(a);- int ret;-- /* If we don't have any data to be processed, this most probably means- * we need to switch to the next volume. */- if(rar->main.volume && rar->file.bytes_remaining == 0) {- ret = advance_multivolume(a);- if(ret != ARCHIVE_OK)- return ret;- }-- if(rar->cstate.block_parsing_finished) {- ssize_t block_size;- ssize_t to_skip;- ssize_t cur_block_size;-- /* The header size won't be bigger than 6 bytes. */- if(!read_ahead(a, 6, &p)) {- /* Failed to prefetch data block header. */- return ARCHIVE_EOF;- }-- /*- * Read block_size by parsing block header. Validate the header- * by calculating CRC byte stored inside the header. Size of- * the header is not constant (block size can be stored either- * in 1 or 2 bytes), that's why block size is left out from the- * `compressed_block_header` structure and returned by- * `parse_block_header` as the second argument. */-- ret = parse_block_header(a, p, &block_size,- &rar->last_block_hdr);- if(ret != ARCHIVE_OK) {- return ret;- }-- /* Skip block header. Next data is huffman tables,- * if present. */- to_skip = sizeof(struct compressed_block_header) +- bf_byte_count(&rar->last_block_hdr) + 1;-- if(ARCHIVE_OK != consume(a, to_skip))- return ARCHIVE_EOF;-- rar->file.bytes_remaining -= to_skip;-- /* The block size gives information about the whole block size,- * but the block could be stored in split form when using- * multi-volume archives. In this case, the block size will be- * bigger than the actual data stored in this file. Remaining- * part of the data will be in another file. */-- cur_block_size =- rar5_min(rar->file.bytes_remaining, block_size);-- if(block_size > rar->file.bytes_remaining) {- /* If current blocks' size is bigger than our data- * size, this means we have a multivolume archive.- * In this case, skip all base headers until the end- * of the file, proceed to next "partXXX.rar" volume,- * find its signature, skip all headers up to the first- * FILE base header, and continue from there.- *- * Note that `merge_block` will update the `rar`- * context structure quite extensively. */-- ret = merge_block(a, block_size, &p);- if(ret != ARCHIVE_OK) {- return ret;- }-- cur_block_size = block_size;-- /* Current stream pointer should be now directly- * *after* the block that spanned through multiple- * archive files. `p` pointer should have the data of- * the *whole* block (merged from partial blocks- * stored in multiple archives files). */- } else {- rar->cstate.switch_multivolume = 0;-- /* Read the whole block size into memory. This can take- * up to 8 megabytes of memory in theoretical cases.- * Might be worth to optimize this and use a standard- * chunk of 4kb's. */- if(!read_ahead(a, 4 + cur_block_size, &p)) {- /* Failed to prefetch block data. */- return ARCHIVE_EOF;- }- }-- rar->cstate.block_buf = p;- rar->cstate.cur_block_size = cur_block_size;- rar->cstate.block_parsing_finished = 0;-- rar->bits.in_addr = 0;- rar->bits.bit_addr = 0;-- if(bf_is_table_present(&rar->last_block_hdr)) {- /* Load Huffman tables. */- ret = parse_tables(a, rar, p);- if(ret != ARCHIVE_OK) {- /* Error during decompression of Huffman- * tables. */- return ret;- }- }- } else {- /* Block parsing not finished, reuse previous memory buffer. */- p = rar->cstate.block_buf;- }-- /* Uncompress the block, or a part of it, depending on how many bytes- * will be generated by uncompressing the block.- *- * In case too many bytes will be generated, calling this function- * again will resume the uncompression operation. */- ret = do_uncompress_block(a, p);- if(ret != ARCHIVE_OK) {- return ret;- }-- if(rar->cstate.block_parsing_finished &&- rar->cstate.switch_multivolume == 0 &&- rar->cstate.cur_block_size > 0)- {- /* If we're processing a normal block, consume the whole- * block. We can do this because we've already read the whole- * block to memory. */- if(ARCHIVE_OK != consume(a, rar->cstate.cur_block_size))- return ARCHIVE_FATAL;-- rar->file.bytes_remaining -= rar->cstate.cur_block_size;- } else if(rar->cstate.switch_multivolume) {- /* Don't consume the block if we're doing multivolume- * processing. The volume switching function will consume- * the proper count of bytes instead. */- rar->cstate.switch_multivolume = 0;- }-- return ARCHIVE_OK;-}--/* Pops the `buf`, `size` and `offset` from the "data ready" stack.- *- * Returns ARCHIVE_OK when those arguments can be used, ARCHIVE_RETRY- * when there is no data on the stack. */-static int use_data(struct rar5* rar, const void** buf, size_t* size,- int64_t* offset)-{- int i;-- for(i = 0; i < rar5_countof(rar->cstate.dready); i++) {- struct data_ready *d = &rar->cstate.dready[i];-- if(d->used) {- if(buf) *buf = d->buf;- if(size) *size = d->size;- if(offset) *offset = d->offset;-- d->used = 0;- return ARCHIVE_OK;- }- }-- return ARCHIVE_RETRY;-}--/* Pushes the `buf`, `size` and `offset` arguments to the rar->cstate.dready- * FIFO stack. Those values will be popped from this stack by the `use_data`- * function. */-static int push_data_ready(struct archive_read* a, struct rar5* rar,- const uint8_t* buf, size_t size, int64_t offset)-{- int i;-- /* Don't push if we're in skip mode. This is needed because solid- * streams need full processing even if we're skipping data. After- * fully processing the stream, we need to discard the generated bytes,- * because we're interested only in the side effect: building up the- * internal window circular buffer. This window buffer will be used- * later during unpacking of requested data. */- if(rar->skip_mode)- return ARCHIVE_OK;-- /* Sanity check. */- if(offset != rar->file.last_offset + rar->file.last_size) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Sanity check error: output stream is not continuous");- return ARCHIVE_FATAL;- }-- for(i = 0; i < rar5_countof(rar->cstate.dready); i++) {- struct data_ready* d = &rar->cstate.dready[i];- if(!d->used) {- d->used = 1;- d->buf = buf;- d->size = size;- d->offset = offset;-- /* These fields are used only in sanity checking. */- rar->file.last_offset = offset;- rar->file.last_size = size;-- /* Calculate the checksum of this new block before- * submitting data to libarchive's engine. */- update_crc(rar, d->buf, d->size);-- return ARCHIVE_OK;- }- }-- /* Program counter will reach this code if the `rar->cstate.data_ready`- * stack will be filled up so that no new entries will be allowed. The- * code shouldn't allow such situation to occur. So we treat this case- * as an internal error. */-- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Error: premature end of data_ready stack");- return ARCHIVE_FATAL;-}--/* This function uncompresses the data that is stored in the <FILE> base- * block.- *- * The FILE base block looks like this:- *- * <header><huffman tables><block_1><block_2>...<block_n>- *- * The <header> is a block header, that is parsed in parse_block_header().- * It's a "compressed_block_header" structure, containing metadata needed- * to know when we should stop looking for more <block_n> blocks.- *- * <huffman tables> contain data needed to set up the huffman tables, needed- * for the actual decompression.- *- * Each <block_n> consists of series of literals:- *- * <literal><literal><literal>...<literal>- *- * Those literals generate the uncompression data. They operate on a circular- * buffer, sometimes writing raw data into it, sometimes referencing- * some previous data inside this buffer, and sometimes declaring a filter- * that will need to be executed on the data stored in the circular buffer.- * It all depends on the literal that is used.- *- * Sometimes blocks produce output data, sometimes they don't. For example, for- * some huge files that use lots of filters, sometimes a block is filled with- * only filter declaration literals. Such blocks won't produce any data in the- * circular buffer.- *- * Sometimes blocks will produce 4 bytes of data, and sometimes 1 megabyte,- * because a literal can reference previously decompressed data. For example,- * there can be a literal that says: 'append a byte 0xFE here', and after- * it another literal can say 'append 1 megabyte of data from circular buffer- * offset 0x12345'. This is how RAR format handles compressing repeated- * patterns.- *- * The RAR compressor creates those literals and the actual efficiency of- * compression depends on what those literals are. The literals can also- * be seen as a kind of a non-turing-complete virtual machine that simply- * tells the decompressor what it should do.- * */--static int do_uncompress_file(struct archive_read* a) {- struct rar5* rar = get_context(a);- int ret;- int64_t max_end_pos;-- if(!rar->cstate.initialized) {- /* Don't perform full context reinitialization if we're- * processing a solid archive. */- if(!rar->main.solid || !rar->cstate.window_buf) {- init_unpack(rar);- }-- rar->cstate.initialized = 1;- }-- /* Don't allow extraction if window_size is invalid. */- if(rar->cstate.window_size == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid window size declaration in this file");-- /* This should never happen in valid files. */- return ARCHIVE_FATAL;- }-- if(rar->cstate.all_filters_applied == 1) {- /* We use while(1) here, but standard case allows for just 1- * iteration. The loop will iterate if process_block() didn't- * generate any data at all. This can happen if the block- * contains only filter definitions (this is common in big- * files). */- while(1) {- ret = process_block(a);- if(ret == ARCHIVE_EOF || ret == ARCHIVE_FATAL)- return ret;-- if(rar->cstate.last_write_ptr ==- rar->cstate.write_ptr) {- /* The block didn't generate any new data,- * so just process a new block. */- continue;- }-- /* The block has generated some new data, so break- * the loop. */- break;- }- }-- /* Try to run filters. If filters won't be applied, it means that- * insufficient data was generated. */- ret = apply_filters(a);- if(ret == ARCHIVE_RETRY) {- return ARCHIVE_OK;- } else if(ret == ARCHIVE_FATAL) {- return ARCHIVE_FATAL;- }-- /* If apply_filters() will return ARCHIVE_OK, we can continue here. */-- if(cdeque_size(&rar->cstate.filters) > 0) {- /* Check if we can write something before hitting first- * filter. */- struct filter_info* flt;-- /* Get the block_start offset from the first filter. */- if(CDE_OK != cdeque_front(&rar->cstate.filters,- cdeque_filter_p(&flt)))- {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_PROGRAMMER,- "Can't read first filter");- return ARCHIVE_FATAL;- }-- max_end_pos = rar5_min(flt->block_start,- rar->cstate.write_ptr);- } else {- /* There are no filters defined, or all filters were applied.- * This means we can just store the data without any- * postprocessing. */- max_end_pos = rar->cstate.write_ptr;- }-- if(max_end_pos == rar->cstate.last_write_ptr) {- /* We can't write anything yet. The block uncompression- * function did not generate enough data, and no filter can be- * applied. At the same time we don't have any data that can be- * stored without filter postprocessing. This means we need to- * wait for more data to be generated, so we can apply the- * filters.- *- * Signal the caller that we need more data to be able to do- * anything.- */- return ARCHIVE_RETRY;- } else {- /* We can write the data before hitting the first filter.- * So let's do it. The push_window_data() function will- * effectively return the selected data block to the user- * application. */- push_window_data(a, rar, rar->cstate.last_write_ptr,- max_end_pos);- rar->cstate.last_write_ptr = max_end_pos;- }-- return ARCHIVE_OK;-}--static int uncompress_file(struct archive_read* a) {- int ret;-- while(1) {- /* Sometimes the uncompression function will return a- * 'retry' signal. If this will happen, we have to retry- * the function. */- ret = do_uncompress_file(a);- if(ret != ARCHIVE_RETRY)- return ret;- }-}---static int do_unstore_file(struct archive_read* a,- struct rar5* rar, const void** buf, size_t* size, int64_t* offset)-{- size_t to_read;- const uint8_t* p;-- if(rar->file.bytes_remaining == 0 && rar->main.volume > 0 &&- rar->generic.split_after > 0)- {- int ret;-- rar->cstate.switch_multivolume = 1;- ret = advance_multivolume(a);- rar->cstate.switch_multivolume = 0;-- if(ret != ARCHIVE_OK) {- /* Failed to advance to next multivolume archive- * file. */- return ret;- }- }-- to_read = rar5_min(rar->file.bytes_remaining, 64 * 1024);- if(to_read == 0) {- return ARCHIVE_EOF;- }-- if(!read_ahead(a, to_read, &p)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "I/O error when unstoring file");- return ARCHIVE_FATAL;- }-- if(ARCHIVE_OK != consume(a, to_read)) {- return ARCHIVE_EOF;- }-- if(buf) *buf = p;- if(size) *size = to_read;- if(offset) *offset = rar->cstate.last_unstore_ptr;-- rar->file.bytes_remaining -= to_read;- rar->cstate.last_unstore_ptr += to_read;-- update_crc(rar, p, to_read);- return ARCHIVE_OK;-}--static int do_unpack(struct archive_read* a, struct rar5* rar,- const void** buf, size_t* size, int64_t* offset)-{- enum COMPRESSION_METHOD {- STORE = 0, FASTEST = 1, FAST = 2, NORMAL = 3, GOOD = 4,- BEST = 5- };-- if(rar->file.service > 0) {- return do_unstore_file(a, rar, buf, size, offset);- } else {- switch(rar->cstate.method) {- case STORE:- return do_unstore_file(a, rar, buf, size,- offset);- case FASTEST:- /* fallthrough */- case FAST:- /* fallthrough */- case NORMAL:- /* fallthrough */- case GOOD:- /* fallthrough */- case BEST:- /* No data is returned here. But because a sparse-file aware- * caller (like archive_read_data_into_fd) may treat zero-size- * as a sparse file block, we need to update the offset- * accordingly. At this point the decoder doesn't have any- * pending uncompressed data blocks, so the current position in- * the output file should be last_write_ptr. */- if (offset) *offset = rar->cstate.last_write_ptr;- return uncompress_file(a);- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Compression method not supported: 0x%x",- rar->cstate.method);-- return ARCHIVE_FATAL;- }- }--#if !defined WIN32- /* Not reached. */- return ARCHIVE_OK;-#endif-}--static int verify_checksums(struct archive_read* a) {- int verify_crc;- struct rar5* rar = get_context(a);-- /* Check checksums only when actually unpacking the data. There's no- * need to calculate checksum when we're skipping data in solid archives- * (skipping in solid archives is the same thing as unpacking compressed- * data and discarding the result). */-- if(!rar->skip_mode) {- /* Always check checksums if we're not in skip mode */- verify_crc = 1;- } else {- /* We can override the logic above with a compile-time option- * NO_CRC_ON_SOLID_SKIP. This option is used during debugging,- * and it will check checksums of unpacked data even when- * we're skipping it. */--#if defined CHECK_CRC_ON_SOLID_SKIP- /* Debug case */- verify_crc = 1;-#else- /* Normal case */- verify_crc = 0;-#endif- }-- if(verify_crc) {- /* During unpacking, on each unpacked block we're calling the- * update_crc() function. Since we are here, the unpacking- * process is already over and we can check if calculated- * checksum (CRC32 or BLAKE2sp) is the same as what is stored- * in the archive. */- if(rar->file.stored_crc32 > 0) {- /* Check CRC32 only when the file contains a CRC32- * value for this file. */-- if(rar->file.calculated_crc32 !=- rar->file.stored_crc32) {- /* Checksums do not match; the unpacked file- * is corrupted. */-- DEBUG_CODE {- printf("Checksum error: CRC32 "- "(was: %08" PRIx32 ", expected: %08" PRIx32 ")\n",- rar->file.calculated_crc32,- rar->file.stored_crc32);- }--#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Checksum error: CRC32");- return ARCHIVE_FATAL;-#endif- } else {- DEBUG_CODE {- printf("Checksum OK: CRC32 "- "(%08" PRIx32 "/%08" PRIx32 ")\n",- rar->file.stored_crc32,- rar->file.calculated_crc32);- }- }- }-- if(rar->file.has_blake2 > 0) {- /* BLAKE2sp is an optional checksum algorithm that is- * added to RARv5 archives when using the `-htb` switch- * during creation of archive.- *- * We now finalize the hash calculation by calling the- * `final` function. This will generate the final hash- * value we can use to compare it with the BLAKE2sp- * checksum that is stored in the archive.- *- * The return value of this `final` function is not- * very helpful, as it guards only against improper use.- * This is why we're explicitly ignoring it. */-- uint8_t b2_buf[32];- (void) blake2sp_final(&rar->file.b2state, b2_buf, 32);-- if(memcmp(&rar->file.blake2sp, b2_buf, 32) != 0) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Checksum error: BLAKE2");-- return ARCHIVE_FATAL;-#endif- }- }- }-- /* Finalization for this file has been successfully completed. */- return ARCHIVE_OK;-}--static int verify_global_checksums(struct archive_read* a) {- return verify_checksums(a);-}--/*- * Decryption function for the magic signature pattern. Check the comment near- * the `rar5_signature_xor` symbol to read the rationale behind this.- */-static void rar5_signature(char *buf) {- size_t i;-- for(i = 0; i < sizeof(rar5_signature_xor); i++) {- buf[i] = rar5_signature_xor[i] ^ 0xA1;- }-}--static int rar5_read_data(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset) {- int ret;- struct rar5* rar = get_context(a);-- if (size)- *size = 0;-- if(rar->file.dir > 0) {- /* Don't process any data if this file entry was declared- * as a directory. This is needed, because entries marked as- * directory doesn't have any dictionary buffer allocated, so- * it's impossible to perform any decompression. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't decompress an entry marked as a directory");- return ARCHIVE_FAILED;- }-- if(!rar->skip_mode && (rar->cstate.last_write_ptr > rar->file.unpacked_size)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "Unpacker has written too many bytes");- return ARCHIVE_FATAL;- }-- ret = use_data(rar, buff, size, offset);- if(ret == ARCHIVE_OK) {- return ret;- }-- if(rar->file.eof == 1) {- return ARCHIVE_EOF;- }-- ret = do_unpack(a, rar, buff, size, offset);- if(ret != ARCHIVE_OK) {- return ret;- }-- if(rar->file.bytes_remaining == 0 &&- rar->cstate.last_write_ptr == rar->file.unpacked_size)- {- /* If all bytes of current file were processed, run- * finalization.- *- * Finalization will check checksum against proper values. If- * some of the checksums will not match, we'll return an error- * value in the last `archive_read_data` call to signal an error- * to the user. */-- rar->file.eof = 1;- return verify_global_checksums(a);- }-- return ARCHIVE_OK;-}--static int rar5_read_data_skip(struct archive_read *a) {- struct rar5* rar = get_context(a);-- if(rar->main.solid) {- /* In solid archives, instead of skipping the data, we need to- * extract it, and dispose the result. The side effect of this- * operation will be setting up the initial window buffer state- * needed to be able to extract the selected file. */-- int ret;-- /* Make sure to process all blocks in the compressed stream. */- while(rar->file.bytes_remaining > 0) {- /* Setting the "skip mode" will allow us to skip- * checksum checks during data skipping. Checking the- * checksum of skipped data isn't really necessary and- * it's only slowing things down.- *- * This is incremented instead of setting to 1 because- * this data skipping function can be called- * recursively. */- rar->skip_mode++;-- /* We're disposing 1 block of data, so we use triple- * NULLs in arguments. */- ret = rar5_read_data(a, NULL, NULL, NULL);-- /* Turn off "skip mode". */- rar->skip_mode--;-- if(ret < 0 || ret == ARCHIVE_EOF) {- /* Propagate any potential error conditions- * to the caller. */- return ret;- }- }- } else {- /* In standard archives, we can just jump over the compressed- * stream. Each file in non-solid archives starts from an empty- * window buffer. */-- if(ARCHIVE_OK != consume(a, rar->file.bytes_remaining)) {- return ARCHIVE_FATAL;- }-- rar->file.bytes_remaining = 0;- }-- return ARCHIVE_OK;-}--static int64_t rar5_seek_data(struct archive_read *a, int64_t offset,- int whence)-{- (void) a;- (void) offset;- (void) whence;-- /* We're a streaming unpacker, and we don't support seeking. */-- return ARCHIVE_FATAL;-}--static int rar5_cleanup(struct archive_read *a) {- struct rar5* rar = get_context(a);-- free(rar->cstate.window_buf);- free(rar->cstate.filtered_buf);-- free(rar->vol.push_buf);-- free_filters(rar);- cdeque_free(&rar->cstate.filters);-- free(rar);- a->format->data = NULL;-- return ARCHIVE_OK;-}--static int rar5_capabilities(struct archive_read * a) {- (void) a;- return 0;-}--static int rar5_has_encrypted_entries(struct archive_read *_a) {- (void) _a;-- /* Unsupported for now. */- return ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED;-}--static int rar5_init(struct rar5* rar) {- memset(rar, 0, sizeof(struct rar5));-- if(CDE_OK != cdeque_init(&rar->cstate.filters, 8192))- return ARCHIVE_FATAL;-- return ARCHIVE_OK;-}--int archive_read_support_format_rar5(struct archive *_a) {- struct archive_read* ar;- int ret;- struct rar5* rar;-- if(ARCHIVE_OK != (ret = get_archive_read(_a, &ar)))- return ret;-- rar = malloc(sizeof(*rar));- if(rar == NULL) {- archive_set_error(&ar->archive, ENOMEM,- "Can't allocate rar5 data");- return ARCHIVE_FATAL;- }-- if(ARCHIVE_OK != rar5_init(rar)) {- archive_set_error(&ar->archive, ENOMEM,- "Can't allocate rar5 filter buffer");- free(rar);- return ARCHIVE_FATAL;- }-- ret = __archive_read_register_format(ar,- rar,- "rar5",- rar5_bid,- rar5_options,- rar5_read_header,- rar5_read_data,- rar5_read_data_skip,- rar5_seek_data,- rar5_cleanup,- rar5_capabilities,- rar5_has_encrypted_entries);-- if(ret != ARCHIVE_OK) {- (void) rar5_cleanup(ar);- }-- return ret;-}
− c/archive_read_support_format_raw.c
@@ -1,192 +0,0 @@-/*-- * Copyright (c) 2003-2009 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */-#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_raw.c 201107 2009-12-28 03:25:33Z kientzle $");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#include <stdio.h>-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_private.h"--struct raw_info {- int64_t offset; /* Current position in the file. */- int64_t unconsumed;- int end_of_file;-};--static int archive_read_format_raw_bid(struct archive_read *, int);-static int archive_read_format_raw_cleanup(struct archive_read *);-static int archive_read_format_raw_read_data(struct archive_read *,- const void **, size_t *, int64_t *);-static int archive_read_format_raw_read_data_skip(struct archive_read *);-static int archive_read_format_raw_read_header(struct archive_read *,- struct archive_entry *);--int-archive_read_support_format_raw(struct archive *_a)-{- struct raw_info *info;- struct archive_read *a = (struct archive_read *)_a;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_raw");-- info = (struct raw_info *)calloc(1, sizeof(*info));- if (info == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate raw_info data");- return (ARCHIVE_FATAL);- }-- r = __archive_read_register_format(a,- info,- "raw",- archive_read_format_raw_bid,- NULL,- archive_read_format_raw_read_header,- archive_read_format_raw_read_data,- archive_read_format_raw_read_data_skip,- NULL,- archive_read_format_raw_cleanup,- NULL,- NULL);- if (r != ARCHIVE_OK)- free(info);- return (r);-}--/*- * Bid 1 if this is a non-empty file. Anyone who can really support- * this should outbid us, so it should generally be safe to use "raw"- * in conjunction with other formats. But, this could really confuse- * folks if there are bid errors or minor file damage, so we don't- * include "raw" as part of support_format_all().- */-static int-archive_read_format_raw_bid(struct archive_read *a, int best_bid)-{- if (best_bid < 1 && __archive_read_ahead(a, 1, NULL) != NULL)- return (1);- return (-1);-}--/*- * Mock up a fake header.- */-static int-archive_read_format_raw_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct raw_info *info;-- info = (struct raw_info *)(a->format->data);- if (info->end_of_file)- return (ARCHIVE_EOF);-- a->archive.archive_format = ARCHIVE_FORMAT_RAW;- a->archive.archive_format_name = "raw";- archive_entry_set_pathname(entry, "data");- archive_entry_set_filetype(entry, AE_IFREG);- archive_entry_set_perm(entry, 0644);- /* I'm deliberately leaving most fields unset here. */-- /* Let the filter fill out any fields it might have. */- return __archive_read_header(a, entry);-}--static int-archive_read_format_raw_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- struct raw_info *info;- ssize_t avail;-- info = (struct raw_info *)(a->format->data);-- /* Consume the bytes we read last time. */- if (info->unconsumed) {- __archive_read_consume(a, info->unconsumed);- info->unconsumed = 0;- }-- if (info->end_of_file)- return (ARCHIVE_EOF);-- /* Get whatever bytes are immediately available. */- *buff = __archive_read_ahead(a, 1, &avail);- if (avail > 0) {- /* Return the bytes we just read */- *size = avail;- *offset = info->offset;- info->offset += *size;- info->unconsumed = avail;- return (ARCHIVE_OK);- } else if (0 == avail) {- /* Record and return end-of-file. */- info->end_of_file = 1;- *size = 0;- *offset = info->offset;- return (ARCHIVE_EOF);- } else {- /* Record and return an error. */- *size = 0;- *offset = info->offset;- return ((int)avail);- }-}--static int-archive_read_format_raw_read_data_skip(struct archive_read *a)-{- struct raw_info *info = (struct raw_info *)(a->format->data);-- /* Consume the bytes we read last time. */- if (info->unconsumed) {- __archive_read_consume(a, info->unconsumed);- info->unconsumed = 0;- }- info->end_of_file = 1;- return (ARCHIVE_OK);-}--static int-archive_read_format_raw_cleanup(struct archive_read *a)-{- struct raw_info *info;-- info = (struct raw_info *)(a->format->data);- free(info);- a->format->data = NULL;- return (ARCHIVE_OK);-}
− c/archive_read_support_format_tar.c
@@ -1,2946 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- * Copyright (c) 2016 Martin Matuska- * 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_read_support_format_tar.c 201161 2009-12-29 05:44:39Z kientzle $");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#include <stddef.h>-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_acl_private.h" /* For ACL parsing routines. */-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_read_private.h"--#define tar_min(a,b) ((a) < (b) ? (a) : (b))--/*- * Layout of POSIX 'ustar' tar header.- */-struct archive_entry_header_ustar {- char name[100];- char mode[8];- char uid[8];- char gid[8];- char size[12];- char mtime[12];- char checksum[8];- char typeflag[1];- char linkname[100]; /* "old format" header ends here */- char magic[6]; /* For POSIX: "ustar\0" */- char version[2]; /* For POSIX: "00" */- char uname[32];- char gname[32];- char rdevmajor[8];- char rdevminor[8];- char prefix[155];-};--/*- * Structure of GNU tar header- */-struct gnu_sparse {- char offset[12];- char numbytes[12];-};--struct archive_entry_header_gnutar {- char name[100];- char mode[8];- char uid[8];- char gid[8];- char size[12];- char mtime[12];- char checksum[8];- char typeflag[1];- char linkname[100];- char magic[8]; /* "ustar \0" (note blank/blank/null at end) */- char uname[32];- char gname[32];- char rdevmajor[8];- char rdevminor[8];- char atime[12];- char ctime[12];- char offset[12];- char longnames[4];- char unused[1];- struct gnu_sparse sparse[4];- char isextended[1];- char realsize[12];- /*- * Old GNU format doesn't use POSIX 'prefix' field; they use- * the 'L' (longname) entry instead.- */-};--/*- * Data specific to this format.- */-struct sparse_block {- struct sparse_block *next;- int64_t offset;- int64_t remaining;- int hole;-};--struct tar {- struct archive_string acl_text;- struct archive_string entry_pathname;- /* For "GNU.sparse.name" and other similar path extensions. */- struct archive_string entry_pathname_override;- struct archive_string entry_linkpath;- struct archive_string entry_uname;- struct archive_string entry_gname;- struct archive_string longlink;- struct archive_string longname;- struct archive_string pax_header;- struct archive_string pax_global;- struct archive_string line;- int pax_hdrcharset_binary;- int header_recursion_depth;- int64_t entry_bytes_remaining;- int64_t entry_offset;- int64_t entry_padding;- int64_t entry_bytes_unconsumed;- int64_t realsize;- int sparse_allowed;- struct sparse_block *sparse_list;- struct sparse_block *sparse_last;- int64_t sparse_offset;- int64_t sparse_numbytes;- int sparse_gnu_major;- int sparse_gnu_minor;- char sparse_gnu_pending;-- struct archive_string localname;- struct archive_string_conv *opt_sconv;- struct archive_string_conv *sconv;- struct archive_string_conv *sconv_acl;- struct archive_string_conv *sconv_default;- int init_default_conversion;- int compat_2x;- int process_mac_extensions;- int read_concatenated_archives;- int realsize_override;-};--static int archive_block_is_null(const char *p);-static char *base64_decode(const char *, size_t, size_t *);-static int gnu_add_sparse_entry(struct archive_read *, struct tar *,- int64_t offset, int64_t remaining);--static void gnu_clear_sparse_list(struct tar *);-static int gnu_sparse_old_read(struct archive_read *, struct tar *,- const struct archive_entry_header_gnutar *header, size_t *);-static int gnu_sparse_old_parse(struct archive_read *, struct tar *,- const struct gnu_sparse *sparse, int length);-static int gnu_sparse_01_parse(struct archive_read *, struct tar *,- const char *);-static ssize_t gnu_sparse_10_read(struct archive_read *, struct tar *,- size_t *);-static int header_Solaris_ACL(struct archive_read *, struct tar *,- struct archive_entry *, const void *, size_t *);-static int header_common(struct archive_read *, struct tar *,- struct archive_entry *, const void *);-static int header_old_tar(struct archive_read *, struct tar *,- struct archive_entry *, const void *);-static int header_pax_extensions(struct archive_read *, struct tar *,- struct archive_entry *, const void *, size_t *);-static int header_pax_global(struct archive_read *, struct tar *,- struct archive_entry *, const void *h, size_t *);-static int header_longlink(struct archive_read *, struct tar *,- struct archive_entry *, const void *h, size_t *);-static int header_longname(struct archive_read *, struct tar *,- struct archive_entry *, const void *h, size_t *);-static int read_mac_metadata_blob(struct archive_read *, struct tar *,- struct archive_entry *, const void *h, size_t *);-static int header_volume(struct archive_read *, struct tar *,- struct archive_entry *, const void *h, size_t *);-static int header_ustar(struct archive_read *, struct tar *,- struct archive_entry *, const void *h);-static int header_gnutar(struct archive_read *, struct tar *,- struct archive_entry *, const void *h, size_t *);-static int archive_read_format_tar_bid(struct archive_read *, int);-static int archive_read_format_tar_options(struct archive_read *,- const char *, const char *);-static int archive_read_format_tar_cleanup(struct archive_read *);-static int archive_read_format_tar_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset);-static int archive_read_format_tar_skip(struct archive_read *a);-static int archive_read_format_tar_read_header(struct archive_read *,- struct archive_entry *);-static int checksum(struct archive_read *, const void *);-static int pax_attribute(struct archive_read *, struct tar *,- struct archive_entry *, const char *key, const char *value,- size_t value_length);-static int pax_attribute_acl(struct archive_read *, struct tar *,- struct archive_entry *, const char *, int);-static int pax_attribute_xattr(struct archive_entry *, const char *,- const char *);-static int pax_header(struct archive_read *, struct tar *,- struct archive_entry *, struct archive_string *);-static void pax_time(const char *, int64_t *sec, long *nanos);-static ssize_t readline(struct archive_read *, struct tar *, const char **,- ssize_t limit, size_t *);-static int read_body_to_string(struct archive_read *, struct tar *,- struct archive_string *, const void *h, size_t *);-static int solaris_sparse_parse(struct archive_read *, struct tar *,- struct archive_entry *, const char *);-static int64_t tar_atol(const char *, size_t);-static int64_t tar_atol10(const char *, size_t);-static int64_t tar_atol256(const char *, size_t);-static int64_t tar_atol8(const char *, size_t);-static int tar_read_header(struct archive_read *, struct tar *,- struct archive_entry *, size_t *);-static int tohex(int c);-static char *url_decode(const char *);-static void tar_flush_unconsumed(struct archive_read *, size_t *);---int-archive_read_support_format_gnutar(struct archive *a)-{- archive_check_magic(a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_gnutar");- return (archive_read_support_format_tar(a));-}---int-archive_read_support_format_tar(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct tar *tar;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_tar");-- tar = (struct tar *)calloc(1, sizeof(*tar));- if (tar == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate tar data");- return (ARCHIVE_FATAL);- }-#ifdef HAVE_COPYFILE_H- /* Set this by default on Mac OS. */- tar->process_mac_extensions = 1;-#endif-- r = __archive_read_register_format(a, tar, "tar",- archive_read_format_tar_bid,- archive_read_format_tar_options,- archive_read_format_tar_read_header,- archive_read_format_tar_read_data,- archive_read_format_tar_skip,- NULL,- archive_read_format_tar_cleanup,- NULL,- NULL);-- if (r != ARCHIVE_OK)- free(tar);- return (ARCHIVE_OK);-}--static int-archive_read_format_tar_cleanup(struct archive_read *a)-{- struct tar *tar;-- tar = (struct tar *)(a->format->data);- gnu_clear_sparse_list(tar);- archive_string_free(&tar->acl_text);- archive_string_free(&tar->entry_pathname);- archive_string_free(&tar->entry_pathname_override);- archive_string_free(&tar->entry_linkpath);- archive_string_free(&tar->entry_uname);- archive_string_free(&tar->entry_gname);- archive_string_free(&tar->line);- archive_string_free(&tar->pax_global);- archive_string_free(&tar->pax_header);- archive_string_free(&tar->longname);- archive_string_free(&tar->longlink);- archive_string_free(&tar->localname);- free(tar);- (a->format->data) = NULL;- return (ARCHIVE_OK);-}--/*- * Validate number field- *- * This has to be pretty lenient in order to accommodate the enormous- * variety of tar writers in the world:- * = POSIX (IEEE Std 1003.1-1988) ustar requires octal values with leading- * zeros and allows fields to be terminated with space or null characters- * = Many writers use different termination (in particular, libarchive- * omits terminator bytes to squeeze one or two more digits)- * = Many writers pad with space and omit leading zeros- * = GNU tar and star write base-256 values if numbers are too- * big to be represented in octal- *- * Examples of specific tar headers that we should support:- * = Perl Archive::Tar terminates uid, gid, devminor and devmajor with two- * null bytes, pads size with spaces and other numeric fields with zeroes- * = plexus-archiver prior to 2.6.3 (before switching to commons-compress)- * may have uid and gid fields filled with spaces without any octal digits- * at all and pads all numeric fields with spaces- *- * This should tolerate all variants in use. It will reject a field- * where the writer just left garbage after a trailing NUL.- */-static int-validate_number_field(const char* p_field, size_t i_size)-{- unsigned char marker = (unsigned char)p_field[0];- if (marker == 128 || marker == 255 || marker == 0) {- /* Base-256 marker, there's nothing we can check. */- return 1;- } else {- /* Must be octal */- size_t i = 0;- /* Skip any leading spaces */- while (i < i_size && p_field[i] == ' ') {- ++i;- }- /* Skip octal digits. */- while (i < i_size && p_field[i] >= '0' && p_field[i] <= '7') {- ++i;- }- /* Any remaining characters must be space or NUL padding. */- while (i < i_size) {- if (p_field[i] != ' ' && p_field[i] != 0) {- return 0;- }- ++i;- }- return 1;- }-}--static int-archive_read_format_tar_bid(struct archive_read *a, int best_bid)-{- int bid;- const char *h;- const struct archive_entry_header_ustar *header;-- (void)best_bid; /* UNUSED */-- bid = 0;-- /* Now let's look at the actual header and see if it matches. */- h = __archive_read_ahead(a, 512, NULL);- if (h == NULL)- return (-1);-- /* If it's an end-of-archive mark, we can handle it. */- if (h[0] == 0 && archive_block_is_null(h)) {- /*- * Usually, I bid the number of bits verified, but- * in this case, 4096 seems excessive so I picked 10 as- * an arbitrary but reasonable-seeming value.- */- return (10);- }-- /* If it's not an end-of-archive mark, it must have a valid checksum.*/- if (!checksum(a, h))- return (0);- bid += 48; /* Checksum is usually 6 octal digits. */-- header = (const struct archive_entry_header_ustar *)h;-- /* Recognize POSIX formats. */- if ((memcmp(header->magic, "ustar\0", 6) == 0)- && (memcmp(header->version, "00", 2) == 0))- bid += 56;-- /* Recognize GNU tar format. */- if ((memcmp(header->magic, "ustar ", 6) == 0)- && (memcmp(header->version, " \0", 2) == 0))- bid += 56;-- /* Type flag must be null, digit or A-Z, a-z. */- if (header->typeflag[0] != 0 &&- !( header->typeflag[0] >= '0' && header->typeflag[0] <= '9') &&- !( header->typeflag[0] >= 'A' && header->typeflag[0] <= 'Z') &&- !( header->typeflag[0] >= 'a' && header->typeflag[0] <= 'z') )- return (0);- bid += 2; /* 6 bits of variation in an 8-bit field leaves 2 bits. */-- /*- * Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields.- */- if (validate_number_field(header->mode, sizeof(header->mode)) == 0- || validate_number_field(header->uid, sizeof(header->uid)) == 0- || validate_number_field(header->gid, sizeof(header->gid)) == 0- || validate_number_field(header->mtime, sizeof(header->mtime)) == 0- || validate_number_field(header->size, sizeof(header->size)) == 0- || validate_number_field(header->rdevmajor, sizeof(header->rdevmajor)) == 0- || validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0) {- bid = 0;- }-- return (bid);-}--static int-archive_read_format_tar_options(struct archive_read *a,- const char *key, const char *val)-{- struct tar *tar;- int ret = ARCHIVE_FAILED;-- tar = (struct tar *)(a->format->data);- if (strcmp(key, "compat-2x") == 0) {- /* Handle UTF-8 filenames as libarchive 2.x */- tar->compat_2x = (val != NULL && val[0] != 0);- tar->init_default_conversion = tar->compat_2x;- return (ARCHIVE_OK);- } else if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "tar: hdrcharset option needs a character-set name");- else {- tar->opt_sconv =- archive_string_conversion_from_charset(- &a->archive, val, 0);- if (tar->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- } else if (strcmp(key, "mac-ext") == 0) {- tar->process_mac_extensions = (val != NULL && val[0] != 0);- return (ARCHIVE_OK);- } else if (strcmp(key, "read_concatenated_archives") == 0) {- tar->read_concatenated_archives = (val != NULL && val[0] != 0);- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--/* utility function- this exists to centralize the logic of tracking- * how much unconsumed data we have floating around, and to consume- * anything outstanding since we're going to do read_aheads- */-static void-tar_flush_unconsumed(struct archive_read *a, size_t *unconsumed)-{- if (*unconsumed) {-/*- void *data = (void *)__archive_read_ahead(a, *unconsumed, NULL);- * this block of code is to poison claimed unconsumed space, ensuring- * things break if it is in use still.- * currently it WILL break things, so enable it only for debugging this issue- if (data) {- memset(data, 0xff, *unconsumed);- }-*/- __archive_read_consume(a, *unconsumed);- *unconsumed = 0;- }-}--/*- * The function invoked by archive_read_next_header(). This- * just sets up a few things and then calls the internal- * tar_read_header() function below.- */-static int-archive_read_format_tar_read_header(struct archive_read *a,- struct archive_entry *entry)-{- /*- * When converting tar archives to cpio archives, it is- * essential that each distinct file have a distinct inode- * number. To simplify this, we keep a static count here to- * assign fake dev/inode numbers to each tar entry. Note that- * pax format archives may overwrite this with something more- * useful.- *- * Ideally, we would track every file read from the archive so- * that we could assign the same dev/ino pair to hardlinks,- * but the memory required to store a complete lookup table is- * probably not worthwhile just to support the relatively- * obscure tar->cpio conversion case.- */- static int default_inode;- static int default_dev;- struct tar *tar;- const char *p;- const wchar_t *wp;- int r;- size_t l, unconsumed = 0;-- /* Assign default device/inode values. */- archive_entry_set_dev(entry, 1 + default_dev); /* Don't use zero. */- archive_entry_set_ino(entry, ++default_inode); /* Don't use zero. */- /* Limit generated st_ino number to 16 bits. */- if (default_inode >= 0xffff) {- ++default_dev;- default_inode = 0;- }-- tar = (struct tar *)(a->format->data);- tar->entry_offset = 0;- gnu_clear_sparse_list(tar);- tar->realsize = -1; /* Mark this as "unset" */- tar->realsize_override = 0;-- /* Setup default string conversion. */- tar->sconv = tar->opt_sconv;- if (tar->sconv == NULL) {- if (!tar->init_default_conversion) {- tar->sconv_default =- archive_string_default_conversion_for_read(&(a->archive));- tar->init_default_conversion = 1;- }- tar->sconv = tar->sconv_default;- }-- r = tar_read_header(a, tar, entry, &unconsumed);-- tar_flush_unconsumed(a, &unconsumed);-- /*- * "non-sparse" files are really just sparse files with- * a single block.- */- if (tar->sparse_list == NULL) {- if (gnu_add_sparse_entry(a, tar, 0, tar->entry_bytes_remaining)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- } else {- struct sparse_block *sb;-- for (sb = tar->sparse_list; sb != NULL; sb = sb->next) {- if (!sb->hole)- archive_entry_sparse_add_entry(entry,- sb->offset, sb->remaining);- }- }-- if (r == ARCHIVE_OK && archive_entry_filetype(entry) == AE_IFREG) {- /*- * "Regular" entry with trailing '/' is really- * directory: This is needed for certain old tar- * variants and even for some broken newer ones.- */- if ((wp = archive_entry_pathname_w(entry)) != NULL) {- l = wcslen(wp);- if (l > 0 && wp[l - 1] == L'/') {- archive_entry_set_filetype(entry, AE_IFDIR);- tar->entry_bytes_remaining = 0;- tar->entry_padding = 0;- }- } else if ((p = archive_entry_pathname(entry)) != NULL) {- l = strlen(p);- if (l > 0 && p[l - 1] == '/') {- archive_entry_set_filetype(entry, AE_IFDIR);- tar->entry_bytes_remaining = 0;- tar->entry_padding = 0;- }- }- }- return (r);-}--static int-archive_read_format_tar_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- ssize_t bytes_read;- struct tar *tar;- struct sparse_block *p;-- tar = (struct tar *)(a->format->data);-- for (;;) {- /* Remove exhausted entries from sparse list. */- while (tar->sparse_list != NULL &&- tar->sparse_list->remaining == 0) {- p = tar->sparse_list;- tar->sparse_list = p->next;- free(p);- }-- if (tar->entry_bytes_unconsumed) {- __archive_read_consume(a, tar->entry_bytes_unconsumed);- tar->entry_bytes_unconsumed = 0;- }-- /* If we're at end of file, return EOF. */- if (tar->sparse_list == NULL ||- tar->entry_bytes_remaining == 0) {- if (__archive_read_consume(a, tar->entry_padding) < 0)- return (ARCHIVE_FATAL);- tar->entry_padding = 0;- *buff = NULL;- *size = 0;- *offset = tar->realsize;- return (ARCHIVE_EOF);- }-- *buff = __archive_read_ahead(a, 1, &bytes_read);- if (bytes_read < 0)- return (ARCHIVE_FATAL);- if (*buff == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Truncated tar archive");- return (ARCHIVE_FATAL);- }- if (bytes_read > tar->entry_bytes_remaining)- bytes_read = (ssize_t)tar->entry_bytes_remaining;- /* Don't read more than is available in the- * current sparse block. */- if (tar->sparse_list->remaining < bytes_read)- bytes_read = (ssize_t)tar->sparse_list->remaining;- *size = bytes_read;- *offset = tar->sparse_list->offset;- tar->sparse_list->remaining -= bytes_read;- tar->sparse_list->offset += bytes_read;- tar->entry_bytes_remaining -= bytes_read;- tar->entry_bytes_unconsumed = bytes_read;-- if (!tar->sparse_list->hole)- return (ARCHIVE_OK);- /* Current is hole data and skip this. */- }-}--static int-archive_read_format_tar_skip(struct archive_read *a)-{- int64_t bytes_skipped;- int64_t request;- struct sparse_block *p;- struct tar* tar;-- tar = (struct tar *)(a->format->data);-- /* Do not consume the hole of a sparse file. */- request = 0;- for (p = tar->sparse_list; p != NULL; p = p->next) {- if (!p->hole) {- if (p->remaining >= INT64_MAX - request) {- return ARCHIVE_FATAL;- }- request += p->remaining;- }- }- if (request > tar->entry_bytes_remaining)- request = tar->entry_bytes_remaining;- request += tar->entry_padding + tar->entry_bytes_unconsumed;-- bytes_skipped = __archive_read_consume(a, request);- if (bytes_skipped < 0)- return (ARCHIVE_FATAL);-- tar->entry_bytes_remaining = 0;- tar->entry_bytes_unconsumed = 0;- tar->entry_padding = 0;-- /* Free the sparse list. */- gnu_clear_sparse_list(tar);-- return (ARCHIVE_OK);-}--/*- * This function recursively interprets all of the headers associated- * with a single entry.- */-static int-tar_read_header(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, size_t *unconsumed)-{- ssize_t bytes;- int err, eof_vol_header;- const char *h;- const struct archive_entry_header_ustar *header;- const struct archive_entry_header_gnutar *gnuheader;-- eof_vol_header = 0;-- /* Loop until we find a workable header record. */- for (;;) {- tar_flush_unconsumed(a, unconsumed);-- /* Read 512-byte header record */- h = __archive_read_ahead(a, 512, &bytes);- if (bytes < 0)- return ((int)bytes);- if (bytes == 0) { /* EOF at a block boundary. */- /* Some writers do omit the block of nulls. <sigh> */- return (ARCHIVE_EOF);- }- if (bytes < 512) { /* Short block at EOF; this is bad. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated tar archive");- return (ARCHIVE_FATAL);- }- *unconsumed = 512;-- /* Header is workable if it's not an end-of-archive mark. */- if (h[0] != 0 || !archive_block_is_null(h))- break;-- /* Ensure format is set for archives with only null blocks. */- if (a->archive.archive_format_name == NULL) {- a->archive.archive_format = ARCHIVE_FORMAT_TAR;- a->archive.archive_format_name = "tar";- }-- if (!tar->read_concatenated_archives) {- /* Try to consume a second all-null record, as well. */- tar_flush_unconsumed(a, unconsumed);- h = __archive_read_ahead(a, 512, NULL);- if (h != NULL && h[0] == 0 && archive_block_is_null(h))- __archive_read_consume(a, 512);- archive_clear_error(&a->archive);- return (ARCHIVE_EOF);- }-- /*- * We're reading concatenated archives, ignore this block and- * loop to get the next.- */- }-- /*- * Note: If the checksum fails and we return ARCHIVE_RETRY,- * then the client is likely to just retry. This is a very- * crude way to search for the next valid header!- *- * TODO: Improve this by implementing a real header scan.- */- if (!checksum(a, h)) {- tar_flush_unconsumed(a, unconsumed);- archive_set_error(&a->archive, EINVAL, "Damaged tar archive");- return (ARCHIVE_RETRY); /* Retryable: Invalid header */- }-- if (++tar->header_recursion_depth > 32) {- tar_flush_unconsumed(a, unconsumed);- archive_set_error(&a->archive, EINVAL, "Too many special headers");- return (ARCHIVE_WARN);- }-- /* Determine the format variant. */- header = (const struct archive_entry_header_ustar *)h;-- switch(header->typeflag[0]) {- case 'A': /* Solaris tar ACL */- a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;- a->archive.archive_format_name = "Solaris tar";- err = header_Solaris_ACL(a, tar, entry, h, unconsumed);- break;- case 'g': /* POSIX-standard 'g' header. */- a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;- a->archive.archive_format_name = "POSIX pax interchange format";- err = header_pax_global(a, tar, entry, h, unconsumed);- if (err == ARCHIVE_EOF)- return (err);- break;- case 'K': /* Long link name (GNU tar, others) */- err = header_longlink(a, tar, entry, h, unconsumed);- break;- case 'L': /* Long filename (GNU tar, others) */- err = header_longname(a, tar, entry, h, unconsumed);- break;- case 'V': /* GNU volume header */- err = header_volume(a, tar, entry, h, unconsumed);- if (err == ARCHIVE_EOF)- eof_vol_header = 1;- break;- case 'X': /* Used by SUN tar; same as 'x'. */- a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;- a->archive.archive_format_name =- "POSIX pax interchange format (Sun variant)";- err = header_pax_extensions(a, tar, entry, h, unconsumed);- break;- case 'x': /* POSIX-standard 'x' header. */- a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;- a->archive.archive_format_name = "POSIX pax interchange format";- err = header_pax_extensions(a, tar, entry, h, unconsumed);- break;- default:- gnuheader = (const struct archive_entry_header_gnutar *)h;- if (memcmp(gnuheader->magic, "ustar \0", 8) == 0) {- a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;- a->archive.archive_format_name = "GNU tar format";- err = header_gnutar(a, tar, entry, h, unconsumed);- } else if (memcmp(header->magic, "ustar", 5) == 0) {- if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) {- a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR;- a->archive.archive_format_name = "POSIX ustar format";- }- err = header_ustar(a, tar, entry, h);- } else {- a->archive.archive_format = ARCHIVE_FORMAT_TAR;- a->archive.archive_format_name = "tar (non-POSIX)";- err = header_old_tar(a, tar, entry, h);- }- }- if (err == ARCHIVE_FATAL)- return (err);-- tar_flush_unconsumed(a, unconsumed);-- h = NULL;- header = NULL;-- --tar->header_recursion_depth;- /* Yuck. Apple's design here ends up storing long pathname- * extensions for both the AppleDouble extension entry and the- * regular entry.- */- if ((err == ARCHIVE_WARN || err == ARCHIVE_OK) &&- tar->header_recursion_depth == 0 &&- tar->process_mac_extensions) {- int err2 = read_mac_metadata_blob(a, tar, entry, h, unconsumed);- if (err2 < err)- err = err2;- }-- /* We return warnings or success as-is. Anything else is fatal. */- if (err == ARCHIVE_WARN || err == ARCHIVE_OK) {- if (tar->sparse_gnu_pending) {- if (tar->sparse_gnu_major == 1 &&- tar->sparse_gnu_minor == 0) {- ssize_t bytes_read;-- tar->sparse_gnu_pending = 0;- /* Read initial sparse map. */- bytes_read = gnu_sparse_10_read(a, tar, unconsumed);- if (bytes_read < 0)- return ((int)bytes_read);- tar->entry_bytes_remaining -= bytes_read;- } else {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Unrecognized GNU sparse file format");- return (ARCHIVE_WARN);- }- tar->sparse_gnu_pending = 0;- }- return (err);- }- if (err == ARCHIVE_EOF) {- if (!eof_vol_header) {- /* EOF when recursively reading a header is bad. */- archive_set_error(&a->archive, EINVAL,- "Damaged tar archive");- } else {- /* If we encounter just a GNU volume header treat- * this situation as an empty archive */- return (ARCHIVE_EOF);- }- }- return (ARCHIVE_FATAL);-}--/*- * Return true if block checksum is correct.- */-static int-checksum(struct archive_read *a, const void *h)-{- const unsigned char *bytes;- const struct archive_entry_header_ustar *header;- int check, sum;- size_t i;-- (void)a; /* UNUSED */- bytes = (const unsigned char *)h;- header = (const struct archive_entry_header_ustar *)h;-- /* Checksum field must hold an octal number */- for (i = 0; i < sizeof(header->checksum); ++i) {- char c = header->checksum[i];- if (c != ' ' && c != '\0' && (c < '0' || c > '7'))- return 0;- }-- /*- * Test the checksum. Note that POSIX specifies _unsigned_- * bytes for this calculation.- */- sum = (int)tar_atol(header->checksum, sizeof(header->checksum));- check = 0;- for (i = 0; i < 148; i++)- check += (unsigned char)bytes[i];- for (; i < 156; i++)- check += 32;- for (; i < 512; i++)- check += (unsigned char)bytes[i];- if (sum == check)- return (1);-- /*- * Repeat test with _signed_ bytes, just in case this archive- * was created by an old BSD, Solaris, or HP-UX tar with a- * broken checksum calculation.- */- check = 0;- for (i = 0; i < 148; i++)- check += (signed char)bytes[i];- for (; i < 156; i++)- check += 32;- for (; i < 512; i++)- check += (signed char)bytes[i];- if (sum == check)- return (1);-- return (0);-}--/*- * Return true if this block contains only nulls.- */-static int-archive_block_is_null(const char *p)-{- unsigned i;-- for (i = 0; i < 512; i++)- if (*p++)- return (0);- return (1);-}--/*- * Interpret 'A' Solaris ACL header- */-static int-header_Solaris_ACL(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h, size_t *unconsumed)-{- const struct archive_entry_header_ustar *header;- size_t size;- int err, acl_type;- int64_t type;- char *acl, *p;-- /*- * read_body_to_string adds a NUL terminator, but we need a little- * more to make sure that we don't overrun acl_text later.- */- header = (const struct archive_entry_header_ustar *)h;- size = (size_t)tar_atol(header->size, sizeof(header->size));- err = read_body_to_string(a, tar, &(tar->acl_text), h, unconsumed);- if (err != ARCHIVE_OK)- return (err);-- /* Recursively read next header */- err = tar_read_header(a, tar, entry, unconsumed);- if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))- return (err);-- /* TODO: Examine the first characters to see if this- * is an AIX ACL descriptor. We'll likely never support- * them, but it would be polite to recognize and warn when- * we do see them. */-- /* Leading octal number indicates ACL type and number of entries. */- p = acl = tar->acl_text.s;- type = 0;- while (*p != '\0' && p < acl + size) {- if (*p < '0' || *p > '7') {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Malformed Solaris ACL attribute (invalid digit)");- return(ARCHIVE_WARN);- }- type <<= 3;- type += *p - '0';- if (type > 077777777) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Malformed Solaris ACL attribute (count too large)");- return (ARCHIVE_WARN);- }- p++;- }- switch ((int)type & ~0777777) {- case 01000000:- /* POSIX.1e ACL */- acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;- break;- case 03000000:- /* NFSv4 ACL */- acl_type = ARCHIVE_ENTRY_ACL_TYPE_NFS4;- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Malformed Solaris ACL attribute (unsupported type %o)",- (int)type);- return (ARCHIVE_WARN);- }- p++;-- if (p >= acl + size) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Malformed Solaris ACL attribute (body overflow)");- return(ARCHIVE_WARN);- }-- /* ACL text is null-terminated; find the end. */- size -= (p - acl);- acl = p;-- while (*p != '\0' && p < acl + size)- p++;-- if (tar->sconv_acl == NULL) {- tar->sconv_acl = archive_string_conversion_from_charset(- &(a->archive), "UTF-8", 1);- if (tar->sconv_acl == NULL)- return (ARCHIVE_FATAL);- }- archive_strncpy(&(tar->localname), acl, p - acl);- err = archive_acl_from_text_l(archive_entry_acl(entry),- tar->localname.s, acl_type, tar->sconv_acl);- if (err != ARCHIVE_OK) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for ACL");- } else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Malformed Solaris ACL attribute (unparsable)");- }- return (err);-}--/*- * Interpret 'K' long linkname header.- */-static int-header_longlink(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h, size_t *unconsumed)-{- int err;-- err = read_body_to_string(a, tar, &(tar->longlink), h, unconsumed);- if (err != ARCHIVE_OK)- return (err);- err = tar_read_header(a, tar, entry, unconsumed);- if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))- return (err);- /* Set symlink if symlink already set, else hardlink. */- archive_entry_copy_link(entry, tar->longlink.s);- return (ARCHIVE_OK);-}--static int-set_conversion_failed_error(struct archive_read *a,- struct archive_string_conv *sconv, const char *name)-{- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for %s", name);- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "%s can't be converted from %s to current locale.",- name, archive_string_conversion_charset_name(sconv));- return (ARCHIVE_WARN);-}--/*- * Interpret 'L' long filename header.- */-static int-header_longname(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h, size_t *unconsumed)-{- int err;-- err = read_body_to_string(a, tar, &(tar->longname), h, unconsumed);- if (err != ARCHIVE_OK)- return (err);- /* Read and parse "real" header, then override name. */- err = tar_read_header(a, tar, entry, unconsumed);- if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))- return (err);- if (archive_entry_copy_pathname_l(entry, tar->longname.s,- archive_strlen(&(tar->longname)), tar->sconv) != 0)- err = set_conversion_failed_error(a, tar->sconv, "Pathname");- return (err);-}---/*- * Interpret 'V' GNU tar volume header.- */-static int-header_volume(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h, size_t *unconsumed)-{- (void)h;-- /* Just skip this and read the next header. */- return (tar_read_header(a, tar, entry, unconsumed));-}--/*- * Read body of an archive entry into an archive_string object.- */-static int-read_body_to_string(struct archive_read *a, struct tar *tar,- struct archive_string *as, const void *h, size_t *unconsumed)-{- int64_t size;- const struct archive_entry_header_ustar *header;- const void *src;-- (void)tar; /* UNUSED */- header = (const struct archive_entry_header_ustar *)h;- size = tar_atol(header->size, sizeof(header->size));- if ((size > 1048576) || (size < 0)) {- archive_set_error(&a->archive, EINVAL,- "Special header too large");- return (ARCHIVE_FATAL);- }-- /* Fail if we can't make our buffer big enough. */- if (archive_string_ensure(as, (size_t)size+1) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory");- return (ARCHIVE_FATAL);- }-- tar_flush_unconsumed(a, unconsumed);-- /* Read the body into the string. */- *unconsumed = (size_t)((size + 511) & ~ 511);- src = __archive_read_ahead(a, *unconsumed, NULL);- if (src == NULL) {- *unconsumed = 0;- return (ARCHIVE_FATAL);- }- memcpy(as->s, src, (size_t)size);- as->s[size] = '\0';- as->length = (size_t)size;- return (ARCHIVE_OK);-}--/*- * Parse out common header elements.- *- * This would be the same as header_old_tar, except that the- * filename is handled slightly differently for old and POSIX- * entries (POSIX entries support a 'prefix'). This factoring- * allows header_old_tar and header_ustar- * to handle filenames differently, while still putting most of the- * common parsing into one place.- */-static int-header_common(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h)-{- const struct archive_entry_header_ustar *header;- char tartype;- int err = ARCHIVE_OK;-- header = (const struct archive_entry_header_ustar *)h;- if (header->linkname[0])- archive_strncpy(&(tar->entry_linkpath),- header->linkname, sizeof(header->linkname));- else- archive_string_empty(&(tar->entry_linkpath));-- /* Parse out the numeric fields (all are octal) */- archive_entry_set_mode(entry,- (mode_t)tar_atol(header->mode, sizeof(header->mode)));- archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid)));- archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));- tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size));- if (tar->entry_bytes_remaining < 0) {- tar->entry_bytes_remaining = 0;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Tar entry has negative size");- return (ARCHIVE_FATAL);- }- if (tar->entry_bytes_remaining == INT64_MAX) {- /* Note: tar_atol returns INT64_MAX on overflow */- tar->entry_bytes_remaining = 0;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Tar entry size overflow");- return (ARCHIVE_FATAL);- }- tar->realsize = tar->entry_bytes_remaining;- archive_entry_set_size(entry, tar->entry_bytes_remaining);- archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);-- /* Handle the tar type flag appropriately. */- tartype = header->typeflag[0];-- switch (tartype) {- case '1': /* Hard link */- if (archive_entry_copy_hardlink_l(entry, tar->entry_linkpath.s,- archive_strlen(&(tar->entry_linkpath)), tar->sconv) != 0) {- err = set_conversion_failed_error(a, tar->sconv,- "Linkname");- if (err == ARCHIVE_FATAL)- return (err);- }- /*- * The following may seem odd, but: Technically, tar- * does not store the file type for a "hard link"- * entry, only the fact that it is a hard link. So, I- * leave the type zero normally. But, pax interchange- * format allows hard links to have data, which- * implies that the underlying entry is a regular- * file.- */- if (archive_entry_size(entry) > 0)- archive_entry_set_filetype(entry, AE_IFREG);-- /*- * A tricky point: Traditionally, tar readers have- * ignored the size field when reading hardlink- * entries, and some writers put non-zero sizes even- * though the body is empty. POSIX blessed this- * convention in the 1988 standard, but broke with- * this tradition in 2001 by permitting hardlink- * entries to store valid bodies in pax interchange- * format, but not in ustar format. Since there is no- * hard and fast way to distinguish pax interchange- * from earlier archives (the 'x' and 'g' entries are- * optional, after all), we need a heuristic.- */- if (archive_entry_size(entry) == 0) {- /* If the size is already zero, we're done. */- } else if (a->archive.archive_format- == ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) {- /* Definitely pax extended; must obey hardlink size. */- } else if (a->archive.archive_format == ARCHIVE_FORMAT_TAR- || a->archive.archive_format == ARCHIVE_FORMAT_TAR_GNUTAR)- {- /* Old-style or GNU tar: we must ignore the size. */- archive_entry_set_size(entry, 0);- tar->entry_bytes_remaining = 0;- } else if (archive_read_format_tar_bid(a, 50) > 50) {- /*- * We don't know if it's pax: If the bid- * function sees a valid ustar header- * immediately following, then let's ignore- * the hardlink size.- */- archive_entry_set_size(entry, 0);- tar->entry_bytes_remaining = 0;- }- /*- * TODO: There are still two cases I'd like to handle:- * = a ustar non-pax archive with a hardlink entry at- * end-of-archive. (Look for block of nulls following?)- * = a pax archive that has not seen any pax headers- * and has an entry which is a hardlink entry storing- * a body containing an uncompressed tar archive.- * The first is worth addressing; I don't see any reliable- * way to deal with the second possibility.- */- break;- case '2': /* Symlink */- archive_entry_set_filetype(entry, AE_IFLNK);- archive_entry_set_size(entry, 0);- tar->entry_bytes_remaining = 0;- if (archive_entry_copy_symlink_l(entry, tar->entry_linkpath.s,- archive_strlen(&(tar->entry_linkpath)), tar->sconv) != 0) {- err = set_conversion_failed_error(a, tar->sconv,- "Linkname");- if (err == ARCHIVE_FATAL)- return (err);- }- break;- case '3': /* Character device */- archive_entry_set_filetype(entry, AE_IFCHR);- archive_entry_set_size(entry, 0);- tar->entry_bytes_remaining = 0;- break;- case '4': /* Block device */- archive_entry_set_filetype(entry, AE_IFBLK);- archive_entry_set_size(entry, 0);- tar->entry_bytes_remaining = 0;- break;- case '5': /* Dir */- archive_entry_set_filetype(entry, AE_IFDIR);- archive_entry_set_size(entry, 0);- tar->entry_bytes_remaining = 0;- break;- case '6': /* FIFO device */- archive_entry_set_filetype(entry, AE_IFIFO);- archive_entry_set_size(entry, 0);- tar->entry_bytes_remaining = 0;- break;- case 'D': /* GNU incremental directory type */- /*- * No special handling is actually required here.- * It might be nice someday to preprocess the file list and- * provide it to the client, though.- */- archive_entry_set_filetype(entry, AE_IFDIR);- break;- case 'M': /* GNU "Multi-volume" (remainder of file from last archive)*/- /*- * As far as I can tell, this is just like a regular file- * entry, except that the contents should be _appended_ to- * the indicated file at the indicated offset. This may- * require some API work to fully support.- */- break;- case 'N': /* Old GNU "long filename" entry. */- /* The body of this entry is a script for renaming- * previously-extracted entries. Ugh. It will never- * be supported by libarchive. */- archive_entry_set_filetype(entry, AE_IFREG);- break;- case 'S': /* GNU sparse files */- /*- * Sparse files are really just regular files with- * sparse information in the extended area.- */- /* FALLTHROUGH */- case '0':- /*- * Enable sparse file "read" support only for regular- * files and explicit GNU sparse files. However, we- * don't allow non-standard file types to be sparse.- */- tar->sparse_allowed = 1;- /* FALLTHROUGH */- default: /* Regular file and non-standard types */- /*- * Per POSIX: non-recognized types should always be- * treated as regular files.- */- archive_entry_set_filetype(entry, AE_IFREG);- break;- }- return (err);-}--/*- * Parse out header elements for "old-style" tar archives.- */-static int-header_old_tar(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h)-{- const struct archive_entry_header_ustar *header;- int err = ARCHIVE_OK, err2;-- /* Copy filename over (to ensure null termination). */- header = (const struct archive_entry_header_ustar *)h;- if (archive_entry_copy_pathname_l(entry,- header->name, sizeof(header->name), tar->sconv) != 0) {- err = set_conversion_failed_error(a, tar->sconv, "Pathname");- if (err == ARCHIVE_FATAL)- return (err);- }-- /* Grab rest of common fields */- err2 = header_common(a, tar, entry, h);- if (err > err2)- err = err2;-- tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);- return (err);-}--/*- * Read a Mac AppleDouble-encoded blob of file metadata,- * if there is one.- */-static int-read_mac_metadata_blob(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h, size_t *unconsumed)-{- int64_t size;- size_t msize;- const void *data;- const char *p, *name;- const wchar_t *wp, *wname;-- (void)h; /* UNUSED */-- wname = wp = archive_entry_pathname_w(entry);- if (wp != NULL) {- /* Find the last path element. */- for (; *wp != L'\0'; ++wp) {- if (wp[0] == '/' && wp[1] != L'\0')- wname = wp + 1;- }- /*- * If last path element starts with "._", then- * this is a Mac extension.- */- if (wname[0] != L'.' || wname[1] != L'_' || wname[2] == L'\0')- return ARCHIVE_OK;- } else {- /* Find the last path element. */- name = p = archive_entry_pathname(entry);- if (p == NULL)- return (ARCHIVE_FAILED);- for (; *p != '\0'; ++p) {- if (p[0] == '/' && p[1] != '\0')- name = p + 1;- }- /*- * If last path element starts with "._", then- * this is a Mac extension.- */- if (name[0] != '.' || name[1] != '_' || name[2] == '\0')- return ARCHIVE_OK;- }-- /* Read the body as a Mac OS metadata blob. */- size = archive_entry_size(entry);- msize = (size_t)size;- if (size < 0 || (uintmax_t)msize != (uintmax_t)size) {- *unconsumed = 0;- return (ARCHIVE_FATAL);- }-- /*- * TODO: Look beyond the body here to peek at the next header.- * If it's a regular header (not an extension header)- * that has the wrong name, just return the current- * entry as-is, without consuming the body here.- * That would reduce the risk of us mis-identifying- * an ordinary file that just happened to have- * a name starting with "._".- *- * Q: Is the above idea really possible? Even- * when there are GNU or pax extension entries?- */- data = __archive_read_ahead(a, msize, NULL);- if (data == NULL) {- *unconsumed = 0;- return (ARCHIVE_FATAL);- }- archive_entry_copy_mac_metadata(entry, data, msize);- *unconsumed = (msize + 511) & ~ 511;- tar_flush_unconsumed(a, unconsumed);- return (tar_read_header(a, tar, entry, unconsumed));-}--/*- * Parse a file header for a pax extended archive entry.- */-static int-header_pax_global(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h, size_t *unconsumed)-{- int err;-- err = read_body_to_string(a, tar, &(tar->pax_global), h, unconsumed);- if (err != ARCHIVE_OK)- return (err);- err = tar_read_header(a, tar, entry, unconsumed);- return (err);-}--static int-header_pax_extensions(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h, size_t *unconsumed)-{- int err, err2;-- err = read_body_to_string(a, tar, &(tar->pax_header), h, unconsumed);- if (err != ARCHIVE_OK)- return (err);-- /* Parse the next header. */- err = tar_read_header(a, tar, entry, unconsumed);- if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))- return (err);-- /*- * TODO: Parse global/default options into 'entry' struct here- * before handling file-specific options.- *- * This design (parse standard header, then overwrite with pax- * extended attribute data) usually works well, but isn't ideal;- * it would be better to parse the pax extended attributes first- * and then skip any fields in the standard header that were- * defined in the pax header.- */- err2 = pax_header(a, tar, entry, &tar->pax_header);- err = err_combine(err, err2);- tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);- return (err);-}---/*- * Parse a file header for a Posix "ustar" archive entry. This also- * handles "pax" or "extended ustar" entries.- */-static int-header_ustar(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h)-{- const struct archive_entry_header_ustar *header;- struct archive_string *as;- int err = ARCHIVE_OK, r;-- header = (const struct archive_entry_header_ustar *)h;-- /* Copy name into an internal buffer to ensure null-termination. */- as = &(tar->entry_pathname);- if (header->prefix[0]) {- archive_strncpy(as, header->prefix, sizeof(header->prefix));- if (as->s[archive_strlen(as) - 1] != '/')- archive_strappend_char(as, '/');- archive_strncat(as, header->name, sizeof(header->name));- } else {- archive_strncpy(as, header->name, sizeof(header->name));- }- if (archive_entry_copy_pathname_l(entry, as->s, archive_strlen(as),- tar->sconv) != 0) {- err = set_conversion_failed_error(a, tar->sconv, "Pathname");- if (err == ARCHIVE_FATAL)- return (err);- }-- /* Handle rest of common fields. */- r = header_common(a, tar, entry, h);- if (r == ARCHIVE_FATAL)- return (r);- if (r < err)- err = r;-- /* Handle POSIX ustar fields. */- if (archive_entry_copy_uname_l(entry,- header->uname, sizeof(header->uname), tar->sconv) != 0) {- err = set_conversion_failed_error(a, tar->sconv, "Uname");- if (err == ARCHIVE_FATAL)- return (err);- }-- if (archive_entry_copy_gname_l(entry,- header->gname, sizeof(header->gname), tar->sconv) != 0) {- err = set_conversion_failed_error(a, tar->sconv, "Gname");- if (err == ARCHIVE_FATAL)- return (err);- }-- /* Parse out device numbers only for char and block specials. */- if (header->typeflag[0] == '3' || header->typeflag[0] == '4') {- archive_entry_set_rdevmajor(entry, (dev_t)- tar_atol(header->rdevmajor, sizeof(header->rdevmajor)));- archive_entry_set_rdevminor(entry, (dev_t)- tar_atol(header->rdevminor, sizeof(header->rdevminor)));- }-- tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);-- return (err);-}---/*- * Parse the pax extended attributes record.- *- * Returns non-zero if there's an error in the data.- */-static int-pax_header(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, struct archive_string *in_as)-{- size_t attr_length, l, line_length, value_length;- char *p;- char *key, *value;- struct archive_string *as;- struct archive_string_conv *sconv;- int err, err2;- char *attr = in_as->s;-- attr_length = in_as->length;- tar->pax_hdrcharset_binary = 0;- archive_string_empty(&(tar->entry_gname));- archive_string_empty(&(tar->entry_linkpath));- archive_string_empty(&(tar->entry_pathname));- archive_string_empty(&(tar->entry_pathname_override));- archive_string_empty(&(tar->entry_uname));- err = ARCHIVE_OK;- while (attr_length > 0) {- /* Parse decimal length field at start of line. */- line_length = 0;- l = attr_length;- p = attr; /* Record start of line. */- while (l>0) {- if (*p == ' ') {- p++;- l--;- break;- }- if (*p < '0' || *p > '9') {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Ignoring malformed pax extended attributes");- return (ARCHIVE_WARN);- }- line_length *= 10;- line_length += *p - '0';- if (line_length > 999999) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Rejecting pax extended attribute > 1MB");- return (ARCHIVE_WARN);- }- p++;- l--;- }-- /*- * Parsed length must be no bigger than available data,- * at least 1, and the last character of the line must- * be '\n'.- */- if (line_length > attr_length- || line_length < 1- || attr[line_length - 1] != '\n')- {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Ignoring malformed pax extended attribute");- return (ARCHIVE_WARN);- }-- /* Null-terminate the line. */- attr[line_length - 1] = '\0';-- /* Find end of key and null terminate it. */- key = p;- if (key[0] == '=')- return (-1);- while (*p && *p != '=')- ++p;- if (*p == '\0') {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid pax extended attributes");- return (ARCHIVE_WARN);- }- *p = '\0';-- value = p + 1;-- /* Some values may be binary data */- value_length = attr + line_length - 1 - value;-- /* Identify this attribute and set it in the entry. */- err2 = pax_attribute(a, tar, entry, key, value, value_length);- if (err2 == ARCHIVE_FATAL)- return (err2);- err = err_combine(err, err2);-- /* Skip to next line */- attr += line_length;- attr_length -= line_length;- }-- /*- * PAX format uses UTF-8 as default charset for its metadata- * unless hdrcharset=BINARY is present in its header.- * We apply the charset specified by the hdrcharset option only- * when the hdrcharset attribute(in PAX header) is BINARY because- * we respect the charset described in PAX header and BINARY also- * means that metadata(filename,uname and gname) character-set- * is unknown.- */- if (tar->pax_hdrcharset_binary)- sconv = tar->opt_sconv;- else {- sconv = archive_string_conversion_from_charset(- &(a->archive), "UTF-8", 1);- if (sconv == NULL)- return (ARCHIVE_FATAL);- if (tar->compat_2x)- archive_string_conversion_set_opt(sconv,- SCONV_SET_OPT_UTF8_LIBARCHIVE2X);- }-- if (archive_strlen(&(tar->entry_gname)) > 0) {- if (archive_entry_copy_gname_l(entry, tar->entry_gname.s,- archive_strlen(&(tar->entry_gname)), sconv) != 0) {- err = set_conversion_failed_error(a, sconv, "Gname");- if (err == ARCHIVE_FATAL)- return (err);- /* Use a converted an original name. */- archive_entry_copy_gname(entry, tar->entry_gname.s);- }- }- if (archive_strlen(&(tar->entry_linkpath)) > 0) {- if (archive_entry_copy_link_l(entry, tar->entry_linkpath.s,- archive_strlen(&(tar->entry_linkpath)), sconv) != 0) {- err = set_conversion_failed_error(a, sconv, "Linkname");- if (err == ARCHIVE_FATAL)- return (err);- /* Use a converted an original name. */- archive_entry_copy_link(entry, tar->entry_linkpath.s);- }- }- /*- * Some extensions (such as the GNU sparse file extensions)- * deliberately store a synthetic name under the regular 'path'- * attribute and the real file name under a different attribute.- * Since we're supposed to not care about the order, we- * have no choice but to store all of the various filenames- * we find and figure it all out afterwards. This is the- * figuring out part.- */- as = NULL;- if (archive_strlen(&(tar->entry_pathname_override)) > 0)- as = &(tar->entry_pathname_override);- else if (archive_strlen(&(tar->entry_pathname)) > 0)- as = &(tar->entry_pathname);- if (as != NULL) {- if (archive_entry_copy_pathname_l(entry, as->s,- archive_strlen(as), sconv) != 0) {- err = set_conversion_failed_error(a, sconv, "Pathname");- if (err == ARCHIVE_FATAL)- return (err);- /* Use a converted an original name. */- archive_entry_copy_pathname(entry, as->s);- }- }- if (archive_strlen(&(tar->entry_uname)) > 0) {- if (archive_entry_copy_uname_l(entry, tar->entry_uname.s,- archive_strlen(&(tar->entry_uname)), sconv) != 0) {- err = set_conversion_failed_error(a, sconv, "Uname");- if (err == ARCHIVE_FATAL)- return (err);- /* Use a converted an original name. */- archive_entry_copy_uname(entry, tar->entry_uname.s);- }- }- return (err);-}--static int-pax_attribute_xattr(struct archive_entry *entry,- const char *name, const char *value)-{- char *name_decoded;- void *value_decoded;- size_t value_len;-- if (strlen(name) < 18 || (memcmp(name, "LIBARCHIVE.xattr.", 17)) != 0)- return 3;-- name += 17;-- /* URL-decode name */- name_decoded = url_decode(name);- if (name_decoded == NULL)- return 2;-- /* Base-64 decode value */- value_decoded = base64_decode(value, strlen(value), &value_len);- if (value_decoded == NULL) {- free(name_decoded);- return 1;- }-- archive_entry_xattr_add_entry(entry, name_decoded,- value_decoded, value_len);-- free(name_decoded);- free(value_decoded);- return 0;-}--static int-pax_attribute_schily_xattr(struct archive_entry *entry,- const char *name, const char *value, size_t value_length)-{- if (strlen(name) < 14 || (memcmp(name, "SCHILY.xattr.", 13)) != 0)- return 1;-- name += 13;-- archive_entry_xattr_add_entry(entry, name, value, value_length);-- return 0;-}--static int-pax_attribute_rht_security_selinux(struct archive_entry *entry,- const char *value, size_t value_length)-{- archive_entry_xattr_add_entry(entry, "security.selinux",- value, value_length);-- return 0;-}--static int-pax_attribute_acl(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const char *value, int type)-{- int r;- const char* errstr;-- switch (type) {- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:- errstr = "SCHILY.acl.access";- break;- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:- errstr = "SCHILY.acl.default";- break;- case ARCHIVE_ENTRY_ACL_TYPE_NFS4:- errstr = "SCHILY.acl.ace";- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Unknown ACL type: %d", type);- return(ARCHIVE_FATAL);- }-- if (tar->sconv_acl == NULL) {- tar->sconv_acl =- archive_string_conversion_from_charset(- &(a->archive), "UTF-8", 1);- if (tar->sconv_acl == NULL)- return (ARCHIVE_FATAL);- }-- r = archive_acl_from_text_l(archive_entry_acl(entry), value, type,- tar->sconv_acl);- if (r != ARCHIVE_OK) {- if (r == ARCHIVE_FATAL) {- archive_set_error(&a->archive, ENOMEM,- "%s %s", "Can't allocate memory for ",- errstr);- return (r);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC, "%s %s", "Parse error: ", errstr);- }- return (r);-}--/*- * Parse a single key=value attribute. key/value pointers are- * assumed to point into reasonably long-lived storage.- *- * Note that POSIX reserves all-lowercase keywords. Vendor-specific- * extensions should always have keywords of the form "VENDOR.attribute"- * In particular, it's quite feasible to support many different- * vendor extensions here. I'm using "LIBARCHIVE" for extensions- * unique to this library.- *- * Investigate other vendor-specific extensions and see if- * any of them look useful.- */-static int-pax_attribute(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const char *key, const char *value, size_t value_length)-{- int64_t s;- long n;- int err = ARCHIVE_OK, r;-- if (value == NULL)- value = ""; /* Disable compiler warning; do not pass- * NULL pointer to strlen(). */- switch (key[0]) {- case 'G':- /* Reject GNU.sparse.* headers on non-regular files. */- if (strncmp(key, "GNU.sparse", 10) == 0 &&- !tar->sparse_allowed) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Non-regular file cannot be sparse");- return (ARCHIVE_FATAL);- }-- /* GNU "0.0" sparse pax format. */- if (strcmp(key, "GNU.sparse.numblocks") == 0) {- tar->sparse_offset = -1;- tar->sparse_numbytes = -1;- tar->sparse_gnu_major = 0;- tar->sparse_gnu_minor = 0;- }- if (strcmp(key, "GNU.sparse.offset") == 0) {- tar->sparse_offset = tar_atol10(value, strlen(value));- if (tar->sparse_numbytes != -1) {- if (gnu_add_sparse_entry(a, tar,- tar->sparse_offset, tar->sparse_numbytes)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- tar->sparse_offset = -1;- tar->sparse_numbytes = -1;- }- }- if (strcmp(key, "GNU.sparse.numbytes") == 0) {- tar->sparse_numbytes = tar_atol10(value, strlen(value));- if (tar->sparse_offset != -1) {- if (gnu_add_sparse_entry(a, tar,- tar->sparse_offset, tar->sparse_numbytes)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- tar->sparse_offset = -1;- tar->sparse_numbytes = -1;- }- }- if (strcmp(key, "GNU.sparse.size") == 0) {- tar->realsize = tar_atol10(value, strlen(value));- archive_entry_set_size(entry, tar->realsize);- tar->realsize_override = 1;- }-- /* GNU "0.1" sparse pax format. */- if (strcmp(key, "GNU.sparse.map") == 0) {- tar->sparse_gnu_major = 0;- tar->sparse_gnu_minor = 1;- if (gnu_sparse_01_parse(a, tar, value) != ARCHIVE_OK)- return (ARCHIVE_WARN);- }-- /* GNU "1.0" sparse pax format */- if (strcmp(key, "GNU.sparse.major") == 0) {- tar->sparse_gnu_major = (int)tar_atol10(value, strlen(value));- tar->sparse_gnu_pending = 1;- }- if (strcmp(key, "GNU.sparse.minor") == 0) {- tar->sparse_gnu_minor = (int)tar_atol10(value, strlen(value));- tar->sparse_gnu_pending = 1;- }- if (strcmp(key, "GNU.sparse.name") == 0) {- /*- * The real filename; when storing sparse- * files, GNU tar puts a synthesized name into- * the regular 'path' attribute in an attempt- * to limit confusion. ;-)- */- archive_strcpy(&(tar->entry_pathname_override), value);- }- if (strcmp(key, "GNU.sparse.realsize") == 0) {- tar->realsize = tar_atol10(value, strlen(value));- archive_entry_set_size(entry, tar->realsize);- tar->realsize_override = 1;- }- break;- case 'L':- /* Our extensions */-/* TODO: Handle arbitrary extended attributes... */-/*- if (strcmp(key, "LIBARCHIVE.xxxxxxx") == 0)- archive_entry_set_xxxxxx(entry, value);-*/- if (strcmp(key, "LIBARCHIVE.creationtime") == 0) {- pax_time(value, &s, &n);- archive_entry_set_birthtime(entry, s, n);- }- if (strcmp(key, "LIBARCHIVE.symlinktype") == 0) {- if (strcmp(value, "file") == 0) {- archive_entry_set_symlink_type(entry,- AE_SYMLINK_TYPE_FILE);- } else if (strcmp(value, "dir") == 0) {- archive_entry_set_symlink_type(entry,- AE_SYMLINK_TYPE_DIRECTORY);- }- }- if (memcmp(key, "LIBARCHIVE.xattr.", 17) == 0)- pax_attribute_xattr(entry, key, value);- break;- case 'R':- /* GNU tar uses RHT.security header to store SELinux xattrs- * SCHILY.xattr.security.selinux == RHT.security.selinux */- if (strcmp(key, "RHT.security.selinux") == 0) {- pax_attribute_rht_security_selinux(entry, value,- value_length);- }- break;- case 'S':- /* We support some keys used by the "star" archiver */- if (strcmp(key, "SCHILY.acl.access") == 0) {- r = pax_attribute_acl(a, tar, entry, value,- ARCHIVE_ENTRY_ACL_TYPE_ACCESS);- if (r == ARCHIVE_FATAL)- return (r);- } else if (strcmp(key, "SCHILY.acl.default") == 0) {- r = pax_attribute_acl(a, tar, entry, value,- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);- if (r == ARCHIVE_FATAL)- return (r);- } else if (strcmp(key, "SCHILY.acl.ace") == 0) {- r = pax_attribute_acl(a, tar, entry, value,- ARCHIVE_ENTRY_ACL_TYPE_NFS4);- if (r == ARCHIVE_FATAL)- return (r);- } else if (strcmp(key, "SCHILY.devmajor") == 0) {- archive_entry_set_rdevmajor(entry,- (dev_t)tar_atol10(value, strlen(value)));- } else if (strcmp(key, "SCHILY.devminor") == 0) {- archive_entry_set_rdevminor(entry,- (dev_t)tar_atol10(value, strlen(value)));- } else if (strcmp(key, "SCHILY.fflags") == 0) {- archive_entry_copy_fflags_text(entry, value);- } else if (strcmp(key, "SCHILY.dev") == 0) {- archive_entry_set_dev(entry,- (dev_t)tar_atol10(value, strlen(value)));- } else if (strcmp(key, "SCHILY.ino") == 0) {- archive_entry_set_ino(entry,- tar_atol10(value, strlen(value)));- } else if (strcmp(key, "SCHILY.nlink") == 0) {- archive_entry_set_nlink(entry, (unsigned)- tar_atol10(value, strlen(value)));- } else if (strcmp(key, "SCHILY.realsize") == 0) {- tar->realsize = tar_atol10(value, strlen(value));- tar->realsize_override = 1;- archive_entry_set_size(entry, tar->realsize);- } else if (strncmp(key, "SCHILY.xattr.", 13) == 0) {- pax_attribute_schily_xattr(entry, key, value,- value_length);- } else if (strcmp(key, "SUN.holesdata") == 0) {- /* A Solaris extension for sparse. */- r = solaris_sparse_parse(a, tar, entry, value);- if (r < err) {- if (r == ARCHIVE_FATAL)- return (r);- err = r;- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Parse error: SUN.holesdata");- }- }- break;- case 'a':- if (strcmp(key, "atime") == 0) {- pax_time(value, &s, &n);- archive_entry_set_atime(entry, s, n);- }- break;- case 'c':- if (strcmp(key, "ctime") == 0) {- pax_time(value, &s, &n);- archive_entry_set_ctime(entry, s, n);- } else if (strcmp(key, "charset") == 0) {- /* TODO: Publish charset information in entry. */- } else if (strcmp(key, "comment") == 0) {- /* TODO: Publish comment in entry. */- }- break;- case 'g':- if (strcmp(key, "gid") == 0) {- archive_entry_set_gid(entry,- tar_atol10(value, strlen(value)));- } else if (strcmp(key, "gname") == 0) {- archive_strcpy(&(tar->entry_gname), value);- }- break;- case 'h':- if (strcmp(key, "hdrcharset") == 0) {- if (strcmp(value, "BINARY") == 0)- /* Binary mode. */- tar->pax_hdrcharset_binary = 1;- else if (strcmp(value, "ISO-IR 10646 2000 UTF-8") == 0)- tar->pax_hdrcharset_binary = 0;- }- break;- case 'l':- /* pax interchange doesn't distinguish hardlink vs. symlink. */- if (strcmp(key, "linkpath") == 0) {- archive_strcpy(&(tar->entry_linkpath), value);- }- break;- case 'm':- if (strcmp(key, "mtime") == 0) {- pax_time(value, &s, &n);- archive_entry_set_mtime(entry, s, n);- }- break;- case 'p':- if (strcmp(key, "path") == 0) {- archive_strcpy(&(tar->entry_pathname), value);- }- break;- case 'r':- /* POSIX has reserved 'realtime.*' */- break;- case 's':- /* POSIX has reserved 'security.*' */- /* Someday: if (strcmp(key, "security.acl") == 0) { ... } */- if (strcmp(key, "size") == 0) {- /* "size" is the size of the data in the entry. */- tar->entry_bytes_remaining- = tar_atol10(value, strlen(value));- if (tar->entry_bytes_remaining < 0) {- tar->entry_bytes_remaining = 0;- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Tar size attribute is negative");- return (ARCHIVE_FATAL);- }- if (tar->entry_bytes_remaining == INT64_MAX) {- /* Note: tar_atol returns INT64_MAX on overflow */- tar->entry_bytes_remaining = 0;- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Tar size attribute overflow");- return (ARCHIVE_FATAL);- }- /*- * The "size" pax header keyword always overrides the- * "size" field in the tar header.- * GNU.sparse.realsize, GNU.sparse.size and- * SCHILY.realsize override this value.- */- if (!tar->realsize_override) {- archive_entry_set_size(entry,- tar->entry_bytes_remaining);- tar->realsize- = tar->entry_bytes_remaining;- }- }- break;- case 'u':- if (strcmp(key, "uid") == 0) {- archive_entry_set_uid(entry,- tar_atol10(value, strlen(value)));- } else if (strcmp(key, "uname") == 0) {- archive_strcpy(&(tar->entry_uname), value);- }- break;- }- return (err);-}----/*- * parse a decimal time value, which may include a fractional portion- */-static void-pax_time(const char *p, int64_t *ps, long *pn)-{- char digit;- int64_t s;- unsigned long l;- int sign;- int64_t limit, last_digit_limit;-- limit = INT64_MAX / 10;- last_digit_limit = INT64_MAX % 10;-- s = 0;- sign = 1;- if (*p == '-') {- sign = -1;- p++;- }- while (*p >= '0' && *p <= '9') {- digit = *p - '0';- if (s > limit ||- (s == limit && digit > last_digit_limit)) {- s = INT64_MAX;- break;- }- s = (s * 10) + digit;- ++p;- }-- *ps = s * sign;-- /* Calculate nanoseconds. */- *pn = 0;-- if (*p != '.')- return;-- l = 100000000UL;- do {- ++p;- if (*p >= '0' && *p <= '9')- *pn += (*p - '0') * l;- else- break;- } while (l /= 10);-}--/*- * Parse GNU tar header- */-static int-header_gnutar(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const void *h, size_t *unconsumed)-{- const struct archive_entry_header_gnutar *header;- int64_t t;- int err = ARCHIVE_OK;-- /*- * GNU header is like POSIX ustar, except 'prefix' is- * replaced with some other fields. This also means the- * filename is stored as in old-style archives.- */-- /* Grab fields common to all tar variants. */- err = header_common(a, tar, entry, h);- if (err == ARCHIVE_FATAL)- return (err);-- /* Copy filename over (to ensure null termination). */- header = (const struct archive_entry_header_gnutar *)h;- if (archive_entry_copy_pathname_l(entry,- header->name, sizeof(header->name), tar->sconv) != 0) {- err = set_conversion_failed_error(a, tar->sconv, "Pathname");- if (err == ARCHIVE_FATAL)- return (err);- }-- /* Fields common to ustar and GNU */- /* XXX Can the following be factored out since it's common- * to ustar and gnu tar? Is it okay to move it down into- * header_common, perhaps? */- if (archive_entry_copy_uname_l(entry,- header->uname, sizeof(header->uname), tar->sconv) != 0) {- err = set_conversion_failed_error(a, tar->sconv, "Uname");- if (err == ARCHIVE_FATAL)- return (err);- }-- if (archive_entry_copy_gname_l(entry,- header->gname, sizeof(header->gname), tar->sconv) != 0) {- err = set_conversion_failed_error(a, tar->sconv, "Gname");- if (err == ARCHIVE_FATAL)- return (err);- }-- /* Parse out device numbers only for char and block specials */- if (header->typeflag[0] == '3' || header->typeflag[0] == '4') {- archive_entry_set_rdevmajor(entry, (dev_t)- tar_atol(header->rdevmajor, sizeof(header->rdevmajor)));- archive_entry_set_rdevminor(entry, (dev_t)- tar_atol(header->rdevminor, sizeof(header->rdevminor)));- } else- archive_entry_set_rdev(entry, 0);-- tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);-- /* Grab GNU-specific fields. */- t = tar_atol(header->atime, sizeof(header->atime));- if (t > 0)- archive_entry_set_atime(entry, t, 0);- t = tar_atol(header->ctime, sizeof(header->ctime));- if (t > 0)- archive_entry_set_ctime(entry, t, 0);-- if (header->realsize[0] != 0) {- tar->realsize- = tar_atol(header->realsize, sizeof(header->realsize));- archive_entry_set_size(entry, tar->realsize);- tar->realsize_override = 1;- }-- if (header->sparse[0].offset[0] != 0) {- if (gnu_sparse_old_read(a, tar, header, unconsumed)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- } else {- if (header->isextended[0] != 0) {- /* XXX WTF? XXX */- }- }-- return (err);-}--static int-gnu_add_sparse_entry(struct archive_read *a, struct tar *tar,- int64_t offset, int64_t remaining)-{- struct sparse_block *p;-- p = (struct sparse_block *)calloc(1, sizeof(*p));- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- if (tar->sparse_last != NULL)- tar->sparse_last->next = p;- else- tar->sparse_list = p;- tar->sparse_last = p;- if (remaining < 0 || offset < 0 || offset > INT64_MAX - remaining) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Malformed sparse map data");- return (ARCHIVE_FATAL);- }- p->offset = offset;- p->remaining = remaining;- return (ARCHIVE_OK);-}--static void-gnu_clear_sparse_list(struct tar *tar)-{- struct sparse_block *p;-- while (tar->sparse_list != NULL) {- p = tar->sparse_list;- tar->sparse_list = p->next;- free(p);- }- tar->sparse_last = NULL;-}--/*- * GNU tar old-format sparse data.- *- * GNU old-format sparse data is stored in a fixed-field- * format. Offset/size values are 11-byte octal fields (same- * format as 'size' field in ustart header). These are- * stored in the header, allocating subsequent header blocks- * as needed. Extending the header in this way is a pretty- * severe POSIX violation; this design has earned GNU tar a- * lot of criticism.- */--static int-gnu_sparse_old_read(struct archive_read *a, struct tar *tar,- const struct archive_entry_header_gnutar *header, size_t *unconsumed)-{- ssize_t bytes_read;- const void *data;- struct extended {- struct gnu_sparse sparse[21];- char isextended[1];- char padding[7];- };- const struct extended *ext;-- if (gnu_sparse_old_parse(a, tar, header->sparse, 4) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- if (header->isextended[0] == 0)- return (ARCHIVE_OK);-- do {- tar_flush_unconsumed(a, unconsumed);- data = __archive_read_ahead(a, 512, &bytes_read);- if (bytes_read < 0)- return (ARCHIVE_FATAL);- if (bytes_read < 512) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated tar archive "- "detected while reading sparse file data");- return (ARCHIVE_FATAL);- }- *unconsumed = 512;- ext = (const struct extended *)data;- if (gnu_sparse_old_parse(a, tar, ext->sparse, 21) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- } while (ext->isextended[0] != 0);- if (tar->sparse_list != NULL)- tar->entry_offset = tar->sparse_list->offset;- return (ARCHIVE_OK);-}--static int-gnu_sparse_old_parse(struct archive_read *a, struct tar *tar,- const struct gnu_sparse *sparse, int length)-{- while (length > 0 && sparse->offset[0] != 0) {- if (gnu_add_sparse_entry(a, tar,- tar_atol(sparse->offset, sizeof(sparse->offset)),- tar_atol(sparse->numbytes, sizeof(sparse->numbytes)))- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- sparse++;- length--;- }- return (ARCHIVE_OK);-}--/*- * GNU tar sparse format 0.0- *- * Beginning with GNU tar 1.15, sparse files are stored using- * information in the pax extended header. The GNU tar maintainers- * have gone through a number of variations in the process of working- * out this scheme; fortunately, they're all numbered.- *- * Sparse format 0.0 uses attribute GNU.sparse.numblocks to store the- * number of blocks, and GNU.sparse.offset/GNU.sparse.numbytes to- * store offset/size for each block. The repeated instances of these- * latter fields violate the pax specification (which frowns on- * duplicate keys), so this format was quickly replaced.- */--/*- * GNU tar sparse format 0.1- *- * This version replaced the offset/numbytes attributes with- * a single "map" attribute that stored a list of integers. This- * format had two problems: First, the "map" attribute could be very- * long, which caused problems for some implementations. More- * importantly, the sparse data was lost when extracted by archivers- * that didn't recognize this extension.- */--static int-gnu_sparse_01_parse(struct archive_read *a, struct tar *tar, const char *p)-{- const char *e;- int64_t offset = -1, size = -1;-- for (;;) {- e = p;- while (*e != '\0' && *e != ',') {- if (*e < '0' || *e > '9')- return (ARCHIVE_WARN);- e++;- }- if (offset < 0) {- offset = tar_atol10(p, e - p);- if (offset < 0)- return (ARCHIVE_WARN);- } else {- size = tar_atol10(p, e - p);- if (size < 0)- return (ARCHIVE_WARN);- if (gnu_add_sparse_entry(a, tar, offset, size)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- offset = -1;- }- if (*e == '\0')- return (ARCHIVE_OK);- p = e + 1;- }-}--/*- * GNU tar sparse format 1.0- *- * The idea: The offset/size data is stored as a series of base-10- * ASCII numbers prepended to the file data, so that dearchivers that- * don't support this format will extract the block map along with the- * data and a separate post-process can restore the sparseness.- *- * Unfortunately, GNU tar 1.16 had a bug that added unnecessary- * padding to the body of the file when using this format. GNU tar- * 1.17 corrected this bug without bumping the version number, so- * it's not possible to support both variants. This code supports- * the later variant at the expense of not supporting the former.- *- * This variant also replaced GNU.sparse.size with GNU.sparse.realsize- * and introduced the GNU.sparse.major/GNU.sparse.minor attributes.- */--/*- * Read the next line from the input, and parse it as a decimal- * integer followed by '\n'. Returns positive integer value or- * negative on error.- */-static int64_t-gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,- int64_t *remaining, size_t *unconsumed)-{- int64_t l, limit, last_digit_limit;- const char *p;- ssize_t bytes_read;- int base, digit;-- base = 10;- limit = INT64_MAX / base;- last_digit_limit = INT64_MAX % base;-- /*- * Skip any lines starting with '#'; GNU tar specs- * don't require this, but they should.- */- do {- bytes_read = readline(a, tar, &p,- (ssize_t)tar_min(*remaining, 100), unconsumed);- if (bytes_read <= 0)- return (ARCHIVE_FATAL);- *remaining -= bytes_read;- } while (p[0] == '#');-- l = 0;- while (bytes_read > 0) {- if (*p == '\n')- return (l);- if (*p < '0' || *p >= '0' + base)- return (ARCHIVE_WARN);- digit = *p - '0';- if (l > limit || (l == limit && digit > last_digit_limit))- l = INT64_MAX; /* Truncate on overflow. */- else- l = (l * base) + digit;- p++;- bytes_read--;- }- /* TODO: Error message. */- return (ARCHIVE_WARN);-}--/*- * Returns length (in bytes) of the sparse data description- * that was read.- */-static ssize_t-gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed)-{- ssize_t bytes_read;- int entries;- int64_t offset, size, to_skip, remaining;-- /* Clear out the existing sparse list. */- gnu_clear_sparse_list(tar);-- remaining = tar->entry_bytes_remaining;-- /* Parse entries. */- entries = (int)gnu_sparse_10_atol(a, tar, &remaining, unconsumed);- if (entries < 0)- return (ARCHIVE_FATAL);- /* Parse the individual entries. */- while (entries-- > 0) {- /* Parse offset/size */- offset = gnu_sparse_10_atol(a, tar, &remaining, unconsumed);- if (offset < 0)- return (ARCHIVE_FATAL);- size = gnu_sparse_10_atol(a, tar, &remaining, unconsumed);- if (size < 0)- return (ARCHIVE_FATAL);- /* Add a new sparse entry. */- if (gnu_add_sparse_entry(a, tar, offset, size) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }- /* Skip rest of block... */- tar_flush_unconsumed(a, unconsumed);- bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining);- to_skip = 0x1ff & -bytes_read;- /* Fail if tar->entry_bytes_remaing would get negative */- if (to_skip > remaining)- return (ARCHIVE_FATAL);- if (to_skip != __archive_read_consume(a, to_skip))- return (ARCHIVE_FATAL);- return ((ssize_t)(bytes_read + to_skip));-}--/*- * Solaris pax extension for a sparse file. This is recorded with the- * data and hole pairs. The way recording sparse information by Solaris'- * pax simply indicates where data and sparse are, so the stored contents- * consist of both data and hole.- */-static int-solaris_sparse_parse(struct archive_read *a, struct tar *tar,- struct archive_entry *entry, const char *p)-{- const char *e;- int64_t start, end;- int hole = 1;-- (void)entry; /* UNUSED */-- end = 0;- if (*p == ' ')- p++;- else- return (ARCHIVE_WARN);- for (;;) {- e = p;- while (*e != '\0' && *e != ' ') {- if (*e < '0' || *e > '9')- return (ARCHIVE_WARN);- e++;- }- start = end;- end = tar_atol10(p, e - p);- if (end < 0)- return (ARCHIVE_WARN);- if (start < end) {- if (gnu_add_sparse_entry(a, tar, start,- end - start) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- tar->sparse_last->hole = hole;- }- if (*e == '\0')- return (ARCHIVE_OK);- p = e + 1;- hole = hole == 0;- }-}--/*-- * Convert text->integer.- *- * Traditional tar formats (including POSIX) specify base-8 for- * all of the standard numeric fields. This is a significant limitation- * in practice:- * = file size is limited to 8GB- * = rdevmajor and rdevminor are limited to 21 bits- * = uid/gid are limited to 21 bits- *- * There are two workarounds for this:- * = pax extended headers, which use variable-length string fields- * = GNU tar and STAR both allow either base-8 or base-256 in- * most fields. The high bit is set to indicate base-256.- *- * On read, this implementation supports both extensions.- */-static int64_t-tar_atol(const char *p, size_t char_cnt)-{- /*- * Technically, GNU tar considers a field to be in base-256- * only if the first byte is 0xff or 0x80.- */- if (*p & 0x80)- return (tar_atol256(p, char_cnt));- return (tar_atol8(p, char_cnt));-}--/*- * Note that this implementation does not (and should not!) obey- * locale settings; you cannot simply substitute strtol here, since- * it does obey locale.- */-static int64_t-tar_atol_base_n(const char *p, size_t char_cnt, int base)-{- int64_t l, maxval, limit, last_digit_limit;- int digit, sign;-- maxval = INT64_MAX;- limit = INT64_MAX / base;- last_digit_limit = INT64_MAX % base;-- /* the pointer will not be dereferenced if char_cnt is zero- * due to the way the && operator is evaluated.- */- while (char_cnt != 0 && (*p == ' ' || *p == '\t')) {- p++;- char_cnt--;- }-- sign = 1;- if (char_cnt != 0 && *p == '-') {- sign = -1;- p++;- char_cnt--;-- maxval = INT64_MIN;- limit = -(INT64_MIN / base);- last_digit_limit = -(INT64_MIN % base);- }-- l = 0;- if (char_cnt != 0) {- digit = *p - '0';- while (digit >= 0 && digit < base && char_cnt != 0) {- if (l>limit || (l == limit && digit >= last_digit_limit)) {- return maxval; /* Truncate on overflow. */- }- l = (l * base) + digit;- digit = *++p - '0';- char_cnt--;- }- }- return (sign < 0) ? -l : l;-}--static int64_t-tar_atol8(const char *p, size_t char_cnt)-{- return tar_atol_base_n(p, char_cnt, 8);-}--static int64_t-tar_atol10(const char *p, size_t char_cnt)-{- return tar_atol_base_n(p, char_cnt, 10);-}--/*- * Parse a base-256 integer. This is just a variable-length- * twos-complement signed binary value in big-endian order, except- * that the high-order bit is ignored. The values here can be up to- * 12 bytes, so we need to be careful about overflowing 64-bit- * (8-byte) integers.- *- * This code unashamedly assumes that the local machine uses 8-bit- * bytes and twos-complement arithmetic.- */-static int64_t-tar_atol256(const char *_p, size_t char_cnt)-{- uint64_t l;- const unsigned char *p = (const unsigned char *)_p;- unsigned char c, neg;-- /* Extend 7-bit 2s-comp to 8-bit 2s-comp, decide sign. */- c = *p;- if (c & 0x40) {- neg = 0xff;- c |= 0x80;- l = ~ARCHIVE_LITERAL_ULL(0);- } else {- neg = 0;- c &= 0x7f;- l = 0;- }-- /* If more than 8 bytes, check that we can ignore- * high-order bits without overflow. */- while (char_cnt > sizeof(int64_t)) {- --char_cnt;- if (c != neg)- return neg ? INT64_MIN : INT64_MAX;- c = *++p;- }-- /* c is first byte that fits; if sign mismatch, return overflow */- if ((c ^ neg) & 0x80) {- return neg ? INT64_MIN : INT64_MAX;- }-- /* Accumulate remaining bytes. */- while (--char_cnt > 0) {- l = (l << 8) | c;- c = *++p;- }- l = (l << 8) | c;- /* Return signed twos-complement value. */- return (int64_t)(l);-}--/*- * Returns length of line (including trailing newline)- * or negative on error. 'start' argument is updated to- * point to first character of line. This avoids copying- * when possible.- */-static ssize_t-readline(struct archive_read *a, struct tar *tar, const char **start,- ssize_t limit, size_t *unconsumed)-{- ssize_t bytes_read;- ssize_t total_size = 0;- const void *t;- const char *s;- void *p;-- tar_flush_unconsumed(a, unconsumed);-- t = __archive_read_ahead(a, 1, &bytes_read);- if (bytes_read <= 0)- return (ARCHIVE_FATAL);- s = t; /* Start of line? */- p = memchr(t, '\n', bytes_read);- /* If we found '\n' in the read buffer, return pointer to that. */- if (p != NULL) {- bytes_read = 1 + ((const char *)p) - s;- if (bytes_read > limit) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Line too long");- return (ARCHIVE_FATAL);- }- *unconsumed = bytes_read;- *start = s;- return (bytes_read);- }- *unconsumed = bytes_read;- /* Otherwise, we need to accumulate in a line buffer. */- for (;;) {- if (total_size + bytes_read > limit) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Line too long");- return (ARCHIVE_FATAL);- }- if (archive_string_ensure(&tar->line, total_size + bytes_read) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate working buffer");- return (ARCHIVE_FATAL);- }- memcpy(tar->line.s + total_size, t, bytes_read);- tar_flush_unconsumed(a, unconsumed);- total_size += bytes_read;- /* If we found '\n', clean up and return. */- if (p != NULL) {- *start = tar->line.s;- return (total_size);- }- /* Read some more. */- t = __archive_read_ahead(a, 1, &bytes_read);- if (bytes_read <= 0)- return (ARCHIVE_FATAL);- s = t; /* Start of line? */- p = memchr(t, '\n', bytes_read);- /* If we found '\n', trim the read. */- if (p != NULL) {- bytes_read = 1 + ((const char *)p) - s;- }- *unconsumed = bytes_read;- }-}--/*- * base64_decode - Base64 decode- *- * This accepts most variations of base-64 encoding, including:- * * with or without line breaks- * * with or without the final group padded with '=' or '_' characters- * (The most economical Base-64 variant does not pad the last group and- * omits line breaks; RFC1341 used for MIME requires both.)- */-static char *-base64_decode(const char *s, size_t len, size_t *out_len)-{- static const unsigned char digits[64] = {- 'A','B','C','D','E','F','G','H','I','J','K','L','M','N',- 'O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b',- 'c','d','e','f','g','h','i','j','k','l','m','n','o','p',- 'q','r','s','t','u','v','w','x','y','z','0','1','2','3',- '4','5','6','7','8','9','+','/' };- static unsigned char decode_table[128];- char *out, *d;- const unsigned char *src = (const unsigned char *)s;-- /* If the decode table is not yet initialized, prepare it. */- if (decode_table[digits[1]] != 1) {- unsigned i;- memset(decode_table, 0xff, sizeof(decode_table));- for (i = 0; i < sizeof(digits); i++)- decode_table[digits[i]] = i;- }-- /* Allocate enough space to hold the entire output. */- /* Note that we may not use all of this... */- out = (char *)malloc(len - len / 4 + 1);- if (out == NULL) {- *out_len = 0;- return (NULL);- }- d = out;-- while (len > 0) {- /* Collect the next group of (up to) four characters. */- int v = 0;- int group_size = 0;- while (group_size < 4 && len > 0) {- /* '=' or '_' padding indicates final group. */- if (*src == '=' || *src == '_') {- len = 0;- break;- }- /* Skip illegal characters (including line breaks) */- if (*src > 127 || *src < 32- || decode_table[*src] == 0xff) {- len--;- src++;- continue;- }- v <<= 6;- v |= decode_table[*src++];- len --;- group_size++;- }- /* Align a short group properly. */- v <<= 6 * (4 - group_size);- /* Unpack the group we just collected. */- switch (group_size) {- case 4: d[2] = v & 0xff;- /* FALLTHROUGH */- case 3: d[1] = (v >> 8) & 0xff;- /* FALLTHROUGH */- case 2: d[0] = (v >> 16) & 0xff;- break;- case 1: /* this is invalid! */- break;- }- d += group_size * 3 / 4;- }-- *out_len = d - out;- return (out);-}--static char *-url_decode(const char *in)-{- char *out, *d;- const char *s;-- out = (char *)malloc(strlen(in) + 1);- if (out == NULL)- return (NULL);- for (s = in, d = out; *s != '\0'; ) {- if (s[0] == '%' && s[1] != '\0' && s[2] != '\0') {- /* Try to convert % escape */- int digit1 = tohex(s[1]);- int digit2 = tohex(s[2]);- if (digit1 >= 0 && digit2 >= 0) {- /* Looks good, consume three chars */- s += 3;- /* Convert output */- *d++ = ((digit1 << 4) | digit2);- continue;- }- /* Else fall through and treat '%' as normal char */- }- *d++ = *s++;- }- *d = '\0';- return (out);-}--static int-tohex(int c)-{- if (c >= '0' && c <= '9')- return (c - '0');- else if (c >= 'A' && c <= 'F')- return (c - 'A' + 10);- else if (c >= 'a' && c <= 'f')- return (c - 'a' + 10);- else- return (-1);-}
− c/archive_read_support_format_warc.c
@@ -1,848 +0,0 @@-/*-- * Copyright (c) 2014 Sebastian Freundt- * 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$");--/**- * WARC is standardised by ISO TC46/SC4/WG12 and currently available as- * ISO 28500:2009.- * For the purposes of this file we used the final draft from:- * http://bibnum.bnf.fr/warc/WARC_ISO_28500_version1_latestdraft.pdf- *- * Todo:- * [ ] real-world warcs can contain resources at endpoints ending in /- * e.g. http://bibnum.bnf.fr/warc/- * if you're lucky their response contains a Content-Location: header- * pointing to a unix-compliant filename, in the example above it's- * Content-Location: http://bibnum.bnf.fr/warc/index.html- * however, that's not mandated and github for example doesn't follow- * this convention.- * We need a set of archive options to control what to do with- * entries like these, at the moment care is taken to skip them.- *- **/--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_CTYPE_H-#include <ctype.h>-#endif-#ifdef HAVE_TIME_H-#include <time.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_read_private.h"--typedef enum {- WT_NONE,- /* warcinfo */- WT_INFO,- /* metadata */- WT_META,- /* resource */- WT_RSRC,- /* request, unsupported */- WT_REQ,- /* response, unsupported */- WT_RSP,- /* revisit, unsupported */- WT_RVIS,- /* conversion, unsupported */- WT_CONV,- /* continuation, unsupported at the moment */- WT_CONT,- /* invalid type */- LAST_WT-} warc_type_t;--typedef struct {- size_t len;- const char *str;-} warc_string_t;--typedef struct {- size_t len;- char *str;-} warc_strbuf_t;--struct warc_s {- /* content length ahead */- size_t cntlen;- /* and how much we've processed so far */- size_t cntoff;- /* and how much we need to consume between calls */- size_t unconsumed;-- /* string pool */- warc_strbuf_t pool;- /* previous version */- unsigned int pver;- /* stringified format name */- struct archive_string sver;-};--static int _warc_bid(struct archive_read *a, int);-static int _warc_cleanup(struct archive_read *a);-static int _warc_read(struct archive_read*, const void**, size_t*, int64_t*);-static int _warc_skip(struct archive_read *a);-static int _warc_rdhdr(struct archive_read *a, struct archive_entry *e);--/* private routines */-static unsigned int _warc_rdver(const char *buf, size_t bsz);-static unsigned int _warc_rdtyp(const char *buf, size_t bsz);-static warc_string_t _warc_rduri(const char *buf, size_t bsz);-static ssize_t _warc_rdlen(const char *buf, size_t bsz);-static time_t _warc_rdrtm(const char *buf, size_t bsz);-static time_t _warc_rdmtm(const char *buf, size_t bsz);-static const char *_warc_find_eoh(const char *buf, size_t bsz);-static const char *_warc_find_eol(const char *buf, size_t bsz);--int-archive_read_support_format_warc(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct warc_s *w;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_warc");-- if ((w = calloc(1, sizeof(*w))) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate warc data");- return (ARCHIVE_FATAL);- }-- r = __archive_read_register_format(- a, w, "warc",- _warc_bid, NULL, _warc_rdhdr, _warc_read,- _warc_skip, NULL, _warc_cleanup, NULL, NULL);-- if (r != ARCHIVE_OK) {- free(w);- return (r);- }- return (ARCHIVE_OK);-}--static int-_warc_cleanup(struct archive_read *a)-{- struct warc_s *w = a->format->data;-- if (w->pool.len > 0U) {- free(w->pool.str);- }- archive_string_free(&w->sver);- free(w);- a->format->data = NULL;- return (ARCHIVE_OK);-}--static int-_warc_bid(struct archive_read *a, int best_bid)-{- const char *hdr;- ssize_t nrd;- unsigned int ver;-- (void)best_bid; /* UNUSED */-- /* check first line of file, it should be a record already */- if ((hdr = __archive_read_ahead(a, 12U, &nrd)) == NULL) {- /* no idea what to do */- return -1;- } else if (nrd < 12) {- /* nah, not for us, our magic cookie is at least 12 bytes */- return -1;- }-- /* otherwise snarf the record's version number */- ver = _warc_rdver(hdr, nrd);- if (ver < 1200U || ver > 10000U) {- /* we only support WARC 0.12 to 1.0 */- return -1;- }-- /* otherwise be confident */- return (64);-}--static int-_warc_rdhdr(struct archive_read *a, struct archive_entry *entry)-{-#define HDR_PROBE_LEN (12U)- struct warc_s *w = a->format->data;- unsigned int ver;- const char *buf;- ssize_t nrd;- const char *eoh;- /* for the file name, saves some strndup()'ing */- warc_string_t fnam;- /* warc record type, not that we really use it a lot */- warc_type_t ftyp;- /* content-length+error monad */- ssize_t cntlen;- /* record time is the WARC-Date time we reinterpret it as ctime */- time_t rtime;- /* mtime is the Last-Modified time which will be the entry's mtime */- time_t mtime;--start_over:- /* just use read_ahead() they keep track of unconsumed- * bits and bobs for us; no need to put an extra shift in- * and reproduce that functionality here */- buf = __archive_read_ahead(a, HDR_PROBE_LEN, &nrd);-- if (nrd < 0) {- /* no good */- archive_set_error(- &a->archive, ARCHIVE_ERRNO_MISC,- "Bad record header");- return (ARCHIVE_FATAL);- } else if (buf == NULL) {- /* there should be room for at least WARC/bla\r\n- * must be EOF therefore */- return (ARCHIVE_EOF);- }- /* looks good so far, try and find the end of the header now */- eoh = _warc_find_eoh(buf, nrd);- if (eoh == NULL) {- /* still no good, the header end might be beyond the- * probe we've requested, but then again who'd cram- * so much stuff into the header *and* be 28500-compliant */- archive_set_error(- &a->archive, ARCHIVE_ERRNO_MISC,- "Bad record header");- return (ARCHIVE_FATAL);- }- ver = _warc_rdver(buf, eoh - buf);- /* we currently support WARC 0.12 to 1.0 */- if (ver == 0U) {- archive_set_error(- &a->archive, ARCHIVE_ERRNO_MISC,- "Invalid record version");- return (ARCHIVE_FATAL);- } else if (ver < 1200U || ver > 10000U) {- archive_set_error(- &a->archive, ARCHIVE_ERRNO_MISC,- "Unsupported record version: %u.%u",- ver / 10000, (ver % 10000) / 100);- return (ARCHIVE_FATAL);- }- cntlen = _warc_rdlen(buf, eoh - buf);- if (cntlen < 0) {- /* nightmare! the specs say content-length is mandatory- * so I don't feel overly bad stopping the reader here */- archive_set_error(- &a->archive, EINVAL,- "Bad content length");- return (ARCHIVE_FATAL);- }- rtime = _warc_rdrtm(buf, eoh - buf);- if (rtime == (time_t)-1) {- /* record time is mandatory as per WARC/1.0,- * so just barf here, fast and loud */- archive_set_error(- &a->archive, EINVAL,- "Bad record time");- return (ARCHIVE_FATAL);- }-- /* let the world know we're a WARC archive */- a->archive.archive_format = ARCHIVE_FORMAT_WARC;- if (ver != w->pver) {- /* stringify this entry's version */- archive_string_sprintf(&w->sver,- "WARC/%u.%u", ver / 10000, (ver % 10000) / 100);- /* remember the version */- w->pver = ver;- }- /* start off with the type */- ftyp = _warc_rdtyp(buf, eoh - buf);- /* and let future calls know about the content */- w->cntlen = cntlen;- w->cntoff = 0U;- mtime = 0;/* Avoid compiling error on some platform. */-- switch (ftyp) {- case WT_RSRC:- case WT_RSP:- /* only try and read the filename in the cases that are- * guaranteed to have one */- fnam = _warc_rduri(buf, eoh - buf);- /* check the last character in the URI to avoid creating- * directory endpoints as files, see Todo above */- if (fnam.len == 0 || fnam.str[fnam.len - 1] == '/') {- /* break here for now */- fnam.len = 0U;- fnam.str = NULL;- break;- }- /* bang to our string pool, so we save a- * malloc()+free() roundtrip */- if (fnam.len + 1U > w->pool.len) {- w->pool.len = ((fnam.len + 64U) / 64U) * 64U;- w->pool.str = realloc(w->pool.str, w->pool.len);- }- memcpy(w->pool.str, fnam.str, fnam.len);- w->pool.str[fnam.len] = '\0';- /* let no one else know about the pool, it's a secret, shhh */- fnam.str = w->pool.str;-- /* snarf mtime or deduce from rtime- * this is a custom header added by our writer, it's quite- * hard to believe anyone else would go through with it- * (apart from being part of some http responses of course) */- if ((mtime = _warc_rdmtm(buf, eoh - buf)) == (time_t)-1) {- mtime = rtime;- }- break;- case WT_NONE:- case WT_INFO:- case WT_META:- case WT_REQ:- case WT_RVIS:- case WT_CONV:- case WT_CONT:- case LAST_WT:- default:- fnam.len = 0U;- fnam.str = NULL;- break;- }-- /* now eat some of those delicious buffer bits */- __archive_read_consume(a, eoh - buf);-- switch (ftyp) {- case WT_RSRC:- case WT_RSP:- if (fnam.len > 0U) {- /* populate entry object */- archive_entry_set_filetype(entry, AE_IFREG);- archive_entry_copy_pathname(entry, fnam.str);- archive_entry_set_size(entry, cntlen);- archive_entry_set_perm(entry, 0644);- /* rtime is the new ctime, mtime stays mtime */- archive_entry_set_ctime(entry, rtime, 0L);- archive_entry_set_mtime(entry, mtime, 0L);- break;- }- /* FALLTHROUGH */- case WT_NONE:- case WT_INFO:- case WT_META:- case WT_REQ:- case WT_RVIS:- case WT_CONV:- case WT_CONT:- case LAST_WT:- default:- /* consume the content and start over */- _warc_skip(a);- goto start_over;- }- return (ARCHIVE_OK);-}--static int-_warc_read(struct archive_read *a, const void **buf, size_t *bsz, int64_t *off)-{- struct warc_s *w = a->format->data;- const char *rab;- ssize_t nrd;-- if (w->cntoff >= w->cntlen) {- eof:- /* it's our lucky day, no work, we can leave early */- *buf = NULL;- *bsz = 0U;- *off = w->cntoff + 4U/*for \r\n\r\n separator*/;- w->unconsumed = 0U;- return (ARCHIVE_EOF);- }-- if (w->unconsumed) {- __archive_read_consume(a, w->unconsumed);- w->unconsumed = 0U;- }-- rab = __archive_read_ahead(a, 1U, &nrd);- if (nrd < 0) {- *bsz = 0U;- /* big catastrophe */- return (int)nrd;- } else if (nrd == 0) {- goto eof;- } else if ((size_t)nrd > w->cntlen - w->cntoff) {- /* clamp to content-length */- nrd = w->cntlen - w->cntoff;- }- *off = w->cntoff;- *bsz = nrd;- *buf = rab;-- w->cntoff += nrd;- w->unconsumed = (size_t)nrd;- return (ARCHIVE_OK);-}--static int-_warc_skip(struct archive_read *a)-{- struct warc_s *w = a->format->data;-- __archive_read_consume(a, w->cntlen + 4U/*\r\n\r\n separator*/);- w->cntlen = 0U;- w->cntoff = 0U;- return (ARCHIVE_OK);-}---/* private routines */-static void*-deconst(const void *c)-{- return (void *)(uintptr_t)c;-}--static char*-xmemmem(const char *hay, const size_t haysize,- const char *needle, const size_t needlesize)-{- const char *const eoh = hay + haysize;- const char *const eon = needle + needlesize;- const char *hp;- const char *np;- const char *cand;- unsigned int hsum;- unsigned int nsum;- unsigned int eqp;-- /* trivial checks first- * a 0-sized needle is defined to be found anywhere in haystack- * then run strchr() to find a candidate in HAYSTACK (i.e. a portion- * that happens to begin with *NEEDLE) */- if (needlesize == 0UL) {- return deconst(hay);- } else if ((hay = memchr(hay, *needle, haysize)) == NULL) {- /* trivial */- return NULL;- }-- /* First characters of haystack and needle are the same now. Both are- * guaranteed to be at least one character long. Now computes the sum- * of characters values of needle together with the sum of the first- * needle_len characters of haystack. */- for (hp = hay + 1U, np = needle + 1U, hsum = *hay, nsum = *hay, eqp = 1U;- hp < eoh && np < eon;- hsum ^= *hp, nsum ^= *np, eqp &= *hp == *np, hp++, np++);-- /* HP now references the (NEEDLESIZE + 1)-th character. */- if (np < eon) {- /* haystack is smaller than needle, :O */- return NULL;- } else if (eqp) {- /* found a match */- return deconst(hay);- }-- /* now loop through the rest of haystack,- * updating the sum iteratively */- for (cand = hay; hp < eoh; hp++) {- hsum ^= *cand++;- hsum ^= *hp;-- /* Since the sum of the characters is already known to be- * equal at that point, it is enough to check just NEEDLESIZE - 1- * characters for equality,- * also CAND is by design < HP, so no need for range checks */- if (hsum == nsum && memcmp(cand, needle, needlesize - 1U) == 0) {- return deconst(cand);- }- }- return NULL;-}--static int-strtoi_lim(const char *str, const char **ep, int llim, int ulim)-{- int res = 0;- const char *sp;- /* we keep track of the number of digits via rulim */- int rulim;-- for (sp = str, rulim = ulim > 10 ? ulim : 10;- res * 10 <= ulim && rulim && *sp >= '0' && *sp <= '9';- sp++, rulim /= 10) {- res *= 10;- res += *sp - '0';- }- if (sp == str) {- res = -1;- } else if (res < llim || res > ulim) {- res = -2;- }- *ep = (const char*)sp;- return res;-}--static time_t-time_from_tm(struct tm *t)-{-#if HAVE__MKGMTIME- return _mkgmtime(t);-#elif HAVE_TIMEGM- /* Use platform timegm() if available. */- return (timegm(t));-#else- /* Else use direct calculation using POSIX assumptions. */- /* First, fix up tm_yday based on the year/month/day. */- if (mktime(t) == (time_t)-1)- return ((time_t)-1);- /* Then we can compute timegm() from first principles. */- return (t->tm_sec- + t->tm_min * 60- + t->tm_hour * 3600- + t->tm_yday * 86400- + (t->tm_year - 70) * 31536000- + ((t->tm_year - 69) / 4) * 86400- - ((t->tm_year - 1) / 100) * 86400- + ((t->tm_year + 299) / 400) * 86400);-#endif-}--static time_t-xstrpisotime(const char *s, char **endptr)-{-/** like strptime() but strictly for ISO 8601 Zulu strings */- struct tm tm;- time_t res = (time_t)-1;-- /* make sure tm is clean */- memset(&tm, 0, sizeof(tm));-- /* as a courtesy to our callers, and since this is a non-standard- * routine, we skip leading whitespace */- while (*s == ' ' || *s == '\t')- ++s;-- /* read year */- if ((tm.tm_year = strtoi_lim(s, &s, 1583, 4095)) < 0 || *s++ != '-') {- goto out;- }- /* read month */- if ((tm.tm_mon = strtoi_lim(s, &s, 1, 12)) < 0 || *s++ != '-') {- goto out;- }- /* read day-of-month */- if ((tm.tm_mday = strtoi_lim(s, &s, 1, 31)) < 0 || *s++ != 'T') {- goto out;- }- /* read hour */- if ((tm.tm_hour = strtoi_lim(s, &s, 0, 23)) < 0 || *s++ != ':') {- goto out;- }- /* read minute */- if ((tm.tm_min = strtoi_lim(s, &s, 0, 59)) < 0 || *s++ != ':') {- goto out;- }- /* read second */- if ((tm.tm_sec = strtoi_lim(s, &s, 0, 60)) < 0 || *s++ != 'Z') {- goto out;- }-- /* massage TM to fulfill some of POSIX' constraints */- tm.tm_year -= 1900;- tm.tm_mon--;-- /* now convert our custom tm struct to a unix stamp using UTC */- res = time_from_tm(&tm);--out:- if (endptr != NULL) {- *endptr = deconst(s);- }- return res;-}--static unsigned int-_warc_rdver(const char *buf, size_t bsz)-{- static const char magic[] = "WARC/";- const char *c;- unsigned int ver = 0U;- unsigned int end = 0U;-- if (bsz < 12 || memcmp(buf, magic, sizeof(magic) - 1U) != 0) {- /* buffer too small or invalid magic */- return ver;- }- /* looks good so far, read the version number for a laugh */- buf += sizeof(magic) - 1U;-- if (isdigit((unsigned char)buf[0U]) && (buf[1U] == '.') &&- isdigit((unsigned char)buf[2U])) {- /* we support a maximum of 2 digits in the minor version */- if (isdigit((unsigned char)buf[3U]))- end = 1U;- /* set up major version */- ver = (buf[0U] - '0') * 10000U;- /* set up minor version */- if (end == 1U) {- ver += (buf[2U] - '0') * 1000U;- ver += (buf[3U] - '0') * 100U;- } else- ver += (buf[2U] - '0') * 100U;- /*- * WARC below version 0.12 has a space-separated header- * WARC 0.12 and above terminates the version with a CRLF- */- c = buf + 3U + end;- if (ver >= 1200U) {- if (memcmp(c, "\r\n", 2U) != 0)- ver = 0U;- } else {- /* ver < 1200U */- if (*c != ' ' && *c != '\t')- ver = 0U;- }- }- return ver;-}--static unsigned int-_warc_rdtyp(const char *buf, size_t bsz)-{- static const char _key[] = "\r\nWARC-Type:";- const char *val, *eol;-- if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {- /* no bother */- return WT_NONE;- }- val += sizeof(_key) - 1U;- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {- /* no end of line */- return WT_NONE;- }-- /* overread whitespace */- while (val < eol && (*val == ' ' || *val == '\t'))- ++val;-- if (val + 8U == eol) {- if (memcmp(val, "resource", 8U) == 0)- return WT_RSRC;- else if (memcmp(val, "response", 8U) == 0)- return WT_RSP;- }- return WT_NONE;-}--static warc_string_t-_warc_rduri(const char *buf, size_t bsz)-{- static const char _key[] = "\r\nWARC-Target-URI:";- const char *val, *uri, *eol, *p;- warc_string_t res = {0U, NULL};-- if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {- /* no bother */- return res;- }- /* overread whitespace */- val += sizeof(_key) - 1U;- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {- /* no end of line */- return res;- }-- while (val < eol && (*val == ' ' || *val == '\t'))- ++val;-- /* overread URL designators */- if ((uri = xmemmem(val, eol - val, "://", 3U)) == NULL) {- /* not touching that! */- return res;- }-- /* spaces inside uri are not allowed, CRLF should follow */- for (p = val; p < eol; p++) {- if (isspace((unsigned char)*p))- return res;- }-- /* there must be at least space for ftp */- if (uri < (val + 3U))- return res;-- /* move uri to point to after :// */- uri += 3U;-- /* now then, inspect the URI */- if (memcmp(val, "file", 4U) == 0) {- /* perfect, nothing left to do here */-- } else if (memcmp(val, "http", 4U) == 0 ||- memcmp(val, "ftp", 3U) == 0) {- /* overread domain, and the first / */- while (uri < eol && *uri++ != '/');- } else {- /* not sure what to do? best to bugger off */- return res;- }- res.str = uri;- res.len = eol - uri;- return res;-}--static ssize_t-_warc_rdlen(const char *buf, size_t bsz)-{- static const char _key[] = "\r\nContent-Length:";- const char *val, *eol;- char *on = NULL;- long int len;-- if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {- /* no bother */- return -1;- }- val += sizeof(_key) - 1U;- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {- /* no end of line */- return -1;- }-- /* skip leading whitespace */- while (val < eol && (*val == ' ' || *val == '\t'))- val++;- /* there must be at least one digit */- if (!isdigit((unsigned char)*val))- return -1;- errno = 0;- len = strtol(val, &on, 10);- if (errno != 0 || on != eol) {- /* line must end here */- return -1;- }-- return (size_t)len;-}--static time_t-_warc_rdrtm(const char *buf, size_t bsz)-{- static const char _key[] = "\r\nWARC-Date:";- const char *val, *eol;- char *on = NULL;- time_t res;-- if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {- /* no bother */- return (time_t)-1;- }- val += sizeof(_key) - 1U;- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {- /* no end of line */- return -1;- }-- /* xstrpisotime() kindly overreads whitespace for us, so use that */- res = xstrpisotime(val, &on);- if (on != eol) {- /* line must end here */- return -1;- }- return res;-}--static time_t-_warc_rdmtm(const char *buf, size_t bsz)-{- static const char _key[] = "\r\nLast-Modified:";- const char *val, *eol;- char *on = NULL;- time_t res;-- if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {- /* no bother */- return (time_t)-1;- }- val += sizeof(_key) - 1U;- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {- /* no end of line */- return -1;- }-- /* xstrpisotime() kindly overreads whitespace for us, so use that */- res = xstrpisotime(val, &on);- if (on != eol) {- /* line must end here */- return -1;- }- return res;-}--static const char*-_warc_find_eoh(const char *buf, size_t bsz)-{- static const char _marker[] = "\r\n\r\n";- const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);-- if (hit != NULL) {- hit += sizeof(_marker) - 1U;- }- return hit;-}--static const char*-_warc_find_eol(const char *buf, size_t bsz)-{- static const char _marker[] = "\r\n";- const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);-- return hit;-}-/* archive_read_support_format_warc.c ends here */
− c/archive_read_support_format_xar.c
@@ -1,3332 +0,0 @@-/*-- * Copyright (c) 2009 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */-#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#if HAVE_LIBXML_XMLREADER_H-#include <libxml/xmlreader.h>-#elif HAVE_BSDXML_H-#include <bsdxml.h>-#elif HAVE_EXPAT_H-#include <expat.h>-#endif-#ifdef HAVE_BZLIB_H-#include <bzlib.h>-#endif-#if HAVE_LZMA_H-#include <lzma.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif--#include "archive.h"-#include "archive_digest_private.h"-#include "archive_endian.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_read_private.h"--#if (!defined(HAVE_LIBXML_XMLREADER_H) && \- !defined(HAVE_BSDXML_H) && !defined(HAVE_EXPAT_H)) ||\- !defined(HAVE_ZLIB_H) || \- !defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)-/*- * xar needs several external libraries.- * o libxml2 or expat --- XML parser- * o openssl or MD5/SHA1 hash function- * o zlib- * o bzlib2 (option)- * o liblzma (option)- */-int-archive_read_support_format_xar(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_xar");-- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Xar not supported on this platform");- return (ARCHIVE_WARN);-}--#else /* Support xar format */--/* #define DEBUG 1 */-/* #define DEBUG_PRINT_TOC 1 */-#if DEBUG_PRINT_TOC-#define PRINT_TOC(d, outbytes) do { \- unsigned char *x = (unsigned char *)(uintptr_t)d; \- unsigned char c = x[outbytes-1]; \- x[outbytes - 1] = 0; \- fprintf(stderr, "%s", x); \- fprintf(stderr, "%c", c); \- x[outbytes - 1] = c; \-} while (0)-#else-#define PRINT_TOC(d, outbytes)-#endif--#define HEADER_MAGIC 0x78617221-#define HEADER_SIZE 28-#define HEADER_VERSION 1-#define CKSUM_NONE 0-#define CKSUM_SHA1 1-#define CKSUM_MD5 2--#define MD5_SIZE 16-#define SHA1_SIZE 20-#define MAX_SUM_SIZE 20--enum enctype {- NONE,- GZIP,- BZIP2,- LZMA,- XZ,-};--struct chksumval {- int alg;- size_t len;- unsigned char val[MAX_SUM_SIZE];-};--struct chksumwork {- int alg;-#ifdef ARCHIVE_HAS_MD5- archive_md5_ctx md5ctx;-#endif-#ifdef ARCHIVE_HAS_SHA1- archive_sha1_ctx sha1ctx;-#endif-};--struct xattr {- struct xattr *next;- struct archive_string name;- uint64_t id;- uint64_t length;- uint64_t offset;- uint64_t size;- enum enctype encoding;- struct chksumval a_sum;- struct chksumval e_sum;- struct archive_string fstype;-};--struct xar_file {- struct xar_file *next;- struct xar_file *hdnext;- struct xar_file *parent;- int subdirs;-- unsigned int has;-#define HAS_DATA 0x00001-#define HAS_PATHNAME 0x00002-#define HAS_SYMLINK 0x00004-#define HAS_TIME 0x00008-#define HAS_UID 0x00010-#define HAS_GID 0x00020-#define HAS_MODE 0x00040-#define HAS_TYPE 0x00080-#define HAS_DEV 0x00100-#define HAS_DEVMAJOR 0x00200-#define HAS_DEVMINOR 0x00400-#define HAS_INO 0x00800-#define HAS_FFLAGS 0x01000-#define HAS_XATTR 0x02000-#define HAS_ACL 0x04000-#define HAS_CTIME 0x08000-#define HAS_MTIME 0x10000-#define HAS_ATIME 0x20000-- uint64_t id;- uint64_t length;- uint64_t offset;- uint64_t size;- enum enctype encoding;- struct chksumval a_sum;- struct chksumval e_sum;- struct archive_string pathname;- struct archive_string symlink;- time_t ctime;- time_t mtime;- time_t atime;- struct archive_string uname;- int64_t uid;- struct archive_string gname;- int64_t gid;- mode_t mode;- dev_t dev;- dev_t devmajor;- dev_t devminor;- int64_t ino64;- struct archive_string fflags_text;- unsigned int link;- unsigned int nlink;- struct archive_string hardlink;- struct xattr *xattr_list;-};--struct hdlink {- struct hdlink *next;-- unsigned int id;- int cnt;- struct xar_file *files;-};--struct heap_queue {- struct xar_file **files;- int allocated;- int used;-};--enum xmlstatus {- INIT,- XAR,- TOC,- TOC_CREATION_TIME,- TOC_CHECKSUM,- TOC_CHECKSUM_OFFSET,- TOC_CHECKSUM_SIZE,- TOC_FILE,- FILE_DATA,- FILE_DATA_LENGTH,- FILE_DATA_OFFSET,- FILE_DATA_SIZE,- FILE_DATA_ENCODING,- FILE_DATA_A_CHECKSUM,- FILE_DATA_E_CHECKSUM,- FILE_DATA_CONTENT,- FILE_EA,- FILE_EA_LENGTH,- FILE_EA_OFFSET,- FILE_EA_SIZE,- FILE_EA_ENCODING,- FILE_EA_A_CHECKSUM,- FILE_EA_E_CHECKSUM,- FILE_EA_NAME,- FILE_EA_FSTYPE,- FILE_CTIME,- FILE_MTIME,- FILE_ATIME,- FILE_GROUP,- FILE_GID,- FILE_USER,- FILE_UID,- FILE_MODE,- FILE_DEVICE,- FILE_DEVICE_MAJOR,- FILE_DEVICE_MINOR,- FILE_DEVICENO,- FILE_INODE,- FILE_LINK,- FILE_TYPE,- FILE_NAME,- FILE_ACL,- FILE_ACL_DEFAULT,- FILE_ACL_ACCESS,- FILE_ACL_APPLEEXTENDED,- /* BSD file flags. */- FILE_FLAGS,- FILE_FLAGS_USER_NODUMP,- FILE_FLAGS_USER_IMMUTABLE,- FILE_FLAGS_USER_APPEND,- FILE_FLAGS_USER_OPAQUE,- FILE_FLAGS_USER_NOUNLINK,- FILE_FLAGS_SYS_ARCHIVED,- FILE_FLAGS_SYS_IMMUTABLE,- FILE_FLAGS_SYS_APPEND,- FILE_FLAGS_SYS_NOUNLINK,- FILE_FLAGS_SYS_SNAPSHOT,- /* Linux file flags. */- FILE_EXT2,- FILE_EXT2_SecureDeletion,- FILE_EXT2_Undelete,- FILE_EXT2_Compress,- FILE_EXT2_Synchronous,- FILE_EXT2_Immutable,- FILE_EXT2_AppendOnly,- FILE_EXT2_NoDump,- FILE_EXT2_NoAtime,- FILE_EXT2_CompDirty,- FILE_EXT2_CompBlock,- FILE_EXT2_NoCompBlock,- FILE_EXT2_CompError,- FILE_EXT2_BTree,- FILE_EXT2_HashIndexed,- FILE_EXT2_iMagic,- FILE_EXT2_Journaled,- FILE_EXT2_NoTail,- FILE_EXT2_DirSync,- FILE_EXT2_TopDir,- FILE_EXT2_Reserved,- UNKNOWN,-};--struct unknown_tag {- struct unknown_tag *next;- struct archive_string name;-};--struct xar {- uint64_t offset; /* Current position in the file. */- int64_t total;- uint64_t h_base;- int end_of_file;-#define OUTBUFF_SIZE (1024 * 64)- unsigned char *outbuff;-- enum xmlstatus xmlsts;- enum xmlstatus xmlsts_unknown;- struct unknown_tag *unknowntags;- int base64text;-- /*- * TOC- */- uint64_t toc_remaining;- uint64_t toc_total;- uint64_t toc_chksum_offset;- uint64_t toc_chksum_size;-- /*- * For Decoding data.- */- enum enctype rd_encoding;- z_stream stream;- int stream_valid;-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- bz_stream bzstream;- int bzstream_valid;-#endif-#if HAVE_LZMA_H && HAVE_LIBLZMA- lzma_stream lzstream;- int lzstream_valid;-#endif- /*- * For Checksum data.- */- struct chksumwork a_sumwrk;- struct chksumwork e_sumwrk;-- struct xar_file *file; /* current reading file. */- struct xattr *xattr; /* current reading extended attribute. */- struct heap_queue file_queue;- struct xar_file *hdlink_orgs;- struct hdlink *hdlink_list;-- int entry_init;- uint64_t entry_total;- uint64_t entry_remaining;- size_t entry_unconsumed;- uint64_t entry_size;- enum enctype entry_encoding;- struct chksumval entry_a_sum;- struct chksumval entry_e_sum;-- struct archive_string_conv *sconv;-};--struct xmlattr {- struct xmlattr *next;- char *name;- char *value;-};--struct xmlattr_list {- struct xmlattr *first;- struct xmlattr **last;-};--static int xar_bid(struct archive_read *, int);-static int xar_read_header(struct archive_read *,- struct archive_entry *);-static int xar_read_data(struct archive_read *,- const void **, size_t *, int64_t *);-static int xar_read_data_skip(struct archive_read *);-static int xar_cleanup(struct archive_read *);-static int move_reading_point(struct archive_read *, uint64_t);-static int rd_contents_init(struct archive_read *,- enum enctype, int, int);-static int rd_contents(struct archive_read *, const void **,- size_t *, size_t *, uint64_t);-static uint64_t atol10(const char *, size_t);-static int64_t atol8(const char *, size_t);-static size_t atohex(unsigned char *, size_t, const char *, size_t);-static time_t parse_time(const char *p, size_t n);-static int heap_add_entry(struct archive_read *a,- struct heap_queue *, struct xar_file *);-static struct xar_file *heap_get_entry(struct heap_queue *);-static int add_link(struct archive_read *,- struct xar *, struct xar_file *);-static void checksum_init(struct archive_read *, int, int);-static void checksum_update(struct archive_read *, const void *,- size_t, const void *, size_t);-static int checksum_final(struct archive_read *, const void *,- size_t, const void *, size_t);-static void checksum_cleanup(struct archive_read *);-static int decompression_init(struct archive_read *, enum enctype);-static int decompress(struct archive_read *, const void **,- size_t *, const void *, size_t *);-static int decompression_cleanup(struct archive_read *);-static void xmlattr_cleanup(struct xmlattr_list *);-static int file_new(struct archive_read *,- struct xar *, struct xmlattr_list *);-static void file_free(struct xar_file *);-static int xattr_new(struct archive_read *,- struct xar *, struct xmlattr_list *);-static void xattr_free(struct xattr *);-static int getencoding(struct xmlattr_list *);-static int getsumalgorithm(struct xmlattr_list *);-static int unknowntag_start(struct archive_read *,- struct xar *, const char *);-static void unknowntag_end(struct xar *, const char *);-static int xml_start(struct archive_read *,- const char *, struct xmlattr_list *);-static void xml_end(void *, const char *);-static void xml_data(void *, const char *, int);-static int xml_parse_file_flags(struct xar *, const char *);-static int xml_parse_file_ext2(struct xar *, const char *);-#if defined(HAVE_LIBXML_XMLREADER_H)-static int xml2_xmlattr_setup(struct archive_read *,- struct xmlattr_list *, xmlTextReaderPtr);-static int xml2_read_cb(void *, char *, int);-static int xml2_close_cb(void *);-static void xml2_error_hdr(void *, const char *, xmlParserSeverities,- xmlTextReaderLocatorPtr);-static int xml2_read_toc(struct archive_read *);-#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)-struct expat_userData {- int state;- struct archive_read *archive;-};-static int expat_xmlattr_setup(struct archive_read *,- struct xmlattr_list *, const XML_Char **);-static void expat_start_cb(void *, const XML_Char *, const XML_Char **);-static void expat_end_cb(void *, const XML_Char *);-static void expat_data_cb(void *, const XML_Char *, int);-static int expat_read_toc(struct archive_read *);-#endif--int-archive_read_support_format_xar(struct archive *_a)-{- struct xar *xar;- struct archive_read *a = (struct archive_read *)_a;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_xar");-- xar = (struct xar *)calloc(1, sizeof(*xar));- if (xar == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate xar data");- return (ARCHIVE_FATAL);- }-- /* initialize xar->file_queue */- xar->file_queue.allocated = 0;- xar->file_queue.used = 0;- xar->file_queue.files = NULL;-- r = __archive_read_register_format(a,- xar,- "xar",- xar_bid,- NULL,- xar_read_header,- xar_read_data,- xar_read_data_skip,- NULL,- xar_cleanup,- NULL,- NULL);- if (r != ARCHIVE_OK)- free(xar);- return (r);-}--static int-xar_bid(struct archive_read *a, int best_bid)-{- const unsigned char *b;- int bid;-- (void)best_bid; /* UNUSED */-- b = __archive_read_ahead(a, HEADER_SIZE, NULL);- if (b == NULL)- return (-1);-- bid = 0;- /*- * Verify magic code- */- if (archive_be32dec(b) != HEADER_MAGIC)- return (0);- bid += 32;- /*- * Verify header size- */- if (archive_be16dec(b+4) != HEADER_SIZE)- return (0);- bid += 16;- /*- * Verify header version- */- if (archive_be16dec(b+6) != HEADER_VERSION)- return (0);- bid += 16;- /*- * Verify type of checksum- */- switch (archive_be32dec(b+24)) {- case CKSUM_NONE:- case CKSUM_SHA1:- case CKSUM_MD5:- bid += 32;- break;- default:- return (0);- }-- return (bid);-}--static int-read_toc(struct archive_read *a)-{- struct xar *xar;- struct xar_file *file;- const unsigned char *b;- uint64_t toc_compressed_size;- uint64_t toc_uncompressed_size;- uint32_t toc_chksum_alg;- ssize_t bytes;- int r;-- xar = (struct xar *)(a->format->data);-- /*- * Read xar header.- */- b = __archive_read_ahead(a, HEADER_SIZE, &bytes);- if (bytes < 0)- return ((int)bytes);- if (bytes < HEADER_SIZE) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated archive header");- return (ARCHIVE_FATAL);- }-- if (archive_be32dec(b) != HEADER_MAGIC) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid header magic");- return (ARCHIVE_FATAL);- }- if (archive_be16dec(b+6) != HEADER_VERSION) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported header version(%d)",- archive_be16dec(b+6));- return (ARCHIVE_FATAL);- }- toc_compressed_size = archive_be64dec(b+8);- xar->toc_remaining = toc_compressed_size;- toc_uncompressed_size = archive_be64dec(b+16);- toc_chksum_alg = archive_be32dec(b+24);- __archive_read_consume(a, HEADER_SIZE);- xar->offset += HEADER_SIZE;- xar->toc_total = 0;-- /*- * Read TOC(Table of Contents).- */- /* Initialize reading contents. */- r = move_reading_point(a, HEADER_SIZE);- if (r != ARCHIVE_OK)- return (r);- r = rd_contents_init(a, GZIP, toc_chksum_alg, CKSUM_NONE);- if (r != ARCHIVE_OK)- return (r);--#ifdef HAVE_LIBXML_XMLREADER_H- r = xml2_read_toc(a);-#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)- r = expat_read_toc(a);-#endif- if (r != ARCHIVE_OK)- return (r);-- /* Set 'The HEAP' base. */- xar->h_base = xar->offset;- if (xar->toc_total != toc_uncompressed_size) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "TOC uncompressed size error");- return (ARCHIVE_FATAL);- }-- /*- * Checksum TOC- */- if (toc_chksum_alg != CKSUM_NONE) {- r = move_reading_point(a, xar->toc_chksum_offset);- if (r != ARCHIVE_OK)- return (r);- b = __archive_read_ahead(a,- (size_t)xar->toc_chksum_size, &bytes);- if (bytes < 0)- return ((int)bytes);- if ((uint64_t)bytes < xar->toc_chksum_size) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated archive file");- return (ARCHIVE_FATAL);- }- r = checksum_final(a, b,- (size_t)xar->toc_chksum_size, NULL, 0);- __archive_read_consume(a, xar->toc_chksum_size);- xar->offset += xar->toc_chksum_size;- if (r != ARCHIVE_OK)-#ifndef DONT_FAIL_ON_CRC_ERROR- return (ARCHIVE_FATAL);-#endif- }-- /*- * Connect hardlinked files.- */- for (file = xar->hdlink_orgs; file != NULL; file = file->hdnext) {- struct hdlink **hdlink;-- for (hdlink = &(xar->hdlink_list); *hdlink != NULL;- hdlink = &((*hdlink)->next)) {- if ((*hdlink)->id == file->id) {- struct hdlink *hltmp;- struct xar_file *f2;- int nlink = (*hdlink)->cnt + 1;-- file->nlink = nlink;- for (f2 = (*hdlink)->files; f2 != NULL;- f2 = f2->hdnext) {- f2->nlink = nlink;- archive_string_copy(- &(f2->hardlink), &(file->pathname));- }- /* Remove resolved files from hdlist_list. */- hltmp = *hdlink;- *hdlink = hltmp->next;- free(hltmp);- break;- }- }- }- a->archive.archive_format = ARCHIVE_FORMAT_XAR;- a->archive.archive_format_name = "xar";-- return (ARCHIVE_OK);-}--static int-xar_read_header(struct archive_read *a, struct archive_entry *entry)-{- struct xar *xar;- struct xar_file *file;- struct xattr *xattr;- int r;-- xar = (struct xar *)(a->format->data);- r = ARCHIVE_OK;-- if (xar->offset == 0) {- /* Create a character conversion object. */- if (xar->sconv == NULL) {- xar->sconv = archive_string_conversion_from_charset(- &(a->archive), "UTF-8", 1);- if (xar->sconv == NULL)- return (ARCHIVE_FATAL);- }-- /* Read TOC. */- r = read_toc(a);- if (r != ARCHIVE_OK)- return (r);- }-- for (;;) {- file = xar->file = heap_get_entry(&(xar->file_queue));- if (file == NULL) {- xar->end_of_file = 1;- return (ARCHIVE_EOF);- }- if ((file->mode & AE_IFMT) != AE_IFDIR)- break;- if (file->has != (HAS_PATHNAME | HAS_TYPE))- break;- /*- * If a file type is a directory and it does not have- * any metadata, do not export.- */- file_free(file);- }- if (file->has & HAS_ATIME) {- archive_entry_set_atime(entry, file->atime, 0);- }- if (file->has & HAS_CTIME) {- archive_entry_set_ctime(entry, file->ctime, 0);- }- if (file->has & HAS_MTIME) {- archive_entry_set_mtime(entry, file->mtime, 0);- }- archive_entry_set_gid(entry, file->gid);- if (file->gname.length > 0 &&- archive_entry_copy_gname_l(entry, file->gname.s,- archive_strlen(&(file->gname)), xar->sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Gname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Gname cannot be converted from %s to current locale.",- archive_string_conversion_charset_name(xar->sconv));- r = ARCHIVE_WARN;- }- archive_entry_set_uid(entry, file->uid);- if (file->uname.length > 0 &&- archive_entry_copy_uname_l(entry, file->uname.s,- archive_strlen(&(file->uname)), xar->sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Uname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Uname cannot be converted from %s to current locale.",- archive_string_conversion_charset_name(xar->sconv));- r = ARCHIVE_WARN;- }- archive_entry_set_mode(entry, file->mode);- if (archive_entry_copy_pathname_l(entry, file->pathname.s,- archive_strlen(&(file->pathname)), xar->sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname cannot be converted from %s to current locale.",- archive_string_conversion_charset_name(xar->sconv));- r = ARCHIVE_WARN;- }--- if (file->symlink.length > 0 &&- archive_entry_copy_symlink_l(entry, file->symlink.s,- archive_strlen(&(file->symlink)), xar->sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Linkname cannot be converted from %s to current locale.",- archive_string_conversion_charset_name(xar->sconv));- r = ARCHIVE_WARN;- }- /* Set proper nlink. */- if ((file->mode & AE_IFMT) == AE_IFDIR)- archive_entry_set_nlink(entry, file->subdirs + 2);- else- archive_entry_set_nlink(entry, file->nlink);- archive_entry_set_size(entry, file->size);- if (archive_strlen(&(file->hardlink)) > 0)- archive_entry_set_hardlink(entry, file->hardlink.s);- archive_entry_set_ino64(entry, file->ino64);- if (file->has & HAS_DEV)- archive_entry_set_dev(entry, file->dev);- if (file->has & HAS_DEVMAJOR)- archive_entry_set_devmajor(entry, file->devmajor);- if (file->has & HAS_DEVMINOR)- archive_entry_set_devminor(entry, file->devminor);- if (archive_strlen(&(file->fflags_text)) > 0)- archive_entry_copy_fflags_text(entry, file->fflags_text.s);-- xar->entry_init = 1;- xar->entry_total = 0;- xar->entry_remaining = file->length;- xar->entry_size = file->size;- xar->entry_encoding = file->encoding;- xar->entry_a_sum = file->a_sum;- xar->entry_e_sum = file->e_sum;- /*- * Read extended attributes.- */- xattr = file->xattr_list;- while (xattr != NULL) {- const void *d;- size_t outbytes = 0;- size_t used = 0;-- r = move_reading_point(a, xattr->offset);- if (r != ARCHIVE_OK)- break;- r = rd_contents_init(a, xattr->encoding,- xattr->a_sum.alg, xattr->e_sum.alg);- if (r != ARCHIVE_OK)- break;- d = NULL;- r = rd_contents(a, &d, &outbytes, &used, xattr->length);- if (r != ARCHIVE_OK)- break;- if (outbytes != xattr->size) {- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,- "Decompressed size error");- r = ARCHIVE_FATAL;- break;- }- r = checksum_final(a,- xattr->a_sum.val, xattr->a_sum.len,- xattr->e_sum.val, xattr->e_sum.len);- if (r != ARCHIVE_OK) {-#ifndef DONT_FAIL_ON_CRC_ERROR- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,- "Xattr checksum error");- r = ARCHIVE_WARN;- break;-#endif- }- if (xattr->name.s == NULL) {- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,- "Xattr name error");- r = ARCHIVE_WARN;- break;- }- archive_entry_xattr_add_entry(entry,- xattr->name.s, d, outbytes);- xattr = xattr->next;- }- if (r != ARCHIVE_OK) {- file_free(file);- return (r);- }-- if (xar->entry_remaining > 0)- /* Move reading point to the beginning of current- * file contents. */- r = move_reading_point(a, file->offset);- else- r = ARCHIVE_OK;-- file_free(file);- return (r);-}--static int-xar_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- struct xar *xar;- size_t used = 0;- int r;-- xar = (struct xar *)(a->format->data);-- if (xar->entry_unconsumed) {- __archive_read_consume(a, xar->entry_unconsumed);- xar->entry_unconsumed = 0;- }-- if (xar->end_of_file || xar->entry_remaining <= 0) {- r = ARCHIVE_EOF;- goto abort_read_data;- }-- if (xar->entry_init) {- r = rd_contents_init(a, xar->entry_encoding,- xar->entry_a_sum.alg, xar->entry_e_sum.alg);- if (r != ARCHIVE_OK) {- xar->entry_remaining = 0;- return (r);- }- xar->entry_init = 0;- }-- *buff = NULL;- r = rd_contents(a, buff, size, &used, xar->entry_remaining);- if (r != ARCHIVE_OK)- goto abort_read_data;-- *offset = xar->entry_total;- xar->entry_total += *size;- xar->total += *size;- xar->offset += used;- xar->entry_remaining -= used;- xar->entry_unconsumed = used;-- if (xar->entry_remaining == 0) {- if (xar->entry_total != xar->entry_size) {- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,- "Decompressed size error");- r = ARCHIVE_FATAL;- goto abort_read_data;- }- r = checksum_final(a,- xar->entry_a_sum.val, xar->entry_a_sum.len,- xar->entry_e_sum.val, xar->entry_e_sum.len);- if (r != ARCHIVE_OK)- goto abort_read_data;- }-- return (ARCHIVE_OK);-abort_read_data:- *buff = NULL;- *size = 0;- *offset = xar->total;- return (r);-}--static int-xar_read_data_skip(struct archive_read *a)-{- struct xar *xar;- int64_t bytes_skipped;-- xar = (struct xar *)(a->format->data);- if (xar->end_of_file)- return (ARCHIVE_EOF);- bytes_skipped = __archive_read_consume(a, xar->entry_remaining +- xar->entry_unconsumed);- if (bytes_skipped < 0)- return (ARCHIVE_FATAL);- xar->offset += bytes_skipped;- xar->entry_unconsumed = 0;- return (ARCHIVE_OK);-}--static int-xar_cleanup(struct archive_read *a)-{- struct xar *xar;- struct hdlink *hdlink;- int i;- int r;-- xar = (struct xar *)(a->format->data);- checksum_cleanup(a);- r = decompression_cleanup(a);- hdlink = xar->hdlink_list;- while (hdlink != NULL) {- struct hdlink *next = hdlink->next;-- free(hdlink);- hdlink = next;- }- for (i = 0; i < xar->file_queue.used; i++)- file_free(xar->file_queue.files[i]);- free(xar->file_queue.files);- while (xar->unknowntags != NULL) {- struct unknown_tag *tag;-- tag = xar->unknowntags;- xar->unknowntags = tag->next;- archive_string_free(&(tag->name));- free(tag);- }- free(xar->outbuff);- free(xar);- a->format->data = NULL;- return (r);-}--static int-move_reading_point(struct archive_read *a, uint64_t offset)-{- struct xar *xar;-- xar = (struct xar *)(a->format->data);- if (xar->offset - xar->h_base != offset) {- /* Seek forward to the start of file contents. */- int64_t step;-- step = offset - (xar->offset - xar->h_base);- if (step > 0) {- step = __archive_read_consume(a, step);- if (step < 0)- return ((int)step);- xar->offset += step;- } else {- int64_t pos = __archive_read_seek(a, xar->h_base + offset, SEEK_SET);- if (pos == ARCHIVE_FAILED) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Cannot seek.");- return (ARCHIVE_FAILED);- }- xar->offset = pos;- }- }- return (ARCHIVE_OK);-}--static int-rd_contents_init(struct archive_read *a, enum enctype encoding,- int a_sum_alg, int e_sum_alg)-{- int r;-- /* Init decompress library. */- if ((r = decompression_init(a, encoding)) != ARCHIVE_OK)- return (r);- /* Init checksum library. */- checksum_init(a, a_sum_alg, e_sum_alg);- return (ARCHIVE_OK);-}--static int-rd_contents(struct archive_read *a, const void **buff, size_t *size,- size_t *used, uint64_t remaining)-{- const unsigned char *b;- ssize_t bytes;-- /* Get whatever bytes are immediately available. */- b = __archive_read_ahead(a, 1, &bytes);- if (bytes < 0)- return ((int)bytes);- if (bytes == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Truncated archive file");- return (ARCHIVE_FATAL);- }- if ((uint64_t)bytes > remaining)- bytes = (ssize_t)remaining;-- /*- * Decompress contents of file.- */- *used = bytes;- if (decompress(a, buff, size, b, used) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /*- * Update checksum of a compressed data and a extracted data.- */- checksum_update(a, b, *used, *buff, *size);-- return (ARCHIVE_OK);-}--/*- * Note that this implementation does not (and should not!) obey- * locale settings; you cannot simply substitute strtol here, since- * it does obey locale.- */--static uint64_t-atol10(const char *p, size_t char_cnt)-{- uint64_t l;- int digit;-- if (char_cnt == 0)- return (0);-- l = 0;- digit = *p - '0';- while (digit >= 0 && digit < 10 && char_cnt-- > 0) {- l = (l * 10) + digit;- digit = *++p - '0';- }- return (l);-}--static int64_t-atol8(const char *p, size_t char_cnt)-{- int64_t l;- int digit;-- if (char_cnt == 0)- return (0);-- l = 0;- while (char_cnt-- > 0) {- if (*p >= '0' && *p <= '7')- digit = *p - '0';- else- break;- p++;- l <<= 3;- l |= digit;- }- return (l);-}--static size_t-atohex(unsigned char *b, size_t bsize, const char *p, size_t psize)-{- size_t fbsize = bsize;-- while (bsize && psize > 1) {- unsigned char x;-- if (p[0] >= 'a' && p[0] <= 'z')- x = (p[0] - 'a' + 0x0a) << 4;- else if (p[0] >= 'A' && p[0] <= 'Z')- x = (p[0] - 'A' + 0x0a) << 4;- else if (p[0] >= '0' && p[0] <= '9')- x = (p[0] - '0') << 4;- else- return (-1);- if (p[1] >= 'a' && p[1] <= 'z')- x |= p[1] - 'a' + 0x0a;- else if (p[1] >= 'A' && p[1] <= 'Z')- x |= p[1] - 'A' + 0x0a;- else if (p[1] >= '0' && p[1] <= '9')- x |= p[1] - '0';- else- return (-1);-- *b++ = x;- bsize--;- p += 2;- psize -= 2;- }- return (fbsize - bsize);-}--static time_t-time_from_tm(struct tm *t)-{-#if HAVE__MKGMTIME- return _mkgmtime(t);-#elif HAVE_TIMEGM- /* Use platform timegm() if available. */- return (timegm(t));-#else- /* Else use direct calculation using POSIX assumptions. */- /* First, fix up tm_yday based on the year/month/day. */- mktime(t);- /* Then we can compute timegm() from first principles. */- return (t->tm_sec- + t->tm_min * 60- + t->tm_hour * 3600- + t->tm_yday * 86400- + (t->tm_year - 70) * 31536000- + ((t->tm_year - 69) / 4) * 86400- - ((t->tm_year - 1) / 100) * 86400- + ((t->tm_year + 299) / 400) * 86400);-#endif-}--static time_t-parse_time(const char *p, size_t n)-{- struct tm tm;- time_t t = 0;- int64_t data;-- memset(&tm, 0, sizeof(tm));- if (n != 20)- return (t);- data = atol10(p, 4);- if (data < 1900)- return (t);- tm.tm_year = (int)data - 1900;- p += 4;- if (*p++ != '-')- return (t);- data = atol10(p, 2);- if (data < 1 || data > 12)- return (t);- tm.tm_mon = (int)data -1;- p += 2;- if (*p++ != '-')- return (t);- data = atol10(p, 2);- if (data < 1 || data > 31)- return (t);- tm.tm_mday = (int)data;- p += 2;- if (*p++ != 'T')- return (t);- data = atol10(p, 2);- if (data < 0 || data > 23)- return (t);- tm.tm_hour = (int)data;- p += 2;- if (*p++ != ':')- return (t);- data = atol10(p, 2);- if (data < 0 || data > 59)- return (t);- tm.tm_min = (int)data;- p += 2;- if (*p++ != ':')- return (t);- data = atol10(p, 2);- if (data < 0 || data > 60)- return (t);- tm.tm_sec = (int)data;-#if 0- p += 2;- if (*p != 'Z')- return (t);-#endif-- t = time_from_tm(&tm);-- return (t);-}--static int-heap_add_entry(struct archive_read *a,- struct heap_queue *heap, struct xar_file *file)-{- uint64_t file_id, parent_id;- int hole, parent;-- /* Expand our pending files list as necessary. */- if (heap->used >= heap->allocated) {- struct xar_file **new_pending_files;- int new_size;-- if (heap->allocated < 1024)- new_size = 1024;- else- new_size = heap->allocated * 2;- /* Overflow might keep us from growing the list. */- if (new_size <= heap->allocated) {- archive_set_error(&a->archive,- ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- new_pending_files = (struct xar_file **)- malloc(new_size * sizeof(new_pending_files[0]));- if (new_pending_files == NULL) {- archive_set_error(&a->archive,- ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- if (heap->allocated) {- memcpy(new_pending_files, heap->files,- heap->allocated * sizeof(new_pending_files[0]));- free(heap->files);- }- heap->files = new_pending_files;- heap->allocated = new_size;- }-- file_id = file->id;-- /*- * Start with hole at end, walk it up tree to find insertion point.- */- hole = heap->used++;- while (hole > 0) {- parent = (hole - 1)/2;- parent_id = heap->files[parent]->id;- if (file_id >= parent_id) {- heap->files[hole] = file;- return (ARCHIVE_OK);- }- /* Move parent into hole <==> move hole up tree. */- heap->files[hole] = heap->files[parent];- hole = parent;- }- heap->files[0] = file;-- return (ARCHIVE_OK);-}--static struct xar_file *-heap_get_entry(struct heap_queue *heap)-{- uint64_t a_id, b_id, c_id;- int a, b, c;- struct xar_file *r, *tmp;-- if (heap->used < 1)- return (NULL);-- /*- * The first file in the list is the earliest; we'll return this.- */- r = heap->files[0];-- /*- * Move the last item in the heap to the root of the tree- */- heap->files[0] = heap->files[--(heap->used)];-- /*- * Rebalance the heap.- */- a = 0; /* Starting element and its heap key */- a_id = heap->files[a]->id;- for (;;) {- b = a + a + 1; /* First child */- if (b >= heap->used)- return (r);- b_id = heap->files[b]->id;- c = b + 1; /* Use second child if it is smaller. */- if (c < heap->used) {- c_id = heap->files[c]->id;- if (c_id < b_id) {- b = c;- b_id = c_id;- }- }- if (a_id <= b_id)- return (r);- tmp = heap->files[a];- heap->files[a] = heap->files[b];- heap->files[b] = tmp;- a = b;- }-}--static int-add_link(struct archive_read *a, struct xar *xar, struct xar_file *file)-{- struct hdlink *hdlink;-- for (hdlink = xar->hdlink_list; hdlink != NULL; hdlink = hdlink->next) {- if (hdlink->id == file->link) {- file->hdnext = hdlink->files;- hdlink->cnt++;- hdlink->files = file;- return (ARCHIVE_OK);- }- }- hdlink = malloc(sizeof(*hdlink));- if (hdlink == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- file->hdnext = NULL;- hdlink->id = file->link;- hdlink->cnt = 1;- hdlink->files = file;- hdlink->next = xar->hdlink_list;- xar->hdlink_list = hdlink;- return (ARCHIVE_OK);-}--static void-_checksum_init(struct chksumwork *sumwrk, int sum_alg)-{- sumwrk->alg = sum_alg;- switch (sum_alg) {- case CKSUM_NONE:- break;- case CKSUM_SHA1:- archive_sha1_init(&(sumwrk->sha1ctx));- break;- case CKSUM_MD5:- archive_md5_init(&(sumwrk->md5ctx));- break;- }-}--static void-_checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)-{-- switch (sumwrk->alg) {- case CKSUM_NONE:- break;- case CKSUM_SHA1:- archive_sha1_update(&(sumwrk->sha1ctx), buff, size);- break;- case CKSUM_MD5:- archive_md5_update(&(sumwrk->md5ctx), buff, size);- break;- }-}--static int-_checksum_final(struct chksumwork *sumwrk, const void *val, size_t len)-{- unsigned char sum[MAX_SUM_SIZE];- int r = ARCHIVE_OK;-- switch (sumwrk->alg) {- case CKSUM_NONE:- break;- case CKSUM_SHA1:- archive_sha1_final(&(sumwrk->sha1ctx), sum);- if (len != SHA1_SIZE ||- memcmp(val, sum, SHA1_SIZE) != 0)- r = ARCHIVE_FAILED;- break;- case CKSUM_MD5:- archive_md5_final(&(sumwrk->md5ctx), sum);- if (len != MD5_SIZE ||- memcmp(val, sum, MD5_SIZE) != 0)- r = ARCHIVE_FAILED;- break;- }- return (r);-}--static void-checksum_init(struct archive_read *a, int a_sum_alg, int e_sum_alg)-{- struct xar *xar;-- xar = (struct xar *)(a->format->data);- _checksum_init(&(xar->a_sumwrk), a_sum_alg);- _checksum_init(&(xar->e_sumwrk), e_sum_alg);-}--static void-checksum_update(struct archive_read *a, const void *abuff, size_t asize,- const void *ebuff, size_t esize)-{- struct xar *xar;-- xar = (struct xar *)(a->format->data);- _checksum_update(&(xar->a_sumwrk), abuff, asize);- _checksum_update(&(xar->e_sumwrk), ebuff, esize);-}--static int-checksum_final(struct archive_read *a, const void *a_sum_val,- size_t a_sum_len, const void *e_sum_val, size_t e_sum_len)-{- struct xar *xar;- int r;-- xar = (struct xar *)(a->format->data);- r = _checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len);- if (r == ARCHIVE_OK)- r = _checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len);- if (r != ARCHIVE_OK)- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,- "Sumcheck error");- return (r);-}--static int-decompression_init(struct archive_read *a, enum enctype encoding)-{- struct xar *xar;- const char *detail;- int r;-- xar = (struct xar *)(a->format->data);- xar->rd_encoding = encoding;- switch (encoding) {- case NONE:- break;- case GZIP:- if (xar->stream_valid)- r = inflateReset(&(xar->stream));- else- r = inflateInit(&(xar->stream));- if (r != Z_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Couldn't initialize zlib stream.");- return (ARCHIVE_FATAL);- }- xar->stream_valid = 1;- xar->stream.total_in = 0;- xar->stream.total_out = 0;- break;-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- case BZIP2:- if (xar->bzstream_valid) {- BZ2_bzDecompressEnd(&(xar->bzstream));- xar->bzstream_valid = 0;- }- r = BZ2_bzDecompressInit(&(xar->bzstream), 0, 0);- if (r == BZ_MEM_ERROR)- r = BZ2_bzDecompressInit(&(xar->bzstream), 0, 1);- if (r != BZ_OK) {- int err = ARCHIVE_ERRNO_MISC;- detail = NULL;- switch (r) {- case BZ_PARAM_ERROR:- detail = "invalid setup parameter";- break;- case BZ_MEM_ERROR:- err = ENOMEM;- detail = "out of memory";- break;- case BZ_CONFIG_ERROR:- detail = "mis-compiled library";- break;- }- archive_set_error(&a->archive, err,- "Internal error initializing decompressor: %s",- detail == NULL ? "??" : detail);- xar->bzstream_valid = 0;- return (ARCHIVE_FATAL);- }- xar->bzstream_valid = 1;- xar->bzstream.total_in_lo32 = 0;- xar->bzstream.total_in_hi32 = 0;- xar->bzstream.total_out_lo32 = 0;- xar->bzstream.total_out_hi32 = 0;- break;-#endif-#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)-#if LZMA_VERSION_MAJOR >= 5-/* Effectively disable the limiter. */-#define LZMA_MEMLIMIT UINT64_MAX-#else-/* NOTE: This needs to check memory size which running system has. */-#define LZMA_MEMLIMIT (1U << 30)-#endif- case XZ:- case LZMA:- if (xar->lzstream_valid) {- lzma_end(&(xar->lzstream));- xar->lzstream_valid = 0;- }- if (xar->entry_encoding == XZ)- r = lzma_stream_decoder(&(xar->lzstream),- LZMA_MEMLIMIT,/* memlimit */- LZMA_CONCATENATED);- else- r = lzma_alone_decoder(&(xar->lzstream),- LZMA_MEMLIMIT);/* memlimit */- if (r != LZMA_OK) {- switch (r) {- case LZMA_MEM_ERROR:- archive_set_error(&a->archive,- ENOMEM,- "Internal error initializing "- "compression library: "- "Cannot allocate memory");- break;- case LZMA_OPTIONS_ERROR:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Internal error initializing "- "compression library: "- "Invalid or unsupported options");- break;- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Internal error initializing "- "lzma library");- break;- }- return (ARCHIVE_FATAL);- }- xar->lzstream_valid = 1;- xar->lzstream.total_in = 0;- xar->lzstream.total_out = 0;- break;-#endif- /*- * Unsupported compression.- */- default:-#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)- case BZIP2:-#endif-#if !defined(HAVE_LZMA_H) || !defined(HAVE_LIBLZMA)- case LZMA:- case XZ:-#endif- switch (xar->entry_encoding) {- case BZIP2: detail = "bzip2"; break;- case LZMA: detail = "lzma"; break;- case XZ: detail = "xz"; break;- default: detail = "??"; break;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s compression not supported on this platform",- detail);- return (ARCHIVE_FAILED);- }- return (ARCHIVE_OK);-}--static int-decompress(struct archive_read *a, const void **buff, size_t *outbytes,- const void *b, size_t *used)-{- struct xar *xar;- void *outbuff;- size_t avail_in, avail_out;- int r;-- xar = (struct xar *)(a->format->data);- avail_in = *used;- outbuff = (void *)(uintptr_t)*buff;- if (outbuff == NULL) {- if (xar->outbuff == NULL) {- xar->outbuff = malloc(OUTBUFF_SIZE);- if (xar->outbuff == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Couldn't allocate memory for out buffer");- return (ARCHIVE_FATAL);- }- }- outbuff = xar->outbuff;- *buff = outbuff;- avail_out = OUTBUFF_SIZE;- } else- avail_out = *outbytes;- switch (xar->rd_encoding) {- case GZIP:- xar->stream.next_in = (Bytef *)(uintptr_t)b;- xar->stream.avail_in = avail_in;- xar->stream.next_out = (unsigned char *)outbuff;- xar->stream.avail_out = avail_out;- r = inflate(&(xar->stream), 0);- switch (r) {- case Z_OK: /* Decompressor made some progress.*/- case Z_STREAM_END: /* Found end of stream. */- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "File decompression failed (%d)", r);- return (ARCHIVE_FATAL);- }- *used = avail_in - xar->stream.avail_in;- *outbytes = avail_out - xar->stream.avail_out;- break;-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- case BZIP2:- xar->bzstream.next_in = (char *)(uintptr_t)b;- xar->bzstream.avail_in = avail_in;- xar->bzstream.next_out = (char *)outbuff;- xar->bzstream.avail_out = avail_out;- r = BZ2_bzDecompress(&(xar->bzstream));- switch (r) {- case BZ_STREAM_END: /* Found end of stream. */- switch (BZ2_bzDecompressEnd(&(xar->bzstream))) {- case BZ_OK:- break;- default:- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Failed to clean up decompressor");- return (ARCHIVE_FATAL);- }- xar->bzstream_valid = 0;- /* FALLTHROUGH */- case BZ_OK: /* Decompressor made some progress. */- break;- default:- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "bzip decompression failed");- return (ARCHIVE_FATAL);- }- *used = avail_in - xar->bzstream.avail_in;- *outbytes = avail_out - xar->bzstream.avail_out;- break;-#endif-#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)- case LZMA:- case XZ:- xar->lzstream.next_in = b;- xar->lzstream.avail_in = avail_in;- xar->lzstream.next_out = (unsigned char *)outbuff;- xar->lzstream.avail_out = avail_out;- r = lzma_code(&(xar->lzstream), LZMA_RUN);- switch (r) {- case LZMA_STREAM_END: /* Found end of stream. */- lzma_end(&(xar->lzstream));- xar->lzstream_valid = 0;- /* FALLTHROUGH */- case LZMA_OK: /* Decompressor made some progress. */- break;- default:- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "%s decompression failed(%d)",- (xar->entry_encoding == XZ)?"xz":"lzma",- r);- return (ARCHIVE_FATAL);- }- *used = avail_in - xar->lzstream.avail_in;- *outbytes = avail_out - xar->lzstream.avail_out;- break;-#endif-#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)- case BZIP2:-#endif-#if !defined(HAVE_LZMA_H) || !defined(HAVE_LIBLZMA)- case LZMA:- case XZ:-#endif- case NONE:- default:- if (outbuff == xar->outbuff) {- *buff = b;- *used = avail_in;- *outbytes = avail_in;- } else {- if (avail_out > avail_in)- avail_out = avail_in;- memcpy(outbuff, b, avail_out);- *used = avail_out;- *outbytes = avail_out;- }- break;- }- return (ARCHIVE_OK);-}--static int-decompression_cleanup(struct archive_read *a)-{- struct xar *xar;- int r;-- xar = (struct xar *)(a->format->data);- r = ARCHIVE_OK;- if (xar->stream_valid) {- if (inflateEnd(&(xar->stream)) != Z_OK) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to clean up zlib decompressor");- r = ARCHIVE_FATAL;- }- }-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- if (xar->bzstream_valid) {- if (BZ2_bzDecompressEnd(&(xar->bzstream)) != BZ_OK) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to clean up bzip2 decompressor");- r = ARCHIVE_FATAL;- }- }-#endif-#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)- if (xar->lzstream_valid)- lzma_end(&(xar->lzstream));-#elif defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)- if (xar->lzstream_valid) {- if (lzmadec_end(&(xar->lzstream)) != LZMADEC_OK) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to clean up lzmadec decompressor");- r = ARCHIVE_FATAL;- }- }-#endif- return (r);-}--static void-checksum_cleanup(struct archive_read *a) {- struct xar *xar;-- xar = (struct xar *)(a->format->data);-- _checksum_final(&(xar->a_sumwrk), NULL, 0);- _checksum_final(&(xar->e_sumwrk), NULL, 0);-}--static void-xmlattr_cleanup(struct xmlattr_list *list)-{- struct xmlattr *attr, *next;-- attr = list->first;- while (attr != NULL) {- next = attr->next;- free(attr->name);- free(attr->value);- free(attr);- attr = next;- }- list->first = NULL;- list->last = &(list->first);-}--static int-file_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)-{- struct xar_file *file;- struct xmlattr *attr;-- file = calloc(1, sizeof(*file));- if (file == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- file->parent = xar->file;- file->mode = 0777 | AE_IFREG;- file->atime = 0;- file->mtime = 0;- xar->file = file;- xar->xattr = NULL;- for (attr = list->first; attr != NULL; attr = attr->next) {- if (strcmp(attr->name, "id") == 0)- file->id = atol10(attr->value, strlen(attr->value));- }- file->nlink = 1;- if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- return (ARCHIVE_OK);-}--static void-file_free(struct xar_file *file)-{- struct xattr *xattr;-- archive_string_free(&(file->pathname));- archive_string_free(&(file->symlink));- archive_string_free(&(file->uname));- archive_string_free(&(file->gname));- archive_string_free(&(file->hardlink));- xattr = file->xattr_list;- while (xattr != NULL) {- struct xattr *next;-- next = xattr->next;- xattr_free(xattr);- xattr = next;- }-- free(file);-}--static int-xattr_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)-{- struct xattr *xattr, **nx;- struct xmlattr *attr;-- xattr = calloc(1, sizeof(*xattr));- if (xattr == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- xar->xattr = xattr;- for (attr = list->first; attr != NULL; attr = attr->next) {- if (strcmp(attr->name, "id") == 0)- xattr->id = atol10(attr->value, strlen(attr->value));- }- /* Chain to xattr list. */- for (nx = &(xar->file->xattr_list);- *nx != NULL; nx = &((*nx)->next)) {- if (xattr->id < (*nx)->id)- break;- }- xattr->next = *nx;- *nx = xattr;-- return (ARCHIVE_OK);-}--static void-xattr_free(struct xattr *xattr)-{- archive_string_free(&(xattr->name));- free(xattr);-}--static int-getencoding(struct xmlattr_list *list)-{- struct xmlattr *attr;- enum enctype encoding = NONE;-- for (attr = list->first; attr != NULL; attr = attr->next) {- if (strcmp(attr->name, "style") == 0) {- if (strcmp(attr->value, "application/octet-stream") == 0)- encoding = NONE;- else if (strcmp(attr->value, "application/x-gzip") == 0)- encoding = GZIP;- else if (strcmp(attr->value, "application/x-bzip2") == 0)- encoding = BZIP2;- else if (strcmp(attr->value, "application/x-lzma") == 0)- encoding = LZMA;- else if (strcmp(attr->value, "application/x-xz") == 0)- encoding = XZ;- }- }- return (encoding);-}--static int-getsumalgorithm(struct xmlattr_list *list)-{- struct xmlattr *attr;- int alg = CKSUM_NONE;-- for (attr = list->first; attr != NULL; attr = attr->next) {- if (strcmp(attr->name, "style") == 0) {- const char *v = attr->value;- if ((v[0] == 'S' || v[0] == 's') &&- (v[1] == 'H' || v[1] == 'h') &&- (v[2] == 'A' || v[2] == 'a') &&- v[3] == '1' && v[4] == '\0')- alg = CKSUM_SHA1;- if ((v[0] == 'M' || v[0] == 'm') &&- (v[1] == 'D' || v[1] == 'd') &&- v[2] == '5' && v[3] == '\0')- alg = CKSUM_MD5;- }- }- return (alg);-}--static int-unknowntag_start(struct archive_read *a, struct xar *xar, const char *name)-{- struct unknown_tag *tag;-- tag = malloc(sizeof(*tag));- if (tag == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- tag->next = xar->unknowntags;- archive_string_init(&(tag->name));- archive_strcpy(&(tag->name), name);- if (xar->unknowntags == NULL) {-#if DEBUG- fprintf(stderr, "UNKNOWNTAG_START:%s\n", name);-#endif- xar->xmlsts_unknown = xar->xmlsts;- xar->xmlsts = UNKNOWN;- }- xar->unknowntags = tag;- return (ARCHIVE_OK);-}--static void-unknowntag_end(struct xar *xar, const char *name)-{- struct unknown_tag *tag;-- tag = xar->unknowntags;- if (tag == NULL || name == NULL)- return;- if (strcmp(tag->name.s, name) == 0) {- xar->unknowntags = tag->next;- archive_string_free(&(tag->name));- free(tag);- if (xar->unknowntags == NULL) {-#if DEBUG- fprintf(stderr, "UNKNOWNTAG_END:%s\n", name);-#endif- xar->xmlsts = xar->xmlsts_unknown;- }- }-}--static int-xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)-{- struct xar *xar;- struct xmlattr *attr;-- xar = (struct xar *)(a->format->data);--#if DEBUG- fprintf(stderr, "xml_sta:[%s]\n", name);- for (attr = list->first; attr != NULL; attr = attr->next)- fprintf(stderr, " attr:\"%s\"=\"%s\"\n",- attr->name, attr->value);-#endif- xar->base64text = 0;- switch (xar->xmlsts) {- case INIT:- if (strcmp(name, "xar") == 0)- xar->xmlsts = XAR;- else- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case XAR:- if (strcmp(name, "toc") == 0)- xar->xmlsts = TOC;- else- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case TOC:- if (strcmp(name, "creation-time") == 0)- xar->xmlsts = TOC_CREATION_TIME;- else if (strcmp(name, "checksum") == 0)- xar->xmlsts = TOC_CHECKSUM;- else if (strcmp(name, "file") == 0) {- if (file_new(a, xar, list) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- xar->xmlsts = TOC_FILE;- }- else- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case TOC_CHECKSUM:- if (strcmp(name, "offset") == 0)- xar->xmlsts = TOC_CHECKSUM_OFFSET;- else if (strcmp(name, "size") == 0)- xar->xmlsts = TOC_CHECKSUM_SIZE;- else- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case TOC_FILE:- if (strcmp(name, "file") == 0) {- if (file_new(a, xar, list) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }- else if (strcmp(name, "data") == 0)- xar->xmlsts = FILE_DATA;- else if (strcmp(name, "ea") == 0) {- if (xattr_new(a, xar, list) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- xar->xmlsts = FILE_EA;- }- else if (strcmp(name, "ctime") == 0)- xar->xmlsts = FILE_CTIME;- else if (strcmp(name, "mtime") == 0)- xar->xmlsts = FILE_MTIME;- else if (strcmp(name, "atime") == 0)- xar->xmlsts = FILE_ATIME;- else if (strcmp(name, "group") == 0)- xar->xmlsts = FILE_GROUP;- else if (strcmp(name, "gid") == 0)- xar->xmlsts = FILE_GID;- else if (strcmp(name, "user") == 0)- xar->xmlsts = FILE_USER;- else if (strcmp(name, "uid") == 0)- xar->xmlsts = FILE_UID;- else if (strcmp(name, "mode") == 0)- xar->xmlsts = FILE_MODE;- else if (strcmp(name, "device") == 0)- xar->xmlsts = FILE_DEVICE;- else if (strcmp(name, "deviceno") == 0)- xar->xmlsts = FILE_DEVICENO;- else if (strcmp(name, "inode") == 0)- xar->xmlsts = FILE_INODE;- else if (strcmp(name, "link") == 0)- xar->xmlsts = FILE_LINK;- else if (strcmp(name, "type") == 0) {- xar->xmlsts = FILE_TYPE;- for (attr = list->first; attr != NULL;- attr = attr->next) {- if (strcmp(attr->name, "link") != 0)- continue;- if (strcmp(attr->value, "original") == 0) {- xar->file->hdnext = xar->hdlink_orgs;- xar->hdlink_orgs = xar->file;- } else {- xar->file->link = (unsigned)atol10(attr->value,- strlen(attr->value));- if (xar->file->link > 0)- if (add_link(a, xar, xar->file) != ARCHIVE_OK) {- return (ARCHIVE_FATAL);- };- }- }- }- else if (strcmp(name, "name") == 0) {- xar->xmlsts = FILE_NAME;- for (attr = list->first; attr != NULL;- attr = attr->next) {- if (strcmp(attr->name, "enctype") == 0 &&- strcmp(attr->value, "base64") == 0)- xar->base64text = 1;- }- }- else if (strcmp(name, "acl") == 0)- xar->xmlsts = FILE_ACL;- else if (strcmp(name, "flags") == 0)- xar->xmlsts = FILE_FLAGS;- else if (strcmp(name, "ext2") == 0)- xar->xmlsts = FILE_EXT2;- else- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case FILE_DATA:- if (strcmp(name, "length") == 0)- xar->xmlsts = FILE_DATA_LENGTH;- else if (strcmp(name, "offset") == 0)- xar->xmlsts = FILE_DATA_OFFSET;- else if (strcmp(name, "size") == 0)- xar->xmlsts = FILE_DATA_SIZE;- else if (strcmp(name, "encoding") == 0) {- xar->xmlsts = FILE_DATA_ENCODING;- xar->file->encoding = getencoding(list);- }- else if (strcmp(name, "archived-checksum") == 0) {- xar->xmlsts = FILE_DATA_A_CHECKSUM;- xar->file->a_sum.alg = getsumalgorithm(list);- }- else if (strcmp(name, "extracted-checksum") == 0) {- xar->xmlsts = FILE_DATA_E_CHECKSUM;- xar->file->e_sum.alg = getsumalgorithm(list);- }- else if (strcmp(name, "content") == 0)- xar->xmlsts = FILE_DATA_CONTENT;- else- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case FILE_DEVICE:- if (strcmp(name, "major") == 0)- xar->xmlsts = FILE_DEVICE_MAJOR;- else if (strcmp(name, "minor") == 0)- xar->xmlsts = FILE_DEVICE_MINOR;- else- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case FILE_DATA_CONTENT:- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case FILE_EA:- if (strcmp(name, "length") == 0)- xar->xmlsts = FILE_EA_LENGTH;- else if (strcmp(name, "offset") == 0)- xar->xmlsts = FILE_EA_OFFSET;- else if (strcmp(name, "size") == 0)- xar->xmlsts = FILE_EA_SIZE;- else if (strcmp(name, "encoding") == 0) {- xar->xmlsts = FILE_EA_ENCODING;- xar->xattr->encoding = getencoding(list);- } else if (strcmp(name, "archived-checksum") == 0)- xar->xmlsts = FILE_EA_A_CHECKSUM;- else if (strcmp(name, "extracted-checksum") == 0)- xar->xmlsts = FILE_EA_E_CHECKSUM;- else if (strcmp(name, "name") == 0)- xar->xmlsts = FILE_EA_NAME;- else if (strcmp(name, "fstype") == 0)- xar->xmlsts = FILE_EA_FSTYPE;- else- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case FILE_ACL:- if (strcmp(name, "appleextended") == 0)- xar->xmlsts = FILE_ACL_APPLEEXTENDED;- else if (strcmp(name, "default") == 0)- xar->xmlsts = FILE_ACL_DEFAULT;- else if (strcmp(name, "access") == 0)- xar->xmlsts = FILE_ACL_ACCESS;- else- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case FILE_FLAGS:- if (!xml_parse_file_flags(xar, name))- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case FILE_EXT2:- if (!xml_parse_file_ext2(xar, name))- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- case TOC_CREATION_TIME:- case TOC_CHECKSUM_OFFSET:- case TOC_CHECKSUM_SIZE:- case FILE_DATA_LENGTH:- case FILE_DATA_OFFSET:- case FILE_DATA_SIZE:- case FILE_DATA_ENCODING:- case FILE_DATA_A_CHECKSUM:- case FILE_DATA_E_CHECKSUM:- case FILE_EA_LENGTH:- case FILE_EA_OFFSET:- case FILE_EA_SIZE:- case FILE_EA_ENCODING:- case FILE_EA_A_CHECKSUM:- case FILE_EA_E_CHECKSUM:- case FILE_EA_NAME:- case FILE_EA_FSTYPE:- case FILE_CTIME:- case FILE_MTIME:- case FILE_ATIME:- case FILE_GROUP:- case FILE_GID:- case FILE_USER:- case FILE_UID:- case FILE_INODE:- case FILE_DEVICE_MAJOR:- case FILE_DEVICE_MINOR:- case FILE_DEVICENO:- case FILE_MODE:- case FILE_TYPE:- case FILE_LINK:- case FILE_NAME:- case FILE_ACL_DEFAULT:- case FILE_ACL_ACCESS:- case FILE_ACL_APPLEEXTENDED:- case FILE_FLAGS_USER_NODUMP:- case FILE_FLAGS_USER_IMMUTABLE:- case FILE_FLAGS_USER_APPEND:- case FILE_FLAGS_USER_OPAQUE:- case FILE_FLAGS_USER_NOUNLINK:- case FILE_FLAGS_SYS_ARCHIVED:- case FILE_FLAGS_SYS_IMMUTABLE:- case FILE_FLAGS_SYS_APPEND:- case FILE_FLAGS_SYS_NOUNLINK:- case FILE_FLAGS_SYS_SNAPSHOT:- case FILE_EXT2_SecureDeletion:- case FILE_EXT2_Undelete:- case FILE_EXT2_Compress:- case FILE_EXT2_Synchronous:- case FILE_EXT2_Immutable:- case FILE_EXT2_AppendOnly:- case FILE_EXT2_NoDump:- case FILE_EXT2_NoAtime:- case FILE_EXT2_CompDirty:- case FILE_EXT2_CompBlock:- case FILE_EXT2_NoCompBlock:- case FILE_EXT2_CompError:- case FILE_EXT2_BTree:- case FILE_EXT2_HashIndexed:- case FILE_EXT2_iMagic:- case FILE_EXT2_Journaled:- case FILE_EXT2_NoTail:- case FILE_EXT2_DirSync:- case FILE_EXT2_TopDir:- case FILE_EXT2_Reserved:- case UNKNOWN:- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- break;- }- return (ARCHIVE_OK);-}--static void-xml_end(void *userData, const char *name)-{- struct archive_read *a;- struct xar *xar;-- a = (struct archive_read *)userData;- xar = (struct xar *)(a->format->data);--#if DEBUG- fprintf(stderr, "xml_end:[%s]\n", name);-#endif- switch (xar->xmlsts) {- case INIT:- break;- case XAR:- if (strcmp(name, "xar") == 0)- xar->xmlsts = INIT;- break;- case TOC:- if (strcmp(name, "toc") == 0)- xar->xmlsts = XAR;- break;- case TOC_CREATION_TIME:- if (strcmp(name, "creation-time") == 0)- xar->xmlsts = TOC;- break;- case TOC_CHECKSUM:- if (strcmp(name, "checksum") == 0)- xar->xmlsts = TOC;- break;- case TOC_CHECKSUM_OFFSET:- if (strcmp(name, "offset") == 0)- xar->xmlsts = TOC_CHECKSUM;- break;- case TOC_CHECKSUM_SIZE:- if (strcmp(name, "size") == 0)- xar->xmlsts = TOC_CHECKSUM;- break;- case TOC_FILE:- if (strcmp(name, "file") == 0) {- if (xar->file->parent != NULL &&- ((xar->file->mode & AE_IFMT) == AE_IFDIR))- xar->file->parent->subdirs++;- xar->file = xar->file->parent;- if (xar->file == NULL)- xar->xmlsts = TOC;- }- break;- case FILE_DATA:- if (strcmp(name, "data") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_DATA_LENGTH:- if (strcmp(name, "length") == 0)- xar->xmlsts = FILE_DATA;- break;- case FILE_DATA_OFFSET:- if (strcmp(name, "offset") == 0)- xar->xmlsts = FILE_DATA;- break;- case FILE_DATA_SIZE:- if (strcmp(name, "size") == 0)- xar->xmlsts = FILE_DATA;- break;- case FILE_DATA_ENCODING:- if (strcmp(name, "encoding") == 0)- xar->xmlsts = FILE_DATA;- break;- case FILE_DATA_A_CHECKSUM:- if (strcmp(name, "archived-checksum") == 0)- xar->xmlsts = FILE_DATA;- break;- case FILE_DATA_E_CHECKSUM:- if (strcmp(name, "extracted-checksum") == 0)- xar->xmlsts = FILE_DATA;- break;- case FILE_DATA_CONTENT:- if (strcmp(name, "content") == 0)- xar->xmlsts = FILE_DATA;- break;- case FILE_EA:- if (strcmp(name, "ea") == 0) {- xar->xmlsts = TOC_FILE;- xar->xattr = NULL;- }- break;- case FILE_EA_LENGTH:- if (strcmp(name, "length") == 0)- xar->xmlsts = FILE_EA;- break;- case FILE_EA_OFFSET:- if (strcmp(name, "offset") == 0)- xar->xmlsts = FILE_EA;- break;- case FILE_EA_SIZE:- if (strcmp(name, "size") == 0)- xar->xmlsts = FILE_EA;- break;- case FILE_EA_ENCODING:- if (strcmp(name, "encoding") == 0)- xar->xmlsts = FILE_EA;- break;- case FILE_EA_A_CHECKSUM:- if (strcmp(name, "archived-checksum") == 0)- xar->xmlsts = FILE_EA;- break;- case FILE_EA_E_CHECKSUM:- if (strcmp(name, "extracted-checksum") == 0)- xar->xmlsts = FILE_EA;- break;- case FILE_EA_NAME:- if (strcmp(name, "name") == 0)- xar->xmlsts = FILE_EA;- break;- case FILE_EA_FSTYPE:- if (strcmp(name, "fstype") == 0)- xar->xmlsts = FILE_EA;- break;- case FILE_CTIME:- if (strcmp(name, "ctime") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_MTIME:- if (strcmp(name, "mtime") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_ATIME:- if (strcmp(name, "atime") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_GROUP:- if (strcmp(name, "group") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_GID:- if (strcmp(name, "gid") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_USER:- if (strcmp(name, "user") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_UID:- if (strcmp(name, "uid") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_MODE:- if (strcmp(name, "mode") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_DEVICE:- if (strcmp(name, "device") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_DEVICE_MAJOR:- if (strcmp(name, "major") == 0)- xar->xmlsts = FILE_DEVICE;- break;- case FILE_DEVICE_MINOR:- if (strcmp(name, "minor") == 0)- xar->xmlsts = FILE_DEVICE;- break;- case FILE_DEVICENO:- if (strcmp(name, "deviceno") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_INODE:- if (strcmp(name, "inode") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_LINK:- if (strcmp(name, "link") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_TYPE:- if (strcmp(name, "type") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_NAME:- if (strcmp(name, "name") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_ACL:- if (strcmp(name, "acl") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_ACL_DEFAULT:- if (strcmp(name, "default") == 0)- xar->xmlsts = FILE_ACL;- break;- case FILE_ACL_ACCESS:- if (strcmp(name, "access") == 0)- xar->xmlsts = FILE_ACL;- break;- case FILE_ACL_APPLEEXTENDED:- if (strcmp(name, "appleextended") == 0)- xar->xmlsts = FILE_ACL;- break;- case FILE_FLAGS:- if (strcmp(name, "flags") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_FLAGS_USER_NODUMP:- if (strcmp(name, "UserNoDump") == 0)- xar->xmlsts = FILE_FLAGS;- break;- case FILE_FLAGS_USER_IMMUTABLE:- if (strcmp(name, "UserImmutable") == 0)- xar->xmlsts = FILE_FLAGS;- break;- case FILE_FLAGS_USER_APPEND:- if (strcmp(name, "UserAppend") == 0)- xar->xmlsts = FILE_FLAGS;- break;- case FILE_FLAGS_USER_OPAQUE:- if (strcmp(name, "UserOpaque") == 0)- xar->xmlsts = FILE_FLAGS;- break;- case FILE_FLAGS_USER_NOUNLINK:- if (strcmp(name, "UserNoUnlink") == 0)- xar->xmlsts = FILE_FLAGS;- break;- case FILE_FLAGS_SYS_ARCHIVED:- if (strcmp(name, "SystemArchived") == 0)- xar->xmlsts = FILE_FLAGS;- break;- case FILE_FLAGS_SYS_IMMUTABLE:- if (strcmp(name, "SystemImmutable") == 0)- xar->xmlsts = FILE_FLAGS;- break;- case FILE_FLAGS_SYS_APPEND:- if (strcmp(name, "SystemAppend") == 0)- xar->xmlsts = FILE_FLAGS;- break;- case FILE_FLAGS_SYS_NOUNLINK:- if (strcmp(name, "SystemNoUnlink") == 0)- xar->xmlsts = FILE_FLAGS;- break;- case FILE_FLAGS_SYS_SNAPSHOT:- if (strcmp(name, "SystemSnapshot") == 0)- xar->xmlsts = FILE_FLAGS;- break;- case FILE_EXT2:- if (strcmp(name, "ext2") == 0)- xar->xmlsts = TOC_FILE;- break;- case FILE_EXT2_SecureDeletion:- if (strcmp(name, "SecureDeletion") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_Undelete:- if (strcmp(name, "Undelete") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_Compress:- if (strcmp(name, "Compress") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_Synchronous:- if (strcmp(name, "Synchronous") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_Immutable:- if (strcmp(name, "Immutable") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_AppendOnly:- if (strcmp(name, "AppendOnly") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_NoDump:- if (strcmp(name, "NoDump") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_NoAtime:- if (strcmp(name, "NoAtime") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_CompDirty:- if (strcmp(name, "CompDirty") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_CompBlock:- if (strcmp(name, "CompBlock") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_NoCompBlock:- if (strcmp(name, "NoCompBlock") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_CompError:- if (strcmp(name, "CompError") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_BTree:- if (strcmp(name, "BTree") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_HashIndexed:- if (strcmp(name, "HashIndexed") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_iMagic:- if (strcmp(name, "iMagic") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_Journaled:- if (strcmp(name, "Journaled") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_NoTail:- if (strcmp(name, "NoTail") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_DirSync:- if (strcmp(name, "DirSync") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_TopDir:- if (strcmp(name, "TopDir") == 0)- xar->xmlsts = FILE_EXT2;- break;- case FILE_EXT2_Reserved:- if (strcmp(name, "Reserved") == 0)- xar->xmlsts = FILE_EXT2;- break;- case UNKNOWN:- unknowntag_end(xar, name);- break;- }-}--static const int base64[256] = {- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, -1, -1, -1, -1, -1, /* 00 - 0F */- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, -1, -1, -1, -1, -1, /* 10 - 1F */- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, 62, -1, -1, -1, 63, /* 20 - 2F */- 52, 53, 54, 55, 56, 57, 58, 59,- 60, 61, -1, -1, -1, -1, -1, -1, /* 30 - 3F */- -1, 0, 1, 2, 3, 4, 5, 6,- 7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */- 15, 16, 17, 18, 19, 20, 21, 22,- 23, 24, 25, -1, -1, -1, -1, -1, /* 50 - 5F */- -1, 26, 27, 28, 29, 30, 31, 32,- 33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */- 41, 42, 43, 44, 45, 46, 47, 48,- 49, 50, 51, -1, -1, -1, -1, -1, /* 70 - 7F */- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, -1, -1, -1, -1, -1, /* 80 - 8F */- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, -1, -1, -1, -1, -1, /* 90 - 9F */- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, -1, -1, -1, -1, -1, /* A0 - AF */- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, -1, -1, -1, -1, -1, /* B0 - BF */- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, -1, -1, -1, -1, -1, /* C0 - CF */- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, -1, -1, -1, -1, -1, /* D0 - DF */- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, -1, -1, -1, -1, -1, /* E0 - EF */- -1, -1, -1, -1, -1, -1, -1, -1,- -1, -1, -1, -1, -1, -1, -1, -1, /* F0 - FF */-};--static void-strappend_base64(struct xar *xar,- struct archive_string *as, const char *s, size_t l)-{- unsigned char buff[256];- unsigned char *out;- const unsigned char *b;- size_t len;-- (void)xar; /* UNUSED */- len = 0;- out = buff;- b = (const unsigned char *)s;- while (l > 0) {- int n = 0;-- if (base64[b[0]] < 0 || base64[b[1]] < 0)- break;- n = base64[*b++] << 18;- n |= base64[*b++] << 12;- *out++ = n >> 16;- len++;- l -= 2;-- if (l > 0) {- if (base64[*b] < 0)- break;- n |= base64[*b++] << 6;- *out++ = (n >> 8) & 0xFF;- len++;- --l;- }- if (l > 0) {- if (base64[*b] < 0)- break;- n |= base64[*b++];- *out++ = n & 0xFF;- len++;- --l;- }- if (len+3 >= sizeof(buff)) {- archive_strncat(as, (const char *)buff, len);- len = 0;- out = buff;- }- }- if (len > 0)- archive_strncat(as, (const char *)buff, len);-}--static int-is_string(const char *known, const char *data, size_t len)-{- if (strlen(known) != len)- return -1;- return memcmp(data, known, len);-}--static void-xml_data(void *userData, const char *s, int len)-{- struct archive_read *a;- struct xar *xar;-- a = (struct archive_read *)userData;- xar = (struct xar *)(a->format->data);--#if DEBUG- {- char buff[1024];- if (len > (int)(sizeof(buff)-1))- len = (int)(sizeof(buff)-1);- strncpy(buff, s, len);- buff[len] = 0;- fprintf(stderr, "\tlen=%d:\"%s\"\n", len, buff);- }-#endif- switch (xar->xmlsts) {- case TOC_CHECKSUM_OFFSET:- xar->toc_chksum_offset = atol10(s, len);- break;- case TOC_CHECKSUM_SIZE:- xar->toc_chksum_size = atol10(s, len);- break;- default:- break;- }- if (xar->file == NULL)- return;-- switch (xar->xmlsts) {- case FILE_NAME:- if (xar->file->parent != NULL) {- archive_string_concat(&(xar->file->pathname),- &(xar->file->parent->pathname));- archive_strappend_char(&(xar->file->pathname), '/');- }- xar->file->has |= HAS_PATHNAME;- if (xar->base64text) {- strappend_base64(xar,- &(xar->file->pathname), s, len);- } else- archive_strncat(&(xar->file->pathname), s, len);- break;- case FILE_LINK:- xar->file->has |= HAS_SYMLINK;- archive_strncpy(&(xar->file->symlink), s, len);- break;- case FILE_TYPE:- if (is_string("file", s, len) == 0 ||- is_string("hardlink", s, len) == 0)- xar->file->mode =- (xar->file->mode & ~AE_IFMT) | AE_IFREG;- if (is_string("directory", s, len) == 0)- xar->file->mode =- (xar->file->mode & ~AE_IFMT) | AE_IFDIR;- if (is_string("symlink", s, len) == 0)- xar->file->mode =- (xar->file->mode & ~AE_IFMT) | AE_IFLNK;- if (is_string("character special", s, len) == 0)- xar->file->mode =- (xar->file->mode & ~AE_IFMT) | AE_IFCHR;- if (is_string("block special", s, len) == 0)- xar->file->mode =- (xar->file->mode & ~AE_IFMT) | AE_IFBLK;- if (is_string("socket", s, len) == 0)- xar->file->mode =- (xar->file->mode & ~AE_IFMT) | AE_IFSOCK;- if (is_string("fifo", s, len) == 0)- xar->file->mode =- (xar->file->mode & ~AE_IFMT) | AE_IFIFO;- xar->file->has |= HAS_TYPE;- break;- case FILE_INODE:- xar->file->has |= HAS_INO;- xar->file->ino64 = atol10(s, len);- break;- case FILE_DEVICE_MAJOR:- xar->file->has |= HAS_DEVMAJOR;- xar->file->devmajor = (dev_t)atol10(s, len);- break;- case FILE_DEVICE_MINOR:- xar->file->has |= HAS_DEVMINOR;- xar->file->devminor = (dev_t)atol10(s, len);- break;- case FILE_DEVICENO:- xar->file->has |= HAS_DEV;- xar->file->dev = (dev_t)atol10(s, len);- break;- case FILE_MODE:- xar->file->has |= HAS_MODE;- xar->file->mode =- (xar->file->mode & AE_IFMT) |- ((mode_t)(atol8(s, len)) & ~AE_IFMT);- break;- case FILE_GROUP:- xar->file->has |= HAS_GID;- archive_strncpy(&(xar->file->gname), s, len);- break;- case FILE_GID:- xar->file->has |= HAS_GID;- xar->file->gid = atol10(s, len);- break;- case FILE_USER:- xar->file->has |= HAS_UID;- archive_strncpy(&(xar->file->uname), s, len);- break;- case FILE_UID:- xar->file->has |= HAS_UID;- xar->file->uid = atol10(s, len);- break;- case FILE_CTIME:- xar->file->has |= HAS_TIME | HAS_CTIME;- xar->file->ctime = parse_time(s, len);- break;- case FILE_MTIME:- xar->file->has |= HAS_TIME | HAS_MTIME;- xar->file->mtime = parse_time(s, len);- break;- case FILE_ATIME:- xar->file->has |= HAS_TIME | HAS_ATIME;- xar->file->atime = parse_time(s, len);- break;- case FILE_DATA_LENGTH:- xar->file->has |= HAS_DATA;- xar->file->length = atol10(s, len);- break;- case FILE_DATA_OFFSET:- xar->file->has |= HAS_DATA;- xar->file->offset = atol10(s, len);- break;- case FILE_DATA_SIZE:- xar->file->has |= HAS_DATA;- xar->file->size = atol10(s, len);- break;- case FILE_DATA_A_CHECKSUM:- xar->file->a_sum.len = atohex(xar->file->a_sum.val,- sizeof(xar->file->a_sum.val), s, len);- break;- case FILE_DATA_E_CHECKSUM:- xar->file->e_sum.len = atohex(xar->file->e_sum.val,- sizeof(xar->file->e_sum.val), s, len);- break;- case FILE_EA_LENGTH:- xar->file->has |= HAS_XATTR;- xar->xattr->length = atol10(s, len);- break;- case FILE_EA_OFFSET:- xar->file->has |= HAS_XATTR;- xar->xattr->offset = atol10(s, len);- break;- case FILE_EA_SIZE:- xar->file->has |= HAS_XATTR;- xar->xattr->size = atol10(s, len);- break;- case FILE_EA_A_CHECKSUM:- xar->file->has |= HAS_XATTR;- xar->xattr->a_sum.len = atohex(xar->xattr->a_sum.val,- sizeof(xar->xattr->a_sum.val), s, len);- break;- case FILE_EA_E_CHECKSUM:- xar->file->has |= HAS_XATTR;- xar->xattr->e_sum.len = atohex(xar->xattr->e_sum.val,- sizeof(xar->xattr->e_sum.val), s, len);- break;- case FILE_EA_NAME:- xar->file->has |= HAS_XATTR;- archive_strncpy(&(xar->xattr->name), s, len);- break;- case FILE_EA_FSTYPE:- xar->file->has |= HAS_XATTR;- archive_strncpy(&(xar->xattr->fstype), s, len);- break;- break;- case FILE_ACL_DEFAULT:- case FILE_ACL_ACCESS:- case FILE_ACL_APPLEEXTENDED:- xar->file->has |= HAS_ACL;- /* TODO */- break;- case INIT:- case XAR:- case TOC:- case TOC_CREATION_TIME:- case TOC_CHECKSUM:- case TOC_CHECKSUM_OFFSET:- case TOC_CHECKSUM_SIZE:- case TOC_FILE:- case FILE_DATA:- case FILE_DATA_ENCODING:- case FILE_DATA_CONTENT:- case FILE_DEVICE:- case FILE_EA:- case FILE_EA_ENCODING:- case FILE_ACL:- case FILE_FLAGS:- case FILE_FLAGS_USER_NODUMP:- case FILE_FLAGS_USER_IMMUTABLE:- case FILE_FLAGS_USER_APPEND:- case FILE_FLAGS_USER_OPAQUE:- case FILE_FLAGS_USER_NOUNLINK:- case FILE_FLAGS_SYS_ARCHIVED:- case FILE_FLAGS_SYS_IMMUTABLE:- case FILE_FLAGS_SYS_APPEND:- case FILE_FLAGS_SYS_NOUNLINK:- case FILE_FLAGS_SYS_SNAPSHOT:- case FILE_EXT2:- case FILE_EXT2_SecureDeletion:- case FILE_EXT2_Undelete:- case FILE_EXT2_Compress:- case FILE_EXT2_Synchronous:- case FILE_EXT2_Immutable:- case FILE_EXT2_AppendOnly:- case FILE_EXT2_NoDump:- case FILE_EXT2_NoAtime:- case FILE_EXT2_CompDirty:- case FILE_EXT2_CompBlock:- case FILE_EXT2_NoCompBlock:- case FILE_EXT2_CompError:- case FILE_EXT2_BTree:- case FILE_EXT2_HashIndexed:- case FILE_EXT2_iMagic:- case FILE_EXT2_Journaled:- case FILE_EXT2_NoTail:- case FILE_EXT2_DirSync:- case FILE_EXT2_TopDir:- case FILE_EXT2_Reserved:- case UNKNOWN:- break;- }-}--/*- * BSD file flags.- */-static int-xml_parse_file_flags(struct xar *xar, const char *name)-{- const char *flag = NULL;-- if (strcmp(name, "UserNoDump") == 0) {- xar->xmlsts = FILE_FLAGS_USER_NODUMP;- flag = "nodump";- }- else if (strcmp(name, "UserImmutable") == 0) {- xar->xmlsts = FILE_FLAGS_USER_IMMUTABLE;- flag = "uimmutable";- }- else if (strcmp(name, "UserAppend") == 0) {- xar->xmlsts = FILE_FLAGS_USER_APPEND;- flag = "uappend";- }- else if (strcmp(name, "UserOpaque") == 0) {- xar->xmlsts = FILE_FLAGS_USER_OPAQUE;- flag = "opaque";- }- else if (strcmp(name, "UserNoUnlink") == 0) {- xar->xmlsts = FILE_FLAGS_USER_NOUNLINK;- flag = "nouunlink";- }- else if (strcmp(name, "SystemArchived") == 0) {- xar->xmlsts = FILE_FLAGS_SYS_ARCHIVED;- flag = "archived";- }- else if (strcmp(name, "SystemImmutable") == 0) {- xar->xmlsts = FILE_FLAGS_SYS_IMMUTABLE;- flag = "simmutable";- }- else if (strcmp(name, "SystemAppend") == 0) {- xar->xmlsts = FILE_FLAGS_SYS_APPEND;- flag = "sappend";- }- else if (strcmp(name, "SystemNoUnlink") == 0) {- xar->xmlsts = FILE_FLAGS_SYS_NOUNLINK;- flag = "nosunlink";- }- else if (strcmp(name, "SystemSnapshot") == 0) {- xar->xmlsts = FILE_FLAGS_SYS_SNAPSHOT;- flag = "snapshot";- }-- if (flag == NULL)- return (0);- xar->file->has |= HAS_FFLAGS;- if (archive_strlen(&(xar->file->fflags_text)) > 0)- archive_strappend_char(&(xar->file->fflags_text), ',');- archive_strcat(&(xar->file->fflags_text), flag);- return (1);-}--/*- * Linux file flags.- */-static int-xml_parse_file_ext2(struct xar *xar, const char *name)-{- const char *flag = NULL;-- if (strcmp(name, "SecureDeletion") == 0) {- xar->xmlsts = FILE_EXT2_SecureDeletion;- flag = "securedeletion";- }- else if (strcmp(name, "Undelete") == 0) {- xar->xmlsts = FILE_EXT2_Undelete;- flag = "nouunlink";- }- else if (strcmp(name, "Compress") == 0) {- xar->xmlsts = FILE_EXT2_Compress;- flag = "compress";- }- else if (strcmp(name, "Synchronous") == 0) {- xar->xmlsts = FILE_EXT2_Synchronous;- flag = "sync";- }- else if (strcmp(name, "Immutable") == 0) {- xar->xmlsts = FILE_EXT2_Immutable;- flag = "simmutable";- }- else if (strcmp(name, "AppendOnly") == 0) {- xar->xmlsts = FILE_EXT2_AppendOnly;- flag = "sappend";- }- else if (strcmp(name, "NoDump") == 0) {- xar->xmlsts = FILE_EXT2_NoDump;- flag = "nodump";- }- else if (strcmp(name, "NoAtime") == 0) {- xar->xmlsts = FILE_EXT2_NoAtime;- flag = "noatime";- }- else if (strcmp(name, "CompDirty") == 0) {- xar->xmlsts = FILE_EXT2_CompDirty;- flag = "compdirty";- }- else if (strcmp(name, "CompBlock") == 0) {- xar->xmlsts = FILE_EXT2_CompBlock;- flag = "comprblk";- }- else if (strcmp(name, "NoCompBlock") == 0) {- xar->xmlsts = FILE_EXT2_NoCompBlock;- flag = "nocomprblk";- }- else if (strcmp(name, "CompError") == 0) {- xar->xmlsts = FILE_EXT2_CompError;- flag = "comperr";- }- else if (strcmp(name, "BTree") == 0) {- xar->xmlsts = FILE_EXT2_BTree;- flag = "btree";- }- else if (strcmp(name, "HashIndexed") == 0) {- xar->xmlsts = FILE_EXT2_HashIndexed;- flag = "hashidx";- }- else if (strcmp(name, "iMagic") == 0) {- xar->xmlsts = FILE_EXT2_iMagic;- flag = "imagic";- }- else if (strcmp(name, "Journaled") == 0) {- xar->xmlsts = FILE_EXT2_Journaled;- flag = "journal";- }- else if (strcmp(name, "NoTail") == 0) {- xar->xmlsts = FILE_EXT2_NoTail;- flag = "notail";- }- else if (strcmp(name, "DirSync") == 0) {- xar->xmlsts = FILE_EXT2_DirSync;- flag = "dirsync";- }- else if (strcmp(name, "TopDir") == 0) {- xar->xmlsts = FILE_EXT2_TopDir;- flag = "topdir";- }- else if (strcmp(name, "Reserved") == 0) {- xar->xmlsts = FILE_EXT2_Reserved;- flag = "reserved";- }-- if (flag == NULL)- return (0);- if (archive_strlen(&(xar->file->fflags_text)) > 0)- archive_strappend_char(&(xar->file->fflags_text), ',');- archive_strcat(&(xar->file->fflags_text), flag);- return (1);-}--#ifdef HAVE_LIBXML_XMLREADER_H--static int-xml2_xmlattr_setup(struct archive_read *a,- struct xmlattr_list *list, xmlTextReaderPtr reader)-{- struct xmlattr *attr;- int r;-- list->first = NULL;- list->last = &(list->first);- r = xmlTextReaderMoveToFirstAttribute(reader);- while (r == 1) {- attr = malloc(sizeof*(attr));- if (attr == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- attr->name = strdup(- (const char *)xmlTextReaderConstLocalName(reader));- if (attr->name == NULL) {- free(attr);- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- attr->value = strdup(- (const char *)xmlTextReaderConstValue(reader));- if (attr->value == NULL) {- free(attr->name);- free(attr);- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- attr->next = NULL;- *list->last = attr;- list->last = &(attr->next);- r = xmlTextReaderMoveToNextAttribute(reader);- }- return (r);-}--static int-xml2_read_cb(void *context, char *buffer, int len)-{- struct archive_read *a;- struct xar *xar;- const void *d;- size_t outbytes;- size_t used = 0;- int r;-- a = (struct archive_read *)context;- xar = (struct xar *)(a->format->data);-- if (xar->toc_remaining <= 0)- return (0);- d = buffer;- outbytes = len;- r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);- if (r != ARCHIVE_OK)- return (r);- __archive_read_consume(a, used);- xar->toc_remaining -= used;- xar->offset += used;- xar->toc_total += outbytes;- PRINT_TOC(buffer, len);-- return ((int)outbytes);-}--static int-xml2_close_cb(void *context)-{-- (void)context; /* UNUSED */- return (0);-}--static void-xml2_error_hdr(void *arg, const char *msg, xmlParserSeverities severity,- xmlTextReaderLocatorPtr locator)-{- struct archive_read *a;-- (void)locator; /* UNUSED */- a = (struct archive_read *)arg;- switch (severity) {- case XML_PARSER_SEVERITY_VALIDITY_WARNING:- case XML_PARSER_SEVERITY_WARNING:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "XML Parsing error: %s", msg);- break;- case XML_PARSER_SEVERITY_VALIDITY_ERROR:- case XML_PARSER_SEVERITY_ERROR:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "XML Parsing error: %s", msg);- break;- }-}--static int-xml2_read_toc(struct archive_read *a)-{- xmlTextReaderPtr reader;- struct xmlattr_list list;- int r;-- reader = xmlReaderForIO(xml2_read_cb, xml2_close_cb, a, NULL, NULL, 0);- if (reader == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Couldn't allocate memory for xml parser");- return (ARCHIVE_FATAL);- }- xmlTextReaderSetErrorHandler(reader, xml2_error_hdr, a);-- while ((r = xmlTextReaderRead(reader)) == 1) {- const char *name, *value;- int type, empty;-- type = xmlTextReaderNodeType(reader);- name = (const char *)xmlTextReaderConstLocalName(reader);- switch (type) {- case XML_READER_TYPE_ELEMENT:- empty = xmlTextReaderIsEmptyElement(reader);- r = xml2_xmlattr_setup(a, &list, reader);- if (r == ARCHIVE_OK)- r = xml_start(a, name, &list);- xmlattr_cleanup(&list);- if (r != ARCHIVE_OK)- return (r);- if (empty)- xml_end(a, name);- break;- case XML_READER_TYPE_END_ELEMENT:- xml_end(a, name);- break;- case XML_READER_TYPE_TEXT:- value = (const char *)xmlTextReaderConstValue(reader);- xml_data(a, value, strlen(value));- break;- case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:- default:- break;- }- if (r < 0)- break;- }- xmlFreeTextReader(reader);- xmlCleanupParser();-- return ((r == 0)?ARCHIVE_OK:ARCHIVE_FATAL);-}--#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)--static int-expat_xmlattr_setup(struct archive_read *a,- struct xmlattr_list *list, const XML_Char **atts)-{- struct xmlattr *attr;- char *name, *value;-- list->first = NULL;- list->last = &(list->first);- if (atts == NULL)- return (ARCHIVE_OK);- while (atts[0] != NULL && atts[1] != NULL) {- attr = malloc(sizeof*(attr));- name = strdup(atts[0]);- value = strdup(atts[1]);- if (attr == NULL || name == NULL || value == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- free(attr);- free(name);- free(value);- return (ARCHIVE_FATAL);- }- attr->name = name;- attr->value = value;- attr->next = NULL;- *list->last = attr;- list->last = &(attr->next);- atts += 2;- }- return (ARCHIVE_OK);-}--static void-expat_start_cb(void *userData, const XML_Char *name, const XML_Char **atts)-{- struct expat_userData *ud = (struct expat_userData *)userData;- struct archive_read *a = ud->archive;- struct xmlattr_list list;- int r;-- r = expat_xmlattr_setup(a, &list, atts);- if (r == ARCHIVE_OK)- r = xml_start(a, (const char *)name, &list);- xmlattr_cleanup(&list);- ud->state = r;-}--static void-expat_end_cb(void *userData, const XML_Char *name)-{- struct expat_userData *ud = (struct expat_userData *)userData;-- xml_end(ud->archive, (const char *)name);-}--static void-expat_data_cb(void *userData, const XML_Char *s, int len)-{- struct expat_userData *ud = (struct expat_userData *)userData;-- xml_data(ud->archive, s, len);-}--static int-expat_read_toc(struct archive_read *a)-{- struct xar *xar;- XML_Parser parser;- struct expat_userData ud;-- ud.state = ARCHIVE_OK;- ud.archive = a;-- xar = (struct xar *)(a->format->data);-- /* Initialize XML Parser library. */- parser = XML_ParserCreate(NULL);- if (parser == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Couldn't allocate memory for xml parser");- return (ARCHIVE_FATAL);- }- XML_SetUserData(parser, &ud);- XML_SetElementHandler(parser, expat_start_cb, expat_end_cb);- XML_SetCharacterDataHandler(parser, expat_data_cb);- xar->xmlsts = INIT;-- while (xar->toc_remaining && ud.state == ARCHIVE_OK) {- enum XML_Status xr;- const void *d;- size_t outbytes;- size_t used;- int r;-- d = NULL;- r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);- if (r != ARCHIVE_OK)- return (r);- xar->toc_remaining -= used;- xar->offset += used;- xar->toc_total += outbytes;- PRINT_TOC(d, outbytes);-- xr = XML_Parse(parser, d, outbytes, xar->toc_remaining == 0);- __archive_read_consume(a, used);- if (xr == XML_STATUS_ERROR) {- XML_ParserFree(parser);- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "XML Parsing failed");- return (ARCHIVE_FATAL);- }- }- XML_ParserFree(parser);- return (ud.state);-}-#endif /* defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) */--#endif /* Support xar format */
− c/archive_read_support_format_zip.c
@@ -1,4270 +0,0 @@-/*-- * Copyright (c) 2004-2013 Tim Kientzle- * Copyright (c) 2011-2012,2014 Michihiro NAKAJIMA- * Copyright (c) 2013 Konrad Kleine- * 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_read_support_format_zip.c 201102 2009-12-28 03:11:36Z kientzle $");--/*- * The definitive documentation of the Zip file format is:- * http://www.pkware.com/documents/casestudies/APPNOTE.TXT- *- * The Info-Zip project has pioneered various extensions to better- * support Zip on Unix, including the 0x5455 "UT", 0x5855 "UX", 0x7855- * "Ux", and 0x7875 "ux" extensions for time and ownership- * information.- *- * History of this code: The streaming Zip reader was first added to- * libarchive in January 2005. Support for seekable input sources was- * added in Nov 2011. Zip64 support (including a significant code- * refactoring) was added in 2014.- */--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif-#ifdef HAVE_BZLIB_H-#include <bzlib.h>-#endif-#ifdef HAVE_LZMA_H-#include <lzma.h>-#endif-#ifdef HAVE_ZSTD_H-#include <zstd.h>-#endif--#include "archive.h"-#include "archive_digest_private.h"-#include "archive_cryptor_private.h"-#include "archive_endian.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_hmac_private.h"-#include "archive_private.h"-#include "archive_rb.h"-#include "archive_read_private.h"-#include "archive_ppmd8_private.h"--#ifndef HAVE_ZLIB_H-#include "archive_crc32.h"-#endif--struct zip_entry {- struct archive_rb_node node;- struct zip_entry *next;- int64_t local_header_offset;- int64_t compressed_size;- int64_t uncompressed_size;- int64_t gid;- int64_t uid;- struct archive_string rsrcname;- time_t mtime;- time_t atime;- time_t ctime;- uint32_t crc32;- uint16_t mode;- uint16_t zip_flags; /* From GP Flags Field */- unsigned char compression;- unsigned char system; /* From "version written by" */- unsigned char flags; /* Our extra markers. */- unsigned char decdat;/* Used for Decryption check */-- /* WinZip AES encryption extra field should be available- * when compression is 99. */- struct {- /* Vendor version: AE-1 - 0x0001, AE-2 - 0x0002 */- unsigned vendor;-#define AES_VENDOR_AE_1 0x0001-#define AES_VENDOR_AE_2 0x0002- /* AES encryption strength:- * 1 - 128 bits, 2 - 192 bits, 2 - 256 bits. */- unsigned strength;- /* Actual compression method. */- unsigned char compression;- } aes_extra;-};--struct trad_enc_ctx {- uint32_t keys[3];-};--/* Bits used in zip_flags. */-#define ZIP_ENCRYPTED (1 << 0)-#define ZIP_LENGTH_AT_END (1 << 3)-#define ZIP_STRONG_ENCRYPTED (1 << 6)-#define ZIP_UTF8_NAME (1 << 11)-/* See "7.2 Single Password Symmetric Encryption Method"- in http://www.pkware.com/documents/casestudies/APPNOTE.TXT */-#define ZIP_CENTRAL_DIRECTORY_ENCRYPTED (1 << 13)--/* Bits used in flags. */-#define LA_USED_ZIP64 (1 << 0)-#define LA_FROM_CENTRAL_DIRECTORY (1 << 1)--/*- * See "WinZip - AES Encryption Information"- * http://www.winzip.com/aes_info.htm- */-/* Value used in compression method. */-#define WINZIP_AES_ENCRYPTION 99-/* Authentication code size. */-#define AUTH_CODE_SIZE 10-/**/-#define MAX_DERIVED_KEY_BUF_SIZE (AES_MAX_KEY_SIZE * 2 + 2)--struct zip {- /* Structural information about the archive. */- struct archive_string format_name;- int64_t central_directory_offset;- int64_t central_directory_offset_adjusted;- size_t central_directory_entries_total;- size_t central_directory_entries_on_this_disk;- int has_encrypted_entries;-- /* List of entries (seekable Zip only) */- struct zip_entry *zip_entries;- struct archive_rb_tree tree;- struct archive_rb_tree tree_rsrc;-- /* Bytes read but not yet consumed via __archive_read_consume() */- size_t unconsumed;-- /* Information about entry we're currently reading. */- struct zip_entry *entry;- int64_t entry_bytes_remaining;-- /* These count the number of bytes actually read for the entry. */- int64_t entry_compressed_bytes_read;- int64_t entry_uncompressed_bytes_read;-- /* Running CRC32 of the decompressed data */- unsigned long entry_crc32;- unsigned long (*crc32func)(unsigned long, const void *,- size_t);- char ignore_crc32;-- /* Flags to mark progress of decompression. */- char decompress_init;- char end_of_entry;-- unsigned char *uncompressed_buffer;- size_t uncompressed_buffer_size;--#ifdef HAVE_ZLIB_H- z_stream stream;- char stream_valid;-#endif--#if HAVE_LZMA_H && HAVE_LIBLZMA- lzma_stream zipx_lzma_stream;- char zipx_lzma_valid;-#endif--#ifdef HAVE_BZLIB_H- bz_stream bzstream;- char bzstream_valid;-#endif--#if HAVE_ZSTD_H && HAVE_LIBZSTD- ZSTD_DStream *zstdstream;- char zstdstream_valid;-#endif-- IByteIn zipx_ppmd_stream;- ssize_t zipx_ppmd_read_compressed;- CPpmd8 ppmd8;- char ppmd8_valid;- char ppmd8_stream_failed;-- struct archive_string_conv *sconv;- struct archive_string_conv *sconv_default;- struct archive_string_conv *sconv_utf8;- int init_default_conversion;- int process_mac_extensions;-- char init_decryption;-- /* Decryption buffer. */- /*- * The decrypted data starts at decrypted_ptr and- * extends for decrypted_bytes_remaining. Decryption- * adds new data to the end of this block, data is returned- * to clients from the beginning. When the block hits the- * end of decrypted_buffer, it has to be shuffled back to- * the beginning of the buffer.- */- unsigned char *decrypted_buffer;- unsigned char *decrypted_ptr;- size_t decrypted_buffer_size;- size_t decrypted_bytes_remaining;- size_t decrypted_unconsumed_bytes;-- /* Traditional PKWARE decryption. */- struct trad_enc_ctx tctx;- char tctx_valid;-- /* WinZip AES decryption. */- /* Contexts used for AES decryption. */- archive_crypto_ctx cctx;- char cctx_valid;- archive_hmac_sha1_ctx hctx;- char hctx_valid;-- /* Strong encryption's decryption header information. */- unsigned iv_size;- unsigned alg_id;- unsigned bit_len;- unsigned flags;- unsigned erd_size;- unsigned v_size;- unsigned v_crc32;- uint8_t *iv;- uint8_t *erd;- uint8_t *v_data;-};--/* Many systems define min or MIN, but not all. */-#define zipmin(a,b) ((a) < (b) ? (a) : (b))--#ifdef HAVE_ZLIB_H-static int-zip_read_data_deflate(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset);-#endif-#if HAVE_LZMA_H && HAVE_LIBLZMA-static int-zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset);-#endif--/* This function is used by Ppmd8_DecodeSymbol during decompression of Ppmd8- * streams inside ZIP files. It has 2 purposes: one is to fetch the next- * compressed byte from the stream, second one is to increase the counter how- * many compressed bytes were read. */-static Byte-ppmd_read(void* p) {- /* Get the handle to current decompression context. */- struct archive_read *a = ((IByteIn*)p)->a;- struct zip *zip = (struct zip*) a->format->data;- ssize_t bytes_avail = 0;-- /* Fetch next byte. */- const uint8_t* data = __archive_read_ahead(a, 1, &bytes_avail);- if(bytes_avail < 1) {- zip->ppmd8_stream_failed = 1;- return 0;- }-- __archive_read_consume(a, 1);-- /* Increment the counter. */- ++zip->zipx_ppmd_read_compressed;-- /* Return the next compressed byte. */- return data[0];-}--/* ------------------------------------------------------------------------ */--/*- Traditional PKWARE Decryption functions.- */--static void-trad_enc_update_keys(struct trad_enc_ctx *ctx, uint8_t c)-{- uint8_t t;-#define CRC32(c, b) (crc32(c ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL)-- ctx->keys[0] = CRC32(ctx->keys[0], c);- ctx->keys[1] = (ctx->keys[1] + (ctx->keys[0] & 0xff)) * 134775813L + 1;- t = (ctx->keys[1] >> 24) & 0xff;- ctx->keys[2] = CRC32(ctx->keys[2], t);-#undef CRC32-}--static uint8_t-trad_enc_decrypt_byte(struct trad_enc_ctx *ctx)-{- unsigned temp = ctx->keys[2] | 2;- return (uint8_t)((temp * (temp ^ 1)) >> 8) & 0xff;-}--static void-trad_enc_decrypt_update(struct trad_enc_ctx *ctx, const uint8_t *in,- size_t in_len, uint8_t *out, size_t out_len)-{- unsigned i, max;-- max = (unsigned)((in_len < out_len)? in_len: out_len);-- for (i = 0; i < max; i++) {- uint8_t t = in[i] ^ trad_enc_decrypt_byte(ctx);- out[i] = t;- trad_enc_update_keys(ctx, t);- }-}--static int-trad_enc_init(struct trad_enc_ctx *ctx, const char *pw, size_t pw_len,- const uint8_t *key, size_t key_len, uint8_t *crcchk)-{- uint8_t header[12];-- if (key_len < 12) {- *crcchk = 0xff;- return -1;- }-- ctx->keys[0] = 305419896L;- ctx->keys[1] = 591751049L;- ctx->keys[2] = 878082192L;-- for (;pw_len; --pw_len)- trad_enc_update_keys(ctx, *pw++);-- trad_enc_decrypt_update(ctx, key, 12, header, 12);- /* Return the last byte for CRC check. */- *crcchk = header[11];- return 0;-}--#if 0-static void-crypt_derive_key_sha1(const void *p, int size, unsigned char *key,- int key_size)-{-#define MD_SIZE 20- archive_sha1_ctx ctx;- unsigned char md1[MD_SIZE];- unsigned char md2[MD_SIZE * 2];- unsigned char mkb[64];- int i;-- archive_sha1_init(&ctx);- archive_sha1_update(&ctx, p, size);- archive_sha1_final(&ctx, md1);-- memset(mkb, 0x36, sizeof(mkb));- for (i = 0; i < MD_SIZE; i++)- mkb[i] ^= md1[i];- archive_sha1_init(&ctx);- archive_sha1_update(&ctx, mkb, sizeof(mkb));- archive_sha1_final(&ctx, md2);-- memset(mkb, 0x5C, sizeof(mkb));- for (i = 0; i < MD_SIZE; i++)- mkb[i] ^= md1[i];- archive_sha1_init(&ctx);- archive_sha1_update(&ctx, mkb, sizeof(mkb));- archive_sha1_final(&ctx, md2 + MD_SIZE);-- if (key_size > 32)- key_size = 32;- memcpy(key, md2, key_size);-#undef MD_SIZE-}-#endif--/*- * Common code for streaming or seeking modes.- *- * Includes code to read local file headers, decompress data- * from entry bodies, and common API.- */--static unsigned long-real_crc32(unsigned long crc, const void *buff, size_t len)-{- return crc32(crc, buff, (unsigned int)len);-}--/* Used by "ignorecrc32" option to speed up tests. */-static unsigned long-fake_crc32(unsigned long crc, const void *buff, size_t len)-{- (void)crc; /* UNUSED */- (void)buff; /* UNUSED */- (void)len; /* UNUSED */- return 0;-}--static const struct {- int id;- const char * name;-} compression_methods[] = {- {0, "uncompressed"}, /* The file is stored (no compression) */- {1, "shrinking"}, /* The file is Shrunk */- {2, "reduced-1"}, /* The file is Reduced with compression factor 1 */- {3, "reduced-2"}, /* The file is Reduced with compression factor 2 */- {4, "reduced-3"}, /* The file is Reduced with compression factor 3 */- {5, "reduced-4"}, /* The file is Reduced with compression factor 4 */- {6, "imploded"}, /* The file is Imploded */- {7, "reserved"}, /* Reserved for Tokenizing compression algorithm */- {8, "deflation"}, /* The file is Deflated */- {9, "deflation-64-bit"}, /* Enhanced Deflating using Deflate64(tm) */- {10, "ibm-terse"},/* PKWARE Data Compression Library Imploding- * (old IBM TERSE) */- {11, "reserved"}, /* Reserved by PKWARE */- {12, "bzip"}, /* File is compressed using BZIP2 algorithm */- {13, "reserved"}, /* Reserved by PKWARE */- {14, "lzma"}, /* LZMA (EFS) */- {15, "reserved"}, /* Reserved by PKWARE */- {16, "reserved"}, /* Reserved by PKWARE */- {17, "reserved"}, /* Reserved by PKWARE */- {18, "ibm-terse-new"}, /* File is compressed using IBM TERSE (new) */- {19, "ibm-lz777"},/* IBM LZ77 z Architecture (PFS) */- {93, "zstd"}, /* Zstandard (zstd) Compression */- {95, "xz"}, /* XZ compressed data */- {96, "jpeg"}, /* JPEG compressed data */- {97, "wav-pack"}, /* WavPack compressed data */- {98, "ppmd-1"}, /* PPMd version I, Rev 1 */- {99, "aes"} /* WinZip AES encryption */-};--static const char *-compression_name(const int compression)-{- static const int num_compression_methods =- sizeof(compression_methods)/sizeof(compression_methods[0]);- int i=0;-- while(compression >= 0 && i < num_compression_methods) {- if (compression_methods[i].id == compression)- return compression_methods[i].name;- i++;- }- return "??";-}--/* Convert an MSDOS-style date/time into Unix-style time. */-static time_t-zip_time(const char *p)-{- int msTime, msDate;- struct tm ts;-- msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]);- msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]);-- memset(&ts, 0, sizeof(ts));- ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */- ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */- ts.tm_mday = msDate & 0x1f; /* Day of month. */- ts.tm_hour = (msTime >> 11) & 0x1f;- ts.tm_min = (msTime >> 5) & 0x3f;- ts.tm_sec = (msTime << 1) & 0x3e;- ts.tm_isdst = -1;- return mktime(&ts);-}--/*- * The extra data is stored as a list of- * id1+size1+data1 + id2+size2+data2 ...- * triplets. id and size are 2 bytes each.- */-static int-process_extra(struct archive_read *a, struct archive_entry *entry,- const char *p, size_t extra_length, struct zip_entry* zip_entry)-{- unsigned offset = 0;- struct zip *zip = (struct zip *)(a->format->data);-- if (extra_length == 0) {- return ARCHIVE_OK;- }-- if (extra_length < 4) {- size_t i = 0;- /* Some ZIP files may have trailing 0 bytes. Let's check they- * are all 0 and ignore them instead of returning an error.- *- * This is not technically correct, but some ZIP files look- * like this and other tools support those files - so let's- * also support them.- */- for (; i < extra_length; i++) {- if (p[i] != 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Too-small extra data: "- "Need at least 4 bytes, "- "but only found %d bytes",- (int)extra_length);- return ARCHIVE_FAILED;- }- }-- return ARCHIVE_OK;- }-- while (offset <= extra_length - 4) {- unsigned short headerid = archive_le16dec(p + offset);- unsigned short datasize = archive_le16dec(p + offset + 2);-- offset += 4;- if (offset + datasize > extra_length) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT, "Extra data overflow: "- "Need %d bytes but only found %d bytes",- (int)datasize, (int)(extra_length - offset));- return ARCHIVE_FAILED;- }-#ifdef DEBUG- fprintf(stderr, "Header id 0x%04x, length %d\n",- headerid, datasize);-#endif- switch (headerid) {- case 0x0001:- /* Zip64 extended information extra field. */- zip_entry->flags |= LA_USED_ZIP64;- if (zip_entry->uncompressed_size == 0xffffffff) {- uint64_t t = 0;- if (datasize < 8- || (t = archive_le64dec(p + offset)) >- INT64_MAX) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Malformed 64-bit "- "uncompressed size");- return ARCHIVE_FAILED;- }- zip_entry->uncompressed_size = t;- offset += 8;- datasize -= 8;- }- if (zip_entry->compressed_size == 0xffffffff) {- uint64_t t = 0;- if (datasize < 8- || (t = archive_le64dec(p + offset)) >- INT64_MAX) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Malformed 64-bit "- "compressed size");- return ARCHIVE_FAILED;- }- zip_entry->compressed_size = t;- offset += 8;- datasize -= 8;- }- if (zip_entry->local_header_offset == 0xffffffff) {- uint64_t t = 0;- if (datasize < 8- || (t = archive_le64dec(p + offset)) >- INT64_MAX) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Malformed 64-bit "- "local header offset");- return ARCHIVE_FAILED;- }- zip_entry->local_header_offset = t;- offset += 8;- datasize -= 8;- }- /* archive_le32dec(p + offset) gives disk- * on which file starts, but we don't handle- * multi-volume Zip files. */- break;-#ifdef DEBUG- case 0x0017:- {- /* Strong encryption field. */- if (archive_le16dec(p + offset) == 2) {- unsigned algId =- archive_le16dec(p + offset + 2);- unsigned bitLen =- archive_le16dec(p + offset + 4);- int flags =- archive_le16dec(p + offset + 6);- fprintf(stderr, "algId=0x%04x, bitLen=%u, "- "flgas=%d\n", algId, bitLen,flags);- }- break;- }-#endif- case 0x5455:- {- /* Extended time field "UT". */- int flags;- if (datasize == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Incomplete extended time field");- return ARCHIVE_FAILED;- }- flags = p[offset];- offset++;- datasize--;- /* Flag bits indicate which dates are present. */- if (flags & 0x01)- {-#ifdef DEBUG- fprintf(stderr, "mtime: %lld -> %d\n",- (long long)zip_entry->mtime,- archive_le32dec(p + offset));-#endif- if (datasize < 4)- break;- zip_entry->mtime = archive_le32dec(p + offset);- offset += 4;- datasize -= 4;- }- if (flags & 0x02)- {- if (datasize < 4)- break;- zip_entry->atime = archive_le32dec(p + offset);- offset += 4;- datasize -= 4;- }- if (flags & 0x04)- {- if (datasize < 4)- break;- zip_entry->ctime = archive_le32dec(p + offset);- offset += 4;- datasize -= 4;- }- break;- }- case 0x5855:- {- /* Info-ZIP Unix Extra Field (old version) "UX". */- if (datasize >= 8) {- zip_entry->atime = archive_le32dec(p + offset);- zip_entry->mtime =- archive_le32dec(p + offset + 4);- }- if (datasize >= 12) {- zip_entry->uid =- archive_le16dec(p + offset + 8);- zip_entry->gid =- archive_le16dec(p + offset + 10);- }- break;- }- case 0x6c78:- {- /* Experimental 'xl' field */- /*- * Introduced Dec 2013 to provide a way to- * include external file attributes (and other- * fields that ordinarily appear only in- * central directory) in local file header.- * This provides file type and permission- * information necessary to support full- * streaming extraction. Currently being- * discussed with other Zip developers- * ... subject to change.- *- * Format:- * The field starts with a bitmap that specifies- * which additional fields are included. The- * bitmap is variable length and can be extended in- * the future.- *- * n bytes - feature bitmap: first byte has low-order- * 7 bits. If high-order bit is set, a subsequent- * byte holds the next 7 bits, etc.- *- * if bitmap & 1, 2 byte "version made by"- * if bitmap & 2, 2 byte "internal file attributes"- * if bitmap & 4, 4 byte "external file attributes"- * if bitmap & 8, 2 byte comment length + n byte- * comment- */- int bitmap, bitmap_last;-- if (datasize < 1)- break;- bitmap_last = bitmap = 0xff & p[offset];- offset += 1;- datasize -= 1;-- /* We only support first 7 bits of bitmap; skip rest. */- while ((bitmap_last & 0x80) != 0- && datasize >= 1) {- bitmap_last = p[offset];- offset += 1;- datasize -= 1;- }-- if (bitmap & 1) {- /* 2 byte "version made by" */- if (datasize < 2)- break;- zip_entry->system- = archive_le16dec(p + offset) >> 8;- offset += 2;- datasize -= 2;- }- if (bitmap & 2) {- /* 2 byte "internal file attributes" */- uint32_t internal_attributes;- if (datasize < 2)- break;- internal_attributes- = archive_le16dec(p + offset);- /* Not used by libarchive at present. */- (void)internal_attributes; /* UNUSED */- offset += 2;- datasize -= 2;- }- if (bitmap & 4) {- /* 4 byte "external file attributes" */- uint32_t external_attributes;- if (datasize < 4)- break;- external_attributes- = archive_le32dec(p + offset);- if (zip_entry->system == 3) {- zip_entry->mode- = external_attributes >> 16;- } else if (zip_entry->system == 0) {- // Interpret MSDOS directory bit- if (0x10 == (external_attributes &- 0x10)) {- zip_entry->mode =- AE_IFDIR | 0775;- } else {- zip_entry->mode =- AE_IFREG | 0664;- }- if (0x01 == (external_attributes &- 0x01)) {- /* Read-only bit;- * strip write permissions */- zip_entry->mode &= 0555;- }- } else {- zip_entry->mode = 0;- }- offset += 4;- datasize -= 4;- }- if (bitmap & 8) {- /* 2 byte comment length + comment */- uint32_t comment_length;- if (datasize < 2)- break;- comment_length- = archive_le16dec(p + offset);- offset += 2;- datasize -= 2;-- if (datasize < comment_length)- break;- /* Comment is not supported by libarchive */- offset += comment_length;- datasize -= comment_length;- }- break;- }- case 0x7075:- {- /* Info-ZIP Unicode Path Extra Field. */- if (datasize < 5 || entry == NULL)- break;- offset += 5;- datasize -= 5;-- /* The path name in this field is always encoded- * in UTF-8. */- if (zip->sconv_utf8 == NULL) {- zip->sconv_utf8 =- archive_string_conversion_from_charset(- &a->archive, "UTF-8", 1);- /* If the converter from UTF-8 is not- * available, then the path name from the main- * field will more likely be correct. */- if (zip->sconv_utf8 == NULL)- break;- }-- /* Make sure the CRC32 of the filename matches. */- if (!zip->ignore_crc32) {- const char *cp = archive_entry_pathname(entry);- if (cp) {- unsigned long file_crc =- zip->crc32func(0, cp, strlen(cp));- unsigned long utf_crc =- archive_le32dec(p + offset - 4);- if (file_crc != utf_crc) {-#ifdef DEBUG- fprintf(stderr,- "CRC filename mismatch; "- "CDE is %lx, but UTF8 "- "is outdated with %lx\n",- file_crc, utf_crc);-#endif- break;- }- }- }-- if (archive_entry_copy_pathname_l(entry,- p + offset, datasize, zip->sconv_utf8) != 0) {- /* Ignore the error, and fallback to the path- * name from the main field. */-#ifdef DEBUG- fprintf(stderr, "Failed to read the ZIP "- "0x7075 extra field path.\n");-#endif- }- break;- }- case 0x7855:- /* Info-ZIP Unix Extra Field (type 2) "Ux". */-#ifdef DEBUG- fprintf(stderr, "uid %d gid %d\n",- archive_le16dec(p + offset),- archive_le16dec(p + offset + 2));-#endif- if (datasize >= 2)- zip_entry->uid = archive_le16dec(p + offset);- if (datasize >= 4)- zip_entry->gid =- archive_le16dec(p + offset + 2);- break;- case 0x7875:- {- /* Info-Zip Unix Extra Field (type 3) "ux". */- int uidsize = 0, gidsize = 0;-- /* TODO: support arbitrary uidsize/gidsize. */- if (datasize >= 1 && p[offset] == 1) {/* version=1 */- if (datasize >= 4) {- /* get a uid size. */- uidsize = 0xff & (int)p[offset+1];- if (uidsize == 2)- zip_entry->uid =- archive_le16dec(- p + offset + 2);- else if (uidsize == 4 && datasize >= 6)- zip_entry->uid =- archive_le32dec(- p + offset + 2);- }- if (datasize >= (2 + uidsize + 3)) {- /* get a gid size. */- gidsize = 0xff &- (int)p[offset+2+uidsize];- if (gidsize == 2)- zip_entry->gid =- archive_le16dec(- p+offset+2+uidsize+1);- else if (gidsize == 4 &&- datasize >= (2 + uidsize + 5))- zip_entry->gid =- archive_le32dec(- p+offset+2+uidsize+1);- }- }- break;- }- case 0x9901:- /* WinZip AES extra data field. */- if (datasize < 6) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Incomplete AES field");- return ARCHIVE_FAILED;- }- if (p[offset + 2] == 'A' && p[offset + 3] == 'E') {- /* Vendor version. */- zip_entry->aes_extra.vendor =- archive_le16dec(p + offset);- /* AES encryption strength. */- zip_entry->aes_extra.strength = p[offset + 4];- /* Actual compression method. */- zip_entry->aes_extra.compression =- p[offset + 5];- }- break;- default:- break;- }- offset += datasize;- }- return ARCHIVE_OK;-}--/*- * Assumes file pointer is at beginning of local file header.- */-static int-zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,- struct zip *zip)-{- const char *p;- const void *h;- const wchar_t *wp;- const char *cp;- size_t len, filename_length, extra_length;- struct archive_string_conv *sconv;- struct zip_entry *zip_entry = zip->entry;- struct zip_entry zip_entry_central_dir;- int ret = ARCHIVE_OK;- char version;-- /* Save a copy of the original for consistency checks. */- zip_entry_central_dir = *zip_entry;-- zip->decompress_init = 0;- zip->end_of_entry = 0;- zip->entry_uncompressed_bytes_read = 0;- zip->entry_compressed_bytes_read = 0;- zip->entry_crc32 = zip->crc32func(0, NULL, 0);-- /* Setup default conversion. */- if (zip->sconv == NULL && !zip->init_default_conversion) {- zip->sconv_default =- archive_string_default_conversion_for_read(&(a->archive));- zip->init_default_conversion = 1;- }-- if ((p = __archive_read_ahead(a, 30, NULL)) == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file header");- return (ARCHIVE_FATAL);- }-- if (memcmp(p, "PK\003\004", 4) != 0) {- archive_set_error(&a->archive, -1, "Damaged Zip archive");- return ARCHIVE_FATAL;- }- version = p[4];- zip_entry->system = p[5];- zip_entry->zip_flags = archive_le16dec(p + 6);- if (zip_entry->zip_flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)) {- zip->has_encrypted_entries = 1;- archive_entry_set_is_data_encrypted(entry, 1);- if (zip_entry->zip_flags & ZIP_CENTRAL_DIRECTORY_ENCRYPTED &&- zip_entry->zip_flags & ZIP_ENCRYPTED &&- zip_entry->zip_flags & ZIP_STRONG_ENCRYPTED) {- archive_entry_set_is_metadata_encrypted(entry, 1);- return ARCHIVE_FATAL;- }- }- zip->init_decryption = (zip_entry->zip_flags & ZIP_ENCRYPTED);- zip_entry->compression = (char)archive_le16dec(p + 8);- zip_entry->mtime = zip_time(p + 10);- zip_entry->crc32 = archive_le32dec(p + 14);- if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)- zip_entry->decdat = p[11];- else- zip_entry->decdat = p[17];- zip_entry->compressed_size = archive_le32dec(p + 18);- zip_entry->uncompressed_size = archive_le32dec(p + 22);- filename_length = archive_le16dec(p + 26);- extra_length = archive_le16dec(p + 28);-- __archive_read_consume(a, 30);-- /* Read the filename. */- if ((h = __archive_read_ahead(a, filename_length, NULL)) == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file header");- return (ARCHIVE_FATAL);- }- if (zip_entry->zip_flags & ZIP_UTF8_NAME) {- /* The filename is stored to be UTF-8. */- if (zip->sconv_utf8 == NULL) {- zip->sconv_utf8 =- archive_string_conversion_from_charset(- &a->archive, "UTF-8", 1);- if (zip->sconv_utf8 == NULL)- return (ARCHIVE_FATAL);- }- sconv = zip->sconv_utf8;- } else if (zip->sconv != NULL)- sconv = zip->sconv;- else- sconv = zip->sconv_default;-- if (archive_entry_copy_pathname_l(entry,- h, filename_length, sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Pathname cannot be converted "- "from %s to current locale.",- archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- }- __archive_read_consume(a, filename_length);-- /* Read the extra data. */- if ((h = __archive_read_ahead(a, extra_length, NULL)) == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file header");- return (ARCHIVE_FATAL);- }-- if (ARCHIVE_OK != process_extra(a, entry, h, extra_length,- zip_entry)) {- return ARCHIVE_FATAL;- }- __archive_read_consume(a, extra_length);-- /* Work around a bug in Info-Zip: When reading from a pipe, it- * stats the pipe instead of synthesizing a file entry. */- if ((zip_entry->mode & AE_IFMT) == AE_IFIFO) {- zip_entry->mode &= ~ AE_IFMT;- zip_entry->mode |= AE_IFREG;- }-- /* If the mode is totally empty, set some sane default. */- if (zip_entry->mode == 0) {- zip_entry->mode |= 0664;- }-- /* Windows archivers sometimes use backslash as the directory- * separator. Normalize to slash. */- if (zip_entry->system == 0 &&- (wp = archive_entry_pathname_w(entry)) != NULL) {- if (wcschr(wp, L'/') == NULL && wcschr(wp, L'\\') != NULL) {- size_t i;- struct archive_wstring s;- archive_string_init(&s);- archive_wstrcpy(&s, wp);- for (i = 0; i < archive_strlen(&s); i++) {- if (s.s[i] == '\\')- s.s[i] = '/';- }- archive_entry_copy_pathname_w(entry, s.s);- archive_wstring_free(&s);- }- }-- /* Make sure that entries with a trailing '/' are marked as directories- * even if the External File Attributes contains bogus values. If this- * is not a directory and there is no type, assume a regular file. */- if ((zip_entry->mode & AE_IFMT) != AE_IFDIR) {- int has_slash;-- wp = archive_entry_pathname_w(entry);- if (wp != NULL) {- len = wcslen(wp);- has_slash = len > 0 && wp[len - 1] == L'/';- } else {- cp = archive_entry_pathname(entry);- len = (cp != NULL)?strlen(cp):0;- has_slash = len > 0 && cp[len - 1] == '/';- }- /* Correct file type as needed. */- if (has_slash) {- zip_entry->mode &= ~AE_IFMT;- zip_entry->mode |= AE_IFDIR;- zip_entry->mode |= 0111;- } else if ((zip_entry->mode & AE_IFMT) == 0) {- zip_entry->mode |= AE_IFREG;- }- }-- /* Make sure directories end in '/' */- if ((zip_entry->mode & AE_IFMT) == AE_IFDIR) {- wp = archive_entry_pathname_w(entry);- if (wp != NULL) {- len = wcslen(wp);- if (len > 0 && wp[len - 1] != L'/') {- struct archive_wstring s;- archive_string_init(&s);- archive_wstrcat(&s, wp);- archive_wstrappend_wchar(&s, L'/');- archive_entry_copy_pathname_w(entry, s.s);- archive_wstring_free(&s);- }- } else {- cp = archive_entry_pathname(entry);- len = (cp != NULL)?strlen(cp):0;- if (len > 0 && cp[len - 1] != '/') {- struct archive_string s;- archive_string_init(&s);- archive_strcat(&s, cp);- archive_strappend_char(&s, '/');- archive_entry_set_pathname(entry, s.s);- archive_string_free(&s);- }- }- }-- if (zip_entry->flags & LA_FROM_CENTRAL_DIRECTORY) {- /* If this came from the central dir, its size info- * is definitive, so ignore the length-at-end flag. */- zip_entry->zip_flags &= ~ZIP_LENGTH_AT_END;- /* If local header is missing a value, use the one from- the central directory. If both have it, warn about- mismatches. */- if (zip_entry->crc32 == 0) {- zip_entry->crc32 = zip_entry_central_dir.crc32;- } else if (!zip->ignore_crc32- && zip_entry->crc32 != zip_entry_central_dir.crc32) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Inconsistent CRC32 values");- ret = ARCHIVE_WARN;- }- if (zip_entry->compressed_size == 0) {- zip_entry->compressed_size- = zip_entry_central_dir.compressed_size;- } else if (zip_entry->compressed_size- != zip_entry_central_dir.compressed_size) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Inconsistent compressed size: "- "%jd in central directory, %jd in local header",- (intmax_t)zip_entry_central_dir.compressed_size,- (intmax_t)zip_entry->compressed_size);- ret = ARCHIVE_WARN;- }- if (zip_entry->uncompressed_size == 0 ||- zip_entry->uncompressed_size == 0xffffffff) {- zip_entry->uncompressed_size- = zip_entry_central_dir.uncompressed_size;- } else if (zip_entry->uncompressed_size- != zip_entry_central_dir.uncompressed_size) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Inconsistent uncompressed size: "- "%jd in central directory, %jd in local header",- (intmax_t)zip_entry_central_dir.uncompressed_size,- (intmax_t)zip_entry->uncompressed_size);- ret = ARCHIVE_WARN;- }- }-- /* Populate some additional entry fields: */- archive_entry_set_mode(entry, zip_entry->mode);- archive_entry_set_uid(entry, zip_entry->uid);- archive_entry_set_gid(entry, zip_entry->gid);- archive_entry_set_mtime(entry, zip_entry->mtime, 0);- archive_entry_set_ctime(entry, zip_entry->ctime, 0);- archive_entry_set_atime(entry, zip_entry->atime, 0);-- if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) {- size_t linkname_length;-- if (zip_entry->compressed_size > 64 * 1024) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Zip file with oversized link entry");- return ARCHIVE_FATAL;- }-- linkname_length = (size_t)zip_entry->compressed_size;-- archive_entry_set_size(entry, 0);-- // take into account link compression if any- size_t linkname_full_length = linkname_length;- if (zip->entry->compression != 0)- {- // symlink target string appeared to be compressed- int status = ARCHIVE_FATAL;- const void *uncompressed_buffer = NULL;-- switch (zip->entry->compression)- {-#if HAVE_ZLIB_H- case 8: /* Deflate compression. */- zip->entry_bytes_remaining = zip_entry->compressed_size;- status = zip_read_data_deflate(a, &uncompressed_buffer,- &linkname_full_length, NULL);- break;-#endif-#if HAVE_LZMA_H && HAVE_LIBLZMA- case 14: /* ZIPx LZMA compression. */- /*(see zip file format specification, section 4.4.5)*/- zip->entry_bytes_remaining = zip_entry->compressed_size;- status = zip_read_data_zipx_lzma_alone(a, &uncompressed_buffer,- &linkname_full_length, NULL);- break;-#endif- default: /* Unsupported compression. */- break;- }- if (status == ARCHIVE_OK)- {- p = uncompressed_buffer;- }- else- {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported ZIP compression method "- "during decompression of link entry (%d: %s)",- zip->entry->compression,- compression_name(zip->entry->compression));- return ARCHIVE_FAILED;- }- }- else- {- p = __archive_read_ahead(a, linkname_length, NULL);- }-- if (p == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Truncated Zip file");- return ARCHIVE_FATAL;- }-- sconv = zip->sconv;- if (sconv == NULL && (zip->entry->zip_flags & ZIP_UTF8_NAME))- sconv = zip->sconv_utf8;- if (sconv == NULL)- sconv = zip->sconv_default;- if (archive_entry_copy_symlink_l(entry, p, linkname_full_length,- sconv) != 0) {- if (errno != ENOMEM && sconv == zip->sconv_utf8 &&- (zip->entry->zip_flags & ZIP_UTF8_NAME))- archive_entry_copy_symlink_l(entry, p,- linkname_full_length, NULL);- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Symlink");- return (ARCHIVE_FATAL);- }- /*- * Since there is no character-set regulation for- * symlink name, do not report the conversion error- * in an automatic conversion.- */- if (sconv != zip->sconv_utf8 ||- (zip->entry->zip_flags & ZIP_UTF8_NAME) == 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Symlink cannot be converted "- "from %s to current locale.",- archive_string_conversion_charset_name(- sconv));- ret = ARCHIVE_WARN;- }- }- zip_entry->uncompressed_size = zip_entry->compressed_size = 0;-- if (__archive_read_consume(a, linkname_length) < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Read error skipping symlink target name");- return ARCHIVE_FATAL;- }- } else if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)- || zip_entry->uncompressed_size > 0) {- /* Set the size only if it's meaningful. */- archive_entry_set_size(entry, zip_entry->uncompressed_size);- }- zip->entry_bytes_remaining = zip_entry->compressed_size;-- /* If there's no body, force read_data() to return EOF immediately. */- if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)- && zip->entry_bytes_remaining < 1)- zip->end_of_entry = 1;-- /* Set up a more descriptive format name. */- archive_string_empty(&zip->format_name);- archive_string_sprintf(&zip->format_name, "ZIP %d.%d (%s)",- version / 10, version % 10,- compression_name(zip->entry->compression));- a->archive.archive_format_name = zip->format_name.s;-- return (ret);-}--static int-check_authentication_code(struct archive_read *a, const void *_p)-{- struct zip *zip = (struct zip *)(a->format->data);-- /* Check authentication code. */- if (zip->hctx_valid) {- const void *p;- uint8_t hmac[20];- size_t hmac_len = 20;- int cmp;-- archive_hmac_sha1_final(&zip->hctx, hmac, &hmac_len);- if (_p == NULL) {- /* Read authentication code. */- p = __archive_read_ahead(a, AUTH_CODE_SIZE, NULL);- if (p == NULL) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file data");- return (ARCHIVE_FATAL);- }- } else {- p = _p;- }- cmp = memcmp(hmac, p, AUTH_CODE_SIZE);- __archive_read_consume(a, AUTH_CODE_SIZE);- if (cmp != 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "ZIP bad Authentication code");- return (ARCHIVE_WARN);- }- }- return (ARCHIVE_OK);-}--/*- * Read "uncompressed" data. There are three cases:- * 1) We know the size of the data. This is always true for the- * seeking reader (we've examined the Central Directory already).- * 2) ZIP_LENGTH_AT_END was set, but only the CRC was deferred.- * Info-ZIP seems to do this; we know the size but have to grab- * the CRC from the data descriptor afterwards.- * 3) We're streaming and ZIP_LENGTH_AT_END was specified and- * we have no size information. In this case, we can do pretty- * well by watching for the data descriptor record. The data- * descriptor is 16 bytes and includes a computed CRC that should- * provide a strong check.- *- * TODO: Technically, the PK\007\010 signature is optional.- * In the original spec, the data descriptor contained CRC- * and size fields but had no leading signature. In practice,- * newer writers seem to provide the signature pretty consistently.- *- * For uncompressed data, the PK\007\010 marker seems essential- * to be sure we've actually seen the end of the entry.- *- * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets- * zip->end_of_entry if it consumes all of the data.- */-static int-zip_read_data_none(struct archive_read *a, const void **_buff,- size_t *size, int64_t *offset)-{- struct zip *zip;- const char *buff;- ssize_t bytes_avail;- int r;-- (void)offset; /* UNUSED */-- zip = (struct zip *)(a->format->data);-- if (zip->entry->zip_flags & ZIP_LENGTH_AT_END) {- const char *p;- ssize_t grabbing_bytes = 24;-- if (zip->hctx_valid)- grabbing_bytes += AUTH_CODE_SIZE;- /* Grab at least 24 bytes. */- buff = __archive_read_ahead(a, grabbing_bytes, &bytes_avail);- if (bytes_avail < grabbing_bytes) {- /* Zip archives have end-of-archive markers- that are longer than this, so a failure to get at- least 24 bytes really does indicate a truncated- file. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file data");- return (ARCHIVE_FATAL);- }- /* Check for a complete PK\007\010 signature, followed- * by the correct 4-byte CRC. */- p = buff;- if (zip->hctx_valid)- p += AUTH_CODE_SIZE;- if (p[0] == 'P' && p[1] == 'K'- && p[2] == '\007' && p[3] == '\010'- && (archive_le32dec(p + 4) == zip->entry_crc32- || zip->ignore_crc32- || (zip->hctx_valid- && zip->entry->aes_extra.vendor == AES_VENDOR_AE_2))) {- if (zip->entry->flags & LA_USED_ZIP64) {- uint64_t compressed, uncompressed;- zip->entry->crc32 = archive_le32dec(p + 4);- compressed = archive_le64dec(p + 8);- uncompressed = archive_le64dec(p + 16);- if (compressed > INT64_MAX || uncompressed >- INT64_MAX) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Overflow of 64-bit file sizes");- return ARCHIVE_FAILED;- }- zip->entry->compressed_size = compressed;- zip->entry->uncompressed_size = uncompressed;- zip->unconsumed = 24;- } else {- zip->entry->crc32 = archive_le32dec(p + 4);- zip->entry->compressed_size =- archive_le32dec(p + 8);- zip->entry->uncompressed_size =- archive_le32dec(p + 12);- zip->unconsumed = 16;- }- if (zip->hctx_valid) {- r = check_authentication_code(a, buff);- if (r != ARCHIVE_OK)- return (r);- }- zip->end_of_entry = 1;- return (ARCHIVE_OK);- }- /* If not at EOF, ensure we consume at least one byte. */- ++p;-- /* Scan forward until we see where a PK\007\010 signature- * might be. */- /* Return bytes up until that point. On the next call,- * the code above will verify the data descriptor. */- while (p < buff + bytes_avail - 4) {- if (p[3] == 'P') { p += 3; }- else if (p[3] == 'K') { p += 2; }- else if (p[3] == '\007') { p += 1; }- else if (p[3] == '\010' && p[2] == '\007'- && p[1] == 'K' && p[0] == 'P') {- if (zip->hctx_valid)- p -= AUTH_CODE_SIZE;- break;- } else { p += 4; }- }- bytes_avail = p - buff;- } else {- if (zip->entry_bytes_remaining == 0) {- zip->end_of_entry = 1;- if (zip->hctx_valid) {- r = check_authentication_code(a, NULL);- if (r != ARCHIVE_OK)- return (r);- }- return (ARCHIVE_OK);- }- /* Grab a bunch of bytes. */- buff = __archive_read_ahead(a, 1, &bytes_avail);- if (bytes_avail <= 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file data");- return (ARCHIVE_FATAL);- }- if (bytes_avail > zip->entry_bytes_remaining)- bytes_avail = (ssize_t)zip->entry_bytes_remaining;- }- if (zip->tctx_valid || zip->cctx_valid) {- size_t dec_size = bytes_avail;-- if (dec_size > zip->decrypted_buffer_size)- dec_size = zip->decrypted_buffer_size;- if (zip->tctx_valid) {- trad_enc_decrypt_update(&zip->tctx,- (const uint8_t *)buff, dec_size,- zip->decrypted_buffer, dec_size);- } else {- size_t dsize = dec_size;- archive_hmac_sha1_update(&zip->hctx,- (const uint8_t *)buff, dec_size);- archive_decrypto_aes_ctr_update(&zip->cctx,- (const uint8_t *)buff, dec_size,- zip->decrypted_buffer, &dsize);- }- bytes_avail = dec_size;- buff = (const char *)zip->decrypted_buffer;- }- *size = bytes_avail;- zip->entry_bytes_remaining -= bytes_avail;- zip->entry_uncompressed_bytes_read += bytes_avail;- zip->entry_compressed_bytes_read += bytes_avail;- zip->unconsumed += bytes_avail;- *_buff = buff;- return (ARCHIVE_OK);-}--static int-consume_optional_marker(struct archive_read *a, struct zip *zip)-{- if (zip->end_of_entry && (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {- const char *p;-- if (NULL == (p = __archive_read_ahead(a, 24, NULL))) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP end-of-file record");- return (ARCHIVE_FATAL);- }- /* Consume the optional PK\007\010 marker. */- if (p[0] == 'P' && p[1] == 'K' &&- p[2] == '\007' && p[3] == '\010') {- p += 4;- zip->unconsumed = 4;- }- if (zip->entry->flags & LA_USED_ZIP64) {- uint64_t compressed, uncompressed;- zip->entry->crc32 = archive_le32dec(p);- compressed = archive_le64dec(p + 4);- uncompressed = archive_le64dec(p + 12);- if (compressed > INT64_MAX ||- uncompressed > INT64_MAX) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Overflow of 64-bit file sizes");- return ARCHIVE_FAILED;- }- zip->entry->compressed_size = compressed;- zip->entry->uncompressed_size = uncompressed;- zip->unconsumed += 20;- } else {- zip->entry->crc32 = archive_le32dec(p);- zip->entry->compressed_size = archive_le32dec(p + 4);- zip->entry->uncompressed_size = archive_le32dec(p + 8);- zip->unconsumed += 12;- }- }-- return (ARCHIVE_OK);-}--#if HAVE_LZMA_H && HAVE_LIBLZMA-static int-zipx_xz_init(struct archive_read *a, struct zip *zip)-{- lzma_ret r;-- if(zip->zipx_lzma_valid) {- lzma_end(&zip->zipx_lzma_stream);- zip->zipx_lzma_valid = 0;- }-- memset(&zip->zipx_lzma_stream, 0, sizeof(zip->zipx_lzma_stream));- r = lzma_stream_decoder(&zip->zipx_lzma_stream, UINT64_MAX, 0);- if (r != LZMA_OK) {- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,- "xz initialization failed(%d)",- r);-- return (ARCHIVE_FAILED);- }-- zip->zipx_lzma_valid = 1;-- free(zip->uncompressed_buffer);-- zip->uncompressed_buffer_size = 256 * 1024;- zip->uncompressed_buffer =- (uint8_t*) malloc(zip->uncompressed_buffer_size);- if (zip->uncompressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for xz decompression");- return (ARCHIVE_FATAL);- }-- zip->decompress_init = 1;- return (ARCHIVE_OK);-}--static int-zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)-{- lzma_ret r;- const uint8_t* p;--#pragma pack(push)-#pragma pack(1)- struct _alone_header {- uint8_t bytes[5];- uint64_t uncompressed_size;- } alone_header;-#pragma pack(pop)-- if(zip->zipx_lzma_valid) {- lzma_end(&zip->zipx_lzma_stream);- zip->zipx_lzma_valid = 0;- }-- /* To unpack ZIPX's "LZMA" (id 14) stream we can use standard liblzma- * that is a part of XZ Utils. The stream format stored inside ZIPX- * file is a modified "lzma alone" file format, that was used by the- * `lzma` utility which was later deprecated in favour of `xz` utility.- * Since those formats are nearly the same, we can use a standard- * "lzma alone" decoder from XZ Utils. */-- memset(&zip->zipx_lzma_stream, 0, sizeof(zip->zipx_lzma_stream));- r = lzma_alone_decoder(&zip->zipx_lzma_stream, UINT64_MAX);- if (r != LZMA_OK) {- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,- "lzma initialization failed(%d)", r);-- return (ARCHIVE_FAILED);- }-- /* Flag the cleanup function that we want our lzma-related structures- * to be freed later. */- zip->zipx_lzma_valid = 1;-- /* The "lzma alone" file format and the stream format inside ZIPx are- * almost the same. Here's an example of a structure of "lzma alone"- * format:- *- * $ cat /bin/ls | lzma | xxd | head -n 1- * 00000000: 5d00 0080 00ff ffff ffff ffff ff00 2814- *- * 5 bytes 8 bytes n bytes- * <lzma_params><uncompressed_size><data...>- *- * lzma_params is a 5-byte blob that has to be decoded to extract- * parameters of this LZMA stream. The uncompressed_size field is an- * uint64_t value that contains information about the size of the- * uncompressed file, or UINT64_MAX if this value is unknown.- * The <data...> part is the actual lzma-compressed data stream.- *- * Now here's the structure of the stream inside the ZIPX file:- *- * $ cat stream_inside_zipx | xxd | head -n 1- * 00000000: 0914 0500 5d00 8000 0000 2814 .... ....- *- * 2byte 2byte 5 bytes n bytes- * <magic1><magic2><lzma_params><data...>- *- * This means that the ZIPX file contains an additional magic1 and- * magic2 headers, the lzma_params field contains the same parameter- * set as in the "lzma alone" format, and the <data...> field is the- * same as in the "lzma alone" format as well. Note that also the zipx- * format is missing the uncompressed_size field.- *- * So, in order to use the "lzma alone" decoder for the zipx lzma- * stream, we simply need to shuffle around some fields, prepare a new- * lzma alone header, feed it into lzma alone decoder so it will- * initialize itself properly, and then we can start feeding normal- * zipx lzma stream into the decoder.- */-- /* Read magic1,magic2,lzma_params from the ZIPX stream. */- if(zip->entry_bytes_remaining < 9 || (p = __archive_read_ahead(a, 9, NULL)) == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated lzma data");- return (ARCHIVE_FATAL);- }-- if(p[2] != 0x05 || p[3] != 0x00) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid lzma data");- return (ARCHIVE_FATAL);- }-- /* Prepare an lzma alone header: copy the lzma_params blob into- * a proper place into the lzma alone header. */- memcpy(&alone_header.bytes[0], p + 4, 5);-- /* Initialize the 'uncompressed size' field to unknown; we'll manually- * monitor how many bytes there are still to be uncompressed. */- alone_header.uncompressed_size = UINT64_MAX;-- if(!zip->uncompressed_buffer) {- zip->uncompressed_buffer_size = 256 * 1024;- zip->uncompressed_buffer =- (uint8_t*) malloc(zip->uncompressed_buffer_size);-- if (zip->uncompressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for lzma decompression");- return (ARCHIVE_FATAL);- }- }-- zip->zipx_lzma_stream.next_in = (void*) &alone_header;- zip->zipx_lzma_stream.avail_in = sizeof(alone_header);- zip->zipx_lzma_stream.total_in = 0;- zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;- zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;- zip->zipx_lzma_stream.total_out = 0;-- /* Feed only the header into the lzma alone decoder. This will- * effectively initialize the decoder, and will not produce any- * output bytes yet. */- r = lzma_code(&zip->zipx_lzma_stream, LZMA_RUN);- if (r != LZMA_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "lzma stream initialization error");- return ARCHIVE_FATAL;- }-- /* We've already consumed some bytes, so take this into account. */- __archive_read_consume(a, 9);- zip->entry_bytes_remaining -= 9;- zip->entry_compressed_bytes_read += 9;-- zip->decompress_init = 1;- return (ARCHIVE_OK);-}--static int-zip_read_data_zipx_xz(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset)-{- struct zip* zip = (struct zip *)(a->format->data);- int ret;- lzma_ret lz_ret;- const void* compressed_buf;- ssize_t bytes_avail, in_bytes, to_consume = 0;-- (void) offset; /* UNUSED */-- /* Initialize decompressor if not yet initialized. */- if (!zip->decompress_init) {- ret = zipx_xz_init(a, zip);- if (ret != ARCHIVE_OK)- return (ret);- }-- compressed_buf = __archive_read_ahead(a, 1, &bytes_avail);- if (bytes_avail < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated xz file body");- return (ARCHIVE_FATAL);- }-- in_bytes = zipmin(zip->entry_bytes_remaining, bytes_avail);- zip->zipx_lzma_stream.next_in = compressed_buf;- zip->zipx_lzma_stream.avail_in = in_bytes;- zip->zipx_lzma_stream.total_in = 0;- zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;- zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;- zip->zipx_lzma_stream.total_out = 0;-- /* Perform the decompression. */- lz_ret = lzma_code(&zip->zipx_lzma_stream, LZMA_RUN);- switch(lz_ret) {- case LZMA_DATA_ERROR:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "xz data error (error %d)", (int) lz_ret);- return (ARCHIVE_FATAL);-- case LZMA_NO_CHECK:- case LZMA_OK:- break;-- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "xz unknown error %d", (int) lz_ret);- return (ARCHIVE_FATAL);-- case LZMA_STREAM_END:- lzma_end(&zip->zipx_lzma_stream);- zip->zipx_lzma_valid = 0;-- if((int64_t) zip->zipx_lzma_stream.total_in !=- zip->entry_bytes_remaining)- {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xz premature end of stream");- return (ARCHIVE_FATAL);- }-- zip->end_of_entry = 1;- break;- }-- to_consume = zip->zipx_lzma_stream.total_in;-- __archive_read_consume(a, to_consume);- zip->entry_bytes_remaining -= to_consume;- zip->entry_compressed_bytes_read += to_consume;- zip->entry_uncompressed_bytes_read += zip->zipx_lzma_stream.total_out;-- *size = zip->zipx_lzma_stream.total_out;- *buff = zip->uncompressed_buffer;-- ret = consume_optional_marker(a, zip);- if (ret != ARCHIVE_OK)- return (ret);-- return (ARCHIVE_OK);-}--static int-zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset)-{- struct zip* zip = (struct zip *)(a->format->data);- int ret;- lzma_ret lz_ret;- const void* compressed_buf;- ssize_t bytes_avail, in_bytes, to_consume;-- (void) offset; /* UNUSED */-- /* Initialize decompressor if not yet initialized. */- if (!zip->decompress_init) {- ret = zipx_lzma_alone_init(a, zip);- if (ret != ARCHIVE_OK)- return (ret);- }-- /* Fetch more compressed data. The same note as in deflate handler- * applies here as well:- *- * Note: '1' here is a performance optimization. Recall that the- * decompression layer returns a count of available bytes; asking for- * more than that forces the decompressor to combine reads by copying- * data.- */- compressed_buf = __archive_read_ahead(a, 1, &bytes_avail);- if (bytes_avail < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated lzma file body");- return (ARCHIVE_FATAL);- }-- /* Set decompressor parameters. */- in_bytes = zipmin(zip->entry_bytes_remaining, bytes_avail);-- zip->zipx_lzma_stream.next_in = compressed_buf;- zip->zipx_lzma_stream.avail_in = in_bytes;- zip->zipx_lzma_stream.total_in = 0;- zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;- zip->zipx_lzma_stream.avail_out =- /* These lzma_alone streams lack end of stream marker, so let's- * make sure the unpacker won't try to unpack more than it's- * supposed to. */- zipmin((int64_t) zip->uncompressed_buffer_size,- zip->entry->uncompressed_size -- zip->entry_uncompressed_bytes_read);- zip->zipx_lzma_stream.total_out = 0;-- /* Perform the decompression. */- lz_ret = lzma_code(&zip->zipx_lzma_stream, LZMA_RUN);- switch(lz_ret) {- case LZMA_DATA_ERROR:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "lzma data error (error %d)", (int) lz_ret);- return (ARCHIVE_FATAL);-- /* This case is optional in lzma alone format. It can happen,- * but most of the files don't have it. (GitHub #1257) */- case LZMA_STREAM_END:- lzma_end(&zip->zipx_lzma_stream);- zip->zipx_lzma_valid = 0;- if((int64_t) zip->zipx_lzma_stream.total_in !=- zip->entry_bytes_remaining)- {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "lzma alone premature end of stream");- return (ARCHIVE_FATAL);- }-- zip->end_of_entry = 1;- break;-- case LZMA_OK:- break;-- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "lzma unknown error %d", (int) lz_ret);- return (ARCHIVE_FATAL);- }-- to_consume = zip->zipx_lzma_stream.total_in;-- /* Update pointers. */- __archive_read_consume(a, to_consume);- zip->entry_bytes_remaining -= to_consume;- zip->entry_compressed_bytes_read += to_consume;- zip->entry_uncompressed_bytes_read += zip->zipx_lzma_stream.total_out;-- if(zip->entry_bytes_remaining == 0) {- zip->end_of_entry = 1;- }-- /* Return values. */- *size = zip->zipx_lzma_stream.total_out;- *buff = zip->uncompressed_buffer;-- /* Behave the same way as during deflate decompression. */- ret = consume_optional_marker(a, zip);- if (ret != ARCHIVE_OK)- return (ret);-- /* Free lzma decoder handle because we'll no longer need it. */- if(zip->end_of_entry) {- lzma_end(&zip->zipx_lzma_stream);- zip->zipx_lzma_valid = 0;- }-- /* If we're here, then we're good! */- return (ARCHIVE_OK);-}-#endif /* HAVE_LZMA_H && HAVE_LIBLZMA */--static int-zipx_ppmd8_init(struct archive_read *a, struct zip *zip)-{- const void* p;- uint32_t val;- uint32_t order;- uint32_t mem;- uint32_t restore_method;-- /* Remove previous decompression context if it exists. */- if(zip->ppmd8_valid) {- __archive_ppmd8_functions.Ppmd8_Free(&zip->ppmd8);- zip->ppmd8_valid = 0;- }-- /* Create a new decompression context. */- __archive_ppmd8_functions.Ppmd8_Construct(&zip->ppmd8);- zip->ppmd8_stream_failed = 0;-- /* Setup function pointers required by Ppmd8 decompressor. The- * 'ppmd_read' function will feed new bytes to the decompressor,- * and will increment the 'zip->zipx_ppmd_read_compressed' counter. */- zip->ppmd8.Stream.In = &zip->zipx_ppmd_stream;- zip->zipx_ppmd_stream.a = a;- zip->zipx_ppmd_stream.Read = &ppmd_read;-- /* Reset number of read bytes to 0. */- zip->zipx_ppmd_read_compressed = 0;-- /* Read Ppmd8 header (2 bytes). */- p = __archive_read_ahead(a, 2, NULL);- if(!p) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated file data in PPMd8 stream");- return (ARCHIVE_FATAL);- }- __archive_read_consume(a, 2);-- /* Decode the stream's compression parameters. */- val = archive_le16dec(p);- order = (val & 15) + 1;- mem = ((val >> 4) & 0xff) + 1;- restore_method = (val >> 12);-- if(order < 2 || restore_method > 2) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Invalid parameter set in PPMd8 stream (order=%" PRId32 ", "- "restore=%" PRId32 ")", order, restore_method);- return (ARCHIVE_FAILED);- }-- /* Allocate the memory needed to properly decompress the file. */- if(!__archive_ppmd8_functions.Ppmd8_Alloc(&zip->ppmd8, mem << 20)) {- archive_set_error(&a->archive, ENOMEM,- "Unable to allocate memory for PPMd8 stream: %" PRId32 " bytes",- mem << 20);- return (ARCHIVE_FATAL);- }-- /* Signal the cleanup function to release Ppmd8 context in the- * cleanup phase. */- zip->ppmd8_valid = 1;-- /* Perform further Ppmd8 initialization. */- if(!__archive_ppmd8_functions.Ppmd8_RangeDec_Init(&zip->ppmd8)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,- "PPMd8 stream range decoder initialization error");- return (ARCHIVE_FATAL);- }-- __archive_ppmd8_functions.Ppmd8_Init(&zip->ppmd8, order,- restore_method);-- /* Allocate the buffer that will hold uncompressed data. */- free(zip->uncompressed_buffer);-- zip->uncompressed_buffer_size = 256 * 1024;- zip->uncompressed_buffer =- (uint8_t*) malloc(zip->uncompressed_buffer_size);-- if(zip->uncompressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for PPMd8 decompression");- return ARCHIVE_FATAL;- }-- /* Ppmd8 initialization is done. */- zip->decompress_init = 1;-- /* We've already read 2 bytes in the output stream. Additionally,- * Ppmd8 initialization code could read some data as well. So we- * are advancing the stream by 2 bytes plus whatever number of- * bytes Ppmd8 init function used. */- zip->entry_compressed_bytes_read += 2 + zip->zipx_ppmd_read_compressed;-- return ARCHIVE_OK;-}--static int-zip_read_data_zipx_ppmd(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset)-{- struct zip* zip = (struct zip *)(a->format->data);- int ret;- size_t consumed_bytes = 0;- ssize_t bytes_avail = 0;-- (void) offset; /* UNUSED */-- /* If we're here for the first time, initialize Ppmd8 decompression- * context first. */- if(!zip->decompress_init) {- ret = zipx_ppmd8_init(a, zip);- if(ret != ARCHIVE_OK)- return ret;- }-- /* Fetch for more data. We're reading 1 byte here, but libarchive- * should prefetch more bytes. */- (void) __archive_read_ahead(a, 1, &bytes_avail);- if(bytes_avail < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated PPMd8 file body");- return (ARCHIVE_FATAL);- }-- /* This counter will be updated inside ppmd_read(), which at one- * point will be called by Ppmd8_DecodeSymbol. */- zip->zipx_ppmd_read_compressed = 0;-- /* Decompression loop. */- do {- int sym = __archive_ppmd8_functions.Ppmd8_DecodeSymbol(- &zip->ppmd8);- if(sym < 0) {- zip->end_of_entry = 1;- break;- }-- /* This field is set by ppmd_read() when there was no more data- * to be read. */- if(zip->ppmd8_stream_failed) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated PPMd8 file body");- return (ARCHIVE_FATAL);- }-- zip->uncompressed_buffer[consumed_bytes] = (uint8_t) sym;- ++consumed_bytes;- } while(consumed_bytes < zip->uncompressed_buffer_size);-- /* Update pointers for libarchive. */- *buff = zip->uncompressed_buffer;- *size = consumed_bytes;-- /* Update pointers so we can continue decompression in another call. */- zip->entry_bytes_remaining -= zip->zipx_ppmd_read_compressed;- zip->entry_compressed_bytes_read += zip->zipx_ppmd_read_compressed;- zip->entry_uncompressed_bytes_read += consumed_bytes;-- /* If we're at the end of stream, deinitialize Ppmd8 context. */- if(zip->end_of_entry) {- __archive_ppmd8_functions.Ppmd8_Free(&zip->ppmd8);- zip->ppmd8_valid = 0;- }-- /* Seek for optional marker, same way as in each zip entry. */- ret = consume_optional_marker(a, zip);- if (ret != ARCHIVE_OK)- return ret;-- return ARCHIVE_OK;-}--#ifdef HAVE_BZLIB_H-static int-zipx_bzip2_init(struct archive_read *a, struct zip *zip)-{- int r;-- /* Deallocate already existing BZ2 decompression context if it- * exists. */- if(zip->bzstream_valid) {- BZ2_bzDecompressEnd(&zip->bzstream);- zip->bzstream_valid = 0;- }-- /* Allocate a new BZ2 decompression context. */- memset(&zip->bzstream, 0, sizeof(bz_stream));- r = BZ2_bzDecompressInit(&zip->bzstream, 0, 1);- if(r != BZ_OK) {- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,- "bzip2 initialization failed(%d)",- r);-- return ARCHIVE_FAILED;- }-- /* Mark the bzstream field to be released in cleanup phase. */- zip->bzstream_valid = 1;-- /* (Re)allocate the buffer that will contain decompressed bytes. */- free(zip->uncompressed_buffer);-- zip->uncompressed_buffer_size = 256 * 1024;- zip->uncompressed_buffer =- (uint8_t*) malloc(zip->uncompressed_buffer_size);- if (zip->uncompressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for bzip2 decompression");- return ARCHIVE_FATAL;- }-- /* Initialization done. */- zip->decompress_init = 1;- return ARCHIVE_OK;-}--static int-zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset)-{- struct zip *zip = (struct zip *)(a->format->data);- ssize_t bytes_avail = 0, in_bytes, to_consume;- const void *compressed_buff;- int r;- uint64_t total_out;-- (void) offset; /* UNUSED */-- /* Initialize decompression context if we're here for the first time. */- if(!zip->decompress_init) {- r = zipx_bzip2_init(a, zip);- if(r != ARCHIVE_OK)- return r;- }-- /* Fetch more compressed bytes. */- compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);- if(bytes_avail < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated bzip2 file body");- return (ARCHIVE_FATAL);- }-- in_bytes = zipmin(zip->entry_bytes_remaining, bytes_avail);- if(in_bytes < 1) {- /* libbz2 doesn't complain when caller feeds avail_in == 0.- * It will actually return success in this case, which is- * undesirable. This is why we need to make this check- * manually. */-- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated bzip2 file body");- return (ARCHIVE_FATAL);- }-- /* Setup buffer boundaries. */- zip->bzstream.next_in = (char*)(uintptr_t) compressed_buff;- zip->bzstream.avail_in = (uint32_t)in_bytes;- zip->bzstream.total_in_hi32 = 0;- zip->bzstream.total_in_lo32 = 0;- zip->bzstream.next_out = (char*) zip->uncompressed_buffer;- zip->bzstream.avail_out = (uint32_t)zip->uncompressed_buffer_size;- zip->bzstream.total_out_hi32 = 0;- zip->bzstream.total_out_lo32 = 0;-- /* Perform the decompression. */- r = BZ2_bzDecompress(&zip->bzstream);- switch(r) {- case BZ_STREAM_END:- /* If we're at the end of the stream, deinitialize the- * decompression context now. */- switch(BZ2_bzDecompressEnd(&zip->bzstream)) {- case BZ_OK:- break;- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to clean up bzip2 "- "decompressor");- return ARCHIVE_FATAL;- }-- zip->end_of_entry = 1;- break;- case BZ_OK:- /* The decompressor has successfully decoded this- * chunk of data, but more data is still in queue. */- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "bzip2 decompression failed");- return ARCHIVE_FATAL;- }-- /* Update the pointers so decompressor can continue decoding. */- to_consume = zip->bzstream.total_in_lo32;- __archive_read_consume(a, to_consume);-- total_out = ((uint64_t) zip->bzstream.total_out_hi32 << 32) |- zip->bzstream.total_out_lo32;-- zip->entry_bytes_remaining -= to_consume;- zip->entry_compressed_bytes_read += to_consume;- zip->entry_uncompressed_bytes_read += total_out;-- /* Give libarchive its due. */- *size = total_out;- *buff = zip->uncompressed_buffer;-- /* Seek for optional marker, like in other entries. */- r = consume_optional_marker(a, zip);- if(r != ARCHIVE_OK)- return r;-- return ARCHIVE_OK;-}--#endif--#if HAVE_ZSTD_H && HAVE_LIBZSTD-static int-zipx_zstd_init(struct archive_read *a, struct zip *zip)-{- size_t r;-- /* Deallocate already existing Zstd decompression context if it- * exists. */- if(zip->zstdstream_valid) {- ZSTD_freeDStream(zip->zstdstream);- zip->zstdstream_valid = 0;- }-- /* Allocate a new Zstd decompression context. */- zip->zstdstream = ZSTD_createDStream();-- r = ZSTD_initDStream(zip->zstdstream);- if (ZSTD_isError(r)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Error initializing zstd decompressor: %s",- ZSTD_getErrorName(r));-- return ARCHIVE_FAILED;- }-- /* Mark the zstdstream field to be released in cleanup phase. */- zip->zstdstream_valid = 1;-- /* (Re)allocate the buffer that will contain decompressed bytes. */- free(zip->uncompressed_buffer);-- zip->uncompressed_buffer_size = ZSTD_DStreamOutSize();- zip->uncompressed_buffer =- (uint8_t*) malloc(zip->uncompressed_buffer_size);- if (zip->uncompressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for Zstd decompression");-- return ARCHIVE_FATAL;- }-- /* Initialization done. */- zip->decompress_init = 1;- return ARCHIVE_OK;-}--static int-zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset)-{- struct zip *zip = (struct zip *)(a->format->data);- ssize_t bytes_avail = 0, in_bytes, to_consume;- const void *compressed_buff;- int r;- size_t ret;- uint64_t total_out;- ZSTD_outBuffer out;- ZSTD_inBuffer in;-- (void) offset; /* UNUSED */-- /* Initialize decompression context if we're here for the first time. */- if(!zip->decompress_init) {- r = zipx_zstd_init(a, zip);- if(r != ARCHIVE_OK)- return r;- }-- /* Fetch more compressed bytes */- compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);- if(bytes_avail < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated zstd file body");- return (ARCHIVE_FATAL);- }-- in_bytes = zipmin(zip->entry_bytes_remaining, bytes_avail);- if(in_bytes < 1) {- /* zstd doesn't complain when caller feeds avail_in == 0.- * It will actually return success in this case, which is- * undesirable. This is why we need to make this check- * manually. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated zstd file body");- return (ARCHIVE_FATAL);- }-- /* Setup buffer boundaries */- in.src = compressed_buff;- in.size = in_bytes;- in.pos = 0;- out = (ZSTD_outBuffer) { zip->uncompressed_buffer, zip->uncompressed_buffer_size, 0 };-- /* Perform the decompression. */- ret = ZSTD_decompressStream(zip->zstdstream, &out, &in);- if (ZSTD_isError(ret)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Error during zstd decompression: %s",- ZSTD_getErrorName(ret));- return (ARCHIVE_FATAL);- }-- /* Check end of the stream. */- if (ret == 0) {- if ((in.pos == in.size) && (out.pos < out.size)) {- zip->end_of_entry = 1;- ZSTD_freeDStream(zip->zstdstream);- zip->zstdstream_valid = 0;- }- }-- /* Update the pointers so decompressor can continue decoding. */- to_consume = in.pos;- __archive_read_consume(a, to_consume);-- total_out = out.pos;-- zip->entry_bytes_remaining -= to_consume;- zip->entry_compressed_bytes_read += to_consume;- zip->entry_uncompressed_bytes_read += total_out;-- /* Give libarchive its due. */- *size = total_out;- *buff = zip->uncompressed_buffer;-- /* Seek for optional marker, like in other entries. */- r = consume_optional_marker(a, zip);- if(r != ARCHIVE_OK)- return r;-- return ARCHIVE_OK;-}-#endif--#ifdef HAVE_ZLIB_H-static int-zip_deflate_init(struct archive_read *a, struct zip *zip)-{- int r;-- /* If we haven't yet read any data, initialize the decompressor. */- if (!zip->decompress_init) {- if (zip->stream_valid)- r = inflateReset(&zip->stream);- else- r = inflateInit2(&zip->stream,- -15 /* Don't check for zlib header */);- if (r != Z_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't initialize ZIP decompression.");- return (ARCHIVE_FATAL);- }- /* Stream structure has been set up. */- zip->stream_valid = 1;- /* We've initialized decompression for this stream. */- zip->decompress_init = 1;- }- return (ARCHIVE_OK);-}--static int-zip_read_data_deflate(struct archive_read *a, const void **buff,- size_t *size, int64_t *offset)-{- struct zip *zip;- ssize_t bytes_avail;- const void *compressed_buff, *sp;- int r;-- (void)offset; /* UNUSED */-- zip = (struct zip *)(a->format->data);-- /* If the buffer hasn't been allocated, allocate it now. */- if (zip->uncompressed_buffer == NULL) {- zip->uncompressed_buffer_size = 256 * 1024;- zip->uncompressed_buffer- = (unsigned char *)malloc(zip->uncompressed_buffer_size);- if (zip->uncompressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for ZIP decompression");- return (ARCHIVE_FATAL);- }- }-- r = zip_deflate_init(a, zip);- if (r != ARCHIVE_OK)- return (r);-- /*- * Note: '1' here is a performance optimization.- * Recall that the decompression layer returns a count of- * available bytes; asking for more than that forces the- * decompressor to combine reads by copying data.- */- compressed_buff = sp = __archive_read_ahead(a, 1, &bytes_avail);- if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)- && bytes_avail > zip->entry_bytes_remaining) {- bytes_avail = (ssize_t)zip->entry_bytes_remaining;- }- if (bytes_avail < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file body");- return (ARCHIVE_FATAL);- }-- if (zip->tctx_valid || zip->cctx_valid) {- if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) {- size_t buff_remaining =- (zip->decrypted_buffer +- zip->decrypted_buffer_size)- - (zip->decrypted_ptr +- zip->decrypted_bytes_remaining);-- if (buff_remaining > (size_t)bytes_avail)- buff_remaining = (size_t)bytes_avail;-- if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END) &&- zip->entry_bytes_remaining > 0) {- if ((int64_t)(zip->decrypted_bytes_remaining- + buff_remaining)- > zip->entry_bytes_remaining) {- if (zip->entry_bytes_remaining <- (int64_t)zip->decrypted_bytes_remaining)- buff_remaining = 0;- else- buff_remaining =- (size_t)zip->entry_bytes_remaining- - zip->decrypted_bytes_remaining;- }- }- if (buff_remaining > 0) {- if (zip->tctx_valid) {- trad_enc_decrypt_update(&zip->tctx,- compressed_buff, buff_remaining,- zip->decrypted_ptr- + zip->decrypted_bytes_remaining,- buff_remaining);- } else {- size_t dsize = buff_remaining;- archive_decrypto_aes_ctr_update(- &zip->cctx,- compressed_buff, buff_remaining,- zip->decrypted_ptr- + zip->decrypted_bytes_remaining,- &dsize);- }- zip->decrypted_bytes_remaining +=- buff_remaining;- }- }- bytes_avail = zip->decrypted_bytes_remaining;- compressed_buff = (const char *)zip->decrypted_ptr;- }-- /*- * A bug in zlib.h: stream.next_in should be marked 'const'- * but isn't (the library never alters data through the- * next_in pointer, only reads it). The result: this ugly- * cast to remove 'const'.- */- zip->stream.next_in = (Bytef *)(uintptr_t)(const void *)compressed_buff;- zip->stream.avail_in = (uInt)bytes_avail;- zip->stream.total_in = 0;- zip->stream.next_out = zip->uncompressed_buffer;- zip->stream.avail_out = (uInt)zip->uncompressed_buffer_size;- zip->stream.total_out = 0;-- r = inflate(&zip->stream, 0);- switch (r) {- case Z_OK:- break;- case Z_STREAM_END:- zip->end_of_entry = 1;- break;- case Z_MEM_ERROR:- archive_set_error(&a->archive, ENOMEM,- "Out of memory for ZIP decompression");- return (ARCHIVE_FATAL);- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "ZIP decompression failed (%d)", r);- return (ARCHIVE_FATAL);- }-- /* Consume as much as the compressor actually used. */- bytes_avail = zip->stream.total_in;- if (zip->tctx_valid || zip->cctx_valid) {- zip->decrypted_bytes_remaining -= bytes_avail;- if (zip->decrypted_bytes_remaining == 0)- zip->decrypted_ptr = zip->decrypted_buffer;- else- zip->decrypted_ptr += bytes_avail;- }- /* Calculate compressed data as much as we used.*/- if (zip->hctx_valid)- archive_hmac_sha1_update(&zip->hctx, sp, bytes_avail);- __archive_read_consume(a, bytes_avail);- zip->entry_bytes_remaining -= bytes_avail;- zip->entry_compressed_bytes_read += bytes_avail;-- *size = zip->stream.total_out;- zip->entry_uncompressed_bytes_read += zip->stream.total_out;- *buff = zip->uncompressed_buffer;-- if (zip->end_of_entry && zip->hctx_valid) {- r = check_authentication_code(a, NULL);- if (r != ARCHIVE_OK)- return (r);- }-- r = consume_optional_marker(a, zip);- if (r != ARCHIVE_OK)- return (r);-- return (ARCHIVE_OK);-}-#endif--static int-read_decryption_header(struct archive_read *a)-{- struct zip *zip = (struct zip *)(a->format->data);- const char *p;- unsigned int remaining_size;- unsigned int ts;-- /*- * Read an initialization vector data field.- */- p = __archive_read_ahead(a, 2, NULL);- if (p == NULL)- goto truncated;- ts = zip->iv_size;- zip->iv_size = archive_le16dec(p);- __archive_read_consume(a, 2);- if (ts < zip->iv_size) {- free(zip->iv);- zip->iv = NULL;- }- p = __archive_read_ahead(a, zip->iv_size, NULL);- if (p == NULL)- goto truncated;- if (zip->iv == NULL) {- zip->iv = malloc(zip->iv_size);- if (zip->iv == NULL)- goto nomem;- }- memcpy(zip->iv, p, zip->iv_size);- __archive_read_consume(a, zip->iv_size);-- /*- * Read a size of remaining decryption header field.- */- p = __archive_read_ahead(a, 14, NULL);- if (p == NULL)- goto truncated;- remaining_size = archive_le32dec(p);- if (remaining_size < 16 || remaining_size > (1 << 18))- goto corrupted;-- /* Check if format version is supported. */- if (archive_le16dec(p+4) != 3) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported encryption format version: %u",- archive_le16dec(p+4));- return (ARCHIVE_FAILED);- }-- /*- * Read an encryption algorithm field.- */- zip->alg_id = archive_le16dec(p+6);- switch (zip->alg_id) {- case 0x6601:/* DES */- case 0x6602:/* RC2 */- case 0x6603:/* 3DES 168 */- case 0x6609:/* 3DES 112 */- case 0x660E:/* AES 128 */- case 0x660F:/* AES 192 */- case 0x6610:/* AES 256 */- case 0x6702:/* RC2 (version >= 5.2) */- case 0x6720:/* Blowfish */- case 0x6721:/* Twofish */- case 0x6801:/* RC4 */- /* Supported encryption algorithm. */- break;- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unknown encryption algorithm: %u", zip->alg_id);- return (ARCHIVE_FAILED);- }-- /*- * Read a bit length field.- */- zip->bit_len = archive_le16dec(p+8);-- /*- * Read a flags field.- */- zip->flags = archive_le16dec(p+10);- switch (zip->flags & 0xf000) {- case 0x0001: /* Password is required to decrypt. */- case 0x0002: /* Certificates only. */- case 0x0003: /* Password or certificate required to decrypt. */- break;- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unknown encryption flag: %u", zip->flags);- return (ARCHIVE_FAILED);- }- if ((zip->flags & 0xf000) == 0 ||- (zip->flags & 0xf000) == 0x4000) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Unknown encryption flag: %u", zip->flags);- return (ARCHIVE_FAILED);- }-- /*- * Read an encrypted random data field.- */- ts = zip->erd_size;- zip->erd_size = archive_le16dec(p+12);- __archive_read_consume(a, 14);- if ((zip->erd_size & 0xf) != 0 ||- (zip->erd_size + 16) > remaining_size ||- (zip->erd_size + 16) < zip->erd_size)- goto corrupted;-- if (ts < zip->erd_size) {- free(zip->erd);- zip->erd = NULL;- }- p = __archive_read_ahead(a, zip->erd_size, NULL);- if (p == NULL)- goto truncated;- if (zip->erd == NULL) {- zip->erd = malloc(zip->erd_size);- if (zip->erd == NULL)- goto nomem;- }- memcpy(zip->erd, p, zip->erd_size);- __archive_read_consume(a, zip->erd_size);-- /*- * Read a reserved data field.- */- p = __archive_read_ahead(a, 4, NULL);- if (p == NULL)- goto truncated;- /* Reserved data size should be zero. */- if (archive_le32dec(p) != 0)- goto corrupted;- __archive_read_consume(a, 4);-- /*- * Read a password validation data field.- */- p = __archive_read_ahead(a, 2, NULL);- if (p == NULL)- goto truncated;- ts = zip->v_size;- zip->v_size = archive_le16dec(p);- __archive_read_consume(a, 2);- if ((zip->v_size & 0x0f) != 0 ||- (zip->erd_size + zip->v_size + 16) > remaining_size ||- (zip->erd_size + zip->v_size + 16) < (zip->erd_size + zip->v_size))- goto corrupted;- if (ts < zip->v_size) {- free(zip->v_data);- zip->v_data = NULL;- }- p = __archive_read_ahead(a, zip->v_size, NULL);- if (p == NULL)- goto truncated;- if (zip->v_data == NULL) {- zip->v_data = malloc(zip->v_size);- if (zip->v_data == NULL)- goto nomem;- }- memcpy(zip->v_data, p, zip->v_size);- __archive_read_consume(a, zip->v_size);-- p = __archive_read_ahead(a, 4, NULL);- if (p == NULL)- goto truncated;- zip->v_crc32 = archive_le32dec(p);- __archive_read_consume(a, 4);-- /*return (ARCHIVE_OK);- * This is not fully implemented yet.*/- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Encrypted file is unsupported");- return (ARCHIVE_FAILED);-truncated:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file data");- return (ARCHIVE_FATAL);-corrupted:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Corrupted ZIP file data");- return (ARCHIVE_FATAL);-nomem:- archive_set_error(&a->archive, ENOMEM,- "No memory for ZIP decryption");- return (ARCHIVE_FATAL);-}--static int-zip_alloc_decryption_buffer(struct archive_read *a)-{- struct zip *zip = (struct zip *)(a->format->data);- size_t bs = 256 * 1024;-- if (zip->decrypted_buffer == NULL) {- zip->decrypted_buffer_size = bs;- zip->decrypted_buffer = malloc(bs);- if (zip->decrypted_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for ZIP decryption");- return (ARCHIVE_FATAL);- }- }- zip->decrypted_ptr = zip->decrypted_buffer;- return (ARCHIVE_OK);-}--static int-init_traditional_PKWARE_decryption(struct archive_read *a)-{- struct zip *zip = (struct zip *)(a->format->data);- const void *p;- int retry;- int r;-- if (zip->tctx_valid)- return (ARCHIVE_OK);-- /*- Read the 12 bytes encryption header stored at- the start of the data area.- */-#define ENC_HEADER_SIZE 12- if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)- && zip->entry_bytes_remaining < ENC_HEADER_SIZE) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated Zip encrypted body: only %jd bytes available",- (intmax_t)zip->entry_bytes_remaining);- return (ARCHIVE_FATAL);- }-- p = __archive_read_ahead(a, ENC_HEADER_SIZE, NULL);- if (p == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file data");- return (ARCHIVE_FATAL);- }-- for (retry = 0;; retry++) {- const char *passphrase;- uint8_t crcchk;-- passphrase = __archive_read_next_passphrase(a);- if (passphrase == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- (retry > 0)?- "Incorrect passphrase":- "Passphrase required for this entry");- return (ARCHIVE_FAILED);- }-- /*- * Initialize ctx for Traditional PKWARE Decryption.- */- r = trad_enc_init(&zip->tctx, passphrase, strlen(passphrase),- p, ENC_HEADER_SIZE, &crcchk);- if (r == 0 && crcchk == zip->entry->decdat)- break;/* The passphrase is OK. */- if (retry > 10000) {- /* Avoid infinity loop. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Too many incorrect passphrases");- return (ARCHIVE_FAILED);- }- }-- __archive_read_consume(a, ENC_HEADER_SIZE);- zip->tctx_valid = 1;- if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {- zip->entry_bytes_remaining -= ENC_HEADER_SIZE;- }- /*zip->entry_uncompressed_bytes_read += ENC_HEADER_SIZE;*/- zip->entry_compressed_bytes_read += ENC_HEADER_SIZE;- zip->decrypted_bytes_remaining = 0;-- return (zip_alloc_decryption_buffer(a));-#undef ENC_HEADER_SIZE-}--static int-init_WinZip_AES_decryption(struct archive_read *a)-{- struct zip *zip = (struct zip *)(a->format->data);- const void *p;- const uint8_t *pv;- size_t key_len, salt_len;- uint8_t derived_key[MAX_DERIVED_KEY_BUF_SIZE];- int retry;- int r;-- if (zip->cctx_valid || zip->hctx_valid)- return (ARCHIVE_OK);-- switch (zip->entry->aes_extra.strength) {- case 1: salt_len = 8; key_len = 16; break;- case 2: salt_len = 12; key_len = 24; break;- case 3: salt_len = 16; key_len = 32; break;- default: goto corrupted;- }- p = __archive_read_ahead(a, salt_len + 2, NULL);- if (p == NULL)- goto truncated;-- for (retry = 0;; retry++) {- const char *passphrase;-- passphrase = __archive_read_next_passphrase(a);- if (passphrase == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- (retry > 0)?- "Incorrect passphrase":- "Passphrase required for this entry");- return (ARCHIVE_FAILED);- }- memset(derived_key, 0, sizeof(derived_key));- r = archive_pbkdf2_sha1(passphrase, strlen(passphrase),- p, salt_len, 1000, derived_key, key_len * 2 + 2);- if (r != 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Decryption is unsupported due to lack of "- "crypto library");- return (ARCHIVE_FAILED);- }-- /* Check password verification value. */- pv = ((const uint8_t *)p) + salt_len;- if (derived_key[key_len * 2] == pv[0] &&- derived_key[key_len * 2 + 1] == pv[1])- break;/* The passphrase is OK. */- if (retry > 10000) {- /* Avoid infinity loop. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Too many incorrect passphrases");- return (ARCHIVE_FAILED);- }- }-- r = archive_decrypto_aes_ctr_init(&zip->cctx, derived_key, key_len);- if (r != 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Decryption is unsupported due to lack of crypto library");- return (ARCHIVE_FAILED);- }- r = archive_hmac_sha1_init(&zip->hctx, derived_key + key_len, key_len);- if (r != 0) {- archive_decrypto_aes_ctr_release(&zip->cctx);- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to initialize HMAC-SHA1");- return (ARCHIVE_FAILED);- }- zip->cctx_valid = zip->hctx_valid = 1;- __archive_read_consume(a, salt_len + 2);- zip->entry_bytes_remaining -= salt_len + 2 + AUTH_CODE_SIZE;- if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)- && zip->entry_bytes_remaining < 0)- goto corrupted;- zip->entry_compressed_bytes_read += salt_len + 2 + AUTH_CODE_SIZE;- zip->decrypted_bytes_remaining = 0;-- zip->entry->compression = zip->entry->aes_extra.compression;- return (zip_alloc_decryption_buffer(a));--truncated:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file data");- return (ARCHIVE_FATAL);-corrupted:- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Corrupted ZIP file data");- return (ARCHIVE_FATAL);-}--static int-archive_read_format_zip_read_data(struct archive_read *a,- const void **buff, size_t *size, int64_t *offset)-{- int r;- struct zip *zip = (struct zip *)(a->format->data);-- if (zip->has_encrypted_entries ==- ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {- zip->has_encrypted_entries = 0;- }-- *offset = zip->entry_uncompressed_bytes_read;- *size = 0;- *buff = NULL;-- /* If we hit end-of-entry last time, return ARCHIVE_EOF. */- if (zip->end_of_entry)- return (ARCHIVE_EOF);-- /* Return EOF immediately if this is a non-regular file. */- if (AE_IFREG != (zip->entry->mode & AE_IFMT))- return (ARCHIVE_EOF);-- __archive_read_consume(a, zip->unconsumed);- zip->unconsumed = 0;-- if (zip->init_decryption) {- zip->has_encrypted_entries = 1;- if (zip->entry->zip_flags & ZIP_STRONG_ENCRYPTED)- r = read_decryption_header(a);- else if (zip->entry->compression == WINZIP_AES_ENCRYPTION)- r = init_WinZip_AES_decryption(a);- else- r = init_traditional_PKWARE_decryption(a);- if (r != ARCHIVE_OK)- return (r);- zip->init_decryption = 0;- }-- switch(zip->entry->compression) {- case 0: /* No compression. */- r = zip_read_data_none(a, buff, size, offset);- break;-#ifdef HAVE_BZLIB_H- case 12: /* ZIPx bzip2 compression. */- r = zip_read_data_zipx_bzip2(a, buff, size, offset);- break;-#endif-#if HAVE_LZMA_H && HAVE_LIBLZMA- case 14: /* ZIPx LZMA compression. */- r = zip_read_data_zipx_lzma_alone(a, buff, size, offset);- break;- case 95: /* ZIPx XZ compression. */- r = zip_read_data_zipx_xz(a, buff, size, offset);- break;-#endif-#if HAVE_ZSTD_H && HAVE_LIBZSTD- case 93: /* ZIPx Zstd compression. */- r = zip_read_data_zipx_zstd(a, buff, size, offset);- break;-#endif- /* PPMd support is built-in, so we don't need any #if guards. */- case 98: /* ZIPx PPMd compression. */- r = zip_read_data_zipx_ppmd(a, buff, size, offset);- break;--#ifdef HAVE_ZLIB_H- case 8: /* Deflate compression. */- r = zip_read_data_deflate(a, buff, size, offset);- break;-#endif- default: /* Unsupported compression. */- /* Return a warning. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported ZIP compression method (%d: %s)",- zip->entry->compression, compression_name(zip->entry->compression));- /* We can't decompress this entry, but we will- * be able to skip() it and try the next entry. */- return (ARCHIVE_FAILED);- break;- }- if (r != ARCHIVE_OK)- return (r);- /* Update checksum */- if (*size)- zip->entry_crc32 = zip->crc32func(zip->entry_crc32, *buff,- (unsigned)*size);- /* If we hit the end, swallow any end-of-data marker. */- if (zip->end_of_entry) {- /* Check file size, CRC against these values. */- if (zip->entry->compressed_size !=- zip->entry_compressed_bytes_read) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "ZIP compressed data is wrong size "- "(read %jd, expected %jd)",- (intmax_t)zip->entry_compressed_bytes_read,- (intmax_t)zip->entry->compressed_size);- return (ARCHIVE_WARN);- }- /* Size field only stores the lower 32 bits of the actual- * size. */- if ((zip->entry->uncompressed_size & UINT32_MAX)- != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "ZIP uncompressed data is wrong size "- "(read %jd, expected %jd)\n",- (intmax_t)zip->entry_uncompressed_bytes_read,- (intmax_t)zip->entry->uncompressed_size);- return (ARCHIVE_WARN);- }- /* Check computed CRC against header */- if ((!zip->hctx_valid ||- zip->entry->aes_extra.vendor != AES_VENDOR_AE_2) &&- zip->entry->crc32 != zip->entry_crc32- && !zip->ignore_crc32) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "ZIP bad CRC: 0x%lx should be 0x%lx",- (unsigned long)zip->entry_crc32,- (unsigned long)zip->entry->crc32);- return (ARCHIVE_WARN);- }- }-- return (ARCHIVE_OK);-}--static int-archive_read_format_zip_cleanup(struct archive_read *a)-{- struct zip *zip;- struct zip_entry *zip_entry, *next_zip_entry;-- zip = (struct zip *)(a->format->data);--#ifdef HAVE_ZLIB_H- if (zip->stream_valid)- inflateEnd(&zip->stream);-#endif--#if HAVE_LZMA_H && HAVE_LIBLZMA- if (zip->zipx_lzma_valid) {- lzma_end(&zip->zipx_lzma_stream);- }-#endif--#ifdef HAVE_BZLIB_H- if (zip->bzstream_valid) {- BZ2_bzDecompressEnd(&zip->bzstream);- }-#endif--#if HAVE_ZSTD_H && HAVE_LIBZSTD- if (zip->zstdstream_valid) {- ZSTD_freeDStream(zip->zstdstream);- }-#endif-- free(zip->uncompressed_buffer);-- if (zip->ppmd8_valid)- __archive_ppmd8_functions.Ppmd8_Free(&zip->ppmd8);-- if (zip->zip_entries) {- zip_entry = zip->zip_entries;- while (zip_entry != NULL) {- next_zip_entry = zip_entry->next;- archive_string_free(&zip_entry->rsrcname);- free(zip_entry);- zip_entry = next_zip_entry;- }- }- free(zip->decrypted_buffer);- if (zip->cctx_valid)- archive_decrypto_aes_ctr_release(&zip->cctx);- if (zip->hctx_valid)- archive_hmac_sha1_cleanup(&zip->hctx);- free(zip->iv);- free(zip->erd);- free(zip->v_data);- archive_string_free(&zip->format_name);- free(zip);- (a->format->data) = NULL;- return (ARCHIVE_OK);-}--static int-archive_read_format_zip_has_encrypted_entries(struct archive_read *_a)-{- if (_a && _a->format) {- struct zip * zip = (struct zip *)_a->format->data;- if (zip) {- return zip->has_encrypted_entries;- }- }- return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;-}--static int-archive_read_format_zip_options(struct archive_read *a,- const char *key, const char *val)-{- struct zip *zip;- int ret = ARCHIVE_FAILED;-- zip = (struct zip *)(a->format->data);- if (strcmp(key, "compat-2x") == 0) {- /* Handle filenames as libarchive 2.x */- zip->init_default_conversion = (val != NULL) ? 1 : 0;- return (ARCHIVE_OK);- } else if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "zip: hdrcharset option needs a character-set name"- );- else {- zip->sconv = archive_string_conversion_from_charset(- &a->archive, val, 0);- if (zip->sconv != NULL) {- if (strcmp(val, "UTF-8") == 0)- zip->sconv_utf8 = zip->sconv;- ret = ARCHIVE_OK;- } else- ret = ARCHIVE_FATAL;- }- return (ret);- } else if (strcmp(key, "ignorecrc32") == 0) {- /* Mostly useful for testing. */- if (val == NULL || val[0] == 0) {- zip->crc32func = real_crc32;- zip->ignore_crc32 = 0;- } else {- zip->crc32func = fake_crc32;- zip->ignore_crc32 = 1;- }- return (ARCHIVE_OK);- } else if (strcmp(key, "mac-ext") == 0) {- zip->process_mac_extensions = (val != NULL && val[0] != 0);- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--int-archive_read_support_format_zip(struct archive *a)-{- int r;- r = archive_read_support_format_zip_streamable(a);- if (r != ARCHIVE_OK)- return r;- return (archive_read_support_format_zip_seekable(a));-}--/* ------------------------------------------------------------------------ */--/*- * Streaming-mode support- */---static int-archive_read_support_format_zip_capabilities_streamable(struct archive_read * a)-{- (void)a; /* UNUSED */- return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA |- ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);-}--static int-archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid)-{- const char *p;-- (void)best_bid; /* UNUSED */-- if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)- return (-1);-- /*- * Bid of 29 here comes from:- * + 16 bits for "PK",- * + next 16-bit field has 6 options so contributes- * about 16 - log_2(6) ~= 16 - 2.6 ~= 13 bits- *- * So we've effectively verified ~29 total bits of check data.- */- if (p[0] == 'P' && p[1] == 'K') {- if ((p[2] == '\001' && p[3] == '\002')- || (p[2] == '\003' && p[3] == '\004')- || (p[2] == '\005' && p[3] == '\006')- || (p[2] == '\006' && p[3] == '\006')- || (p[2] == '\007' && p[3] == '\010')- || (p[2] == '0' && p[3] == '0'))- return (29);- }-- /* TODO: It's worth looking ahead a little bit for a valid- * PK signature. In particular, that would make it possible- * to read some UUEncoded SFX files or SFX files coming from- * a network socket. */-- return (0);-}--static int-archive_read_format_zip_streamable_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct zip *zip;-- a->archive.archive_format = ARCHIVE_FORMAT_ZIP;- if (a->archive.archive_format_name == NULL)- a->archive.archive_format_name = "ZIP";-- zip = (struct zip *)(a->format->data);-- /*- * It should be sufficient to call archive_read_next_header() for- * a reader to determine if an entry is encrypted or not. If the- * encryption of an entry is only detectable when calling- * archive_read_data(), so be it. We'll do the same check there- * as well.- */- if (zip->has_encrypted_entries ==- ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW)- zip->has_encrypted_entries = 0;-- /* Make sure we have a zip_entry structure to use. */- if (zip->zip_entries == NULL) {- zip->zip_entries = malloc(sizeof(struct zip_entry));- if (zip->zip_entries == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Out of memory");- return ARCHIVE_FATAL;- }- }- zip->entry = zip->zip_entries;- memset(zip->entry, 0, sizeof(struct zip_entry));-- if (zip->cctx_valid)- archive_decrypto_aes_ctr_release(&zip->cctx);- if (zip->hctx_valid)- archive_hmac_sha1_cleanup(&zip->hctx);- zip->tctx_valid = zip->cctx_valid = zip->hctx_valid = 0;- __archive_read_reset_passphrase(a);-- /* Search ahead for the next local file header. */- __archive_read_consume(a, zip->unconsumed);- zip->unconsumed = 0;- for (;;) {- int64_t skipped = 0;- const char *p, *end;- ssize_t bytes;-- p = __archive_read_ahead(a, 4, &bytes);- if (p == NULL)- return (ARCHIVE_FATAL);- end = p + bytes;-- while (p + 4 <= end) {- if (p[0] == 'P' && p[1] == 'K') {- if (p[2] == '\003' && p[3] == '\004') {- /* Regular file entry. */- __archive_read_consume(a, skipped);- return zip_read_local_file_header(a,- entry, zip);- }-- /*- * TODO: We cannot restore permissions- * based only on the local file headers.- * Consider scanning the central- * directory and returning additional- * entries for at least directories.- * This would allow us to properly set- * directory permissions.- *- * This won't help us fix symlinks- * and may not help with regular file- * permissions, either. <sigh>- */- if (p[2] == '\001' && p[3] == '\002') {- return (ARCHIVE_EOF);- }-- /* End of central directory? Must be an- * empty archive. */- if ((p[2] == '\005' && p[3] == '\006')- || (p[2] == '\006' && p[3] == '\006'))- return (ARCHIVE_EOF);- }- ++p;- ++skipped;- }- __archive_read_consume(a, skipped);- }-}--static int-archive_read_format_zip_read_data_skip_streamable(struct archive_read *a)-{- struct zip *zip;- int64_t bytes_skipped;-- zip = (struct zip *)(a->format->data);- bytes_skipped = __archive_read_consume(a, zip->unconsumed);- zip->unconsumed = 0;- if (bytes_skipped < 0)- return (ARCHIVE_FATAL);-- /* If we've already read to end of data, we're done. */- if (zip->end_of_entry)- return (ARCHIVE_OK);-- /* So we know we're streaming... */- if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)- || zip->entry->compressed_size > 0) {- /* We know the compressed length, so we can just skip. */- bytes_skipped = __archive_read_consume(a,- zip->entry_bytes_remaining);- if (bytes_skipped < 0)- return (ARCHIVE_FATAL);- return (ARCHIVE_OK);- }-- if (zip->init_decryption) {- int r;-- zip->has_encrypted_entries = 1;- if (zip->entry->zip_flags & ZIP_STRONG_ENCRYPTED)- r = read_decryption_header(a);- else if (zip->entry->compression == WINZIP_AES_ENCRYPTION)- r = init_WinZip_AES_decryption(a);- else- r = init_traditional_PKWARE_decryption(a);- if (r != ARCHIVE_OK)- return (r);- zip->init_decryption = 0;- }-- /* We're streaming and we don't know the length. */- /* If the body is compressed and we know the format, we can- * find an exact end-of-entry by decompressing it. */- switch (zip->entry->compression) {-#ifdef HAVE_ZLIB_H- case 8: /* Deflate compression. */- while (!zip->end_of_entry) {- int64_t offset = 0;- const void *buff = NULL;- size_t size = 0;- int r;- r = zip_read_data_deflate(a, &buff, &size, &offset);- if (r != ARCHIVE_OK)- return (r);- }- return ARCHIVE_OK;-#endif- default: /* Uncompressed or unknown. */- /* Scan for a PK\007\010 signature. */- for (;;) {- const char *p, *buff;- ssize_t bytes_avail;- buff = __archive_read_ahead(a, 16, &bytes_avail);- if (bytes_avail < 16) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file data");- return (ARCHIVE_FATAL);- }- p = buff;- while (p <= buff + bytes_avail - 16) {- if (p[3] == 'P') { p += 3; }- else if (p[3] == 'K') { p += 2; }- else if (p[3] == '\007') { p += 1; }- else if (p[3] == '\010' && p[2] == '\007'- && p[1] == 'K' && p[0] == 'P') {- if (zip->entry->flags & LA_USED_ZIP64)- __archive_read_consume(a,- p - buff + 24);- else- __archive_read_consume(a,- p - buff + 16);- return ARCHIVE_OK;- } else { p += 4; }- }- __archive_read_consume(a, p - buff);- }- }-}--int-archive_read_support_format_zip_streamable(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct zip *zip;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_zip");-- zip = (struct zip *)calloc(1, sizeof(*zip));- if (zip == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate zip data");- return (ARCHIVE_FATAL);- }-- /* Streamable reader doesn't support mac extensions. */- zip->process_mac_extensions = 0;-- /*- * Until enough data has been read, we cannot tell about- * any encrypted entries yet.- */- zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;- zip->crc32func = real_crc32;-- r = __archive_read_register_format(a,- zip,- "zip",- archive_read_format_zip_streamable_bid,- archive_read_format_zip_options,- archive_read_format_zip_streamable_read_header,- archive_read_format_zip_read_data,- archive_read_format_zip_read_data_skip_streamable,- NULL,- archive_read_format_zip_cleanup,- archive_read_support_format_zip_capabilities_streamable,- archive_read_format_zip_has_encrypted_entries);-- if (r != ARCHIVE_OK)- free(zip);- return (ARCHIVE_OK);-}--/* ------------------------------------------------------------------------ */--/*- * Seeking-mode support- */--static int-archive_read_support_format_zip_capabilities_seekable(struct archive_read * a)-{- (void)a; /* UNUSED */- return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA |- ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);-}--/*- * TODO: This is a performance sink because it forces the read core to- * drop buffered data from the start of file, which will then have to- * be re-read again if this bidder loses.- *- * We workaround this a little by passing in the best bid so far so- * that later bidders can do nothing if they know they'll never- * outbid. But we can certainly do better...- */-static int-read_eocd(struct zip *zip, const char *p, int64_t current_offset)-{- uint16_t disk_num;- uint32_t cd_size, cd_offset;- - disk_num = archive_le16dec(p + 4);- cd_size = archive_le32dec(p + 12);- cd_offset = archive_le32dec(p + 16);-- /* Sanity-check the EOCD we've found. */-- /* This must be the first volume. */- if (disk_num != 0)- return 0;- /* Central directory must be on this volume. */- if (disk_num != archive_le16dec(p + 6))- return 0;- /* All central directory entries must be on this volume. */- if (archive_le16dec(p + 10) != archive_le16dec(p + 8))- return 0;- /* Central directory can't extend beyond start of EOCD record. */- if (cd_offset + cd_size > current_offset)- return 0;-- /* Save the central directory location for later use. */- zip->central_directory_offset = cd_offset;- zip->central_directory_offset_adjusted = current_offset - cd_size;-- /* This is just a tiny bit higher than the maximum- returned by the streaming Zip bidder. This ensures- that the more accurate seeking Zip parser wins- whenever seek is available. */- return 32;-}--/*- * Examine Zip64 EOCD locator: If it's valid, store the information- * from it.- */-static int-read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p)-{- int64_t eocd64_offset;- int64_t eocd64_size;-- /* Sanity-check the locator record. */-- /* Central dir must be on first volume. */- if (archive_le32dec(p + 4) != 0)- return 0;- /* Must be only a single volume. */- if (archive_le32dec(p + 16) != 1)- return 0;-- /* Find the Zip64 EOCD record. */- eocd64_offset = archive_le64dec(p + 8);- if (__archive_read_seek(a, eocd64_offset, SEEK_SET) < 0)- return 0;- if ((p = __archive_read_ahead(a, 56, NULL)) == NULL)- return 0;- /* Make sure we can read all of it. */- eocd64_size = archive_le64dec(p + 4) + 12;- if (eocd64_size < 56 || eocd64_size > 16384)- return 0;- if ((p = __archive_read_ahead(a, (size_t)eocd64_size, NULL)) == NULL)- return 0;-- /* Sanity-check the EOCD64 */- if (archive_le32dec(p + 16) != 0) /* Must be disk #0 */- return 0;- if (archive_le32dec(p + 20) != 0) /* CD must be on disk #0 */- return 0;- /* CD can't be split. */- if (archive_le64dec(p + 24) != archive_le64dec(p + 32))- return 0;-- /* Save the central directory offset for later use. */- zip->central_directory_offset = archive_le64dec(p + 48);- /* TODO: Needs scanning backwards to find the eocd64 instead of assuming */- zip->central_directory_offset_adjusted = zip->central_directory_offset;-- return 32;-}--static int-archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)-{- struct zip *zip = (struct zip *)a->format->data;- int64_t file_size, current_offset;- const char *p;- int i, tail;-- /* If someone has already bid more than 32, then avoid- trashing the look-ahead buffers with a seek. */- if (best_bid > 32)- return (-1);-- file_size = __archive_read_seek(a, 0, SEEK_END);- if (file_size <= 0)- return 0;-- /* Search last 16k of file for end-of-central-directory- * record (which starts with PK\005\006) */- tail = (int)zipmin(1024 * 16, file_size);- current_offset = __archive_read_seek(a, -tail, SEEK_END);- if (current_offset < 0)- return 0;- if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL)- return 0;- /* Boyer-Moore search backwards from the end, since we want- * to match the last EOCD in the file (there can be more than- * one if there is an uncompressed Zip archive as a member- * within this Zip archive). */- for (i = tail - 22; i > 0;) {- switch (p[i]) {- case 'P':- if (memcmp(p + i, "PK\005\006", 4) == 0) {- int ret = read_eocd(zip, p + i,- current_offset + i);- /* Zip64 EOCD locator precedes- * regular EOCD if present. */- if (i >= 20 && memcmp(p + i - 20, "PK\006\007", 4) == 0) {- int ret_zip64 = read_zip64_eocd(a, zip, p + i - 20);- if (ret_zip64 > ret)- ret = ret_zip64;- }- return (ret);- }- i -= 4;- break;- case 'K': i -= 1; break;- case 005: i -= 2; break;- case 006: i -= 3; break;- default: i -= 4; break;- }- }- return 0;-}--/* The red-black trees are only used in seeking mode to manage- * the in-memory copy of the central directory. */--static int-cmp_node(const struct archive_rb_node *n1, const struct archive_rb_node *n2)-{- const struct zip_entry *e1 = (const struct zip_entry *)n1;- const struct zip_entry *e2 = (const struct zip_entry *)n2;-- if (e1->local_header_offset > e2->local_header_offset)- return -1;- if (e1->local_header_offset < e2->local_header_offset)- return 1;- return 0;-}--static int-cmp_key(const struct archive_rb_node *n, const void *key)-{- /* This function won't be called */- (void)n; /* UNUSED */- (void)key; /* UNUSED */- return 1;-}--static const struct archive_rb_tree_ops rb_ops = {- &cmp_node, &cmp_key-};--static int-rsrc_cmp_node(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- const struct zip_entry *e1 = (const struct zip_entry *)n1;- const struct zip_entry *e2 = (const struct zip_entry *)n2;-- return (strcmp(e2->rsrcname.s, e1->rsrcname.s));-}--static int-rsrc_cmp_key(const struct archive_rb_node *n, const void *key)-{- const struct zip_entry *e = (const struct zip_entry *)n;- return (strcmp((const char *)key, e->rsrcname.s));-}--static const struct archive_rb_tree_ops rb_rsrc_ops = {- &rsrc_cmp_node, &rsrc_cmp_key-};--static const char *-rsrc_basename(const char *name, size_t name_length)-{- const char *s, *r;-- r = s = name;- for (;;) {- s = memchr(s, '/', name_length - (s - name));- if (s == NULL)- break;- r = ++s;- }- return (r);-}--static void-expose_parent_dirs(struct zip *zip, const char *name, size_t name_length)-{- struct archive_string str;- struct zip_entry *dir;- char *s;-- archive_string_init(&str);- archive_strncpy(&str, name, name_length);- for (;;) {- s = strrchr(str.s, '/');- if (s == NULL)- break;- *s = '\0';- /* Transfer the parent directory from zip->tree_rsrc RB- * tree to zip->tree RB tree to expose. */- dir = (struct zip_entry *)- __archive_rb_tree_find_node(&zip->tree_rsrc, str.s);- if (dir == NULL)- break;- __archive_rb_tree_remove_node(&zip->tree_rsrc, &dir->node);- archive_string_free(&dir->rsrcname);- __archive_rb_tree_insert_node(&zip->tree, &dir->node);- }- archive_string_free(&str);-}--static int-slurp_central_directory(struct archive_read *a, struct archive_entry* entry,- struct zip *zip)-{- ssize_t i;- unsigned found;- int64_t correction;- ssize_t bytes_avail;- const char *p;-- /*- * Find the start of the central directory. The end-of-CD- * record has our starting point, but there are lots of- * Zip archives which have had other data prepended to the- * file, which makes the recorded offsets all too small.- * So we search forward from the specified offset until we- * find the real start of the central directory. Then we- * know the correction we need to apply to account for leading- * padding.- */- if (__archive_read_seek(a, zip->central_directory_offset_adjusted, SEEK_SET)- < 0)- return ARCHIVE_FATAL;-- found = 0;- while (!found) {- if ((p = __archive_read_ahead(a, 20, &bytes_avail)) == NULL)- return ARCHIVE_FATAL;- for (found = 0, i = 0; !found && i < bytes_avail - 4;) {- switch (p[i + 3]) {- case 'P': i += 3; break;- case 'K': i += 2; break;- case 001: i += 1; break;- case 002:- if (memcmp(p + i, "PK\001\002", 4) == 0) {- p += i;- found = 1;- } else- i += 4;- break;- case 005: i += 1; break;- case 006:- if (memcmp(p + i, "PK\005\006", 4) == 0) {- p += i;- found = 1;- } else if (memcmp(p + i, "PK\006\006", 4) == 0) {- p += i;- found = 1;- } else- i += 1;- break;- default: i += 4; break;- }- }- __archive_read_consume(a, i);- }- correction = archive_filter_bytes(&a->archive, 0)- - zip->central_directory_offset;-- __archive_rb_tree_init(&zip->tree, &rb_ops);- __archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops);-- zip->central_directory_entries_total = 0;- while (1) {- struct zip_entry *zip_entry;- size_t filename_length, extra_length, comment_length;- uint32_t external_attributes;- const char *name, *r;-- if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)- return ARCHIVE_FATAL;- if (memcmp(p, "PK\006\006", 4) == 0- || memcmp(p, "PK\005\006", 4) == 0) {- break;- } else if (memcmp(p, "PK\001\002", 4) != 0) {- archive_set_error(&a->archive,- -1, "Invalid central directory signature");- return ARCHIVE_FATAL;- }- if ((p = __archive_read_ahead(a, 46, NULL)) == NULL)- return ARCHIVE_FATAL;-- zip_entry = calloc(1, sizeof(struct zip_entry));- if (zip_entry == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate zip entry");- return ARCHIVE_FATAL;- }- zip_entry->next = zip->zip_entries;- zip_entry->flags |= LA_FROM_CENTRAL_DIRECTORY;- zip->zip_entries = zip_entry;- zip->central_directory_entries_total++;-- /* version = p[4]; */- zip_entry->system = p[5];- /* version_required = archive_le16dec(p + 6); */- zip_entry->zip_flags = archive_le16dec(p + 8);- if (zip_entry->zip_flags- & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)){- zip->has_encrypted_entries = 1;- }- zip_entry->compression = (char)archive_le16dec(p + 10);- zip_entry->mtime = zip_time(p + 12);- zip_entry->crc32 = archive_le32dec(p + 16);- if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)- zip_entry->decdat = p[13];- else- zip_entry->decdat = p[19];- zip_entry->compressed_size = archive_le32dec(p + 20);- zip_entry->uncompressed_size = archive_le32dec(p + 24);- filename_length = archive_le16dec(p + 28);- extra_length = archive_le16dec(p + 30);- comment_length = archive_le16dec(p + 32);- /* disk_start = archive_le16dec(p + 34);- * Better be zero.- * internal_attributes = archive_le16dec(p + 36);- * text bit */- external_attributes = archive_le32dec(p + 38);- zip_entry->local_header_offset =- archive_le32dec(p + 42) + correction;-- /* If we can't guess the mode, leave it zero here;- when we read the local file header we might get- more information. */- if (zip_entry->system == 3) {- zip_entry->mode = external_attributes >> 16;- } else if (zip_entry->system == 0) {- // Interpret MSDOS directory bit- if (0x10 == (external_attributes & 0x10)) {- zip_entry->mode = AE_IFDIR | 0775;- } else {- zip_entry->mode = AE_IFREG | 0664;- }- if (0x01 == (external_attributes & 0x01)) {- // Read-only bit; strip write permissions- zip_entry->mode &= 0555;- }- } else {- zip_entry->mode = 0;- }-- /* We're done with the regular data; get the filename and- * extra data. */- __archive_read_consume(a, 46);- p = __archive_read_ahead(a, filename_length + extra_length,- NULL);- if (p == NULL) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file header");- return ARCHIVE_FATAL;- }- if (ARCHIVE_OK != process_extra(a, entry, p + filename_length,- extra_length, zip_entry)) {- return ARCHIVE_FATAL;- }-- /*- * Mac resource fork files are stored under the- * "__MACOSX/" directory, so we should check if- * it is.- */- if (!zip->process_mac_extensions) {- /* Treat every entry as a regular entry. */- __archive_rb_tree_insert_node(&zip->tree,- &zip_entry->node);- } else {- name = p;- r = rsrc_basename(name, filename_length);- if (filename_length >= 9 &&- strncmp("__MACOSX/", name, 9) == 0) {- /* If this file is not a resource fork nor- * a directory. We should treat it as a non- * resource fork file to expose it. */- if (name[filename_length-1] != '/' &&- (r - name < 3 || r[0] != '.' ||- r[1] != '_')) {- __archive_rb_tree_insert_node(- &zip->tree, &zip_entry->node);- /* Expose its parent directories. */- expose_parent_dirs(zip, name,- filename_length);- } else {- /* This file is a resource fork file or- * a directory. */- archive_strncpy(&(zip_entry->rsrcname),- name, filename_length);- __archive_rb_tree_insert_node(- &zip->tree_rsrc, &zip_entry->node);- }- } else {- /* Generate resource fork name to find its- * resource file at zip->tree_rsrc. */- archive_strcpy(&(zip_entry->rsrcname),- "__MACOSX/");- archive_strncat(&(zip_entry->rsrcname),- name, r - name);- archive_strcat(&(zip_entry->rsrcname), "._");- archive_strncat(&(zip_entry->rsrcname),- name + (r - name),- filename_length - (r - name));- /* Register an entry to RB tree to sort it by- * file offset. */- __archive_rb_tree_insert_node(&zip->tree,- &zip_entry->node);- }- }-- /* Skip the comment too ... */- __archive_read_consume(a,- filename_length + extra_length + comment_length);- }-- return ARCHIVE_OK;-}--static ssize_t-zip_get_local_file_header_size(struct archive_read *a, size_t extra)-{- const char *p;- ssize_t filename_length, extra_length;-- if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file header");- return (ARCHIVE_WARN);- }- p += extra;-- if (memcmp(p, "PK\003\004", 4) != 0) {- archive_set_error(&a->archive, -1, "Damaged Zip archive");- return ARCHIVE_WARN;- }- filename_length = archive_le16dec(p + 26);- extra_length = archive_le16dec(p + 28);-- return (30 + filename_length + extra_length);-}--static int-zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,- struct zip_entry *rsrc)-{- struct zip *zip = (struct zip *)a->format->data;- unsigned char *metadata, *mp;- int64_t offset = archive_filter_bytes(&a->archive, 0);- size_t remaining_bytes, metadata_bytes;- ssize_t hsize;- int ret = ARCHIVE_OK, eof;-- switch(rsrc->compression) {- case 0: /* No compression. */- if (rsrc->uncompressed_size != rsrc->compressed_size) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Malformed OS X metadata entry: "- "inconsistent size");- return (ARCHIVE_FATAL);- }-#ifdef HAVE_ZLIB_H- case 8: /* Deflate compression. */-#endif- break;- default: /* Unsupported compression. */- /* Return a warning. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Unsupported ZIP compression method (%s)",- compression_name(rsrc->compression));- /* We can't decompress this entry, but we will- * be able to skip() it and try the next entry. */- return (ARCHIVE_WARN);- }-- if (rsrc->uncompressed_size > (4 * 1024 * 1024)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Mac metadata is too large: %jd > 4M bytes",- (intmax_t)rsrc->uncompressed_size);- return (ARCHIVE_WARN);- }- if (rsrc->compressed_size > (4 * 1024 * 1024)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Mac metadata is too large: %jd > 4M bytes",- (intmax_t)rsrc->compressed_size);- return (ARCHIVE_WARN);- }-- metadata = malloc((size_t)rsrc->uncompressed_size);- if (metadata == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Mac metadata");- return (ARCHIVE_FATAL);- }-- if (offset < rsrc->local_header_offset)- __archive_read_consume(a, rsrc->local_header_offset - offset);- else if (offset != rsrc->local_header_offset) {- __archive_read_seek(a, rsrc->local_header_offset, SEEK_SET);- }-- hsize = zip_get_local_file_header_size(a, 0);- __archive_read_consume(a, hsize);-- remaining_bytes = (size_t)rsrc->compressed_size;- metadata_bytes = (size_t)rsrc->uncompressed_size;- mp = metadata;- eof = 0;- while (!eof && remaining_bytes) {- const unsigned char *p;- ssize_t bytes_avail;- size_t bytes_used;-- p = __archive_read_ahead(a, 1, &bytes_avail);- if (p == NULL) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Truncated ZIP file header");- ret = ARCHIVE_WARN;- goto exit_mac_metadata;- }- if ((size_t)bytes_avail > remaining_bytes)- bytes_avail = remaining_bytes;- switch(rsrc->compression) {- case 0: /* No compression. */- if ((size_t)bytes_avail > metadata_bytes)- bytes_avail = metadata_bytes;- memcpy(mp, p, bytes_avail);- bytes_used = (size_t)bytes_avail;- metadata_bytes -= bytes_used;- mp += bytes_used;- if (metadata_bytes == 0)- eof = 1;- break;-#ifdef HAVE_ZLIB_H- case 8: /* Deflate compression. */- {- int r;-- ret = zip_deflate_init(a, zip);- if (ret != ARCHIVE_OK)- goto exit_mac_metadata;- zip->stream.next_in =- (Bytef *)(uintptr_t)(const void *)p;- zip->stream.avail_in = (uInt)bytes_avail;- zip->stream.total_in = 0;- zip->stream.next_out = mp;- zip->stream.avail_out = (uInt)metadata_bytes;- zip->stream.total_out = 0;-- r = inflate(&zip->stream, 0);- switch (r) {- case Z_OK:- break;- case Z_STREAM_END:- eof = 1;- break;- case Z_MEM_ERROR:- archive_set_error(&a->archive, ENOMEM,- "Out of memory for ZIP decompression");- ret = ARCHIVE_FATAL;- goto exit_mac_metadata;- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "ZIP decompression failed (%d)", r);- ret = ARCHIVE_FATAL;- goto exit_mac_metadata;- }- bytes_used = zip->stream.total_in;- metadata_bytes -= zip->stream.total_out;- mp += zip->stream.total_out;- break;- }-#endif- default:- bytes_used = 0;- break;- }- __archive_read_consume(a, bytes_used);- remaining_bytes -= bytes_used;- }- archive_entry_copy_mac_metadata(entry, metadata,- (size_t)rsrc->uncompressed_size - metadata_bytes);--exit_mac_metadata:- __archive_read_seek(a, offset, SEEK_SET);- zip->decompress_init = 0;- free(metadata);- return (ret);-}--static int-archive_read_format_zip_seekable_read_header(struct archive_read *a,- struct archive_entry *entry)-{- struct zip *zip = (struct zip *)a->format->data;- struct zip_entry *rsrc;- int64_t offset;- int r, ret = ARCHIVE_OK;-- /*- * It should be sufficient to call archive_read_next_header() for- * a reader to determine if an entry is encrypted or not. If the- * encryption of an entry is only detectable when calling- * archive_read_data(), so be it. We'll do the same check there- * as well.- */- if (zip->has_encrypted_entries ==- ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW)- zip->has_encrypted_entries = 0;-- a->archive.archive_format = ARCHIVE_FORMAT_ZIP;- if (a->archive.archive_format_name == NULL)- a->archive.archive_format_name = "ZIP";-- if (zip->zip_entries == NULL) {- r = slurp_central_directory(a, entry, zip);- if (r != ARCHIVE_OK)- return r;- /* Get first entry whose local header offset is lower than- * other entries in the archive file. */- zip->entry =- (struct zip_entry *)ARCHIVE_RB_TREE_MIN(&zip->tree);- } else if (zip->entry != NULL) {- /* Get next entry in local header offset order. */- zip->entry = (struct zip_entry *)__archive_rb_tree_iterate(- &zip->tree, &zip->entry->node, ARCHIVE_RB_DIR_RIGHT);- }-- if (zip->entry == NULL)- return ARCHIVE_EOF;-- if (zip->entry->rsrcname.s)- rsrc = (struct zip_entry *)__archive_rb_tree_find_node(- &zip->tree_rsrc, zip->entry->rsrcname.s);- else- rsrc = NULL;-- if (zip->cctx_valid)- archive_decrypto_aes_ctr_release(&zip->cctx);- if (zip->hctx_valid)- archive_hmac_sha1_cleanup(&zip->hctx);- zip->tctx_valid = zip->cctx_valid = zip->hctx_valid = 0;- __archive_read_reset_passphrase(a);-- /* File entries are sorted by the header offset, we should mostly- * use __archive_read_consume to advance a read point to avoid- * redundant data reading. */- offset = archive_filter_bytes(&a->archive, 0);- if (offset < zip->entry->local_header_offset)- __archive_read_consume(a,- zip->entry->local_header_offset - offset);- else if (offset != zip->entry->local_header_offset) {- __archive_read_seek(a, zip->entry->local_header_offset,- SEEK_SET);- }- zip->unconsumed = 0;- r = zip_read_local_file_header(a, entry, zip);- if (r != ARCHIVE_OK)- return r;- if (rsrc) {- int ret2 = zip_read_mac_metadata(a, entry, rsrc);- if (ret2 < ret)- ret = ret2;- }- return (ret);-}--/*- * We're going to seek for the next header anyway, so we don't- * need to bother doing anything here.- */-static int-archive_read_format_zip_read_data_skip_seekable(struct archive_read *a)-{- struct zip *zip;- zip = (struct zip *)(a->format->data);-- zip->unconsumed = 0;- return (ARCHIVE_OK);-}--int-archive_read_support_format_zip_seekable(struct archive *_a)-{- struct archive_read *a = (struct archive_read *)_a;- struct zip *zip;- int r;-- archive_check_magic(_a, ARCHIVE_READ_MAGIC,- ARCHIVE_STATE_NEW, "archive_read_support_format_zip_seekable");-- zip = (struct zip *)calloc(1, sizeof(*zip));- if (zip == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate zip data");- return (ARCHIVE_FATAL);- }--#ifdef HAVE_COPYFILE_H- /* Set this by default on Mac OS. */- zip->process_mac_extensions = 1;-#endif-- /*- * Until enough data has been read, we cannot tell about- * any encrypted entries yet.- */- zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;- zip->crc32func = real_crc32;-- r = __archive_read_register_format(a,- zip,- "zip",- archive_read_format_zip_seekable_bid,- archive_read_format_zip_options,- archive_read_format_zip_seekable_read_header,- archive_read_format_zip_read_data,- archive_read_format_zip_read_data_skip_seekable,- NULL,- archive_read_format_zip_cleanup,- archive_read_support_format_zip_capabilities_seekable,- archive_read_format_zip_has_encrypted_entries);-- if (r != ARCHIVE_OK)- free(zip);- return (ARCHIVE_OK);-}--/*# vim:set noet:*/
− c/archive_string.c
@@ -1,4244 +0,0 @@-/*-- * Copyright (c) 2003-2011 Tim Kientzle- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_string.c 201095 2009-12-28 02:33:22Z kientzle $");--/*- * Basic resizable string support, to simplify manipulating arbitrary-sized- * strings while minimizing heap activity.- *- * In particular, the buffer used by a string object is only grown, it- * never shrinks, so you can clear and reuse the same string object- * without incurring additional memory allocations.- */--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_ICONV_H-#include <iconv.h>-#endif-#ifdef HAVE_LANGINFO_H-#include <langinfo.h>-#endif-#ifdef HAVE_LOCALCHARSET_H-#include <localcharset.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_WCHAR_H-#include <wchar.h>-#endif-#if defined(_WIN32) && !defined(__CYGWIN__)-#include <windows.h>-#include <locale.h>-#endif--#include "archive_endian.h"-#include "archive_private.h"-#include "archive_string.h"-#include "archive_string_composition.h"--#if !defined(HAVE_WMEMCPY) && !defined(wmemcpy)-#define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))-#endif--#if !defined(HAVE_WMEMMOVE) && !defined(wmemmove)-#define wmemmove(a,b,i) (wchar_t *)memmove((a), (b), (i) * sizeof(wchar_t))-#endif--#undef max-#define max(a, b) ((a)>(b)?(a):(b))--struct archive_string_conv {- struct archive_string_conv *next;- char *from_charset;- char *to_charset;- unsigned from_cp;- unsigned to_cp;- /* Set 1 if from_charset and to_charset are the same. */- int same;- int flag;-#define SCONV_TO_CHARSET 1 /* MBS is being converted to specified- * charset. */-#define SCONV_FROM_CHARSET (1<<1) /* MBS is being converted from- * specified charset. */-#define SCONV_BEST_EFFORT (1<<2) /* Copy at least ASCII code. */-#define SCONV_WIN_CP (1<<3) /* Use Windows API for converting- * MBS. */-#define SCONV_UTF8_LIBARCHIVE_2 (1<<4) /* Incorrect UTF-8 made by libarchive- * 2.x in the wrong assumption. */-#define SCONV_NORMALIZATION_C (1<<6) /* Need normalization to be Form C.- * Before UTF-8 characters are actually- * processed. */-#define SCONV_NORMALIZATION_D (1<<7) /* Need normalization to be Form D.- * Before UTF-8 characters are actually- * processed.- * Currently this only for MAC OS X. */-#define SCONV_TO_UTF8 (1<<8) /* "to charset" side is UTF-8. */-#define SCONV_FROM_UTF8 (1<<9) /* "from charset" side is UTF-8. */-#define SCONV_TO_UTF16BE (1<<10) /* "to charset" side is UTF-16BE. */-#define SCONV_FROM_UTF16BE (1<<11) /* "from charset" side is UTF-16BE. */-#define SCONV_TO_UTF16LE (1<<12) /* "to charset" side is UTF-16LE. */-#define SCONV_FROM_UTF16LE (1<<13) /* "from charset" side is UTF-16LE. */-#define SCONV_TO_UTF16 (SCONV_TO_UTF16BE | SCONV_TO_UTF16LE)-#define SCONV_FROM_UTF16 (SCONV_FROM_UTF16BE | SCONV_FROM_UTF16LE)--#if HAVE_ICONV- iconv_t cd;- iconv_t cd_w;/* Use at archive_mstring on- * Windows. */-#endif- /* A temporary buffer for normalization. */- struct archive_string utftmp;- int (*converter[2])(struct archive_string *, const void *, size_t,- struct archive_string_conv *);- int nconverter;-};--#define CP_C_LOCALE 0 /* "C" locale only for this file. */-#define CP_UTF16LE 1200-#define CP_UTF16BE 1201--#define IS_HIGH_SURROGATE_LA(uc) ((uc) >= 0xD800 && (uc) <= 0xDBFF)-#define IS_LOW_SURROGATE_LA(uc) ((uc) >= 0xDC00 && (uc) <= 0xDFFF)-#define IS_SURROGATE_PAIR_LA(uc) ((uc) >= 0xD800 && (uc) <= 0xDFFF)-#define UNICODE_MAX 0x10FFFF-#define UNICODE_R_CHAR 0xFFFD /* Replacement character. */-/* Set U+FFFD(Replacement character) in UTF-8. */-static const char utf8_replacement_char[] = {0xef, 0xbf, 0xbd};--static struct archive_string_conv *find_sconv_object(struct archive *,- const char *, const char *);-static void add_sconv_object(struct archive *, struct archive_string_conv *);-static struct archive_string_conv *create_sconv_object(const char *,- const char *, unsigned, int);-static void free_sconv_object(struct archive_string_conv *);-static struct archive_string_conv *get_sconv_object(struct archive *,- const char *, const char *, int);-static unsigned make_codepage_from_charset(const char *);-static unsigned get_current_codepage(void);-static unsigned get_current_oemcp(void);-static size_t mbsnbytes(const void *, size_t);-static size_t utf16nbytes(const void *, size_t);-#if defined(_WIN32) && !defined(__CYGWIN__)-static int archive_wstring_append_from_mbs_in_codepage(- struct archive_wstring *, const char *, size_t,- struct archive_string_conv *);-static int archive_string_append_from_wcs_in_codepage(struct archive_string *,- const wchar_t *, size_t, struct archive_string_conv *);-static int is_big_endian(void);-static int strncat_in_codepage(struct archive_string *, const void *,- size_t, struct archive_string_conv *);-static int win_strncat_from_utf16be(struct archive_string *, const void *,- size_t, struct archive_string_conv *);-static int win_strncat_from_utf16le(struct archive_string *, const void *,- size_t, struct archive_string_conv *);-static int win_strncat_to_utf16be(struct archive_string *, const void *,- size_t, struct archive_string_conv *);-static int win_strncat_to_utf16le(struct archive_string *, const void *,- size_t, struct archive_string_conv *);-#endif-static int best_effort_strncat_from_utf16be(struct archive_string *,- const void *, size_t, struct archive_string_conv *);-static int best_effort_strncat_from_utf16le(struct archive_string *,- const void *, size_t, struct archive_string_conv *);-static int best_effort_strncat_to_utf16be(struct archive_string *,- const void *, size_t, struct archive_string_conv *);-static int best_effort_strncat_to_utf16le(struct archive_string *,- const void *, size_t, struct archive_string_conv *);-#if defined(HAVE_ICONV)-static int iconv_strncat_in_locale(struct archive_string *, const void *,- size_t, struct archive_string_conv *);-#endif-static int best_effort_strncat_in_locale(struct archive_string *,- const void *, size_t, struct archive_string_conv *);-static int _utf8_to_unicode(uint32_t *, const char *, size_t);-static int utf8_to_unicode(uint32_t *, const char *, size_t);-static inline uint32_t combine_surrogate_pair(uint32_t, uint32_t);-static int cesu8_to_unicode(uint32_t *, const char *, size_t);-static size_t unicode_to_utf8(char *, size_t, uint32_t);-static int utf16_to_unicode(uint32_t *, const char *, size_t, int);-static size_t unicode_to_utf16be(char *, size_t, uint32_t);-static size_t unicode_to_utf16le(char *, size_t, uint32_t);-static int strncat_from_utf8_libarchive2(struct archive_string *,- const void *, size_t, struct archive_string_conv *);-static int strncat_from_utf8_to_utf8(struct archive_string *, const void *,- size_t, struct archive_string_conv *);-static int archive_string_normalize_C(struct archive_string *, const void *,- size_t, struct archive_string_conv *);-static int archive_string_normalize_D(struct archive_string *, const void *,- size_t, struct archive_string_conv *);-static int archive_string_append_unicode(struct archive_string *,- const void *, size_t, struct archive_string_conv *);--static struct archive_string *-archive_string_append(struct archive_string *as, const char *p, size_t s)-{- if (archive_string_ensure(as, as->length + s + 1) == NULL)- return (NULL);- if (s)- memmove(as->s + as->length, p, s);- as->length += s;- as->s[as->length] = 0;- return (as);-}--static struct archive_wstring *-archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s)-{- if (archive_wstring_ensure(as, as->length + s + 1) == NULL)- return (NULL);- if (s)- wmemmove(as->s + as->length, p, s);- as->length += s;- as->s[as->length] = 0;- return (as);-}--struct archive_string *-archive_array_append(struct archive_string *as, const char *p, size_t s)-{- return archive_string_append(as, p, s);-}--void-archive_string_concat(struct archive_string *dest, struct archive_string *src)-{- if (archive_string_append(dest, src->s, src->length) == NULL)- __archive_errx(1, "Out of memory");-}--void-archive_wstring_concat(struct archive_wstring *dest,- struct archive_wstring *src)-{- if (archive_wstring_append(dest, src->s, src->length) == NULL)- __archive_errx(1, "Out of memory");-}--void-archive_string_free(struct archive_string *as)-{- as->length = 0;- as->buffer_length = 0;- free(as->s);- as->s = NULL;-}--void-archive_wstring_free(struct archive_wstring *as)-{- as->length = 0;- as->buffer_length = 0;- free(as->s);- as->s = NULL;-}--struct archive_wstring *-archive_wstring_ensure(struct archive_wstring *as, size_t s)-{- return (struct archive_wstring *)- archive_string_ensure((struct archive_string *)as,- s * sizeof(wchar_t));-}--/* Returns NULL on any allocation failure. */-struct archive_string *-archive_string_ensure(struct archive_string *as, size_t s)-{- char *p;- size_t new_length;-- /* If buffer is already big enough, don't reallocate. */- if (as->s && (s <= as->buffer_length))- return (as);-- /*- * Growing the buffer at least exponentially ensures that- * append operations are always linear in the number of- * characters appended. Using a smaller growth rate for- * larger buffers reduces memory waste somewhat at the cost of- * a larger constant factor.- */- if (as->buffer_length < 32)- /* Start with a minimum 32-character buffer. */- new_length = 32;- else if (as->buffer_length < 8192)- /* Buffers under 8k are doubled for speed. */- new_length = as->buffer_length + as->buffer_length;- else {- /* Buffers 8k and over grow by at least 25% each time. */- new_length = as->buffer_length + as->buffer_length / 4;- /* Be safe: If size wraps, fail. */- if (new_length < as->buffer_length) {- /* On failure, wipe the string and return NULL. */- archive_string_free(as);- errno = ENOMEM;/* Make sure errno has ENOMEM. */- return (NULL);- }- }- /*- * The computation above is a lower limit to how much we'll- * grow the buffer. In any case, we have to grow it enough to- * hold the request.- */- if (new_length < s)- new_length = s;- /* Now we can reallocate the buffer. */- p = (char *)realloc(as->s, new_length);- if (p == NULL) {- /* On failure, wipe the string and return NULL. */- archive_string_free(as);- errno = ENOMEM;/* Make sure errno has ENOMEM. */- return (NULL);- }-- as->s = p;- as->buffer_length = new_length;- return (as);-}--/*- * TODO: See if there's a way to avoid scanning- * the source string twice. Then test to see- * if it actually helps (remember that we're almost- * always called with pretty short arguments, so- * such an optimization might not help).- */-struct archive_string *-archive_strncat(struct archive_string *as, const void *_p, size_t n)-{- size_t s;- const char *p, *pp;-- p = (const char *)_p;-- /* Like strlen(p), except won't examine positions beyond p[n]. */- s = 0;- pp = p;- while (s < n && *pp) {- pp++;- s++;- }- if ((as = archive_string_append(as, p, s)) == NULL)- __archive_errx(1, "Out of memory");- return (as);-}--struct archive_wstring *-archive_wstrncat(struct archive_wstring *as, const wchar_t *p, size_t n)-{- size_t s;- const wchar_t *pp;-- /* Like strlen(p), except won't examine positions beyond p[n]. */- s = 0;- pp = p;- while (s < n && *pp) {- pp++;- s++;- }- if ((as = archive_wstring_append(as, p, s)) == NULL)- __archive_errx(1, "Out of memory");- return (as);-}--struct archive_string *-archive_strcat(struct archive_string *as, const void *p)-{- /* strcat is just strncat without an effective limit. - * Assert that we'll never get called with a source- * string over 16MB.- * TODO: Review all uses of strcat in the source- * and try to replace them with strncat().- */- return archive_strncat(as, p, 0x1000000);-}--struct archive_wstring *-archive_wstrcat(struct archive_wstring *as, const wchar_t *p)-{- /* Ditto. */- return archive_wstrncat(as, p, 0x1000000);-}--struct archive_string *-archive_strappend_char(struct archive_string *as, char c)-{- if ((as = archive_string_append(as, &c, 1)) == NULL)- __archive_errx(1, "Out of memory");- return (as);-}--struct archive_wstring *-archive_wstrappend_wchar(struct archive_wstring *as, wchar_t c)-{- if ((as = archive_wstring_append(as, &c, 1)) == NULL)- __archive_errx(1, "Out of memory");- return (as);-}--/*- * Get the "current character set" name to use with iconv.- * On FreeBSD, the empty character set name "" chooses- * the correct character encoding for the current locale,- * so this isn't necessary.- * But iconv on Mac OS 10.6 doesn't seem to handle this correctly;- * on that system, we have to explicitly call nl_langinfo()- * to get the right name. Not sure about other platforms.- *- * NOTE: GNU libiconv does not recognize the character-set name- * which some platform nl_langinfo(CODESET) returns, so we should- * use locale_charset() instead of nl_langinfo(CODESET) for GNU libiconv.- */-static const char *-default_iconv_charset(const char *charset) {- if (charset != NULL && charset[0] != '\0')- return charset;-#if HAVE_LOCALE_CHARSET && !defined(__APPLE__)- /* locale_charset() is broken on Mac OS */- return locale_charset();-#elif HAVE_NL_LANGINFO- return nl_langinfo(CODESET);-#else- return "";-#endif-}--#if defined(_WIN32) && !defined(__CYGWIN__)--/*- * Convert MBS to WCS.- * Note: returns -1 if conversion fails.- */-int-archive_wstring_append_from_mbs(struct archive_wstring *dest,- const char *p, size_t len)-{- return archive_wstring_append_from_mbs_in_codepage(dest, p, len, NULL);-}--static int-archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,- const char *s, size_t length, struct archive_string_conv *sc)-{- int count, ret = 0;- UINT from_cp;-- if (sc != NULL)- from_cp = sc->from_cp;- else- from_cp = get_current_codepage();-- if (from_cp == CP_C_LOCALE) {- /*- * "C" locale special processing.- */- wchar_t *ws;- const unsigned char *mp;-- if (NULL == archive_wstring_ensure(dest,- dest->length + length + 1))- return (-1);-- ws = dest->s + dest->length;- mp = (const unsigned char *)s;- count = 0;- while (count < (int)length && *mp) {- *ws++ = (wchar_t)*mp++;- count++;- }- } else if (sc != NULL &&- (sc->flag & (SCONV_NORMALIZATION_C | SCONV_NORMALIZATION_D))) {- /*- * Normalize UTF-8 and UTF-16BE and convert it directly- * to UTF-16 as wchar_t.- */- struct archive_string u16;- int saved_flag = sc->flag;/* save current flag. */-- if (is_big_endian())- sc->flag |= SCONV_TO_UTF16BE;- else- sc->flag |= SCONV_TO_UTF16LE;-- if (sc->flag & SCONV_FROM_UTF16) {- /*- * UTF-16BE/LE NFD ===> UTF-16 NFC- * UTF-16BE/LE NFC ===> UTF-16 NFD- */- count = (int)utf16nbytes(s, length);- } else {- /*- * UTF-8 NFD ===> UTF-16 NFC- * UTF-8 NFC ===> UTF-16 NFD- */- count = (int)mbsnbytes(s, length);- }- u16.s = (char *)dest->s;- u16.length = dest->length << 1;;- u16.buffer_length = dest->buffer_length;- if (sc->flag & SCONV_NORMALIZATION_C)- ret = archive_string_normalize_C(&u16, s, count, sc);- else- ret = archive_string_normalize_D(&u16, s, count, sc);- dest->s = (wchar_t *)u16.s;- dest->length = u16.length >> 1;- dest->buffer_length = u16.buffer_length;- sc->flag = saved_flag;/* restore the saved flag. */- return (ret);- } else if (sc != NULL && (sc->flag & SCONV_FROM_UTF16)) {- count = (int)utf16nbytes(s, length);- count >>= 1; /* to be WCS length */- /* Allocate memory for WCS. */- if (NULL == archive_wstring_ensure(dest,- dest->length + count + 1))- return (-1);- wmemcpy(dest->s + dest->length, (const wchar_t *)s, count);- if ((sc->flag & SCONV_FROM_UTF16BE) && !is_big_endian()) {- uint16_t *u16 = (uint16_t *)(dest->s + dest->length);- int b;- for (b = 0; b < count; b++) {- uint16_t val = archive_le16dec(u16+b);- archive_be16enc(u16+b, val);- }- } else if ((sc->flag & SCONV_FROM_UTF16LE) && is_big_endian()) {- uint16_t *u16 = (uint16_t *)(dest->s + dest->length);- int b;- for (b = 0; b < count; b++) {- uint16_t val = archive_be16dec(u16+b);- archive_le16enc(u16+b, val);- }- }- } else {- DWORD mbflag;- size_t buffsize;-- if (sc == NULL)- mbflag = 0;- else if (sc->flag & SCONV_FROM_CHARSET) {- /* Do not trust the length which comes from- * an archive file. */- length = mbsnbytes(s, length);- mbflag = 0;- } else- mbflag = MB_PRECOMPOSED;-- buffsize = dest->length + length + 1;- do {- /* Allocate memory for WCS. */- if (NULL == archive_wstring_ensure(dest, buffsize))- return (-1);- /* Convert MBS to WCS. */- count = MultiByteToWideChar(from_cp,- mbflag, s, (int)length, dest->s + dest->length,- (int)(dest->buffer_length >> 1) -1);- if (count == 0 &&- GetLastError() == ERROR_INSUFFICIENT_BUFFER) {- /* Expand the WCS buffer. */- buffsize = dest->buffer_length << 1;- continue;- }- if (count == 0 && length != 0)- ret = -1;- break;- } while (1);- }- dest->length += count;- dest->s[dest->length] = L'\0';- return (ret);-}--#else--/*- * Convert MBS to WCS.- * Note: returns -1 if conversion fails.- */-int-archive_wstring_append_from_mbs(struct archive_wstring *dest,- const char *p, size_t len)-{- size_t r;- int ret_val = 0;- /*- * No single byte will be more than one wide character,- * so this length estimate will always be big enough.- */- // size_t wcs_length = len;- size_t mbs_length = len;- const char *mbs = p;- wchar_t *wcs;-#if HAVE_MBRTOWC- mbstate_t shift_state;-- memset(&shift_state, 0, sizeof(shift_state));-#endif- /*- * As we decided to have wcs_length == mbs_length == len- * we can use len here instead of wcs_length- */- if (NULL == archive_wstring_ensure(dest, dest->length + len + 1))- return (-1);- wcs = dest->s + dest->length;- /*- * We cannot use mbsrtowcs/mbstowcs here because those may convert- * extra MBS when strlen(p) > len and one wide character consists of- * multi bytes.- */- while (*mbs && mbs_length > 0) {- /*- * The buffer we allocated is always big enough.- * Keep this code path in a comment if we decide to choose- * smaller wcs_length in the future- */-/*- if (wcs_length == 0) {- dest->length = wcs - dest->s;- dest->s[dest->length] = L'\0';- wcs_length = mbs_length;- if (NULL == archive_wstring_ensure(dest,- dest->length + wcs_length + 1))- return (-1);- wcs = dest->s + dest->length;- }-*/-#if HAVE_MBRTOWC- r = mbrtowc(wcs, mbs, mbs_length, &shift_state);-#else- r = mbtowc(wcs, mbs, mbs_length);-#endif- if (r == (size_t)-1 || r == (size_t)-2) {- ret_val = -1;- break;- }- if (r == 0 || r > mbs_length)- break;- wcs++;- // wcs_length--;- mbs += r;- mbs_length -= r;- }- dest->length = wcs - dest->s;- dest->s[dest->length] = L'\0';- return (ret_val);-}--#endif--#if defined(_WIN32) && !defined(__CYGWIN__)--/*- * WCS ==> MBS.- * Note: returns -1 if conversion fails.- *- * Win32 builds use WideCharToMultiByte from the Windows API.- * (Maybe Cygwin should too? WideCharToMultiByte will know a- * lot more about local character encodings than the wcrtomb()- * wrapper is going to know.)- */-int-archive_string_append_from_wcs(struct archive_string *as,- const wchar_t *w, size_t len)-{- return archive_string_append_from_wcs_in_codepage(as, w, len, NULL);-}--static int-archive_string_append_from_wcs_in_codepage(struct archive_string *as,- const wchar_t *ws, size_t len, struct archive_string_conv *sc)-{- BOOL defchar_used, *dp;- int count, ret = 0;- UINT to_cp;- int wslen = (int)len;-- if (sc != NULL)- to_cp = sc->to_cp;- else- to_cp = get_current_codepage();-- if (to_cp == CP_C_LOCALE) {- /*- * "C" locale special processing.- */- const wchar_t *wp = ws;- char *p;-- if (NULL == archive_string_ensure(as,- as->length + wslen +1))- return (-1);- p = as->s + as->length;- count = 0;- defchar_used = 0;- while (count < wslen && *wp) {- if (*wp > 255) {- *p++ = '?';- wp++;- defchar_used = 1;- } else- *p++ = (char)*wp++;- count++;- }- } else if (sc != NULL && (sc->flag & SCONV_TO_UTF16)) {- uint16_t *u16;-- if (NULL ==- archive_string_ensure(as, as->length + len * 2 + 2))- return (-1);- u16 = (uint16_t *)(as->s + as->length);- count = 0;- defchar_used = 0;- if (sc->flag & SCONV_TO_UTF16BE) {- while (count < (int)len && *ws) {- archive_be16enc(u16+count, *ws);- ws++;- count++;- }- } else {- while (count < (int)len && *ws) {- archive_le16enc(u16+count, *ws);- ws++;- count++;- }- }- count <<= 1; /* to be byte size */- } else {- /* Make sure the MBS buffer has plenty to set. */- if (NULL ==- archive_string_ensure(as, as->length + len * 2 + 1))- return (-1);- do {- defchar_used = 0;- if (to_cp == CP_UTF8 || sc == NULL)- dp = NULL;- else- dp = &defchar_used;- count = WideCharToMultiByte(to_cp, 0, ws, wslen,- as->s + as->length,- (int)as->buffer_length - (int)as->length - 1, NULL, dp);- if (count == 0 &&- GetLastError() == ERROR_INSUFFICIENT_BUFFER) {- /* Expand the MBS buffer and retry. */- if (NULL == archive_string_ensure(as,- as->buffer_length + len))- return (-1);- continue;- }- if (count == 0)- ret = -1;- break;- } while (1);- }- as->length += count;- as->s[as->length] = '\0';- return (defchar_used?-1:ret);-}--#elif defined(HAVE_WCTOMB) || defined(HAVE_WCRTOMB)--/*- * Translates a wide character string into current locale character set- * and appends to the archive_string. Note: returns -1 if conversion- * fails.- */-int-archive_string_append_from_wcs(struct archive_string *as,- const wchar_t *w, size_t len)-{- /* We cannot use the standard wcstombs() here because it- * cannot tell us how big the output buffer should be. So- * I've built a loop around wcrtomb() or wctomb() that- * converts a character at a time and resizes the string as- * needed. We prefer wcrtomb() when it's available because- * it's thread-safe. */- int n, ret_val = 0;- char *p;- char *end;-#if HAVE_WCRTOMB- mbstate_t shift_state;-- memset(&shift_state, 0, sizeof(shift_state));-#else- /* Clear the shift state before starting. */- wctomb(NULL, L'\0');-#endif- /*- * Allocate buffer for MBS.- * We need this allocation here since it is possible that- * as->s is still NULL.- */- if (archive_string_ensure(as, as->length + len + 1) == NULL)- return (-1);-- p = as->s + as->length;- end = as->s + as->buffer_length - MB_CUR_MAX -1;- while (*w != L'\0' && len > 0) {- if (p >= end) {- as->length = p - as->s;- as->s[as->length] = '\0';- /* Re-allocate buffer for MBS. */- if (archive_string_ensure(as,- as->length + max(len * 2,- (size_t)MB_CUR_MAX) + 1) == NULL)- return (-1);- p = as->s + as->length;- end = as->s + as->buffer_length - MB_CUR_MAX -1;- }-#if HAVE_WCRTOMB- n = wcrtomb(p, *w++, &shift_state);-#else- n = wctomb(p, *w++);-#endif- if (n == -1) {- if (errno == EILSEQ) {- /* Skip an illegal wide char. */- *p++ = '?';- ret_val = -1;- } else {- ret_val = -1;- break;- }- } else- p += n;- len--;- }- as->length = p - as->s;- as->s[as->length] = '\0';- return (ret_val);-}--#else /* HAVE_WCTOMB || HAVE_WCRTOMB */--/*- * TODO: Test if __STDC_ISO_10646__ is defined.- * Non-Windows uses ISO C wcrtomb() or wctomb() to perform the conversion- * one character at a time. If a non-Windows platform doesn't have- * either of these, fall back to the built-in UTF8 conversion.- */-int-archive_string_append_from_wcs(struct archive_string *as,- const wchar_t *w, size_t len)-{- (void)as;/* UNUSED */- (void)w;/* UNUSED */- (void)len;/* UNUSED */- errno = ENOSYS;- return (-1);-}--#endif /* HAVE_WCTOMB || HAVE_WCRTOMB */--/*- * Find a string conversion object by a pair of 'from' charset name- * and 'to' charset name from an archive object.- * Return NULL if not found.- */-static struct archive_string_conv *-find_sconv_object(struct archive *a, const char *fc, const char *tc)-{- struct archive_string_conv *sc; -- if (a == NULL)- return (NULL);-- for (sc = a->sconv; sc != NULL; sc = sc->next) {- if (strcmp(sc->from_charset, fc) == 0 &&- strcmp(sc->to_charset, tc) == 0)- break;- }- return (sc);-}--/*- * Register a string object to an archive object.- */-static void-add_sconv_object(struct archive *a, struct archive_string_conv *sc)-{- struct archive_string_conv **psc; -- /* Add a new sconv to sconv list. */- psc = &(a->sconv);- while (*psc != NULL)- psc = &((*psc)->next);- *psc = sc;-}--static void-add_converter(struct archive_string_conv *sc, int (*converter)- (struct archive_string *, const void *, size_t,- struct archive_string_conv *))-{- if (sc == NULL || sc->nconverter >= 2)- __archive_errx(1, "Programming error");- sc->converter[sc->nconverter++] = converter;-}--static void-setup_converter(struct archive_string_conv *sc)-{-- /* Reset. */- sc->nconverter = 0;-- /*- * Perform special sequence for the incorrect UTF-8 filenames- * made by libarchive2.x.- */- if (sc->flag & SCONV_UTF8_LIBARCHIVE_2) {- add_converter(sc, strncat_from_utf8_libarchive2);- return;- }-- /*- * Convert a string to UTF-16BE/LE.- */- if (sc->flag & SCONV_TO_UTF16) {- /*- * If the current locale is UTF-8, we can translate- * a UTF-8 string into a UTF-16BE string.- */- if (sc->flag & SCONV_FROM_UTF8) {- add_converter(sc, archive_string_append_unicode);- return;- }--#if defined(_WIN32) && !defined(__CYGWIN__)- if (sc->flag & SCONV_WIN_CP) {- if (sc->flag & SCONV_TO_UTF16BE)- add_converter(sc, win_strncat_to_utf16be);- else- add_converter(sc, win_strncat_to_utf16le);- return;- }-#endif--#if defined(HAVE_ICONV)- if (sc->cd != (iconv_t)-1) {- add_converter(sc, iconv_strncat_in_locale);- return;- }-#endif-- if (sc->flag & SCONV_BEST_EFFORT) {- if (sc->flag & SCONV_TO_UTF16BE)- add_converter(sc,- best_effort_strncat_to_utf16be);- else- add_converter(sc,- best_effort_strncat_to_utf16le);- } else- /* Make sure we have no converter. */- sc->nconverter = 0;- return;- }-- /*- * Convert a string from UTF-16BE/LE.- */- if (sc->flag & SCONV_FROM_UTF16) {- /*- * At least we should normalize a UTF-16BE string.- */- if (sc->flag & SCONV_NORMALIZATION_D)- add_converter(sc,archive_string_normalize_D);- else if (sc->flag & SCONV_NORMALIZATION_C)- add_converter(sc, archive_string_normalize_C);-- if (sc->flag & SCONV_TO_UTF8) {- /*- * If the current locale is UTF-8, we can translate- * a UTF-16BE/LE string into a UTF-8 string directly.- */- if (!(sc->flag &- (SCONV_NORMALIZATION_D |SCONV_NORMALIZATION_C)))- add_converter(sc,- archive_string_append_unicode);- return;- }--#if defined(_WIN32) && !defined(__CYGWIN__)- if (sc->flag & SCONV_WIN_CP) {- if (sc->flag & SCONV_FROM_UTF16BE)- add_converter(sc, win_strncat_from_utf16be);- else- add_converter(sc, win_strncat_from_utf16le);- return;- }-#endif--#if defined(HAVE_ICONV)- if (sc->cd != (iconv_t)-1) {- add_converter(sc, iconv_strncat_in_locale);- return;- }-#endif-- if ((sc->flag & (SCONV_BEST_EFFORT | SCONV_FROM_UTF16BE))- == (SCONV_BEST_EFFORT | SCONV_FROM_UTF16BE))- add_converter(sc, best_effort_strncat_from_utf16be);- else if ((sc->flag & (SCONV_BEST_EFFORT | SCONV_FROM_UTF16LE))- == (SCONV_BEST_EFFORT | SCONV_FROM_UTF16LE))- add_converter(sc, best_effort_strncat_from_utf16le);- else- /* Make sure we have no converter. */- sc->nconverter = 0;- return;- }-- if (sc->flag & SCONV_FROM_UTF8) {- /*- * At least we should normalize a UTF-8 string.- */- if (sc->flag & SCONV_NORMALIZATION_D)- add_converter(sc,archive_string_normalize_D);- else if (sc->flag & SCONV_NORMALIZATION_C)- add_converter(sc, archive_string_normalize_C);-- /*- * Copy UTF-8 string with a check of CESU-8.- * Apparently, iconv does not check surrogate pairs in UTF-8- * when both from-charset and to-charset are UTF-8, and then- * we use our UTF-8 copy code.- */- if (sc->flag & SCONV_TO_UTF8) {- /*- * If the current locale is UTF-8, we can translate- * a UTF-16BE string into a UTF-8 string directly.- */- if (!(sc->flag &- (SCONV_NORMALIZATION_D |SCONV_NORMALIZATION_C)))- add_converter(sc, strncat_from_utf8_to_utf8);- return;- }- }--#if defined(_WIN32) && !defined(__CYGWIN__)- /*- * On Windows we can use Windows API for a string conversion.- */- if (sc->flag & SCONV_WIN_CP) {- add_converter(sc, strncat_in_codepage);- return;- }-#endif--#if HAVE_ICONV- if (sc->cd != (iconv_t)-1) {- add_converter(sc, iconv_strncat_in_locale);- /*- * iconv generally does not support UTF-8-MAC and so- * we have to the output of iconv from NFC to NFD if- * need.- */- if ((sc->flag & SCONV_FROM_CHARSET) &&- (sc->flag & SCONV_TO_UTF8)) {- if (sc->flag & SCONV_NORMALIZATION_D)- add_converter(sc, archive_string_normalize_D);- }- return;- }-#endif-- /*- * Try conversion in the best effort or no conversion.- */- if ((sc->flag & SCONV_BEST_EFFORT) || sc->same)- add_converter(sc, best_effort_strncat_in_locale);- else- /* Make sure we have no converter. */- sc->nconverter = 0;-}--/*- * Return canonicalized charset-name but this supports just UTF-8, UTF-16BE- * and CP932 which are referenced in create_sconv_object().- */-static const char *-canonical_charset_name(const char *charset)-{- char cs[16];- char *p;- const char *s;-- if (charset == NULL || charset[0] == '\0'- || strlen(charset) > 15)- return (charset);-- /* Copy name to uppercase. */- p = cs;- s = charset;- while (*s) {- char c = *s++;- if (c >= 'a' && c <= 'z')- c -= 'a' - 'A';- *p++ = c;- }- *p++ = '\0';-- if (strcmp(cs, "UTF-8") == 0 ||- strcmp(cs, "UTF8") == 0)- return ("UTF-8");- if (strcmp(cs, "UTF-16BE") == 0 ||- strcmp(cs, "UTF16BE") == 0)- return ("UTF-16BE");- if (strcmp(cs, "UTF-16LE") == 0 ||- strcmp(cs, "UTF16LE") == 0)- return ("UTF-16LE");- if (strcmp(cs, "CP932") == 0)- return ("CP932");- return (charset);-}--/*- * Create a string conversion object.- */-static struct archive_string_conv *-create_sconv_object(const char *fc, const char *tc,- unsigned current_codepage, int flag)-{- struct archive_string_conv *sc; -- sc = calloc(1, sizeof(*sc));- if (sc == NULL)- return (NULL);- sc->next = NULL;- sc->from_charset = strdup(fc);- if (sc->from_charset == NULL) {- free(sc);- return (NULL);- }- sc->to_charset = strdup(tc);- if (sc->to_charset == NULL) {- free(sc->from_charset);- free(sc);- return (NULL);- }- archive_string_init(&sc->utftmp);-- if (flag & SCONV_TO_CHARSET) {- /*- * Convert characters from the current locale charset to- * a specified charset.- */- sc->from_cp = current_codepage;- sc->to_cp = make_codepage_from_charset(tc);-#if defined(_WIN32) && !defined(__CYGWIN__)- if (IsValidCodePage(sc->to_cp))- flag |= SCONV_WIN_CP;-#endif- } else if (flag & SCONV_FROM_CHARSET) {- /*- * Convert characters from a specified charset to- * the current locale charset.- */- sc->to_cp = current_codepage;- sc->from_cp = make_codepage_from_charset(fc);-#if defined(_WIN32) && !defined(__CYGWIN__)- if (IsValidCodePage(sc->from_cp))- flag |= SCONV_WIN_CP;-#endif- }-- /*- * Check if "from charset" and "to charset" are the same.- */- if (strcmp(fc, tc) == 0 ||- (sc->from_cp != (unsigned)-1 && sc->from_cp == sc->to_cp))- sc->same = 1;- else- sc->same = 0;-- /*- * Mark if "from charset" or "to charset" are UTF-8 or UTF-16BE/LE.- */- if (strcmp(tc, "UTF-8") == 0)- flag |= SCONV_TO_UTF8;- else if (strcmp(tc, "UTF-16BE") == 0)- flag |= SCONV_TO_UTF16BE;- else if (strcmp(tc, "UTF-16LE") == 0)- flag |= SCONV_TO_UTF16LE;- if (strcmp(fc, "UTF-8") == 0)- flag |= SCONV_FROM_UTF8;- else if (strcmp(fc, "UTF-16BE") == 0)- flag |= SCONV_FROM_UTF16BE;- else if (strcmp(fc, "UTF-16LE") == 0)- flag |= SCONV_FROM_UTF16LE;-#if defined(_WIN32) && !defined(__CYGWIN__)- if (sc->to_cp == CP_UTF8)- flag |= SCONV_TO_UTF8;- else if (sc->to_cp == CP_UTF16BE)- flag |= SCONV_TO_UTF16BE | SCONV_WIN_CP;- else if (sc->to_cp == CP_UTF16LE)- flag |= SCONV_TO_UTF16LE | SCONV_WIN_CP;- if (sc->from_cp == CP_UTF8)- flag |= SCONV_FROM_UTF8;- else if (sc->from_cp == CP_UTF16BE)- flag |= SCONV_FROM_UTF16BE | SCONV_WIN_CP;- else if (sc->from_cp == CP_UTF16LE)- flag |= SCONV_FROM_UTF16LE | SCONV_WIN_CP;-#endif-- /*- * Set a flag for Unicode NFD. Usually iconv cannot correctly- * handle it. So we have to translate NFD characters to NFC ones- * ourselves before iconv handles. Another reason is to prevent- * that the same sight of two filenames, one is NFC and other- * is NFD, would be in its directory.- * On Mac OS X, although its filesystem layer automatically- * convert filenames to NFD, it would be useful for filename- * comparing to find out the same filenames that we normalize- * that to be NFD ourselves.- */- if ((flag & SCONV_FROM_CHARSET) &&- (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8))) {-#if defined(__APPLE__)- if (flag & SCONV_TO_UTF8)- flag |= SCONV_NORMALIZATION_D;- else-#endif- flag |= SCONV_NORMALIZATION_C;- }-#if defined(__APPLE__)- /*- * In case writing an archive file, make sure that a filename- * going to be passed to iconv is a Unicode NFC string since- * a filename in HFS Plus filesystem is a Unicode NFD one and- * iconv cannot handle it with "UTF-8" charset. It is simpler- * than a use of "UTF-8-MAC" charset.- */- if ((flag & SCONV_TO_CHARSET) &&- (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) &&- !(flag & (SCONV_TO_UTF16 | SCONV_TO_UTF8)))- flag |= SCONV_NORMALIZATION_C;- /*- * In case reading an archive file. make sure that a filename- * will be passed to users is a Unicode NFD string in order to- * correctly compare the filename with other one which comes- * from HFS Plus filesystem.- */- if ((flag & SCONV_FROM_CHARSET) &&- !(flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) &&- (flag & SCONV_TO_UTF8))- flag |= SCONV_NORMALIZATION_D;-#endif--#if defined(HAVE_ICONV)- sc->cd_w = (iconv_t)-1;- /*- * Create an iconv object.- */- if (((flag & (SCONV_TO_UTF8 | SCONV_TO_UTF16)) &&- (flag & (SCONV_FROM_UTF8 | SCONV_FROM_UTF16))) ||- (flag & SCONV_WIN_CP)) {- /* This case we won't use iconv. */- sc->cd = (iconv_t)-1;- } else {- sc->cd = iconv_open(tc, fc);- if (sc->cd == (iconv_t)-1 && (sc->flag & SCONV_BEST_EFFORT)) {- /*- * Unfortunately, all of iconv implements do support- * "CP932" character-set, so we should use "SJIS"- * instead if iconv_open failed.- */- if (strcmp(tc, "CP932") == 0)- sc->cd = iconv_open("SJIS", fc);- else if (strcmp(fc, "CP932") == 0)- sc->cd = iconv_open(tc, "SJIS");- }-#if defined(_WIN32) && !defined(__CYGWIN__)- /*- * archive_mstring on Windows directly convert multi-bytes- * into archive_wstring in order not to depend on locale- * so that you can do a I18N programming. This will be- * used only in archive_mstring_copy_mbs_len_l so far.- */- if (flag & SCONV_FROM_CHARSET) {- sc->cd_w = iconv_open("UTF-8", fc);- if (sc->cd_w == (iconv_t)-1 &&- (sc->flag & SCONV_BEST_EFFORT)) {- if (strcmp(fc, "CP932") == 0)- sc->cd_w = iconv_open("UTF-8", "SJIS");- }- }-#endif /* _WIN32 && !__CYGWIN__ */- }-#endif /* HAVE_ICONV */-- sc->flag = flag;-- /*- * Set up converters.- */- setup_converter(sc);-- return (sc);-}--/*- * Free a string conversion object.- */-static void-free_sconv_object(struct archive_string_conv *sc)-{- free(sc->from_charset);- free(sc->to_charset);- archive_string_free(&sc->utftmp);-#if HAVE_ICONV- if (sc->cd != (iconv_t)-1)- iconv_close(sc->cd);- if (sc->cd_w != (iconv_t)-1)- iconv_close(sc->cd_w);-#endif- free(sc);-}--#if defined(_WIN32) && !defined(__CYGWIN__)-# if defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)-# define GetOEMCP() CP_OEMCP-# endif--static unsigned-my_atoi(const char *p)-{- unsigned cp;-- cp = 0;- while (*p) {- if (*p >= '0' && *p <= '9')- cp = cp * 10 + (*p - '0');- else- return (-1);- p++;- }- return (cp);-}--/*- * Translate Charset name (as used by iconv) into CodePage (as used by Windows)- * Return -1 if failed.- *- * Note: This translation code may be insufficient.- */-static struct charset {- const char *name;- unsigned cp;-} charsets[] = {- /* MUST BE SORTED! */- {"ASCII", 1252},- {"ASMO-708", 708},- {"BIG5", 950},- {"CHINESE", 936},- {"CP367", 1252},- {"CP819", 1252},- {"CP1025", 21025},- {"DOS-720", 720},- {"DOS-862", 862},- {"EUC-CN", 51936},- {"EUC-JP", 51932},- {"EUC-KR", 949},- {"EUCCN", 51936},- {"EUCJP", 51932},- {"EUCKR", 949},- {"GB18030", 54936},- {"GB2312", 936},- {"HEBREW", 1255},- {"HZ-GB-2312", 52936},- {"IBM273", 20273},- {"IBM277", 20277},- {"IBM278", 20278},- {"IBM280", 20280},- {"IBM284", 20284},- {"IBM285", 20285},- {"IBM290", 20290},- {"IBM297", 20297},- {"IBM367", 1252},- {"IBM420", 20420},- {"IBM423", 20423},- {"IBM424", 20424},- {"IBM819", 1252},- {"IBM871", 20871},- {"IBM880", 20880},- {"IBM905", 20905},- {"IBM924", 20924},- {"ISO-8859-1", 28591},- {"ISO-8859-13", 28603},- {"ISO-8859-15", 28605},- {"ISO-8859-2", 28592},- {"ISO-8859-3", 28593},- {"ISO-8859-4", 28594},- {"ISO-8859-5", 28595},- {"ISO-8859-6", 28596},- {"ISO-8859-7", 28597},- {"ISO-8859-8", 28598},- {"ISO-8859-9", 28599},- {"ISO8859-1", 28591},- {"ISO8859-13", 28603},- {"ISO8859-15", 28605},- {"ISO8859-2", 28592},- {"ISO8859-3", 28593},- {"ISO8859-4", 28594},- {"ISO8859-5", 28595},- {"ISO8859-6", 28596},- {"ISO8859-7", 28597},- {"ISO8859-8", 28598},- {"ISO8859-9", 28599},- {"JOHAB", 1361},- {"KOI8-R", 20866},- {"KOI8-U", 21866},- {"KS_C_5601-1987", 949},- {"LATIN1", 1252},- {"LATIN2", 28592},- {"MACINTOSH", 10000},- {"SHIFT-JIS", 932},- {"SHIFT_JIS", 932},- {"SJIS", 932},- {"US", 1252},- {"US-ASCII", 1252},- {"UTF-16", 1200},- {"UTF-16BE", 1201},- {"UTF-16LE", 1200},- {"UTF-8", CP_UTF8},- {"X-EUROPA", 29001},- {"X-MAC-ARABIC", 10004},- {"X-MAC-CE", 10029},- {"X-MAC-CHINESEIMP", 10008},- {"X-MAC-CHINESETRAD", 10002},- {"X-MAC-CROATIAN", 10082},- {"X-MAC-CYRILLIC", 10007},- {"X-MAC-GREEK", 10006},- {"X-MAC-HEBREW", 10005},- {"X-MAC-ICELANDIC", 10079},- {"X-MAC-JAPANESE", 10001},- {"X-MAC-KOREAN", 10003},- {"X-MAC-ROMANIAN", 10010},- {"X-MAC-THAI", 10021},- {"X-MAC-TURKISH", 10081},- {"X-MAC-UKRAINIAN", 10017},-};-static unsigned-make_codepage_from_charset(const char *charset)-{- char cs[16];- char *p;- unsigned cp;- int a, b;-- if (charset == NULL || strlen(charset) > 15)- return -1;-- /* Copy name to uppercase. */- p = cs;- while (*charset) {- char c = *charset++;- if (c >= 'a' && c <= 'z')- c -= 'a' - 'A';- *p++ = c;- }- *p++ = '\0';- cp = -1;-- /* Look it up in the table first, so that we can easily- * override CP367, which we map to 1252 instead of 367. */- a = 0;- b = sizeof(charsets)/sizeof(charsets[0]);- while (b > a) {- int c = (b + a) / 2;- int r = strcmp(charsets[c].name, cs);- if (r < 0)- a = c + 1;- else if (r > 0)- b = c;- else- return charsets[c].cp;- }-- /* If it's not in the table, try to parse it. */- switch (*cs) {- case 'C':- if (cs[1] == 'P' && cs[2] >= '0' && cs[2] <= '9') {- cp = my_atoi(cs + 2);- } else if (strcmp(cs, "CP_ACP") == 0)- cp = get_current_codepage();- else if (strcmp(cs, "CP_OEMCP") == 0)- cp = get_current_oemcp();- break;- case 'I':- if (cs[1] == 'B' && cs[2] == 'M' &&- cs[3] >= '0' && cs[3] <= '9') {- cp = my_atoi(cs + 3);- }- break;- case 'W':- if (strncmp(cs, "WINDOWS-", 8) == 0) {- cp = my_atoi(cs + 8);- if (cp != 874 && (cp < 1250 || cp > 1258))- cp = -1;/* This may invalid code. */- }- break;- }- return (cp);-}--/*- * Return ANSI Code Page of current locale set by setlocale().- */-static unsigned-get_current_codepage(void)-{- char *locale, *p;- unsigned cp;-- locale = setlocale(LC_CTYPE, NULL);- if (locale == NULL)- return (GetACP());- if (locale[0] == 'C' && locale[1] == '\0')- return (CP_C_LOCALE);- p = strrchr(locale, '.');- if (p == NULL)- return (GetACP());- if (strcmp(p+1, "utf8") == 0)- return CP_UTF8;- cp = my_atoi(p+1);- if ((int)cp <= 0)- return (GetACP());- return (cp);-}--/*- * Translation table between Locale Name and ACP/OEMCP.- */-static struct {- unsigned acp;- unsigned ocp;- const char *locale;-} acp_ocp_map[] = {- { 950, 950, "Chinese_Taiwan" },- { 936, 936, "Chinese_People's Republic of China" },- { 950, 950, "Chinese_Taiwan" },- { 1250, 852, "Czech_Czech Republic" },- { 1252, 850, "Danish_Denmark" },- { 1252, 850, "Dutch_Netherlands" },- { 1252, 850, "Dutch_Belgium" },- { 1252, 437, "English_United States" },- { 1252, 850, "English_Australia" },- { 1252, 850, "English_Canada" },- { 1252, 850, "English_New Zealand" },- { 1252, 850, "English_United Kingdom" },- { 1252, 437, "English_United States" },- { 1252, 850, "Finnish_Finland" },- { 1252, 850, "French_France" },- { 1252, 850, "French_Belgium" },- { 1252, 850, "French_Canada" },- { 1252, 850, "French_Switzerland" },- { 1252, 850, "German_Germany" },- { 1252, 850, "German_Austria" },- { 1252, 850, "German_Switzerland" },- { 1253, 737, "Greek_Greece" },- { 1250, 852, "Hungarian_Hungary" },- { 1252, 850, "Icelandic_Iceland" },- { 1252, 850, "Italian_Italy" },- { 1252, 850, "Italian_Switzerland" },- { 932, 932, "Japanese_Japan" },- { 949, 949, "Korean_Korea" },- { 1252, 850, "Norwegian (BokmOl)_Norway" },- { 1252, 850, "Norwegian (BokmOl)_Norway" },- { 1252, 850, "Norwegian-Nynorsk_Norway" },- { 1250, 852, "Polish_Poland" },- { 1252, 850, "Portuguese_Portugal" },- { 1252, 850, "Portuguese_Brazil" },- { 1251, 866, "Russian_Russia" },- { 1250, 852, "Slovak_Slovakia" },- { 1252, 850, "Spanish_Spain" },- { 1252, 850, "Spanish_Mexico" },- { 1252, 850, "Spanish_Spain" },- { 1252, 850, "Swedish_Sweden" },- { 1254, 857, "Turkish_Turkey" },- { 0, 0, NULL}-};--/*- * Return OEM Code Page of current locale set by setlocale().- */-static unsigned-get_current_oemcp(void)-{- int i;- char *locale, *p;- size_t len;-- locale = setlocale(LC_CTYPE, NULL);- if (locale == NULL)- return (GetOEMCP());- if (locale[0] == 'C' && locale[1] == '\0')- return (CP_C_LOCALE);-- p = strrchr(locale, '.');- if (p == NULL)- return (GetOEMCP());- len = p - locale;- for (i = 0; acp_ocp_map[i].acp; i++) {- if (strncmp(acp_ocp_map[i].locale, locale, len) == 0)- return (acp_ocp_map[i].ocp);- }- return (GetOEMCP());-}-#else--/*- * POSIX platform does not use CodePage.- */--static unsigned-get_current_codepage(void)-{- return (-1);/* Unknown */-}-static unsigned-make_codepage_from_charset(const char *charset)-{- (void)charset; /* UNUSED */- return (-1);/* Unknown */-}-static unsigned-get_current_oemcp(void)-{- return (-1);/* Unknown */-}--#endif /* defined(_WIN32) && !defined(__CYGWIN__) */--/*- * Return a string conversion object.- */-static struct archive_string_conv *-get_sconv_object(struct archive *a, const char *fc, const char *tc, int flag)-{- struct archive_string_conv *sc;- unsigned current_codepage;-- /* Check if we have made the sconv object. */- sc = find_sconv_object(a, fc, tc);- if (sc != NULL)- return (sc);-- if (a == NULL)- current_codepage = get_current_codepage();- else- current_codepage = a->current_codepage;-- sc = create_sconv_object(canonical_charset_name(fc),- canonical_charset_name(tc), current_codepage, flag);- if (sc == NULL) {- if (a != NULL)- archive_set_error(a, ENOMEM,- "Could not allocate memory for "- "a string conversion object");- return (NULL);- }-- /*- * If there is no converter for current string conversion object,- * we cannot handle this conversion.- */- if (sc->nconverter == 0) {- if (a != NULL) {-#if HAVE_ICONV- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "iconv_open failed : Cannot handle ``%s''",- (flag & SCONV_TO_CHARSET)?tc:fc);-#else- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "A character-set conversion not fully supported "- "on this platform");-#endif- }- /* Failed; free a sconv object. */- free_sconv_object(sc);- return (NULL);- }-- /*- * Success!- */- if (a != NULL)- add_sconv_object(a, sc);- return (sc);-}--static const char *-get_current_charset(struct archive *a)-{- const char *cur_charset;-- if (a == NULL)- cur_charset = default_iconv_charset("");- else {- cur_charset = default_iconv_charset(a->current_code);- if (a->current_code == NULL) {- a->current_code = strdup(cur_charset);- a->current_codepage = get_current_codepage();- a->current_oemcp = get_current_oemcp();- }- }- return (cur_charset);-}--/*- * Make and Return a string conversion object.- * Return NULL if the platform does not support the specified conversion- * and best_effort is 0.- * If best_effort is set, A string conversion object must be returned- * unless memory allocation for the object fails, but the conversion- * might fail when non-ASCII code is found.- */-struct archive_string_conv *-archive_string_conversion_to_charset(struct archive *a, const char *charset,- int best_effort)-{- int flag = SCONV_TO_CHARSET;-- if (best_effort)- flag |= SCONV_BEST_EFFORT;- return (get_sconv_object(a, get_current_charset(a), charset, flag));-}--struct archive_string_conv *-archive_string_conversion_from_charset(struct archive *a, const char *charset,- int best_effort)-{- int flag = SCONV_FROM_CHARSET;-- if (best_effort)- flag |= SCONV_BEST_EFFORT;- return (get_sconv_object(a, charset, get_current_charset(a), flag));-}--/*- * archive_string_default_conversion_*_archive() are provided for Windows- * platform because other archiver application use CP_OEMCP for- * MultiByteToWideChar() and WideCharToMultiByte() for the filenames- * in tar or zip files. But mbstowcs/wcstombs(CRT) usually use CP_ACP- * unless you use setlocale(LC_ALL, ".OCP")(specify CP_OEMCP).- * So we should make a string conversion between CP_ACP and CP_OEMCP- * for compatibility.- */-#if defined(_WIN32) && !defined(__CYGWIN__)-struct archive_string_conv *-archive_string_default_conversion_for_read(struct archive *a)-{- const char *cur_charset = get_current_charset(a);- char oemcp[16];-- /* NOTE: a check of cur_charset is unneeded but we need- * that get_current_charset() has been surely called at- * this time whatever C compiler optimized. */- if (cur_charset != NULL &&- (a->current_codepage == CP_C_LOCALE ||- a->current_codepage == a->current_oemcp))- return (NULL);/* no conversion. */-- _snprintf(oemcp, sizeof(oemcp)-1, "CP%d", a->current_oemcp);- /* Make sure a null termination must be set. */- oemcp[sizeof(oemcp)-1] = '\0';- return (get_sconv_object(a, oemcp, cur_charset,- SCONV_FROM_CHARSET));-}--struct archive_string_conv *-archive_string_default_conversion_for_write(struct archive *a)-{- const char *cur_charset = get_current_charset(a);- char oemcp[16];-- /* NOTE: a check of cur_charset is unneeded but we need- * that get_current_charset() has been surely called at- * this time whatever C compiler optimized. */- if (cur_charset != NULL &&- (a->current_codepage == CP_C_LOCALE ||- a->current_codepage == a->current_oemcp))- return (NULL);/* no conversion. */-- _snprintf(oemcp, sizeof(oemcp)-1, "CP%d", a->current_oemcp);- /* Make sure a null termination must be set. */- oemcp[sizeof(oemcp)-1] = '\0';- return (get_sconv_object(a, cur_charset, oemcp,- SCONV_TO_CHARSET));-}-#else-struct archive_string_conv *-archive_string_default_conversion_for_read(struct archive *a)-{- (void)a; /* UNUSED */- return (NULL);-}--struct archive_string_conv *-archive_string_default_conversion_for_write(struct archive *a)-{- (void)a; /* UNUSED */- return (NULL);-}-#endif--/*- * Dispose of all character conversion objects in the archive object.- */-void-archive_string_conversion_free(struct archive *a)-{- struct archive_string_conv *sc; - struct archive_string_conv *sc_next; -- for (sc = a->sconv; sc != NULL; sc = sc_next) {- sc_next = sc->next;- free_sconv_object(sc);- }- a->sconv = NULL;- free(a->current_code);- a->current_code = NULL;-}--/*- * Return a conversion charset name.- */-const char *-archive_string_conversion_charset_name(struct archive_string_conv *sc)-{- if (sc->flag & SCONV_TO_CHARSET)- return (sc->to_charset);- else- return (sc->from_charset);-}--/*- * Change the behavior of a string conversion.- */-void-archive_string_conversion_set_opt(struct archive_string_conv *sc, int opt)-{- switch (opt) {- /*- * A filename in UTF-8 was made with libarchive 2.x in a wrong- * assumption that wchar_t was Unicode.- * This option enables simulating the assumption in order to read- * that filename correctly.- */- case SCONV_SET_OPT_UTF8_LIBARCHIVE2X:-#if (defined(_WIN32) && !defined(__CYGWIN__)) \- || defined(__STDC_ISO_10646__) || defined(__APPLE__)- /*- * Nothing to do for it since wchar_t on these platforms- * is really Unicode.- */- (void)sc; /* UNUSED */-#else- if ((sc->flag & SCONV_UTF8_LIBARCHIVE_2) == 0) {- sc->flag |= SCONV_UTF8_LIBARCHIVE_2;- /* Set up string converters. */- setup_converter(sc);- }-#endif- break;- case SCONV_SET_OPT_NORMALIZATION_C:- if ((sc->flag & SCONV_NORMALIZATION_C) == 0) {- sc->flag |= SCONV_NORMALIZATION_C;- sc->flag &= ~SCONV_NORMALIZATION_D;- /* Set up string converters. */- setup_converter(sc);- }- break;- case SCONV_SET_OPT_NORMALIZATION_D:-#if defined(HAVE_ICONV)- /*- * If iconv will take the string, do not change the- * setting of the normalization.- */- if (!(sc->flag & SCONV_WIN_CP) &&- (sc->flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) &&- !(sc->flag & (SCONV_TO_UTF16 | SCONV_TO_UTF8)))- break;-#endif- if ((sc->flag & SCONV_NORMALIZATION_D) == 0) {- sc->flag |= SCONV_NORMALIZATION_D;- sc->flag &= ~SCONV_NORMALIZATION_C;- /* Set up string converters. */- setup_converter(sc);- }- break;- default:- break;- }-}--/*- *- * Copy one archive_string to another in locale conversion.- *- * archive_strncat_l();- * archive_strncpy_l();- *- */--static size_t-mbsnbytes(const void *_p, size_t n)-{- size_t s;- const char *p, *pp;-- if (_p == NULL)- return (0);- p = (const char *)_p;-- /* Like strlen(p), except won't examine positions beyond p[n]. */- s = 0;- pp = p;- while (s < n && *pp) {- pp++;- s++;- }- return (s);-}--static size_t-utf16nbytes(const void *_p, size_t n)-{- size_t s;- const char *p, *pp;-- if (_p == NULL)- return (0);- p = (const char *)_p;-- /* Like strlen(p), except won't examine positions beyond p[n]. */- s = 0;- pp = p;- n >>= 1;- while (s < n && (pp[0] || pp[1])) {- pp += 2;- s++;- }- return (s<<1);-}--int-archive_strncpy_l(struct archive_string *as, const void *_p, size_t n,- struct archive_string_conv *sc)-{- as->length = 0;- return (archive_strncat_l(as, _p, n, sc));-}--int-archive_strncat_l(struct archive_string *as, const void *_p, size_t n,- struct archive_string_conv *sc)-{- const void *s;- size_t length = 0;- int i, r = 0, r2;-- if (_p != NULL && n > 0) {- if (sc != NULL && (sc->flag & SCONV_FROM_UTF16))- length = utf16nbytes(_p, n);- else- length = mbsnbytes(_p, n);- }-- /* We must allocate memory even if there is no data for conversion- * or copy. This simulates archive_string_append behavior. */- if (length == 0) {- int tn = 1;- if (sc != NULL && (sc->flag & SCONV_TO_UTF16))- tn = 2;- if (archive_string_ensure(as, as->length + tn) == NULL)- return (-1);- as->s[as->length] = 0;- if (tn == 2)- as->s[as->length+1] = 0;- return (0);- }-- /*- * If sc is NULL, we just make a copy.- */- if (sc == NULL) {- if (archive_string_append(as, _p, length) == NULL)- return (-1);/* No memory */- return (0);- }-- s = _p;- i = 0;- if (sc->nconverter > 1) {- sc->utftmp.length = 0;- r2 = sc->converter[0](&(sc->utftmp), s, length, sc);- if (r2 != 0 && errno == ENOMEM)- return (r2);- if (r > r2)- r = r2;- s = sc->utftmp.s;- length = sc->utftmp.length;- ++i;- }- r2 = sc->converter[i](as, s, length, sc);- if (r > r2)- r = r2;- return (r);-}--#if HAVE_ICONV--/*- * Return -1 if conversion fails.- */-static int-iconv_strncat_in_locale(struct archive_string *as, const void *_p,- size_t length, struct archive_string_conv *sc)-{- ICONV_CONST char *itp;- size_t remaining;- iconv_t cd;- char *outp;- size_t avail, bs;- int return_value = 0; /* success */- int to_size, from_size;-- if (sc->flag & SCONV_TO_UTF16)- to_size = 2;- else- to_size = 1;- if (sc->flag & SCONV_FROM_UTF16)- from_size = 2;- else- from_size = 1;-- if (archive_string_ensure(as, as->length + length*2+to_size) == NULL)- return (-1);-- cd = sc->cd;- itp = (char *)(uintptr_t)_p;- remaining = length;- outp = as->s + as->length;- avail = as->buffer_length - as->length - to_size;- while (remaining >= (size_t)from_size) {- size_t result = iconv(cd, &itp, &remaining, &outp, &avail);-- if (result != (size_t)-1)- break; /* Conversion completed. */-- if (errno == EILSEQ || errno == EINVAL) {- /*- * If an output charset is UTF-8 or UTF-16BE/LE,- * unknown character should be U+FFFD- * (replacement character).- */- if (sc->flag & (SCONV_TO_UTF8 | SCONV_TO_UTF16)) {- size_t rbytes;- if (sc->flag & SCONV_TO_UTF8)- rbytes = sizeof(utf8_replacement_char);- else- rbytes = 2;-- if (avail < rbytes) {- as->length = outp - as->s;- bs = as->buffer_length +- (remaining * to_size) + rbytes;- if (NULL ==- archive_string_ensure(as, bs))- return (-1);- outp = as->s + as->length;- avail = as->buffer_length- - as->length - to_size;- }- if (sc->flag & SCONV_TO_UTF8)- memcpy(outp, utf8_replacement_char, sizeof(utf8_replacement_char));- else if (sc->flag & SCONV_TO_UTF16BE)- archive_be16enc(outp, UNICODE_R_CHAR);- else- archive_le16enc(outp, UNICODE_R_CHAR);- outp += rbytes;- avail -= rbytes;- } else {- /* Skip the illegal input bytes. */- *outp++ = '?';- avail--;- }- itp += from_size;- remaining -= from_size;- return_value = -1; /* failure */- } else {- /* E2BIG no output buffer,- * Increase an output buffer. */- as->length = outp - as->s;- bs = as->buffer_length + remaining * 2;- if (NULL == archive_string_ensure(as, bs))- return (-1);- outp = as->s + as->length;- avail = as->buffer_length - as->length - to_size;- }- }- as->length = outp - as->s;- as->s[as->length] = 0;- if (to_size == 2)- as->s[as->length+1] = 0;- return (return_value);-}--#endif /* HAVE_ICONV */---#if defined(_WIN32) && !defined(__CYGWIN__)--/*- * Translate a string from a some CodePage to an another CodePage by- * Windows APIs, and copy the result. Return -1 if conversion fails.- */-static int-strncat_in_codepage(struct archive_string *as,- const void *_p, size_t length, struct archive_string_conv *sc)-{- const char *s = (const char *)_p;- struct archive_wstring aws;- size_t l;- int r, saved_flag;-- archive_string_init(&aws);- saved_flag = sc->flag;- sc->flag &= ~(SCONV_NORMALIZATION_D | SCONV_NORMALIZATION_C);- r = archive_wstring_append_from_mbs_in_codepage(&aws, s, length, sc);- sc->flag = saved_flag;- if (r != 0) {- archive_wstring_free(&aws);- if (errno != ENOMEM)- archive_string_append(as, s, length);- return (-1);- }-- l = as->length;- r = archive_string_append_from_wcs_in_codepage(- as, aws.s, aws.length, sc);- if (r != 0 && errno != ENOMEM && l == as->length)- archive_string_append(as, s, length);- archive_wstring_free(&aws);- return (r);-}--/*- * Test whether MBS ==> WCS is okay.- */-static int-invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc)-{- const char *p = (const char *)_p;- unsigned codepage;- DWORD mbflag = MB_ERR_INVALID_CHARS;-- if (sc->flag & SCONV_FROM_CHARSET)- codepage = sc->to_cp;- else- codepage = sc->from_cp;-- if (codepage == CP_C_LOCALE)- return (0);- if (codepage != CP_UTF8)- mbflag |= MB_PRECOMPOSED;-- if (MultiByteToWideChar(codepage, mbflag, p, (int)n, NULL, 0) == 0)- return (-1); /* Invalid */- return (0); /* Okay */-}--#else--/*- * Test whether MBS ==> WCS is okay.- */-static int-invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc)-{- const char *p = (const char *)_p;- size_t r;--#if HAVE_MBRTOWC- mbstate_t shift_state;-- memset(&shift_state, 0, sizeof(shift_state));-#else- /* Clear the shift state before starting. */- mbtowc(NULL, NULL, 0);-#endif- while (n) {- wchar_t wc;--#if HAVE_MBRTOWC- r = mbrtowc(&wc, p, n, &shift_state);-#else- r = mbtowc(&wc, p, n);-#endif- if (r == (size_t)-1 || r == (size_t)-2)- return (-1);/* Invalid. */- if (r == 0)- break;- p += r;- n -= r;- }- (void)sc; /* UNUSED */- return (0); /* All Okey. */-}--#endif /* defined(_WIN32) && !defined(__CYGWIN__) */--/*- * Basically returns -1 because we cannot make a conversion of charset- * without iconv but in some cases this would return 0.- * Returns 0 if all copied characters are ASCII.- * Returns 0 if both from-locale and to-locale are the same and those- * can be WCS with no error.- */-static int-best_effort_strncat_in_locale(struct archive_string *as, const void *_p,- size_t length, struct archive_string_conv *sc)-{- size_t remaining;- const uint8_t *itp;- int return_value = 0; /* success */-- /*- * If both from-locale and to-locale is the same, this makes a copy.- * And then this checks all copied MBS can be WCS if so returns 0.- */- if (sc->same) {- if (archive_string_append(as, _p, length) == NULL)- return (-1);/* No memory */- return (invalid_mbs(_p, length, sc));- }-- /*- * If a character is ASCII, this just copies it. If not, this- * assigns '?' character instead but in UTF-8 locale this assigns- * byte sequence 0xEF 0xBD 0xBD, which are code point U+FFFD,- * a Replacement Character in Unicode.- */-- remaining = length;- itp = (const uint8_t *)_p;- while (*itp && remaining > 0) {- if (*itp > 127) {- // Non-ASCII: Substitute with suitable replacement- if (sc->flag & SCONV_TO_UTF8) {- if (archive_string_append(as, utf8_replacement_char, sizeof(utf8_replacement_char)) == NULL) {- __archive_errx(1, "Out of memory");- }- } else {- archive_strappend_char(as, '?');- }- return_value = -1;- } else {- archive_strappend_char(as, *itp);- }- ++itp;- }- return (return_value);-}---/*- * Unicode conversion functions.- * - UTF-8 <===> UTF-8 in removing surrogate pairs.- * - UTF-8 NFD ===> UTF-8 NFC in removing surrogate pairs.- * - UTF-8 made by libarchive 2.x ===> UTF-8.- * - UTF-16BE <===> UTF-8.- *- */--/*- * Utility to convert a single UTF-8 sequence.- *- * Usually return used bytes, return used byte in negative value when- * a unicode character is replaced with U+FFFD.- * See also http://unicode.org/review/pr-121.html Public Review Issue #121- * Recommended Practice for Replacement Characters.- */-static int-_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)-{- static const char utf8_count[256] = {- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */- 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */- 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */- };- int ch, i;- int cnt;- uint32_t wc;-- /* Sanity check. */- if (n == 0)- return (0);- /*- * Decode 1-4 bytes depending on the value of the first byte.- */- ch = (unsigned char)*s;- if (ch == 0)- return (0); /* Standard: return 0 for end-of-string. */- cnt = utf8_count[ch];-- /* Invalid sequence or there are not plenty bytes. */- if ((int)n < cnt) {- cnt = (int)n;- for (i = 1; i < cnt; i++) {- if ((s[i] & 0xc0) != 0x80) {- cnt = i;- break;- }- }- goto invalid_sequence;- }-- /* Make a Unicode code point from a single UTF-8 sequence. */- switch (cnt) {- case 1: /* 1 byte sequence. */- *pwc = ch & 0x7f;- return (cnt);- case 2: /* 2 bytes sequence. */- if ((s[1] & 0xc0) != 0x80) {- cnt = 1;- goto invalid_sequence;- }- *pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f);- return (cnt);- case 3: /* 3 bytes sequence. */- if ((s[1] & 0xc0) != 0x80) {- cnt = 1;- goto invalid_sequence;- }- if ((s[2] & 0xc0) != 0x80) {- cnt = 2;- goto invalid_sequence;- }- wc = ((ch & 0x0f) << 12)- | ((s[1] & 0x3f) << 6)- | (s[2] & 0x3f);- if (wc < 0x800)- goto invalid_sequence;/* Overlong sequence. */- break;- case 4: /* 4 bytes sequence. */- if ((s[1] & 0xc0) != 0x80) {- cnt = 1;- goto invalid_sequence;- }- if ((s[2] & 0xc0) != 0x80) {- cnt = 2;- goto invalid_sequence;- }- if ((s[3] & 0xc0) != 0x80) {- cnt = 3;- goto invalid_sequence;- }- wc = ((ch & 0x07) << 18)- | ((s[1] & 0x3f) << 12)- | ((s[2] & 0x3f) << 6)- | (s[3] & 0x3f);- if (wc < 0x10000)- goto invalid_sequence;/* Overlong sequence. */- break;- default: /* Others are all invalid sequence. */- if (ch == 0xc0 || ch == 0xc1)- cnt = 2;- else if (ch >= 0xf5 && ch <= 0xf7)- cnt = 4;- else if (ch >= 0xf8 && ch <= 0xfb)- cnt = 5;- else if (ch == 0xfc || ch == 0xfd)- cnt = 6;- else- cnt = 1;- if ((int)n < cnt)- cnt = (int)n;- for (i = 1; i < cnt; i++) {- if ((s[i] & 0xc0) != 0x80) {- cnt = i;- break;- }- }- goto invalid_sequence;- }-- /* The code point larger than 0x10FFFF is not legal- * Unicode values. */- if (wc > UNICODE_MAX)- goto invalid_sequence;- /* Correctly gets a Unicode, returns used bytes. */- *pwc = wc;- return (cnt);-invalid_sequence:- *pwc = UNICODE_R_CHAR;/* set the Replacement Character instead. */- return (cnt * -1);-}--static int-utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)-{- int cnt;-- cnt = _utf8_to_unicode(pwc, s, n);- /* Any of Surrogate pair is not legal Unicode values. */- if (cnt == 3 && IS_SURROGATE_PAIR_LA(*pwc))- return (-3);- return (cnt);-}--static inline uint32_t-combine_surrogate_pair(uint32_t uc, uint32_t uc2)-{- uc -= 0xD800;- uc *= 0x400;- uc += uc2 - 0xDC00;- uc += 0x10000;- return (uc);-}--/*- * Convert a single UTF-8/CESU-8 sequence to a Unicode code point in- * removing surrogate pairs.- *- * CESU-8: The Compatibility Encoding Scheme for UTF-16.- *- * Usually return used bytes, return used byte in negative value when- * a unicode character is replaced with U+FFFD.- */-static int-cesu8_to_unicode(uint32_t *pwc, const char *s, size_t n)-{- uint32_t wc = 0;- int cnt;-- cnt = _utf8_to_unicode(&wc, s, n);- if (cnt == 3 && IS_HIGH_SURROGATE_LA(wc)) {- uint32_t wc2 = 0;- if (n - 3 < 3) {- /* Invalid byte sequence. */- goto invalid_sequence;- }- cnt = _utf8_to_unicode(&wc2, s+3, n-3);- if (cnt != 3 || !IS_LOW_SURROGATE_LA(wc2)) {- /* Invalid byte sequence. */- goto invalid_sequence;- }- wc = combine_surrogate_pair(wc, wc2);- cnt = 6;- } else if (cnt == 3 && IS_LOW_SURROGATE_LA(wc)) {- /* Invalid byte sequence. */- goto invalid_sequence;- }- *pwc = wc;- return (cnt);-invalid_sequence:- *pwc = UNICODE_R_CHAR;/* set the Replacement Character instead. */- if (cnt > 0)- cnt *= -1;- return (cnt);-}--/*- * Convert a Unicode code point to a single UTF-8 sequence.- *- * NOTE:This function does not check if the Unicode is legal or not.- * Please you definitely check it before calling this.- */-static size_t-unicode_to_utf8(char *p, size_t remaining, uint32_t uc)-{- char *_p = p;-- /* Invalid Unicode char maps to Replacement character */- if (uc > UNICODE_MAX)- uc = UNICODE_R_CHAR;- /* Translate code point to UTF8 */- if (uc <= 0x7f) {- if (remaining == 0)- return (0);- *p++ = (char)uc;- } else if (uc <= 0x7ff) {- if (remaining < 2)- return (0);- *p++ = 0xc0 | ((uc >> 6) & 0x1f);- *p++ = 0x80 | (uc & 0x3f);- } else if (uc <= 0xffff) {- if (remaining < 3)- return (0);- *p++ = 0xe0 | ((uc >> 12) & 0x0f);- *p++ = 0x80 | ((uc >> 6) & 0x3f);- *p++ = 0x80 | (uc & 0x3f);- } else {- if (remaining < 4)- return (0);- *p++ = 0xf0 | ((uc >> 18) & 0x07);- *p++ = 0x80 | ((uc >> 12) & 0x3f);- *p++ = 0x80 | ((uc >> 6) & 0x3f);- *p++ = 0x80 | (uc & 0x3f);- }- return (p - _p);-}--static int-utf16be_to_unicode(uint32_t *pwc, const char *s, size_t n)-{- return (utf16_to_unicode(pwc, s, n, 1));-}--static int-utf16le_to_unicode(uint32_t *pwc, const char *s, size_t n)-{- return (utf16_to_unicode(pwc, s, n, 0));-}--static int-utf16_to_unicode(uint32_t *pwc, const char *s, size_t n, int be)-{- const char *utf16 = s;- unsigned uc;-- if (n == 0)- return (0);- if (n == 1) {- /* set the Replacement Character instead. */- *pwc = UNICODE_R_CHAR;- return (-1);- }-- if (be)- uc = archive_be16dec(utf16);- else- uc = archive_le16dec(utf16);- utf16 += 2;- - /* If this is a surrogate pair, assemble the full code point.*/- if (IS_HIGH_SURROGATE_LA(uc)) {- unsigned uc2;-- if (n >= 4) {- if (be)- uc2 = archive_be16dec(utf16);- else- uc2 = archive_le16dec(utf16);- } else- uc2 = 0;- if (IS_LOW_SURROGATE_LA(uc2)) {- uc = combine_surrogate_pair(uc, uc2);- utf16 += 2;- } else {- /* Undescribed code point should be U+FFFD- * (replacement character). */- *pwc = UNICODE_R_CHAR;- return (-2);- }- }-- /*- * Surrogate pair values(0xd800 through 0xdfff) are only- * used by UTF-16, so, after above calculation, the code- * must not be surrogate values, and Unicode has no codes- * larger than 0x10ffff. Thus, those are not legal Unicode- * values.- */- if (IS_SURROGATE_PAIR_LA(uc) || uc > UNICODE_MAX) {- /* Undescribed code point should be U+FFFD- * (replacement character). */- *pwc = UNICODE_R_CHAR;- return (((int)(utf16 - s)) * -1);- }- *pwc = uc;- return ((int)(utf16 - s));-}--static size_t-unicode_to_utf16be(char *p, size_t remaining, uint32_t uc)-{- char *utf16 = p;-- if (uc > 0xffff) {- /* We have a code point that won't fit into a- * wchar_t; convert it to a surrogate pair. */- if (remaining < 4)- return (0);- uc -= 0x10000;- archive_be16enc(utf16, ((uc >> 10) & 0x3ff) + 0xD800);- archive_be16enc(utf16+2, (uc & 0x3ff) + 0xDC00);- return (4);- } else {- if (remaining < 2)- return (0);- archive_be16enc(utf16, uc);- return (2);- }-}--static size_t-unicode_to_utf16le(char *p, size_t remaining, uint32_t uc)-{- char *utf16 = p;-- if (uc > 0xffff) {- /* We have a code point that won't fit into a- * wchar_t; convert it to a surrogate pair. */- if (remaining < 4)- return (0);- uc -= 0x10000;- archive_le16enc(utf16, ((uc >> 10) & 0x3ff) + 0xD800);- archive_le16enc(utf16+2, (uc & 0x3ff) + 0xDC00);- return (4);- } else {- if (remaining < 2)- return (0);- archive_le16enc(utf16, uc);- return (2);- }-}--/*- * Copy UTF-8 string in checking surrogate pair.- * If any surrogate pair are found, it would be canonicalized.- */-static int-strncat_from_utf8_to_utf8(struct archive_string *as, const void *_p,- size_t len, struct archive_string_conv *sc)-{- const char *s;- char *p, *endp;- int n, ret = 0;-- (void)sc; /* UNUSED */-- if (archive_string_ensure(as, as->length + len + 1) == NULL)- return (-1);-- s = (const char *)_p;- p = as->s + as->length;- endp = as->s + as->buffer_length -1;- do {- uint32_t uc;- const char *ss = s;- size_t w;-- /*- * Forward byte sequence until a conversion of that is needed.- */- while ((n = utf8_to_unicode(&uc, s, len)) > 0) {- s += n;- len -= n;- }- if (ss < s) {- if (p + (s - ss) > endp) {- as->length = p - as->s;- if (archive_string_ensure(as,- as->buffer_length + len + 1) == NULL)- return (-1);- p = as->s + as->length;- endp = as->s + as->buffer_length -1;- }-- memcpy(p, ss, s - ss);- p += s - ss;- }-- /*- * If n is negative, current byte sequence needs a replacement.- */- if (n < 0) {- if (n == -3 && IS_SURROGATE_PAIR_LA(uc)) {- /* Current byte sequence may be CESU-8. */- n = cesu8_to_unicode(&uc, s, len);- }- if (n < 0) {- ret = -1;- n *= -1;/* Use a replaced unicode character. */- }-- /* Rebuild UTF-8 byte sequence. */- while ((w = unicode_to_utf8(p, endp - p, uc)) == 0) {- as->length = p - as->s;- if (archive_string_ensure(as,- as->buffer_length + len + 1) == NULL)- return (-1);- p = as->s + as->length;- endp = as->s + as->buffer_length -1;- }- p += w;- s += n;- len -= n;- }- } while (n > 0);- as->length = p - as->s;- as->s[as->length] = '\0';- return (ret);-}--static int-archive_string_append_unicode(struct archive_string *as, const void *_p,- size_t len, struct archive_string_conv *sc)-{- const char *s;- char *p, *endp;- uint32_t uc;- size_t w;- int n, ret = 0, ts, tm;- int (*parse)(uint32_t *, const char *, size_t);- size_t (*unparse)(char *, size_t, uint32_t);-- if (sc->flag & SCONV_TO_UTF16BE) {- unparse = unicode_to_utf16be;- ts = 2;- } else if (sc->flag & SCONV_TO_UTF16LE) {- unparse = unicode_to_utf16le;- ts = 2;- } else if (sc->flag & SCONV_TO_UTF8) {- unparse = unicode_to_utf8;- ts = 1;- } else {- /*- * This case is going to be converted to another- * character-set through iconv.- */- if (sc->flag & SCONV_FROM_UTF16BE) {- unparse = unicode_to_utf16be;- ts = 2;- } else if (sc->flag & SCONV_FROM_UTF16LE) {- unparse = unicode_to_utf16le;- ts = 2;- } else {- unparse = unicode_to_utf8;- ts = 1;- }- }-- if (sc->flag & SCONV_FROM_UTF16BE) {- parse = utf16be_to_unicode;- tm = 1;- } else if (sc->flag & SCONV_FROM_UTF16LE) {- parse = utf16le_to_unicode;- tm = 1;- } else {- parse = cesu8_to_unicode;- tm = ts;- }-- if (archive_string_ensure(as, as->length + len * tm + ts) == NULL)- return (-1);-- s = (const char *)_p;- p = as->s + as->length;- endp = as->s + as->buffer_length - ts;- while ((n = parse(&uc, s, len)) != 0) {- if (n < 0) {- /* Use a replaced unicode character. */- n *= -1;- ret = -1;- }- s += n;- len -= n;- while ((w = unparse(p, endp - p, uc)) == 0) {- /* There is not enough output buffer so- * we have to expand it. */- as->length = p - as->s;- if (archive_string_ensure(as,- as->buffer_length + len * tm + ts) == NULL)- return (-1);- p = as->s + as->length;- endp = as->s + as->buffer_length - ts;- }- p += w;- }- as->length = p - as->s;- as->s[as->length] = '\0';- if (ts == 2)- as->s[as->length+1] = '\0';- return (ret);-}--/*- * Following Constants for Hangul compositions this information comes from- * Unicode Standard Annex #15 http://unicode.org/reports/tr15/- */-#define HC_SBASE 0xAC00-#define HC_LBASE 0x1100-#define HC_VBASE 0x1161-#define HC_TBASE 0x11A7-#define HC_LCOUNT 19-#define HC_VCOUNT 21-#define HC_TCOUNT 28-#define HC_NCOUNT (HC_VCOUNT * HC_TCOUNT)-#define HC_SCOUNT (HC_LCOUNT * HC_NCOUNT)--static uint32_t-get_nfc(uint32_t uc, uint32_t uc2)-{- int t, b;-- t = 0;- b = sizeof(u_composition_table)/sizeof(u_composition_table[0]) -1;- while (b >= t) {- int m = (t + b) / 2;- if (u_composition_table[m].cp1 < uc)- t = m + 1;- else if (u_composition_table[m].cp1 > uc)- b = m - 1;- else if (u_composition_table[m].cp2 < uc2)- t = m + 1;- else if (u_composition_table[m].cp2 > uc2)- b = m - 1;- else- return (u_composition_table[m].nfc);- }- return (0);-}--#define FDC_MAX 10 /* The maximum number of Following Decomposable- * Characters. */--/*- * Update first code point.- */-#define UPDATE_UC(new_uc) do { \- uc = new_uc; \- ucptr = NULL; \-} while (0)--/*- * Replace first code point with second code point.- */-#define REPLACE_UC_WITH_UC2() do { \- uc = uc2; \- ucptr = uc2ptr; \- n = n2; \-} while (0)--#define EXPAND_BUFFER() do { \- as->length = p - as->s; \- if (archive_string_ensure(as, \- as->buffer_length + len * tm + ts) == NULL)\- return (-1); \- p = as->s + as->length; \- endp = as->s + as->buffer_length - ts; \-} while (0)--#define UNPARSE(p, endp, uc) do { \- while ((w = unparse(p, (endp) - (p), uc)) == 0) {\- EXPAND_BUFFER(); \- } \- p += w; \-} while (0)--/*- * Write first code point.- * If the code point has not be changed from its original code,- * this just copies it from its original buffer pointer.- * If not, this converts it to UTF-8 byte sequence and copies it.- */-#define WRITE_UC() do { \- if (ucptr) { \- if (p + n > endp) \- EXPAND_BUFFER(); \- switch (n) { \- case 4: \- *p++ = *ucptr++; \- /* FALL THROUGH */ \- case 3: \- *p++ = *ucptr++; \- /* FALL THROUGH */ \- case 2: \- *p++ = *ucptr++; \- /* FALL THROUGH */ \- case 1: \- *p++ = *ucptr; \- break; \- } \- ucptr = NULL; \- } else { \- UNPARSE(p, endp, uc); \- } \-} while (0)--/*- * Collect following decomposable code points.- */-#define COLLECT_CPS(start) do { \- int _i; \- for (_i = start; _i < FDC_MAX ; _i++) { \- nx = parse(&ucx[_i], s, len); \- if (nx <= 0) \- break; \- cx = CCC(ucx[_i]); \- if (cl >= cx && cl != 228 && cx != 228)\- break; \- s += nx; \- len -= nx; \- cl = cx; \- ccx[_i] = cx; \- } \- if (_i >= FDC_MAX) { \- ret = -1; \- ucx_size = FDC_MAX; \- } else \- ucx_size = _i; \-} while (0)--/*- * Normalize UTF-8/UTF-16BE characters to Form C and copy the result.- *- * TODO: Convert composition exclusions, which are never converted- * from NFC,NFD,NFKC and NFKD, to Form C.- */-static int-archive_string_normalize_C(struct archive_string *as, const void *_p,- size_t len, struct archive_string_conv *sc)-{- const char *s = (const char *)_p;- char *p, *endp;- uint32_t uc, uc2;- size_t w;- int always_replace, n, n2, ret = 0, spair, ts, tm;- int (*parse)(uint32_t *, const char *, size_t);- size_t (*unparse)(char *, size_t, uint32_t);-- always_replace = 1;- ts = 1;/* text size. */- if (sc->flag & SCONV_TO_UTF16BE) {- unparse = unicode_to_utf16be;- ts = 2;- if (sc->flag & SCONV_FROM_UTF16BE)- always_replace = 0;- } else if (sc->flag & SCONV_TO_UTF16LE) {- unparse = unicode_to_utf16le;- ts = 2;- if (sc->flag & SCONV_FROM_UTF16LE)- always_replace = 0;- } else if (sc->flag & SCONV_TO_UTF8) {- unparse = unicode_to_utf8;- if (sc->flag & SCONV_FROM_UTF8)- always_replace = 0;- } else {- /*- * This case is going to be converted to another- * character-set through iconv.- */- always_replace = 0;- if (sc->flag & SCONV_FROM_UTF16BE) {- unparse = unicode_to_utf16be;- ts = 2;- } else if (sc->flag & SCONV_FROM_UTF16LE) {- unparse = unicode_to_utf16le;- ts = 2;- } else {- unparse = unicode_to_utf8;- }- }-- if (sc->flag & SCONV_FROM_UTF16BE) {- parse = utf16be_to_unicode;- tm = 1;- spair = 4;/* surrogate pair size in UTF-16. */- } else if (sc->flag & SCONV_FROM_UTF16LE) {- parse = utf16le_to_unicode;- tm = 1;- spair = 4;/* surrogate pair size in UTF-16. */- } else {- parse = cesu8_to_unicode;- tm = ts;- spair = 6;/* surrogate pair size in UTF-8. */- }-- if (archive_string_ensure(as, as->length + len * tm + ts) == NULL)- return (-1);-- p = as->s + as->length;- endp = as->s + as->buffer_length - ts;- while ((n = parse(&uc, s, len)) != 0) {- const char *ucptr, *uc2ptr;-- if (n < 0) {- /* Use a replaced unicode character. */- UNPARSE(p, endp, uc);- s += n*-1;- len -= n*-1;- ret = -1;- continue;- } else if (n == spair || always_replace)- /* uc is converted from a surrogate pair.- * this should be treated as a changed code. */- ucptr = NULL;- else- ucptr = s;- s += n;- len -= n;-- /* Read second code point. */- while ((n2 = parse(&uc2, s, len)) > 0) {- uint32_t ucx[FDC_MAX];- int ccx[FDC_MAX];- int cl, cx, i, nx, ucx_size;- int LIndex,SIndex;- uint32_t nfc;-- if (n2 == spair || always_replace)- /* uc2 is converted from a surrogate pair.- * this should be treated as a changed code. */- uc2ptr = NULL;- else- uc2ptr = s;- s += n2;- len -= n2;-- /*- * If current second code point is out of decomposable- * code points, finding compositions is unneeded.- */- if (!IS_DECOMPOSABLE_BLOCK(uc2)) {- WRITE_UC();- REPLACE_UC_WITH_UC2();- continue;- }-- /*- * Try to combine current code points.- */- /*- * We have to combine Hangul characters according to- * http://uniicode.org/reports/tr15/#Hangul- */- if (0 <= (LIndex = uc - HC_LBASE) &&- LIndex < HC_LCOUNT) {- /*- * Hangul Composition.- * 1. Two current code points are L and V.- */- int VIndex = uc2 - HC_VBASE;- if (0 <= VIndex && VIndex < HC_VCOUNT) {- /* Make syllable of form LV. */- UPDATE_UC(HC_SBASE +- (LIndex * HC_VCOUNT + VIndex) *- HC_TCOUNT);- } else {- WRITE_UC();- REPLACE_UC_WITH_UC2();- }- continue;- } else if (0 <= (SIndex = uc - HC_SBASE) &&- SIndex < HC_SCOUNT && (SIndex % HC_TCOUNT) == 0) {- /*- * Hangul Composition.- * 2. Two current code points are LV and T.- */- int TIndex = uc2 - HC_TBASE;- if (0 < TIndex && TIndex < HC_TCOUNT) {- /* Make syllable of form LVT. */- UPDATE_UC(uc + TIndex);- } else {- WRITE_UC();- REPLACE_UC_WITH_UC2();- }- continue;- } else if ((nfc = get_nfc(uc, uc2)) != 0) {- /* A composition to current code points- * is found. */- UPDATE_UC(nfc);- continue;- } else if ((cl = CCC(uc2)) == 0) {- /* Clearly 'uc2' the second code point is not- * a decomposable code. */- WRITE_UC();- REPLACE_UC_WITH_UC2();- continue;- }-- /*- * Collect following decomposable code points.- */- cx = 0;- ucx[0] = uc2;- ccx[0] = cl;- COLLECT_CPS(1);-- /*- * Find a composed code in the collected code points.- */- i = 1;- while (i < ucx_size) {- int j;-- if ((nfc = get_nfc(uc, ucx[i])) == 0) {- i++;- continue;- }-- /*- * nfc is composed of uc and ucx[i].- */- UPDATE_UC(nfc);-- /*- * Remove ucx[i] by shifting- * following code points.- */- for (j = i; j+1 < ucx_size; j++) {- ucx[j] = ucx[j+1];- ccx[j] = ccx[j+1];- }- ucx_size --;-- /*- * Collect following code points blocked- * by ucx[i] the removed code point.- */- if (ucx_size > 0 && i == ucx_size &&- nx > 0 && cx == cl) {- cl = ccx[ucx_size-1];- COLLECT_CPS(ucx_size);- }- /*- * Restart finding a composed code with- * the updated uc from the top of the- * collected code points.- */- i = 0;- }-- /*- * Apparently the current code points are not- * decomposed characters or already composed.- */- WRITE_UC();- for (i = 0; i < ucx_size; i++)- UNPARSE(p, endp, ucx[i]);-- /*- * Flush out remaining canonical combining characters.- */- if (nx > 0 && cx == cl && len > 0) {- while ((nx = parse(&ucx[0], s, len))- > 0) {- cx = CCC(ucx[0]);- if (cl > cx)- break;- s += nx;- len -= nx;- cl = cx;- UNPARSE(p, endp, ucx[0]);- }- }- break;- }- if (n2 < 0) {- WRITE_UC();- /* Use a replaced unicode character. */- UNPARSE(p, endp, uc2);- s += n2*-1;- len -= n2*-1;- ret = -1;- continue;- } else if (n2 == 0) {- WRITE_UC();- break;- }- }- as->length = p - as->s;- as->s[as->length] = '\0';- if (ts == 2)- as->s[as->length+1] = '\0';- return (ret);-}--static int-get_nfd(uint32_t *cp1, uint32_t *cp2, uint32_t uc)-{- int t, b;-- /*- * These are not converted to NFD on Mac OS.- */- if ((uc >= 0x2000 && uc <= 0x2FFF) ||- (uc >= 0xF900 && uc <= 0xFAFF) ||- (uc >= 0x2F800 && uc <= 0x2FAFF))- return (0);- /*- * Those code points are not converted to NFD on Mac OS.- * I do not know the reason because it is undocumented.- * NFC NFD- * 1109A ==> 11099 110BA- * 1109C ==> 1109B 110BA- * 110AB ==> 110A5 110BA- */- if (uc == 0x1109A || uc == 0x1109C || uc == 0x110AB)- return (0);-- t = 0;- b = sizeof(u_decomposition_table)/sizeof(u_decomposition_table[0]) -1;- while (b >= t) {- int m = (t + b) / 2;- if (u_decomposition_table[m].nfc < uc)- t = m + 1;- else if (u_decomposition_table[m].nfc > uc)- b = m - 1;- else {- *cp1 = u_decomposition_table[m].cp1;- *cp2 = u_decomposition_table[m].cp2;- return (1);- }- }- return (0);-}--#define REPLACE_UC_WITH(cp) do { \- uc = cp; \- ucptr = NULL; \-} while (0)--/*- * Normalize UTF-8 characters to Form D and copy the result.- */-static int-archive_string_normalize_D(struct archive_string *as, const void *_p,- size_t len, struct archive_string_conv *sc)-{- const char *s = (const char *)_p;- char *p, *endp;- uint32_t uc, uc2;- size_t w;- int always_replace, n, n2, ret = 0, spair, ts, tm;- int (*parse)(uint32_t *, const char *, size_t);- size_t (*unparse)(char *, size_t, uint32_t);-- always_replace = 1;- ts = 1;/* text size. */- if (sc->flag & SCONV_TO_UTF16BE) {- unparse = unicode_to_utf16be;- ts = 2;- if (sc->flag & SCONV_FROM_UTF16BE)- always_replace = 0;- } else if (sc->flag & SCONV_TO_UTF16LE) {- unparse = unicode_to_utf16le;- ts = 2;- if (sc->flag & SCONV_FROM_UTF16LE)- always_replace = 0;- } else if (sc->flag & SCONV_TO_UTF8) {- unparse = unicode_to_utf8;- if (sc->flag & SCONV_FROM_UTF8)- always_replace = 0;- } else {- /*- * This case is going to be converted to another- * character-set through iconv.- */- always_replace = 0;- if (sc->flag & SCONV_FROM_UTF16BE) {- unparse = unicode_to_utf16be;- ts = 2;- } else if (sc->flag & SCONV_FROM_UTF16LE) {- unparse = unicode_to_utf16le;- ts = 2;- } else {- unparse = unicode_to_utf8;- }- }-- if (sc->flag & SCONV_FROM_UTF16BE) {- parse = utf16be_to_unicode;- tm = 1;- spair = 4;/* surrogate pair size in UTF-16. */- } else if (sc->flag & SCONV_FROM_UTF16LE) {- parse = utf16le_to_unicode;- tm = 1;- spair = 4;/* surrogate pair size in UTF-16. */- } else {- parse = cesu8_to_unicode;- tm = ts;- spair = 6;/* surrogate pair size in UTF-8. */- }-- if (archive_string_ensure(as, as->length + len * tm + ts) == NULL)- return (-1);-- p = as->s + as->length;- endp = as->s + as->buffer_length - ts;- while ((n = parse(&uc, s, len)) != 0) {- const char *ucptr;- uint32_t cp1, cp2;- int SIndex;- struct {- uint32_t uc;- int ccc;- } fdc[FDC_MAX];- int fdi, fdj;- int ccc;--check_first_code:- if (n < 0) {- /* Use a replaced unicode character. */- UNPARSE(p, endp, uc);- s += n*-1;- len -= n*-1;- ret = -1;- continue;- } else if (n == spair || always_replace)- /* uc is converted from a surrogate pair.- * this should be treated as a changed code. */- ucptr = NULL;- else- ucptr = s;- s += n;- len -= n;-- /* Hangul Decomposition. */- if ((SIndex = uc - HC_SBASE) >= 0 && SIndex < HC_SCOUNT) {- int L = HC_LBASE + SIndex / HC_NCOUNT;- int V = HC_VBASE + (SIndex % HC_NCOUNT) / HC_TCOUNT;- int T = HC_TBASE + SIndex % HC_TCOUNT;-- REPLACE_UC_WITH(L);- WRITE_UC();- REPLACE_UC_WITH(V);- WRITE_UC();- if (T != HC_TBASE) {- REPLACE_UC_WITH(T);- WRITE_UC();- }- continue;- }- if (IS_DECOMPOSABLE_BLOCK(uc) && CCC(uc) != 0) {- WRITE_UC();- continue;- }-- fdi = 0;- while (get_nfd(&cp1, &cp2, uc) && fdi < FDC_MAX) {- int k;-- for (k = fdi; k > 0; k--)- fdc[k] = fdc[k-1];- fdc[0].ccc = CCC(cp2);- fdc[0].uc = cp2;- fdi++;- REPLACE_UC_WITH(cp1);- }-- /* Read following code points. */- while ((n2 = parse(&uc2, s, len)) > 0 &&- (ccc = CCC(uc2)) != 0 && fdi < FDC_MAX) {- int j, k;-- s += n2;- len -= n2;- for (j = 0; j < fdi; j++) {- if (fdc[j].ccc > ccc)- break;- }- if (j < fdi) {- for (k = fdi; k > j; k--)- fdc[k] = fdc[k-1];- fdc[j].ccc = ccc;- fdc[j].uc = uc2;- } else {- fdc[fdi].ccc = ccc;- fdc[fdi].uc = uc2;- }- fdi++;- }-- WRITE_UC();- for (fdj = 0; fdj < fdi; fdj++) {- REPLACE_UC_WITH(fdc[fdj].uc);- WRITE_UC();- }-- if (n2 == 0)- break;- REPLACE_UC_WITH(uc2);- n = n2;- goto check_first_code;- }- as->length = p - as->s;- as->s[as->length] = '\0';- if (ts == 2)- as->s[as->length+1] = '\0';- return (ret);-}--/*- * libarchive 2.x made incorrect UTF-8 strings in the wrong assumption- * that WCS is Unicode. It is true for several platforms but some are false.- * And then people who did not use UTF-8 locale on the non Unicode WCS- * platform and made a tar file with libarchive(mostly bsdtar) 2.x. Those- * now cannot get right filename from libarchive 3.x and later since we- * fixed the wrong assumption and it is incompatible to older its versions.- * So we provide special option, "compat-2x.x", for resolving it.- * That option enable the string conversion of libarchive 2.x.- *- * Translates the wrong UTF-8 string made by libarchive 2.x into current- * locale character set and appends to the archive_string.- * Note: returns -1 if conversion fails.- */-static int-strncat_from_utf8_libarchive2(struct archive_string *as,- const void *_p, size_t len, struct archive_string_conv *sc)-{- const char *s;- int n;- char *p;- char *end;- uint32_t unicode;-#if HAVE_WCRTOMB- mbstate_t shift_state;-- memset(&shift_state, 0, sizeof(shift_state));-#else- /* Clear the shift state before starting. */- wctomb(NULL, L'\0');-#endif- (void)sc; /* UNUSED */- /*- * Allocate buffer for MBS.- * We need this allocation here since it is possible that- * as->s is still NULL.- */- if (archive_string_ensure(as, as->length + len + 1) == NULL)- return (-1);-- s = (const char *)_p;- p = as->s + as->length;- end = as->s + as->buffer_length - MB_CUR_MAX -1;- while ((n = _utf8_to_unicode(&unicode, s, len)) != 0) {- wchar_t wc;-- if (p >= end) {- as->length = p - as->s;- /* Re-allocate buffer for MBS. */- if (archive_string_ensure(as,- as->length + max(len * 2,- (size_t)MB_CUR_MAX) + 1) == NULL)- return (-1);- p = as->s + as->length;- end = as->s + as->buffer_length - MB_CUR_MAX -1;- }-- /*- * As libarchive 2.x, translates the UTF-8 characters into- * wide-characters in the assumption that WCS is Unicode.- */- if (n < 0) {- n *= -1;- wc = L'?';- } else- wc = (wchar_t)unicode;-- s += n;- len -= n;- /*- * Translates the wide-character into the current locale MBS.- */-#if HAVE_WCRTOMB- n = (int)wcrtomb(p, wc, &shift_state);-#else- n = (int)wctomb(p, wc);-#endif- if (n == -1)- return (-1);- p += n;- }- as->length = p - as->s;- as->s[as->length] = '\0';- return (0);-}---/*- * Conversion functions between current locale dependent MBS and UTF-16BE.- * strncat_from_utf16be() : UTF-16BE --> MBS- * strncat_to_utf16be() : MBS --> UTF16BE- */--#if defined(_WIN32) && !defined(__CYGWIN__)--/*- * Convert a UTF-16BE/LE string to current locale and copy the result.- * Return -1 if conversion fails.- */-static int-win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,- struct archive_string_conv *sc, int be)-{- struct archive_string tmp;- const char *u16;- int ll;- BOOL defchar;- char *mbs;- size_t mbs_size, b;- int ret = 0;-- bytes &= ~1;- if (archive_string_ensure(as, as->length + bytes +1) == NULL)- return (-1);-- mbs = as->s + as->length;- mbs_size = as->buffer_length - as->length -1;-- if (sc->to_cp == CP_C_LOCALE) {- /*- * "C" locale special process.- */- u16 = _p;- ll = 0;- for (b = 0; b < bytes; b += 2) {- uint16_t val;- if (be)- val = archive_be16dec(u16+b);- else- val = archive_le16dec(u16+b);- if (val > 255) {- *mbs++ = '?';- ret = -1;- } else- *mbs++ = (char)(val&0xff);- ll++;- }- as->length += ll;- as->s[as->length] = '\0';- return (ret);- }-- archive_string_init(&tmp);- if (be) {- if (is_big_endian()) {- u16 = _p;- } else {- if (archive_string_ensure(&tmp, bytes+2) == NULL)- return (-1);- memcpy(tmp.s, _p, bytes);- for (b = 0; b < bytes; b += 2) {- uint16_t val = archive_be16dec(tmp.s+b);- archive_le16enc(tmp.s+b, val);- }- u16 = tmp.s;- }- } else {- if (!is_big_endian()) {- u16 = _p;- } else {- if (archive_string_ensure(&tmp, bytes+2) == NULL)- return (-1);- memcpy(tmp.s, _p, bytes);- for (b = 0; b < bytes; b += 2) {- uint16_t val = archive_le16dec(tmp.s+b);- archive_be16enc(tmp.s+b, val);- }- u16 = tmp.s;- }- }-- do {- defchar = 0;- ll = WideCharToMultiByte(sc->to_cp, 0,- (LPCWSTR)u16, (int)bytes>>1, mbs, (int)mbs_size,- NULL, &defchar);- /* Exit loop if we succeeded */- if (ll != 0 ||- GetLastError() != ERROR_INSUFFICIENT_BUFFER) {- break;- }- /* Else expand buffer and loop to try again. */- ll = WideCharToMultiByte(sc->to_cp, 0,- (LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL);- if (archive_string_ensure(as, ll +1) == NULL)- return (-1);- mbs = as->s + as->length;- mbs_size = as->buffer_length - as->length -1;- } while (1);- archive_string_free(&tmp);- as->length += ll;- as->s[as->length] = '\0';- if (ll == 0 || defchar)- ret = -1;- return (ret);-}--static int-win_strncat_from_utf16be(struct archive_string *as, const void *_p,- size_t bytes, struct archive_string_conv *sc)-{- return (win_strncat_from_utf16(as, _p, bytes, sc, 1));-}--static int-win_strncat_from_utf16le(struct archive_string *as, const void *_p,- size_t bytes, struct archive_string_conv *sc)-{- return (win_strncat_from_utf16(as, _p, bytes, sc, 0));-}--static int-is_big_endian(void)-{- uint16_t d = 1;-- return (archive_be16dec(&d) == 1);-}--/*- * Convert a current locale string to UTF-16BE/LE and copy the result.- * Return -1 if conversion fails.- */-static int-win_strncat_to_utf16(struct archive_string *as16, const void *_p,- size_t length, struct archive_string_conv *sc, int bigendian)-{- const char *s = (const char *)_p;- char *u16;- size_t count, avail;-- if (archive_string_ensure(as16,- as16->length + (length + 1) * 2) == NULL)- return (-1);-- u16 = as16->s + as16->length;- avail = as16->buffer_length - 2;- if (sc->from_cp == CP_C_LOCALE) {- /*- * "C" locale special process.- */- count = 0;- while (count < length && *s) {- if (bigendian)- archive_be16enc(u16, *s);- else- archive_le16enc(u16, *s);- u16 += 2;- s++;- count++;- }- as16->length += count << 1;- as16->s[as16->length] = 0;- as16->s[as16->length+1] = 0;- return (0);- }- do {- count = MultiByteToWideChar(sc->from_cp,- MB_PRECOMPOSED, s, (int)length, (LPWSTR)u16, (int)avail>>1);- /* Exit loop if we succeeded */- if (count != 0 ||- GetLastError() != ERROR_INSUFFICIENT_BUFFER) {- break;- }- /* Expand buffer and try again */- count = MultiByteToWideChar(sc->from_cp,- MB_PRECOMPOSED, s, (int)length, NULL, 0);- if (archive_string_ensure(as16, (count +1) * 2)- == NULL)- return (-1);- u16 = as16->s + as16->length;- avail = as16->buffer_length - 2;- } while (1);- as16->length += count * 2;- as16->s[as16->length] = 0;- as16->s[as16->length+1] = 0;- if (count == 0)- return (-1);-- if (is_big_endian()) {- if (!bigendian) {- while (count > 0) {- uint16_t v = archive_be16dec(u16);- archive_le16enc(u16, v);- u16 += 2;- count--;- }- }- } else {- if (bigendian) {- while (count > 0) {- uint16_t v = archive_le16dec(u16);- archive_be16enc(u16, v);- u16 += 2;- count--;- }- }- }- return (0);-}--static int-win_strncat_to_utf16be(struct archive_string *as16, const void *_p,- size_t length, struct archive_string_conv *sc)-{- return (win_strncat_to_utf16(as16, _p, length, sc, 1));-}--static int-win_strncat_to_utf16le(struct archive_string *as16, const void *_p,- size_t length, struct archive_string_conv *sc)-{- return (win_strncat_to_utf16(as16, _p, length, sc, 0));-}--#endif /* _WIN32 && !__CYGWIN__ */--/*- * Do the best effort for conversions.- * We cannot handle UTF-16BE character-set without such iconv,- * but there is a chance if a string consists just ASCII code or- * a current locale is UTF-8.- */--/*- * Convert a UTF-16BE string to current locale and copy the result.- * Return -1 if conversion fails.- */-static int-best_effort_strncat_from_utf16(struct archive_string *as, const void *_p,- size_t bytes, struct archive_string_conv *sc, int be)-{- const char *utf16 = (const char *)_p;- char *mbs;- uint32_t uc;- int n, ret;-- (void)sc; /* UNUSED */- /*- * Other case, we should do the best effort.- * If all character are ASCII(<0x7f), we can convert it.- * if not , we set a alternative character and return -1.- */- ret = 0;- if (archive_string_ensure(as, as->length + bytes +1) == NULL)- return (-1);- mbs = as->s + as->length;-- while ((n = utf16_to_unicode(&uc, utf16, bytes, be)) != 0) {- if (n < 0) {- n *= -1;- ret = -1;- }- bytes -= n;- utf16 += n;-- if (uc > 127) {- /* We cannot handle it. */- *mbs++ = '?';- ret = -1;- } else- *mbs++ = (char)uc;- }- as->length = mbs - as->s;- as->s[as->length] = '\0';- return (ret);-}--static int-best_effort_strncat_from_utf16be(struct archive_string *as, const void *_p,- size_t bytes, struct archive_string_conv *sc)-{- return (best_effort_strncat_from_utf16(as, _p, bytes, sc, 1));-}--static int-best_effort_strncat_from_utf16le(struct archive_string *as, const void *_p,- size_t bytes, struct archive_string_conv *sc)-{- return (best_effort_strncat_from_utf16(as, _p, bytes, sc, 0));-}--/*- * Convert a current locale string to UTF-16BE/LE and copy the result.- * Return -1 if conversion fails.- */-static int-best_effort_strncat_to_utf16(struct archive_string *as16, const void *_p,- size_t length, struct archive_string_conv *sc, int bigendian)-{- const char *s = (const char *)_p;- char *utf16;- size_t remaining;- int ret;-- (void)sc; /* UNUSED */- /*- * Other case, we should do the best effort.- * If all character are ASCII(<0x7f), we can convert it.- * if not , we set a alternative character and return -1.- */- ret = 0;- remaining = length;-- if (archive_string_ensure(as16,- as16->length + (length + 1) * 2) == NULL)- return (-1);-- utf16 = as16->s + as16->length;- while (remaining--) {- unsigned c = *s++;- if (c > 127) {- /* We cannot handle it. */- c = UNICODE_R_CHAR;- ret = -1;- }- if (bigendian)- archive_be16enc(utf16, c);- else- archive_le16enc(utf16, c);- utf16 += 2;- }- as16->length = utf16 - as16->s;- as16->s[as16->length] = 0;- as16->s[as16->length+1] = 0;- return (ret);-}--static int-best_effort_strncat_to_utf16be(struct archive_string *as16, const void *_p,- size_t length, struct archive_string_conv *sc)-{- return (best_effort_strncat_to_utf16(as16, _p, length, sc, 1));-}--static int-best_effort_strncat_to_utf16le(struct archive_string *as16, const void *_p,- size_t length, struct archive_string_conv *sc)-{- return (best_effort_strncat_to_utf16(as16, _p, length, sc, 0));-}---/*- * Multistring operations.- */--void-archive_mstring_clean(struct archive_mstring *aes)-{- archive_wstring_free(&(aes->aes_wcs));- archive_string_free(&(aes->aes_mbs));- archive_string_free(&(aes->aes_utf8));- archive_string_free(&(aes->aes_mbs_in_locale));- aes->aes_set = 0;-}--void-archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *src)-{- dest->aes_set = src->aes_set;- archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs));- archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8));- archive_wstring_copy(&(dest->aes_wcs), &(src->aes_wcs));-}--int-archive_mstring_get_utf8(struct archive *a, struct archive_mstring *aes,- const char **p)-{- struct archive_string_conv *sc;- int r;-- /* If we already have a UTF8 form, return that immediately. */- if (aes->aes_set & AES_SET_UTF8) {- *p = aes->aes_utf8.s;- return (0);- }-- *p = NULL;- /* Try converting WCS to MBS first if MBS does not exist yet. */- if ((aes->aes_set & AES_SET_MBS) == 0) {- const char *pm; /* unused */- archive_mstring_get_mbs(a, aes, &pm); /* ignore errors, we'll handle it later */- }- if (aes->aes_set & AES_SET_MBS) {- sc = archive_string_conversion_to_charset(a, "UTF-8", 1);- if (sc == NULL)- return (-1);/* Couldn't allocate memory for sc. */- r = archive_strncpy_l(&(aes->aes_utf8), aes->aes_mbs.s,- aes->aes_mbs.length, sc);- if (a == NULL)- free_sconv_object(sc);- if (r == 0) {- aes->aes_set |= AES_SET_UTF8;- *p = aes->aes_utf8.s;- return (0);/* success. */- } else- return (-1);/* failure. */- }- return (0);/* success. */-}--int-archive_mstring_get_mbs(struct archive *a, struct archive_mstring *aes,- const char **p)-{- struct archive_string_conv *sc;- int r, ret = 0;-- /* If we already have an MBS form, return that immediately. */- if (aes->aes_set & AES_SET_MBS) {- *p = aes->aes_mbs.s;- return (ret);- }-- *p = NULL;- /* If there's a WCS form, try converting with the native locale. */- if (aes->aes_set & AES_SET_WCS) {- archive_string_empty(&(aes->aes_mbs));- r = archive_string_append_from_wcs(&(aes->aes_mbs),- aes->aes_wcs.s, aes->aes_wcs.length);- *p = aes->aes_mbs.s;- if (r == 0) {- aes->aes_set |= AES_SET_MBS;- return (ret);- } else- ret = -1;- }-- /* If there's a UTF-8 form, try converting with the native locale. */- if (aes->aes_set & AES_SET_UTF8) {- archive_string_empty(&(aes->aes_mbs));- sc = archive_string_conversion_from_charset(a, "UTF-8", 1);- if (sc == NULL)- return (-1);/* Couldn't allocate memory for sc. */- r = archive_strncpy_l(&(aes->aes_mbs),- aes->aes_utf8.s, aes->aes_utf8.length, sc);- if (a == NULL)- free_sconv_object(sc);- *p = aes->aes_mbs.s;- if (r == 0) {- aes->aes_set |= AES_SET_MBS;- ret = 0;/* success; overwrite previous error. */- } else- ret = -1;/* failure. */- }- return (ret);-}--int-archive_mstring_get_wcs(struct archive *a, struct archive_mstring *aes,- const wchar_t **wp)-{- int r, ret = 0;-- (void)a;/* UNUSED */- /* Return WCS form if we already have it. */- if (aes->aes_set & AES_SET_WCS) {- *wp = aes->aes_wcs.s;- return (ret);- }-- *wp = NULL;- /* Try converting UTF8 to MBS first if MBS does not exist yet. */- if ((aes->aes_set & AES_SET_MBS) == 0) {- const char *p; /* unused */- archive_mstring_get_mbs(a, aes, &p); /* ignore errors, we'll handle it later */- }- /* Try converting MBS to WCS using native locale. */- if (aes->aes_set & AES_SET_MBS) {- archive_wstring_empty(&(aes->aes_wcs));- r = archive_wstring_append_from_mbs(&(aes->aes_wcs),- aes->aes_mbs.s, aes->aes_mbs.length);- if (r == 0) {- aes->aes_set |= AES_SET_WCS;- *wp = aes->aes_wcs.s;- } else- ret = -1;/* failure. */- }- return (ret);-}--int-archive_mstring_get_mbs_l(struct archive *a, struct archive_mstring *aes,- const char **p, size_t *length, struct archive_string_conv *sc)-{- int ret = 0;-#if defined(_WIN32) && !defined(__CYGWIN__)- int r;-- /*- * Internationalization programming on Windows must use Wide- * characters because Windows platform cannot make locale UTF-8.- */- if (sc != NULL && (aes->aes_set & AES_SET_WCS) != 0) {- archive_string_empty(&(aes->aes_mbs_in_locale));- r = archive_string_append_from_wcs_in_codepage(- &(aes->aes_mbs_in_locale), aes->aes_wcs.s,- aes->aes_wcs.length, sc);- if (r == 0) {- *p = aes->aes_mbs_in_locale.s;- if (length != NULL)- *length = aes->aes_mbs_in_locale.length;- return (0);- } else if (errno == ENOMEM)- return (-1);- else- ret = -1;- }-#endif-- /* If there is not an MBS form but there is a WCS or UTF8 form, try converting- * with the native locale to be used for translating it to specified- * character-set. */- if ((aes->aes_set & AES_SET_MBS) == 0) {- const char *pm; /* unused */- archive_mstring_get_mbs(a, aes, &pm); /* ignore errors, we'll handle it later */- }- /* If we already have an MBS form, use it to be translated to- * specified character-set. */- if (aes->aes_set & AES_SET_MBS) {- if (sc == NULL) {- /* Conversion is unneeded. */- *p = aes->aes_mbs.s;- if (length != NULL)- *length = aes->aes_mbs.length;- return (0);- }- ret = archive_strncpy_l(&(aes->aes_mbs_in_locale),- aes->aes_mbs.s, aes->aes_mbs.length, sc);- *p = aes->aes_mbs_in_locale.s;- if (length != NULL)- *length = aes->aes_mbs_in_locale.length;- } else {- *p = NULL;- if (length != NULL)- *length = 0;- }- return (ret);-}--int-archive_mstring_copy_mbs(struct archive_mstring *aes, const char *mbs)-{- if (mbs == NULL) {- aes->aes_set = 0;- return (0);- }- return (archive_mstring_copy_mbs_len(aes, mbs, strlen(mbs)));-}--int-archive_mstring_copy_mbs_len(struct archive_mstring *aes, const char *mbs,- size_t len)-{- if (mbs == NULL) {- aes->aes_set = 0;- return (0);- }- aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */- archive_strncpy(&(aes->aes_mbs), mbs, len);- archive_string_empty(&(aes->aes_utf8));- archive_wstring_empty(&(aes->aes_wcs));- return (0);-}--int-archive_mstring_copy_wcs(struct archive_mstring *aes, const wchar_t *wcs)-{- return archive_mstring_copy_wcs_len(aes, wcs,- wcs == NULL ? 0 : wcslen(wcs));-}--int-archive_mstring_copy_utf8(struct archive_mstring *aes, const char *utf8)-{- if (utf8 == NULL) {- aes->aes_set = 0;- return (0);- }- aes->aes_set = AES_SET_UTF8;- archive_string_empty(&(aes->aes_mbs));- archive_string_empty(&(aes->aes_wcs));- archive_strncpy(&(aes->aes_utf8), utf8, strlen(utf8));- return (int)strlen(utf8);-}--int-archive_mstring_copy_wcs_len(struct archive_mstring *aes, const wchar_t *wcs,- size_t len)-{- if (wcs == NULL) {- aes->aes_set = 0;- return (0);- }- aes->aes_set = AES_SET_WCS; /* Only WCS form set. */- archive_string_empty(&(aes->aes_mbs));- archive_string_empty(&(aes->aes_utf8));- archive_wstrncpy(&(aes->aes_wcs), wcs, len);- return (0);-}--int-archive_mstring_copy_mbs_len_l(struct archive_mstring *aes,- const char *mbs, size_t len, struct archive_string_conv *sc)-{- int r;-- if (mbs == NULL) {- aes->aes_set = 0;- return (0);- }- archive_string_empty(&(aes->aes_mbs));- archive_wstring_empty(&(aes->aes_wcs));- archive_string_empty(&(aes->aes_utf8));-#if defined(_WIN32) && !defined(__CYGWIN__)- /*- * Internationalization programming on Windows must use Wide- * characters because Windows platform cannot make locale UTF-8.- */- if (sc == NULL) {- if (archive_string_append(&(aes->aes_mbs),- mbs, mbsnbytes(mbs, len)) == NULL) {- aes->aes_set = 0;- r = -1;- } else {- aes->aes_set = AES_SET_MBS;- r = 0;- }-#if defined(HAVE_ICONV)- } else if (sc != NULL && sc->cd_w != (iconv_t)-1) {- /*- * This case happens only when MultiByteToWideChar() cannot- * handle sc->from_cp, and we have to iconv in order to- * translate character-set to wchar_t,UTF-16.- */- iconv_t cd = sc->cd;- unsigned from_cp;- int flag;-- /*- * Translate multi-bytes from some character-set to UTF-8.- */ - sc->cd = sc->cd_w;- r = archive_strncpy_l(&(aes->aes_utf8), mbs, len, sc);- sc->cd = cd;- if (r != 0) {- aes->aes_set = 0;- return (r);- }- aes->aes_set = AES_SET_UTF8;-- /*- * Append the UTF-8 string into wstring.- */ - flag = sc->flag;- sc->flag &= ~(SCONV_NORMALIZATION_C- | SCONV_TO_UTF16| SCONV_FROM_UTF16);- from_cp = sc->from_cp;- sc->from_cp = CP_UTF8;- r = archive_wstring_append_from_mbs_in_codepage(&(aes->aes_wcs),- aes->aes_utf8.s, aes->aes_utf8.length, sc);- sc->flag = flag;- sc->from_cp = from_cp;- if (r == 0)- aes->aes_set |= AES_SET_WCS;-#endif- } else {- r = archive_wstring_append_from_mbs_in_codepage(- &(aes->aes_wcs), mbs, len, sc);- if (r == 0)- aes->aes_set = AES_SET_WCS;- else- aes->aes_set = 0;- }-#else- r = archive_strncpy_l(&(aes->aes_mbs), mbs, len, sc);- if (r == 0)- aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */- else- aes->aes_set = 0;-#endif- return (r);-}--/*- * The 'update' form tries to proactively update all forms of- * this string (WCS and MBS) and returns an error if any of- * them fail. This is used by the 'pax' handler, for instance,- * to detect and report character-conversion failures early while- * still allowing clients to get potentially useful values from- * the more tolerant lazy conversions. (get_mbs and get_wcs will- * strive to give the user something useful, so you can get hopefully- * usable values even if some of the character conversions are failing.)- */-int-archive_mstring_update_utf8(struct archive *a, struct archive_mstring *aes,- const char *utf8)-{- struct archive_string_conv *sc;- int r;-- if (utf8 == NULL) {- aes->aes_set = 0;- return (0); /* Succeeded in clearing everything. */- }-- /* Save the UTF8 string. */- archive_strcpy(&(aes->aes_utf8), utf8);-- /* Empty the mbs and wcs strings. */- archive_string_empty(&(aes->aes_mbs));- archive_wstring_empty(&(aes->aes_wcs));-- aes->aes_set = AES_SET_UTF8; /* Only UTF8 is set now. */-- /* Try converting UTF-8 to MBS, return false on failure. */- sc = archive_string_conversion_from_charset(a, "UTF-8", 1);- if (sc == NULL)- return (-1);/* Couldn't allocate memory for sc. */- r = archive_strcpy_l(&(aes->aes_mbs), utf8, sc);- if (a == NULL)- free_sconv_object(sc);- if (r != 0)- return (-1);- aes->aes_set = AES_SET_UTF8 | AES_SET_MBS; /* Both UTF8 and MBS set. */-- /* Try converting MBS to WCS, return false on failure. */- if (archive_wstring_append_from_mbs(&(aes->aes_wcs), aes->aes_mbs.s,- aes->aes_mbs.length))- return (-1);- aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS;-- /* All conversions succeeded. */- return (0);-}
− c/archive_string.h
@@ -1,243 +0,0 @@-/*-- * 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.- *- * $FreeBSD: head/lib/libarchive/archive_string.h 201092 2009-12-28 02:26:06Z kientzle $- *- */--#ifndef ARCHIVE_STRING_H_INCLUDED-#define ARCHIVE_STRING_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#ifndef __LIBARCHIVE_TEST-#error This header is only to be used internally to libarchive.-#endif-#endif--#include <stdarg.h>-#ifdef HAVE_STDLIB_H-#include <stdlib.h> /* required for wchar_t on some systems */-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_WCHAR_H-#include <wchar.h>-#endif--#include "archive.h"--/*- * Basic resizable/reusable string support similar to Java's "StringBuffer."- *- * Unlike sbuf(9), the buffers here are fully reusable and track the- * length throughout.- */--struct archive_string {- char *s; /* Pointer to the storage */- size_t length; /* Length of 's' in characters */- size_t buffer_length; /* Length of malloc-ed storage in bytes. */-};--struct archive_wstring {- wchar_t *s; /* Pointer to the storage */- size_t length; /* Length of 's' in characters */- size_t buffer_length; /* Length of malloc-ed storage in bytes. */-};--struct archive_string_conv;--/* Initialize an archive_string object on the stack or elsewhere. */-#define archive_string_init(a) \- do { (a)->s = NULL; (a)->length = 0; (a)->buffer_length = 0; } while(0)--/* Append a C char to an archive_string, resizing as necessary. */-struct archive_string *-archive_strappend_char(struct archive_string *, char);--/* Ditto for a wchar_t and an archive_wstring. */-struct archive_wstring *-archive_wstrappend_wchar(struct archive_wstring *, wchar_t);--/* Append a raw array to an archive_string, resizing as necessary */-struct archive_string *-archive_array_append(struct archive_string *, const char *, size_t);--/* Convert a Unicode string to current locale and append the result. */-/* Returns -1 if conversion fails. */-int-archive_string_append_from_wcs(struct archive_string *, const wchar_t *, size_t);---/* Create a string conversion object.- * Return NULL and set a error message if the conversion is not supported- * on the platform. */-struct archive_string_conv *-archive_string_conversion_to_charset(struct archive *, const char *, int);-struct archive_string_conv *-archive_string_conversion_from_charset(struct archive *, const char *, int);-/* Create the default string conversion object for reading/writing an archive.- * Return NULL if the conversion is unneeded.- * Note: On non Windows platform this always returns NULL.- */-struct archive_string_conv *-archive_string_default_conversion_for_read(struct archive *);-struct archive_string_conv *-archive_string_default_conversion_for_write(struct archive *);-/* Dispose of a string conversion object. */-void-archive_string_conversion_free(struct archive *);-const char *-archive_string_conversion_charset_name(struct archive_string_conv *);-void-archive_string_conversion_set_opt(struct archive_string_conv *, int);-#define SCONV_SET_OPT_UTF8_LIBARCHIVE2X 1-#define SCONV_SET_OPT_NORMALIZATION_C 2-#define SCONV_SET_OPT_NORMALIZATION_D 4---/* Copy one archive_string to another in locale conversion.- * Return -1 if conversion fails. */-int-archive_strncpy_l(struct archive_string *, const void *, size_t,- struct archive_string_conv *);--/* Copy one archive_string to another in locale conversion.- * Return -1 if conversion fails. */-int-archive_strncat_l(struct archive_string *, const void *, size_t,- struct archive_string_conv *);---/* Copy one archive_string to another */-#define archive_string_copy(dest, src) \- ((dest)->length = 0, archive_string_concat((dest), (src)))-#define archive_wstring_copy(dest, src) \- ((dest)->length = 0, archive_wstring_concat((dest), (src)))--/* Concatenate one archive_string to another */-void archive_string_concat(struct archive_string *dest, struct archive_string *src);-void archive_wstring_concat(struct archive_wstring *dest, struct archive_wstring *src);--/* Ensure that the underlying buffer is at least as large as the request. */-struct archive_string *-archive_string_ensure(struct archive_string *, size_t);-struct archive_wstring *-archive_wstring_ensure(struct archive_wstring *, size_t);--/* Append C string, which may lack trailing \0. */-/* The source is declared void * here because this gets used with- * "signed char *", "unsigned char *" and "char *" arguments.- * Declaring it "char *" as with some of the other functions just- * leads to a lot of extra casts. */-struct archive_string *-archive_strncat(struct archive_string *, const void *, size_t);-struct archive_wstring *-archive_wstrncat(struct archive_wstring *, const wchar_t *, size_t);--/* Append a C string to an archive_string, resizing as necessary. */-struct archive_string *-archive_strcat(struct archive_string *, const void *);-struct archive_wstring *-archive_wstrcat(struct archive_wstring *, const wchar_t *);--/* Copy a C string to an archive_string, resizing as necessary. */-#define archive_strcpy(as,p) \- archive_strncpy((as), (p), ((p) == NULL ? 0 : strlen(p)))-#define archive_wstrcpy(as,p) \- archive_wstrncpy((as), (p), ((p) == NULL ? 0 : wcslen(p)))-#define archive_strcpy_l(as,p,lo) \- archive_strncpy_l((as), (p), ((p) == NULL ? 0 : strlen(p)), (lo))--/* Copy a C string to an archive_string with limit, resizing as necessary. */-#define archive_strncpy(as,p,l) \- ((as)->length=0, archive_strncat((as), (p), (l)))-#define archive_wstrncpy(as,p,l) \- ((as)->length = 0, archive_wstrncat((as), (p), (l)))--/* Return length of string. */-#define archive_strlen(a) ((a)->length)--/* Set string length to zero. */-#define archive_string_empty(a) ((a)->length = 0)-#define archive_wstring_empty(a) ((a)->length = 0)--/* Release any allocated storage resources. */-void archive_string_free(struct archive_string *);-void archive_wstring_free(struct archive_wstring *);--/* Like 'vsprintf', but resizes the underlying string as necessary. */-/* Note: This only implements a small subset of standard printf functionality. */-void archive_string_vsprintf(struct archive_string *, const char *,- va_list) __LA_PRINTF(2, 0);-void archive_string_sprintf(struct archive_string *, const char *, ...)- __LA_PRINTF(2, 3);--/* Translates from MBS to Unicode. */-/* Returns non-zero if conversion failed in any way. */-int archive_wstring_append_from_mbs(struct archive_wstring *dest,- const char *, size_t);---/* A "multistring" can hold Unicode, UTF8, or MBS versions of- * the string. If you set and read the same version, no translation- * is done. If you set and read different versions, the library- * will attempt to transparently convert.- */-struct archive_mstring {- struct archive_string aes_mbs;- struct archive_string aes_utf8;- struct archive_wstring aes_wcs;- struct archive_string aes_mbs_in_locale;- /* Bitmap of which of the above are valid. Because we're lazy- * about malloc-ing and reusing the underlying storage, we- * can't rely on NULL pointers to indicate whether a string- * has been set. */- int aes_set;-#define AES_SET_MBS 1-#define AES_SET_UTF8 2-#define AES_SET_WCS 4-};--void archive_mstring_clean(struct archive_mstring *);-void archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *src);-int archive_mstring_get_mbs(struct archive *, struct archive_mstring *, const char **);-int archive_mstring_get_utf8(struct archive *, struct archive_mstring *, const char **);-int archive_mstring_get_wcs(struct archive *, struct archive_mstring *, const wchar_t **);-int archive_mstring_get_mbs_l(struct archive *, struct archive_mstring *, const char **,- size_t *, struct archive_string_conv *);-int archive_mstring_copy_mbs(struct archive_mstring *, const char *mbs);-int archive_mstring_copy_mbs_len(struct archive_mstring *, const char *mbs,- size_t);-int archive_mstring_copy_utf8(struct archive_mstring *, const char *utf8);-int archive_mstring_copy_wcs(struct archive_mstring *, const wchar_t *wcs);-int archive_mstring_copy_wcs_len(struct archive_mstring *,- const wchar_t *wcs, size_t);-int archive_mstring_copy_mbs_len_l(struct archive_mstring *,- const char *mbs, size_t, struct archive_string_conv *);-int archive_mstring_update_utf8(struct archive *, struct archive_mstring *aes, const char *utf8);---#endif
− c/archive_string_composition.h
@@ -1,2292 +0,0 @@-/*-- * Copyright (c) 2011-2012 libarchive Project- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- *- */--/*- * ATTENTION!- * This file is generated by build/utils/gen_archive_string_composition_h.sh- * from http://unicode.org/Public/6.0.0/ucd/UnicodeData.txt- *- * See also http://unicode.org/report/tr15/- */--#ifndef ARCHIVE_STRING_COMPOSITION_H_INCLUDED-#define ARCHIVE_STRING_COMPOSITION_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--struct unicode_composition_table {- uint32_t cp1;- uint32_t cp2;- uint32_t nfc;-};--static const struct unicode_composition_table u_composition_table[] = {- { 0x0003C , 0x00338 , 0x0226E },- { 0x0003D , 0x00338 , 0x02260 },- { 0x0003E , 0x00338 , 0x0226F },- { 0x00041 , 0x00300 , 0x000C0 },- { 0x00041 , 0x00301 , 0x000C1 },- { 0x00041 , 0x00302 , 0x000C2 },- { 0x00041 , 0x00303 , 0x000C3 },- { 0x00041 , 0x00304 , 0x00100 },- { 0x00041 , 0x00306 , 0x00102 },- { 0x00041 , 0x00307 , 0x00226 },- { 0x00041 , 0x00308 , 0x000C4 },- { 0x00041 , 0x00309 , 0x01EA2 },- { 0x00041 , 0x0030A , 0x000C5 },- { 0x00041 , 0x0030C , 0x001CD },- { 0x00041 , 0x0030F , 0x00200 },- { 0x00041 , 0x00311 , 0x00202 },- { 0x00041 , 0x00323 , 0x01EA0 },- { 0x00041 , 0x00325 , 0x01E00 },- { 0x00041 , 0x00328 , 0x00104 },- { 0x00042 , 0x00307 , 0x01E02 },- { 0x00042 , 0x00323 , 0x01E04 },- { 0x00042 , 0x00331 , 0x01E06 },- { 0x00043 , 0x00301 , 0x00106 },- { 0x00043 , 0x00302 , 0x00108 },- { 0x00043 , 0x00307 , 0x0010A },- { 0x00043 , 0x0030C , 0x0010C },- { 0x00043 , 0x00327 , 0x000C7 },- { 0x00044 , 0x00307 , 0x01E0A },- { 0x00044 , 0x0030C , 0x0010E },- { 0x00044 , 0x00323 , 0x01E0C },- { 0x00044 , 0x00327 , 0x01E10 },- { 0x00044 , 0x0032D , 0x01E12 },- { 0x00044 , 0x00331 , 0x01E0E },- { 0x00045 , 0x00300 , 0x000C8 },- { 0x00045 , 0x00301 , 0x000C9 },- { 0x00045 , 0x00302 , 0x000CA },- { 0x00045 , 0x00303 , 0x01EBC },- { 0x00045 , 0x00304 , 0x00112 },- { 0x00045 , 0x00306 , 0x00114 },- { 0x00045 , 0x00307 , 0x00116 },- { 0x00045 , 0x00308 , 0x000CB },- { 0x00045 , 0x00309 , 0x01EBA },- { 0x00045 , 0x0030C , 0x0011A },- { 0x00045 , 0x0030F , 0x00204 },- { 0x00045 , 0x00311 , 0x00206 },- { 0x00045 , 0x00323 , 0x01EB8 },- { 0x00045 , 0x00327 , 0x00228 },- { 0x00045 , 0x00328 , 0x00118 },- { 0x00045 , 0x0032D , 0x01E18 },- { 0x00045 , 0x00330 , 0x01E1A },- { 0x00046 , 0x00307 , 0x01E1E },- { 0x00047 , 0x00301 , 0x001F4 },- { 0x00047 , 0x00302 , 0x0011C },- { 0x00047 , 0x00304 , 0x01E20 },- { 0x00047 , 0x00306 , 0x0011E },- { 0x00047 , 0x00307 , 0x00120 },- { 0x00047 , 0x0030C , 0x001E6 },- { 0x00047 , 0x00327 , 0x00122 },- { 0x00048 , 0x00302 , 0x00124 },- { 0x00048 , 0x00307 , 0x01E22 },- { 0x00048 , 0x00308 , 0x01E26 },- { 0x00048 , 0x0030C , 0x0021E },- { 0x00048 , 0x00323 , 0x01E24 },- { 0x00048 , 0x00327 , 0x01E28 },- { 0x00048 , 0x0032E , 0x01E2A },- { 0x00049 , 0x00300 , 0x000CC },- { 0x00049 , 0x00301 , 0x000CD },- { 0x00049 , 0x00302 , 0x000CE },- { 0x00049 , 0x00303 , 0x00128 },- { 0x00049 , 0x00304 , 0x0012A },- { 0x00049 , 0x00306 , 0x0012C },- { 0x00049 , 0x00307 , 0x00130 },- { 0x00049 , 0x00308 , 0x000CF },- { 0x00049 , 0x00309 , 0x01EC8 },- { 0x00049 , 0x0030C , 0x001CF },- { 0x00049 , 0x0030F , 0x00208 },- { 0x00049 , 0x00311 , 0x0020A },- { 0x00049 , 0x00323 , 0x01ECA },- { 0x00049 , 0x00328 , 0x0012E },- { 0x00049 , 0x00330 , 0x01E2C },- { 0x0004A , 0x00302 , 0x00134 },- { 0x0004B , 0x00301 , 0x01E30 },- { 0x0004B , 0x0030C , 0x001E8 },- { 0x0004B , 0x00323 , 0x01E32 },- { 0x0004B , 0x00327 , 0x00136 },- { 0x0004B , 0x00331 , 0x01E34 },- { 0x0004C , 0x00301 , 0x00139 },- { 0x0004C , 0x0030C , 0x0013D },- { 0x0004C , 0x00323 , 0x01E36 },- { 0x0004C , 0x00327 , 0x0013B },- { 0x0004C , 0x0032D , 0x01E3C },- { 0x0004C , 0x00331 , 0x01E3A },- { 0x0004D , 0x00301 , 0x01E3E },- { 0x0004D , 0x00307 , 0x01E40 },- { 0x0004D , 0x00323 , 0x01E42 },- { 0x0004E , 0x00300 , 0x001F8 },- { 0x0004E , 0x00301 , 0x00143 },- { 0x0004E , 0x00303 , 0x000D1 },- { 0x0004E , 0x00307 , 0x01E44 },- { 0x0004E , 0x0030C , 0x00147 },- { 0x0004E , 0x00323 , 0x01E46 },- { 0x0004E , 0x00327 , 0x00145 },- { 0x0004E , 0x0032D , 0x01E4A },- { 0x0004E , 0x00331 , 0x01E48 },- { 0x0004F , 0x00300 , 0x000D2 },- { 0x0004F , 0x00301 , 0x000D3 },- { 0x0004F , 0x00302 , 0x000D4 },- { 0x0004F , 0x00303 , 0x000D5 },- { 0x0004F , 0x00304 , 0x0014C },- { 0x0004F , 0x00306 , 0x0014E },- { 0x0004F , 0x00307 , 0x0022E },- { 0x0004F , 0x00308 , 0x000D6 },- { 0x0004F , 0x00309 , 0x01ECE },- { 0x0004F , 0x0030B , 0x00150 },- { 0x0004F , 0x0030C , 0x001D1 },- { 0x0004F , 0x0030F , 0x0020C },- { 0x0004F , 0x00311 , 0x0020E },- { 0x0004F , 0x0031B , 0x001A0 },- { 0x0004F , 0x00323 , 0x01ECC },- { 0x0004F , 0x00328 , 0x001EA },- { 0x00050 , 0x00301 , 0x01E54 },- { 0x00050 , 0x00307 , 0x01E56 },- { 0x00052 , 0x00301 , 0x00154 },- { 0x00052 , 0x00307 , 0x01E58 },- { 0x00052 , 0x0030C , 0x00158 },- { 0x00052 , 0x0030F , 0x00210 },- { 0x00052 , 0x00311 , 0x00212 },- { 0x00052 , 0x00323 , 0x01E5A },- { 0x00052 , 0x00327 , 0x00156 },- { 0x00052 , 0x00331 , 0x01E5E },- { 0x00053 , 0x00301 , 0x0015A },- { 0x00053 , 0x00302 , 0x0015C },- { 0x00053 , 0x00307 , 0x01E60 },- { 0x00053 , 0x0030C , 0x00160 },- { 0x00053 , 0x00323 , 0x01E62 },- { 0x00053 , 0x00326 , 0x00218 },- { 0x00053 , 0x00327 , 0x0015E },- { 0x00054 , 0x00307 , 0x01E6A },- { 0x00054 , 0x0030C , 0x00164 },- { 0x00054 , 0x00323 , 0x01E6C },- { 0x00054 , 0x00326 , 0x0021A },- { 0x00054 , 0x00327 , 0x00162 },- { 0x00054 , 0x0032D , 0x01E70 },- { 0x00054 , 0x00331 , 0x01E6E },- { 0x00055 , 0x00300 , 0x000D9 },- { 0x00055 , 0x00301 , 0x000DA },- { 0x00055 , 0x00302 , 0x000DB },- { 0x00055 , 0x00303 , 0x00168 },- { 0x00055 , 0x00304 , 0x0016A },- { 0x00055 , 0x00306 , 0x0016C },- { 0x00055 , 0x00308 , 0x000DC },- { 0x00055 , 0x00309 , 0x01EE6 },- { 0x00055 , 0x0030A , 0x0016E },- { 0x00055 , 0x0030B , 0x00170 },- { 0x00055 , 0x0030C , 0x001D3 },- { 0x00055 , 0x0030F , 0x00214 },- { 0x00055 , 0x00311 , 0x00216 },- { 0x00055 , 0x0031B , 0x001AF },- { 0x00055 , 0x00323 , 0x01EE4 },- { 0x00055 , 0x00324 , 0x01E72 },- { 0x00055 , 0x00328 , 0x00172 },- { 0x00055 , 0x0032D , 0x01E76 },- { 0x00055 , 0x00330 , 0x01E74 },- { 0x00056 , 0x00303 , 0x01E7C },- { 0x00056 , 0x00323 , 0x01E7E },- { 0x00057 , 0x00300 , 0x01E80 },- { 0x00057 , 0x00301 , 0x01E82 },- { 0x00057 , 0x00302 , 0x00174 },- { 0x00057 , 0x00307 , 0x01E86 },- { 0x00057 , 0x00308 , 0x01E84 },- { 0x00057 , 0x00323 , 0x01E88 },- { 0x00058 , 0x00307 , 0x01E8A },- { 0x00058 , 0x00308 , 0x01E8C },- { 0x00059 , 0x00300 , 0x01EF2 },- { 0x00059 , 0x00301 , 0x000DD },- { 0x00059 , 0x00302 , 0x00176 },- { 0x00059 , 0x00303 , 0x01EF8 },- { 0x00059 , 0x00304 , 0x00232 },- { 0x00059 , 0x00307 , 0x01E8E },- { 0x00059 , 0x00308 , 0x00178 },- { 0x00059 , 0x00309 , 0x01EF6 },- { 0x00059 , 0x00323 , 0x01EF4 },- { 0x0005A , 0x00301 , 0x00179 },- { 0x0005A , 0x00302 , 0x01E90 },- { 0x0005A , 0x00307 , 0x0017B },- { 0x0005A , 0x0030C , 0x0017D },- { 0x0005A , 0x00323 , 0x01E92 },- { 0x0005A , 0x00331 , 0x01E94 },- { 0x00061 , 0x00300 , 0x000E0 },- { 0x00061 , 0x00301 , 0x000E1 },- { 0x00061 , 0x00302 , 0x000E2 },- { 0x00061 , 0x00303 , 0x000E3 },- { 0x00061 , 0x00304 , 0x00101 },- { 0x00061 , 0x00306 , 0x00103 },- { 0x00061 , 0x00307 , 0x00227 },- { 0x00061 , 0x00308 , 0x000E4 },- { 0x00061 , 0x00309 , 0x01EA3 },- { 0x00061 , 0x0030A , 0x000E5 },- { 0x00061 , 0x0030C , 0x001CE },- { 0x00061 , 0x0030F , 0x00201 },- { 0x00061 , 0x00311 , 0x00203 },- { 0x00061 , 0x00323 , 0x01EA1 },- { 0x00061 , 0x00325 , 0x01E01 },- { 0x00061 , 0x00328 , 0x00105 },- { 0x00062 , 0x00307 , 0x01E03 },- { 0x00062 , 0x00323 , 0x01E05 },- { 0x00062 , 0x00331 , 0x01E07 },- { 0x00063 , 0x00301 , 0x00107 },- { 0x00063 , 0x00302 , 0x00109 },- { 0x00063 , 0x00307 , 0x0010B },- { 0x00063 , 0x0030C , 0x0010D },- { 0x00063 , 0x00327 , 0x000E7 },- { 0x00064 , 0x00307 , 0x01E0B },- { 0x00064 , 0x0030C , 0x0010F },- { 0x00064 , 0x00323 , 0x01E0D },- { 0x00064 , 0x00327 , 0x01E11 },- { 0x00064 , 0x0032D , 0x01E13 },- { 0x00064 , 0x00331 , 0x01E0F },- { 0x00065 , 0x00300 , 0x000E8 },- { 0x00065 , 0x00301 , 0x000E9 },- { 0x00065 , 0x00302 , 0x000EA },- { 0x00065 , 0x00303 , 0x01EBD },- { 0x00065 , 0x00304 , 0x00113 },- { 0x00065 , 0x00306 , 0x00115 },- { 0x00065 , 0x00307 , 0x00117 },- { 0x00065 , 0x00308 , 0x000EB },- { 0x00065 , 0x00309 , 0x01EBB },- { 0x00065 , 0x0030C , 0x0011B },- { 0x00065 , 0x0030F , 0x00205 },- { 0x00065 , 0x00311 , 0x00207 },- { 0x00065 , 0x00323 , 0x01EB9 },- { 0x00065 , 0x00327 , 0x00229 },- { 0x00065 , 0x00328 , 0x00119 },- { 0x00065 , 0x0032D , 0x01E19 },- { 0x00065 , 0x00330 , 0x01E1B },- { 0x00066 , 0x00307 , 0x01E1F },- { 0x00067 , 0x00301 , 0x001F5 },- { 0x00067 , 0x00302 , 0x0011D },- { 0x00067 , 0x00304 , 0x01E21 },- { 0x00067 , 0x00306 , 0x0011F },- { 0x00067 , 0x00307 , 0x00121 },- { 0x00067 , 0x0030C , 0x001E7 },- { 0x00067 , 0x00327 , 0x00123 },- { 0x00068 , 0x00302 , 0x00125 },- { 0x00068 , 0x00307 , 0x01E23 },- { 0x00068 , 0x00308 , 0x01E27 },- { 0x00068 , 0x0030C , 0x0021F },- { 0x00068 , 0x00323 , 0x01E25 },- { 0x00068 , 0x00327 , 0x01E29 },- { 0x00068 , 0x0032E , 0x01E2B },- { 0x00068 , 0x00331 , 0x01E96 },- { 0x00069 , 0x00300 , 0x000EC },- { 0x00069 , 0x00301 , 0x000ED },- { 0x00069 , 0x00302 , 0x000EE },- { 0x00069 , 0x00303 , 0x00129 },- { 0x00069 , 0x00304 , 0x0012B },- { 0x00069 , 0x00306 , 0x0012D },- { 0x00069 , 0x00308 , 0x000EF },- { 0x00069 , 0x00309 , 0x01EC9 },- { 0x00069 , 0x0030C , 0x001D0 },- { 0x00069 , 0x0030F , 0x00209 },- { 0x00069 , 0x00311 , 0x0020B },- { 0x00069 , 0x00323 , 0x01ECB },- { 0x00069 , 0x00328 , 0x0012F },- { 0x00069 , 0x00330 , 0x01E2D },- { 0x0006A , 0x00302 , 0x00135 },- { 0x0006A , 0x0030C , 0x001F0 },- { 0x0006B , 0x00301 , 0x01E31 },- { 0x0006B , 0x0030C , 0x001E9 },- { 0x0006B , 0x00323 , 0x01E33 },- { 0x0006B , 0x00327 , 0x00137 },- { 0x0006B , 0x00331 , 0x01E35 },- { 0x0006C , 0x00301 , 0x0013A },- { 0x0006C , 0x0030C , 0x0013E },- { 0x0006C , 0x00323 , 0x01E37 },- { 0x0006C , 0x00327 , 0x0013C },- { 0x0006C , 0x0032D , 0x01E3D },- { 0x0006C , 0x00331 , 0x01E3B },- { 0x0006D , 0x00301 , 0x01E3F },- { 0x0006D , 0x00307 , 0x01E41 },- { 0x0006D , 0x00323 , 0x01E43 },- { 0x0006E , 0x00300 , 0x001F9 },- { 0x0006E , 0x00301 , 0x00144 },- { 0x0006E , 0x00303 , 0x000F1 },- { 0x0006E , 0x00307 , 0x01E45 },- { 0x0006E , 0x0030C , 0x00148 },- { 0x0006E , 0x00323 , 0x01E47 },- { 0x0006E , 0x00327 , 0x00146 },- { 0x0006E , 0x0032D , 0x01E4B },- { 0x0006E , 0x00331 , 0x01E49 },- { 0x0006F , 0x00300 , 0x000F2 },- { 0x0006F , 0x00301 , 0x000F3 },- { 0x0006F , 0x00302 , 0x000F4 },- { 0x0006F , 0x00303 , 0x000F5 },- { 0x0006F , 0x00304 , 0x0014D },- { 0x0006F , 0x00306 , 0x0014F },- { 0x0006F , 0x00307 , 0x0022F },- { 0x0006F , 0x00308 , 0x000F6 },- { 0x0006F , 0x00309 , 0x01ECF },- { 0x0006F , 0x0030B , 0x00151 },- { 0x0006F , 0x0030C , 0x001D2 },- { 0x0006F , 0x0030F , 0x0020D },- { 0x0006F , 0x00311 , 0x0020F },- { 0x0006F , 0x0031B , 0x001A1 },- { 0x0006F , 0x00323 , 0x01ECD },- { 0x0006F , 0x00328 , 0x001EB },- { 0x00070 , 0x00301 , 0x01E55 },- { 0x00070 , 0x00307 , 0x01E57 },- { 0x00072 , 0x00301 , 0x00155 },- { 0x00072 , 0x00307 , 0x01E59 },- { 0x00072 , 0x0030C , 0x00159 },- { 0x00072 , 0x0030F , 0x00211 },- { 0x00072 , 0x00311 , 0x00213 },- { 0x00072 , 0x00323 , 0x01E5B },- { 0x00072 , 0x00327 , 0x00157 },- { 0x00072 , 0x00331 , 0x01E5F },- { 0x00073 , 0x00301 , 0x0015B },- { 0x00073 , 0x00302 , 0x0015D },- { 0x00073 , 0x00307 , 0x01E61 },- { 0x00073 , 0x0030C , 0x00161 },- { 0x00073 , 0x00323 , 0x01E63 },- { 0x00073 , 0x00326 , 0x00219 },- { 0x00073 , 0x00327 , 0x0015F },- { 0x00074 , 0x00307 , 0x01E6B },- { 0x00074 , 0x00308 , 0x01E97 },- { 0x00074 , 0x0030C , 0x00165 },- { 0x00074 , 0x00323 , 0x01E6D },- { 0x00074 , 0x00326 , 0x0021B },- { 0x00074 , 0x00327 , 0x00163 },- { 0x00074 , 0x0032D , 0x01E71 },- { 0x00074 , 0x00331 , 0x01E6F },- { 0x00075 , 0x00300 , 0x000F9 },- { 0x00075 , 0x00301 , 0x000FA },- { 0x00075 , 0x00302 , 0x000FB },- { 0x00075 , 0x00303 , 0x00169 },- { 0x00075 , 0x00304 , 0x0016B },- { 0x00075 , 0x00306 , 0x0016D },- { 0x00075 , 0x00308 , 0x000FC },- { 0x00075 , 0x00309 , 0x01EE7 },- { 0x00075 , 0x0030A , 0x0016F },- { 0x00075 , 0x0030B , 0x00171 },- { 0x00075 , 0x0030C , 0x001D4 },- { 0x00075 , 0x0030F , 0x00215 },- { 0x00075 , 0x00311 , 0x00217 },- { 0x00075 , 0x0031B , 0x001B0 },- { 0x00075 , 0x00323 , 0x01EE5 },- { 0x00075 , 0x00324 , 0x01E73 },- { 0x00075 , 0x00328 , 0x00173 },- { 0x00075 , 0x0032D , 0x01E77 },- { 0x00075 , 0x00330 , 0x01E75 },- { 0x00076 , 0x00303 , 0x01E7D },- { 0x00076 , 0x00323 , 0x01E7F },- { 0x00077 , 0x00300 , 0x01E81 },- { 0x00077 , 0x00301 , 0x01E83 },- { 0x00077 , 0x00302 , 0x00175 },- { 0x00077 , 0x00307 , 0x01E87 },- { 0x00077 , 0x00308 , 0x01E85 },- { 0x00077 , 0x0030A , 0x01E98 },- { 0x00077 , 0x00323 , 0x01E89 },- { 0x00078 , 0x00307 , 0x01E8B },- { 0x00078 , 0x00308 , 0x01E8D },- { 0x00079 , 0x00300 , 0x01EF3 },- { 0x00079 , 0x00301 , 0x000FD },- { 0x00079 , 0x00302 , 0x00177 },- { 0x00079 , 0x00303 , 0x01EF9 },- { 0x00079 , 0x00304 , 0x00233 },- { 0x00079 , 0x00307 , 0x01E8F },- { 0x00079 , 0x00308 , 0x000FF },- { 0x00079 , 0x00309 , 0x01EF7 },- { 0x00079 , 0x0030A , 0x01E99 },- { 0x00079 , 0x00323 , 0x01EF5 },- { 0x0007A , 0x00301 , 0x0017A },- { 0x0007A , 0x00302 , 0x01E91 },- { 0x0007A , 0x00307 , 0x0017C },- { 0x0007A , 0x0030C , 0x0017E },- { 0x0007A , 0x00323 , 0x01E93 },- { 0x0007A , 0x00331 , 0x01E95 },- { 0x000A8 , 0x00300 , 0x01FED },- { 0x000A8 , 0x00301 , 0x00385 },- { 0x000A8 , 0x00342 , 0x01FC1 },- { 0x000C2 , 0x00300 , 0x01EA6 },- { 0x000C2 , 0x00301 , 0x01EA4 },- { 0x000C2 , 0x00303 , 0x01EAA },- { 0x000C2 , 0x00309 , 0x01EA8 },- { 0x000C4 , 0x00304 , 0x001DE },- { 0x000C5 , 0x00301 , 0x001FA },- { 0x000C6 , 0x00301 , 0x001FC },- { 0x000C6 , 0x00304 , 0x001E2 },- { 0x000C7 , 0x00301 , 0x01E08 },- { 0x000CA , 0x00300 , 0x01EC0 },- { 0x000CA , 0x00301 , 0x01EBE },- { 0x000CA , 0x00303 , 0x01EC4 },- { 0x000CA , 0x00309 , 0x01EC2 },- { 0x000CF , 0x00301 , 0x01E2E },- { 0x000D4 , 0x00300 , 0x01ED2 },- { 0x000D4 , 0x00301 , 0x01ED0 },- { 0x000D4 , 0x00303 , 0x01ED6 },- { 0x000D4 , 0x00309 , 0x01ED4 },- { 0x000D5 , 0x00301 , 0x01E4C },- { 0x000D5 , 0x00304 , 0x0022C },- { 0x000D5 , 0x00308 , 0x01E4E },- { 0x000D6 , 0x00304 , 0x0022A },- { 0x000D8 , 0x00301 , 0x001FE },- { 0x000DC , 0x00300 , 0x001DB },- { 0x000DC , 0x00301 , 0x001D7 },- { 0x000DC , 0x00304 , 0x001D5 },- { 0x000DC , 0x0030C , 0x001D9 },- { 0x000E2 , 0x00300 , 0x01EA7 },- { 0x000E2 , 0x00301 , 0x01EA5 },- { 0x000E2 , 0x00303 , 0x01EAB },- { 0x000E2 , 0x00309 , 0x01EA9 },- { 0x000E4 , 0x00304 , 0x001DF },- { 0x000E5 , 0x00301 , 0x001FB },- { 0x000E6 , 0x00301 , 0x001FD },- { 0x000E6 , 0x00304 , 0x001E3 },- { 0x000E7 , 0x00301 , 0x01E09 },- { 0x000EA , 0x00300 , 0x01EC1 },- { 0x000EA , 0x00301 , 0x01EBF },- { 0x000EA , 0x00303 , 0x01EC5 },- { 0x000EA , 0x00309 , 0x01EC3 },- { 0x000EF , 0x00301 , 0x01E2F },- { 0x000F4 , 0x00300 , 0x01ED3 },- { 0x000F4 , 0x00301 , 0x01ED1 },- { 0x000F4 , 0x00303 , 0x01ED7 },- { 0x000F4 , 0x00309 , 0x01ED5 },- { 0x000F5 , 0x00301 , 0x01E4D },- { 0x000F5 , 0x00304 , 0x0022D },- { 0x000F5 , 0x00308 , 0x01E4F },- { 0x000F6 , 0x00304 , 0x0022B },- { 0x000F8 , 0x00301 , 0x001FF },- { 0x000FC , 0x00300 , 0x001DC },- { 0x000FC , 0x00301 , 0x001D8 },- { 0x000FC , 0x00304 , 0x001D6 },- { 0x000FC , 0x0030C , 0x001DA },- { 0x00102 , 0x00300 , 0x01EB0 },- { 0x00102 , 0x00301 , 0x01EAE },- { 0x00102 , 0x00303 , 0x01EB4 },- { 0x00102 , 0x00309 , 0x01EB2 },- { 0x00103 , 0x00300 , 0x01EB1 },- { 0x00103 , 0x00301 , 0x01EAF },- { 0x00103 , 0x00303 , 0x01EB5 },- { 0x00103 , 0x00309 , 0x01EB3 },- { 0x00112 , 0x00300 , 0x01E14 },- { 0x00112 , 0x00301 , 0x01E16 },- { 0x00113 , 0x00300 , 0x01E15 },- { 0x00113 , 0x00301 , 0x01E17 },- { 0x0014C , 0x00300 , 0x01E50 },- { 0x0014C , 0x00301 , 0x01E52 },- { 0x0014D , 0x00300 , 0x01E51 },- { 0x0014D , 0x00301 , 0x01E53 },- { 0x0015A , 0x00307 , 0x01E64 },- { 0x0015B , 0x00307 , 0x01E65 },- { 0x00160 , 0x00307 , 0x01E66 },- { 0x00161 , 0x00307 , 0x01E67 },- { 0x00168 , 0x00301 , 0x01E78 },- { 0x00169 , 0x00301 , 0x01E79 },- { 0x0016A , 0x00308 , 0x01E7A },- { 0x0016B , 0x00308 , 0x01E7B },- { 0x0017F , 0x00307 , 0x01E9B },- { 0x001A0 , 0x00300 , 0x01EDC },- { 0x001A0 , 0x00301 , 0x01EDA },- { 0x001A0 , 0x00303 , 0x01EE0 },- { 0x001A0 , 0x00309 , 0x01EDE },- { 0x001A0 , 0x00323 , 0x01EE2 },- { 0x001A1 , 0x00300 , 0x01EDD },- { 0x001A1 , 0x00301 , 0x01EDB },- { 0x001A1 , 0x00303 , 0x01EE1 },- { 0x001A1 , 0x00309 , 0x01EDF },- { 0x001A1 , 0x00323 , 0x01EE3 },- { 0x001AF , 0x00300 , 0x01EEA },- { 0x001AF , 0x00301 , 0x01EE8 },- { 0x001AF , 0x00303 , 0x01EEE },- { 0x001AF , 0x00309 , 0x01EEC },- { 0x001AF , 0x00323 , 0x01EF0 },- { 0x001B0 , 0x00300 , 0x01EEB },- { 0x001B0 , 0x00301 , 0x01EE9 },- { 0x001B0 , 0x00303 , 0x01EEF },- { 0x001B0 , 0x00309 , 0x01EED },- { 0x001B0 , 0x00323 , 0x01EF1 },- { 0x001B7 , 0x0030C , 0x001EE },- { 0x001EA , 0x00304 , 0x001EC },- { 0x001EB , 0x00304 , 0x001ED },- { 0x00226 , 0x00304 , 0x001E0 },- { 0x00227 , 0x00304 , 0x001E1 },- { 0x00228 , 0x00306 , 0x01E1C },- { 0x00229 , 0x00306 , 0x01E1D },- { 0x0022E , 0x00304 , 0x00230 },- { 0x0022F , 0x00304 , 0x00231 },- { 0x00292 , 0x0030C , 0x001EF },- { 0x00391 , 0x00300 , 0x01FBA },- { 0x00391 , 0x00301 , 0x00386 },- { 0x00391 , 0x00304 , 0x01FB9 },- { 0x00391 , 0x00306 , 0x01FB8 },- { 0x00391 , 0x00313 , 0x01F08 },- { 0x00391 , 0x00314 , 0x01F09 },- { 0x00391 , 0x00345 , 0x01FBC },- { 0x00395 , 0x00300 , 0x01FC8 },- { 0x00395 , 0x00301 , 0x00388 },- { 0x00395 , 0x00313 , 0x01F18 },- { 0x00395 , 0x00314 , 0x01F19 },- { 0x00397 , 0x00300 , 0x01FCA },- { 0x00397 , 0x00301 , 0x00389 },- { 0x00397 , 0x00313 , 0x01F28 },- { 0x00397 , 0x00314 , 0x01F29 },- { 0x00397 , 0x00345 , 0x01FCC },- { 0x00399 , 0x00300 , 0x01FDA },- { 0x00399 , 0x00301 , 0x0038A },- { 0x00399 , 0x00304 , 0x01FD9 },- { 0x00399 , 0x00306 , 0x01FD8 },- { 0x00399 , 0x00308 , 0x003AA },- { 0x00399 , 0x00313 , 0x01F38 },- { 0x00399 , 0x00314 , 0x01F39 },- { 0x0039F , 0x00300 , 0x01FF8 },- { 0x0039F , 0x00301 , 0x0038C },- { 0x0039F , 0x00313 , 0x01F48 },- { 0x0039F , 0x00314 , 0x01F49 },- { 0x003A1 , 0x00314 , 0x01FEC },- { 0x003A5 , 0x00300 , 0x01FEA },- { 0x003A5 , 0x00301 , 0x0038E },- { 0x003A5 , 0x00304 , 0x01FE9 },- { 0x003A5 , 0x00306 , 0x01FE8 },- { 0x003A5 , 0x00308 , 0x003AB },- { 0x003A5 , 0x00314 , 0x01F59 },- { 0x003A9 , 0x00300 , 0x01FFA },- { 0x003A9 , 0x00301 , 0x0038F },- { 0x003A9 , 0x00313 , 0x01F68 },- { 0x003A9 , 0x00314 , 0x01F69 },- { 0x003A9 , 0x00345 , 0x01FFC },- { 0x003AC , 0x00345 , 0x01FB4 },- { 0x003AE , 0x00345 , 0x01FC4 },- { 0x003B1 , 0x00300 , 0x01F70 },- { 0x003B1 , 0x00301 , 0x003AC },- { 0x003B1 , 0x00304 , 0x01FB1 },- { 0x003B1 , 0x00306 , 0x01FB0 },- { 0x003B1 , 0x00313 , 0x01F00 },- { 0x003B1 , 0x00314 , 0x01F01 },- { 0x003B1 , 0x00342 , 0x01FB6 },- { 0x003B1 , 0x00345 , 0x01FB3 },- { 0x003B5 , 0x00300 , 0x01F72 },- { 0x003B5 , 0x00301 , 0x003AD },- { 0x003B5 , 0x00313 , 0x01F10 },- { 0x003B5 , 0x00314 , 0x01F11 },- { 0x003B7 , 0x00300 , 0x01F74 },- { 0x003B7 , 0x00301 , 0x003AE },- { 0x003B7 , 0x00313 , 0x01F20 },- { 0x003B7 , 0x00314 , 0x01F21 },- { 0x003B7 , 0x00342 , 0x01FC6 },- { 0x003B7 , 0x00345 , 0x01FC3 },- { 0x003B9 , 0x00300 , 0x01F76 },- { 0x003B9 , 0x00301 , 0x003AF },- { 0x003B9 , 0x00304 , 0x01FD1 },- { 0x003B9 , 0x00306 , 0x01FD0 },- { 0x003B9 , 0x00308 , 0x003CA },- { 0x003B9 , 0x00313 , 0x01F30 },- { 0x003B9 , 0x00314 , 0x01F31 },- { 0x003B9 , 0x00342 , 0x01FD6 },- { 0x003BF , 0x00300 , 0x01F78 },- { 0x003BF , 0x00301 , 0x003CC },- { 0x003BF , 0x00313 , 0x01F40 },- { 0x003BF , 0x00314 , 0x01F41 },- { 0x003C1 , 0x00313 , 0x01FE4 },- { 0x003C1 , 0x00314 , 0x01FE5 },- { 0x003C5 , 0x00300 , 0x01F7A },- { 0x003C5 , 0x00301 , 0x003CD },- { 0x003C5 , 0x00304 , 0x01FE1 },- { 0x003C5 , 0x00306 , 0x01FE0 },- { 0x003C5 , 0x00308 , 0x003CB },- { 0x003C5 , 0x00313 , 0x01F50 },- { 0x003C5 , 0x00314 , 0x01F51 },- { 0x003C5 , 0x00342 , 0x01FE6 },- { 0x003C9 , 0x00300 , 0x01F7C },- { 0x003C9 , 0x00301 , 0x003CE },- { 0x003C9 , 0x00313 , 0x01F60 },- { 0x003C9 , 0x00314 , 0x01F61 },- { 0x003C9 , 0x00342 , 0x01FF6 },- { 0x003C9 , 0x00345 , 0x01FF3 },- { 0x003CA , 0x00300 , 0x01FD2 },- { 0x003CA , 0x00301 , 0x00390 },- { 0x003CA , 0x00342 , 0x01FD7 },- { 0x003CB , 0x00300 , 0x01FE2 },- { 0x003CB , 0x00301 , 0x003B0 },- { 0x003CB , 0x00342 , 0x01FE7 },- { 0x003CE , 0x00345 , 0x01FF4 },- { 0x003D2 , 0x00301 , 0x003D3 },- { 0x003D2 , 0x00308 , 0x003D4 },- { 0x00406 , 0x00308 , 0x00407 },- { 0x00410 , 0x00306 , 0x004D0 },- { 0x00410 , 0x00308 , 0x004D2 },- { 0x00413 , 0x00301 , 0x00403 },- { 0x00415 , 0x00300 , 0x00400 },- { 0x00415 , 0x00306 , 0x004D6 },- { 0x00415 , 0x00308 , 0x00401 },- { 0x00416 , 0x00306 , 0x004C1 },- { 0x00416 , 0x00308 , 0x004DC },- { 0x00417 , 0x00308 , 0x004DE },- { 0x00418 , 0x00300 , 0x0040D },- { 0x00418 , 0x00304 , 0x004E2 },- { 0x00418 , 0x00306 , 0x00419 },- { 0x00418 , 0x00308 , 0x004E4 },- { 0x0041A , 0x00301 , 0x0040C },- { 0x0041E , 0x00308 , 0x004E6 },- { 0x00423 , 0x00304 , 0x004EE },- { 0x00423 , 0x00306 , 0x0040E },- { 0x00423 , 0x00308 , 0x004F0 },- { 0x00423 , 0x0030B , 0x004F2 },- { 0x00427 , 0x00308 , 0x004F4 },- { 0x0042B , 0x00308 , 0x004F8 },- { 0x0042D , 0x00308 , 0x004EC },- { 0x00430 , 0x00306 , 0x004D1 },- { 0x00430 , 0x00308 , 0x004D3 },- { 0x00433 , 0x00301 , 0x00453 },- { 0x00435 , 0x00300 , 0x00450 },- { 0x00435 , 0x00306 , 0x004D7 },- { 0x00435 , 0x00308 , 0x00451 },- { 0x00436 , 0x00306 , 0x004C2 },- { 0x00436 , 0x00308 , 0x004DD },- { 0x00437 , 0x00308 , 0x004DF },- { 0x00438 , 0x00300 , 0x0045D },- { 0x00438 , 0x00304 , 0x004E3 },- { 0x00438 , 0x00306 , 0x00439 },- { 0x00438 , 0x00308 , 0x004E5 },- { 0x0043A , 0x00301 , 0x0045C },- { 0x0043E , 0x00308 , 0x004E7 },- { 0x00443 , 0x00304 , 0x004EF },- { 0x00443 , 0x00306 , 0x0045E },- { 0x00443 , 0x00308 , 0x004F1 },- { 0x00443 , 0x0030B , 0x004F3 },- { 0x00447 , 0x00308 , 0x004F5 },- { 0x0044B , 0x00308 , 0x004F9 },- { 0x0044D , 0x00308 , 0x004ED },- { 0x00456 , 0x00308 , 0x00457 },- { 0x00474 , 0x0030F , 0x00476 },- { 0x00475 , 0x0030F , 0x00477 },- { 0x004D8 , 0x00308 , 0x004DA },- { 0x004D9 , 0x00308 , 0x004DB },- { 0x004E8 , 0x00308 , 0x004EA },- { 0x004E9 , 0x00308 , 0x004EB },- { 0x00627 , 0x00653 , 0x00622 },- { 0x00627 , 0x00654 , 0x00623 },- { 0x00627 , 0x00655 , 0x00625 },- { 0x00648 , 0x00654 , 0x00624 },- { 0x0064A , 0x00654 , 0x00626 },- { 0x006C1 , 0x00654 , 0x006C2 },- { 0x006D2 , 0x00654 , 0x006D3 },- { 0x006D5 , 0x00654 , 0x006C0 },- { 0x00928 , 0x0093C , 0x00929 },- { 0x00930 , 0x0093C , 0x00931 },- { 0x00933 , 0x0093C , 0x00934 },- { 0x009C7 , 0x009BE , 0x009CB },- { 0x009C7 , 0x009D7 , 0x009CC },- { 0x00B47 , 0x00B3E , 0x00B4B },- { 0x00B47 , 0x00B56 , 0x00B48 },- { 0x00B47 , 0x00B57 , 0x00B4C },- { 0x00B92 , 0x00BD7 , 0x00B94 },- { 0x00BC6 , 0x00BBE , 0x00BCA },- { 0x00BC6 , 0x00BD7 , 0x00BCC },- { 0x00BC7 , 0x00BBE , 0x00BCB },- { 0x00C46 , 0x00C56 , 0x00C48 },- { 0x00CBF , 0x00CD5 , 0x00CC0 },- { 0x00CC6 , 0x00CC2 , 0x00CCA },- { 0x00CC6 , 0x00CD5 , 0x00CC7 },- { 0x00CC6 , 0x00CD6 , 0x00CC8 },- { 0x00CCA , 0x00CD5 , 0x00CCB },- { 0x00D46 , 0x00D3E , 0x00D4A },- { 0x00D46 , 0x00D57 , 0x00D4C },- { 0x00D47 , 0x00D3E , 0x00D4B },- { 0x00DD9 , 0x00DCA , 0x00DDA },- { 0x00DD9 , 0x00DCF , 0x00DDC },- { 0x00DD9 , 0x00DDF , 0x00DDE },- { 0x00DDC , 0x00DCA , 0x00DDD },- { 0x01025 , 0x0102E , 0x01026 },- { 0x01B05 , 0x01B35 , 0x01B06 },- { 0x01B07 , 0x01B35 , 0x01B08 },- { 0x01B09 , 0x01B35 , 0x01B0A },- { 0x01B0B , 0x01B35 , 0x01B0C },- { 0x01B0D , 0x01B35 , 0x01B0E },- { 0x01B11 , 0x01B35 , 0x01B12 },- { 0x01B3A , 0x01B35 , 0x01B3B },- { 0x01B3C , 0x01B35 , 0x01B3D },- { 0x01B3E , 0x01B35 , 0x01B40 },- { 0x01B3F , 0x01B35 , 0x01B41 },- { 0x01B42 , 0x01B35 , 0x01B43 },- { 0x01E36 , 0x00304 , 0x01E38 },- { 0x01E37 , 0x00304 , 0x01E39 },- { 0x01E5A , 0x00304 , 0x01E5C },- { 0x01E5B , 0x00304 , 0x01E5D },- { 0x01E62 , 0x00307 , 0x01E68 },- { 0x01E63 , 0x00307 , 0x01E69 },- { 0x01EA0 , 0x00302 , 0x01EAC },- { 0x01EA0 , 0x00306 , 0x01EB6 },- { 0x01EA1 , 0x00302 , 0x01EAD },- { 0x01EA1 , 0x00306 , 0x01EB7 },- { 0x01EB8 , 0x00302 , 0x01EC6 },- { 0x01EB9 , 0x00302 , 0x01EC7 },- { 0x01ECC , 0x00302 , 0x01ED8 },- { 0x01ECD , 0x00302 , 0x01ED9 },- { 0x01F00 , 0x00300 , 0x01F02 },- { 0x01F00 , 0x00301 , 0x01F04 },- { 0x01F00 , 0x00342 , 0x01F06 },- { 0x01F00 , 0x00345 , 0x01F80 },- { 0x01F01 , 0x00300 , 0x01F03 },- { 0x01F01 , 0x00301 , 0x01F05 },- { 0x01F01 , 0x00342 , 0x01F07 },- { 0x01F01 , 0x00345 , 0x01F81 },- { 0x01F02 , 0x00345 , 0x01F82 },- { 0x01F03 , 0x00345 , 0x01F83 },- { 0x01F04 , 0x00345 , 0x01F84 },- { 0x01F05 , 0x00345 , 0x01F85 },- { 0x01F06 , 0x00345 , 0x01F86 },- { 0x01F07 , 0x00345 , 0x01F87 },- { 0x01F08 , 0x00300 , 0x01F0A },- { 0x01F08 , 0x00301 , 0x01F0C },- { 0x01F08 , 0x00342 , 0x01F0E },- { 0x01F08 , 0x00345 , 0x01F88 },- { 0x01F09 , 0x00300 , 0x01F0B },- { 0x01F09 , 0x00301 , 0x01F0D },- { 0x01F09 , 0x00342 , 0x01F0F },- { 0x01F09 , 0x00345 , 0x01F89 },- { 0x01F0A , 0x00345 , 0x01F8A },- { 0x01F0B , 0x00345 , 0x01F8B },- { 0x01F0C , 0x00345 , 0x01F8C },- { 0x01F0D , 0x00345 , 0x01F8D },- { 0x01F0E , 0x00345 , 0x01F8E },- { 0x01F0F , 0x00345 , 0x01F8F },- { 0x01F10 , 0x00300 , 0x01F12 },- { 0x01F10 , 0x00301 , 0x01F14 },- { 0x01F11 , 0x00300 , 0x01F13 },- { 0x01F11 , 0x00301 , 0x01F15 },- { 0x01F18 , 0x00300 , 0x01F1A },- { 0x01F18 , 0x00301 , 0x01F1C },- { 0x01F19 , 0x00300 , 0x01F1B },- { 0x01F19 , 0x00301 , 0x01F1D },- { 0x01F20 , 0x00300 , 0x01F22 },- { 0x01F20 , 0x00301 , 0x01F24 },- { 0x01F20 , 0x00342 , 0x01F26 },- { 0x01F20 , 0x00345 , 0x01F90 },- { 0x01F21 , 0x00300 , 0x01F23 },- { 0x01F21 , 0x00301 , 0x01F25 },- { 0x01F21 , 0x00342 , 0x01F27 },- { 0x01F21 , 0x00345 , 0x01F91 },- { 0x01F22 , 0x00345 , 0x01F92 },- { 0x01F23 , 0x00345 , 0x01F93 },- { 0x01F24 , 0x00345 , 0x01F94 },- { 0x01F25 , 0x00345 , 0x01F95 },- { 0x01F26 , 0x00345 , 0x01F96 },- { 0x01F27 , 0x00345 , 0x01F97 },- { 0x01F28 , 0x00300 , 0x01F2A },- { 0x01F28 , 0x00301 , 0x01F2C },- { 0x01F28 , 0x00342 , 0x01F2E },- { 0x01F28 , 0x00345 , 0x01F98 },- { 0x01F29 , 0x00300 , 0x01F2B },- { 0x01F29 , 0x00301 , 0x01F2D },- { 0x01F29 , 0x00342 , 0x01F2F },- { 0x01F29 , 0x00345 , 0x01F99 },- { 0x01F2A , 0x00345 , 0x01F9A },- { 0x01F2B , 0x00345 , 0x01F9B },- { 0x01F2C , 0x00345 , 0x01F9C },- { 0x01F2D , 0x00345 , 0x01F9D },- { 0x01F2E , 0x00345 , 0x01F9E },- { 0x01F2F , 0x00345 , 0x01F9F },- { 0x01F30 , 0x00300 , 0x01F32 },- { 0x01F30 , 0x00301 , 0x01F34 },- { 0x01F30 , 0x00342 , 0x01F36 },- { 0x01F31 , 0x00300 , 0x01F33 },- { 0x01F31 , 0x00301 , 0x01F35 },- { 0x01F31 , 0x00342 , 0x01F37 },- { 0x01F38 , 0x00300 , 0x01F3A },- { 0x01F38 , 0x00301 , 0x01F3C },- { 0x01F38 , 0x00342 , 0x01F3E },- { 0x01F39 , 0x00300 , 0x01F3B },- { 0x01F39 , 0x00301 , 0x01F3D },- { 0x01F39 , 0x00342 , 0x01F3F },- { 0x01F40 , 0x00300 , 0x01F42 },- { 0x01F40 , 0x00301 , 0x01F44 },- { 0x01F41 , 0x00300 , 0x01F43 },- { 0x01F41 , 0x00301 , 0x01F45 },- { 0x01F48 , 0x00300 , 0x01F4A },- { 0x01F48 , 0x00301 , 0x01F4C },- { 0x01F49 , 0x00300 , 0x01F4B },- { 0x01F49 , 0x00301 , 0x01F4D },- { 0x01F50 , 0x00300 , 0x01F52 },- { 0x01F50 , 0x00301 , 0x01F54 },- { 0x01F50 , 0x00342 , 0x01F56 },- { 0x01F51 , 0x00300 , 0x01F53 },- { 0x01F51 , 0x00301 , 0x01F55 },- { 0x01F51 , 0x00342 , 0x01F57 },- { 0x01F59 , 0x00300 , 0x01F5B },- { 0x01F59 , 0x00301 , 0x01F5D },- { 0x01F59 , 0x00342 , 0x01F5F },- { 0x01F60 , 0x00300 , 0x01F62 },- { 0x01F60 , 0x00301 , 0x01F64 },- { 0x01F60 , 0x00342 , 0x01F66 },- { 0x01F60 , 0x00345 , 0x01FA0 },- { 0x01F61 , 0x00300 , 0x01F63 },- { 0x01F61 , 0x00301 , 0x01F65 },- { 0x01F61 , 0x00342 , 0x01F67 },- { 0x01F61 , 0x00345 , 0x01FA1 },- { 0x01F62 , 0x00345 , 0x01FA2 },- { 0x01F63 , 0x00345 , 0x01FA3 },- { 0x01F64 , 0x00345 , 0x01FA4 },- { 0x01F65 , 0x00345 , 0x01FA5 },- { 0x01F66 , 0x00345 , 0x01FA6 },- { 0x01F67 , 0x00345 , 0x01FA7 },- { 0x01F68 , 0x00300 , 0x01F6A },- { 0x01F68 , 0x00301 , 0x01F6C },- { 0x01F68 , 0x00342 , 0x01F6E },- { 0x01F68 , 0x00345 , 0x01FA8 },- { 0x01F69 , 0x00300 , 0x01F6B },- { 0x01F69 , 0x00301 , 0x01F6D },- { 0x01F69 , 0x00342 , 0x01F6F },- { 0x01F69 , 0x00345 , 0x01FA9 },- { 0x01F6A , 0x00345 , 0x01FAA },- { 0x01F6B , 0x00345 , 0x01FAB },- { 0x01F6C , 0x00345 , 0x01FAC },- { 0x01F6D , 0x00345 , 0x01FAD },- { 0x01F6E , 0x00345 , 0x01FAE },- { 0x01F6F , 0x00345 , 0x01FAF },- { 0x01F70 , 0x00345 , 0x01FB2 },- { 0x01F74 , 0x00345 , 0x01FC2 },- { 0x01F7C , 0x00345 , 0x01FF2 },- { 0x01FB6 , 0x00345 , 0x01FB7 },- { 0x01FBF , 0x00300 , 0x01FCD },- { 0x01FBF , 0x00301 , 0x01FCE },- { 0x01FBF , 0x00342 , 0x01FCF },- { 0x01FC6 , 0x00345 , 0x01FC7 },- { 0x01FF6 , 0x00345 , 0x01FF7 },- { 0x01FFE , 0x00300 , 0x01FDD },- { 0x01FFE , 0x00301 , 0x01FDE },- { 0x01FFE , 0x00342 , 0x01FDF },- { 0x02190 , 0x00338 , 0x0219A },- { 0x02192 , 0x00338 , 0x0219B },- { 0x02194 , 0x00338 , 0x021AE },- { 0x021D0 , 0x00338 , 0x021CD },- { 0x021D2 , 0x00338 , 0x021CF },- { 0x021D4 , 0x00338 , 0x021CE },- { 0x02203 , 0x00338 , 0x02204 },- { 0x02208 , 0x00338 , 0x02209 },- { 0x0220B , 0x00338 , 0x0220C },- { 0x02223 , 0x00338 , 0x02224 },- { 0x02225 , 0x00338 , 0x02226 },- { 0x0223C , 0x00338 , 0x02241 },- { 0x02243 , 0x00338 , 0x02244 },- { 0x02245 , 0x00338 , 0x02247 },- { 0x02248 , 0x00338 , 0x02249 },- { 0x0224D , 0x00338 , 0x0226D },- { 0x02261 , 0x00338 , 0x02262 },- { 0x02264 , 0x00338 , 0x02270 },- { 0x02265 , 0x00338 , 0x02271 },- { 0x02272 , 0x00338 , 0x02274 },- { 0x02273 , 0x00338 , 0x02275 },- { 0x02276 , 0x00338 , 0x02278 },- { 0x02277 , 0x00338 , 0x02279 },- { 0x0227A , 0x00338 , 0x02280 },- { 0x0227B , 0x00338 , 0x02281 },- { 0x0227C , 0x00338 , 0x022E0 },- { 0x0227D , 0x00338 , 0x022E1 },- { 0x02282 , 0x00338 , 0x02284 },- { 0x02283 , 0x00338 , 0x02285 },- { 0x02286 , 0x00338 , 0x02288 },- { 0x02287 , 0x00338 , 0x02289 },- { 0x02291 , 0x00338 , 0x022E2 },- { 0x02292 , 0x00338 , 0x022E3 },- { 0x022A2 , 0x00338 , 0x022AC },- { 0x022A8 , 0x00338 , 0x022AD },- { 0x022A9 , 0x00338 , 0x022AE },- { 0x022AB , 0x00338 , 0x022AF },- { 0x022B2 , 0x00338 , 0x022EA },- { 0x022B3 , 0x00338 , 0x022EB },- { 0x022B4 , 0x00338 , 0x022EC },- { 0x022B5 , 0x00338 , 0x022ED },- { 0x03046 , 0x03099 , 0x03094 },- { 0x0304B , 0x03099 , 0x0304C },- { 0x0304D , 0x03099 , 0x0304E },- { 0x0304F , 0x03099 , 0x03050 },- { 0x03051 , 0x03099 , 0x03052 },- { 0x03053 , 0x03099 , 0x03054 },- { 0x03055 , 0x03099 , 0x03056 },- { 0x03057 , 0x03099 , 0x03058 },- { 0x03059 , 0x03099 , 0x0305A },- { 0x0305B , 0x03099 , 0x0305C },- { 0x0305D , 0x03099 , 0x0305E },- { 0x0305F , 0x03099 , 0x03060 },- { 0x03061 , 0x03099 , 0x03062 },- { 0x03064 , 0x03099 , 0x03065 },- { 0x03066 , 0x03099 , 0x03067 },- { 0x03068 , 0x03099 , 0x03069 },- { 0x0306F , 0x03099 , 0x03070 },- { 0x0306F , 0x0309A , 0x03071 },- { 0x03072 , 0x03099 , 0x03073 },- { 0x03072 , 0x0309A , 0x03074 },- { 0x03075 , 0x03099 , 0x03076 },- { 0x03075 , 0x0309A , 0x03077 },- { 0x03078 , 0x03099 , 0x03079 },- { 0x03078 , 0x0309A , 0x0307A },- { 0x0307B , 0x03099 , 0x0307C },- { 0x0307B , 0x0309A , 0x0307D },- { 0x0309D , 0x03099 , 0x0309E },- { 0x030A6 , 0x03099 , 0x030F4 },- { 0x030AB , 0x03099 , 0x030AC },- { 0x030AD , 0x03099 , 0x030AE },- { 0x030AF , 0x03099 , 0x030B0 },- { 0x030B1 , 0x03099 , 0x030B2 },- { 0x030B3 , 0x03099 , 0x030B4 },- { 0x030B5 , 0x03099 , 0x030B6 },- { 0x030B7 , 0x03099 , 0x030B8 },- { 0x030B9 , 0x03099 , 0x030BA },- { 0x030BB , 0x03099 , 0x030BC },- { 0x030BD , 0x03099 , 0x030BE },- { 0x030BF , 0x03099 , 0x030C0 },- { 0x030C1 , 0x03099 , 0x030C2 },- { 0x030C4 , 0x03099 , 0x030C5 },- { 0x030C6 , 0x03099 , 0x030C7 },- { 0x030C8 , 0x03099 , 0x030C9 },- { 0x030CF , 0x03099 , 0x030D0 },- { 0x030CF , 0x0309A , 0x030D1 },- { 0x030D2 , 0x03099 , 0x030D3 },- { 0x030D2 , 0x0309A , 0x030D4 },- { 0x030D5 , 0x03099 , 0x030D6 },- { 0x030D5 , 0x0309A , 0x030D7 },- { 0x030D8 , 0x03099 , 0x030D9 },- { 0x030D8 , 0x0309A , 0x030DA },- { 0x030DB , 0x03099 , 0x030DC },- { 0x030DB , 0x0309A , 0x030DD },- { 0x030EF , 0x03099 , 0x030F7 },- { 0x030F0 , 0x03099 , 0x030F8 },- { 0x030F1 , 0x03099 , 0x030F9 },- { 0x030F2 , 0x03099 , 0x030FA },- { 0x030FD , 0x03099 , 0x030FE },- { 0x11099 , 0x110BA , 0x1109A },- { 0x1109B , 0x110BA , 0x1109C },- { 0x110A5 , 0x110BA , 0x110AB },-};--#define CANONICAL_CLASS_MIN 0x0300-#define CANONICAL_CLASS_MAX 0x1D244--#define IS_DECOMPOSABLE_BLOCK(uc) \- (((uc)>>8) <= 0x1D2 && u_decomposable_blocks[(uc)>>8])-static const char u_decomposable_blocks[0x1D2+1] = {- 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,1,1,0,0,- 1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,- 0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,-};--/* Get Canonical Combining Class(CCC). */-#define CCC(uc) \- (((uc) > 0x1D244)?0:\- ccc_val[ccc_val_index[ccc_index[(uc)>>8]][((uc)>>4)&0x0F]][(uc)&0x0F])--/* The table of the value of Canonical Combining Class */-static const unsigned char ccc_val[][16] = {- /* idx=0: XXXX0 - XXXXF */- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=1: 00300 - 0030F */- {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },- /* idx=2: 00310 - 0031F */- {230, 230, 230, 230, 230, 232, 220, 220, 220, 220, 232, 216, 220, 220, 220, 220 },- /* idx=3: 00320 - 0032F */- {220, 202, 202, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 220, 220, 220 },- /* idx=4: 00330 - 0033F */- {220, 220, 220, 220, 1, 1, 1, 1, 1, 220, 220, 220, 220, 230, 230, 230 },- /* idx=5: 00340 - 0034F */- {230, 230, 230, 230, 230, 240, 230, 220, 220, 220, 230, 230, 230, 220, 220, 0 },- /* idx=6: 00350 - 0035F */- {230, 230, 230, 220, 220, 220, 220, 230, 232, 220, 220, 230, 233, 234, 234, 233 },- /* idx=7: 00360 - 0036F */- {234, 234, 233, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },- /* idx=8: 00480 - 0048F */- {0, 0, 0, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=9: 00590 - 0059F */- {0, 220, 230, 230, 230, 230, 220, 230, 230, 230, 222, 220, 230, 230, 230, 230 },- /* idx=10: 005A0 - 005AF */- {230, 230, 220, 220, 220, 220, 220, 220, 230, 230, 220, 230, 230, 222, 228, 230 },- /* idx=11: 005B0 - 005BF */- {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23 },- /* idx=12: 005C0 - 005CF */- {0, 24, 25, 0, 230, 220, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=13: 00610 - 0061F */- {230, 230, 230, 230, 230, 230, 230, 230, 30, 31, 32, 0, 0, 0, 0, 0 },- /* idx=14: 00640 - 0064F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31 },- /* idx=15: 00650 - 0065F */- {32, 33, 34, 230, 230, 220, 220, 230, 230, 230, 230, 230, 220, 230, 230, 220 },- /* idx=16: 00670 - 0067F */- {35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=17: 006D0 - 006DF */- {0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230 },- /* idx=18: 006E0 - 006EF */- {230, 230, 230, 220, 230, 0, 0, 230, 230, 0, 220, 230, 230, 220, 0, 0 },- /* idx=19: 00710 - 0071F */- {0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=20: 00730 - 0073F */- {230, 220, 230, 230, 220, 230, 230, 220, 220, 220, 230, 220, 220, 230, 220, 230 },- /* idx=21: 00740 - 0074F */- {230, 230, 220, 230, 220, 230, 220, 230, 220, 230, 230, 0, 0, 0, 0, 0 },- /* idx=22: 007E0 - 007EF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230 },- /* idx=23: 007F0 - 007FF */- {230, 230, 220, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=24: 00810 - 0081F */- {0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 230, 230, 230, 230, 230 },- /* idx=25: 00820 - 0082F */- {230, 230, 230, 230, 0, 230, 230, 230, 0, 230, 230, 230, 230, 230, 0, 0 },- /* idx=26: 00850 - 0085F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 0, 0, 0 },- /* idx=27: 00930 - 0093F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },- /* idx=28: 00940 - 0094F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },- /* idx=29: 00950 - 0095F */- {0, 230, 220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=30: 009B0 - 009BF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },- /* idx=31: 009C0 - 009CF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },- /* idx=32: 00A30 - 00A3F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },- /* idx=33: 00A40 - 00A4F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },- /* idx=34: 00AB0 - 00ABF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },- /* idx=35: 00AC0 - 00ACF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },- /* idx=36: 00B30 - 00B3F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },- /* idx=37: 00B40 - 00B4F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },- /* idx=38: 00BC0 - 00BCF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },- /* idx=39: 00C40 - 00C4F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },- /* idx=40: 00C50 - 00C5F */- {0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=41: 00CB0 - 00CBF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0 },- /* idx=42: 00CC0 - 00CCF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },- /* idx=43: 00D40 - 00D4F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },- /* idx=44: 00DC0 - 00DCF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0 },- /* idx=45: 00E30 - 00E3F */- {0, 0, 0, 0, 0, 0, 0, 0, 103, 103, 9, 0, 0, 0, 0, 0 },- /* idx=46: 00E40 - 00E4F */- {0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 0, 0, 0, 0 },- /* idx=47: 00EB0 - 00EBF */- {0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 0, 0, 0, 0, 0, 0 },- /* idx=48: 00EC0 - 00ECF */- {0, 0, 0, 0, 0, 0, 0, 0, 122, 122, 122, 122, 0, 0, 0, 0 },- /* idx=49: 00F10 - 00F1F */- {0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 0, 0, 0, 0, 0, 0 },- /* idx=50: 00F30 - 00F3F */- {0, 0, 0, 0, 0, 220, 0, 220, 0, 216, 0, 0, 0, 0, 0, 0 },- /* idx=51: 00F70 - 00F7F */- {0, 129, 130, 0, 132, 0, 0, 0, 0, 0, 130, 130, 130, 130, 0, 0 },- /* idx=52: 00F80 - 00F8F */- {130, 0, 230, 230, 9, 0, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=53: 00FC0 - 00FCF */- {0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=54: 01030 - 0103F */- {0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0, 0, 0, 0 },- /* idx=55: 01080 - 0108F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0 },- /* idx=56: 01350 - 0135F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230 },- /* idx=57: 01710 - 0171F */- {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=58: 01730 - 0173F */- {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=59: 017D0 - 017DF */- {0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, 0 },- /* idx=60: 018A0 - 018AF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0 },- /* idx=61: 01930 - 0193F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 230, 220, 0, 0, 0, 0 },- /* idx=62: 01A10 - 01A1F */- {0, 0, 0, 0, 0, 0, 0, 230, 220, 0, 0, 0, 0, 0, 0, 0 },- /* idx=63: 01A60 - 01A6F */- {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=64: 01A70 - 01A7F */- {0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 220 },- /* idx=65: 01B30 - 01B3F */- {0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=66: 01B40 - 01B4F */- {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=67: 01B60 - 01B6F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 230, 230, 230 },- /* idx=68: 01B70 - 01B7F */- {230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=69: 01BA0 - 01BAF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0 },- /* idx=70: 01BE0 - 01BEF */- {0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=71: 01BF0 - 01BFF */- {0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=72: 01C30 - 01C3F */- {0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=73: 01CD0 - 01CDF */- {230, 230, 230, 0, 1, 220, 220, 220, 220, 220, 230, 230, 220, 220, 220, 220 },- /* idx=74: 01CE0 - 01CEF */- {230, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 220, 0, 0 },- /* idx=75: 01DC0 - 01DCF */- {230, 230, 220, 230, 230, 230, 230, 230, 230, 230, 220, 230, 230, 234, 214, 220 },- /* idx=76: 01DD0 - 01DDF */- {202, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },- /* idx=77: 01DE0 - 01DEF */- {230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=78: 01DF0 - 01DFF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 220, 230, 220 },- /* idx=79: 020D0 - 020DF */- {230, 230, 1, 1, 230, 230, 230, 230, 1, 1, 1, 230, 230, 0, 0, 0 },- /* idx=80: 020E0 - 020EF */- {0, 230, 0, 0, 0, 1, 1, 230, 220, 230, 1, 1, 220, 220, 220, 220 },- /* idx=81: 020F0 - 020FF */- {230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=82: 02CE0 - 02CEF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 },- /* idx=83: 02CF0 - 02CFF */- {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=84: 02D70 - 02D7F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 },- /* idx=85: 02DE0 - 02DEF */- {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },- /* idx=86: 02DF0 - 02DFF */- {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },- /* idx=87: 03020 - 0302F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 228, 232, 222, 224, 224 },- /* idx=88: 03090 - 0309F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0 },- /* idx=89: 0A660 - 0A66F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 },- /* idx=90: 0A670 - 0A67F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 0, 0 },- /* idx=91: 0A6F0 - 0A6FF */- {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=92: 0A800 - 0A80F */- {0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=93: 0A8C0 - 0A8CF */- {0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=94: 0A8E0 - 0A8EF */- {230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230 },- /* idx=95: 0A8F0 - 0A8FF */- {230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=96: 0A920 - 0A92F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 0 },- /* idx=97: 0A950 - 0A95F */- {0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=98: 0A9B0 - 0A9BF */- {0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=99: 0A9C0 - 0A9CF */- {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=100: 0AAB0 - 0AABF */- {230, 0, 230, 230, 220, 0, 0, 230, 230, 0, 0, 0, 0, 0, 230, 230 },- /* idx=101: 0AAC0 - 0AACF */- {0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=102: 0ABE0 - 0ABEF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0 },- /* idx=103: 0FB10 - 0FB1F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0 },- /* idx=104: 0FE20 - 0FE2F */- {230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=105: 101F0 - 101FF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0 },- /* idx=106: 10A00 - 10A0F */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 230 },- /* idx=107: 10A30 - 10A3F */- {0, 0, 0, 0, 0, 0, 0, 0, 230, 1, 220, 0, 0, 0, 0, 9 },- /* idx=108: 11040 - 1104F */- {0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=109: 110B0 - 110BF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0 },- /* idx=110: 1D160 - 1D16F */- {0, 0, 0, 0, 0, 216, 216, 1, 1, 1, 0, 0, 0, 226, 216, 216 },- /* idx=111: 1D170 - 1D17F */- {216, 216, 216, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 220, 220 },- /* idx=112: 1D180 - 1D18F */- {220, 220, 220, 0, 0, 230, 230, 230, 230, 230, 220, 220, 0, 0, 0, 0 },- /* idx=113: 1D1A0 - 1D1AF */- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0 },- /* idx=114: 1D240 - 1D24F */- {0, 0, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },-};--/* The index table to ccc_val[*][16] */-static const unsigned char ccc_val_index[][16] = {- /* idx=0: XXX00 - XXXFF */- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=1: 00300 - 003FF */- { 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=2: 00400 - 004FF */- { 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0 },- /* idx=3: 00500 - 005FF */- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,10,11,12, 0, 0, 0 },- /* idx=4: 00600 - 006FF */- { 0,13, 0, 0,14,15, 0,16, 0, 0, 0, 0, 0,17,18, 0 },- /* idx=5: 00700 - 007FF */- { 0,19, 0,20,21, 0, 0, 0, 0, 0, 0, 0, 0, 0,22,23 },- /* idx=6: 00800 - 008FF */- { 0,24,25, 0, 0,26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=7: 00900 - 009FF */- { 0, 0, 0,27,28,29, 0, 0, 0, 0, 0,30,31, 0, 0, 0 },- /* idx=8: 00A00 - 00AFF */- { 0, 0, 0,32,33, 0, 0, 0, 0, 0, 0,34,35, 0, 0, 0 },- /* idx=9: 00B00 - 00BFF */- { 0, 0, 0,36,37, 0, 0, 0, 0, 0, 0, 0,38, 0, 0, 0 },- /* idx=10: 00C00 - 00CFF */- { 0, 0, 0, 0,39,40, 0, 0, 0, 0, 0,41,42, 0, 0, 0 },- /* idx=11: 00D00 - 00DFF */- { 0, 0, 0, 0,43, 0, 0, 0, 0, 0, 0, 0,44, 0, 0, 0 },- /* idx=12: 00E00 - 00EFF */- { 0, 0, 0,45,46, 0, 0, 0, 0, 0, 0,47,48, 0, 0, 0 },- /* idx=13: 00F00 - 00FFF */- { 0,49, 0,50, 0, 0, 0,51,52, 0, 0, 0,53, 0, 0, 0 },- /* idx=14: 01000 - 010FF */- { 0, 0, 0,54, 0, 0, 0, 0,55, 0, 0, 0, 0, 0, 0, 0 },- /* idx=15: 01300 - 013FF */- { 0, 0, 0, 0, 0,56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=16: 01700 - 017FF */- { 0,57, 0,58, 0, 0, 0, 0, 0, 0, 0, 0, 0,59, 0, 0 },- /* idx=17: 01800 - 018FF */- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,60, 0, 0, 0, 0, 0 },- /* idx=18: 01900 - 019FF */- { 0, 0, 0,61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=19: 01A00 - 01AFF */- { 0,62, 0, 0, 0, 0,63,64, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=20: 01B00 - 01BFF */- { 0, 0, 0,65,66, 0,67,68, 0, 0,69, 0, 0, 0,70,71 },- /* idx=21: 01C00 - 01CFF */- { 0, 0, 0,72, 0, 0, 0, 0, 0, 0, 0, 0, 0,73,74, 0 },- /* idx=22: 01D00 - 01DFF */- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,75,76,77,78 },- /* idx=23: 02000 - 020FF */- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,79,80,81 },- /* idx=24: 02C00 - 02CFF */- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,82,83 },- /* idx=25: 02D00 - 02DFF */- { 0, 0, 0, 0, 0, 0, 0,84, 0, 0, 0, 0, 0, 0,85,86 },- /* idx=26: 03000 - 030FF */- { 0, 0,87, 0, 0, 0, 0, 0, 0,88, 0, 0, 0, 0, 0, 0 },- /* idx=27: 0A600 - 0A6FF */- { 0, 0, 0, 0, 0, 0,89,90, 0, 0, 0, 0, 0, 0, 0,91 },- /* idx=28: 0A800 - 0A8FF */- {92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,93, 0,94,95 },- /* idx=29: 0A900 - 0A9FF */- { 0, 0,96, 0, 0,97, 0, 0, 0, 0, 0,98,99, 0, 0, 0 },- /* idx=30: 0AA00 - 0AAFF */- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,100,101, 0, 0, 0 },- /* idx=31: 0AB00 - 0ABFF */- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102, 0 },- /* idx=32: 0FB00 - 0FBFF */- { 0,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=33: 0FE00 - 0FEFF */- { 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=34: 10100 - 101FF */- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105 },- /* idx=35: 10A00 - 10AFF */- {106, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },- /* idx=36: 11000 - 110FF */- { 0, 0, 0, 0,108, 0, 0, 0, 0, 0, 0,109, 0, 0, 0, 0 },- /* idx=37: 1D100 - 1D1FF */- { 0, 0, 0, 0, 0, 0,110,111,112, 0,113, 0, 0, 0, 0, 0 },- /* idx=38: 1D200 - 1D2FF */- { 0, 0, 0, 0,114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },-};--/* The index table to ccc_val_index[*][16] */-static const unsigned char ccc_index[] = {- 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 0, 0,15, 0, 0, 0,16,- 17,18,19,20,21,22, 0, 0,23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,24,25, 0, 0,- 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,27, 0,- 28,29,30,31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,32, 0, 0,33, 0, 0,34, 0, 0, 0, 0, 0, 0,- 0, 0,35, 0, 0, 0, 0, 0,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,- 0, 0, 0, 0, 0, 0, 0, 0, 0,37,38,};--struct unicode_decomposition_table {- uint32_t nfc;- uint32_t cp1;- uint32_t cp2;-};--static const struct unicode_decomposition_table u_decomposition_table[] = {- { 0x000C0 , 0x00041 , 0x00300 },- { 0x000C1 , 0x00041 , 0x00301 },- { 0x000C2 , 0x00041 , 0x00302 },- { 0x000C3 , 0x00041 , 0x00303 },- { 0x000C4 , 0x00041 , 0x00308 },- { 0x000C5 , 0x00041 , 0x0030A },- { 0x000C7 , 0x00043 , 0x00327 },- { 0x000C8 , 0x00045 , 0x00300 },- { 0x000C9 , 0x00045 , 0x00301 },- { 0x000CA , 0x00045 , 0x00302 },- { 0x000CB , 0x00045 , 0x00308 },- { 0x000CC , 0x00049 , 0x00300 },- { 0x000CD , 0x00049 , 0x00301 },- { 0x000CE , 0x00049 , 0x00302 },- { 0x000CF , 0x00049 , 0x00308 },- { 0x000D1 , 0x0004E , 0x00303 },- { 0x000D2 , 0x0004F , 0x00300 },- { 0x000D3 , 0x0004F , 0x00301 },- { 0x000D4 , 0x0004F , 0x00302 },- { 0x000D5 , 0x0004F , 0x00303 },- { 0x000D6 , 0x0004F , 0x00308 },- { 0x000D9 , 0x00055 , 0x00300 },- { 0x000DA , 0x00055 , 0x00301 },- { 0x000DB , 0x00055 , 0x00302 },- { 0x000DC , 0x00055 , 0x00308 },- { 0x000DD , 0x00059 , 0x00301 },- { 0x000E0 , 0x00061 , 0x00300 },- { 0x000E1 , 0x00061 , 0x00301 },- { 0x000E2 , 0x00061 , 0x00302 },- { 0x000E3 , 0x00061 , 0x00303 },- { 0x000E4 , 0x00061 , 0x00308 },- { 0x000E5 , 0x00061 , 0x0030A },- { 0x000E7 , 0x00063 , 0x00327 },- { 0x000E8 , 0x00065 , 0x00300 },- { 0x000E9 , 0x00065 , 0x00301 },- { 0x000EA , 0x00065 , 0x00302 },- { 0x000EB , 0x00065 , 0x00308 },- { 0x000EC , 0x00069 , 0x00300 },- { 0x000ED , 0x00069 , 0x00301 },- { 0x000EE , 0x00069 , 0x00302 },- { 0x000EF , 0x00069 , 0x00308 },- { 0x000F1 , 0x0006E , 0x00303 },- { 0x000F2 , 0x0006F , 0x00300 },- { 0x000F3 , 0x0006F , 0x00301 },- { 0x000F4 , 0x0006F , 0x00302 },- { 0x000F5 , 0x0006F , 0x00303 },- { 0x000F6 , 0x0006F , 0x00308 },- { 0x000F9 , 0x00075 , 0x00300 },- { 0x000FA , 0x00075 , 0x00301 },- { 0x000FB , 0x00075 , 0x00302 },- { 0x000FC , 0x00075 , 0x00308 },- { 0x000FD , 0x00079 , 0x00301 },- { 0x000FF , 0x00079 , 0x00308 },- { 0x00100 , 0x00041 , 0x00304 },- { 0x00101 , 0x00061 , 0x00304 },- { 0x00102 , 0x00041 , 0x00306 },- { 0x00103 , 0x00061 , 0x00306 },- { 0x00104 , 0x00041 , 0x00328 },- { 0x00105 , 0x00061 , 0x00328 },- { 0x00106 , 0x00043 , 0x00301 },- { 0x00107 , 0x00063 , 0x00301 },- { 0x00108 , 0x00043 , 0x00302 },- { 0x00109 , 0x00063 , 0x00302 },- { 0x0010A , 0x00043 , 0x00307 },- { 0x0010B , 0x00063 , 0x00307 },- { 0x0010C , 0x00043 , 0x0030C },- { 0x0010D , 0x00063 , 0x0030C },- { 0x0010E , 0x00044 , 0x0030C },- { 0x0010F , 0x00064 , 0x0030C },- { 0x00112 , 0x00045 , 0x00304 },- { 0x00113 , 0x00065 , 0x00304 },- { 0x00114 , 0x00045 , 0x00306 },- { 0x00115 , 0x00065 , 0x00306 },- { 0x00116 , 0x00045 , 0x00307 },- { 0x00117 , 0x00065 , 0x00307 },- { 0x00118 , 0x00045 , 0x00328 },- { 0x00119 , 0x00065 , 0x00328 },- { 0x0011A , 0x00045 , 0x0030C },- { 0x0011B , 0x00065 , 0x0030C },- { 0x0011C , 0x00047 , 0x00302 },- { 0x0011D , 0x00067 , 0x00302 },- { 0x0011E , 0x00047 , 0x00306 },- { 0x0011F , 0x00067 , 0x00306 },- { 0x00120 , 0x00047 , 0x00307 },- { 0x00121 , 0x00067 , 0x00307 },- { 0x00122 , 0x00047 , 0x00327 },- { 0x00123 , 0x00067 , 0x00327 },- { 0x00124 , 0x00048 , 0x00302 },- { 0x00125 , 0x00068 , 0x00302 },- { 0x00128 , 0x00049 , 0x00303 },- { 0x00129 , 0x00069 , 0x00303 },- { 0x0012A , 0x00049 , 0x00304 },- { 0x0012B , 0x00069 , 0x00304 },- { 0x0012C , 0x00049 , 0x00306 },- { 0x0012D , 0x00069 , 0x00306 },- { 0x0012E , 0x00049 , 0x00328 },- { 0x0012F , 0x00069 , 0x00328 },- { 0x00130 , 0x00049 , 0x00307 },- { 0x00134 , 0x0004A , 0x00302 },- { 0x00135 , 0x0006A , 0x00302 },- { 0x00136 , 0x0004B , 0x00327 },- { 0x00137 , 0x0006B , 0x00327 },- { 0x00139 , 0x0004C , 0x00301 },- { 0x0013A , 0x0006C , 0x00301 },- { 0x0013B , 0x0004C , 0x00327 },- { 0x0013C , 0x0006C , 0x00327 },- { 0x0013D , 0x0004C , 0x0030C },- { 0x0013E , 0x0006C , 0x0030C },- { 0x00143 , 0x0004E , 0x00301 },- { 0x00144 , 0x0006E , 0x00301 },- { 0x00145 , 0x0004E , 0x00327 },- { 0x00146 , 0x0006E , 0x00327 },- { 0x00147 , 0x0004E , 0x0030C },- { 0x00148 , 0x0006E , 0x0030C },- { 0x0014C , 0x0004F , 0x00304 },- { 0x0014D , 0x0006F , 0x00304 },- { 0x0014E , 0x0004F , 0x00306 },- { 0x0014F , 0x0006F , 0x00306 },- { 0x00150 , 0x0004F , 0x0030B },- { 0x00151 , 0x0006F , 0x0030B },- { 0x00154 , 0x00052 , 0x00301 },- { 0x00155 , 0x00072 , 0x00301 },- { 0x00156 , 0x00052 , 0x00327 },- { 0x00157 , 0x00072 , 0x00327 },- { 0x00158 , 0x00052 , 0x0030C },- { 0x00159 , 0x00072 , 0x0030C },- { 0x0015A , 0x00053 , 0x00301 },- { 0x0015B , 0x00073 , 0x00301 },- { 0x0015C , 0x00053 , 0x00302 },- { 0x0015D , 0x00073 , 0x00302 },- { 0x0015E , 0x00053 , 0x00327 },- { 0x0015F , 0x00073 , 0x00327 },- { 0x00160 , 0x00053 , 0x0030C },- { 0x00161 , 0x00073 , 0x0030C },- { 0x00162 , 0x00054 , 0x00327 },- { 0x00163 , 0x00074 , 0x00327 },- { 0x00164 , 0x00054 , 0x0030C },- { 0x00165 , 0x00074 , 0x0030C },- { 0x00168 , 0x00055 , 0x00303 },- { 0x00169 , 0x00075 , 0x00303 },- { 0x0016A , 0x00055 , 0x00304 },- { 0x0016B , 0x00075 , 0x00304 },- { 0x0016C , 0x00055 , 0x00306 },- { 0x0016D , 0x00075 , 0x00306 },- { 0x0016E , 0x00055 , 0x0030A },- { 0x0016F , 0x00075 , 0x0030A },- { 0x00170 , 0x00055 , 0x0030B },- { 0x00171 , 0x00075 , 0x0030B },- { 0x00172 , 0x00055 , 0x00328 },- { 0x00173 , 0x00075 , 0x00328 },- { 0x00174 , 0x00057 , 0x00302 },- { 0x00175 , 0x00077 , 0x00302 },- { 0x00176 , 0x00059 , 0x00302 },- { 0x00177 , 0x00079 , 0x00302 },- { 0x00178 , 0x00059 , 0x00308 },- { 0x00179 , 0x0005A , 0x00301 },- { 0x0017A , 0x0007A , 0x00301 },- { 0x0017B , 0x0005A , 0x00307 },- { 0x0017C , 0x0007A , 0x00307 },- { 0x0017D , 0x0005A , 0x0030C },- { 0x0017E , 0x0007A , 0x0030C },- { 0x001A0 , 0x0004F , 0x0031B },- { 0x001A1 , 0x0006F , 0x0031B },- { 0x001AF , 0x00055 , 0x0031B },- { 0x001B0 , 0x00075 , 0x0031B },- { 0x001CD , 0x00041 , 0x0030C },- { 0x001CE , 0x00061 , 0x0030C },- { 0x001CF , 0x00049 , 0x0030C },- { 0x001D0 , 0x00069 , 0x0030C },- { 0x001D1 , 0x0004F , 0x0030C },- { 0x001D2 , 0x0006F , 0x0030C },- { 0x001D3 , 0x00055 , 0x0030C },- { 0x001D4 , 0x00075 , 0x0030C },- { 0x001D5 , 0x000DC , 0x00304 },- { 0x001D6 , 0x000FC , 0x00304 },- { 0x001D7 , 0x000DC , 0x00301 },- { 0x001D8 , 0x000FC , 0x00301 },- { 0x001D9 , 0x000DC , 0x0030C },- { 0x001DA , 0x000FC , 0x0030C },- { 0x001DB , 0x000DC , 0x00300 },- { 0x001DC , 0x000FC , 0x00300 },- { 0x001DE , 0x000C4 , 0x00304 },- { 0x001DF , 0x000E4 , 0x00304 },- { 0x001E0 , 0x00226 , 0x00304 },- { 0x001E1 , 0x00227 , 0x00304 },- { 0x001E2 , 0x000C6 , 0x00304 },- { 0x001E3 , 0x000E6 , 0x00304 },- { 0x001E6 , 0x00047 , 0x0030C },- { 0x001E7 , 0x00067 , 0x0030C },- { 0x001E8 , 0x0004B , 0x0030C },- { 0x001E9 , 0x0006B , 0x0030C },- { 0x001EA , 0x0004F , 0x00328 },- { 0x001EB , 0x0006F , 0x00328 },- { 0x001EC , 0x001EA , 0x00304 },- { 0x001ED , 0x001EB , 0x00304 },- { 0x001EE , 0x001B7 , 0x0030C },- { 0x001EF , 0x00292 , 0x0030C },- { 0x001F0 , 0x0006A , 0x0030C },- { 0x001F4 , 0x00047 , 0x00301 },- { 0x001F5 , 0x00067 , 0x00301 },- { 0x001F8 , 0x0004E , 0x00300 },- { 0x001F9 , 0x0006E , 0x00300 },- { 0x001FA , 0x000C5 , 0x00301 },- { 0x001FB , 0x000E5 , 0x00301 },- { 0x001FC , 0x000C6 , 0x00301 },- { 0x001FD , 0x000E6 , 0x00301 },- { 0x001FE , 0x000D8 , 0x00301 },- { 0x001FF , 0x000F8 , 0x00301 },- { 0x00200 , 0x00041 , 0x0030F },- { 0x00201 , 0x00061 , 0x0030F },- { 0x00202 , 0x00041 , 0x00311 },- { 0x00203 , 0x00061 , 0x00311 },- { 0x00204 , 0x00045 , 0x0030F },- { 0x00205 , 0x00065 , 0x0030F },- { 0x00206 , 0x00045 , 0x00311 },- { 0x00207 , 0x00065 , 0x00311 },- { 0x00208 , 0x00049 , 0x0030F },- { 0x00209 , 0x00069 , 0x0030F },- { 0x0020A , 0x00049 , 0x00311 },- { 0x0020B , 0x00069 , 0x00311 },- { 0x0020C , 0x0004F , 0x0030F },- { 0x0020D , 0x0006F , 0x0030F },- { 0x0020E , 0x0004F , 0x00311 },- { 0x0020F , 0x0006F , 0x00311 },- { 0x00210 , 0x00052 , 0x0030F },- { 0x00211 , 0x00072 , 0x0030F },- { 0x00212 , 0x00052 , 0x00311 },- { 0x00213 , 0x00072 , 0x00311 },- { 0x00214 , 0x00055 , 0x0030F },- { 0x00215 , 0x00075 , 0x0030F },- { 0x00216 , 0x00055 , 0x00311 },- { 0x00217 , 0x00075 , 0x00311 },- { 0x00218 , 0x00053 , 0x00326 },- { 0x00219 , 0x00073 , 0x00326 },- { 0x0021A , 0x00054 , 0x00326 },- { 0x0021B , 0x00074 , 0x00326 },- { 0x0021E , 0x00048 , 0x0030C },- { 0x0021F , 0x00068 , 0x0030C },- { 0x00226 , 0x00041 , 0x00307 },- { 0x00227 , 0x00061 , 0x00307 },- { 0x00228 , 0x00045 , 0x00327 },- { 0x00229 , 0x00065 , 0x00327 },- { 0x0022A , 0x000D6 , 0x00304 },- { 0x0022B , 0x000F6 , 0x00304 },- { 0x0022C , 0x000D5 , 0x00304 },- { 0x0022D , 0x000F5 , 0x00304 },- { 0x0022E , 0x0004F , 0x00307 },- { 0x0022F , 0x0006F , 0x00307 },- { 0x00230 , 0x0022E , 0x00304 },- { 0x00231 , 0x0022F , 0x00304 },- { 0x00232 , 0x00059 , 0x00304 },- { 0x00233 , 0x00079 , 0x00304 },- { 0x00385 , 0x000A8 , 0x00301 },- { 0x00386 , 0x00391 , 0x00301 },- { 0x00388 , 0x00395 , 0x00301 },- { 0x00389 , 0x00397 , 0x00301 },- { 0x0038A , 0x00399 , 0x00301 },- { 0x0038C , 0x0039F , 0x00301 },- { 0x0038E , 0x003A5 , 0x00301 },- { 0x0038F , 0x003A9 , 0x00301 },- { 0x00390 , 0x003CA , 0x00301 },- { 0x003AA , 0x00399 , 0x00308 },- { 0x003AB , 0x003A5 , 0x00308 },- { 0x003AC , 0x003B1 , 0x00301 },- { 0x003AD , 0x003B5 , 0x00301 },- { 0x003AE , 0x003B7 , 0x00301 },- { 0x003AF , 0x003B9 , 0x00301 },- { 0x003B0 , 0x003CB , 0x00301 },- { 0x003CA , 0x003B9 , 0x00308 },- { 0x003CB , 0x003C5 , 0x00308 },- { 0x003CC , 0x003BF , 0x00301 },- { 0x003CD , 0x003C5 , 0x00301 },- { 0x003CE , 0x003C9 , 0x00301 },- { 0x003D3 , 0x003D2 , 0x00301 },- { 0x003D4 , 0x003D2 , 0x00308 },- { 0x00400 , 0x00415 , 0x00300 },- { 0x00401 , 0x00415 , 0x00308 },- { 0x00403 , 0x00413 , 0x00301 },- { 0x00407 , 0x00406 , 0x00308 },- { 0x0040C , 0x0041A , 0x00301 },- { 0x0040D , 0x00418 , 0x00300 },- { 0x0040E , 0x00423 , 0x00306 },- { 0x00419 , 0x00418 , 0x00306 },- { 0x00439 , 0x00438 , 0x00306 },- { 0x00450 , 0x00435 , 0x00300 },- { 0x00451 , 0x00435 , 0x00308 },- { 0x00453 , 0x00433 , 0x00301 },- { 0x00457 , 0x00456 , 0x00308 },- { 0x0045C , 0x0043A , 0x00301 },- { 0x0045D , 0x00438 , 0x00300 },- { 0x0045E , 0x00443 , 0x00306 },- { 0x00476 , 0x00474 , 0x0030F },- { 0x00477 , 0x00475 , 0x0030F },- { 0x004C1 , 0x00416 , 0x00306 },- { 0x004C2 , 0x00436 , 0x00306 },- { 0x004D0 , 0x00410 , 0x00306 },- { 0x004D1 , 0x00430 , 0x00306 },- { 0x004D2 , 0x00410 , 0x00308 },- { 0x004D3 , 0x00430 , 0x00308 },- { 0x004D6 , 0x00415 , 0x00306 },- { 0x004D7 , 0x00435 , 0x00306 },- { 0x004DA , 0x004D8 , 0x00308 },- { 0x004DB , 0x004D9 , 0x00308 },- { 0x004DC , 0x00416 , 0x00308 },- { 0x004DD , 0x00436 , 0x00308 },- { 0x004DE , 0x00417 , 0x00308 },- { 0x004DF , 0x00437 , 0x00308 },- { 0x004E2 , 0x00418 , 0x00304 },- { 0x004E3 , 0x00438 , 0x00304 },- { 0x004E4 , 0x00418 , 0x00308 },- { 0x004E5 , 0x00438 , 0x00308 },- { 0x004E6 , 0x0041E , 0x00308 },- { 0x004E7 , 0x0043E , 0x00308 },- { 0x004EA , 0x004E8 , 0x00308 },- { 0x004EB , 0x004E9 , 0x00308 },- { 0x004EC , 0x0042D , 0x00308 },- { 0x004ED , 0x0044D , 0x00308 },- { 0x004EE , 0x00423 , 0x00304 },- { 0x004EF , 0x00443 , 0x00304 },- { 0x004F0 , 0x00423 , 0x00308 },- { 0x004F1 , 0x00443 , 0x00308 },- { 0x004F2 , 0x00423 , 0x0030B },- { 0x004F3 , 0x00443 , 0x0030B },- { 0x004F4 , 0x00427 , 0x00308 },- { 0x004F5 , 0x00447 , 0x00308 },- { 0x004F8 , 0x0042B , 0x00308 },- { 0x004F9 , 0x0044B , 0x00308 },- { 0x00622 , 0x00627 , 0x00653 },- { 0x00623 , 0x00627 , 0x00654 },- { 0x00624 , 0x00648 , 0x00654 },- { 0x00625 , 0x00627 , 0x00655 },- { 0x00626 , 0x0064A , 0x00654 },- { 0x006C0 , 0x006D5 , 0x00654 },- { 0x006C2 , 0x006C1 , 0x00654 },- { 0x006D3 , 0x006D2 , 0x00654 },- { 0x00929 , 0x00928 , 0x0093C },- { 0x00931 , 0x00930 , 0x0093C },- { 0x00934 , 0x00933 , 0x0093C },- { 0x009CB , 0x009C7 , 0x009BE },- { 0x009CC , 0x009C7 , 0x009D7 },- { 0x00B48 , 0x00B47 , 0x00B56 },- { 0x00B4B , 0x00B47 , 0x00B3E },- { 0x00B4C , 0x00B47 , 0x00B57 },- { 0x00B94 , 0x00B92 , 0x00BD7 },- { 0x00BCA , 0x00BC6 , 0x00BBE },- { 0x00BCB , 0x00BC7 , 0x00BBE },- { 0x00BCC , 0x00BC6 , 0x00BD7 },- { 0x00C48 , 0x00C46 , 0x00C56 },- { 0x00CC0 , 0x00CBF , 0x00CD5 },- { 0x00CC7 , 0x00CC6 , 0x00CD5 },- { 0x00CC8 , 0x00CC6 , 0x00CD6 },- { 0x00CCA , 0x00CC6 , 0x00CC2 },- { 0x00CCB , 0x00CCA , 0x00CD5 },- { 0x00D4A , 0x00D46 , 0x00D3E },- { 0x00D4B , 0x00D47 , 0x00D3E },- { 0x00D4C , 0x00D46 , 0x00D57 },- { 0x00DDA , 0x00DD9 , 0x00DCA },- { 0x00DDC , 0x00DD9 , 0x00DCF },- { 0x00DDD , 0x00DDC , 0x00DCA },- { 0x00DDE , 0x00DD9 , 0x00DDF },- { 0x01026 , 0x01025 , 0x0102E },- { 0x01B06 , 0x01B05 , 0x01B35 },- { 0x01B08 , 0x01B07 , 0x01B35 },- { 0x01B0A , 0x01B09 , 0x01B35 },- { 0x01B0C , 0x01B0B , 0x01B35 },- { 0x01B0E , 0x01B0D , 0x01B35 },- { 0x01B12 , 0x01B11 , 0x01B35 },- { 0x01B3B , 0x01B3A , 0x01B35 },- { 0x01B3D , 0x01B3C , 0x01B35 },- { 0x01B40 , 0x01B3E , 0x01B35 },- { 0x01B41 , 0x01B3F , 0x01B35 },- { 0x01B43 , 0x01B42 , 0x01B35 },- { 0x01E00 , 0x00041 , 0x00325 },- { 0x01E01 , 0x00061 , 0x00325 },- { 0x01E02 , 0x00042 , 0x00307 },- { 0x01E03 , 0x00062 , 0x00307 },- { 0x01E04 , 0x00042 , 0x00323 },- { 0x01E05 , 0x00062 , 0x00323 },- { 0x01E06 , 0x00042 , 0x00331 },- { 0x01E07 , 0x00062 , 0x00331 },- { 0x01E08 , 0x000C7 , 0x00301 },- { 0x01E09 , 0x000E7 , 0x00301 },- { 0x01E0A , 0x00044 , 0x00307 },- { 0x01E0B , 0x00064 , 0x00307 },- { 0x01E0C , 0x00044 , 0x00323 },- { 0x01E0D , 0x00064 , 0x00323 },- { 0x01E0E , 0x00044 , 0x00331 },- { 0x01E0F , 0x00064 , 0x00331 },- { 0x01E10 , 0x00044 , 0x00327 },- { 0x01E11 , 0x00064 , 0x00327 },- { 0x01E12 , 0x00044 , 0x0032D },- { 0x01E13 , 0x00064 , 0x0032D },- { 0x01E14 , 0x00112 , 0x00300 },- { 0x01E15 , 0x00113 , 0x00300 },- { 0x01E16 , 0x00112 , 0x00301 },- { 0x01E17 , 0x00113 , 0x00301 },- { 0x01E18 , 0x00045 , 0x0032D },- { 0x01E19 , 0x00065 , 0x0032D },- { 0x01E1A , 0x00045 , 0x00330 },- { 0x01E1B , 0x00065 , 0x00330 },- { 0x01E1C , 0x00228 , 0x00306 },- { 0x01E1D , 0x00229 , 0x00306 },- { 0x01E1E , 0x00046 , 0x00307 },- { 0x01E1F , 0x00066 , 0x00307 },- { 0x01E20 , 0x00047 , 0x00304 },- { 0x01E21 , 0x00067 , 0x00304 },- { 0x01E22 , 0x00048 , 0x00307 },- { 0x01E23 , 0x00068 , 0x00307 },- { 0x01E24 , 0x00048 , 0x00323 },- { 0x01E25 , 0x00068 , 0x00323 },- { 0x01E26 , 0x00048 , 0x00308 },- { 0x01E27 , 0x00068 , 0x00308 },- { 0x01E28 , 0x00048 , 0x00327 },- { 0x01E29 , 0x00068 , 0x00327 },- { 0x01E2A , 0x00048 , 0x0032E },- { 0x01E2B , 0x00068 , 0x0032E },- { 0x01E2C , 0x00049 , 0x00330 },- { 0x01E2D , 0x00069 , 0x00330 },- { 0x01E2E , 0x000CF , 0x00301 },- { 0x01E2F , 0x000EF , 0x00301 },- { 0x01E30 , 0x0004B , 0x00301 },- { 0x01E31 , 0x0006B , 0x00301 },- { 0x01E32 , 0x0004B , 0x00323 },- { 0x01E33 , 0x0006B , 0x00323 },- { 0x01E34 , 0x0004B , 0x00331 },- { 0x01E35 , 0x0006B , 0x00331 },- { 0x01E36 , 0x0004C , 0x00323 },- { 0x01E37 , 0x0006C , 0x00323 },- { 0x01E38 , 0x01E36 , 0x00304 },- { 0x01E39 , 0x01E37 , 0x00304 },- { 0x01E3A , 0x0004C , 0x00331 },- { 0x01E3B , 0x0006C , 0x00331 },- { 0x01E3C , 0x0004C , 0x0032D },- { 0x01E3D , 0x0006C , 0x0032D },- { 0x01E3E , 0x0004D , 0x00301 },- { 0x01E3F , 0x0006D , 0x00301 },- { 0x01E40 , 0x0004D , 0x00307 },- { 0x01E41 , 0x0006D , 0x00307 },- { 0x01E42 , 0x0004D , 0x00323 },- { 0x01E43 , 0x0006D , 0x00323 },- { 0x01E44 , 0x0004E , 0x00307 },- { 0x01E45 , 0x0006E , 0x00307 },- { 0x01E46 , 0x0004E , 0x00323 },- { 0x01E47 , 0x0006E , 0x00323 },- { 0x01E48 , 0x0004E , 0x00331 },- { 0x01E49 , 0x0006E , 0x00331 },- { 0x01E4A , 0x0004E , 0x0032D },- { 0x01E4B , 0x0006E , 0x0032D },- { 0x01E4C , 0x000D5 , 0x00301 },- { 0x01E4D , 0x000F5 , 0x00301 },- { 0x01E4E , 0x000D5 , 0x00308 },- { 0x01E4F , 0x000F5 , 0x00308 },- { 0x01E50 , 0x0014C , 0x00300 },- { 0x01E51 , 0x0014D , 0x00300 },- { 0x01E52 , 0x0014C , 0x00301 },- { 0x01E53 , 0x0014D , 0x00301 },- { 0x01E54 , 0x00050 , 0x00301 },- { 0x01E55 , 0x00070 , 0x00301 },- { 0x01E56 , 0x00050 , 0x00307 },- { 0x01E57 , 0x00070 , 0x00307 },- { 0x01E58 , 0x00052 , 0x00307 },- { 0x01E59 , 0x00072 , 0x00307 },- { 0x01E5A , 0x00052 , 0x00323 },- { 0x01E5B , 0x00072 , 0x00323 },- { 0x01E5C , 0x01E5A , 0x00304 },- { 0x01E5D , 0x01E5B , 0x00304 },- { 0x01E5E , 0x00052 , 0x00331 },- { 0x01E5F , 0x00072 , 0x00331 },- { 0x01E60 , 0x00053 , 0x00307 },- { 0x01E61 , 0x00073 , 0x00307 },- { 0x01E62 , 0x00053 , 0x00323 },- { 0x01E63 , 0x00073 , 0x00323 },- { 0x01E64 , 0x0015A , 0x00307 },- { 0x01E65 , 0x0015B , 0x00307 },- { 0x01E66 , 0x00160 , 0x00307 },- { 0x01E67 , 0x00161 , 0x00307 },- { 0x01E68 , 0x01E62 , 0x00307 },- { 0x01E69 , 0x01E63 , 0x00307 },- { 0x01E6A , 0x00054 , 0x00307 },- { 0x01E6B , 0x00074 , 0x00307 },- { 0x01E6C , 0x00054 , 0x00323 },- { 0x01E6D , 0x00074 , 0x00323 },- { 0x01E6E , 0x00054 , 0x00331 },- { 0x01E6F , 0x00074 , 0x00331 },- { 0x01E70 , 0x00054 , 0x0032D },- { 0x01E71 , 0x00074 , 0x0032D },- { 0x01E72 , 0x00055 , 0x00324 },- { 0x01E73 , 0x00075 , 0x00324 },- { 0x01E74 , 0x00055 , 0x00330 },- { 0x01E75 , 0x00075 , 0x00330 },- { 0x01E76 , 0x00055 , 0x0032D },- { 0x01E77 , 0x00075 , 0x0032D },- { 0x01E78 , 0x00168 , 0x00301 },- { 0x01E79 , 0x00169 , 0x00301 },- { 0x01E7A , 0x0016A , 0x00308 },- { 0x01E7B , 0x0016B , 0x00308 },- { 0x01E7C , 0x00056 , 0x00303 },- { 0x01E7D , 0x00076 , 0x00303 },- { 0x01E7E , 0x00056 , 0x00323 },- { 0x01E7F , 0x00076 , 0x00323 },- { 0x01E80 , 0x00057 , 0x00300 },- { 0x01E81 , 0x00077 , 0x00300 },- { 0x01E82 , 0x00057 , 0x00301 },- { 0x01E83 , 0x00077 , 0x00301 },- { 0x01E84 , 0x00057 , 0x00308 },- { 0x01E85 , 0x00077 , 0x00308 },- { 0x01E86 , 0x00057 , 0x00307 },- { 0x01E87 , 0x00077 , 0x00307 },- { 0x01E88 , 0x00057 , 0x00323 },- { 0x01E89 , 0x00077 , 0x00323 },- { 0x01E8A , 0x00058 , 0x00307 },- { 0x01E8B , 0x00078 , 0x00307 },- { 0x01E8C , 0x00058 , 0x00308 },- { 0x01E8D , 0x00078 , 0x00308 },- { 0x01E8E , 0x00059 , 0x00307 },- { 0x01E8F , 0x00079 , 0x00307 },- { 0x01E90 , 0x0005A , 0x00302 },- { 0x01E91 , 0x0007A , 0x00302 },- { 0x01E92 , 0x0005A , 0x00323 },- { 0x01E93 , 0x0007A , 0x00323 },- { 0x01E94 , 0x0005A , 0x00331 },- { 0x01E95 , 0x0007A , 0x00331 },- { 0x01E96 , 0x00068 , 0x00331 },- { 0x01E97 , 0x00074 , 0x00308 },- { 0x01E98 , 0x00077 , 0x0030A },- { 0x01E99 , 0x00079 , 0x0030A },- { 0x01E9B , 0x0017F , 0x00307 },- { 0x01EA0 , 0x00041 , 0x00323 },- { 0x01EA1 , 0x00061 , 0x00323 },- { 0x01EA2 , 0x00041 , 0x00309 },- { 0x01EA3 , 0x00061 , 0x00309 },- { 0x01EA4 , 0x000C2 , 0x00301 },- { 0x01EA5 , 0x000E2 , 0x00301 },- { 0x01EA6 , 0x000C2 , 0x00300 },- { 0x01EA7 , 0x000E2 , 0x00300 },- { 0x01EA8 , 0x000C2 , 0x00309 },- { 0x01EA9 , 0x000E2 , 0x00309 },- { 0x01EAA , 0x000C2 , 0x00303 },- { 0x01EAB , 0x000E2 , 0x00303 },- { 0x01EAC , 0x01EA0 , 0x00302 },- { 0x01EAD , 0x01EA1 , 0x00302 },- { 0x01EAE , 0x00102 , 0x00301 },- { 0x01EAF , 0x00103 , 0x00301 },- { 0x01EB0 , 0x00102 , 0x00300 },- { 0x01EB1 , 0x00103 , 0x00300 },- { 0x01EB2 , 0x00102 , 0x00309 },- { 0x01EB3 , 0x00103 , 0x00309 },- { 0x01EB4 , 0x00102 , 0x00303 },- { 0x01EB5 , 0x00103 , 0x00303 },- { 0x01EB6 , 0x01EA0 , 0x00306 },- { 0x01EB7 , 0x01EA1 , 0x00306 },- { 0x01EB8 , 0x00045 , 0x00323 },- { 0x01EB9 , 0x00065 , 0x00323 },- { 0x01EBA , 0x00045 , 0x00309 },- { 0x01EBB , 0x00065 , 0x00309 },- { 0x01EBC , 0x00045 , 0x00303 },- { 0x01EBD , 0x00065 , 0x00303 },- { 0x01EBE , 0x000CA , 0x00301 },- { 0x01EBF , 0x000EA , 0x00301 },- { 0x01EC0 , 0x000CA , 0x00300 },- { 0x01EC1 , 0x000EA , 0x00300 },- { 0x01EC2 , 0x000CA , 0x00309 },- { 0x01EC3 , 0x000EA , 0x00309 },- { 0x01EC4 , 0x000CA , 0x00303 },- { 0x01EC5 , 0x000EA , 0x00303 },- { 0x01EC6 , 0x01EB8 , 0x00302 },- { 0x01EC7 , 0x01EB9 , 0x00302 },- { 0x01EC8 , 0x00049 , 0x00309 },- { 0x01EC9 , 0x00069 , 0x00309 },- { 0x01ECA , 0x00049 , 0x00323 },- { 0x01ECB , 0x00069 , 0x00323 },- { 0x01ECC , 0x0004F , 0x00323 },- { 0x01ECD , 0x0006F , 0x00323 },- { 0x01ECE , 0x0004F , 0x00309 },- { 0x01ECF , 0x0006F , 0x00309 },- { 0x01ED0 , 0x000D4 , 0x00301 },- { 0x01ED1 , 0x000F4 , 0x00301 },- { 0x01ED2 , 0x000D4 , 0x00300 },- { 0x01ED3 , 0x000F4 , 0x00300 },- { 0x01ED4 , 0x000D4 , 0x00309 },- { 0x01ED5 , 0x000F4 , 0x00309 },- { 0x01ED6 , 0x000D4 , 0x00303 },- { 0x01ED7 , 0x000F4 , 0x00303 },- { 0x01ED8 , 0x01ECC , 0x00302 },- { 0x01ED9 , 0x01ECD , 0x00302 },- { 0x01EDA , 0x001A0 , 0x00301 },- { 0x01EDB , 0x001A1 , 0x00301 },- { 0x01EDC , 0x001A0 , 0x00300 },- { 0x01EDD , 0x001A1 , 0x00300 },- { 0x01EDE , 0x001A0 , 0x00309 },- { 0x01EDF , 0x001A1 , 0x00309 },- { 0x01EE0 , 0x001A0 , 0x00303 },- { 0x01EE1 , 0x001A1 , 0x00303 },- { 0x01EE2 , 0x001A0 , 0x00323 },- { 0x01EE3 , 0x001A1 , 0x00323 },- { 0x01EE4 , 0x00055 , 0x00323 },- { 0x01EE5 , 0x00075 , 0x00323 },- { 0x01EE6 , 0x00055 , 0x00309 },- { 0x01EE7 , 0x00075 , 0x00309 },- { 0x01EE8 , 0x001AF , 0x00301 },- { 0x01EE9 , 0x001B0 , 0x00301 },- { 0x01EEA , 0x001AF , 0x00300 },- { 0x01EEB , 0x001B0 , 0x00300 },- { 0x01EEC , 0x001AF , 0x00309 },- { 0x01EED , 0x001B0 , 0x00309 },- { 0x01EEE , 0x001AF , 0x00303 },- { 0x01EEF , 0x001B0 , 0x00303 },- { 0x01EF0 , 0x001AF , 0x00323 },- { 0x01EF1 , 0x001B0 , 0x00323 },- { 0x01EF2 , 0x00059 , 0x00300 },- { 0x01EF3 , 0x00079 , 0x00300 },- { 0x01EF4 , 0x00059 , 0x00323 },- { 0x01EF5 , 0x00079 , 0x00323 },- { 0x01EF6 , 0x00059 , 0x00309 },- { 0x01EF7 , 0x00079 , 0x00309 },- { 0x01EF8 , 0x00059 , 0x00303 },- { 0x01EF9 , 0x00079 , 0x00303 },- { 0x01F00 , 0x003B1 , 0x00313 },- { 0x01F01 , 0x003B1 , 0x00314 },- { 0x01F02 , 0x01F00 , 0x00300 },- { 0x01F03 , 0x01F01 , 0x00300 },- { 0x01F04 , 0x01F00 , 0x00301 },- { 0x01F05 , 0x01F01 , 0x00301 },- { 0x01F06 , 0x01F00 , 0x00342 },- { 0x01F07 , 0x01F01 , 0x00342 },- { 0x01F08 , 0x00391 , 0x00313 },- { 0x01F09 , 0x00391 , 0x00314 },- { 0x01F0A , 0x01F08 , 0x00300 },- { 0x01F0B , 0x01F09 , 0x00300 },- { 0x01F0C , 0x01F08 , 0x00301 },- { 0x01F0D , 0x01F09 , 0x00301 },- { 0x01F0E , 0x01F08 , 0x00342 },- { 0x01F0F , 0x01F09 , 0x00342 },- { 0x01F10 , 0x003B5 , 0x00313 },- { 0x01F11 , 0x003B5 , 0x00314 },- { 0x01F12 , 0x01F10 , 0x00300 },- { 0x01F13 , 0x01F11 , 0x00300 },- { 0x01F14 , 0x01F10 , 0x00301 },- { 0x01F15 , 0x01F11 , 0x00301 },- { 0x01F18 , 0x00395 , 0x00313 },- { 0x01F19 , 0x00395 , 0x00314 },- { 0x01F1A , 0x01F18 , 0x00300 },- { 0x01F1B , 0x01F19 , 0x00300 },- { 0x01F1C , 0x01F18 , 0x00301 },- { 0x01F1D , 0x01F19 , 0x00301 },- { 0x01F20 , 0x003B7 , 0x00313 },- { 0x01F21 , 0x003B7 , 0x00314 },- { 0x01F22 , 0x01F20 , 0x00300 },- { 0x01F23 , 0x01F21 , 0x00300 },- { 0x01F24 , 0x01F20 , 0x00301 },- { 0x01F25 , 0x01F21 , 0x00301 },- { 0x01F26 , 0x01F20 , 0x00342 },- { 0x01F27 , 0x01F21 , 0x00342 },- { 0x01F28 , 0x00397 , 0x00313 },- { 0x01F29 , 0x00397 , 0x00314 },- { 0x01F2A , 0x01F28 , 0x00300 },- { 0x01F2B , 0x01F29 , 0x00300 },- { 0x01F2C , 0x01F28 , 0x00301 },- { 0x01F2D , 0x01F29 , 0x00301 },- { 0x01F2E , 0x01F28 , 0x00342 },- { 0x01F2F , 0x01F29 , 0x00342 },- { 0x01F30 , 0x003B9 , 0x00313 },- { 0x01F31 , 0x003B9 , 0x00314 },- { 0x01F32 , 0x01F30 , 0x00300 },- { 0x01F33 , 0x01F31 , 0x00300 },- { 0x01F34 , 0x01F30 , 0x00301 },- { 0x01F35 , 0x01F31 , 0x00301 },- { 0x01F36 , 0x01F30 , 0x00342 },- { 0x01F37 , 0x01F31 , 0x00342 },- { 0x01F38 , 0x00399 , 0x00313 },- { 0x01F39 , 0x00399 , 0x00314 },- { 0x01F3A , 0x01F38 , 0x00300 },- { 0x01F3B , 0x01F39 , 0x00300 },- { 0x01F3C , 0x01F38 , 0x00301 },- { 0x01F3D , 0x01F39 , 0x00301 },- { 0x01F3E , 0x01F38 , 0x00342 },- { 0x01F3F , 0x01F39 , 0x00342 },- { 0x01F40 , 0x003BF , 0x00313 },- { 0x01F41 , 0x003BF , 0x00314 },- { 0x01F42 , 0x01F40 , 0x00300 },- { 0x01F43 , 0x01F41 , 0x00300 },- { 0x01F44 , 0x01F40 , 0x00301 },- { 0x01F45 , 0x01F41 , 0x00301 },- { 0x01F48 , 0x0039F , 0x00313 },- { 0x01F49 , 0x0039F , 0x00314 },- { 0x01F4A , 0x01F48 , 0x00300 },- { 0x01F4B , 0x01F49 , 0x00300 },- { 0x01F4C , 0x01F48 , 0x00301 },- { 0x01F4D , 0x01F49 , 0x00301 },- { 0x01F50 , 0x003C5 , 0x00313 },- { 0x01F51 , 0x003C5 , 0x00314 },- { 0x01F52 , 0x01F50 , 0x00300 },- { 0x01F53 , 0x01F51 , 0x00300 },- { 0x01F54 , 0x01F50 , 0x00301 },- { 0x01F55 , 0x01F51 , 0x00301 },- { 0x01F56 , 0x01F50 , 0x00342 },- { 0x01F57 , 0x01F51 , 0x00342 },- { 0x01F59 , 0x003A5 , 0x00314 },- { 0x01F5B , 0x01F59 , 0x00300 },- { 0x01F5D , 0x01F59 , 0x00301 },- { 0x01F5F , 0x01F59 , 0x00342 },- { 0x01F60 , 0x003C9 , 0x00313 },- { 0x01F61 , 0x003C9 , 0x00314 },- { 0x01F62 , 0x01F60 , 0x00300 },- { 0x01F63 , 0x01F61 , 0x00300 },- { 0x01F64 , 0x01F60 , 0x00301 },- { 0x01F65 , 0x01F61 , 0x00301 },- { 0x01F66 , 0x01F60 , 0x00342 },- { 0x01F67 , 0x01F61 , 0x00342 },- { 0x01F68 , 0x003A9 , 0x00313 },- { 0x01F69 , 0x003A9 , 0x00314 },- { 0x01F6A , 0x01F68 , 0x00300 },- { 0x01F6B , 0x01F69 , 0x00300 },- { 0x01F6C , 0x01F68 , 0x00301 },- { 0x01F6D , 0x01F69 , 0x00301 },- { 0x01F6E , 0x01F68 , 0x00342 },- { 0x01F6F , 0x01F69 , 0x00342 },- { 0x01F70 , 0x003B1 , 0x00300 },- { 0x01F72 , 0x003B5 , 0x00300 },- { 0x01F74 , 0x003B7 , 0x00300 },- { 0x01F76 , 0x003B9 , 0x00300 },- { 0x01F78 , 0x003BF , 0x00300 },- { 0x01F7A , 0x003C5 , 0x00300 },- { 0x01F7C , 0x003C9 , 0x00300 },- { 0x01F80 , 0x01F00 , 0x00345 },- { 0x01F81 , 0x01F01 , 0x00345 },- { 0x01F82 , 0x01F02 , 0x00345 },- { 0x01F83 , 0x01F03 , 0x00345 },- { 0x01F84 , 0x01F04 , 0x00345 },- { 0x01F85 , 0x01F05 , 0x00345 },- { 0x01F86 , 0x01F06 , 0x00345 },- { 0x01F87 , 0x01F07 , 0x00345 },- { 0x01F88 , 0x01F08 , 0x00345 },- { 0x01F89 , 0x01F09 , 0x00345 },- { 0x01F8A , 0x01F0A , 0x00345 },- { 0x01F8B , 0x01F0B , 0x00345 },- { 0x01F8C , 0x01F0C , 0x00345 },- { 0x01F8D , 0x01F0D , 0x00345 },- { 0x01F8E , 0x01F0E , 0x00345 },- { 0x01F8F , 0x01F0F , 0x00345 },- { 0x01F90 , 0x01F20 , 0x00345 },- { 0x01F91 , 0x01F21 , 0x00345 },- { 0x01F92 , 0x01F22 , 0x00345 },- { 0x01F93 , 0x01F23 , 0x00345 },- { 0x01F94 , 0x01F24 , 0x00345 },- { 0x01F95 , 0x01F25 , 0x00345 },- { 0x01F96 , 0x01F26 , 0x00345 },- { 0x01F97 , 0x01F27 , 0x00345 },- { 0x01F98 , 0x01F28 , 0x00345 },- { 0x01F99 , 0x01F29 , 0x00345 },- { 0x01F9A , 0x01F2A , 0x00345 },- { 0x01F9B , 0x01F2B , 0x00345 },- { 0x01F9C , 0x01F2C , 0x00345 },- { 0x01F9D , 0x01F2D , 0x00345 },- { 0x01F9E , 0x01F2E , 0x00345 },- { 0x01F9F , 0x01F2F , 0x00345 },- { 0x01FA0 , 0x01F60 , 0x00345 },- { 0x01FA1 , 0x01F61 , 0x00345 },- { 0x01FA2 , 0x01F62 , 0x00345 },- { 0x01FA3 , 0x01F63 , 0x00345 },- { 0x01FA4 , 0x01F64 , 0x00345 },- { 0x01FA5 , 0x01F65 , 0x00345 },- { 0x01FA6 , 0x01F66 , 0x00345 },- { 0x01FA7 , 0x01F67 , 0x00345 },- { 0x01FA8 , 0x01F68 , 0x00345 },- { 0x01FA9 , 0x01F69 , 0x00345 },- { 0x01FAA , 0x01F6A , 0x00345 },- { 0x01FAB , 0x01F6B , 0x00345 },- { 0x01FAC , 0x01F6C , 0x00345 },- { 0x01FAD , 0x01F6D , 0x00345 },- { 0x01FAE , 0x01F6E , 0x00345 },- { 0x01FAF , 0x01F6F , 0x00345 },- { 0x01FB0 , 0x003B1 , 0x00306 },- { 0x01FB1 , 0x003B1 , 0x00304 },- { 0x01FB2 , 0x01F70 , 0x00345 },- { 0x01FB3 , 0x003B1 , 0x00345 },- { 0x01FB4 , 0x003AC , 0x00345 },- { 0x01FB6 , 0x003B1 , 0x00342 },- { 0x01FB7 , 0x01FB6 , 0x00345 },- { 0x01FB8 , 0x00391 , 0x00306 },- { 0x01FB9 , 0x00391 , 0x00304 },- { 0x01FBA , 0x00391 , 0x00300 },- { 0x01FBC , 0x00391 , 0x00345 },- { 0x01FC1 , 0x000A8 , 0x00342 },- { 0x01FC2 , 0x01F74 , 0x00345 },- { 0x01FC3 , 0x003B7 , 0x00345 },- { 0x01FC4 , 0x003AE , 0x00345 },- { 0x01FC6 , 0x003B7 , 0x00342 },- { 0x01FC7 , 0x01FC6 , 0x00345 },- { 0x01FC8 , 0x00395 , 0x00300 },- { 0x01FCA , 0x00397 , 0x00300 },- { 0x01FCC , 0x00397 , 0x00345 },- { 0x01FCD , 0x01FBF , 0x00300 },- { 0x01FCE , 0x01FBF , 0x00301 },- { 0x01FCF , 0x01FBF , 0x00342 },- { 0x01FD0 , 0x003B9 , 0x00306 },- { 0x01FD1 , 0x003B9 , 0x00304 },- { 0x01FD2 , 0x003CA , 0x00300 },- { 0x01FD6 , 0x003B9 , 0x00342 },- { 0x01FD7 , 0x003CA , 0x00342 },- { 0x01FD8 , 0x00399 , 0x00306 },- { 0x01FD9 , 0x00399 , 0x00304 },- { 0x01FDA , 0x00399 , 0x00300 },- { 0x01FDD , 0x01FFE , 0x00300 },- { 0x01FDE , 0x01FFE , 0x00301 },- { 0x01FDF , 0x01FFE , 0x00342 },- { 0x01FE0 , 0x003C5 , 0x00306 },- { 0x01FE1 , 0x003C5 , 0x00304 },- { 0x01FE2 , 0x003CB , 0x00300 },- { 0x01FE4 , 0x003C1 , 0x00313 },- { 0x01FE5 , 0x003C1 , 0x00314 },- { 0x01FE6 , 0x003C5 , 0x00342 },- { 0x01FE7 , 0x003CB , 0x00342 },- { 0x01FE8 , 0x003A5 , 0x00306 },- { 0x01FE9 , 0x003A5 , 0x00304 },- { 0x01FEA , 0x003A5 , 0x00300 },- { 0x01FEC , 0x003A1 , 0x00314 },- { 0x01FED , 0x000A8 , 0x00300 },- { 0x01FF2 , 0x01F7C , 0x00345 },- { 0x01FF3 , 0x003C9 , 0x00345 },- { 0x01FF4 , 0x003CE , 0x00345 },- { 0x01FF6 , 0x003C9 , 0x00342 },- { 0x01FF7 , 0x01FF6 , 0x00345 },- { 0x01FF8 , 0x0039F , 0x00300 },- { 0x01FFA , 0x003A9 , 0x00300 },- { 0x01FFC , 0x003A9 , 0x00345 },- { 0x0219A , 0x02190 , 0x00338 },- { 0x0219B , 0x02192 , 0x00338 },- { 0x021AE , 0x02194 , 0x00338 },- { 0x021CD , 0x021D0 , 0x00338 },- { 0x021CE , 0x021D4 , 0x00338 },- { 0x021CF , 0x021D2 , 0x00338 },- { 0x02204 , 0x02203 , 0x00338 },- { 0x02209 , 0x02208 , 0x00338 },- { 0x0220C , 0x0220B , 0x00338 },- { 0x02224 , 0x02223 , 0x00338 },- { 0x02226 , 0x02225 , 0x00338 },- { 0x02241 , 0x0223C , 0x00338 },- { 0x02244 , 0x02243 , 0x00338 },- { 0x02247 , 0x02245 , 0x00338 },- { 0x02249 , 0x02248 , 0x00338 },- { 0x02260 , 0x0003D , 0x00338 },- { 0x02262 , 0x02261 , 0x00338 },- { 0x0226D , 0x0224D , 0x00338 },- { 0x0226E , 0x0003C , 0x00338 },- { 0x0226F , 0x0003E , 0x00338 },- { 0x02270 , 0x02264 , 0x00338 },- { 0x02271 , 0x02265 , 0x00338 },- { 0x02274 , 0x02272 , 0x00338 },- { 0x02275 , 0x02273 , 0x00338 },- { 0x02278 , 0x02276 , 0x00338 },- { 0x02279 , 0x02277 , 0x00338 },- { 0x02280 , 0x0227A , 0x00338 },- { 0x02281 , 0x0227B , 0x00338 },- { 0x02284 , 0x02282 , 0x00338 },- { 0x02285 , 0x02283 , 0x00338 },- { 0x02288 , 0x02286 , 0x00338 },- { 0x02289 , 0x02287 , 0x00338 },- { 0x022AC , 0x022A2 , 0x00338 },- { 0x022AD , 0x022A8 , 0x00338 },- { 0x022AE , 0x022A9 , 0x00338 },- { 0x022AF , 0x022AB , 0x00338 },- { 0x022E0 , 0x0227C , 0x00338 },- { 0x022E1 , 0x0227D , 0x00338 },- { 0x022E2 , 0x02291 , 0x00338 },- { 0x022E3 , 0x02292 , 0x00338 },- { 0x022EA , 0x022B2 , 0x00338 },- { 0x022EB , 0x022B3 , 0x00338 },- { 0x022EC , 0x022B4 , 0x00338 },- { 0x022ED , 0x022B5 , 0x00338 },- { 0x0304C , 0x0304B , 0x03099 },- { 0x0304E , 0x0304D , 0x03099 },- { 0x03050 , 0x0304F , 0x03099 },- { 0x03052 , 0x03051 , 0x03099 },- { 0x03054 , 0x03053 , 0x03099 },- { 0x03056 , 0x03055 , 0x03099 },- { 0x03058 , 0x03057 , 0x03099 },- { 0x0305A , 0x03059 , 0x03099 },- { 0x0305C , 0x0305B , 0x03099 },- { 0x0305E , 0x0305D , 0x03099 },- { 0x03060 , 0x0305F , 0x03099 },- { 0x03062 , 0x03061 , 0x03099 },- { 0x03065 , 0x03064 , 0x03099 },- { 0x03067 , 0x03066 , 0x03099 },- { 0x03069 , 0x03068 , 0x03099 },- { 0x03070 , 0x0306F , 0x03099 },- { 0x03071 , 0x0306F , 0x0309A },- { 0x03073 , 0x03072 , 0x03099 },- { 0x03074 , 0x03072 , 0x0309A },- { 0x03076 , 0x03075 , 0x03099 },- { 0x03077 , 0x03075 , 0x0309A },- { 0x03079 , 0x03078 , 0x03099 },- { 0x0307A , 0x03078 , 0x0309A },- { 0x0307C , 0x0307B , 0x03099 },- { 0x0307D , 0x0307B , 0x0309A },- { 0x03094 , 0x03046 , 0x03099 },- { 0x0309E , 0x0309D , 0x03099 },- { 0x030AC , 0x030AB , 0x03099 },- { 0x030AE , 0x030AD , 0x03099 },- { 0x030B0 , 0x030AF , 0x03099 },- { 0x030B2 , 0x030B1 , 0x03099 },- { 0x030B4 , 0x030B3 , 0x03099 },- { 0x030B6 , 0x030B5 , 0x03099 },- { 0x030B8 , 0x030B7 , 0x03099 },- { 0x030BA , 0x030B9 , 0x03099 },- { 0x030BC , 0x030BB , 0x03099 },- { 0x030BE , 0x030BD , 0x03099 },- { 0x030C0 , 0x030BF , 0x03099 },- { 0x030C2 , 0x030C1 , 0x03099 },- { 0x030C5 , 0x030C4 , 0x03099 },- { 0x030C7 , 0x030C6 , 0x03099 },- { 0x030C9 , 0x030C8 , 0x03099 },- { 0x030D0 , 0x030CF , 0x03099 },- { 0x030D1 , 0x030CF , 0x0309A },- { 0x030D3 , 0x030D2 , 0x03099 },- { 0x030D4 , 0x030D2 , 0x0309A },- { 0x030D6 , 0x030D5 , 0x03099 },- { 0x030D7 , 0x030D5 , 0x0309A },- { 0x030D9 , 0x030D8 , 0x03099 },- { 0x030DA , 0x030D8 , 0x0309A },- { 0x030DC , 0x030DB , 0x03099 },- { 0x030DD , 0x030DB , 0x0309A },- { 0x030F4 , 0x030A6 , 0x03099 },- { 0x030F7 , 0x030EF , 0x03099 },- { 0x030F8 , 0x030F0 , 0x03099 },- { 0x030F9 , 0x030F1 , 0x03099 },- { 0x030FA , 0x030F2 , 0x03099 },- { 0x030FE , 0x030FD , 0x03099 },- { 0x1109A , 0x11099 , 0x110BA },- { 0x1109C , 0x1109B , 0x110BA },- { 0x110AB , 0x110A5 , 0x110BA },-};--#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */-
− c/archive_string_sprintf.c
@@ -1,192 +0,0 @@-/*-- * 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_string_sprintf.c 189435 2009-03-06 05:14:55Z kientzle $");--/*- * The use of printf()-family functions can be troublesome- * for space-constrained applications. In addition, correctly- * implementing this function in terms of vsnprintf() requires- * two calls (one to determine the size, another to format the- * result), which in turn requires duplicating the argument list- * using va_copy, which isn't yet universally available. <sigh>- *- * So, I've implemented a bare minimum of printf()-like capability- * here. This is only used to format error messages, so doesn't- * require any floating-point support or field-width handling.- */-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#include <stdio.h>--#include "archive_string.h"-#include "archive_private.h"--/*- * Utility functions to format signed/unsigned integers and append- * them to an archive_string.- */-static void-append_uint(struct archive_string *as, uintmax_t d, unsigned base)-{- static const char digits[] = "0123456789abcdef";- if (d >= base)- append_uint(as, d/base, base);- archive_strappend_char(as, digits[d % base]);-}--static void-append_int(struct archive_string *as, intmax_t d, unsigned base)-{- uintmax_t ud;-- if (d < 0) {- archive_strappend_char(as, '-');- ud = (d == INTMAX_MIN) ? (uintmax_t)(INTMAX_MAX) + 1 : (uintmax_t)(-d);- } else- ud = d;- append_uint(as, ud, base);-}---void-archive_string_sprintf(struct archive_string *as, const char *fmt, ...)-{- va_list ap;-- va_start(ap, fmt);- archive_string_vsprintf(as, fmt, ap);- va_end(ap);-}--/*- * Like 'vsprintf', but ensures the target is big enough, resizing if- * necessary.- */-void-archive_string_vsprintf(struct archive_string *as, const char *fmt,- va_list ap)-{- char long_flag;- intmax_t s; /* Signed integer temp. */- uintmax_t u; /* Unsigned integer temp. */- const char *p, *p2;- const wchar_t *pw;-- if (archive_string_ensure(as, 64) == NULL)- __archive_errx(1, "Out of memory");-- if (fmt == NULL) {- as->s[0] = 0;- return;- }-- for (p = fmt; *p != '\0'; p++) {- const char *saved_p = p;-- if (*p != '%') {- archive_strappend_char(as, *p);- continue;- }-- p++;-- long_flag = '\0';- switch(*p) {- case 'j':- case 'l':- case 'z':- long_flag = *p;- p++;- break;- }-- switch (*p) {- case '%':- archive_strappend_char(as, '%');- break;- case 'c':- s = va_arg(ap, int);- archive_strappend_char(as, (char)s);- break;- case 'd':- switch(long_flag) {- case 'j': s = va_arg(ap, intmax_t); break;- case 'l': s = va_arg(ap, long); break;- case 'z': s = va_arg(ap, ssize_t); break;- default: s = va_arg(ap, int); break;- }- append_int(as, s, 10);- break;- case 's':- switch(long_flag) {- case 'l':- pw = va_arg(ap, wchar_t *);- if (pw == NULL)- pw = L"(null)";- if (archive_string_append_from_wcs(as, pw,- wcslen(pw)) != 0 && errno == ENOMEM)- __archive_errx(1, "Out of memory");- break;- default:- p2 = va_arg(ap, char *);- if (p2 == NULL)- p2 = "(null)";- archive_strcat(as, p2);- break;- }- break;- case 'S':- pw = va_arg(ap, wchar_t *);- if (pw == NULL)- pw = L"(null)";- if (archive_string_append_from_wcs(as, pw,- wcslen(pw)) != 0 && errno == ENOMEM)- __archive_errx(1, "Out of memory");- break;- case 'o': case 'u': case 'x': case 'X':- /* Common handling for unsigned integer formats. */- switch(long_flag) {- case 'j': u = va_arg(ap, uintmax_t); break;- case 'l': u = va_arg(ap, unsigned long); break;- case 'z': u = va_arg(ap, size_t); break;- default: u = va_arg(ap, unsigned int); break;- }- /* Format it in the correct base. */- switch (*p) {- case 'o': append_uint(as, u, 8); break;- case 'u': append_uint(as, u, 10); break;- default: append_uint(as, u, 16); break;- }- break;- default:- /* Rewind and print the initial '%' literally. */- p = saved_p;- archive_strappend_char(as, *p);- }- }-}
− c/archive_util.c
@@ -1,704 +0,0 @@-/*-- * Copyright (c) 2009-2012,2014 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_util.c 201098 2009-12-28 02:58:14Z kientzle $");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.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-#if defined(_WIN32) && !defined(__CYGWIN__)-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA-/* don't use bcrypt when XP needs to be supported */-#include <bcrypt.h>--/* Common in other bcrypt implementations, but missing from VS2008. */-#ifndef BCRYPT_SUCCESS-#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)-#endif--#elif defined(HAVE_WINCRYPT_H)-#include <wincrypt.h>-#endif-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif-#ifdef HAVE_LZMA_H-#include <lzma.h>-#endif-#ifdef HAVE_BZLIB_H-#include <bzlib.h>-#endif-#ifdef HAVE_LZ4_H-#include <lz4.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_random_private.h"-#include "archive_string.h"--#ifndef O_CLOEXEC-#define O_CLOEXEC 0-#endif--static int archive_utility_string_sort_helper(char **, unsigned int);--/* Generic initialization of 'struct archive' objects. */-int-__archive_clean(struct archive *a)-{- archive_string_conversion_free(a);- return (ARCHIVE_OK);-}--int-archive_version_number(void)-{- return (ARCHIVE_VERSION_NUMBER);-}--const char *-archive_version_string(void)-{- return (ARCHIVE_VERSION_STRING);-}--int-archive_errno(struct archive *a)-{- return (a->archive_error_number);-}--const char *-archive_error_string(struct archive *a)-{-- if (a->error != NULL && *a->error != '\0')- return (a->error);- else- return (NULL);-}--int-archive_file_count(struct archive *a)-{- return (a->file_count);-}--int-archive_format(struct archive *a)-{- return (a->archive_format);-}--const char *-archive_format_name(struct archive *a)-{- return (a->archive_format_name);-}---int-archive_compression(struct archive *a)-{- return archive_filter_code(a, 0);-}--const char *-archive_compression_name(struct archive *a)-{- return archive_filter_name(a, 0);-}---/*- * Return a count of the number of compressed bytes processed.- */-la_int64_t-archive_position_compressed(struct archive *a)-{- return archive_filter_bytes(a, -1);-}--/*- * Return a count of the number of uncompressed bytes processed.- */-la_int64_t-archive_position_uncompressed(struct archive *a)-{- return archive_filter_bytes(a, 0);-}--void-archive_clear_error(struct archive *a)-{- archive_string_empty(&a->error_string);- a->error = NULL;- a->archive_error_number = 0;-}--void-archive_set_error(struct archive *a, int error_number, const char *fmt, ...)-{- va_list ap;-- a->archive_error_number = error_number;- if (fmt == NULL) {- a->error = NULL;- return;- }-- archive_string_empty(&(a->error_string));- va_start(ap, fmt);- archive_string_vsprintf(&(a->error_string), fmt, ap);- va_end(ap);- a->error = a->error_string.s;-}--void-archive_copy_error(struct archive *dest, struct archive *src)-{- dest->archive_error_number = src->archive_error_number;-- archive_string_copy(&dest->error_string, &src->error_string);- dest->error = dest->error_string.s;-}--void-__archive_errx(int retvalue, const char *msg)-{- static const char msg1[] = "Fatal Internal Error in libarchive: ";- size_t s;-- s = write(2, msg1, strlen(msg1));- (void)s; /* UNUSED */- s = write(2, msg, strlen(msg));- (void)s; /* UNUSED */- s = write(2, "\n", 1);- (void)s; /* UNUSED */- exit(retvalue);-}--/*- * Create a temporary file- */-#if defined(_WIN32) && !defined(__CYGWIN__)--/*- * Do not use Windows tmpfile() function.- * It will make a temporary file under the root directory- * and it'll cause permission error if a user who is- * non-Administrator creates temporary files.- * Also Windows version of mktemp family including _mktemp_s- * are not secure.- */-static int-__archive_mktempx(const char *tmpdir, wchar_t *template)-{- static const wchar_t prefix[] = L"libarchive_";- static const wchar_t suffix[] = L"XXXXXXXXXX";- static const wchar_t num[] = {- L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',- L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',- L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',- L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',- L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',- L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',- L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',- L'u', L'v', L'w', L'x', L'y', L'z'- };- struct archive_wstring temp_name;- wchar_t *ws;- DWORD attr;- wchar_t *xp, *ep;- int fd;-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- BCRYPT_ALG_HANDLE hAlg = NULL;-#else- HCRYPTPROV hProv = (HCRYPTPROV)NULL;-#endif- fd = -1;- ws = NULL;-- if (template == NULL) {- archive_string_init(&temp_name);-- /* Get a temporary directory. */- if (tmpdir == NULL) {- size_t l;- wchar_t *tmp;-- l = GetTempPathW(0, NULL);- if (l == 0) {- la_dosmaperr(GetLastError());- goto exit_tmpfile;- }- tmp = malloc(l*sizeof(wchar_t));- if (tmp == NULL) {- errno = ENOMEM;- goto exit_tmpfile;- }- GetTempPathW((DWORD)l, tmp);- archive_wstrcpy(&temp_name, tmp);- free(tmp);- } else {- if (archive_wstring_append_from_mbs(&temp_name, tmpdir,- strlen(tmpdir)) < 0)- goto exit_tmpfile;- if (temp_name.s[temp_name.length-1] != L'/')- archive_wstrappend_wchar(&temp_name, L'/');- }-- /* Check if temp_name is a directory. */- attr = GetFileAttributesW(temp_name.s);- if (attr == (DWORD)-1) {- if (GetLastError() != ERROR_FILE_NOT_FOUND) {- la_dosmaperr(GetLastError());- goto exit_tmpfile;- }- ws = __la_win_permissive_name_w(temp_name.s);- if (ws == NULL) {- errno = EINVAL;- goto exit_tmpfile;- }- attr = GetFileAttributesW(ws);- if (attr == (DWORD)-1) {- la_dosmaperr(GetLastError());- goto exit_tmpfile;- }- }- if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {- errno = ENOTDIR;- goto exit_tmpfile;- }-- /*- * Create a temporary file.- */- archive_wstrcat(&temp_name, prefix);- archive_wstrcat(&temp_name, suffix);- ep = temp_name.s + archive_strlen(&temp_name);- xp = ep - wcslen(suffix);- template = temp_name.s;- } else {- xp = wcschr(template, L'X');- if (xp == NULL) /* No X, programming error */- abort();- for (ep = xp; *ep == L'X'; ep++)- continue;- if (*ep) /* X followed by non X, programming error */- abort();- }--#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM,- NULL, 0))) {- la_dosmaperr(GetLastError());- goto exit_tmpfile;- }-#else- if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,- CRYPT_VERIFYCONTEXT)) {- la_dosmaperr(GetLastError());- goto exit_tmpfile;- }-#endif-- for (;;) {- wchar_t *p;- HANDLE h;-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;-#endif-- /* Generate a random file name through CryptGenRandom(). */- p = xp;-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- if (!BCRYPT_SUCCESS(BCryptGenRandom(hAlg, (PUCHAR)p,- (DWORD)(ep - p)*sizeof(wchar_t), 0))) {- la_dosmaperr(GetLastError());- goto exit_tmpfile;- }-#else- if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),- (BYTE*)p)) {- la_dosmaperr(GetLastError());- goto exit_tmpfile;- }-#endif- for (; p < ep; p++)- *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];-- free(ws);- ws = __la_win_permissive_name_w(template);- if (ws == NULL) {- errno = EINVAL;- goto exit_tmpfile;- }- if (template == temp_name.s) {- attr = FILE_ATTRIBUTE_TEMPORARY |- FILE_FLAG_DELETE_ON_CLOSE;- } else {- /* mkstemp */- attr = FILE_ATTRIBUTE_NORMAL;- }-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileAttributes = attr & 0xFFFF;- createExParams.dwFileFlags = attr & 0xFFF00000;- h = CreateFile2(ws,- GENERIC_READ | GENERIC_WRITE | DELETE,- 0,/* Not share */- CREATE_NEW,- &createExParams);-#else- h = CreateFileW(ws,- GENERIC_READ | GENERIC_WRITE | DELETE,- 0,/* Not share */- NULL,- CREATE_NEW,/* Create a new file only */- attr,- NULL);-#endif- if (h == INVALID_HANDLE_VALUE) {- /* The same file already exists. retry with- * a new filename. */- if (GetLastError() == ERROR_FILE_EXISTS)- continue;- /* Otherwise, fail creation temporary file. */- la_dosmaperr(GetLastError());- goto exit_tmpfile;- }- fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);- if (fd == -1) {- la_dosmaperr(GetLastError());- CloseHandle(h);- goto exit_tmpfile;- } else- break;/* success! */- }-exit_tmpfile:-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA- if (hAlg != NULL)- BCryptCloseAlgorithmProvider(hAlg, 0);-#else- if (hProv != (HCRYPTPROV)NULL)- CryptReleaseContext(hProv, 0);-#endif- free(ws);- if (template == temp_name.s)- archive_wstring_free(&temp_name);- return (fd);-}--int-__archive_mktemp(const char *tmpdir)-{- return __archive_mktempx(tmpdir, NULL);-}--int-__archive_mkstemp(wchar_t *template)-{- return __archive_mktempx(NULL, template);-}--#else--static int-get_tempdir(struct archive_string *temppath)-{- const char *tmp;-- tmp = getenv("TMPDIR");- if (tmp == NULL)-#ifdef _PATH_TMP- tmp = _PATH_TMP;-#else- tmp = "/tmp";-#endif- archive_strcpy(temppath, tmp);- if (temppath->s[temppath->length-1] != '/')- archive_strappend_char(temppath, '/');- return (ARCHIVE_OK);-}--#if defined(HAVE_MKSTEMP)--/*- * We can use mkstemp().- */--int-__archive_mktemp(const char *tmpdir)-{- struct archive_string temp_name;- int fd = -1;-- archive_string_init(&temp_name);- if (tmpdir == NULL) {- if (get_tempdir(&temp_name) != ARCHIVE_OK)- goto exit_tmpfile;- } else {- archive_strcpy(&temp_name, tmpdir);- if (temp_name.s[temp_name.length-1] != '/')- archive_strappend_char(&temp_name, '/');- }-#ifdef O_TMPFILE- fd = open(temp_name.s, O_RDWR|O_CLOEXEC|O_TMPFILE|O_EXCL, 0600); - if(fd >= 0)- goto exit_tmpfile;-#endif- archive_strcat(&temp_name, "libarchive_XXXXXX");- fd = mkstemp(temp_name.s);- if (fd < 0)- goto exit_tmpfile;- __archive_ensure_cloexec_flag(fd);- unlink(temp_name.s);-exit_tmpfile:- archive_string_free(&temp_name);- return (fd);-}--int-__archive_mkstemp(char *template)-{- int fd = -1;- fd = mkstemp(template);- if (fd >= 0)- __archive_ensure_cloexec_flag(fd);- return (fd);-}--#else /* !HAVE_MKSTEMP */--/*- * We use a private routine.- */--static int-__archive_mktempx(const char *tmpdir, char *template)-{- static const char num[] = {- '0', '1', '2', '3', '4', '5', '6', '7',- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',- 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',- 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',- 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',- 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',- 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',- 'u', 'v', 'w', 'x', 'y', 'z'- };- struct archive_string temp_name;- struct stat st;- int fd;- char *tp, *ep;-- fd = -1;- if (template == NULL) {- archive_string_init(&temp_name);- if (tmpdir == NULL) {- if (get_tempdir(&temp_name) != ARCHIVE_OK)- goto exit_tmpfile;- } else- archive_strcpy(&temp_name, tmpdir);- if (temp_name.s[temp_name.length-1] == '/') {- temp_name.s[temp_name.length-1] = '\0';- temp_name.length --;- }- if (la_stat(temp_name.s, &st) < 0)- goto exit_tmpfile;- if (!S_ISDIR(st.st_mode)) {- errno = ENOTDIR;- goto exit_tmpfile;- }- archive_strcat(&temp_name, "/libarchive_");- tp = temp_name.s + archive_strlen(&temp_name);- archive_strcat(&temp_name, "XXXXXXXXXX");- ep = temp_name.s + archive_strlen(&temp_name);- template = temp_name.s;- } else {- tp = strchr(template, 'X');- if (tp == NULL) /* No X, programming error */- abort();- for (ep = tp; *ep == 'X'; ep++)- continue;- if (*ep) /* X followed by non X, programming error */- abort();- }-- do {- char *p;-- p = tp;- archive_random(p, ep - p);- while (p < ep) {- int d = *((unsigned char *)p) % sizeof(num);- *p++ = num[d];- }- fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,- 0600);- } while (fd < 0 && errno == EEXIST);- if (fd < 0)- goto exit_tmpfile;- __archive_ensure_cloexec_flag(fd);- if (template == temp_name.s)- unlink(temp_name.s);-exit_tmpfile:- if (template == temp_name.s)- archive_string_free(&temp_name);- return (fd);-}--int-__archive_mktemp(const char *tmpdir)-{- return __archive_mktempx(tmpdir, NULL);-}--int-__archive_mkstemp(char *template)-{- return __archive_mktempx(NULL, template);-}--#endif /* !HAVE_MKSTEMP */-#endif /* !_WIN32 || __CYGWIN__ */--/*- * Set FD_CLOEXEC flag to a file descriptor if it is not set.- * We have to set the flag if the platform does not provide O_CLOEXEC- * or F_DUPFD_CLOEXEC flags.- *- * Note: This function is absolutely called after creating a new file- * descriptor even if the platform seemingly provides O_CLOEXEC or- * F_DUPFD_CLOEXEC macros because it is possible that the platform- * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.- */-void-__archive_ensure_cloexec_flag(int fd)-{-#if defined(_WIN32) && !defined(__CYGWIN__)- (void)fd; /* UNUSED */-#else- int flags;-- if (fd >= 0) {- flags = fcntl(fd, F_GETFD);- if (flags != -1 && (flags & FD_CLOEXEC) == 0)- fcntl(fd, F_SETFD, flags | FD_CLOEXEC);- }-#endif-}--/*- * Utility function to sort a group of strings using quicksort.- */-static int-archive_utility_string_sort_helper(char **strings, unsigned int n)-{- unsigned int i, lesser_count, greater_count;- char **lesser, **greater, **tmp, *pivot;- int retval1, retval2;-- /* A list of 0 or 1 elements is already sorted */- if (n <= 1)- return (ARCHIVE_OK);-- lesser_count = greater_count = 0;- lesser = greater = NULL;- pivot = strings[0];- for (i = 1; i < n; i++)- {- if (strcmp(strings[i], pivot) < 0)- {- lesser_count++;- tmp = (char **)realloc(lesser,- lesser_count * sizeof(char *));- if (!tmp) {- free(greater);- free(lesser);- return (ARCHIVE_FATAL);- }- lesser = tmp;- lesser[lesser_count - 1] = strings[i];- }- else- {- greater_count++;- tmp = (char **)realloc(greater,- greater_count * sizeof(char *));- if (!tmp) {- free(greater);- free(lesser);- return (ARCHIVE_FATAL);- }- greater = tmp;- greater[greater_count - 1] = strings[i];- }- }-- /* quicksort(lesser) */- retval1 = archive_utility_string_sort_helper(lesser, lesser_count);- for (i = 0; i < lesser_count; i++)- strings[i] = lesser[i];- free(lesser);-- /* pivot */- strings[lesser_count] = pivot;-- /* quicksort(greater) */- retval2 = archive_utility_string_sort_helper(greater, greater_count);- for (i = 0; i < greater_count; i++)- strings[lesser_count + 1 + i] = greater[i];- free(greater);-- return (retval1 < retval2) ? retval1 : retval2;-}--int-archive_utility_string_sort(char **strings)-{- unsigned int size = 0;- while (strings[size] != NULL)- size++;- return archive_utility_string_sort_helper(strings, size);-}
− c/archive_version_details.c
@@ -1,151 +0,0 @@-/*-- * Copyright (c) 2009-2012,2014 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_util.c 201098 2009-12-28 02:58:14Z kientzle $");--#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif-#ifdef HAVE_LZMA_H-#include <lzma.h>-#endif-#ifdef HAVE_BZLIB_H-#include <bzlib.h>-#endif-#ifdef HAVE_LZ4_H-#include <lz4.h>-#endif-#ifdef HAVE_ZSTD_H-#include <zstd.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_string.h"--const char *-archive_version_details(void)-{- static struct archive_string str;- static int init = 0;- const char *zlib = archive_zlib_version();- const char *liblzma = archive_liblzma_version();- const char *bzlib = archive_bzlib_version();- const char *liblz4 = archive_liblz4_version();- const char *libzstd = archive_libzstd_version();-- if (!init) {- archive_string_init(&str);-- archive_strcat(&str, ARCHIVE_VERSION_STRING);- if (zlib != NULL) {- archive_strcat(&str, " zlib/");- archive_strcat(&str, zlib);- }- if (liblzma) {- archive_strcat(&str, " liblzma/");- archive_strcat(&str, liblzma);- }- if (bzlib) {- const char *p = bzlib;- const char *sep = strchr(p, ',');- if (sep == NULL)- sep = p + strlen(p);- archive_strcat(&str, " bz2lib/");- archive_strncat(&str, p, sep - p);- }- if (liblz4) {- archive_strcat(&str, " liblz4/");- archive_strcat(&str, liblz4);- }- if (libzstd) {- archive_strcat(&str, " libzstd/");- archive_strcat(&str, libzstd);- }- }- return str.s;-}--const char *-archive_zlib_version(void)-{-#ifdef HAVE_ZLIB_H- return ZLIB_VERSION;-#else- return NULL;-#endif-}--const char *-archive_liblzma_version(void)-{-#ifdef HAVE_LZMA_H- return LZMA_VERSION_STRING;-#else- return NULL;-#endif-}--const char *-archive_bzlib_version(void)-{-#ifdef HAVE_BZLIB_H- return BZ2_bzlibVersion();-#else- return NULL;-#endif-}--const char *-archive_liblz4_version(void)-{-#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4)-#define str(s) #s-#define NUMBER(x) str(x)- return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE);-#undef NUMBER-#undef str-#else- return NULL;-#endif-}--const char *-archive_libzstd_version(void)-{-#if HAVE_ZSTD_H && HAVE_LIBZSTD- return ZSTD_VERSION_STRING;-#else- return NULL;-#endif-}
− c/archive_virtual.c
@@ -1,163 +0,0 @@-/*-- * 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_virtual.c 201098 2009-12-28 02:58:14Z kientzle $");--#include "archive.h"-#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));-}--la_int64_t-archive_filter_bytes(struct archive *a, int n)-{- return ((a->vtable->archive_filter_bytes)(a, n));-}--int-archive_free(struct archive *a)-{- if (a == NULL)- return (ARCHIVE_OK);- return ((a->vtable->archive_free)(a));-}--int-archive_write_close(struct archive *a)-{- return ((a->vtable->archive_close)(a));-}--int-archive_read_close(struct archive *a)-{- return ((a->vtable->archive_close)(a));-}--int-archive_write_fail(struct archive *a)-{- a->state = ARCHIVE_STATE_FATAL;- return a->state;-}--int-archive_write_free(struct archive *a)-{- return archive_free(a);-}--#if ARCHIVE_VERSION_NUMBER < 4000000-/* For backwards compatibility; will be removed with libarchive 4.0. */-int-archive_write_finish(struct archive *a)-{- return archive_write_free(a);-}-#endif--int-archive_read_free(struct archive *a)-{- return archive_free(a);-}--#if ARCHIVE_VERSION_NUMBER < 4000000-/* For backwards compatibility; will be removed with libarchive 4.0. */-int-archive_read_finish(struct archive *a)-{- return archive_read_free(a);-}-#endif--int-archive_write_header(struct archive *a, struct archive_entry *entry)-{- ++a->file_count;- return ((a->vtable->archive_write_header)(a, entry));-}--int-archive_write_finish_entry(struct archive *a)-{- return ((a->vtable->archive_write_finish_entry)(a));-}--la_ssize_t-archive_write_data(struct archive *a, const void *buff, size_t s)-{- return ((a->vtable->archive_write_data)(a, buff, s));-}--la_ssize_t-archive_write_data_block(struct archive *a, const void *buff, size_t s,- la_int64_t o)-{- if (a->vtable->archive_write_data_block == NULL) {- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "archive_write_data_block not supported");- a->state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- return ((a->vtable->archive_write_data_block)(a, buff, s, o));-}--int-archive_read_next_header(struct archive *a, struct archive_entry **entry)-{- return ((a->vtable->archive_read_next_header)(a, entry));-}--int-archive_read_next_header2(struct archive *a, struct archive_entry *entry)-{- return ((a->vtable->archive_read_next_header2)(a, entry));-}--int-archive_read_data_block(struct archive *a,- const void **buff, size_t *s, la_int64_t *o)-{- return ((a->vtable->archive_read_data_block)(a, buff, s, o));-}
− c/archive_windows.c
@@ -1,938 +0,0 @@-/*-- * Copyright (c) 2009-2011 Michihiro NAKAJIMA- * Copyright (c) 2003-2007 Kees Zeelenberg- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- */--/*- * A set of compatibility glue for building libarchive on Windows platforms.- *- * Originally created as "libarchive-nonposix.c" by Kees Zeelenberg- * for the GnuWin32 project, trimmed significantly by Tim Kientzle.- *- * Much of the original file was unnecessary for libarchive, because- * many of the features it emulated were not strictly necessary for- * libarchive. I hope for this to shrink further as libarchive- * internals are gradually reworked to sit more naturally on both- * POSIX and Windows. Any ideas for this are greatly appreciated.- *- * The biggest remaining issue is the dev/ino emulation; libarchive- * has a couple of public APIs that rely on dev/ino uniquely- * identifying a file. This doesn't match well with Windows. I'm- * considering alternative APIs.- */--#if defined(_WIN32) && !defined(__CYGWIN__)--#include "archive_platform.h"-#include "archive_private.h"-#include "archive_entry.h"-#include <ctype.h>-#include <errno.h>-#include <stddef.h>-#ifdef HAVE_SYS_UTIME_H-#include <sys/utime.h>-#endif-#include <sys/stat.h>-#include <locale.h>-#include <process.h>-#include <stdlib.h>-#include <wchar.h>-#include <windows.h>-#include <share.h>--#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)--#if defined(__LA_LSEEK_NEEDED)-static BOOL SetFilePointerEx_perso(HANDLE hFile,- LARGE_INTEGER liDistanceToMove,- PLARGE_INTEGER lpNewFilePointer,- DWORD dwMoveMethod)-{- LARGE_INTEGER li;- li.QuadPart = liDistanceToMove.QuadPart;- li.LowPart = SetFilePointer(- hFile, li.LowPart, &li.HighPart, dwMoveMethod);- if(lpNewFilePointer) {- lpNewFilePointer->QuadPart = li.QuadPart;- }- return li.LowPart != -1 || GetLastError() == NO_ERROR;-}-#endif--struct ustat {- int64_t st_atime;- uint32_t st_atime_nsec;- int64_t st_ctime;- uint32_t st_ctime_nsec;- int64_t st_mtime;- uint32_t st_mtime_nsec;- gid_t st_gid;- /* 64bits ino */- int64_t st_ino;- mode_t st_mode;- uint32_t st_nlink;- uint64_t st_size;- uid_t st_uid;- dev_t st_dev;- dev_t st_rdev;-};--/* Transform 64-bits ino into 32-bits by hashing.- * You do not forget that really unique number size is 64-bits.- */-#define INOSIZE (8*sizeof(ino_t)) /* 32 */-static __inline ino_t-getino(struct ustat *ub)-{- ULARGE_INTEGER ino64;- ino64.QuadPart = ub->st_ino;- /* I don't know this hashing is correct way */- return ((ino_t)(ino64.LowPart ^ (ino64.LowPart >> INOSIZE)));-}--/*- * Prepend "\\?\" to the path name and convert it to unicode to permit- * an extended-length path for a maximum total path length of 32767- * characters.- * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx- */-wchar_t *-__la_win_permissive_name(const char *name)-{- wchar_t *wn;- wchar_t *ws;- size_t ll;-- ll = strlen(name);- wn = malloc((ll + 1) * sizeof(wchar_t));- if (wn == NULL)- return (NULL);- ll = mbstowcs(wn, name, ll);- if (ll == (size_t)-1) {- free(wn);- return (NULL);- }- wn[ll] = L'\0';- ws = __la_win_permissive_name_w(wn);- free(wn);- return (ws);-}--wchar_t *-__la_win_permissive_name_w(const wchar_t *wname)-{- wchar_t *wn, *wnp;- wchar_t *ws, *wsp;- DWORD l, len, slen;- int unc;-- /* Get a full-pathname. */- l = GetFullPathNameW(wname, 0, NULL, NULL);- if (l == 0)- return (NULL);- /* NOTE: GetFullPathNameW has a bug that if the length of the file- * name is just 1 then it returns incomplete buffer size. Thus, we- * have to add three to the size to allocate a sufficient buffer- * size for the full-pathname of the file name. */- l += 3;- wnp = malloc(l * sizeof(wchar_t));- if (wnp == NULL)- return (NULL);- len = GetFullPathNameW(wname, l, wnp, NULL);- wn = wnp;-- if (wnp[0] == L'\\' && wnp[1] == L'\\' &&- wnp[2] == L'?' && wnp[3] == L'\\')- /* We have already a permissive name. */- return (wn);-- if (wnp[0] == L'\\' && wnp[1] == L'\\' &&- wnp[2] == L'.' && wnp[3] == L'\\') {- /* This is a device name */- if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||- (wnp[4] >= L'A' && wnp[4] <= L'Z')) &&- wnp[5] == L':' && wnp[6] == L'\\')- wnp[2] = L'?';/* Not device name. */- return (wn);- }-- unc = 0;- if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {- wchar_t *p = &wnp[2];-- /* Skip server-name letters. */- while (*p != L'\\' && *p != L'\0')- ++p;- if (*p == L'\\') {- wchar_t *rp = ++p;- /* Skip share-name letters. */- while (*p != L'\\' && *p != L'\0')- ++p;- if (*p == L'\\' && p != rp) {- /* Now, match patterns such as- * "\\server-name\share-name\" */- wnp += 2;- len -= 2;- unc = 1;- }- }- }-- slen = 4 + (unc * 4) + len + 1;- ws = wsp = malloc(slen * sizeof(wchar_t));- if (ws == NULL) {- free(wn);- return (NULL);- }- /* prepend "\\?\" */- wcsncpy(wsp, L"\\\\?\\", 4);- wsp += 4;- slen -= 4;- if (unc) {- /* append "UNC\" ---> "\\?\UNC\" */- wcsncpy(wsp, L"UNC\\", 4);- wsp += 4;- slen -= 4;- }- wcsncpy(wsp, wnp, slen);- wsp[slen - 1] = L'\0'; /* Ensure null termination. */- free(wn);- return (ws);-}--/*- * Create a file handle.- * This can exceed MAX_PATH limitation.- */-static HANDLE-la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,- LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,- DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)-{- wchar_t *wpath;- HANDLE handle;-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;-#endif--#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)- handle = CreateFileA(path, dwDesiredAccess, dwShareMode,- lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,- hTemplateFile);- if (handle != INVALID_HANDLE_VALUE)- return (handle);- if (GetLastError() != ERROR_PATH_NOT_FOUND)- return (handle);-#endif- wpath = __la_win_permissive_name(path);- if (wpath == NULL)- return INVALID_HANDLE_VALUE;-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileAttributes = dwFlagsAndAttributes & 0xFFFF;- createExParams.dwFileFlags = dwFlagsAndAttributes & 0xFFF00000;- createExParams.dwSecurityQosFlags = dwFlagsAndAttributes & 0x000F00000;- createExParams.lpSecurityAttributes = lpSecurityAttributes;- createExParams.hTemplateFile = hTemplateFile;- handle = CreateFile2(wpath, dwDesiredAccess, dwShareMode,- dwCreationDisposition, &createExParams);-#else /* !WINAPI_PARTITION_DESKTOP */- handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode,- lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,- hTemplateFile);-#endif /* !WINAPI_PARTITION_DESKTOP */- free(wpath);- return (handle);-}--#if defined(__LA_LSEEK_NEEDED)-__int64-__la_lseek(int fd, __int64 offset, int whence)-{- LARGE_INTEGER distance;- LARGE_INTEGER newpointer;- HANDLE handle;-- if (fd < 0) {- errno = EBADF;- return (-1);- }- handle = (HANDLE)_get_osfhandle(fd);- if (GetFileType(handle) != FILE_TYPE_DISK) {- errno = EBADF;- return (-1);- }- distance.QuadPart = offset;- if (!SetFilePointerEx_perso(handle, distance, &newpointer, whence)) {- DWORD lasterr;-- lasterr = GetLastError();- if (lasterr == ERROR_BROKEN_PIPE)- return (0);- if (lasterr == ERROR_ACCESS_DENIED)- errno = EBADF;- else- la_dosmaperr(lasterr);- return (-1);- }- return (newpointer.QuadPart);-}-#endif--/* This can exceed MAX_PATH limitation. */-int-__la_open(const char *path, int flags, ...)-{- va_list ap;- wchar_t *ws;- int r, pmode;- DWORD attr;-- va_start(ap, flags);- pmode = va_arg(ap, int);- va_end(ap);- ws = NULL;- if ((flags & ~O_BINARY) == O_RDONLY) {- /*- * When we open a directory, _open function returns- * "Permission denied" error.- */- attr = GetFileAttributesA(path);-#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)- if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND)-#endif- {- ws = __la_win_permissive_name(path);- if (ws == NULL) {- errno = EINVAL;- return (-1);- }- attr = GetFileAttributesW(ws);- }- if (attr == (DWORD)-1) {- la_dosmaperr(GetLastError());- free(ws);- return (-1);- }- if (attr & FILE_ATTRIBUTE_DIRECTORY) {- HANDLE handle;-#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)- if (ws != NULL)- handle = CreateFileW(ws, 0, 0, NULL,- OPEN_EXISTING,- FILE_FLAG_BACKUP_SEMANTICS |- FILE_ATTRIBUTE_READONLY,- NULL);- else- handle = CreateFileA(path, 0, 0, NULL,- OPEN_EXISTING,- FILE_FLAG_BACKUP_SEMANTICS |- FILE_ATTRIBUTE_READONLY,- NULL);-#else /* !WINAPI_PARTITION_DESKTOP */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileAttributes = FILE_ATTRIBUTE_READONLY;- createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;- handle = CreateFile2(ws, 0, 0,- OPEN_EXISTING, &createExParams);-#endif /* !WINAPI_PARTITION_DESKTOP */- free(ws);- if (handle == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- return (-1);- }- r = _open_osfhandle((intptr_t)handle, _O_RDONLY);- return (r);- }- }- if (ws == NULL) {-#if defined(__BORLANDC__)- /* Borland has no mode argument.- TODO: Fix mode of new file. */- r = _open(path, flags);-#else- r = _open(path, flags, pmode);-#endif- if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {- /* Simulate other POSIX system action to pass our test suite. */- attr = GetFileAttributesA(path);- if (attr == (DWORD)-1)- la_dosmaperr(GetLastError());- else if (attr & FILE_ATTRIBUTE_DIRECTORY)- errno = EISDIR;- else- errno = EACCES;- return (-1);- }- if (r >= 0 || errno != ENOENT)- return (r);- ws = __la_win_permissive_name(path);- if (ws == NULL) {- errno = EINVAL;- return (-1);- }- }- r = _wopen(ws, flags, pmode);- if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {- /* Simulate other POSIX system action to pass our test suite. */- attr = GetFileAttributesW(ws);- if (attr == (DWORD)-1)- la_dosmaperr(GetLastError());- else if (attr & FILE_ATTRIBUTE_DIRECTORY)- errno = EISDIR;- else- errno = EACCES;- }- free(ws);- return (r);-}--ssize_t-__la_read(int fd, void *buf, size_t nbytes)-{- HANDLE handle;- DWORD bytes_read, lasterr;- int r;--#ifdef _WIN64- if (nbytes > UINT32_MAX)- nbytes = UINT32_MAX;-#endif- if (fd < 0) {- errno = EBADF;- return (-1);- }- /* Do not pass 0 to third parameter of ReadFile(), read bytes.- * This will not return to application side. */- if (nbytes == 0)- return (0);- handle = (HANDLE)_get_osfhandle(fd);- r = ReadFile(handle, buf, (uint32_t)nbytes,- &bytes_read, NULL);- if (r == 0) {- lasterr = GetLastError();- if (lasterr == ERROR_NO_DATA) {- errno = EAGAIN;- return (-1);- }- if (lasterr == ERROR_BROKEN_PIPE)- return (0);- if (lasterr == ERROR_ACCESS_DENIED)- errno = EBADF;- else- la_dosmaperr(lasterr);- return (-1);- }- return ((ssize_t)bytes_read);-}--/* Convert Windows FILETIME to UTC */-__inline static void-fileTimeToUTC(const FILETIME *filetime, time_t *t, long *ns)-{- ULARGE_INTEGER utc;-- utc.HighPart = filetime->dwHighDateTime;- utc.LowPart = filetime->dwLowDateTime;- if (utc.QuadPart >= EPOC_TIME) {- utc.QuadPart -= EPOC_TIME;- *t = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */- *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */- } else {- *t = 0;- *ns = 0;- }-}--/* Stat by handle- * Windows' stat() does not accept the path added "\\?\" especially "?"- * character.- * It means we cannot access the long name path longer than MAX_PATH.- * So I've implemented a function similar to Windows' stat() to access the- * long name path.- * And I've added some feature.- * 1. set st_ino by nFileIndexHigh and nFileIndexLow of- * BY_HANDLE_FILE_INFORMATION.- * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION.- * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION.- */-static int-__hstat(HANDLE handle, struct ustat *st)-{- BY_HANDLE_FILE_INFORMATION info;- ULARGE_INTEGER ino64;- DWORD ftype;- mode_t mode;- time_t t;- long ns;-- switch (ftype = GetFileType(handle)) {- case FILE_TYPE_UNKNOWN:- errno = EBADF;- return (-1);- case FILE_TYPE_CHAR:- case FILE_TYPE_PIPE:- if (ftype == FILE_TYPE_CHAR) {- st->st_mode = S_IFCHR;- st->st_size = 0;- } else {- DWORD avail;-- st->st_mode = S_IFIFO;- if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL))- st->st_size = avail;- else- st->st_size = 0;- }- st->st_atime = 0;- st->st_atime_nsec = 0;- st->st_mtime = 0;- st->st_mtime_nsec = 0;- st->st_ctime = 0;- st->st_ctime_nsec = 0;- st->st_ino = 0;- st->st_nlink = 1;- st->st_uid = 0;- st->st_gid = 0;- st->st_rdev = 0;- st->st_dev = 0;- return (0);- case FILE_TYPE_DISK:- break;- default:- /* This ftype is undocumented type. */- la_dosmaperr(GetLastError());- return (-1);- }-- ZeroMemory(&info, sizeof(info));- if (!GetFileInformationByHandle (handle, &info)) {- la_dosmaperr(GetLastError());- return (-1);- }-- mode = S_IRUSR | S_IRGRP | S_IROTH;- if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)- mode |= S_IWUSR | S_IWGRP | S_IWOTH;- if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)- mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;- else- mode |= S_IFREG;- st->st_mode = mode;-- fileTimeToUTC(&info.ftLastAccessTime, &t, &ns);- st->st_atime = t;- st->st_atime_nsec = ns;- fileTimeToUTC(&info.ftLastWriteTime, &t, &ns);- st->st_mtime = t;- st->st_mtime_nsec = ns;- fileTimeToUTC(&info.ftCreationTime, &t, &ns);- st->st_ctime = t;- st->st_ctime_nsec = ns;- st->st_size =- ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))- + (int64_t)(info.nFileSizeLow);-#ifdef SIMULATE_WIN_STAT- st->st_ino = 0;- st->st_nlink = 1;- st->st_dev = 0;-#else- /* Getting FileIndex as i-node. We should remove a sequence which- * is high-16-bits of nFileIndexHigh. */- ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL;- ino64.LowPart = info.nFileIndexLow;- st->st_ino = ino64.QuadPart;- st->st_nlink = info.nNumberOfLinks;- if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)- ++st->st_nlink;/* Add parent directory. */- st->st_dev = info.dwVolumeSerialNumber;-#endif- st->st_uid = 0;- st->st_gid = 0;- st->st_rdev = 0;- return (0);-}--static void-copy_stat(struct stat *st, struct ustat *us)-{- st->st_atime = us->st_atime;- st->st_ctime = us->st_ctime;- st->st_mtime = us->st_mtime;- st->st_gid = us->st_gid;- st->st_ino = getino(us);- st->st_mode = us->st_mode;- st->st_nlink = us->st_nlink;- st->st_size = (off_t)us->st_size;- st->st_uid = us->st_uid;- st->st_dev = us->st_dev;- st->st_rdev = us->st_rdev;-}--/*- * TODO: Remove a use of __la_fstat and __la_stat.- * We should use GetFileInformationByHandle in place- * where We still use the *stat functions.- */-int-__la_fstat(int fd, struct stat *st)-{- struct ustat u;- int ret;-- if (fd < 0) {- errno = EBADF;- return (-1);- }- ret = __hstat((HANDLE)_get_osfhandle(fd), &u);- if (ret >= 0) {- copy_stat(st, &u);- if (u.st_mode & (S_IFCHR | S_IFIFO)) {- st->st_dev = fd;- st->st_rdev = fd;- }- }- return (ret);-}--/* This can exceed MAX_PATH limitation. */-int-__la_stat(const char *path, struct stat *st)-{- HANDLE handle;- struct ustat u;- int ret;-- handle = la_CreateFile(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,- FILE_FLAG_BACKUP_SEMANTICS,- NULL);- if (handle == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- return (-1);- }- ret = __hstat(handle, &u);- CloseHandle(handle);- if (ret >= 0) {- char *p;-- copy_stat(st, &u);- p = strrchr(path, '.');- if (p != NULL && strlen(p) == 4) {- char exttype[4];-- ++ p;- exttype[0] = toupper(*p++);- exttype[1] = toupper(*p++);- exttype[2] = toupper(*p++);- exttype[3] = '\0';- if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") ||- !strcmp(exttype, "BAT") || !strcmp(exttype, "COM"))- st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;- }- }- return (ret);-}--/*- * This waitpid is limited implementation.- */-pid_t-__la_waitpid(HANDLE child, int *status, int option)-{- DWORD cs;-- (void)option;/* UNUSED */- do {- if (GetExitCodeProcess(child, &cs) == 0) {- CloseHandle(child);- la_dosmaperr(GetLastError());- *status = 0;- return (-1);- }- } while (cs == STILL_ACTIVE);-- *status = (int)(cs & 0xff);- return (0);-}--ssize_t-__la_write(int fd, const void *buf, size_t nbytes)-{- DWORD bytes_written;--#ifdef _WIN64- if (nbytes > UINT32_MAX)- nbytes = UINT32_MAX;-#endif- if (fd < 0) {- errno = EBADF;- return (-1);- }- if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes,- &bytes_written, NULL)) {- DWORD lasterr;-- lasterr = GetLastError();- if (lasterr == ERROR_ACCESS_DENIED)- errno = EBADF;- else- la_dosmaperr(lasterr);- return (-1);- }- return (bytes_written);-}--/*- * Replace the Windows path separator '\' with '/'.- */-static int-replace_pathseparator(struct archive_wstring *ws, const wchar_t *wp)-{- wchar_t *w;- size_t path_length;-- if (wp == NULL)- return(0);- if (wcschr(wp, L'\\') == NULL)- return(0);- path_length = wcslen(wp);- if (archive_wstring_ensure(ws, path_length) == NULL)- return(-1);- archive_wstrncpy(ws, wp, path_length);- for (w = ws->s; *w; w++) {- if (*w == L'\\')- *w = L'/';- }- return(1);-}--static int-fix_pathseparator(struct archive_entry *entry)-{- struct archive_wstring ws;- const wchar_t *wp;- int ret = ARCHIVE_OK;-- archive_string_init(&ws);- wp = archive_entry_pathname_w(entry);- switch (replace_pathseparator(&ws, wp)) {- case 0: /* Not replaced. */- break;- case 1: /* Replaced. */- archive_entry_copy_pathname_w(entry, ws.s);- break;- default:- ret = ARCHIVE_FAILED;- }- wp = archive_entry_hardlink_w(entry);- switch (replace_pathseparator(&ws, wp)) {- case 0: /* Not replaced. */- break;- case 1: /* Replaced. */- archive_entry_copy_hardlink_w(entry, ws.s);- break;- default:- ret = ARCHIVE_FAILED;- }- wp = archive_entry_symlink_w(entry);- switch (replace_pathseparator(&ws, wp)) {- case 0: /* Not replaced. */- break;- case 1: /* Replaced. */- archive_entry_copy_symlink_w(entry, ws.s);- break;- default:- ret = ARCHIVE_FAILED;- }- archive_wstring_free(&ws);- return(ret);-}--struct archive_entry *-__la_win_entry_in_posix_pathseparator(struct archive_entry *entry)-{- struct archive_entry *entry_main;- const wchar_t *wp;- int has_backslash = 0;- int ret;-- wp = archive_entry_pathname_w(entry);- if (wp != NULL && wcschr(wp, L'\\') != NULL)- has_backslash = 1;- if (!has_backslash) {- wp = archive_entry_hardlink_w(entry);- if (wp != NULL && wcschr(wp, L'\\') != NULL)- has_backslash = 1;- }- if (!has_backslash) {- wp = archive_entry_symlink_w(entry);- if (wp != NULL && wcschr(wp, L'\\') != NULL)- has_backslash = 1;- }- /*- * If there is no backslash chars, return the original.- */- if (!has_backslash)- return (entry);-- /* Copy entry so we can modify it as needed. */- entry_main = archive_entry_clone(entry);- if (entry_main == NULL)- return (NULL);- /* Replace the Windows path-separator '\' with '/'. */- ret = fix_pathseparator(entry_main);- if (ret < ARCHIVE_WARN) {- archive_entry_free(entry_main);- return (NULL);- }- return (entry_main);-}---/*- * The following function was modified from PostgreSQL sources and is- * subject to the copyright below.- */-/*-------------------------------------------------------------------------- *- * win32error.c- * Map win32 error codes to errno values- *- * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group- *- * IDENTIFICATION- * $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $- *- *-------------------------------------------------------------------------- */-/*-PostgreSQL Database Management System-(formerly known as Postgres, then as Postgres95)--Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group--Portions Copyright (c) 1994, The Regents of the University of California--Permission to use, copy, modify, and distribute this software and its-documentation for any purpose, without fee, and without a written agreement-is hereby granted, provided that the above copyright notice and this-paragraph and the following two paragraphs appear in all copies.--IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR-DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING-LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS-DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE-POSSIBILITY OF SUCH DAMAGE.--THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY-AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS-ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO-PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.-*/--static const struct {- DWORD winerr;- int doserr;-} doserrors[] =-{- { ERROR_INVALID_FUNCTION, EINVAL },- { ERROR_FILE_NOT_FOUND, ENOENT },- { ERROR_PATH_NOT_FOUND, ENOENT },- { ERROR_TOO_MANY_OPEN_FILES, EMFILE },- { ERROR_ACCESS_DENIED, EACCES },- { ERROR_INVALID_HANDLE, EBADF },- { ERROR_ARENA_TRASHED, ENOMEM },- { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },- { ERROR_INVALID_BLOCK, ENOMEM },- { ERROR_BAD_ENVIRONMENT, E2BIG },- { ERROR_BAD_FORMAT, ENOEXEC },- { ERROR_INVALID_ACCESS, EINVAL },- { ERROR_INVALID_DATA, EINVAL },- { ERROR_INVALID_DRIVE, ENOENT },- { ERROR_CURRENT_DIRECTORY, EACCES },- { ERROR_NOT_SAME_DEVICE, EXDEV },- { ERROR_NO_MORE_FILES, ENOENT },- { ERROR_LOCK_VIOLATION, EACCES },- { ERROR_SHARING_VIOLATION, EACCES },- { ERROR_BAD_NETPATH, ENOENT },- { ERROR_NETWORK_ACCESS_DENIED, EACCES },- { ERROR_BAD_NET_NAME, ENOENT },- { ERROR_FILE_EXISTS, EEXIST },- { ERROR_CANNOT_MAKE, EACCES },- { ERROR_FAIL_I24, EACCES },- { ERROR_INVALID_PARAMETER, EINVAL },- { ERROR_NO_PROC_SLOTS, EAGAIN },- { ERROR_DRIVE_LOCKED, EACCES },- { ERROR_BROKEN_PIPE, EPIPE },- { ERROR_DISK_FULL, ENOSPC },- { ERROR_INVALID_TARGET_HANDLE, EBADF },- { ERROR_INVALID_HANDLE, EINVAL },- { ERROR_WAIT_NO_CHILDREN, ECHILD },- { ERROR_CHILD_NOT_COMPLETE, ECHILD },- { ERROR_DIRECT_ACCESS_HANDLE, EBADF },- { ERROR_NEGATIVE_SEEK, EINVAL },- { ERROR_SEEK_ON_DEVICE, EACCES },- { ERROR_DIR_NOT_EMPTY, ENOTEMPTY },- { ERROR_NOT_LOCKED, EACCES },- { ERROR_BAD_PATHNAME, ENOENT },- { ERROR_MAX_THRDS_REACHED, EAGAIN },- { ERROR_LOCK_FAILED, EACCES },- { ERROR_ALREADY_EXISTS, EEXIST },- { ERROR_FILENAME_EXCED_RANGE, ENOENT },- { ERROR_NESTING_NOT_ALLOWED, EAGAIN },- { ERROR_NOT_ENOUGH_QUOTA, ENOMEM }-};--void-__la_dosmaperr(unsigned long e)-{- int i;-- if (e == 0)- {- errno = 0;- return;- }-- for (i = 0; i < (int)(sizeof(doserrors)/sizeof(doserrors[0])); i++)- {- if (doserrors[i].winerr == e)- {- errno = doserrors[i].doserr;- return;- }- }-- /* fprintf(stderr, "unrecognized win32 error code: %lu", e); */- errno = EINVAL;- return;-}--#endif /* _WIN32 && !__CYGWIN__ */
− c/archive_windows.h
@@ -1,315 +0,0 @@-/*-- * Copyright (c) 2009-2011 Michihiro NAKAJIMA- * Copyright (c) 2003-2006 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- */--/*- * TODO: A lot of stuff in here isn't actually used by libarchive and- * can be trimmed out. Note that this file is used by libarchive and- * libarchive_test but nowhere else. (But note that it gets compiled- * with many different Windows environments, including MinGW, Visual- * Studio, and Cygwin. Significant changes should be tested in all three.)- */--/*- * TODO: Don't use off_t in here. Use __int64 instead. Note that- * Visual Studio and the Windows SDK define off_t as 32 bits; Win32's- * more modern file handling APIs all use __int64 instead of off_t.- */--#ifndef LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED-#define LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--/* Start of configuration for native Win32 */-#ifndef MINGW_HAS_SECURE_API-#define MINGW_HAS_SECURE_API 1-#endif--#include <errno.h>-#define set_errno(val) ((errno)=val)-#include <io.h>-#include <stdlib.h> //brings in NULL-#if defined(HAVE_STDINT_H)-#include <stdint.h>-#endif-#include <stdio.h>-#include <fcntl.h>-#include <sys/stat.h>-#include <process.h>-#include <direct.h>-#if defined(__MINGW32__) && defined(HAVE_UNISTD_H)-/* Prevent build error from a type mismatch of ftruncate().- * This unistd.h defines it as ftruncate(int, off_t). */-#include <unistd.h>-#endif-#define NOCRYPT-#include <windows.h>-//#define EFTYPE 7--#if defined(__BORLANDC__)-#pragma warn -8068 /* Constant out of range in comparison. */-#pragma warn -8072 /* Suspicious pointer arithmetic. */-#endif--#ifndef NULL-#ifdef __cplusplus-#define NULL 0-#else-#define NULL ((void *)0)-#endif-#endif--/* Alias the Windows _function to the POSIX equivalent. */-#define close _close-#define fcntl(fd, cmd, flg) /* No operation. */-#ifndef fileno-#define fileno _fileno-#endif-#ifdef fstat-#undef fstat-#endif-#define fstat __la_fstat-#if !defined(__BORLANDC__)-#ifdef lseek-#undef lseek-#endif-#define lseek _lseeki64-#else-#define lseek __la_lseek-#define __LA_LSEEK_NEEDED-#endif-#define lstat __la_stat-#define open __la_open-#define read __la_read-#if !defined(__BORLANDC__) && !defined(__WATCOMC__)-#define setmode _setmode-#endif-#define la_stat(path,stref) __la_stat(path,stref)-#if !defined(__WATCOMC__)-#if !defined(__BORLANDC__)-#define strdup _strdup-#endif-#define tzset _tzset-#if !defined(__BORLANDC__)-#define umask _umask-#endif-#endif-#define waitpid __la_waitpid-#define write __la_write--#if !defined(__WATCOMC__)--#ifndef O_RDONLY-#define O_RDONLY _O_RDONLY-#define O_WRONLY _O_WRONLY-#define O_TRUNC _O_TRUNC-#define O_CREAT _O_CREAT-#define O_EXCL _O_EXCL-#define O_BINARY _O_BINARY-#endif--#ifndef _S_IFIFO- #define _S_IFIFO 0010000 /* pipe */-#endif-#ifndef _S_IFCHR- #define _S_IFCHR 0020000 /* character special */-#endif-#ifndef _S_IFDIR- #define _S_IFDIR 0040000 /* directory */-#endif-#ifndef _S_IFBLK- #define _S_IFBLK 0060000 /* block special */-#endif-#ifndef _S_IFLNK- #define _S_IFLNK 0120000 /* symbolic link */-#endif-#ifndef _S_IFSOCK- #define _S_IFSOCK 0140000 /* socket */-#endif-#ifndef _S_IFREG- #define _S_IFREG 0100000 /* regular */-#endif-#ifndef _S_IFMT- #define _S_IFMT 0170000 /* file type mask */-#endif--#ifndef S_IFIFO-#define S_IFIFO _S_IFIFO-#endif-//#define S_IFCHR _S_IFCHR-//#define S_IFDIR _S_IFDIR-#ifndef S_IFBLK-#define S_IFBLK _S_IFBLK-#endif-#ifndef S_IFLNK-#define S_IFLNK _S_IFLNK-#endif-#ifndef S_IFSOCK-#define S_IFSOCK _S_IFSOCK-#endif-//#define S_IFREG _S_IFREG-//#define S_IFMT _S_IFMT--#ifndef S_ISBLK-#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) /* block special */-#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) /* fifo or socket */-#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) /* char special */-#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) /* directory */-#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) /* regular file */-#endif-#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) /* Symbolic link */-#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* Socket */--#define _S_ISUID 0004000 /* set user id on execution */-#define _S_ISGID 0002000 /* set group id on execution */-#define _S_ISVTX 0001000 /* save swapped text even after use */--#define S_ISUID _S_ISUID-#define S_ISGID _S_ISGID-#define S_ISVTX _S_ISVTX--#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC)-#define _S_IXUSR _S_IEXEC /* read permission, user */-#define _S_IWUSR _S_IWRITE /* write permission, user */-#define _S_IRUSR _S_IREAD /* execute/search permission, user */-#define _S_IRWXG (_S_IRWXU >> 3)-#define _S_IXGRP (_S_IXUSR >> 3) /* read permission, group */-#define _S_IWGRP (_S_IWUSR >> 3) /* write permission, group */-#define _S_IRGRP (_S_IRUSR >> 3) /* execute/search permission, group */-#define _S_IRWXO (_S_IRWXG >> 3)-#define _S_IXOTH (_S_IXGRP >> 3) /* read permission, other */-#define _S_IWOTH (_S_IWGRP >> 3) /* write permission, other */-#define _S_IROTH (_S_IRGRP >> 3) /* execute/search permission, other */--#ifndef S_IRWXU-#define S_IRWXU _S_IRWXU-#define S_IXUSR _S_IXUSR-#define S_IWUSR _S_IWUSR-#define S_IRUSR _S_IRUSR-#endif-#ifndef S_IRWXG-#define S_IRWXG _S_IRWXG-#define S_IXGRP _S_IXGRP-#define S_IWGRP _S_IWGRP-#endif-#ifndef S_IRGRP-#define S_IRGRP _S_IRGRP-#endif-#ifndef S_IRWXO-#define S_IRWXO _S_IRWXO-#define S_IXOTH _S_IXOTH-#define S_IWOTH _S_IWOTH-#define S_IROTH _S_IROTH-#endif--#endif--#define F_DUPFD 0 /* Duplicate file descriptor. */-#define F_GETFD 1 /* Get file descriptor flags. */-#define F_SETFD 2 /* Set file descriptor flags. */-#define F_GETFL 3 /* Get file status flags. */-#define F_SETFL 4 /* Set file status flags. */-#define F_GETOWN 5 /* Get owner (receiver of SIGIO). */-#define F_SETOWN 6 /* Set owner (receiver of SIGIO). */-#define F_GETLK 7 /* Get record locking info. */-#define F_SETLK 8 /* Set record locking info (non-blocking). */-#define F_SETLKW 9 /* Set record locking info (blocking). */--/* XXX missing */-#define F_GETLK64 7 /* Get record locking info. */-#define F_SETLK64 8 /* Set record locking info (non-blocking). */-#define F_SETLKW64 9 /* Set record locking info (blocking). */--/* File descriptor flags used with F_GETFD and F_SETFD. */-#define FD_CLOEXEC 1 /* Close on exec. */--//NOT SURE IF O_NONBLOCK is OK here but at least the 0x0004 flag is not used by anything else...-#define O_NONBLOCK 0x0004 /* Non-blocking I/O. */-//#define O_NDELAY O_NONBLOCK--/* Symbolic constants for the access() function */-#if !defined(F_OK)- #define R_OK 4 /* Test for read permission */- #define W_OK 2 /* Test for write permission */- #define X_OK 1 /* Test for execute permission */- #define F_OK 0 /* Test for existence of file */-#endif---/* Replacement POSIX function */-extern int __la_fstat(int fd, struct stat *st);-extern int __la_lstat(const char *path, struct stat *st);-#if defined(__LA_LSEEK_NEEDED)-extern __int64 __la_lseek(int fd, __int64 offset, int whence);-#endif-extern int __la_open(const char *path, int flags, ...);-extern ssize_t __la_read(int fd, void *buf, size_t nbytes);-extern int __la_stat(const char *path, struct stat *st);-extern pid_t __la_waitpid(HANDLE child, int *status, int option);-extern ssize_t __la_write(int fd, const void *buf, size_t nbytes);--#define _stat64i32(path, st) __la_stat(path, st)-#define _stat64(path, st) __la_stat(path, st)-/* for status returned by la_waitpid */-#define WIFEXITED(sts) ((sts & 0x100) == 0)-#define WEXITSTATUS(sts) (sts & 0x0FF)--extern wchar_t *__la_win_permissive_name(const char *name);-extern wchar_t *__la_win_permissive_name_w(const wchar_t *wname);-extern void __la_dosmaperr(unsigned long e);-#define la_dosmaperr(e) __la_dosmaperr(e)-extern struct archive_entry *__la_win_entry_in_posix_pathseparator(- struct archive_entry *);--#if defined(HAVE_WCRTOMB) && defined(__BORLANDC__)-typedef int mbstate_t;-size_t wcrtomb(char *, wchar_t, mbstate_t *);-#endif--#if defined(_MSC_VER) && _MSC_VER < 1300-WINBASEAPI BOOL WINAPI GetVolumePathNameW(- LPCWSTR lpszFileName,- LPWSTR lpszVolumePathName,- DWORD cchBufferLength- );-# if _WIN32_WINNT < 0x0500 /* windows.h not providing 0x500 API */-typedef struct _FILE_ALLOCATED_RANGE_BUFFER {- LARGE_INTEGER FileOffset;- LARGE_INTEGER Length;-} FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER;-# define FSCTL_SET_SPARSE \- CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_WRITE_DATA)-# define FSCTL_QUERY_ALLOCATED_RANGES \- CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51, METHOD_NEITHER, FILE_READ_DATA)-# endif-#endif--#endif /* LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */
− c/archive_write.c
@@ -1,859 +0,0 @@-/*-- * 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.c 201099 2009-12-28 03:03:00Z kientzle $");--/*- * This file contains the "essential" portions of the write API, that- * is, stuff that will essentially always be used by any client that- * actually needs to write an archive. Optional pieces have been, as- * far as possible, separated out into separate files to reduce- * needlessly bloating statically-linked clients.- */--#ifdef HAVE_SYS_WAIT_H-#include <sys/wait.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#include <stdio.h>-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#include <time.h>-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_write_private.h"--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_filter_count(struct archive *);-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);--struct archive_none {- size_t buffer_size;- size_t avail;- char *buffer;- char *next;-};--static const struct archive_vtable-archive_write_vtable = {- .archive_close = _archive_write_close,- .archive_filter_bytes = _archive_filter_bytes,- .archive_filter_code = _archive_filter_code,- .archive_filter_name = _archive_filter_name,- .archive_filter_count = _archive_write_filter_count,- .archive_free = _archive_write_free,- .archive_write_header = _archive_write_header,- .archive_write_finish_entry = _archive_write_finish_entry,- .archive_write_data = _archive_write_data,-};--/*- * Allocate, initialize and return an archive object.- */-struct archive *-archive_write_new(void)-{- struct archive_write *a;- unsigned char *nulls;-- a = (struct archive_write *)calloc(1, sizeof(*a));- if (a == NULL)- return (NULL);- a->archive.magic = ARCHIVE_WRITE_MAGIC;- a->archive.state = ARCHIVE_STATE_NEW;- a->archive.vtable = &archive_write_vtable;- /*- * The value 10240 here matches the traditional tar default,- * but is otherwise arbitrary.- * TODO: Set the default block size from the format selected.- */- a->bytes_per_block = 10240;- a->bytes_in_last_block = -1; /* Default */-- /* Initialize a block of nulls for padding purposes. */- a->null_length = 1024;- nulls = (unsigned char *)calloc(1, a->null_length);- if (nulls == NULL) {- free(a);- return (NULL);- }- a->nulls = nulls;- return (&a->archive);-}--/*- * Set the block size. Returns 0 if successful.- */-int-archive_write_set_bytes_per_block(struct archive *_a, int bytes_per_block)-{- struct archive_write *a = (struct archive_write *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_bytes_per_block");- a->bytes_per_block = bytes_per_block;- return (ARCHIVE_OK);-}--/*- * Get the current block size. -1 if it has never been set.- */-int-archive_write_get_bytes_per_block(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_get_bytes_per_block");- return (a->bytes_per_block);-}--/*- * Set the size for the last block.- * Returns 0 if successful.- */-int-archive_write_set_bytes_in_last_block(struct archive *_a, int bytes)-{- struct archive_write *a = (struct archive_write *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_set_bytes_in_last_block");- a->bytes_in_last_block = bytes;- return (ARCHIVE_OK);-}--/*- * Return the value set above. -1 indicates it has not been set.- */-int-archive_write_get_bytes_in_last_block(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_get_bytes_in_last_block");- return (a->bytes_in_last_block);-}--/*- * dev/ino of a file to be rejected. Used to prevent adding- * an archive to itself recursively.- */-int-archive_write_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i)-{- struct archive_write *a = (struct archive_write *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_set_skip_file");- a->skip_file_set = 1;- a->skip_file_dev = d;- a->skip_file_ino = i;- 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;-- f = calloc(1, sizeof(*f));-- if (f == NULL)- return (NULL);-- f->archive = _a;- f->state = ARCHIVE_WRITE_FILTER_STATE_NEW;- 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;- /* Never write to non-open filters */- if (f->state != ARCHIVE_WRITE_FILTER_STATE_OPEN)- return(ARCHIVE_FATAL);- if (length == 0)- return(ARCHIVE_OK);- if (f->write == NULL)- /* If unset, a fatal error has already occurred, so this filter- * didn't open. We cannot write anything. */- return(ARCHIVE_FATAL);- r = (f->write)(f, buff, length);- f->bytes_written += length;- return (r);-}--/*- * Recursive function for opening the filter chain- * Last filter is opened first- */-static int-__archive_write_open_filter(struct archive_write_filter *f)-{- int ret;-- ret = ARCHIVE_OK;- if (f->next_filter != NULL)- ret = __archive_write_open_filter(f->next_filter);- if (ret != ARCHIVE_OK)- return (ret);- if (f->state != ARCHIVE_WRITE_FILTER_STATE_NEW)- return (ARCHIVE_FATAL);- if (f->open == NULL) {- f->state = ARCHIVE_WRITE_FILTER_STATE_OPEN;- return (ARCHIVE_OK);- }- ret = (f->open)(f);- if (ret == ARCHIVE_OK)- f->state = ARCHIVE_WRITE_FILTER_STATE_OPEN;- else- f->state = ARCHIVE_WRITE_FILTER_STATE_FATAL;- return (ret);-}--/*- * Open all filters- */-static int-__archive_write_filters_open(struct archive_write *a)-{- return (__archive_write_open_filter(a->filter_first));-}--/*- * Close all filtes- */-static int-__archive_write_filters_close(struct archive_write *a)-{- struct archive_write_filter *f;- int ret, ret1;- ret = ARCHIVE_OK;- for (f = a->filter_first; f != NULL; f = f->next_filter) {- /* Do not close filters that are not open */- if (f->state == ARCHIVE_WRITE_FILTER_STATE_OPEN) {- if (f->close != NULL) {- ret1 = (f->close)(f);- if (ret1 < ret)- ret = ret1;- if (ret1 == ARCHIVE_OK) {- f->state =- ARCHIVE_WRITE_FILTER_STATE_CLOSED;- } else {- f->state =- ARCHIVE_WRITE_FILTER_STATE_FATAL;- }- } else- f->state = ARCHIVE_WRITE_FILTER_STATE_CLOSED;- }- }- return (ret);-}--int-__archive_write_output(struct archive_write *a, const void *buff, size_t length)-{- return (__archive_write_filter(a->filter_first, buff, length));-}--static int-__archive_write_filters_flush(struct archive_write *a)-{- struct archive_write_filter *f;- int ret, ret1;-- ret = ARCHIVE_OK;- for (f = a->filter_first; f != NULL; f = f->next_filter) {- if (f->flush != NULL && f->bytes_written > 0) {- ret1 = (f->flush)(f);- if (ret1 < ret)- ret = ret1;- if (ret1 < ARCHIVE_WARN)- f->state = ARCHIVE_WRITE_FILTER_STATE_FATAL;- }- }- return (ret);-}--int-__archive_write_nulls(struct archive_write *a, size_t length)-{- if (length == 0)- return (ARCHIVE_OK);-- while (length > 0) {- size_t to_write = length < a->null_length ? length : a->null_length;- int r = __archive_write_output(a, a->nulls, to_write);- if (r < ARCHIVE_OK)- return (r);- length -= to_write;- }- return (ARCHIVE_OK);-}--static int-archive_write_client_open(struct archive_write_filter *f)-{- struct archive_write *a = (struct archive_write *)f->archive;- struct archive_none *state;- void *buffer;- size_t buffer_size;- int 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);- buffer_size = f->bytes_per_block;-- state = (struct archive_none *)calloc(1, sizeof(*state));- buffer = (char *)malloc(buffer_size);- if (state == NULL || buffer == NULL) {- free(state);- free(buffer);- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for output buffering");- return (ARCHIVE_FATAL);- }-- state->buffer_size = buffer_size;- state->buffer = buffer;- state->next = state->buffer;- state->avail = state->buffer_size;- f->data = state;-- if (a->client_opener == NULL)- return (ARCHIVE_OK);- ret = a->client_opener(f->archive, a->client_data);- if (ret != ARCHIVE_OK) {- free(state->buffer);- free(state);- f->data = NULL;- }- return (ret);-}--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;- struct archive_none *state = (struct archive_none *)f->data;- const char *buff = (const char *)_buff;- ssize_t remaining, to_copy;- ssize_t bytes_written;-- remaining = length;-- /*- * If there is no buffer for blocking, just pass the data- * straight through to the client write callback. In- * 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);- remaining -= bytes_written;- buff += bytes_written;- }- return (ARCHIVE_OK);- }-- /* If the copy buffer isn't empty, try to fill it. */- if (state->avail < state->buffer_size) {- /* If buffer is not empty... */- /* ... copy data into buffer ... */- to_copy = ((size_t)remaining > state->avail) ?- state->avail : (size_t)remaining;- memcpy(state->next, buff, to_copy);- state->next += to_copy;- state->avail -= to_copy;- buff += to_copy;- remaining -= to_copy;- /* ... if it's full, write it out. */- if (state->avail == 0) {- char *p = state->buffer;- size_t to_write = state->buffer_size;- while (to_write > 0) {- bytes_written = (a->client_writer)(&a->archive,- a->client_data, p, to_write);- if (bytes_written <= 0)- return (ARCHIVE_FATAL);- if ((size_t)bytes_written > to_write) {- archive_set_error(&(a->archive),- -1, "write overrun");- return (ARCHIVE_FATAL);- }- p += bytes_written;- to_write -= bytes_written;- }- state->next = state->buffer;- state->avail = state->buffer_size;- }- }-- while ((size_t)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)- return (ARCHIVE_FATAL);- buff += bytes_written;- remaining -= bytes_written;- }-- if (remaining > 0) {- /* Copy last bit into copy buffer. */- memcpy(state->next, buff, remaining);- state->next += remaining;- state->avail -= remaining;- }- return (ARCHIVE_OK);-}--static int-archive_write_client_free(struct archive_write_filter *f)-{- struct archive_write *a = (struct archive_write *)f->archive;-- if (a->client_freer)- (*a->client_freer)(&a->archive, a->client_data);- a->client_data = NULL;-- /* Clear passphrase. */- if (a->passphrase != NULL) {- memset(a->passphrase, 0, strlen(a->passphrase));- free(a->passphrase);- a->passphrase = NULL;- }-- return (ARCHIVE_OK);-}--static int-archive_write_client_close(struct archive_write_filter *f)-{- struct archive_write *a = (struct archive_write *)f->archive;- struct archive_none *state = (struct archive_none *)f->data;- ssize_t block_length;- ssize_t target_block_length;- ssize_t bytes_written;- size_t to_write;- char *p;- int ret = ARCHIVE_OK;-- /* 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)- /* Default or Zero: pad to full block */- target_block_length = a->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;- if (block_length < target_block_length) {- memset(state->next, 0,- target_block_length - block_length);- block_length = target_block_length;- }- p = state->buffer;- to_write = block_length;- while (to_write > 0) {- bytes_written = (a->client_writer)(&a->archive,- a->client_data, p, to_write);- if (bytes_written <= 0) {- ret = ARCHIVE_FATAL;- break;- }- if ((size_t)bytes_written > to_write) {- archive_set_error(&(a->archive),- -1, "write overrun");- ret = ARCHIVE_FATAL;- break;- }- p += bytes_written;- to_write -= bytes_written;- }- }- if (a->client_closer)- (*a->client_closer)(&a->archive, a->client_data);- free(state->buffer);- free(state);-- /* Clear the close handler myself not to be called again. */- f->state = ARCHIVE_WRITE_FILTER_STATE_CLOSED;- return (ret);-}--/*- * Open the archive using the current settings.- */-int-archive_write_open2(struct archive *_a, void *client_data,- archive_open_callback *opener, archive_write_callback *writer,- archive_close_callback *closer, archive_free_callback *freer)-{- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *client_filter;- int ret, r1;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_open");- archive_clear_error(&a->archive);-- a->client_writer = writer;- a->client_opener = opener;- a->client_closer = closer;- a->client_freer = freer;- a->client_data = client_data;-- client_filter = __archive_write_allocate_filter(_a);-- if (client_filter == NULL)- return (ARCHIVE_FATAL);-- client_filter->open = archive_write_client_open;- client_filter->write = archive_write_client_write;- client_filter->close = archive_write_client_close;- client_filter->free = archive_write_client_free;-- ret = __archive_write_filters_open(a);- if (ret < ARCHIVE_WARN) {- r1 = __archive_write_filters_close(a);- __archive_write_filters_free(_a);- return (r1 < ret ? r1 : ret);- }-- a->archive.state = ARCHIVE_STATE_HEADER;- if (a->format_init)- ret = (a->format_init)(a);- return (ret);-}--int-archive_write_open(struct archive *_a, void *client_data,- archive_open_callback *opener, archive_write_callback *writer,- archive_close_callback *closer)-{- return archive_write_open2(_a, client_data, opener, writer,- closer, NULL);-}--/*- * Close out the archive.- */-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_STATE_FATAL,- "archive_write_close");- if (a->archive.state == ARCHIVE_STATE_NEW- || a->archive.state == ARCHIVE_STATE_CLOSED)- return (ARCHIVE_OK); /* Okay to close() when not open. */-- archive_clear_error(&a->archive);-- /* Finish the last entry if a finish callback is specified */- if (a->archive.state == ARCHIVE_STATE_DATA- && a->format_finish_entry != NULL)- r = ((a->format_finish_entry)(a));-- /* Finish off the archive. */- /* TODO: have format closers invoke compression close. */- if (a->format_close != NULL) {- r1 = (a->format_close)(a);- if (r1 < r)- r = r1;- }-- /* Finish the compression and close the stream. */- r1 = __archive_write_filters_close(a);- if (r1 < r)- r = r1;-- if (a->archive.state != ARCHIVE_STATE_FATAL)- a->archive.state = ARCHIVE_STATE_CLOSED;- return (r);-}--static int-_archive_write_filter_count(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *p = a->filter_first;- int count = 0;- while(p) {- count++;- p = p->next_filter;- }- return count;-}--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, r1;-- if (_a == NULL)- return (ARCHIVE_OK);- /* It is okay to call free() in state FATAL. */- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_free");- if (a->archive.state != ARCHIVE_STATE_FATAL)- r = archive_write_close(&a->archive);-- /* Release format resources. */- if (a->format_free != NULL) {- r1 = (a->format_free)(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);- if (a->passphrase != NULL) {- /* A passphrase should be cleaned. */- memset(a->passphrase, 0, strlen(a->passphrase));- free(a->passphrase);- }- a->archive.magic = 0;- __archive_clean(&a->archive);- free(a);- return (r);-}--/*- * Write the appropriate header.- */-static int-_archive_write_header(struct archive *_a, struct archive_entry *entry)-{- struct archive_write *a = (struct archive_write *)_a;- int ret, r2;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_DATA | ARCHIVE_STATE_HEADER, "archive_write_header");- archive_clear_error(&a->archive);-- if (a->format_write_header == NULL) {- archive_set_error(&(a->archive), -1,- "Format must be set before you can write to an archive.");- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }-- /* 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);-- if (a->skip_file_set &&- archive_entry_dev_is_set(entry) &&- archive_entry_ino_is_set(entry) &&- archive_entry_dev(entry) == (dev_t)a->skip_file_dev &&- archive_entry_ino64(entry) == a->skip_file_ino) {- archive_set_error(&a->archive, 0,- "Can't add archive to itself");- return (ARCHIVE_FAILED);- }-- /* Flush filters at boundary. */- r2 = __archive_write_filters_flush(a);- if (r2 == ARCHIVE_FAILED) {- return (ARCHIVE_FAILED);- }- if (r2 == ARCHIVE_FATAL) {- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- if (r2 < ret)- ret = r2;-- /* Format and write header. */- r2 = ((a->format_write_header)(a, entry));- if (r2 == ARCHIVE_FAILED) {- return (ARCHIVE_FAILED);- }- if (r2 == ARCHIVE_FATAL) {- a->archive.state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);- }- if (r2 < ret)- ret = r2;-- a->archive.state = ARCHIVE_STATE_DATA;- return (ret);-}--static int-_archive_write_finish_entry(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- int ret = ARCHIVE_OK;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_write_finish_entry");- if (a->archive.state & ARCHIVE_STATE_DATA- && a->format_finish_entry != NULL)- ret = (a->format_finish_entry)(a);- a->archive.state = ARCHIVE_STATE_HEADER;- return (ret);-}--/*- * Note that the compressor is responsible for blocking.- */-static ssize_t-_archive_write_data(struct archive *_a, const void *buff, size_t s)-{- struct archive_write *a = (struct archive_write *)_a;- const size_t max_write = INT_MAX;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_DATA, "archive_write_data");- /* In particular, this catches attempts to pass negative values. */- if (s > max_write)- s = max_write;- 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 ? f->name : NULL;-}--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;-}
− c/archive_write_add_filter.c
@@ -1,72 +0,0 @@-/*-- * Copyright (c) 2012 Ondrej Holy- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif--#include "archive.h"-#include "archive_private.h"--/* A table that maps filter codes to functions. */-static const-struct { int code; int (*setter)(struct archive *); } codes[] =-{- { ARCHIVE_FILTER_NONE, archive_write_add_filter_none },- { ARCHIVE_FILTER_GZIP, archive_write_add_filter_gzip },- { ARCHIVE_FILTER_BZIP2, archive_write_add_filter_bzip2 },- { ARCHIVE_FILTER_COMPRESS, archive_write_add_filter_compress },- { ARCHIVE_FILTER_GRZIP, archive_write_add_filter_grzip },- { ARCHIVE_FILTER_LRZIP, archive_write_add_filter_lrzip },- { ARCHIVE_FILTER_LZ4, archive_write_add_filter_lz4 },- { ARCHIVE_FILTER_LZIP, archive_write_add_filter_lzip },- { ARCHIVE_FILTER_LZMA, archive_write_add_filter_lzma },- { ARCHIVE_FILTER_LZOP, archive_write_add_filter_lzip },- { ARCHIVE_FILTER_UU, archive_write_add_filter_uuencode },- { ARCHIVE_FILTER_XZ, archive_write_add_filter_xz },- { ARCHIVE_FILTER_ZSTD, archive_write_add_filter_zstd },- { -1, NULL }-};--int-archive_write_add_filter(struct archive *a, int code)-{- int i;-- for (i = 0; codes[i].code != -1; i++) {- if (code == codes[i].code)- return ((codes[i].setter)(a));- }-- archive_set_error(a, EINVAL, "No such filter");- return (ARCHIVE_FATAL);-}
− c/archive_write_add_filter_b64encode.c
@@ -1,304 +0,0 @@-/*-- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_string.h"-#include "archive_write_private.h"--#define LBYTES 57--struct private_b64encode {- int mode;- struct archive_string name;- struct archive_string encoded_buff;- size_t bs;- size_t hold_len;- unsigned char hold[LBYTES];-};--static int archive_filter_b64encode_options(struct archive_write_filter *,- const char *, const char *);-static int archive_filter_b64encode_open(struct archive_write_filter *);-static int archive_filter_b64encode_write(struct archive_write_filter *,- const void *, size_t);-static int archive_filter_b64encode_close(struct archive_write_filter *);-static int archive_filter_b64encode_free(struct archive_write_filter *);-static void la_b64_encode(struct archive_string *, const unsigned char *, size_t);-static int64_t atol8(const char *, size_t);--static const char base64[] = {- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',- 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',- 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',- 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',- 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',- 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',- 'w', 'x', 'y', 'z', '0', '1', '2', '3',- '4', '5', '6', '7', '8', '9', '+', '/'-};--/*- * Add a compress filter to this write handle.- */-int-archive_write_add_filter_b64encode(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct private_b64encode *state;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");-- state = (struct private_b64encode *)calloc(1, sizeof(*state));- if (state == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for b64encode filter");- return (ARCHIVE_FATAL);- }- archive_strcpy(&state->name, "-");- state->mode = 0644;-- f->data = state;- f->name = "b64encode";- f->code = ARCHIVE_FILTER_UU;- f->open = archive_filter_b64encode_open;- f->options = archive_filter_b64encode_options;- f->write = archive_filter_b64encode_write;- f->close = archive_filter_b64encode_close;- f->free = archive_filter_b64encode_free;-- return (ARCHIVE_OK);-}--/*- * Set write options.- */-static int-archive_filter_b64encode_options(struct archive_write_filter *f, const char *key,- const char *value)-{- struct private_b64encode *state = (struct private_b64encode *)f->data;-- if (strcmp(key, "mode") == 0) {- if (value == NULL) {- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,- "mode option requires octal digits");- return (ARCHIVE_FAILED);- }- state->mode = (int)atol8(value, strlen(value)) & 0777;- return (ARCHIVE_OK);- } else if (strcmp(key, "name") == 0) {- if (value == NULL) {- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,- "name option requires a string");- return (ARCHIVE_FAILED);- }- archive_strcpy(&state->name, value);- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--/*- * Setup callback.- */-static int-archive_filter_b64encode_open(struct archive_write_filter *f)-{- struct private_b64encode *state = (struct private_b64encode *)f->data;- size_t bs = 65536, bpb;-- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {- /* Buffer size should be a multiple number of the of bytes- * per block for performance. */- bpb = archive_write_get_bytes_per_block(f->archive);- if (bpb > bs)- bs = bpb;- else if (bpb != 0)- bs -= bs % bpb;- }-- state->bs = bs;- if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for b64encode buffer");- return (ARCHIVE_FATAL);- }-- archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n",- state->mode, state->name.s);-- f->data = state;- return (0);-}--static void-la_b64_encode(struct archive_string *as, const unsigned char *p, size_t len)-{- int c;-- for (; len >= 3; p += 3, len -= 3) {- c = p[0] >> 2;- archive_strappend_char(as, base64[c]);- c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4);- archive_strappend_char(as, base64[c]);- c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6);- archive_strappend_char(as, base64[c]);- c = p[2] & 0x3f;- archive_strappend_char(as, base64[c]);- }- if (len > 0) {- c = p[0] >> 2;- archive_strappend_char(as, base64[c]);- c = (p[0] & 0x03) << 4;- if (len == 1) {- archive_strappend_char(as, base64[c]);- archive_strappend_char(as, '=');- archive_strappend_char(as, '=');- } else {- c |= (p[1] & 0xf0) >> 4;- archive_strappend_char(as, base64[c]);- c = (p[1] & 0x0f) << 2;- archive_strappend_char(as, base64[c]);- archive_strappend_char(as, '=');- }- }- archive_strappend_char(as, '\n');-}--/*- * Write data to the encoded stream.- */-static int-archive_filter_b64encode_write(struct archive_write_filter *f, const void *buff,- size_t length)-{- struct private_b64encode *state = (struct private_b64encode *)f->data;- const unsigned char *p = buff;- int ret = ARCHIVE_OK;-- if (length == 0)- return (ret);-- if (state->hold_len) {- while (state->hold_len < LBYTES && length > 0) {- state->hold[state->hold_len++] = *p++;- length--;- }- if (state->hold_len < LBYTES)- return (ret);- la_b64_encode(&state->encoded_buff, state->hold, LBYTES);- state->hold_len = 0;- }-- for (; length >= LBYTES; length -= LBYTES, p += LBYTES)- la_b64_encode(&state->encoded_buff, p, LBYTES);-- /* Save remaining bytes. */- if (length > 0) {- memcpy(state->hold, p, length);- state->hold_len = length;- }- while (archive_strlen(&state->encoded_buff) >= state->bs) {- ret = __archive_write_filter(f->next_filter,- state->encoded_buff.s, state->bs);- memmove(state->encoded_buff.s,- state->encoded_buff.s + state->bs,- state->encoded_buff.length - state->bs);- state->encoded_buff.length -= state->bs;- }-- return (ret);-}---/*- * Finish the compression...- */-static int-archive_filter_b64encode_close(struct archive_write_filter *f)-{- struct private_b64encode *state = (struct private_b64encode *)f->data;-- /* Flush remaining bytes. */- if (state->hold_len != 0)- la_b64_encode(&state->encoded_buff, state->hold, state->hold_len);- archive_string_sprintf(&state->encoded_buff, "====\n");- /* Write the last block */- archive_write_set_bytes_in_last_block(f->archive, 1);- return __archive_write_filter(f->next_filter,- state->encoded_buff.s, archive_strlen(&state->encoded_buff));-}--static int-archive_filter_b64encode_free(struct archive_write_filter *f)-{- struct private_b64encode *state = (struct private_b64encode *)f->data;-- archive_string_free(&state->name);- archive_string_free(&state->encoded_buff);- free(state);- return (ARCHIVE_OK);-}--static int64_t-atol8(const char *p, size_t char_cnt)-{- int64_t l;- int digit;- - l = 0;- while (char_cnt-- > 0) {- if (*p >= '0' && *p <= '7')- digit = *p - '0';- else- break;- p++;- l <<= 3;- l |= digit;- }- return (l);-}-
− c/archive_write_add_filter_by_name.c
@@ -1,77 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_private.h"--/* A table that maps names to functions. */-static const-struct { const char *name; int (*setter)(struct archive *); } names[] =-{- { "b64encode", archive_write_add_filter_b64encode },- { "bzip2", archive_write_add_filter_bzip2 },- { "compress", archive_write_add_filter_compress },- { "grzip", archive_write_add_filter_grzip },- { "gzip", archive_write_add_filter_gzip },- { "lrzip", archive_write_add_filter_lrzip },- { "lz4", archive_write_add_filter_lz4 },- { "lzip", archive_write_add_filter_lzip },- { "lzma", archive_write_add_filter_lzma },- { "lzop", archive_write_add_filter_lzop },- { "uuencode", archive_write_add_filter_uuencode },- { "xz", archive_write_add_filter_xz },- { "zstd", archive_write_add_filter_zstd },- { NULL, NULL }-};--int-archive_write_add_filter_by_name(struct archive *a, const char *name)-{- int i;-- for (i = 0; names[i].name != NULL; i++) {- if (strcmp(name, names[i].name) == 0)- return ((names[i].setter)(a));- }-- archive_set_error(a, EINVAL, "No such filter '%s'", name);- a->state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);-}
− c/archive_write_add_filter_bzip2.c
@@ -1,401 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#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--struct private_data {- int compression_level;-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- bz_stream stream;- int64_t total_in;- char *compressed;- size_t compressed_buffer_size;-#else- struct archive_write_program_data *pdata;-#endif-};--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);--/*- * 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_add_filter_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_FILTER_BZIP2;- f->name = "bzip2";-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- return (ARCHIVE_OK);-#else- data->pdata = __archive_write_program_allocate("bzip2");- if (data->pdata == NULL) {- free(data);- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- data->compression_level = 0;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Using external bzip2 program");- return (ARCHIVE_WARN);-#endif-}--/*- * 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);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)-/* Don't compile this if we don't have bzlib. */--/*- * 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 drive_compressor(struct archive_write_filter *,- struct private_data *, int finishing);--/*- * Setup callback.- */-static int-archive_compressor_bzip2_open(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;- int ret;-- if (data->compressed == NULL) {- size_t bs = 65536, bpb;- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {- /* Buffer size should be a multiple number of the of bytes- * per block for performance. */- bpb = archive_write_get_bytes_per_block(f->archive);- if (bpb > bs)- bs = bpb;- else if (bpb != 0)- bs -= bs % bpb;- }- data->compressed_buffer_size = bs;- 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 = (uint32_t)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);--}--/*- * 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 = (uint32_t)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;- int ret;-- /* Finish compression cycle. */- ret = drive_compressor(f, data, 1);- if (ret == ARCHIVE_OK) {- /* Write the last block */- ret = __archive_write_filter(f->next_filter,- data->compressed,- data->compressed_buffer_size - data->stream.avail_out);- }-- 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 ret;-}--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)-{- 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) {- /* TODO: Handle this write failure */- return (ARCHIVE_FATAL);- }- data->stream.next_out = data->compressed;- data->stream.avail_out = (uint32_t)data->compressed_buffer_size;- }-- /* 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);- }- }-}--#else /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */--static int-archive_compressor_bzip2_open(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;- struct archive_string as;- int r;-- archive_string_init(&as);- archive_strcpy(&as, "bzip2");-- /* Specify compression level. */- if (data->compression_level > 0) {- archive_strcat(&as, " -");- archive_strappend_char(&as, '0' + data->compression_level);- }- f->write = archive_compressor_bzip2_write;-- r = __archive_write_program_open(f, data->pdata, as.s);- archive_string_free(&as);- return (r);-}--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;-- return __archive_write_program_write(f, data->pdata, buff, length);-}--static int-archive_compressor_bzip2_close(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- return __archive_write_program_close(f, data->pdata);-}--static int-archive_compressor_bzip2_free(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- __archive_write_program_free(data->pdata);- free(data);- return (ARCHIVE_OK);-}--#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
− c/archive_write_add_filter_compress.c
@@ -1,447 +0,0 @@-/*-- * Copyright (c) 2008 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.- */--/*-- * Copyright (c) 1985, 1986, 1992, 1993- * The Regents of the University of California. All rights reserved.- *- * This code is derived from software contributed to Berkeley by- * Diomidis Spinellis and James A. Woods, derived from original- * work by Spencer Thomas and Joseph Orost.- *- * 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.- * 3. Neither the name of the University nor the names of its contributors- * may be used to endorse or promote products derived from this software- * without specific prior written permission.- *- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF- * SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_compress.c 201111 2009-12-28 03:33:05Z 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 "archive.h"-#include "archive_private.h"-#include "archive_write_private.h"--#define HSIZE 69001 /* 95% occupancy */-#define HSHIFT 8 /* 8 - trunc(log2(HSIZE / 65536)) */-#define CHECK_GAP 10000 /* Ratio check interval. */--#define MAXCODE(bits) ((1 << (bits)) - 1)--/*- * the next two codes should not be changed lightly, as they must not- * lie within the contiguous general code space.- */-#define FIRST 257 /* First free entry. */-#define CLEAR 256 /* Table clear output code. */--struct private_data {- int64_t in_count, out_count, checkpoint;-- int code_len; /* Number of bits/code. */- int cur_maxcode; /* Maximum code, given n_bits. */- int max_maxcode; /* Should NEVER generate this code. */- int hashtab [HSIZE];- unsigned short codetab [HSIZE];- int first_free; /* First unused entry. */- int compress_ratio;-- int cur_code, cur_fcode;-- int bit_offset;- unsigned char bit_buf;-- unsigned char *compressed;- size_t compressed_buffer_size;- size_t compressed_offset;-};--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--/*- * Add a compress filter to this write handle.- */-int-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_add_filter_compress");- f->open = &archive_compressor_compress_open;- f->code = ARCHIVE_FILTER_COMPRESS;- f->name = "compress";- return (ARCHIVE_OK);-}--/*- * Setup callback.- */-static int-archive_compressor_compress_open(struct archive_write_filter *f)-{- struct private_data *state;- size_t bs = 65536, bpb;-- f->code = ARCHIVE_FILTER_COMPRESS;- f->name = "compress";-- state = (struct private_data *)calloc(1, sizeof(*state));- if (state == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for compression");- return (ARCHIVE_FATAL);- }-- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {- /* Buffer size should be a multiple number of the of bytes- * per block for performance. */- bpb = archive_write_get_bytes_per_block(f->archive);- if (bpb > bs)- bs = bpb;- else if (bpb != 0)- bs -= bs % bpb;- }- state->compressed_buffer_size = bs;- state->compressed = malloc(state->compressed_buffer_size);-- if (state->compressed == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for compression buffer");- free(state);- return (ARCHIVE_FATAL);- }-- 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->bit_buf = 0;- state->bit_offset = 0;- state->out_count = 3; /* Includes 3-byte header mojo. */- state->compress_ratio = 0;- state->checkpoint = CHECK_GAP;- state->code_len = 9;- state->cur_maxcode = MAXCODE(state->code_len);- state->first_free = FIRST;-- memset(state->hashtab, 0xff, sizeof(state->hashtab));-- /* Prime output buffer with a gzip header. */- state->compressed[0] = 0x1f; /* Compress */- state->compressed[1] = 0x9d;- state->compressed[2] = 0x90; /* Block mode, 16bit max */- state->compressed_offset = 3;-- f->data = state;- return (0);-}--/*-- * Output the given code.- * Inputs:- * code: A n_bits-bit integer. If == -1, then EOF. This assumes- * that n_bits <= (long)wordsize - 1.- * Outputs:- * Outputs code to the file.- * Assumptions:- * Chars are 8 bits long.- * Algorithm:- * Maintain a BITS character long buffer (so that 8 codes will- * fit in it exactly). Use the VAX insv instruction to insert each- * code in turn. When the buffer fills up empty it and start over.- */--static const unsigned char rmask[9] =- {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};--static int-output_byte(struct archive_write_filter *f, unsigned char c)-{- struct private_data *state = f->data;-- state->compressed[state->compressed_offset++] = c;- ++state->out_count;-- if (state->compressed_buffer_size == state->compressed_offset) {- int ret = __archive_write_filter(f->next_filter,- state->compressed, state->compressed_buffer_size);- if (ret != ARCHIVE_OK)- return ARCHIVE_FATAL;- state->compressed_offset = 0;- }-- return ARCHIVE_OK;-}--static int-output_code(struct archive_write_filter *f, int ocode)-{- struct private_data *state = f->data;- int bits, ret, clear_flg, bit_offset;-- clear_flg = ocode == CLEAR;-- /*- * Since ocode is always >= 8 bits, only need to mask the first- * hunk on the left.- */- bit_offset = state->bit_offset % 8;- state->bit_buf |= (ocode << bit_offset) & 0xff;- 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(f, ocode & 0xff);- ocode >>= 8;- bits -= 8;- }- /* Last bits. */- state->bit_offset += state->code_len;- state->bit_buf = ocode & rmask[bits];- if (state->bit_offset == state->code_len * 8)- state->bit_offset = 0;-- /*- * If the next entry is going to be too big for the ocode size,- * then increase it, if possible.- */- if (clear_flg || state->first_free > state->cur_maxcode) {- /*- * Write the whole buffer, because the input side won't- * discover the size increase until after it has read it.- */- if (state->bit_offset > 0) {- while (state->bit_offset < state->code_len * 8) {- ret = output_byte(f, state->bit_buf);- if (ret != ARCHIVE_OK)- return ret;- state->bit_offset += 8;- state->bit_buf = 0;- }- }- state->bit_buf = 0;- state->bit_offset = 0;-- if (clear_flg) {- state->code_len = 9;- state->cur_maxcode = MAXCODE(state->code_len);- } else {- state->code_len++;- if (state->code_len == 16)- state->cur_maxcode = state->max_maxcode;- else- state->cur_maxcode = MAXCODE(state->code_len);- }- }-- return (ARCHIVE_OK);-}--static int-output_flush(struct archive_write_filter *f)-{- 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(f, state->bit_buf);- if (ret != ARCHIVE_OK)- return ret;- }-- return (ARCHIVE_OK);-}--/*- * Write data to the compressed stream.- */-static int-archive_compressor_compress_write(struct archive_write_filter *f,- const void *buff, size_t length)-{- struct private_data *state = (struct private_data *)f->data;- int i;- int ratio;- int c, disp, ret;- const unsigned char *bp;-- if (length == 0)- return ARCHIVE_OK;-- bp = buff;-- if (state->in_count == 0) {- state->cur_code = *bp++;- ++state->in_count;- --length;- }-- while (length--) {- c = *bp++;- state->in_count++;- state->cur_fcode = (c << 16) | state->cur_code;- i = ((c << HSHIFT) ^ state->cur_code); /* Xor hashing. */-- if (state->hashtab[i] == state->cur_fcode) {- state->cur_code = state->codetab[i];- continue;- }- if (state->hashtab[i] < 0) /* Empty slot. */- goto nomatch;- /* Secondary hash (after G. Knott). */- if (i == 0)- disp = 1;- else- disp = HSIZE - i;- probe:- if ((i -= disp) < 0)- i += HSIZE;-- if (state->hashtab[i] == state->cur_fcode) {- state->cur_code = state->codetab[i];- continue;- }- if (state->hashtab[i] >= 0)- goto probe;- nomatch:- ret = output_code(f, state->cur_code);- if (ret != ARCHIVE_OK)- return ret;- state->cur_code = c;- if (state->first_free < state->max_maxcode) {- state->codetab[i] = state->first_free++; /* code -> hashtable */- state->hashtab[i] = state->cur_fcode;- continue;- }- if (state->in_count < state->checkpoint)- continue;-- state->checkpoint = state->in_count + CHECK_GAP;-- if (state->in_count <= 0x007fffff && state->out_count != 0)- ratio = (int)(state->in_count * 256 / state->out_count);- else if ((ratio = (int)(state->out_count / 256)) == 0)- ratio = 0x7fffffff;- else- ratio = (int)(state->in_count / ratio);-- if (ratio > state->compress_ratio)- state->compress_ratio = ratio;- else {- state->compress_ratio = 0;- memset(state->hashtab, 0xff, sizeof(state->hashtab));- state->first_free = FIRST;- ret = output_code(f, CLEAR);- if (ret != ARCHIVE_OK)- return ret;- }- }-- return (ARCHIVE_OK);-}---/*- * Finish the compression...- */-static int-archive_compressor_compress_close(struct archive_write_filter *f)-{- struct private_data *state = (struct private_data *)f->data;- int ret;-- ret = output_code(f, state->cur_code);- if (ret != ARCHIVE_OK)- return ret;- ret = output_flush(f);- if (ret != ARCHIVE_OK)- return ret;-- /* Write the last block */- ret = __archive_write_filter(f->next_filter,- state->compressed, state->compressed_offset);- return (ret);-}--static int-archive_compressor_compress_free(struct archive_write_filter *f)-{- struct private_data *state = (struct private_data *)f->data;-- free(state->compressed);- free(state);- return (ARCHIVE_OK);-}
− c/archive_write_add_filter_grzip.c
@@ -1,135 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif--#include "archive.h"-#include "archive_write_private.h"--struct write_grzip {- struct archive_write_program_data *pdata;-};--static int archive_write_grzip_open(struct archive_write_filter *);-static int archive_write_grzip_options(struct archive_write_filter *,- const char *, const char *);-static int archive_write_grzip_write(struct archive_write_filter *,- const void *, size_t);-static int archive_write_grzip_close(struct archive_write_filter *);-static int archive_write_grzip_free(struct archive_write_filter *);--int-archive_write_add_filter_grzip(struct archive *_a)-{- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct write_grzip *data;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_grzip");-- data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }- data->pdata = __archive_write_program_allocate("grzip");- if (data->pdata == NULL) {- free(data);- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }-- f->name = "grzip";- f->code = ARCHIVE_FILTER_GRZIP;- f->data = data;- f->open = archive_write_grzip_open;- f->options = archive_write_grzip_options;- f->write = archive_write_grzip_write;- f->close = archive_write_grzip_close;- f->free = archive_write_grzip_free;-- /* Note: This filter always uses an external program, so we- * return "warn" to inform of the fact. */- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external grzip program for grzip compression");- return (ARCHIVE_WARN);-}--static int-archive_write_grzip_options(struct archive_write_filter *f, const char *key,- const char *value)-{- (void)f; /* UNUSED */- (void)key; /* UNUSED */- (void)value; /* UNUSED */- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-archive_write_grzip_open(struct archive_write_filter *f)-{- struct write_grzip *data = (struct write_grzip *)f->data;-- return __archive_write_program_open(f, data->pdata, "grzip");-}--static int-archive_write_grzip_write(struct archive_write_filter *f,- const void *buff, size_t length)-{- struct write_grzip *data = (struct write_grzip *)f->data;-- return __archive_write_program_write(f, data->pdata, buff, length);-}--static int-archive_write_grzip_close(struct archive_write_filter *f)-{- struct write_grzip *data = (struct write_grzip *)f->data;-- return __archive_write_program_close(f, data->pdata);-}--static int-archive_write_grzip_free(struct archive_write_filter *f)-{- struct write_grzip *data = (struct write_grzip *)f->data;-- __archive_write_program_free(data->pdata);- free(data);- return (ARCHIVE_OK);-}
− c/archive_write_add_filter_gzip.c
@@ -1,442 +0,0 @@-/*-- * 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_string.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--/* Don't compile this if we don't have zlib. */--struct private_data {- int compression_level;- int timestamp;-#ifdef HAVE_ZLIB_H- z_stream stream;- int64_t total_in;- unsigned char *compressed;- size_t compressed_buffer_size;- unsigned long crc;-#else- struct archive_write_program_data *pdata;-#endif-};--/*- * 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 *);-#ifdef HAVE_ZLIB_H-static int drive_compressor(struct archive_write_filter *,- struct private_data *, int finishing);-#endif---/*- * 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_add_filter_gzip");-- data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- f->data = data;- 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_FILTER_GZIP;- f->name = "gzip";-#ifdef HAVE_ZLIB_H- data->compression_level = Z_DEFAULT_COMPRESSION;- return (ARCHIVE_OK);-#else- data->pdata = __archive_write_program_allocate("gzip");- if (data->pdata == NULL) {- free(data);- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- data->compression_level = 0;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Using external gzip program");- return (ARCHIVE_WARN);-#endif-}--static int-archive_compressor_gzip_free(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;--#ifdef HAVE_ZLIB_H- free(data->compressed);-#else- __archive_write_program_free(data->pdata);-#endif- free(data);- f->data = NULL;- return (ARCHIVE_OK);-}--/*- * 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);- }- if (strcmp(key, "timestamp") == 0) {- data->timestamp = (value == NULL)?-1:1;- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--#ifdef HAVE_ZLIB_H-/*- * Setup callback.- */-static int-archive_compressor_gzip_open(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;- int ret;-- if (data->compressed == NULL) {- size_t bs = 65536, bpb;- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {- /* Buffer size should be a multiple number of- * the of bytes per block for performance. */- bpb = archive_write_get_bytes_per_block(f->archive);- if (bpb > bs)- bs = bpb;- else if (bpb != 0)- bs -= bs % bpb;- }- data->compressed_buffer_size = bs;- 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 = (uInt)data->compressed_buffer_size;-- /* Prime output buffer with a gzip header. */- data->compressed[0] = 0x1f; /* GZip signature bytes */- data->compressed[1] = 0x8b;- data->compressed[2] = 0x08; /* "Deflate" compression */- data->compressed[3] = 0; /* No options */- if (data->timestamp >= 0) {- time_t t = time(NULL);- data->compressed[4] = (uint8_t)(t)&0xff; /* Timestamp */- data->compressed[5] = (uint8_t)(t>>8)&0xff;- data->compressed[6] = (uint8_t)(t>>16)&0xff;- data->compressed[7] = (uint8_t)(t>>24)&0xff;- } else- memset(&data->compressed[4], 0, 4);- if (data->compression_level == 9)- data->compressed[8] = 2;- else if(data->compression_level == 1)- data->compressed[8] = 4;- else- data->compressed[8] = 0;- 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);-}--/*- * 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, (uInt)length);- data->total_in += length;-- /* Compress input data to output buffer */- SET_NEXT_IN(data, buff);- data->stream.avail_in = (uInt)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;-- /* Finish compression cycle */- ret = drive_compressor(f, data, 1);- if (ret == ARCHIVE_OK) {- /* 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) {- /* Build and write out 8-byte trailer. */- trailer[0] = (uint8_t)(data->crc)&0xff;- trailer[1] = (uint8_t)(data->crc >> 8)&0xff;- trailer[2] = (uint8_t)(data->crc >> 16)&0xff;- trailer[3] = (uint8_t)(data->crc >> 24)&0xff;- trailer[4] = (uint8_t)(data->total_in)&0xff;- trailer[5] = (uint8_t)(data->total_in >> 8)&0xff;- trailer[6] = (uint8_t)(data->total_in >> 16)&0xff;- trailer[7] = (uint8_t)(data->total_in >> 24)&0xff;- ret = __archive_write_filter(f->next_filter, trailer, 8);- }-- 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;-}--/*- * 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 =- (uInt)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);- }- }-}--#else /* HAVE_ZLIB_H */--static int-archive_compressor_gzip_open(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;- struct archive_string as;- int r;-- archive_string_init(&as);- archive_strcpy(&as, "gzip");-- /* Specify compression level. */- if (data->compression_level > 0) {- archive_strcat(&as, " -");- archive_strappend_char(&as, '0' + data->compression_level);- }- if (data->timestamp < 0)- /* Do not save timestamp. */- archive_strcat(&as, " -n");- else if (data->timestamp > 0)- /* Save timestamp. */- archive_strcat(&as, " -N");-- f->write = archive_compressor_gzip_write;- r = __archive_write_program_open(f, data->pdata, as.s);- archive_string_free(&as);- return (r);-}--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;-- return __archive_write_program_write(f, data->pdata, buff, length);-}--static int-archive_compressor_gzip_close(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- return __archive_write_program_close(f, data->pdata);-}--#endif /* HAVE_ZLIB_H */
− c/archive_write_add_filter_lrzip.c
@@ -1,197 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_string.h"-#include "archive_write_private.h"--struct write_lrzip {- struct archive_write_program_data *pdata;- int compression_level;- enum { lzma = 0, bzip2, gzip, lzo, none, zpaq } compression;-};--static int archive_write_lrzip_open(struct archive_write_filter *);-static int archive_write_lrzip_options(struct archive_write_filter *,- const char *, const char *);-static int archive_write_lrzip_write(struct archive_write_filter *,- const void *, size_t);-static int archive_write_lrzip_close(struct archive_write_filter *);-static int archive_write_lrzip_free(struct archive_write_filter *);--int-archive_write_add_filter_lrzip(struct archive *_a)-{- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct write_lrzip *data;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_lrzip");-- data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }- data->pdata = __archive_write_program_allocate("lrzip");- if (data->pdata == NULL) {- free(data);- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }-- f->name = "lrzip";- f->code = ARCHIVE_FILTER_LRZIP;- f->data = data;- f->open = archive_write_lrzip_open;- f->options = archive_write_lrzip_options;- f->write = archive_write_lrzip_write;- f->close = archive_write_lrzip_close;- f->free = archive_write_lrzip_free;-- /* Note: This filter always uses an external program, so we- * return "warn" to inform of the fact. */- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external lrzip program for lrzip compression");- return (ARCHIVE_WARN);-}--static int-archive_write_lrzip_options(struct archive_write_filter *f, const char *key,- const char *value)-{- struct write_lrzip *data = (struct write_lrzip *)f->data;-- if (strcmp(key, "compression") == 0) {- if (value == NULL)- return (ARCHIVE_WARN);- else if (strcmp(value, "bzip2") == 0)- data->compression = bzip2;- else if (strcmp(value, "gzip") == 0)- data->compression = gzip;- else if (strcmp(value, "lzo") == 0)- data->compression = lzo;- else if (strcmp(value, "none") == 0)- data->compression = none;- else if (strcmp(value, "zpaq") == 0)- data->compression = zpaq;- else- return (ARCHIVE_WARN);- return (ARCHIVE_OK);- } else if (strcmp(key, "compression-level") == 0) {- if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||- value[1] != '\0')- return (ARCHIVE_WARN);- data->compression_level = value[0] - '0';- return (ARCHIVE_OK);- }- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-archive_write_lrzip_open(struct archive_write_filter *f)-{- struct write_lrzip *data = (struct write_lrzip *)f->data;- struct archive_string as;- int r;-- archive_string_init(&as);- archive_strcpy(&as, "lrzip -q");-- /* Specify compression type. */- switch (data->compression) {- case lzma:/* default compression */- break;- case bzip2:- archive_strcat(&as, " -b");- break;- case gzip:- archive_strcat(&as, " -g");- break;- case lzo:- archive_strcat(&as, " -l");- break;- case none:- archive_strcat(&as, " -n");- break;- case zpaq:- archive_strcat(&as, " -z");- break;- }-- /* Specify compression level. */- if (data->compression_level > 0) {- archive_strcat(&as, " -L ");- archive_strappend_char(&as, '0' + data->compression_level);- }-- r = __archive_write_program_open(f, data->pdata, as.s);- archive_string_free(&as);- return (r);-}--static int-archive_write_lrzip_write(struct archive_write_filter *f,- const void *buff, size_t length)-{- struct write_lrzip *data = (struct write_lrzip *)f->data;-- return __archive_write_program_write(f, data->pdata, buff, length);-}--static int-archive_write_lrzip_close(struct archive_write_filter *f)-{- struct write_lrzip *data = (struct write_lrzip *)f->data;-- return __archive_write_program_close(f, data->pdata);-}--static int-archive_write_lrzip_free(struct archive_write_filter *f)-{- struct write_lrzip *data = (struct write_lrzip *)f->data;-- __archive_write_program_free(data->pdata);- free(data);- return (ARCHIVE_OK);-}
− c/archive_write_add_filter_lz4.c
@@ -1,700 +0,0 @@-/*-- * Copyright (c) 2014 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#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_LZ4_H-#include <lz4.h>-#endif-#ifdef HAVE_LZ4HC_H-#include <lz4hc.h>-#endif--#include "archive.h"-#include "archive_endian.h"-#include "archive_private.h"-#include "archive_write_private.h"-#include "archive_xxhash.h"--#define LZ4_MAGICNUMBER 0x184d2204--struct private_data {- int compression_level;- unsigned header_written:1;- unsigned version_number:1;- unsigned block_independence:1;- unsigned block_checksum:1;- unsigned stream_size:1;- unsigned stream_checksum:1;- unsigned preset_dictionary:1;- unsigned block_maximum_size:3;-#if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2- int64_t total_in;- char *out;- char *out_buffer;- size_t out_buffer_size;- size_t out_block_size;- char *in;- char *in_buffer_allocated;- char *in_buffer;- size_t in_buffer_size;- size_t block_size;-- void *xxh32_state;- void *lz4_stream;-#else- struct archive_write_program_data *pdata;-#endif-};--static int archive_filter_lz4_close(struct archive_write_filter *);-static int archive_filter_lz4_free(struct archive_write_filter *);-static int archive_filter_lz4_open(struct archive_write_filter *);-static int archive_filter_lz4_options(struct archive_write_filter *,- const char *, const char *);-static int archive_filter_lz4_write(struct archive_write_filter *,- const void *, size_t);--/*- * Add a lz4 compression filter to this write handle.- */-int-archive_write_add_filter_lz4(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_add_filter_lz4");-- data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }-- /*- * Setup default settings.- */- data->compression_level = 1;- data->version_number = 0x01;- data->block_independence = 1;- data->block_checksum = 0;- data->stream_size = 0;- data->stream_checksum = 1;- data->preset_dictionary = 0;- data->block_maximum_size = 7;-- /*- * Setup a filter setting.- */- f->data = data;- f->options = &archive_filter_lz4_options;- f->close = &archive_filter_lz4_close;- f->free = &archive_filter_lz4_free;- f->open = &archive_filter_lz4_open;- f->code = ARCHIVE_FILTER_LZ4;- f->name = "lz4";-#if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2- return (ARCHIVE_OK);-#else- /*- * We don't have lz4 library, and execute external lz4 program- * instead.- */- data->pdata = __archive_write_program_allocate("lz4");- if (data->pdata == NULL) {- free(data);- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- data->compression_level = 0;- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Using external lz4 program");- return (ARCHIVE_WARN);-#endif-}--/*- * Set write options.- */-static int-archive_filter_lz4_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) {- int val;- if (value == NULL || !((val = value[0] - '0') >= 1 && val <= 9) ||- value[1] != '\0')- return (ARCHIVE_WARN);--#ifndef HAVE_LZ4HC_H- if(val >= 3)- {- archive_set_error(f->archive, ARCHIVE_ERRNO_PROGRAMMER,- "High compression not included in this build");- return (ARCHIVE_FATAL);- }-#endif- data->compression_level = val;- return (ARCHIVE_OK);- }- if (strcmp(key, "stream-checksum") == 0) {- data->stream_checksum = value != NULL;- return (ARCHIVE_OK);- }- if (strcmp(key, "block-checksum") == 0) {- data->block_checksum = value != NULL;- return (ARCHIVE_OK);- }- if (strcmp(key, "block-size") == 0) {- if (value == NULL || !(value[0] >= '4' && value[0] <= '7') ||- value[1] != '\0')- return (ARCHIVE_WARN);- data->block_maximum_size = value[0] - '0';- return (ARCHIVE_OK);- }- if (strcmp(key, "block-dependence") == 0) {- data->block_independence = value == NULL;- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--#if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2-/* Don't compile this if we don't have liblz4. */--static int drive_compressor(struct archive_write_filter *, const char *,- size_t);-static int drive_compressor_independence(struct archive_write_filter *,- const char *, size_t);-static int drive_compressor_dependence(struct archive_write_filter *,- const char *, size_t);-static int lz4_write_stream_descriptor(struct archive_write_filter *);-static ssize_t lz4_write_one_block(struct archive_write_filter *, const char *,- size_t);---/*- * Setup callback.- */-static int-archive_filter_lz4_open(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;- size_t required_size;- static size_t const bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024,- 4 * 1024 * 1024 };- size_t pre_block_size;-- if (data->block_maximum_size < 4)- data->block_size = bkmap[0];- else- data->block_size = bkmap[data->block_maximum_size - 4];-- required_size = 4 + 15 + 4 + data->block_size + 4 + 4;- if (data->out_buffer_size < required_size) {- size_t bs = required_size, bpb;- free(data->out_buffer);- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {- /* Buffer size should be a multiple number of- * the of bytes per block for performance. */- bpb = archive_write_get_bytes_per_block(f->archive);- if (bpb > bs)- bs = bpb;- else if (bpb != 0) {- bs += bpb;- bs -= bs % bpb;- }- }- data->out_block_size = bs;- bs += required_size;- data->out_buffer = malloc(bs);- data->out = data->out_buffer;- data->out_buffer_size = bs;- }-- pre_block_size = (data->block_independence)? 0: 64 * 1024;- if (data->in_buffer_size < data->block_size + pre_block_size) {- free(data->in_buffer_allocated);- data->in_buffer_size = data->block_size;- data->in_buffer_allocated =- malloc(data->in_buffer_size + pre_block_size);- data->in_buffer = data->in_buffer_allocated + pre_block_size;- if (!data->block_independence && data->compression_level >= 3)- data->in_buffer = data->in_buffer_allocated;- data->in = data->in_buffer;- data->in_buffer_size = data->block_size;- }-- if (data->out_buffer == NULL || data->in_buffer_allocated == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for compression buffer");- return (ARCHIVE_FATAL);- }-- f->write = archive_filter_lz4_write;-- return (ARCHIVE_OK);-}--/*- * Write data to the out stream.- *- * Returns ARCHIVE_OK if all data written, error otherwise.- */-static int-archive_filter_lz4_write(struct archive_write_filter *f,- const void *buff, size_t length)-{- struct private_data *data = (struct private_data *)f->data;- int ret = ARCHIVE_OK;- const char *p;- size_t remaining;- ssize_t size;-- /* If we haven't written a stream descriptor, we have to do it first. */- if (!data->header_written) {- ret = lz4_write_stream_descriptor(f);- if (ret != ARCHIVE_OK)- return (ret);- data->header_written = 1;- }-- /* Update statistics */- data->total_in += length;-- p = (const char *)buff;- remaining = length;- while (remaining) {- size_t l;- /* Compress input data to output buffer */- size = lz4_write_one_block(f, p, remaining);- if (size < ARCHIVE_OK)- return (ARCHIVE_FATAL);- l = data->out - data->out_buffer;- if (l >= data->out_block_size) {- ret = __archive_write_filter(f->next_filter,- data->out_buffer, data->out_block_size);- l -= data->out_block_size;- memcpy(data->out_buffer,- data->out_buffer + data->out_block_size, l);- data->out = data->out_buffer + l;- if (ret < ARCHIVE_WARN)- break;- }- p += size;- remaining -= size;- }-- return (ret);-}--/*- * Finish the compression.- */-static int-archive_filter_lz4_close(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;- int ret;-- /* Finish compression cycle. */- ret = (int)lz4_write_one_block(f, NULL, 0);- if (ret >= 0) {- /*- * Write the last block and the end of the stream data.- */-- /* Write End Of Stream. */- memset(data->out, 0, 4); data->out += 4;- /* Write Stream checksum if needed. */- if (data->stream_checksum) {- unsigned int checksum;- checksum = __archive_xxhash.XXH32_digest(- data->xxh32_state);- data->xxh32_state = NULL;- archive_le32enc(data->out, checksum);- data->out += 4;- }- ret = __archive_write_filter(f->next_filter,- data->out_buffer, data->out - data->out_buffer);- }- return ret;-}--static int-archive_filter_lz4_free(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- if (data->lz4_stream != NULL) {-#ifdef HAVE_LZ4HC_H- if (data->compression_level >= 3)-#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- LZ4_freeStreamHC(data->lz4_stream);-#else- LZ4_freeHC(data->lz4_stream);-#endif- else-#endif-#if LZ4_VERSION_MINOR >= 3- LZ4_freeStream(data->lz4_stream);-#else- LZ4_free(data->lz4_stream);-#endif- }- free(data->out_buffer);- free(data->in_buffer_allocated);- free(data->xxh32_state);- free(data);- f->data = NULL;- return (ARCHIVE_OK);-}--static int-lz4_write_stream_descriptor(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;- uint8_t *sd;-- sd = (uint8_t *)data->out;- /* Write Magic Number. */- archive_le32enc(&sd[0], LZ4_MAGICNUMBER);- /* FLG */- sd[4] = (data->version_number << 6)- | (data->block_independence << 5)- | (data->block_checksum << 4)- | (data->stream_size << 3)- | (data->stream_checksum << 2)- | (data->preset_dictionary << 0);- /* BD */- sd[5] = (data->block_maximum_size << 4);- sd[6] = (__archive_xxhash.XXH32(&sd[4], 2, 0) >> 8) & 0xff;- data->out += 7;- if (data->stream_checksum)- data->xxh32_state = __archive_xxhash.XXH32_init(0);- else- data->xxh32_state = NULL;- return (ARCHIVE_OK);-}--static ssize_t-lz4_write_one_block(struct archive_write_filter *f, const char *p,- size_t length)-{- struct private_data *data = (struct private_data *)f->data;- ssize_t r;-- if (p == NULL) {- /* Compress remaining uncompressed data. */- if (data->in_buffer == data->in)- return 0;- else {- size_t l = data->in - data->in_buffer;- r = drive_compressor(f, data->in_buffer, l);- if (r == ARCHIVE_OK)- r = (ssize_t)l;- }- } else if ((data->block_independence || data->compression_level < 3) &&- data->in_buffer == data->in && length >= data->block_size) {- r = drive_compressor(f, p, data->block_size);- if (r == ARCHIVE_OK)- r = (ssize_t)data->block_size;- } else {- size_t remaining_size = data->in_buffer_size -- (data->in - data->in_buffer);- size_t l = (remaining_size > length)? length: remaining_size;- memcpy(data->in, p, l);- data->in += l;- if (l == remaining_size) {- r = drive_compressor(f, data->in_buffer,- data->block_size);- if (r == ARCHIVE_OK)- r = (ssize_t)l;- data->in = data->in_buffer;- } else- r = (ssize_t)l;- }-- return (r);-}---/*- * 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, const char *p, size_t length)-{- struct private_data *data = (struct private_data *)f->data;-- if (data->stream_checksum)- __archive_xxhash.XXH32_update(data->xxh32_state,- p, (int)length);- if (data->block_independence)- return drive_compressor_independence(f, p, length);- else- return drive_compressor_dependence(f, p, length);-}--static int-drive_compressor_independence(struct archive_write_filter *f, const char *p,- size_t length)-{- struct private_data *data = (struct private_data *)f->data;- unsigned int outsize;--#ifdef HAVE_LZ4HC_H- if (data->compression_level >= 3)-#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- outsize = LZ4_compress_HC(p, data->out + 4,- (int)length, (int)data->block_size,- data->compression_level);-#else- outsize = LZ4_compressHC2_limitedOutput(p, data->out + 4,- (int)length, (int)data->block_size,- data->compression_level);-#endif- else-#endif-#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- outsize = LZ4_compress_default(p, data->out + 4,- (int)length, (int)data->block_size);-#else- outsize = LZ4_compress_limitedOutput(p, data->out + 4,- (int)length, (int)data->block_size);-#endif-- if (outsize) {- /* The buffer is compressed. */- archive_le32enc(data->out, outsize);- data->out += 4;- } else {- /* The buffer is not compressed. The compressed size was- * bigger than its uncompressed size. */- archive_le32enc(data->out, (uint32_t)(length | 0x80000000));- data->out += 4;- memcpy(data->out, p, length);- outsize = (uint32_t)length;- }- data->out += outsize;- if (data->block_checksum) {- unsigned int checksum =- __archive_xxhash.XXH32(data->out - outsize, outsize, 0);- archive_le32enc(data->out, checksum);- data->out += 4;- }- return (ARCHIVE_OK);-}--static int-drive_compressor_dependence(struct archive_write_filter *f, const char *p,- size_t length)-{- struct private_data *data = (struct private_data *)f->data;- int outsize;--#define DICT_SIZE (64 * 1024)-#ifdef HAVE_LZ4HC_H- if (data->compression_level >= 3) {- if (data->lz4_stream == NULL) {-#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- data->lz4_stream = LZ4_createStreamHC();- LZ4_resetStreamHC(data->lz4_stream, data->compression_level);-#else- data->lz4_stream =- LZ4_createHC(data->in_buffer_allocated);-#endif- if (data->lz4_stream == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for compression"- " buffer");- return (ARCHIVE_FATAL);- }- }- else- LZ4_loadDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);--#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- outsize = LZ4_compress_HC_continue(- data->lz4_stream, p, data->out + 4, (int)length,- (int)data->block_size);-#else- outsize = LZ4_compressHC2_limitedOutput_continue(- data->lz4_stream, p, data->out + 4, (int)length,- (int)data->block_size, data->compression_level);-#endif- } else-#endif- {- if (data->lz4_stream == NULL) {- data->lz4_stream = LZ4_createStream();- if (data->lz4_stream == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for compression"- " buffer");- return (ARCHIVE_FATAL);- }- }- else- LZ4_loadDict(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);--#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- outsize = LZ4_compress_fast_continue(- data->lz4_stream, p, data->out + 4, (int)length,- (int)data->block_size, 1);-#else- outsize = LZ4_compress_limitedOutput_continue(- data->lz4_stream, p, data->out + 4, (int)length,- (int)data->block_size);-#endif- }-- if (outsize) {- /* The buffer is compressed. */- archive_le32enc(data->out, outsize);- data->out += 4;- } else {- /* The buffer is not compressed. The compressed size was- * bigger than its uncompressed size. */- archive_le32enc(data->out, (uint32_t)(length | 0x80000000));- data->out += 4;- memcpy(data->out, p, length);- outsize = (uint32_t)length;- }- data->out += outsize;- if (data->block_checksum) {- unsigned int checksum =- __archive_xxhash.XXH32(data->out - outsize, outsize, 0);- archive_le32enc(data->out, checksum);- data->out += 4;- }-- if (length == data->block_size) {-#ifdef HAVE_LZ4HC_H- if (data->compression_level >= 3) {-#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7- LZ4_saveDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);-#else- LZ4_slideInputBufferHC(data->lz4_stream);-#endif- data->in_buffer = data->in_buffer_allocated + DICT_SIZE;- }- else-#endif- LZ4_saveDict(data->lz4_stream,- data->in_buffer_allocated, DICT_SIZE);-#undef DICT_SIZE- }- return (ARCHIVE_OK);-}--#else /* HAVE_LIBLZ4 */--static int-archive_filter_lz4_open(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;- struct archive_string as;- int r;-- archive_string_init(&as);- archive_strcpy(&as, "lz4 -z -q -q");-- /* Specify a compression level. */- if (data->compression_level > 0) {- archive_strcat(&as, " -");- archive_strappend_char(&as, '0' + data->compression_level);- }- /* Specify a block size. */- archive_strcat(&as, " -B");- archive_strappend_char(&as, '0' + data->block_maximum_size);-- if (data->block_checksum)- archive_strcat(&as, " -BX");- if (data->stream_checksum == 0)- archive_strcat(&as, " --no-frame-crc");- if (data->block_independence == 0)- archive_strcat(&as, " -BD");-- f->write = archive_filter_lz4_write;-- r = __archive_write_program_open(f, data->pdata, as.s);- archive_string_free(&as);- return (r);-}--static int-archive_filter_lz4_write(struct archive_write_filter *f, const void *buff,- size_t length)-{- struct private_data *data = (struct private_data *)f->data;-- return __archive_write_program_write(f, data->pdata, buff, length);-}--static int-archive_filter_lz4_close(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- return __archive_write_program_close(f, data->pdata);-}--static int-archive_filter_lz4_free(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- __archive_write_program_free(data->pdata);- free(data);- return (ARCHIVE_OK);-}--#endif /* HAVE_LIBLZ4 */
− c/archive_write_add_filter_lzop.c
@@ -1,478 +0,0 @@-/*-- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");-//#undef HAVE_LZO_LZOCONF_H-//#undef HAVE_LZO_LZO1X_H--#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_LZO_LZOCONF_H-#include <lzo/lzoconf.h>-#endif-#ifdef HAVE_LZO_LZO1X_H-#include <lzo/lzo1x.h>-#endif--#include "archive.h"-#include "archive_string.h"-#include "archive_endian.h"-#include "archive_write_private.h"--enum lzo_method {- METHOD_LZO1X_1 = 1,- METHOD_LZO1X_1_15 = 2,- METHOD_LZO1X_999 = 3-};-struct write_lzop {- int compression_level;-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)- unsigned char *uncompressed;- size_t uncompressed_buffer_size;- size_t uncompressed_avail_bytes;- unsigned char *compressed;- size_t compressed_buffer_size;- enum lzo_method method;- unsigned char level;- lzo_voidp work_buffer;- lzo_uint32 work_buffer_size;- char header_written;-#else- struct archive_write_program_data *pdata;-#endif-};--static int archive_write_lzop_open(struct archive_write_filter *);-static int archive_write_lzop_options(struct archive_write_filter *,- const char *, const char *);-static int archive_write_lzop_write(struct archive_write_filter *,- const void *, size_t);-static int archive_write_lzop_close(struct archive_write_filter *);-static int archive_write_lzop_free(struct archive_write_filter *);--#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)-/* Maximum block size. */-#define BLOCK_SIZE (256 * 1024)-/* Block information is composed of uncompressed size(4 bytes),- * compressed size(4 bytes) and the checksum of uncompressed data(4 bytes)- * in this lzop writer. */-#define BLOCK_INfO_SIZE 12--#define HEADER_VERSION 9-#define HEADER_LIBVERSION 11-#define HEADER_METHOD 15-#define HEADER_LEVEL 16-#define HEADER_MTIME_LOW 25-#define HEADER_MTIME_HIGH 29-#define HEADER_H_CHECKSUM 34--/*- * Header template.- */-static const unsigned char header[] = {- /* LZOP Magic code 9 bytes */- 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a,- /* LZOP utility version(fake data) 2 bytes */- 0x10, 0x30,- /* LZO library version 2 bytes */- 0x09, 0x40,- /* Minimum required LZO library version 2 bytes */- 0x09, 0x40,- /* Method */- 1,- /* Level */- 5,- /* Flags 4 bytes- * -OS Unix- * -Stdout- * -Stdin- * -Adler32 used for uncompressed data 4 bytes */- 0x03, 0x00, 0x00, 0x0d,- /* Mode (AE_IFREG | 0644) 4 bytes */- 0x00, 0x00, 0x81, 0xa4,- /* Mtime low 4 bytes */- 0x00, 0x00, 0x00, 0x00,- /* Mtime high 4 bytes */- 0x00, 0x00, 0x00, 0x00,- /* Filename length */- 0x00,- /* Header checksum 4 bytes */- 0x00, 0x00, 0x00, 0x00,-};-#endif--int-archive_write_add_filter_lzop(struct archive *_a)-{- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct write_lzop *data;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_lzop");-- data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }-- f->name = "lzop";- f->code = ARCHIVE_FILTER_LZOP;- f->data = data;- f->open = archive_write_lzop_open;- f->options = archive_write_lzop_options;- f->write = archive_write_lzop_write;- f->close = archive_write_lzop_close;- f->free = archive_write_lzop_free;-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)- if (lzo_init() != LZO_E_OK) {- free(data);- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "lzo_init(type check) failed");- return (ARCHIVE_FATAL);- }- if (lzo_version() < 0x940) {- free(data);- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "liblzo library is too old(%s < 0.940)",- lzo_version_string());- return (ARCHIVE_FATAL);- }- data->compression_level = 5;- return (ARCHIVE_OK);-#else- data->pdata = __archive_write_program_allocate("lzop");- if (data->pdata == NULL) {- free(data);- archive_set_error(_a, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }- data->compression_level = 0;- /* Note: We return "warn" to inform of using an external lzop- * program. */- archive_set_error(_a, ARCHIVE_ERRNO_MISC,- "Using external lzop program for lzop compression");- return (ARCHIVE_WARN);-#endif-}--static int-archive_write_lzop_free(struct archive_write_filter *f)-{- struct write_lzop *data = (struct write_lzop *)f->data;--#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)- free(data->uncompressed);- free(data->compressed);- free(data->work_buffer);-#else- __archive_write_program_free(data->pdata);-#endif- free(data);- return (ARCHIVE_OK);-}--static int-archive_write_lzop_options(struct archive_write_filter *f, const char *key,- const char *value)-{- struct write_lzop *data = (struct write_lzop *)f->data;-- if (strcmp(key, "compression-level") == 0) {- if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||- value[1] != '\0')- return (ARCHIVE_WARN);- data->compression_level = value[0] - '0';- return (ARCHIVE_OK);- }- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)-static int-archive_write_lzop_open(struct archive_write_filter *f)-{- struct write_lzop *data = (struct write_lzop *)f->data;-- switch (data->compression_level) {- case 1:- data->method = METHOD_LZO1X_1_15; data->level = 1; break;- default:- case 2: case 3: case 4: case 5: case 6:- data->method = METHOD_LZO1X_1; data->level = 5; break;- case 7:- data->method = METHOD_LZO1X_999; data->level = 7; break;- case 8:- data->method = METHOD_LZO1X_999; data->level = 8; break;- case 9:- data->method = METHOD_LZO1X_999; data->level = 9; break;- }- switch (data->method) {- case METHOD_LZO1X_1:- data->work_buffer_size = LZO1X_1_MEM_COMPRESS; break;- case METHOD_LZO1X_1_15:- data->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break;- case METHOD_LZO1X_999:- data->work_buffer_size = LZO1X_999_MEM_COMPRESS; break;- }- if (data->work_buffer == NULL) {- data->work_buffer = (lzo_voidp)malloc(data->work_buffer_size);- if (data->work_buffer == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for compression buffer");- return (ARCHIVE_FATAL);- }- }- if (data->compressed == NULL) {- data->compressed_buffer_size = sizeof(header) +- BLOCK_SIZE + (BLOCK_SIZE >> 4) + 64 + 3;- 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);- }- }- if (data->uncompressed == NULL) {- data->uncompressed_buffer_size = BLOCK_SIZE;- data->uncompressed = (unsigned char *)- malloc(data->uncompressed_buffer_size);- if (data->uncompressed == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for compression buffer");- return (ARCHIVE_FATAL);- }- data->uncompressed_avail_bytes = BLOCK_SIZE;- }- return (ARCHIVE_OK);-}--static int-make_header(struct archive_write_filter *f)-{- struct write_lzop *data = (struct write_lzop *)f->data;- int64_t t;- uint32_t checksum;-- memcpy(data->compressed, header, sizeof(header));- /* Overwrite library version. */- data->compressed[HEADER_LIBVERSION] = (unsigned char )- (lzo_version() >> 8) & 0xff;- data->compressed[HEADER_LIBVERSION + 1] = (unsigned char )- lzo_version() & 0xff;- /* Overwrite method and level. */- data->compressed[HEADER_METHOD] = (unsigned char)data->method;- data->compressed[HEADER_LEVEL] = data->level;- /* Overwrite mtime with current time. */- t = (int64_t)time(NULL);- archive_be32enc(&data->compressed[HEADER_MTIME_LOW],- (uint32_t)(t & 0xffffffff));- archive_be32enc(&data->compressed[HEADER_MTIME_HIGH],- (uint32_t)((t >> 32) & 0xffffffff));- /* Overwrite header checksum with calculated value. */- checksum = lzo_adler32(1, data->compressed + HEADER_VERSION,- (lzo_uint)(HEADER_H_CHECKSUM - HEADER_VERSION));- archive_be32enc(&data->compressed[HEADER_H_CHECKSUM], checksum);- return (sizeof(header));-}--static int-drive_compressor(struct archive_write_filter *f)-{- struct write_lzop *data = (struct write_lzop *)f->data;- unsigned char *p;- const int block_info_bytes = 12;- int header_bytes, r;- lzo_uint usize, csize;- uint32_t checksum;-- if (!data->header_written) {- header_bytes = make_header(f);- data->header_written = 1;- } else- header_bytes = 0;- p = data->compressed;-- usize = (lzo_uint)- (data->uncompressed_buffer_size - data->uncompressed_avail_bytes);- csize = 0;- switch (data->method) {- default:- case METHOD_LZO1X_1:- r = lzo1x_1_compress(data->uncompressed, usize,- p + header_bytes + block_info_bytes, &csize,- data->work_buffer);- break;- case METHOD_LZO1X_1_15:- r = lzo1x_1_15_compress(data->uncompressed, usize,- p + header_bytes + block_info_bytes, &csize,- data->work_buffer);- break;- case METHOD_LZO1X_999:- r = lzo1x_999_compress_level(data->uncompressed, usize,- p + header_bytes + block_info_bytes, &csize,- data->work_buffer, NULL, 0, 0, data->level);- break;- }- if (r != LZO_E_OK) {- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,- "Lzop compression failed: returned status %d", r);- return (ARCHIVE_FATAL);- }-- /* Store uncompressed size. */- archive_be32enc(p + header_bytes, (uint32_t)usize);- /* Store the checksum of the uncompressed data. */- checksum = lzo_adler32(1, data->uncompressed, usize);- archive_be32enc(p + header_bytes + 8, checksum);-- if (csize < usize) {- /* Store compressed size. */- archive_be32enc(p + header_bytes + 4, (uint32_t)csize);- r = __archive_write_filter(f->next_filter, data->compressed,- header_bytes + block_info_bytes + csize);- } else {- /*- * This case, we output uncompressed data instead.- */- /* Store uncompressed size as compressed size. */- archive_be32enc(p + header_bytes + 4, (uint32_t)usize);- r = __archive_write_filter(f->next_filter, data->compressed,- header_bytes + block_info_bytes);- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);- r = __archive_write_filter(f->next_filter, data->uncompressed,- usize);- }-- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);- return (ARCHIVE_OK);-}--static int-archive_write_lzop_write(struct archive_write_filter *f,- const void *buff, size_t length)-{- struct write_lzop *data = (struct write_lzop *)f->data;- const char *p = buff;- int r;-- do {- if (data->uncompressed_avail_bytes > length) {- memcpy(data->uncompressed- + data->uncompressed_buffer_size- - data->uncompressed_avail_bytes,- p, length);- data->uncompressed_avail_bytes -= length;- return (ARCHIVE_OK);- }-- memcpy(data->uncompressed + data->uncompressed_buffer_size- - data->uncompressed_avail_bytes,- p, data->uncompressed_avail_bytes);- length -= data->uncompressed_avail_bytes;- p += data->uncompressed_avail_bytes;- data->uncompressed_avail_bytes = 0;-- r = drive_compressor(f);- if (r != ARCHIVE_OK) return (r);- data->uncompressed_avail_bytes = BLOCK_SIZE;- } while (length);-- return (ARCHIVE_OK);-}--static int-archive_write_lzop_close(struct archive_write_filter *f)-{- struct write_lzop *data = (struct write_lzop *)f->data;- const uint32_t endmark = 0;- int r;-- if (data->uncompressed_avail_bytes < BLOCK_SIZE) {- /* Compress and output remaining data. */- r = drive_compressor(f);- if (r != ARCHIVE_OK)- return (r);- }- /* Write a zero uncompressed size as the end mark of the series of- * compressed block. */- return __archive_write_filter(f->next_filter, &endmark, sizeof(endmark));-}--#else-static int-archive_write_lzop_open(struct archive_write_filter *f)-{- struct write_lzop *data = (struct write_lzop *)f->data;- struct archive_string as;- int r;-- archive_string_init(&as);- archive_strcpy(&as, "lzop");- /* Specify compression level. */- if (data->compression_level > 0) {- archive_strappend_char(&as, ' ');- archive_strappend_char(&as, '-');- archive_strappend_char(&as, '0' + data->compression_level);- }-- r = __archive_write_program_open(f, data->pdata, as.s);- archive_string_free(&as);- return (r);-}--static int-archive_write_lzop_write(struct archive_write_filter *f,- const void *buff, size_t length)-{- struct write_lzop *data = (struct write_lzop *)f->data;-- return __archive_write_program_write(f, data->pdata, buff, length);-}--static int-archive_write_lzop_close(struct archive_write_filter *f)-{- struct write_lzop *data = (struct write_lzop *)f->data;-- return __archive_write_program_close(f, data->pdata);-}-#endif
− c/archive_write_add_filter_none.c
@@ -1,43 +0,0 @@-/*-- * 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_none.c 201080 2009-12-28 02:03:54Z kientzle $");--#include "archive.h"--int-archive_write_set_compression_none(struct archive *a)-{- (void)a; /* UNUSED */- return (ARCHIVE_OK);-}--int-archive_write_add_filter_none(struct archive *a)-{- (void)a; /* UNUSED */- return (ARCHIVE_OK);-}
− c/archive_write_add_filter_program.c
@@ -1,391 +0,0 @@-/*-- * Copyright (c) 2007 Joerg Sonnenberger- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#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_string.h"-#include "archive_write_private.h"-#include "filter_fork.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--struct archive_write_program_data {-#if defined(_WIN32) && !defined(__CYGWIN__)- HANDLE child;-#else- pid_t child;-#endif- int child_stdin, child_stdout;-- char *child_buf;- size_t child_buf_len, child_buf_avail;- char *program_name;-};--struct private_data {- struct archive_write_program_data *pdata;- struct archive_string description;- char *cmd;-};--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 private_data *data;- static const char prefix[] = "Program: ";-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_program");-- f->data = calloc(1, sizeof(*data));- if (f->data == NULL)- goto memerr;- data = (struct private_data *)f->data;-- data->cmd = strdup(cmd);- if (data->cmd == NULL)- goto memerr;-- data->pdata = __archive_write_program_allocate(cmd);- if (data->pdata == NULL)- goto memerr;-- /* Make up a description string. */- if (archive_string_ensure(&data->description,- strlen(prefix) + strlen(cmd) + 1) == NULL)- goto memerr;- archive_strcpy(&data->description, prefix);- archive_strcat(&data->description, cmd);-- f->name = data->description.s;- f->code = ARCHIVE_FILTER_PROGRAM;- f->open = archive_compressor_program_open;- f->write = archive_compressor_program_write;- f->close = archive_compressor_program_close;- f->free = archive_compressor_program_free;- return (ARCHIVE_OK);-memerr:- archive_compressor_program_free(f);- archive_set_error(_a, ENOMEM,- "Can't allocate memory for filter program");- return (ARCHIVE_FATAL);-}--static int-archive_compressor_program_open(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- return __archive_write_program_open(f, data->pdata, data->cmd);-}--static int-archive_compressor_program_write(struct archive_write_filter *f,- const void *buff, size_t length)-{- struct private_data *data = (struct private_data *)f->data;-- return __archive_write_program_write(f, data->pdata, buff, length);-}--static int-archive_compressor_program_close(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- return __archive_write_program_close(f, data->pdata);-}--static int-archive_compressor_program_free(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- if (data) {- free(data->cmd);- archive_string_free(&data->description);- __archive_write_program_free(data->pdata);- free(data);- f->data = NULL;- }- return (ARCHIVE_OK);-}--/*- * Allocate resources for executing an external program.- */-struct archive_write_program_data *-__archive_write_program_allocate(const char *program)-{- struct archive_write_program_data *data;-- data = calloc(1, sizeof(struct archive_write_program_data));- if (data == NULL)- return (data);- data->child_stdin = -1;- data->child_stdout = -1;- data->program_name = strdup(program);- return (data);-}--/*- * Release the resources.- */-int-__archive_write_program_free(struct archive_write_program_data *data)-{-- if (data) {- free(data->program_name);- free(data->child_buf);- free(data);- }- return (ARCHIVE_OK);-}--int-__archive_write_program_open(struct archive_write_filter *f,- struct archive_write_program_data *data, const char *cmd)-{- int 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);- }- }-- ret = __archive_create_child(cmd, &data->child_stdin,- &data->child_stdout, &data->child);- if (ret != ARCHIVE_OK) {- archive_set_error(f->archive, EINVAL,- "Can't launch external program: %s", cmd);- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}--static ssize_t-child_write(struct archive_write_filter *f,- struct archive_write_program_data *data, const char *buf, size_t buf_len)-{- ssize_t ret;-- if (data->child_stdin == -1)- return (-1);-- if (buf_len == 0)- return (-1);-- for (;;) {- 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);- continue;- }-- 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);- continue;- }- if (ret == -1 && errno == EAGAIN) {- __archive_check_child(data->child_stdin,- data->child_stdout);- continue;- }- 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 != ARCHIVE_OK)- return (-1);- data->child_buf_avail = 0;- }-}--/*- * Write data to the filter stream.- */-int-__archive_write_program_write(struct archive_write_filter *f,- struct archive_write_program_data *data, const void *buff, size_t length)-{- ssize_t ret;- const char *buf;-- if (data->child == 0)- return (ARCHIVE_OK);-- buf = buff;- while (length > 0) {- ret = child_write(f, data, buf, length);- if (ret == -1 || ret == 0) {- archive_set_error(f->archive, EIO,- "Can't write to program: %s", data->program_name);- return (ARCHIVE_FATAL);- }- length -= ret;- buf += ret;- }- return (ARCHIVE_OK);-}--/*- * Finish the filtering...- */-int-__archive_write_program_close(struct archive_write_filter *f,- struct archive_write_program_data *data)-{- int ret, status;- ssize_t bytes_read;-- if (data->child == 0)- return ARCHIVE_OK;-- 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,- "Error reading from program: %s", data->program_name);- 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 defined(_WIN32) && !defined(__CYGWIN__)- CloseHandle(data->child);-#endif- data->child = 0;-- if (status != 0) {- archive_set_error(f->archive, EIO,- "Error closing program: %s", data->program_name);- ret = ARCHIVE_FATAL;- }- return ret;-}-
− c/archive_write_add_filter_uuencode.c
@@ -1,295 +0,0 @@-/*-- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_string.h"-#include "archive_write_private.h"--#define LBYTES 45--struct private_uuencode {- int mode;- struct archive_string name;- struct archive_string encoded_buff;- size_t bs;- size_t hold_len;- unsigned char hold[LBYTES];-};--static int archive_filter_uuencode_options(struct archive_write_filter *,- const char *, const char *);-static int archive_filter_uuencode_open(struct archive_write_filter *);-static int archive_filter_uuencode_write(struct archive_write_filter *,- const void *, size_t);-static int archive_filter_uuencode_close(struct archive_write_filter *);-static int archive_filter_uuencode_free(struct archive_write_filter *);-static void uu_encode(struct archive_string *, const unsigned char *, size_t);-static int64_t atol8(const char *, size_t);--/*- * Add a compress filter to this write handle.- */-int-archive_write_add_filter_uuencode(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *f = __archive_write_allocate_filter(_a);- struct private_uuencode *state;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");-- state = (struct private_uuencode *)calloc(1, sizeof(*state));- if (state == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for uuencode filter");- return (ARCHIVE_FATAL);- }- archive_strcpy(&state->name, "-");- state->mode = 0644;-- f->data = state;- f->name = "uuencode";- f->code = ARCHIVE_FILTER_UU;- f->open = archive_filter_uuencode_open;- f->options = archive_filter_uuencode_options;- f->write = archive_filter_uuencode_write;- f->close = archive_filter_uuencode_close;- f->free = archive_filter_uuencode_free;-- return (ARCHIVE_OK);-}--/*- * Set write options.- */-static int-archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,- const char *value)-{- struct private_uuencode *state = (struct private_uuencode *)f->data;-- if (strcmp(key, "mode") == 0) {- if (value == NULL) {- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,- "mode option requires octal digits");- return (ARCHIVE_FAILED);- }- state->mode = (int)atol8(value, strlen(value)) & 0777;- return (ARCHIVE_OK);- } else if (strcmp(key, "name") == 0) {- if (value == NULL) {- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,- "name option requires a string");- return (ARCHIVE_FAILED);- }- archive_strcpy(&state->name, value);- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--/*- * Setup callback.- */-static int-archive_filter_uuencode_open(struct archive_write_filter *f)-{- struct private_uuencode *state = (struct private_uuencode *)f->data;- size_t bs = 65536, bpb;-- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {- /* Buffer size should be a multiple number of the of bytes- * per block for performance. */- bpb = archive_write_get_bytes_per_block(f->archive);- if (bpb > bs)- bs = bpb;- else if (bpb != 0)- bs -= bs % bpb;- }-- state->bs = bs;- if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for uuencode buffer");- return (ARCHIVE_FATAL);- }-- archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",- state->mode, state->name.s);-- f->data = state;- return (0);-}--static void-uu_encode(struct archive_string *as, const unsigned char *p, size_t len)-{- int c;-- c = (int)len;- archive_strappend_char(as, c?c + 0x20:'`');- for (; len >= 3; p += 3, len -= 3) {- c = p[0] >> 2;- archive_strappend_char(as, c?c + 0x20:'`');- c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4);- archive_strappend_char(as, c?c + 0x20:'`');- c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6);- archive_strappend_char(as, c?c + 0x20:'`');- c = p[2] & 0x3f;- archive_strappend_char(as, c?c + 0x20:'`');- }- if (len > 0) {- c = p[0] >> 2;- archive_strappend_char(as, c?c + 0x20:'`');- c = (p[0] & 0x03) << 4;- if (len == 1) {- archive_strappend_char(as, c?c + 0x20:'`');- archive_strappend_char(as, '`');- archive_strappend_char(as, '`');- } else {- c |= (p[1] & 0xf0) >> 4;- archive_strappend_char(as, c?c + 0x20:'`');- c = (p[1] & 0x0f) << 2;- archive_strappend_char(as, c?c + 0x20:'`');- archive_strappend_char(as, '`');- }- }- archive_strappend_char(as, '\n');-}--/*- * Write data to the encoded stream.- */-static int-archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff,- size_t length)-{- struct private_uuencode *state = (struct private_uuencode *)f->data;- const unsigned char *p = buff;- int ret = ARCHIVE_OK;-- if (length == 0)- return (ret);-- if (state->hold_len) {- while (state->hold_len < LBYTES && length > 0) {- state->hold[state->hold_len++] = *p++;- length--;- }- if (state->hold_len < LBYTES)- return (ret);- uu_encode(&state->encoded_buff, state->hold, LBYTES);- state->hold_len = 0;- }-- for (; length >= LBYTES; length -= LBYTES, p += LBYTES)- uu_encode(&state->encoded_buff, p, LBYTES);-- /* Save remaining bytes. */- if (length > 0) {- memcpy(state->hold, p, length);- state->hold_len = length;- }- while (archive_strlen(&state->encoded_buff) >= state->bs) {- ret = __archive_write_filter(f->next_filter,- state->encoded_buff.s, state->bs);- memmove(state->encoded_buff.s,- state->encoded_buff.s + state->bs,- state->encoded_buff.length - state->bs);- state->encoded_buff.length -= state->bs;- }-- return (ret);-}---/*- * Finish the compression...- */-static int-archive_filter_uuencode_close(struct archive_write_filter *f)-{- struct private_uuencode *state = (struct private_uuencode *)f->data;-- /* Flush remaining bytes. */- if (state->hold_len != 0)- uu_encode(&state->encoded_buff, state->hold, state->hold_len);- archive_string_sprintf(&state->encoded_buff, "`\nend\n");- /* Write the last block */- archive_write_set_bytes_in_last_block(f->archive, 1);- return __archive_write_filter(f->next_filter,- state->encoded_buff.s, archive_strlen(&state->encoded_buff));-}--static int-archive_filter_uuencode_free(struct archive_write_filter *f)-{- struct private_uuencode *state = (struct private_uuencode *)f->data;-- archive_string_free(&state->name);- archive_string_free(&state->encoded_buff);- free(state);- return (ARCHIVE_OK);-}--static int64_t-atol8(const char *p, size_t char_cnt)-{- int64_t l;- int digit;- - l = 0;- while (char_cnt-- > 0) {- if (*p >= '0' && *p <= '7')- digit = *p - '0';- else- break;- p++;- l <<= 3;- l |= digit;- }- return (l);-}-
− c/archive_write_add_filter_xz.c
@@ -1,545 +0,0 @@-/*-- * Copyright (c) 2003-2010 Tim Kientzle- * Copyright (c) 2009-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#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_endian.h"-#include "archive_private.h"-#include "archive_write_private.h"--#if ARCHIVE_VERSION_NUMBER < 4000000-int-archive_write_set_compression_lzip(struct archive *a)-{- __archive_write_filters_free(a);- return (archive_write_add_filter_lzip(a));-}--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);-}--int-archive_write_add_filter_lzip(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;- uint32_t threads;- lzma_stream stream;- lzma_filter lzmafilters[2];- lzma_options_lzma lzma_opt;- int64_t total_in;- unsigned char *compressed;- size_t compressed_buffer_size;- int64_t total_out;- /* the CRC32 value of uncompressed data for lzip */- uint32_t crc32;-};--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);--struct option_value {- uint32_t dict_size;- uint32_t nice_len;- lzma_match_finder mf;-};-static const struct option_value option_values[] = {- { 1 << 16, 32, LZMA_MF_HC3},- { 1 << 20, 32, LZMA_MF_HC3},- { 3 << 19, 32, LZMA_MF_HC4},- { 1 << 21, 32, LZMA_MF_BT4},- { 3 << 20, 32, LZMA_MF_BT4},- { 1 << 22, 32, LZMA_MF_BT4},- { 1 << 23, 64, LZMA_MF_BT4},- { 1 << 24, 64, LZMA_MF_BT4},- { 3 << 23, 64, LZMA_MF_BT4},- { 1 << 25, 64, LZMA_MF_BT4}-};--static int-common_setup(struct archive_write_filter *f)-{- struct private_data *data;- struct archive_write *a = (struct archive_write *)f->archive;- 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;- data->threads = 1;- 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;- int r;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_xz");- f = __archive_write_allocate_filter(_a);- r = common_setup(f);- if (r == ARCHIVE_OK) {- f->code = ARCHIVE_FILTER_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;- int r;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_lzma");- f = __archive_write_allocate_filter(_a);- r = common_setup(f);- if (r == ARCHIVE_OK) {- f->code = ARCHIVE_FILTER_LZMA;- f->name = "lzma";- }- return (r);-}--int-archive_write_add_filter_lzip(struct archive *_a)-{- struct archive_write_filter *f;- int r;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_add_filter_lzip");- f = __archive_write_allocate_filter(_a);- r = common_setup(f);- if (r == ARCHIVE_OK) {- f->code = ARCHIVE_FILTER_LZIP;- f->name = "lzip";- }- return (r);-}--static int-archive_compressor_xz_init_stream(struct archive_write_filter *f,- struct private_data *data)-{- static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT;- int ret;-#ifdef HAVE_LZMA_STREAM_ENCODER_MT- lzma_mt mt_options;-#endif-- data->stream = lzma_stream_init_data;- data->stream.next_out = data->compressed;- data->stream.avail_out = data->compressed_buffer_size;- if (f->code == ARCHIVE_FILTER_XZ) {-#ifdef HAVE_LZMA_STREAM_ENCODER_MT- if (data->threads != 1) {- memset(&mt_options, 0, sizeof(mt_options));- mt_options.threads = data->threads;- mt_options.timeout = 300;- mt_options.filters = data->lzmafilters;- mt_options.check = LZMA_CHECK_CRC64;- ret = lzma_stream_encoder_mt(&(data->stream),- &mt_options);- } else-#endif- ret = lzma_stream_encoder(&(data->stream),- data->lzmafilters, LZMA_CHECK_CRC64);- } else if (f->code == ARCHIVE_FILTER_LZMA) {- ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt);- } else { /* ARCHIVE_FILTER_LZIP */- int dict_size = data->lzma_opt.dict_size;- int ds, log2dic, wedges;-- /* Calculate a coded dictionary size */- if (dict_size < (1 << 12) || dict_size > (1 << 29)) {- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,- "Unacceptable dictionary size for lzip: %d",- dict_size);- return (ARCHIVE_FATAL);- }- for (log2dic = 29; log2dic >= 12; log2dic--) {- if (dict_size & (1 << log2dic))- break;- }- if (dict_size > (1 << log2dic)) {- log2dic++;- wedges =- ((1 << log2dic) - dict_size) / (1 << (log2dic - 4));- } else- wedges = 0;- ds = ((wedges << 5) & 0xe0) | (log2dic & 0x1f);-- data->crc32 = 0;- /* Make a header */- data->compressed[0] = 0x4C;- data->compressed[1] = 0x5A;- data->compressed[2] = 0x49;- data->compressed[3] = 0x50;- data->compressed[4] = 1;/* Version */- data->compressed[5] = (unsigned char)ds;- data->stream.next_out += 6;- data->stream.avail_out -= 6;-- ret = lzma_raw_encoder(&(data->stream), data->lzmafilters);- }- 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;-- if (data->compressed == NULL) {- size_t bs = 65536, bpb;- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {- /* Buffer size should be a multiple number of the of bytes- * per block for performance. */- bpb = archive_write_get_bytes_per_block(f->archive);- if (bpb > bs)- bs = bpb;- else if (bpb != 0)- bs -= bs % bpb;- }- data->compressed_buffer_size = bs;- 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 (f->code == ARCHIVE_FILTER_LZIP) {- const struct option_value *val =- &option_values[data->compression_level];-- data->lzma_opt.dict_size = val->dict_size;- data->lzma_opt.preset_dict = NULL;- data->lzma_opt.preset_dict_size = 0;- data->lzma_opt.lc = LZMA_LC_DEFAULT;- data->lzma_opt.lp = LZMA_LP_DEFAULT;- data->lzma_opt.pb = LZMA_PB_DEFAULT;- data->lzma_opt.mode =- data->compression_level<= 2? LZMA_MODE_FAST:LZMA_MODE_NORMAL;- data->lzma_opt.nice_len = val->nice_len;- data->lzma_opt.mf = val->mf;- data->lzma_opt.depth = 0;- data->lzmafilters[0].id = LZMA_FILTER_LZMA1;- data->lzmafilters[0].options = &data->lzma_opt;- data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */- } else {- 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 > 9)- data->compression_level = 9;- return (ARCHIVE_OK);- } else if (strcmp(key, "threads") == 0) {- char *endptr;-- if (value == NULL)- return (ARCHIVE_WARN);- errno = 0;- data->threads = (int)strtoul(value, &endptr, 10);- if (errno != 0 || *endptr != '\0') {- data->threads = 1;- return (ARCHIVE_WARN);- }- if (data->threads == 0) {-#ifdef HAVE_LZMA_STREAM_ENCODER_MT- data->threads = lzma_cputhreads();-#else- data->threads = 1;-#endif- }- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- 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;- if (f->code == ARCHIVE_FILTER_LZIP)- data->crc32 = lzma_crc32(buff, length, data->crc32);-- /* 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;-- ret = drive_compressor(f, data, 1);- if (ret == ARCHIVE_OK) {- data->total_out +=- data->compressed_buffer_size - data->stream.avail_out;- ret = __archive_write_filter(f->next_filter,- data->compressed,- data->compressed_buffer_size - data->stream.avail_out);- if (f->code == ARCHIVE_FILTER_LZIP && ret == ARCHIVE_OK) {- archive_le32enc(data->compressed, data->crc32);- archive_le64enc(data->compressed+4, data->total_in);- archive_le64enc(data->compressed+12, data->total_out + 20);- ret = __archive_write_filter(f->next_filter,- data->compressed, 20);- }- }- 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) {- data->total_out += data->compressed_buffer_size;- 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",- (uintmax_t)((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 */
− c/archive_write_add_filter_zstd.c
@@ -1,467 +0,0 @@-/*-- * Copyright (c) 2017 Sean Purcell- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--__FBSDID("$FreeBSD$");---#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STDINT_H-#include <stdint.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_ZSTD_H-#include <zstd.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_string.h"-#include "archive_write_private.h"--/* Don't compile this if we don't have zstd.h */--struct private_data {- int compression_level;- int threads;-#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR- enum {- running,- finishing,- resetting,- } state;- int frame_per_file;- size_t min_frame_size;- size_t max_frame_size;- size_t cur_frame;- size_t cur_frame_in;- size_t cur_frame_out;- size_t total_in;- ZSTD_CStream *cstream;- ZSTD_outBuffer out;-#else- struct archive_write_program_data *pdata;-#endif-};--/* If we don't have the library use default range values (zstdcli.c v1.4.0) */-#define CLEVEL_MIN -99-#define CLEVEL_STD_MIN 0 /* prior to 1.3.4 and more recent without using --fast */-#define CLEVEL_DEFAULT 3-#define CLEVEL_STD_MAX 19 /* without using --ultra */-#define CLEVEL_MAX 22--#define MINVER_NEGCLEVEL 10304-#define MINVER_MINCLEVEL 10306--static int archive_compressor_zstd_options(struct archive_write_filter *,- const char *, const char *);-static int archive_compressor_zstd_open(struct archive_write_filter *);-static int archive_compressor_zstd_write(struct archive_write_filter *,- const void *, size_t);-static int archive_compressor_zstd_flush(struct archive_write_filter *);-static int archive_compressor_zstd_close(struct archive_write_filter *);-static int archive_compressor_zstd_free(struct archive_write_filter *);-#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR-static int drive_compressor(struct archive_write_filter *,- struct private_data *, int, const void *, size_t);-#endif---/*- * Add a zstd compression filter to this write handle.- */-int-archive_write_add_filter_zstd(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_add_filter_zstd");-- data = calloc(1, sizeof(*data));- if (data == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- f->data = data;- f->open = &archive_compressor_zstd_open;- f->options = &archive_compressor_zstd_options;- f->flush = &archive_compressor_zstd_flush;- f->close = &archive_compressor_zstd_close;- f->free = &archive_compressor_zstd_free;- f->code = ARCHIVE_FILTER_ZSTD;- f->name = "zstd";- data->compression_level = CLEVEL_DEFAULT;- data->threads = 0;-#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR- data->frame_per_file = 0;- data->min_frame_size = 0;- data->max_frame_size = SIZE_MAX;- data->cur_frame_in = 0;- data->cur_frame_out = 0;- data->cstream = ZSTD_createCStream();- if (data->cstream == NULL) {- free(data);- archive_set_error(&a->archive, ENOMEM,- "Failed to allocate zstd compressor object");- return (ARCHIVE_FATAL);- }-- return (ARCHIVE_OK);-#else- data->pdata = __archive_write_program_allocate("zstd");- if (data->pdata == NULL) {- free(data);- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Using external zstd program");- return (ARCHIVE_WARN);-#endif-}--static int-archive_compressor_zstd_free(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR- ZSTD_freeCStream(data->cstream);- free(data->out.dst);-#else- __archive_write_program_free(data->pdata);-#endif- free(data);- f->data = NULL;- return (ARCHIVE_OK);-}--static int string_to_number(const char *string, intmax_t *numberp)-{- char *end;-- if (string == NULL || *string == '\0')- return (ARCHIVE_WARN);- *numberp = strtoimax(string, &end, 10);- if (end == string || *end != '\0' || errno == EOVERFLOW) {- *numberp = 0;- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-}--/*- * Set write options.- */-static int-archive_compressor_zstd_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) {- intmax_t level;- if (string_to_number(value, &level) != ARCHIVE_OK) {- return (ARCHIVE_WARN);- }- /* If we don't have the library, hard-code the max level */- int minimum = CLEVEL_MIN;- int maximum = CLEVEL_MAX;-#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR- maximum = ZSTD_maxCLevel();-#if ZSTD_VERSION_NUMBER >= MINVER_MINCLEVEL- if (ZSTD_versionNumber() >= MINVER_MINCLEVEL) {- minimum = ZSTD_minCLevel();- }- else-#endif- if (ZSTD_versionNumber() < MINVER_NEGCLEVEL) {- minimum = CLEVEL_STD_MIN;- }-#endif- if (level < minimum || level > maximum) {- return (ARCHIVE_WARN);- }- data->compression_level = (int)level;- return (ARCHIVE_OK);- } else if (strcmp(key, "threads") == 0) {- intmax_t threads;- if (string_to_number(value, &threads) != ARCHIVE_OK) {- return (ARCHIVE_WARN);- }- if (threads < 0) {- return (ARCHIVE_WARN);- }- data->threads = (int)threads;- return (ARCHIVE_OK);-#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR- } else if (strcmp(key, "frame-per-file") == 0) {- data->frame_per_file = 1;- return (ARCHIVE_OK);- } else if (strcmp(key, "min-frame-size") == 0) {- intmax_t min_frame_size;- if (string_to_number(value, &min_frame_size) != ARCHIVE_OK) {- return (ARCHIVE_WARN);- }- if (min_frame_size < 0) {- return (ARCHIVE_WARN);- }- data->min_frame_size = min_frame_size;- return (ARCHIVE_OK);- } else if (strcmp(key, "max-frame-size") == 0) {- intmax_t max_frame_size;- if (string_to_number(value, &max_frame_size) != ARCHIVE_OK) {- return (ARCHIVE_WARN);- }- if (max_frame_size < 1024) {- return (ARCHIVE_WARN);- }- data->max_frame_size = max_frame_size;- return (ARCHIVE_OK);-#endif- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR-/*- * Setup callback.- */-static int-archive_compressor_zstd_open(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- if (data->out.dst == NULL) {- size_t bs = ZSTD_CStreamOutSize(), bpb;- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {- /* Buffer size should be a multiple number of- * the of bytes per block for performance. */- bpb = archive_write_get_bytes_per_block(f->archive);- if (bpb > bs)- bs = bpb;- else if (bpb != 0)- bs -= bs % bpb;- }- data->out.size = bs;- data->out.pos = 0;- data->out.dst- = (unsigned char *)malloc(data->out.size);- if (data->out.dst == NULL) {- archive_set_error(f->archive, ENOMEM,- "Can't allocate data for compression buffer");- return (ARCHIVE_FATAL);- }- }-- f->write = archive_compressor_zstd_write;-- if (ZSTD_isError(ZSTD_initCStream(data->cstream,- data->compression_level))) {- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,- "Internal error initializing zstd compressor object");- return (ARCHIVE_FATAL);- }-- ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_nbWorkers, data->threads);-- return (ARCHIVE_OK);-}--/*- * Write data to the compressed stream.- */-static int-archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,- size_t length)-{- struct private_data *data = (struct private_data *)f->data;-- return (drive_compressor(f, data, 0, buff, length));-}--/*- * Flush the compressed stream.- */-static int-archive_compressor_zstd_flush(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- if (data->frame_per_file && data->state == running &&- data->cur_frame_out > data->min_frame_size)- data->state = finishing;- return (drive_compressor(f, data, 1, NULL, 0));-}--/*- * Finish the compression...- */-static int-archive_compressor_zstd_close(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- if (data->state == running)- data->state = finishing;- return (drive_compressor(f, data, 1, NULL, 0));-}--/*- * Utility function to push input data through compressor,- * writing full output blocks as necessary.- */-static int-drive_compressor(struct archive_write_filter *f,- struct private_data *data, int flush, const void *src, size_t length)-{- ZSTD_inBuffer in = { .src = src, .size = length, .pos = 0 };- size_t ipos, opos, zstdret = 0;- int ret;-- for (;;) {- ipos = in.pos;- opos = data->out.pos;- switch (data->state) {- case running:- if (in.pos == in.size)- return (ARCHIVE_OK);- zstdret = ZSTD_compressStream(data->cstream,- &data->out, &in);- if (ZSTD_isError(zstdret))- goto zstd_fatal;- break;- case finishing:- zstdret = ZSTD_endStream(data->cstream, &data->out);- if (ZSTD_isError(zstdret))- goto zstd_fatal;- if (zstdret == 0)- data->state = resetting;- break;- case resetting:- ZSTD_CCtx_reset(data->cstream, ZSTD_reset_session_only);- data->cur_frame++;- data->cur_frame_in = 0;- data->cur_frame_out = 0;- data->state = running;- break;- }- data->total_in += in.pos - ipos;- data->cur_frame_in += in.pos - ipos;- data->cur_frame_out += data->out.pos - opos;- if (data->state == running &&- data->cur_frame_in >= data->max_frame_size) {- data->state = finishing;- }- if (data->out.pos == data->out.size ||- (flush && data->out.pos > 0)) {- ret = __archive_write_filter(f->next_filter,- data->out.dst, data->out.pos);- if (ret != ARCHIVE_OK)- goto fatal;- data->out.pos = 0;- }- }-zstd_fatal:- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,- "Zstd compression failed: %s",- ZSTD_getErrorName(zstdret));-fatal:- return (ARCHIVE_FATAL);-}--#else /* HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR */--static int-archive_compressor_zstd_open(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;- struct archive_string as;- int r;-- archive_string_init(&as);- /* --no-check matches library default */- archive_strcpy(&as, "zstd --no-check");-- if (data->compression_level < CLEVEL_STD_MIN) {- archive_string_sprintf(&as, " --fast=%d", -data->compression_level);- } else {- archive_string_sprintf(&as, " -%d", data->compression_level);- }-- if (data->compression_level > CLEVEL_STD_MAX) {- archive_strcat(&as, " --ultra");- }-- if (data->threads != 0) {- archive_string_sprintf(&as, " --threads=%d", data->threads);- }-- f->write = archive_compressor_zstd_write;- r = __archive_write_program_open(f, data->pdata, as.s);- archive_string_free(&as);- return (r);-}--static int-archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,- size_t length)-{- struct private_data *data = (struct private_data *)f->data;-- return __archive_write_program_write(f, data->pdata, buff, length);-}--static int-archive_compressor_zstd_flush(struct archive_write_filter *f)-{- (void)f; /* UNUSED */-- return (ARCHIVE_OK);-}--static int-archive_compressor_zstd_close(struct archive_write_filter *f)-{- struct private_data *data = (struct private_data *)f->data;-- return __archive_write_program_close(f, data->pdata);-}--#endif /* HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR */
− c/archive_write_disk_posix.c
@@ -1,4759 +0,0 @@-/*-- * Copyright (c) 2003-2010 Tim Kientzle- * Copyright (c) 2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#if !defined(_WIN32) || defined(__CYGWIN__)--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_SYS_ACL_H-#include <sys/acl.h>-#endif-#ifdef HAVE_SYS_EXTATTR_H-#include <sys/extattr.h>-#endif-#if HAVE_SYS_XATTR_H-#include <sys/xattr.h>-#elif HAVE_ATTR_XATTR_H-#include <attr/xattr.h>-#endif-#ifdef HAVE_SYS_EA_H-#include <sys/ea.h>-#endif-#ifdef HAVE_SYS_IOCTL_H-#include <sys/ioctl.h>-#endif-#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_SYS_TIME_H-#include <sys/time.h>-#endif-#ifdef HAVE_SYS_UTIME_H-#include <sys/utime.h>-#endif-#ifdef HAVE_COPYFILE_H-#include <copyfile.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_GRP_H-#include <grp.h>-#endif-#ifdef HAVE_LANGINFO_H-#include <langinfo.h>-#endif-#ifdef HAVE_LINUX_FS_H-#include <linux/fs.h> /* for Linux file flags */-#endif-/*- * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.- * As the include guards don't agree, the order of include is important.- */-#ifdef HAVE_LINUX_EXT2_FS_H-#include <linux/ext2_fs.h> /* for Linux file flags */-#endif-#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)-#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_PWD_H-#include <pwd.h>-#endif-#include <stdio.h>-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif-#ifdef HAVE_UTIME_H-#include <utime.h>-#endif-#ifdef F_GETTIMES /* Tru64 specific */-#include <sys/fcntl1.h>-#endif--/*- * Macro to cast st_mtime and time_t to an int64 so that 2 numbers can reliably be compared.- *- * It assumes that the input is an integer type of no more than 64 bits.- * If the number is less than zero, t must be a signed type, so it fits in- * int64_t. Otherwise, it's a nonnegative value so we can cast it to uint64_t- * without loss. But it could be a large unsigned value, so we have to clip it- * to INT64_MAX.*- */-#define to_int64_time(t) \- ((t) < 0 ? (int64_t)(t) : (uint64_t)(t) > (uint64_t)INT64_MAX ? INT64_MAX : (int64_t)(t))--#if __APPLE__-#include <TargetConditionals.h>-#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H-#include <quarantine.h>-#define HAVE_QUARANTINE 1-#endif-#endif--#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif--/* TODO: Support Mac OS 'quarantine' feature. This is really just a- * standard tag to mark files that have been downloaded as "tainted".- * On Mac OS, we should mark the extracted files as tainted if the- * archive being read was tainted. Windows has a similar feature; we- * should investigate ways to support this generically. */--#include "archive.h"-#include "archive_acl_private.h"-#include "archive_string.h"-#include "archive_endian.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_write_disk_private.h"--#ifndef O_BINARY-#define O_BINARY 0-#endif-#ifndef O_CLOEXEC-#define O_CLOEXEC 0-#endif--/* Ignore non-int O_NOFOLLOW constant. */-/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */-#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX)-#undef O_NOFOLLOW-#endif--#ifndef O_NOFOLLOW-#define O_NOFOLLOW 0-#endif--#ifndef AT_FDCWD-#define AT_FDCWD -100-#endif--struct fixup_entry {- struct fixup_entry *next;- struct archive_acl acl;- mode_t mode;- __LA_MODE_T filetype;- int64_t atime;- int64_t birthtime;- int64_t mtime;- int64_t ctime;- unsigned long atime_nanos;- unsigned long birthtime_nanos;- unsigned long mtime_nanos;- unsigned long ctime_nanos;- unsigned long fflags_set;- size_t mac_metadata_size;- void *mac_metadata;- int fixup; /* bitmask of what needs fixing */- char *name;-};--/*- * We use a bitmask to track which operations remain to be done for- * this file. In particular, this helps us avoid unnecessary- * operations when it's possible to take care of one step as a- * side-effect of another. For example, mkdir() can specify the mode- * for the newly-created object but symlink() cannot. This means we- * can skip chmod() if mkdir() succeeded, but we must explicitly- * chmod() if we're trying to create a directory that already exists- * (mkdir() failed) or if we're restoring a symlink. Similarly, we- * need to verify UID/GID before trying to restore SUID/SGID bits;- * that verification can occur explicitly through a stat() call or- * implicitly because of a successful chown() call.- */-#define TODO_MODE_FORCE 0x40000000-#define TODO_MODE_BASE 0x20000000-#define TODO_SUID 0x10000000-#define TODO_SUID_CHECK 0x08000000-#define TODO_SGID 0x04000000-#define TODO_SGID_CHECK 0x02000000-#define TODO_APPLEDOUBLE 0x01000000-#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID)-#define TODO_TIMES ARCHIVE_EXTRACT_TIME-#define TODO_OWNER ARCHIVE_EXTRACT_OWNER-#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS-#define TODO_ACLS ARCHIVE_EXTRACT_ACL-#define TODO_XATTR ARCHIVE_EXTRACT_XATTR-#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA-#define TODO_HFS_COMPRESSION ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED--struct archive_write_disk {- struct archive archive;-- mode_t user_umask;- struct fixup_entry *fixup_list;- struct fixup_entry *current_fixup;- int64_t user_uid;- int skip_file_set;- int64_t skip_file_dev;- int64_t skip_file_ino;- time_t start_time;-- int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid);- void (*cleanup_gid)(void *private);- void *lookup_gid_data;- int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid);- void (*cleanup_uid)(void *private);- void *lookup_uid_data;-- /*- * Full path of last file to satisfy symlink checks.- */- struct archive_string path_safe;-- /*- * Cached stat data from disk for the current entry.- * If this is valid, pst points to st. Otherwise,- * pst is null.- */- struct stat st;- struct stat *pst;-- /* Information about the object being restored right now. */- struct archive_entry *entry; /* Entry being extracted. */- char *name; /* Name of entry, possibly edited. */- struct archive_string _name_data; /* backing store for 'name' */- char *tmpname; /* Temporary name * */- struct archive_string _tmpname_data; /* backing store for 'tmpname' */- /* Tasks remaining for this object. */- int todo;- /* Tasks deferred until end-of-archive. */- int deferred;- /* Options requested by the client. */- int flags;- /* Handle for the file we're restoring. */- int fd;- /* Current offset for writing data to the file. */- int64_t offset;- /* Last offset actually written to disk. */- int64_t fd_offset;- /* Total bytes actually written to files. */- int64_t total_bytes_written;- /* Maximum size of file, -1 if unknown. */- 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. */- mode_t mode;- /* UID/GID to use in restoring this entry. */- int64_t uid;- int64_t gid;- /*- * HFS+ Compression.- */- /* Xattr "com.apple.decmpfs". */- uint32_t decmpfs_attr_size;- unsigned char *decmpfs_header_p;- /* ResourceFork set options used for fsetxattr. */- int rsrc_xattr_options;- /* Xattr "com.apple.ResourceFork". */- unsigned char *resource_fork;- size_t resource_fork_allocated_size;- unsigned int decmpfs_block_count;- uint32_t *decmpfs_block_info;- /* Buffer for compressed data. */- unsigned char *compressed_buffer;- size_t compressed_buffer_size;- size_t compressed_buffer_remaining;- /* The offset of the ResourceFork where compressed data will- * be placed. */- uint32_t compressed_rsrc_position;- uint32_t compressed_rsrc_position_v;- /* Buffer for uncompressed data. */- char *uncompressed_buffer;- size_t block_remaining_bytes;- size_t file_remaining_bytes;-#ifdef HAVE_ZLIB_H- z_stream stream;- int stream_valid;- int decmpfs_compression_level;-#endif-};--/*- * Default mode for dirs created automatically (will be modified by umask).- * Note that POSIX specifies 0777 for implicitly-created dirs, "modified- * by the process' file creation mask."- */-#define DEFAULT_DIR_MODE 0777-/*- * Dir modes are restored in two steps: During the extraction, the permissions- * in the archive are modified to match the following limits. During- * the post-extract fixup pass, the permissions from the archive are- * applied.- */-#define MINIMUM_DIR_MODE 0700-#define MAXIMUM_DIR_MODE 0775--/*- * Maximum uncompressed size of a decmpfs block.- */-#define MAX_DECMPFS_BLOCK_SIZE (64 * 1024)-/*- * HFS+ compression type.- */-#define CMP_XATTR 3/* Compressed data in xattr. */-#define CMP_RESOURCE_FORK 4/* Compressed data in resource fork. */-/*- * HFS+ compression resource fork.- */-#define RSRC_H_SIZE 260 /* Base size of Resource fork header. */-#define RSRC_F_SIZE 50 /* Size of Resource fork footer. */-/* Size to write compressed data to resource fork. */-#define COMPRESSED_W_SIZE (64 * 1024)-/* decmpfs definitions. */-#define MAX_DECMPFS_XATTR_SIZE 3802-#ifndef DECMPFS_XATTR_NAME-#define DECMPFS_XATTR_NAME "com.apple.decmpfs"-#endif-#define DECMPFS_MAGIC 0x636d7066-#define DECMPFS_COMPRESSION_MAGIC 0-#define DECMPFS_COMPRESSION_TYPE 4-#define DECMPFS_UNCOMPRESSED_SIZE 8-#define DECMPFS_HEADER_SIZE 16--#define HFS_BLOCKS(s) ((s) >> 12)---static int la_opendirat(int, const char *);-static int la_mktemp(struct archive_write_disk *);-static int la_verify_filetype(mode_t, __LA_MODE_T);-static void fsobj_error(int *, struct archive_string *, int, const char *,- const char *);-static int check_symlinks_fsobj(char *, int *, struct archive_string *,- int, int);-static int check_symlinks(struct archive_write_disk *);-static int create_filesystem_object(struct archive_write_disk *);-static struct fixup_entry *current_fixup(struct archive_write_disk *,- const char *pathname);-#if defined(HAVE_FCHDIR) && defined(PATH_MAX)-static void edit_deep_directories(struct archive_write_disk *ad);-#endif-static int cleanup_pathname_fsobj(char *, int *, struct archive_string *,- int);-static int cleanup_pathname(struct archive_write_disk *);-static int create_dir(struct archive_write_disk *, char *);-static int create_parent_dir(struct archive_write_disk *, char *);-static ssize_t hfs_write_data_block(struct archive_write_disk *,- const char *, size_t);-static int fixup_appledouble(struct archive_write_disk *, const char *);-static int older(struct stat *, struct archive_entry *);-static int restore_entry(struct archive_write_disk *);-static int set_mac_metadata(struct archive_write_disk *, const char *,- const void *, size_t);-static int set_xattrs(struct archive_write_disk *);-static int clear_nochange_fflags(struct archive_write_disk *);-static int set_fflags(struct archive_write_disk *);-static int set_fflags_platform(struct archive_write_disk *, int fd,- const char *name, mode_t mode,- unsigned long fflags_set, unsigned long fflags_clear);-static int set_ownership(struct archive_write_disk *);-static int set_mode(struct archive_write_disk *, int mode);-static int set_time(int, int, const char *, time_t, long, time_t, long);-static int set_times(struct archive_write_disk *, int, int, const char *,- time_t, long, time_t, long, time_t, long, time_t, long);-static int set_times_from_entry(struct archive_write_disk *);-static struct fixup_entry *sort_dir_list(struct fixup_entry *p);-static ssize_t write_data_block(struct archive_write_disk *,- const char *, size_t);-static void close_file_descriptor(struct archive_write_disk *);--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, int64_t);--static int-la_mktemp(struct archive_write_disk *a)-{- int oerrno, fd;- mode_t mode;-- archive_string_empty(&a->_tmpname_data);- archive_string_sprintf(&a->_tmpname_data, "%s.XXXXXX", a->name);- a->tmpname = a->_tmpname_data.s;-- fd = __archive_mkstemp(a->tmpname);- if (fd == -1)- return -1;-- mode = a->mode & 0777 & ~a->user_umask;- if (fchmod(fd, mode) == -1) {- oerrno = errno;- close(fd);- errno = oerrno;- return -1;- }- return fd;-}--static int-la_opendirat(int fd, const char *path) {- const int flags = O_CLOEXEC-#if defined(O_BINARY)- | O_BINARY-#endif-#if defined(O_DIRECTORY)- | O_DIRECTORY-#endif-#if defined(O_PATH)- | O_PATH-#elif defined(O_SEARCH)- | O_SEARCH-#elif defined(__FreeBSD__) && defined(O_EXEC)- | O_EXEC-#else- | O_RDONLY-#endif- ;--#if !defined(HAVE_OPENAT)- if (fd != AT_FDCWD) {- errno = ENOTSUP;- return (-1);- } else- return (open(path, flags));-#else- return (openat(fd, path, flags));-#endif-}--static int-la_verify_filetype(mode_t mode, __LA_MODE_T filetype) {- int ret = 0;-- switch (filetype) {- case AE_IFREG:- ret = (S_ISREG(mode));- break;- case AE_IFDIR:- ret = (S_ISDIR(mode));- break;- case AE_IFLNK:- ret = (S_ISLNK(mode));- break;- case AE_IFSOCK:- ret = (S_ISSOCK(mode));- break;- case AE_IFCHR:- ret = (S_ISCHR(mode));- break;- case AE_IFBLK:- ret = (S_ISBLK(mode));- break;- case AE_IFIFO:- ret = (S_ISFIFO(mode));- break;- default:- break;- }-- return (ret);-}--static int-lazy_stat(struct archive_write_disk *a)-{- if (a->pst != NULL) {- /* Already have stat() data available. */- return (ARCHIVE_OK);- }-#ifdef HAVE_FSTAT- if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) {- a->pst = &a->st;- return (ARCHIVE_OK);- }-#endif- /*- * XXX At this point, symlinks should not be hit, otherwise- * XXX a race occurred. Do we want to check explicitly for that?- */-#ifdef HAVE_LSTAT- if (lstat(a->name, &a->st) == 0)-#else- if (la_stat(a->name, &a->st) == 0)-#endif- {- a->pst = &a->st;- return (ARCHIVE_OK);- }- archive_set_error(&a->archive, errno, "Couldn't stat file");- return (ARCHIVE_WARN);-}--static const struct archive_vtable-archive_write_disk_vtable = {- .archive_close = _archive_write_disk_close,- .archive_filter_bytes = _archive_write_disk_filter_bytes,- .archive_free = _archive_write_disk_free,- .archive_write_header = _archive_write_disk_header,- .archive_write_finish_entry = _archive_write_disk_finish_entry,- .archive_write_data = _archive_write_disk_data,- .archive_write_data_block = _archive_write_disk_data_block,-};--static int64_t-_archive_write_disk_filter_bytes(struct archive *_a, int n)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- (void)n; /* UNUSED */- if (n == -1 || n == 0)- return (a->total_bytes_written);- return (-1);-}---int-archive_write_disk_set_options(struct archive *_a, int flags)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;-- a->flags = flags;- return (ARCHIVE_OK);-}---/*- * Extract this entry to disk.- *- * TODO: Validate hardlinks. According to the standards, we're- * supposed to check each extracted hardlink and squawk if it refers- * to a file that we didn't restore. I'm not entirely convinced this- * is a good idea, but more importantly: Is there any way to validate- * hardlinks without keeping a complete list of filenames from the- * entire archive?? Ugh.- *- */-static int-_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;- const char *linkname;- int ret, r;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_write_disk_header");- archive_clear_error(&a->archive);- if (a->archive.state & ARCHIVE_STATE_DATA) {- r = _archive_write_disk_finish_entry(&a->archive);- if (r == ARCHIVE_FATAL)- return (r);- }-- /* Set up for this particular entry. */- a->pst = NULL;- a->current_fixup = NULL;- a->deferred = 0;- if (a->entry) {- archive_entry_free(a->entry);- a->entry = NULL;- }- a->entry = archive_entry_clone(entry);- a->fd = -1;- a->fd_offset = 0;- a->offset = 0;- a->restore_pwd = -1;- a->uid = a->user_uid;- a->mode = archive_entry_mode(a->entry);- if (archive_entry_size_is_set(a->entry))- a->filesize = archive_entry_size(a->entry);- else- a->filesize = -1;- archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry));- a->name = a->_name_data.s;- archive_clear_error(&a->archive);-- /*- * Clean up the requested path. This is necessary for correct- * dir restores; the dir restore logic otherwise gets messed- * up by nonsense like "dir/.".- */- ret = cleanup_pathname(a);- if (ret != ARCHIVE_OK)- return (ret);-- /*- * Check if we have a hardlink that points to itself.- */- linkname = archive_entry_hardlink(a->entry);- if (linkname != NULL && strcmp(a->name, linkname) == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Skipping hardlink pointing to itself: %s",- a->name);- return (ARCHIVE_WARN);- }-- /*- * Query the umask so we get predictable mode settings.- * This gets done on every call to _write_header in case the- * user edits their umask during the extraction for some- * reason.- */- umask(a->user_umask = umask(0));-- /* Figure out what we need to do for this entry. */- a->todo = TODO_MODE_BASE;- if (a->flags & ARCHIVE_EXTRACT_PERM) {- a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */- /*- * SGID requires an extra "check" step because we- * cannot easily predict the GID that the system will- * assign. (Different systems assign GIDs to files- * based on a variety of criteria, including process- * credentials and the gid of the enclosing- * directory.) We can only restore the SGID bit if- * the file has the right GID, and we only know the- * GID if we either set it (see set_ownership) or if- * we've actually called stat() on the file after it- * was restored. Since there are several places at- * which we might verify the GID, we need a TODO bit- * to keep track.- */- if (a->mode & S_ISGID)- a->todo |= TODO_SGID | TODO_SGID_CHECK;- /*- * Verifying the SUID is simpler, but can still be- * done in multiple ways, hence the separate "check" bit.- */- if (a->mode & S_ISUID)- a->todo |= TODO_SUID | TODO_SUID_CHECK;- } else {- /*- * User didn't request full permissions, so don't- * restore SUID, SGID bits and obey umask.- */- a->mode &= ~S_ISUID;- a->mode &= ~S_ISGID;- a->mode &= ~S_ISVTX;- a->mode &= ~a->user_umask;- }- if (a->flags & ARCHIVE_EXTRACT_OWNER)- a->todo |= TODO_OWNER;- if (a->flags & ARCHIVE_EXTRACT_TIME)- a->todo |= TODO_TIMES;- if (a->flags & ARCHIVE_EXTRACT_ACL) {-#if ARCHIVE_ACL_DARWIN- /*- * On MacOS, platform ACLs get stored in mac_metadata, too.- * If we intend to extract mac_metadata and it is present- * we skip extracting libarchive NFSv4 ACLs.- */- size_t metadata_size;-- if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 ||- archive_entry_mac_metadata(a->entry,- &metadata_size) == NULL || metadata_size == 0)-#endif-#if ARCHIVE_ACL_LIBRICHACL- /*- * RichACLs are stored in an extended attribute.- * If we intend to extract extended attributes and have this- * attribute we skip extracting libarchive NFSv4 ACLs.- */- short extract_acls = 1;- if (a->flags & ARCHIVE_EXTRACT_XATTR && (- archive_entry_acl_types(a->entry) &- ARCHIVE_ENTRY_ACL_TYPE_NFS4)) {- const char *attr_name;- const void *attr_value;- size_t attr_size;- int i = archive_entry_xattr_reset(a->entry);- while (i--) {- archive_entry_xattr_next(a->entry, &attr_name,- &attr_value, &attr_size);- if (attr_name != NULL && attr_value != NULL &&- attr_size > 0 && strcmp(attr_name,- "trusted.richacl") == 0) {- extract_acls = 0;- break;- }- }- }- if (extract_acls)-#endif-#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL- {-#endif- if (archive_entry_filetype(a->entry) == AE_IFDIR)- a->deferred |= TODO_ACLS;- else- a->todo |= TODO_ACLS;-#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL- }-#endif- }- if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) {- if (archive_entry_filetype(a->entry) == AE_IFDIR)- a->deferred |= TODO_MAC_METADATA;- else- a->todo |= TODO_MAC_METADATA;- }-#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)- if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) {- unsigned long set, clear;- archive_entry_fflags(a->entry, &set, &clear);- if ((set & ~clear) & UF_COMPRESSED) {- a->todo |= TODO_HFS_COMPRESSION;- a->decmpfs_block_count = (unsigned)-1;- }- }- if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 &&- (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) {- a->todo |= TODO_HFS_COMPRESSION;- a->decmpfs_block_count = (unsigned)-1;- }- {- const char *p;-- /* Check if the current file name is a type of the- * resource fork file. */- p = strrchr(a->name, '/');- if (p == NULL)- p = a->name;- else- p++;- if (p[0] == '.' && p[1] == '_') {- /* Do not compress "._XXX" files. */- a->todo &= ~TODO_HFS_COMPRESSION;- if (a->filesize > 0)- a->todo |= TODO_APPLEDOUBLE;- }- }-#endif-- if (a->flags & ARCHIVE_EXTRACT_XATTR) {-#if ARCHIVE_XATTR_DARWIN- /*- * On MacOS, extended attributes get stored in mac_metadata,- * too. If we intend to extract mac_metadata and it is present- * we skip extracting extended attributes.- */- size_t metadata_size;-- if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 ||- archive_entry_mac_metadata(a->entry,- &metadata_size) == NULL || metadata_size == 0)-#endif- a->todo |= TODO_XATTR;- }- if (a->flags & ARCHIVE_EXTRACT_FFLAGS)- a->todo |= TODO_FFLAGS;- if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {- ret = check_symlinks(a);- if (ret != ARCHIVE_OK)- return (ret);- }-#if defined(HAVE_FCHDIR) && defined(PATH_MAX)- /* If path exceeds PATH_MAX, shorten the path. */- edit_deep_directories(a);-#endif-- ret = restore_entry(a);--#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)- /*- * Check if the filesystem the file is restoring on supports- * HFS+ Compression. If not, cancel HFS+ Compression.- */- if (a->todo | TODO_HFS_COMPRESSION) {- /*- * NOTE: UF_COMPRESSED is ignored even if the filesystem- * supports HFS+ Compression because the file should- * have at least an extended attribute "com.apple.decmpfs"- * before the flag is set to indicate that the file have- * been compressed. If the filesystem does not support- * HFS+ Compression the system call will fail.- */- if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0)- a->todo &= ~TODO_HFS_COMPRESSION;- }-#endif-- /*- * TODO: There are rumours that some extended attributes must- * be restored before file data is written. If this is true,- * then we either need to write all extended attributes both- * before and after restoring the data, or find some rule for- * determining which must go first and which last. Due to the- * many ways people are using xattrs, this may prove to be an- * intractable problem.- */--#ifdef HAVE_FCHDIR- /* If we changed directory above, restore it here. */- if (a->restore_pwd >= 0) {- r = fchdir(a->restore_pwd);- if (r != 0) {- archive_set_error(&a->archive, errno,- "chdir() failure");- ret = ARCHIVE_FATAL;- }- close(a->restore_pwd);- a->restore_pwd = -1;- }-#endif-- /*- * Fixup uses the unedited pathname from archive_entry_pathname(),- * because it is relative to the base dir and the edited path- * might be relative to some intermediate dir as a result of the- * deep restore logic.- */- if (a->deferred & TODO_MODE) {- fe = current_fixup(a, archive_entry_pathname(entry));- if (fe == NULL)- return (ARCHIVE_FATAL);- fe->filetype = archive_entry_filetype(entry);- fe->fixup |= TODO_MODE_BASE;- fe->mode = a->mode;- }-- if ((a->deferred & TODO_TIMES)- && (archive_entry_mtime_is_set(entry)- || archive_entry_atime_is_set(entry))) {- fe = current_fixup(a, archive_entry_pathname(entry));- if (fe == NULL)- return (ARCHIVE_FATAL);- fe->filetype = archive_entry_filetype(entry);- fe->mode = a->mode;- fe->fixup |= TODO_TIMES;- if (archive_entry_atime_is_set(entry)) {- fe->atime = archive_entry_atime(entry);- fe->atime_nanos = archive_entry_atime_nsec(entry);- } else {- /* If atime is unset, use start time. */- fe->atime = a->start_time;- fe->atime_nanos = 0;- }- if (archive_entry_mtime_is_set(entry)) {- fe->mtime = archive_entry_mtime(entry);- fe->mtime_nanos = archive_entry_mtime_nsec(entry);- } else {- /* If mtime is unset, use start time. */- fe->mtime = a->start_time;- fe->mtime_nanos = 0;- }- if (archive_entry_birthtime_is_set(entry)) {- fe->birthtime = archive_entry_birthtime(entry);- fe->birthtime_nanos = archive_entry_birthtime_nsec(- entry);- } else {- /* If birthtime is unset, use mtime. */- fe->birthtime = fe->mtime;- fe->birthtime_nanos = fe->mtime_nanos;- }- }-- if (a->deferred & TODO_ACLS) {- fe = current_fixup(a, archive_entry_pathname(entry));- if (fe == NULL)- return (ARCHIVE_FATAL);- fe->filetype = archive_entry_filetype(entry);- fe->fixup |= TODO_ACLS;- archive_acl_copy(&fe->acl, archive_entry_acl(entry));- }-- if (a->deferred & TODO_MAC_METADATA) {- const void *metadata;- size_t metadata_size;- metadata = archive_entry_mac_metadata(a->entry, &metadata_size);- if (metadata != NULL && metadata_size > 0) {- fe = current_fixup(a, archive_entry_pathname(entry));- if (fe == NULL)- return (ARCHIVE_FATAL);- fe->filetype = archive_entry_filetype(entry);- fe->mac_metadata = malloc(metadata_size);- if (fe->mac_metadata != NULL) {- memcpy(fe->mac_metadata, metadata,- metadata_size);- fe->mac_metadata_size = metadata_size;- fe->fixup |= TODO_MAC_METADATA;- }- }- }-- if (a->deferred & TODO_FFLAGS) {- fe = current_fixup(a, archive_entry_pathname(entry));- if (fe == NULL)- return (ARCHIVE_FATAL);- fe->filetype = archive_entry_filetype(entry);- fe->fixup |= TODO_FFLAGS;- /* TODO: Complete this.. defer fflags from below. */- }-- /* We've created the object and are ready to pour data into it. */- if (ret >= ARCHIVE_WARN)- a->archive.state = ARCHIVE_STATE_DATA;- /*- * If it's not open, tell our client not to try writing.- * In particular, dirs, links, etc, don't get written to.- */- if (a->fd < 0) {- archive_entry_set_size(entry, 0);- a->filesize = 0;- }-- return (ret);-}--int-archive_write_disk_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file");- a->skip_file_set = 1;- a->skip_file_dev = d;- a->skip_file_ino = i;- return (ARCHIVE_OK);-}--static ssize_t-write_data_block(struct archive_write_disk *a, const char *buff, size_t size)-{- uint64_t start_size = size;- ssize_t bytes_written = 0;- ssize_t block_size = 0, bytes_to_write;-- if (size == 0)- return (ARCHIVE_OK);-- if (a->filesize == 0 || a->fd < 0) {- archive_set_error(&a->archive, 0,- "Attempt to write to an empty file");- return (ARCHIVE_WARN);- }-- if (a->flags & ARCHIVE_EXTRACT_SPARSE) {-#if HAVE_STRUCT_STAT_ST_BLKSIZE- int r;- if ((r = lazy_stat(a)) != ARCHIVE_OK)- return (r);- block_size = a->pst->st_blksize;-#else- /* XXX TODO XXX Is there a more appropriate choice here ? */- /* This needn't match the filesystem allocation size. */- block_size = 16*1024;-#endif- }-- /* If this write would run beyond the file size, truncate it. */- if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)- start_size = size = (size_t)(a->filesize - a->offset);-- /* Write the data. */- while (size > 0) {- if (block_size == 0) {- bytes_to_write = size;- } else {- /* We're sparsifying the file. */- const char *p, *end;- int64_t block_end;-- /* Skip leading zero bytes. */- for (p = buff, end = buff + size; p < end; ++p) {- if (*p != '\0')- break;- }- a->offset += p - buff;- size -= p - buff;- buff = p;- if (size == 0)- break;-- /* Calculate next block boundary after offset. */- block_end- = (a->offset / block_size + 1) * block_size;-- /* If the adjusted write would cross block boundary,- * truncate it to the block boundary. */- bytes_to_write = size;- if (a->offset + bytes_to_write > block_end)- bytes_to_write = block_end - a->offset;- }- /* Seek if necessary to the specified offset. */- if (a->offset != a->fd_offset) {- if (lseek(a->fd, a->offset, SEEK_SET) < 0) {- archive_set_error(&a->archive, errno,- "Seek failed");- return (ARCHIVE_FATAL);- }- a->fd_offset = a->offset;- }- bytes_written = write(a->fd, buff, bytes_to_write);- if (bytes_written < 0) {- archive_set_error(&a->archive, errno, "Write failed");- return (ARCHIVE_WARN);- }- buff += bytes_written;- size -= bytes_written;- a->total_bytes_written += bytes_written;- a->offset += bytes_written;- a->fd_offset = a->offset;- }- return (start_size - size);-}--#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\- && defined(HAVE_ZLIB_H)--/*- * Set UF_COMPRESSED file flag.- * This have to be called after hfs_write_decmpfs() because if the- * file does not have "com.apple.decmpfs" xattr the flag is ignored.- */-static int-hfs_set_compressed_fflag(struct archive_write_disk *a)-{- int r;-- if ((r = lazy_stat(a)) != ARCHIVE_OK)- return (r);-- a->st.st_flags |= UF_COMPRESSED;- if (fchflags(a->fd, a->st.st_flags) != 0) {- archive_set_error(&a->archive, errno,- "Failed to set UF_COMPRESSED file flag");- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-}--/*- * HFS+ Compression decmpfs- *- * +------------------------------+ +0- * | Magic(LE 4 bytes) |- * +------------------------------+- * | Type(LE 4 bytes) |- * +------------------------------+- * | Uncompressed size(LE 8 bytes)|- * +------------------------------+ +16- * | |- * | Compressed data |- * | (Placed only if Type == 3) |- * | |- * +------------------------------+ +3802 = MAX_DECMPFS_XATTR_SIZE- *- * Type is 3: decmpfs has compressed data.- * Type is 4: Resource Fork has compressed data.- */-/*- * Write "com.apple.decmpfs"- */-static int-hfs_write_decmpfs(struct archive_write_disk *a)-{- int r;- uint32_t compression_type;-- r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p,- a->decmpfs_attr_size, 0, 0);- if (r < 0) {- archive_set_error(&a->archive, errno,- "Cannot restore xattr:%s", DECMPFS_XATTR_NAME);- compression_type = archive_le32dec(- &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]);- if (compression_type == CMP_RESOURCE_FORK)- fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME,- XATTR_SHOWCOMPRESSION);- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-}--/*- * HFS+ Compression Resource Fork- *- * +-----------------------------+- * | Header(260 bytes) |- * +-----------------------------+- * | Block count(LE 4 bytes) |- * +-----------------------------+ --+- * +-- | Offset (LE 4 bytes) | |- * | | [distance from Block count] | | Block 0- * | +-----------------------------+ |- * | | Compressed size(LE 4 bytes) | |- * | +-----------------------------+ --+- * | | |- * | | .................. |- * | | |- * | +-----------------------------+ --+- * | | Offset (LE 4 bytes) | |- * | +-----------------------------+ | Block (Block count -1)- * | | Compressed size(LE 4 bytes) | |- * +-> +-----------------------------+ --+- * | Compressed data(n bytes) | Block 0- * +-----------------------------+- * | |- * | .................. |- * | |- * +-----------------------------+- * | Compressed data(n bytes) | Block (Block count -1)- * +-----------------------------+- * | Footer(50 bytes) |- * +-----------------------------+- *- */-/*- * Write the header of "com.apple.ResourceFork"- */-static int-hfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff,- size_t bytes, uint32_t position)-{- int ret;-- ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes,- position, a->rsrc_xattr_options);- if (ret < 0) {- archive_set_error(&a->archive, errno,- "Cannot restore xattr: %s at %u pos %u bytes",- XATTR_RESOURCEFORK_NAME,- (unsigned)position,- (unsigned)bytes);- return (ARCHIVE_WARN);- }- a->rsrc_xattr_options &= ~XATTR_CREATE;- return (ARCHIVE_OK);-}--static int-hfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed)-{- int ret;-- ret = hfs_write_resource_fork(a, a->compressed_buffer,- bytes_compressed, a->compressed_rsrc_position);- if (ret == ARCHIVE_OK)- a->compressed_rsrc_position += bytes_compressed;- return (ret);-}--static int-hfs_write_resource_fork_header(struct archive_write_disk *a)-{- unsigned char *buff;- uint32_t rsrc_bytes;- uint32_t rsrc_header_bytes;-- /*- * Write resource fork header + block info.- */- buff = a->resource_fork;- rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE;- rsrc_header_bytes =- RSRC_H_SIZE + /* Header base size. */- 4 + /* Block count. */- (a->decmpfs_block_count * 8);/* Block info */- archive_be32enc(buff, 0x100);- archive_be32enc(buff + 4, rsrc_bytes);- archive_be32enc(buff + 8, rsrc_bytes - 256);- archive_be32enc(buff + 12, 0x32);- memset(buff + 16, 0, 240);- archive_be32enc(buff + 256, rsrc_bytes - 260);- return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0);-}--static size_t-hfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size)-{- static const char rsrc_footer[RSRC_F_SIZE] = {- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,- 0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c', 'm',- 'p', 'f', 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01,- 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,- 0x00, 0x00- };- if (buff_size < sizeof(rsrc_footer))- return (0);- memcpy(buff, rsrc_footer, sizeof(rsrc_footer));- return (sizeof(rsrc_footer));-}--static int-hfs_reset_compressor(struct archive_write_disk *a)-{- int ret;-- if (a->stream_valid)- ret = deflateReset(&a->stream);- else- ret = deflateInit(&a->stream, a->decmpfs_compression_level);-- if (ret != Z_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to initialize compressor");- return (ARCHIVE_FATAL);- } else- a->stream_valid = 1;-- return (ARCHIVE_OK);-}--static int-hfs_decompress(struct archive_write_disk *a)-{- uint32_t *block_info;- unsigned int block_count;- uint32_t data_pos, data_size;- ssize_t r;- ssize_t bytes_written, bytes_to_write;- unsigned char *b;-- block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE);- block_count = archive_le32dec(block_info++);- while (block_count--) {- data_pos = RSRC_H_SIZE + archive_le32dec(block_info++);- data_size = archive_le32dec(block_info++);- r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME,- a->compressed_buffer, data_size, data_pos, 0);- if (r != data_size) {- archive_set_error(&a->archive,- (r < 0)?errno:ARCHIVE_ERRNO_MISC,- "Failed to read resource fork");- return (ARCHIVE_WARN);- }- if (a->compressed_buffer[0] == 0xff) {- bytes_to_write = data_size -1;- b = a->compressed_buffer + 1;- } else {- uLong dest_len = MAX_DECMPFS_BLOCK_SIZE;- int zr;-- zr = uncompress((Bytef *)a->uncompressed_buffer,- &dest_len, a->compressed_buffer, data_size);- if (zr != Z_OK) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to decompress resource fork");- return (ARCHIVE_WARN);- }- bytes_to_write = dest_len;- b = (unsigned char *)a->uncompressed_buffer;- }- do {- bytes_written = write(a->fd, b, bytes_to_write);- if (bytes_written < 0) {- archive_set_error(&a->archive, errno,- "Write failed");- return (ARCHIVE_WARN);- }- bytes_to_write -= bytes_written;- b += bytes_written;- } while (bytes_to_write > 0);- }- r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0);- if (r == -1) {- archive_set_error(&a->archive, errno,- "Failed to remove resource fork");- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-}--static int-hfs_drive_compressor(struct archive_write_disk *a, const char *buff,- size_t size)-{- unsigned char *buffer_compressed;- size_t bytes_compressed;- size_t bytes_used;- int ret;-- ret = hfs_reset_compressor(a);- if (ret != ARCHIVE_OK)- return (ret);-- if (a->compressed_buffer == NULL) {- size_t block_size;-- block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE +- + compressBound(MAX_DECMPFS_BLOCK_SIZE);- a->compressed_buffer = malloc(block_size);- if (a->compressed_buffer == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Resource Fork");- return (ARCHIVE_FATAL);- }- a->compressed_buffer_size = block_size;- a->compressed_buffer_remaining = block_size;- }-- buffer_compressed = a->compressed_buffer +- a->compressed_buffer_size - a->compressed_buffer_remaining;- a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff;- a->stream.avail_in = size;- a->stream.next_out = buffer_compressed;- a->stream.avail_out = a->compressed_buffer_remaining;- do {- ret = deflate(&a->stream, Z_FINISH);- switch (ret) {- case Z_OK:- case Z_STREAM_END:- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to compress data");- return (ARCHIVE_FAILED);- }- } while (ret == Z_OK);- bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out;-- /*- * If the compressed size is larger than the original size,- * throw away compressed data, use uncompressed data instead.- */- if (bytes_compressed > size) {- buffer_compressed[0] = 0xFF;/* uncompressed marker. */- memcpy(buffer_compressed + 1, buff, size);- bytes_compressed = size + 1;- }- a->compressed_buffer_remaining -= bytes_compressed;-- /*- * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE- * and the block count in the file is only one, store compressed- * data to decmpfs xattr instead of the resource fork.- */- if (a->decmpfs_block_count == 1 &&- (a->decmpfs_attr_size + bytes_compressed)- <= MAX_DECMPFS_XATTR_SIZE) {- archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],- CMP_XATTR);- memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE,- buffer_compressed, bytes_compressed);- a->decmpfs_attr_size += bytes_compressed;- a->compressed_buffer_remaining = a->compressed_buffer_size;- /*- * Finish HFS+ Compression.- * - Write the decmpfs xattr.- * - Set the UF_COMPRESSED file flag.- */- ret = hfs_write_decmpfs(a);- if (ret == ARCHIVE_OK)- ret = hfs_set_compressed_fflag(a);- return (ret);- }-- /* Update block info. */- archive_le32enc(a->decmpfs_block_info++,- a->compressed_rsrc_position_v - RSRC_H_SIZE);- archive_le32enc(a->decmpfs_block_info++, bytes_compressed);- a->compressed_rsrc_position_v += bytes_compressed;-- /*- * Write the compressed data to the resource fork.- */- bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining;- while (bytes_used >= COMPRESSED_W_SIZE) {- ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE);- if (ret != ARCHIVE_OK)- return (ret);- bytes_used -= COMPRESSED_W_SIZE;- if (bytes_used > COMPRESSED_W_SIZE)- memmove(a->compressed_buffer,- a->compressed_buffer + COMPRESSED_W_SIZE,- bytes_used);- else- memcpy(a->compressed_buffer,- a->compressed_buffer + COMPRESSED_W_SIZE,- bytes_used);- }- a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used;-- /*- * If the current block is the last block, write the remaining- * compressed data and the resource fork footer.- */- if (a->file_remaining_bytes == 0) {- size_t rsrc_size;- int64_t bk;-- /* Append the resource footer. */- rsrc_size = hfs_set_resource_fork_footer(- a->compressed_buffer + bytes_used,- a->compressed_buffer_remaining);- ret = hfs_write_compressed_data(a, bytes_used + rsrc_size);- a->compressed_buffer_remaining = a->compressed_buffer_size;-- /* If the compressed size is not enough smaller than- * the uncompressed size. cancel HFS+ compression.- * TODO: study a behavior of ditto utility and improve- * the condition to fall back into no HFS+ compression. */- bk = HFS_BLOCKS(a->compressed_rsrc_position);- bk += bk >> 7;- if (bk > HFS_BLOCKS(a->filesize))- return hfs_decompress(a);- /*- * Write the resourcefork header.- */- if (ret == ARCHIVE_OK)- ret = hfs_write_resource_fork_header(a);- /*- * Finish HFS+ Compression.- * - Write the decmpfs xattr.- * - Set the UF_COMPRESSED file flag.- */- if (ret == ARCHIVE_OK)- ret = hfs_write_decmpfs(a);- if (ret == ARCHIVE_OK)- ret = hfs_set_compressed_fflag(a);- }- return (ret);-}--static ssize_t-hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,- size_t size)-{- const char *buffer_to_write;- size_t bytes_to_write;- int ret;-- if (a->decmpfs_block_count == (unsigned)-1) {- void *new_block;- size_t new_size;- unsigned int block_count;-- if (a->decmpfs_header_p == NULL) {- new_block = malloc(MAX_DECMPFS_XATTR_SIZE- + sizeof(uint32_t));- if (new_block == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for decmpfs");- return (ARCHIVE_FATAL);- }- a->decmpfs_header_p = new_block;- }- a->decmpfs_attr_size = DECMPFS_HEADER_SIZE;- archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC],- DECMPFS_MAGIC);- archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],- CMP_RESOURCE_FORK);- archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE],- a->filesize);-- /* Calculate a block count of the file. */- block_count =- (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) /- MAX_DECMPFS_BLOCK_SIZE;- /*- * Allocate buffer for resource fork.- * Set up related pointers;- */- new_size =- RSRC_H_SIZE + /* header */- 4 + /* Block count */- (block_count * sizeof(uint32_t) * 2) +- RSRC_F_SIZE; /* footer */- if (new_size > a->resource_fork_allocated_size) {- new_block = realloc(a->resource_fork, new_size);- if (new_block == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for ResourceFork");- return (ARCHIVE_FATAL);- }- a->resource_fork_allocated_size = new_size;- a->resource_fork = new_block;- }-- /* Allocate uncompressed buffer */- if (a->uncompressed_buffer == NULL) {- new_block = malloc(MAX_DECMPFS_BLOCK_SIZE);- if (new_block == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for decmpfs");- return (ARCHIVE_FATAL);- }- a->uncompressed_buffer = new_block;- }- a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;- a->file_remaining_bytes = a->filesize;- a->compressed_buffer_remaining = a->compressed_buffer_size;-- /*- * Set up a resource fork.- */- a->rsrc_xattr_options = XATTR_CREATE;- /* Get the position where we are going to set a bunch- * of block info. */- a->decmpfs_block_info =- (uint32_t *)(a->resource_fork + RSRC_H_SIZE);- /* Set the block count to the resource fork. */- archive_le32enc(a->decmpfs_block_info++, block_count);- /* Get the position where we are going to set compressed- * data. */- a->compressed_rsrc_position =- RSRC_H_SIZE + 4 + (block_count * 8);- a->compressed_rsrc_position_v = a->compressed_rsrc_position;- a->decmpfs_block_count = block_count;- }-- /* Ignore redundant bytes. */- if (a->file_remaining_bytes == 0)- return ((ssize_t)size);-- /* Do not overrun a block size. */- if (size > a->block_remaining_bytes)- bytes_to_write = a->block_remaining_bytes;- else- bytes_to_write = size;- /* Do not overrun the file size. */- if (bytes_to_write > a->file_remaining_bytes)- bytes_to_write = a->file_remaining_bytes;-- /* For efficiency, if a copy length is full of the uncompressed- * buffer size, do not copy writing data to it. */- if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE)- buffer_to_write = buff;- else {- memcpy(a->uncompressed_buffer +- MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes,- buff, bytes_to_write);- buffer_to_write = a->uncompressed_buffer;- }- a->block_remaining_bytes -= bytes_to_write;- a->file_remaining_bytes -= bytes_to_write;-- if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) {- ret = hfs_drive_compressor(a, buffer_to_write,- MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes);- if (ret < 0)- return (ret);- a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;- }- /* Ignore redundant bytes. */- if (a->file_remaining_bytes == 0)- return ((ssize_t)size);- return (bytes_to_write);-}--static ssize_t-hfs_write_data_block(struct archive_write_disk *a, const char *buff,- size_t size)-{- uint64_t start_size = size;- ssize_t bytes_written = 0;- ssize_t bytes_to_write;-- if (size == 0)- return (ARCHIVE_OK);-- if (a->filesize == 0 || a->fd < 0) {- archive_set_error(&a->archive, 0,- "Attempt to write to an empty file");- return (ARCHIVE_WARN);- }-- /* If this write would run beyond the file size, truncate it. */- if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)- start_size = size = (size_t)(a->filesize - a->offset);-- /* Write the data. */- while (size > 0) {- bytes_to_write = size;- /* Seek if necessary to the specified offset. */- if (a->offset < a->fd_offset) {- /* Can't support backward move. */- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Seek failed");- return (ARCHIVE_FATAL);- } else if (a->offset > a->fd_offset) {- uint64_t skip = a->offset - a->fd_offset;- char nullblock[1024];-- memset(nullblock, 0, sizeof(nullblock));- while (skip > 0) {- if (skip > sizeof(nullblock))- bytes_written = hfs_write_decmpfs_block(- a, nullblock, sizeof(nullblock));- else- bytes_written = hfs_write_decmpfs_block(- a, nullblock, skip);- if (bytes_written < 0) {- archive_set_error(&a->archive, errno,- "Write failed");- return (ARCHIVE_WARN);- }- skip -= bytes_written;- }-- a->fd_offset = a->offset;- }- bytes_written =- hfs_write_decmpfs_block(a, buff, bytes_to_write);- if (bytes_written < 0)- return (bytes_written);- buff += bytes_written;- size -= bytes_written;- a->total_bytes_written += bytes_written;- a->offset += bytes_written;- a->fd_offset = a->offset;- }- return (start_size - size);-}-#else-static ssize_t-hfs_write_data_block(struct archive_write_disk *a, const char *buff,- size_t size)-{- return (write_data_block(a, buff, size));-}-#endif--static ssize_t-_archive_write_disk_data_block(struct archive *_a,- const void *buff, size_t size, int64_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_data_block");-- a->offset = offset;- if (a->todo & TODO_HFS_COMPRESSION)- r = hfs_write_data_block(a, buff, size);- else- r = write_data_block(a, buff, size);- if (r < ARCHIVE_OK)- return (r);- if ((size_t)r < size) {- archive_set_error(&a->archive, 0,- "Too much data: Truncating file at %ju bytes",- (uintmax_t)a->filesize);- return (ARCHIVE_WARN);- }-#if ARCHIVE_VERSION_NUMBER < 3999000- return (ARCHIVE_OK);-#else- return (size);-#endif-}--static ssize_t-_archive_write_disk_data(struct archive *_a, const void *buff, size_t size)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_DATA, "archive_write_data");-- if (a->todo & TODO_HFS_COMPRESSION)- return (hfs_write_data_block(a, buff, size));- return (write_data_block(a, buff, size));-}--static int-_archive_write_disk_finish_entry(struct archive *_a)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- int ret = ARCHIVE_OK;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_write_finish_entry");- if (a->archive.state & ARCHIVE_STATE_HEADER)- return (ARCHIVE_OK);- archive_clear_error(&a->archive);-- /* Pad or truncate file to the right size. */- if (a->fd < 0) {- /* There's no file. */- } else if (a->filesize < 0) {- /* File size is unknown, so we can't set the size. */- } else if (a->fd_offset == a->filesize) {- /* Last write ended at exactly the filesize; we're done. */- /* Hopefully, this is the common case. */-#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)- } else if (a->todo & TODO_HFS_COMPRESSION) {- char null_d[1024];- ssize_t r;-- if (a->file_remaining_bytes)- memset(null_d, 0, sizeof(null_d));- while (a->file_remaining_bytes) {- if (a->file_remaining_bytes > sizeof(null_d))- r = hfs_write_data_block(- a, null_d, sizeof(null_d));- else- r = hfs_write_data_block(- a, null_d, a->file_remaining_bytes);- if (r < 0) {- close_file_descriptor(a);- return ((int)r);- }- }-#endif- } else {-#if HAVE_FTRUNCATE- if (ftruncate(a->fd, a->filesize) == -1 &&- a->filesize == 0) {- archive_set_error(&a->archive, errno,- "File size could not be restored");- close_file_descriptor(a);- return (ARCHIVE_FAILED);- }-#endif- /*- * Not all platforms implement the XSI option to- * extend files via ftruncate. Stat() the file again- * to see what happened.- */- a->pst = NULL;- if ((ret = lazy_stat(a)) != ARCHIVE_OK) {- close_file_descriptor(a);- return (ret);- }- /* We can use lseek()/write() to extend the file if- * ftruncate didn't work or isn't available. */- if (a->st.st_size < a->filesize) {- const char nul = '\0';- if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) {- archive_set_error(&a->archive, errno,- "Seek failed");- close_file_descriptor(a);- return (ARCHIVE_FATAL);- }- if (write(a->fd, &nul, 1) < 0) {- archive_set_error(&a->archive, errno,- "Write to restore size failed");- close_file_descriptor(a);- return (ARCHIVE_FATAL);- }- a->pst = NULL;- }- }-- /* Restore metadata. */-- /*- * This is specific to Mac OS X.- * If the current file is an AppleDouble file, it should be- * linked with the data fork file and remove it.- */- if (a->todo & TODO_APPLEDOUBLE) {- int r2 = fixup_appledouble(a, a->name);- if (r2 == ARCHIVE_EOF) {- /* The current file has been successfully linked- * with the data fork file and removed. So there- * is nothing to do on the current file. */- goto finish_metadata;- }- if (r2 < ret) ret = r2;- }-- /*- * Look up the "real" UID only if we're going to need it.- * TODO: the TODO_SGID condition can be dropped here, can't it?- */- if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) {- a->uid = archive_write_disk_uid(&a->archive,- archive_entry_uname(a->entry),- archive_entry_uid(a->entry));- }- /* Look up the "real" GID only if we're going to need it. */- /* TODO: the TODO_SUID condition can be dropped here, can't it? */- if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) {- a->gid = archive_write_disk_gid(&a->archive,- archive_entry_gname(a->entry),- archive_entry_gid(a->entry));- }-- /*- * Restore ownership before set_mode tries to restore suid/sgid- * bits. If we set the owner, we know what it is and can skip- * a stat() call to examine the ownership of the file on disk.- */- if (a->todo & TODO_OWNER) {- int r2 = set_ownership(a);- if (r2 < ret) ret = r2;- }-- /*- * HYPOTHESIS:- * If we're not root, we won't be setting any security- * attributes that may be wiped by the set_mode() routine- * below. We also can't set xattr on non-owner-writable files,- * which may be the state after set_mode(). Perform- * set_xattrs() first based on these constraints.- */- if (a->user_uid != 0 &&- (a->todo & TODO_XATTR)) {- int r2 = set_xattrs(a);- if (r2 < ret) ret = r2;- }-- /*- * set_mode must precede ACLs on systems such as Solaris and- * FreeBSD where setting the mode implicitly clears extended ACLs- */- if (a->todo & TODO_MODE) {- int r2 = set_mode(a, a->mode);- if (r2 < ret) ret = r2;- }-- /*- * Security-related extended attributes (such as- * security.capability on Linux) have to be restored last,- * since they're implicitly removed by other file changes.- * We do this last only when root.- */- if (a->user_uid == 0 &&- (a->todo & TODO_XATTR)) {- int r2 = set_xattrs(a);- if (r2 < ret) ret = r2;- }-- /*- * Some flags prevent file modification; they must be restored after- * file contents are written.- */- if (a->todo & TODO_FFLAGS) {- int r2 = set_fflags(a);- if (r2 < ret) ret = r2;- }-- /*- * Time must follow most other metadata;- * otherwise atime will get changed.- */- if (a->todo & TODO_TIMES) {- int r2 = set_times_from_entry(a);- if (r2 < ret) ret = r2;- }-- /*- * Mac extended metadata includes ACLs.- */- if (a->todo & TODO_MAC_METADATA) {- const void *metadata;- size_t metadata_size;- metadata = archive_entry_mac_metadata(a->entry, &metadata_size);- if (metadata != NULL && metadata_size > 0) {- int r2 = set_mac_metadata(a, archive_entry_pathname(- a->entry), metadata, metadata_size);- if (r2 < ret) ret = r2;- }- }-- /*- * ACLs must be restored after timestamps because there are- * ACLs that prevent attribute changes (including time).- */- if (a->todo & TODO_ACLS) {- int r2;- r2 = archive_write_disk_set_acls(&a->archive, a->fd,- archive_entry_pathname(a->entry),- archive_entry_acl(a->entry),- archive_entry_mode(a->entry));- if (r2 < ret) ret = r2;- }--finish_metadata:- /* If there's an fd, we can close it now. */- if (a->fd >= 0) {- close(a->fd);- a->fd = -1;- if (a->tmpname) {- if (rename(a->tmpname, a->name) == -1) {- archive_set_error(&a->archive, errno,- "Failed to rename temporary file");- ret = ARCHIVE_FAILED;- unlink(a->tmpname);- }- a->tmpname = NULL;- }- }- /* If there's an entry, we can release it now. */- archive_entry_free(a->entry);- a->entry = NULL;- a->archive.state = ARCHIVE_STATE_HEADER;- return (ret);-}--int-archive_write_disk_set_group_lookup(struct archive *_a,- void *private_data,- la_int64_t (*lookup_gid)(void *private, const char *gname, la_int64_t gid),- void (*cleanup_gid)(void *private))-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup");-- if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL)- (a->cleanup_gid)(a->lookup_gid_data);-- a->lookup_gid = lookup_gid;- a->cleanup_gid = cleanup_gid;- a->lookup_gid_data = private_data;- return (ARCHIVE_OK);-}--int-archive_write_disk_set_user_lookup(struct archive *_a,- void *private_data,- int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid),- void (*cleanup_uid)(void *private))-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup");-- if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL)- (a->cleanup_uid)(a->lookup_uid_data);-- a->lookup_uid = lookup_uid;- a->cleanup_uid = cleanup_uid;- a->lookup_uid_data = private_data;- return (ARCHIVE_OK);-}--int64_t-archive_write_disk_gid(struct archive *_a, const char *name, la_int64_t id)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_disk_gid");- if (a->lookup_gid)- return (a->lookup_gid)(a->lookup_gid_data, name, id);- return (id);-}- -int64_t-archive_write_disk_uid(struct archive *_a, const char *name, la_int64_t id)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_disk_uid");- if (a->lookup_uid)- return (a->lookup_uid)(a->lookup_uid_data, name, id);- return (id);-}--/*- * Create a new archive_write_disk object and initialize it with global state.- */-struct archive *-archive_write_disk_new(void)-{- struct archive_write_disk *a;-- a = (struct archive_write_disk *)calloc(1, sizeof(*a));- if (a == NULL)- return (NULL);- a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;- /* We're ready to write a header immediately. */- a->archive.state = ARCHIVE_STATE_HEADER;- a->archive.vtable = &archive_write_disk_vtable;- a->start_time = time(NULL);- /* Query and restore the umask. */- umask(a->user_umask = umask(0));-#ifdef HAVE_GETEUID- a->user_uid = geteuid();-#endif /* HAVE_GETEUID */- if (archive_string_ensure(&a->path_safe, 512) == NULL) {- free(a);- return (NULL);- }- a->path_safe.s[0] = 0;--#ifdef HAVE_ZLIB_H- a->decmpfs_compression_level = 5;-#endif- return (&a->archive);-}---/*- * If pathname is longer than PATH_MAX, chdir to a suitable- * intermediate dir and edit the path down to a shorter suffix. Note- * that this routine never returns an error; if the chdir() attempt- * fails for any reason, we just go ahead with the long pathname. The- * object creation is likely to fail, but any error will get handled- * at that time.- */-#if defined(HAVE_FCHDIR) && defined(PATH_MAX)-static void-edit_deep_directories(struct archive_write_disk *a)-{- int ret;- char *tail = a->name;-- /* If path is short, avoid the open() below. */- if (strlen(tail) < PATH_MAX)- return;-- /* Try to record our starting dir. */- a->restore_pwd = la_opendirat(AT_FDCWD, ".");- __archive_ensure_cloexec_flag(a->restore_pwd);- if (a->restore_pwd < 0)- return;-- /* As long as the path is too long... */- while (strlen(tail) >= PATH_MAX) {- /* Locate a dir prefix shorter than PATH_MAX. */- tail += PATH_MAX - 8;- while (tail > a->name && *tail != '/')- tail--;- /* Exit if we find a too-long path component. */- if (tail <= a->name)- return;- /* Create the intermediate dir and chdir to it. */- *tail = '\0'; /* Terminate dir portion */- ret = create_dir(a, a->name);- if (ret == ARCHIVE_OK && chdir(a->name) != 0)- ret = ARCHIVE_FAILED;- *tail = '/'; /* Restore the / we removed. */- if (ret != ARCHIVE_OK)- return;- tail++;- /* The chdir() succeeded; we've now shortened the path. */- a->name = tail;- }- return;-}-#endif--/*- * The main restore function.- */-static int-restore_entry(struct archive_write_disk *a)-{- int ret = ARCHIVE_OK, en;-- if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) {- /*- * TODO: Fix this. Apparently, there are platforms- * that still allow root to hose the entire filesystem- * by unlinking a dir. The S_ISDIR() test above- * prevents us from using unlink() here if the new- * object is a dir, but that doesn't mean the old- * object isn't a dir.- */- if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)- (void)clear_nochange_fflags(a);- if (unlink(a->name) == 0) {- /* We removed it, reset cached stat. */- a->pst = NULL;- } else if (errno == ENOENT) {- /* File didn't exist, that's just as good. */- } else if (rmdir(a->name) == 0) {- /* It was a dir, but now it's gone. */- a->pst = NULL;- } else {- /* We tried, but couldn't get rid of it. */- archive_set_error(&a->archive, errno,- "Could not unlink");- return(ARCHIVE_FAILED);- }- }-- /* Try creating it first; if this fails, we'll try to recover. */- en = create_filesystem_object(a);-- if ((en == ENOTDIR || en == ENOENT)- && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) {- /* If the parent dir doesn't exist, try creating it. */- create_parent_dir(a, a->name);- /* Now try to create the object again. */- en = create_filesystem_object(a);- }-- if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) {- archive_set_error(&a->archive, en,- "Hard-link target '%s' does not exist.",- archive_entry_hardlink(a->entry));- return (ARCHIVE_FAILED);- }-- if ((en == EISDIR || en == EEXIST)- && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {- /* If we're not overwriting, we're done. */- if (S_ISDIR(a->mode)) {- /* Don't overwrite any settings on existing directories. */- a->todo = 0;- }- archive_entry_unset_size(a->entry);- return (ARCHIVE_OK);- }-- /*- * Some platforms return EISDIR if you call- * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some- * return EEXIST. POSIX is ambiguous, requiring EISDIR- * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT)- * on an existing item.- */- if (en == EISDIR) {- /* A dir is in the way of a non-dir, rmdir it. */- if (rmdir(a->name) != 0) {- archive_set_error(&a->archive, errno,- "Can't remove already-existing dir");- return (ARCHIVE_FAILED);- }- a->pst = NULL;- /* Try again. */- en = create_filesystem_object(a);- } else if (en == EEXIST) {- /*- * We know something is in the way, but we don't know what;- * we need to find out before we go any further.- */- int r = 0;- /*- * The SECURE_SYMLINKS logic has already removed a- * symlink to a dir if the client wants that. So- * follow the symlink if we're creating a dir.- */- if (S_ISDIR(a->mode))- r = la_stat(a->name, &a->st);- /*- * If it's not a dir (or it's a broken symlink),- * then don't follow it.- */- if (r != 0 || !S_ISDIR(a->mode))-#ifdef HAVE_LSTAT- r = lstat(a->name, &a->st);-#else- r = la_stat(a->name, &a->st);-#endif- if (r != 0) {- archive_set_error(&a->archive, errno,- "Can't stat existing object");- return (ARCHIVE_FAILED);- }-- /*- * NO_OVERWRITE_NEWER doesn't apply to directories.- */- if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER)- && !S_ISDIR(a->st.st_mode)) {- if (!older(&(a->st), a->entry)) {- archive_entry_unset_size(a->entry);- return (ARCHIVE_OK);- }- }-- /* If it's our archive, we're done. */- if (a->skip_file_set &&- a->st.st_dev == (dev_t)a->skip_file_dev &&- a->st.st_ino == (ino_t)a->skip_file_ino) {- archive_set_error(&a->archive, 0,- "Refusing to overwrite archive");- return (ARCHIVE_FAILED);- }-- if (!S_ISDIR(a->st.st_mode)) {- if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)- (void)clear_nochange_fflags(a);-- if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) &&- S_ISREG(a->st.st_mode)) {- /* Use a temporary file to extract */- if ((a->fd = la_mktemp(a)) == -1) {- archive_set_error(&a->archive, errno,- "Can't create temporary file");- return ARCHIVE_FAILED;- }- a->pst = NULL;- en = 0;- } else {- /* A non-dir is in the way, unlink it. */- if (unlink(a->name) != 0) {- archive_set_error(&a->archive, errno,- "Can't unlink already-existing "- "object");- return (ARCHIVE_FAILED);- }- a->pst = NULL;- /* Try again. */- en = create_filesystem_object(a);- }- } else if (!S_ISDIR(a->mode)) {- /* A dir is in the way of a non-dir, rmdir it. */- if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)- (void)clear_nochange_fflags(a);- if (rmdir(a->name) != 0) {- archive_set_error(&a->archive, errno,- "Can't replace existing directory with non-directory");- return (ARCHIVE_FAILED);- }- /* Try again. */- en = create_filesystem_object(a);- } else {- /*- * There's a dir in the way of a dir. Don't- * waste time with rmdir()/mkdir(), just fix- * up the permissions on the existing dir.- * Note that we don't change perms on existing- * dirs unless _EXTRACT_PERM is specified.- */- if ((a->mode != a->st.st_mode)- && (a->todo & TODO_MODE_FORCE))- a->deferred |= (a->todo & TODO_MODE);- /* Ownership doesn't need deferred fixup. */- en = 0; /* Forget the EEXIST. */- }- }-- if (en) {- /* Everything failed; give up here. */- if ((&a->archive)->error == NULL)- archive_set_error(&a->archive, en, "Can't create '%s'",- a->name);- return (ARCHIVE_FAILED);- }-- a->pst = NULL; /* Cached stat data no longer valid. */- return (ret);-}--/*- * Returns 0 if creation succeeds, or else returns errno value from- * the failed system call. Note: This function should only ever perform- * a single system call.- */-static int-create_filesystem_object(struct archive_write_disk *a)-{- /* Create the entry. */- const char *linkname;- mode_t final_mode, mode;- int r;- /* these for check_symlinks_fsobj */- char *linkname_copy; /* non-const copy of linkname */- struct stat st;- struct archive_string error_string;- int error_number;-- /* We identify hard/symlinks according to the link names. */- /* Since link(2) and symlink(2) don't handle modes, we're done here. */- linkname = archive_entry_hardlink(a->entry);- if (linkname != NULL) {-#if !HAVE_LINK- return (EPERM);-#else- archive_string_init(&error_string);- linkname_copy = strdup(linkname);- if (linkname_copy == NULL) {- return (EPERM);- }- /*- * TODO: consider using the cleaned-up path as the link- * target?- */- r = cleanup_pathname_fsobj(linkname_copy, &error_number,- &error_string, a->flags);- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, error_number, "%s",- error_string.s);- free(linkname_copy);- archive_string_free(&error_string);- /*- * EPERM is more appropriate than error_number for our- * callers- */- return (EPERM);- }- r = check_symlinks_fsobj(linkname_copy, &error_number,- &error_string, a->flags, 1);- if (r != ARCHIVE_OK) {- archive_set_error(&a->archive, error_number, "%s",- error_string.s);- free(linkname_copy);- archive_string_free(&error_string);- /*- * EPERM is more appropriate than error_number for our- * callers- */- return (EPERM);- }- free(linkname_copy);- archive_string_free(&error_string);- /*- * Unlinking and linking here is really not atomic,- * but doing it right, would require us to construct- * an mktemplink() function, and then use rename(2).- */- if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES)- unlink(a->name);-#ifdef HAVE_LINKAT- r = linkat(AT_FDCWD, linkname, AT_FDCWD, a->name,- 0) ? errno : 0;-#else- r = link(linkname, a->name) ? errno : 0;-#endif- /*- * New cpio and pax formats allow hardlink entries- * to carry data, so we may have to open the file- * for hardlink entries.- *- * If the hardlink was successfully created and- * the archive doesn't have carry data for it,- * consider it to be non-authoritative for meta data.- * This is consistent with GNU tar and BSD pax.- * If the hardlink does carry data, let the last- * archive entry decide ownership.- */- if (r == 0 && a->filesize <= 0) {- a->todo = 0;- a->deferred = 0;- } else if (r == 0 && a->filesize > 0) {-#ifdef HAVE_LSTAT- r = lstat(a->name, &st);-#else- r = la_stat(a->name, &st);-#endif- if (r != 0)- r = errno;- else if ((st.st_mode & AE_IFMT) == AE_IFREG) {- a->fd = open(a->name, O_WRONLY | O_TRUNC |- O_BINARY | O_CLOEXEC | O_NOFOLLOW);- __archive_ensure_cloexec_flag(a->fd);- if (a->fd < 0)- r = errno;- }- }- return (r);-#endif- }- linkname = archive_entry_symlink(a->entry);- if (linkname != NULL) {-#if HAVE_SYMLINK- /*- * Unlinking and linking here is really not atomic,- * but doing it right, would require us to construct- * an mktempsymlink() function, and then use rename(2).- */- if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES)- unlink(a->name);- return symlink(linkname, a->name) ? errno : 0;-#else- return (EPERM);-#endif- }-- /*- * The remaining system calls all set permissions, so let's- * try to take advantage of that to avoid an extra chmod()- * call. (Recall that umask is set to zero right now!)- */-- /* Mode we want for the final restored object (w/o file type bits). */- final_mode = a->mode & 07777;- /*- * The mode that will actually be restored in this step. Note- * that SUID, SGID, etc, require additional work to ensure- * security, so we never restore them at this point.- */- mode = final_mode & 0777 & ~a->user_umask;-- /* - * Always create writable such that [f]setxattr() works if we're not- * root.- */- if (a->user_uid != 0 &&- a->todo & (TODO_HFS_COMPRESSION | TODO_XATTR)) {- mode |= 0200;- }-- switch (a->mode & AE_IFMT) {- default:- /* POSIX requires that we fall through here. */- /* FALLTHROUGH */- case AE_IFREG:- a->tmpname = NULL;- a->fd = open(a->name,- O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode);- __archive_ensure_cloexec_flag(a->fd);- r = (a->fd < 0);- break;- case AE_IFCHR:-#ifdef HAVE_MKNOD- /* Note: we use AE_IFCHR for the case label, and- * S_IFCHR for the mknod() call. This is correct. */- r = mknod(a->name, mode | S_IFCHR,- archive_entry_rdev(a->entry));- break;-#else- /* TODO: Find a better way to warn about our inability- * to restore a char device node. */- return (EINVAL);-#endif /* HAVE_MKNOD */- case AE_IFBLK:-#ifdef HAVE_MKNOD- r = mknod(a->name, mode | S_IFBLK,- archive_entry_rdev(a->entry));- break;-#else- /* TODO: Find a better way to warn about our inability- * to restore a block device node. */- return (EINVAL);-#endif /* HAVE_MKNOD */- case AE_IFDIR:- mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE;- r = mkdir(a->name, mode);- if (r == 0) {- /* Defer setting dir times. */- a->deferred |= (a->todo & TODO_TIMES);- a->todo &= ~TODO_TIMES;- /* Never use an immediate chmod(). */- /* We can't avoid the chmod() entirely if EXTRACT_PERM- * because of SysV SGID inheritance. */- if ((mode != final_mode)- || (a->flags & ARCHIVE_EXTRACT_PERM))- a->deferred |= (a->todo & TODO_MODE);- a->todo &= ~TODO_MODE;- }- break;- case AE_IFIFO:-#ifdef HAVE_MKFIFO- r = mkfifo(a->name, mode);- break;-#else- /* TODO: Find a better way to warn about our inability- * to restore a fifo. */- return (EINVAL);-#endif /* HAVE_MKFIFO */- }-- /* All the system calls above set errno on failure. */- if (r)- return (errno);-- /* If we managed to set the final mode, we've avoided a chmod(). */- if (mode == final_mode)- a->todo &= ~TODO_MODE;- return (0);-}--/*- * Cleanup function for archive_extract. Mostly, this involves processing- * the fixup list, which is used to address a number of problems:- * * Dir permissions might prevent us from restoring a file in that- * dir, so we restore the dir with minimum 0700 permissions first,- * then correct the mode at the end.- * * Similarly, the act of restoring a file touches the directory- * and changes the timestamp on the dir, so we have to touch-up dir- * timestamps at the end as well.- * * Some file flags can interfere with the restore by, for example,- * preventing the creation of hardlinks to those files.- * * Mac OS extended metadata includes ACLs, so must be deferred on dirs.- *- * Note that tar/cpio do not require that archives be in a particular- * order; there is no way to know when the last file has been restored- * within a directory, so there's no way to optimize the memory usage- * here by fixing up the directory any earlier than the- * end-of-archive.- *- * XXX TODO: Directory ACLs should be restored here, for the same- * reason we set directory perms here. XXX- */-static int-_archive_write_disk_close(struct archive *_a)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- struct fixup_entry *next, *p;- struct stat st;- char *c;- int fd, ret, openflags;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_write_disk_close");- 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);-- while (p != NULL) {- fd = -1;- a->pst = NULL; /* Mark stat cache as out-of-date. */-- /* We must strip trailing slashes from the path to avoid- dereferencing symbolic links to directories */- c = p->name;- while (*c != '\0')- c++;- while (c != p->name && *(c - 1) == '/') {- c--;- *c = '\0';- }-- if (p->fixup == 0)- goto skip_fixup_entry;- else {- /*- * We need to verify if the type of the file- * we are going to open matches the file type- * of the fixup entry.- */- openflags = O_BINARY | O_NOFOLLOW | O_RDONLY- | O_CLOEXEC;-#if defined(O_DIRECTORY)- if (p->filetype == AE_IFDIR)- openflags |= O_DIRECTORY;-#endif- fd = open(p->name, openflags);--#if defined(O_DIRECTORY)- /*- * If we support O_DIRECTORY and open was- * successful we can skip the file type check- * for directories. For other file types- * we need to verify via fstat() or lstat()- */- if (fd == -1 || p->filetype != AE_IFDIR) {-#if HAVE_FSTAT- if (fd > 0 && (- fstat(fd, &st) != 0 ||- la_verify_filetype(st.st_mode,- p->filetype) == 0)) {- goto skip_fixup_entry;- } else-#endif- if (-#ifdef HAVE_LSTAT- lstat(p->name, &st) != 0 ||-#else- la_stat(p->name, &st) != 0 ||-#endif- la_verify_filetype(st.st_mode,- p->filetype) == 0) {- goto skip_fixup_entry;- }- }-#else-#if HAVE_FSTAT- if (fd > 0 && (- fstat(fd, &st) != 0 ||- la_verify_filetype(st.st_mode,- p->filetype) == 0)) {- goto skip_fixup_entry;- } else-#endif- if (-#ifdef HAVE_LSTAT- lstat(p->name, &st) != 0 ||-#else- la_stat(p->name, &st) != 0 ||-#endif- la_verify_filetype(st.st_mode,- p->filetype) == 0) {- goto skip_fixup_entry;- }-#endif- }- if (p->fixup & TODO_TIMES) {- set_times(a, fd, p->mode, p->name,- p->atime, p->atime_nanos,- p->birthtime, p->birthtime_nanos,- p->mtime, p->mtime_nanos,- p->ctime, p->ctime_nanos);- }- if (p->fixup & TODO_MODE_BASE) {-#ifdef HAVE_FCHMOD- if (fd >= 0)- fchmod(fd, p->mode & 07777);- else-#endif-#ifdef HAVE_LCHMOD- lchmod(p->name, p->mode & 07777);-#else- chmod(p->name, p->mode & 07777);-#endif- }- if (p->fixup & TODO_ACLS)- archive_write_disk_set_acls(&a->archive, fd,- p->name, &p->acl, p->mode);- if (p->fixup & TODO_FFLAGS)- set_fflags_platform(a, fd, p->name,- p->mode, p->fflags_set, 0);- if (p->fixup & TODO_MAC_METADATA)- set_mac_metadata(a, p->name, p->mac_metadata,- p->mac_metadata_size);-skip_fixup_entry:- next = p->next;- archive_acl_clear(&p->acl);- free(p->mac_metadata);- free(p->name);- if (fd >= 0)- close(fd);- free(p);- p = next;- }- a->fixup_list = NULL;- return (ret);-}--static int-_archive_write_disk_free(struct archive *_a)-{- struct archive_write_disk *a;- int ret;- if (_a == NULL)- return (ARCHIVE_OK);- archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free");- a = (struct archive_write_disk *)_a;- ret = _archive_write_disk_close(&a->archive);- archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL);- archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL);- archive_entry_free(a->entry);- archive_string_free(&a->_name_data);- archive_string_free(&a->_tmpname_data);- archive_string_free(&a->archive.error_string);- archive_string_free(&a->path_safe);- a->archive.magic = 0;- __archive_clean(&a->archive);- free(a->decmpfs_header_p);- free(a->resource_fork);- free(a->compressed_buffer);- free(a->uncompressed_buffer);-#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\- && defined(HAVE_ZLIB_H)- if (a->stream_valid) {- switch (deflateEnd(&a->stream)) {- case Z_OK:- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to clean up compressor");- ret = ARCHIVE_FATAL;- break;- }- }-#endif- free(a);- return (ret);-}--/*- * Simple O(n log n) merge sort to order the fixup list. In- * particular, we want to restore dir timestamps depth-first.- */-static struct fixup_entry *-sort_dir_list(struct fixup_entry *p)-{- struct fixup_entry *a, *b, *t;-- if (p == NULL)- return (NULL);- /* A one-item list is already sorted. */- if (p->next == NULL)- return (p);-- /* Step 1: split the list. */- t = p;- a = p->next->next;- while (a != NULL) {- /* Step a twice, t once. */- a = a->next;- if (a != NULL)- a = a->next;- t = t->next;- }- /* Now, t is at the mid-point, so break the list here. */- b = t->next;- t->next = NULL;- a = p;-- /* Step 2: Recursively sort the two sub-lists. */- a = sort_dir_list(a);- b = sort_dir_list(b);-- /* Step 3: Merge the returned lists. */- /* Pick the first element for the merged list. */- if (strcmp(a->name, b->name) > 0) {- t = p = a;- a = a->next;- } else {- t = p = b;- b = b->next;- }-- /* Always put the later element on the list first. */- while (a != NULL && b != NULL) {- if (strcmp(a->name, b->name) > 0) {- t->next = a;- a = a->next;- } else {- t->next = b;- b = b->next;- }- t = t->next;- }-- /* Only one list is non-empty, so just splice it on. */- if (a != NULL)- t->next = a;- if (b != NULL)- t->next = b;-- return (p);-}--/*- * Returns a new, initialized fixup entry.- *- * TODO: Reduce the memory requirements for this list by using a tree- * structure rather than a simple list of names.- */-static struct fixup_entry *-new_fixup(struct archive_write_disk *a, const char *pathname)-{- struct fixup_entry *fe;-- fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry));- if (fe == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for a fixup");- return (NULL);- }- fe->next = a->fixup_list;- a->fixup_list = fe;- fe->fixup = 0;- fe->filetype = 0;- fe->name = strdup(pathname);- return (fe);-}--/*- * Returns a fixup structure for the current entry.- */-static struct fixup_entry *-current_fixup(struct archive_write_disk *a, const char *pathname)-{- if (a->current_fixup == NULL)- a->current_fixup = new_fixup(a, pathname);- return (a->current_fixup);-}--/* Error helper for new *_fsobj functions */-static void-fsobj_error(int *a_eno, struct archive_string *a_estr,- int err, const char *errstr, const char *path)-{- if (a_eno)- *a_eno = err;- if (a_estr)- archive_string_sprintf(a_estr, "%s%s", errstr, path);-}--/*- * TODO: Someday, integrate this with the deep dir support; they both- * scan the path and both can be optimized by comparing against other- * recent paths.- */-/*- * Checks the given path to see if any elements along it are symlinks. Returns- * ARCHIVE_OK if there are none, otherwise puts an error in errmsg.- */-static int-check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,- int flags, int checking_linkname)-{-#if !defined(HAVE_LSTAT) && \- !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT))- /* Platform doesn't have lstat, so we can't look for symlinks. */- (void)path; /* UNUSED */- (void)a_eno; /* UNUSED */- (void)a_estr; /* UNUSED */- (void)flags; /* UNUSED */- (void)checking_linkname; /* UNUSED */- return (ARCHIVE_OK);-#else- int res = ARCHIVE_OK;- char *tail;- char *head;- int last;- char c = '\0';- int r;- struct stat st;- int chdir_fd;-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)- int fd;-#endif-- /* Nothing to do here if name is empty */- if(path[0] == '\0')- return (ARCHIVE_OK);-- /*- * Guard against symlink tricks. Reject any archive entry whose- * destination would be altered by a symlink.- *- * Walk the filename in chunks separated by '/'. For each segment:- * - if it doesn't exist, continue- * - if it's symlink, abort or remove it- * - if it's a directory and it's not the last chunk, cd into it- * As we go:- * head points to the current (relative) path- * tail points to the temporary \0 terminating the segment we're- * currently examining- * c holds what used to be in *tail- * last is 1 if this is the last tail- */- chdir_fd = la_opendirat(AT_FDCWD, ".");- __archive_ensure_cloexec_flag(chdir_fd);- if (chdir_fd < 0) {- fsobj_error(a_eno, a_estr, errno,- "Could not open ", path);- return (ARCHIVE_FATAL);- }- head = path;- tail = path;- last = 0;- /* TODO: reintroduce a safe cache here? */- /* Skip the root directory if the path is absolute. */- if(tail == path && tail[0] == '/')- ++tail;- /* Keep going until we've checked the entire name.- * head, tail, path all alias the same string, which is- * temporarily zeroed at tail, so be careful restoring the- * stashed (c=tail[0]) for error messages.- * Exiting the loop with break is okay; continue is not.- */- while (!last) {- /*- * Skip the separator we just consumed, plus any adjacent ones- */- while (*tail == '/')- ++tail;- /* Skip the next path element. */- while (*tail != '\0' && *tail != '/')- ++tail;- /* is this the last path component? */- last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0');- /* temporarily truncate the string here */- c = tail[0];- tail[0] = '\0';- /* Check that we haven't hit a symlink. */-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)- r = fstatat(chdir_fd, head, &st, AT_SYMLINK_NOFOLLOW);-#elif defined(HAVE_LSTAT)- r = lstat(head, &st);-#else- r = la_stat(head, &st);-#endif- if (r != 0) {- tail[0] = c;- /* We've hit a dir that doesn't exist; stop now. */- if (errno == ENOENT) {- break;- } else {- /*- * Treat any other error as fatal - best to be- * paranoid here.- * Note: This effectively disables deep- * directory support when security checks are- * enabled. Otherwise, very long pathnames that- * trigger an error here could evade the- * sandbox.- * TODO: We could do better, but it would- * probably require merging the symlink checks- * with the deep-directory editing.- */- fsobj_error(a_eno, a_estr, errno,- "Could not stat ", path);- res = ARCHIVE_FAILED;- break;- }- } else if (S_ISDIR(st.st_mode)) {- if (!last) {-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)- fd = la_opendirat(chdir_fd, head);- if (fd < 0)- r = -1;- else {- r = 0;- close(chdir_fd);- chdir_fd = fd;- }-#else- r = chdir(head);-#endif- if (r != 0) {- tail[0] = c;- fsobj_error(a_eno, a_estr, errno,- "Could not chdir ", path);- res = (ARCHIVE_FATAL);- break;- }- /* Our view is now from inside this dir: */- head = tail + 1;- }- } else if (S_ISLNK(st.st_mode)) {- if (last && checking_linkname) {-#ifdef HAVE_LINKAT- /*- * Hardlinks to symlinks are safe to write- * if linkat() is supported as it does not- * follow symlinks.- */- res = ARCHIVE_OK;-#else- /*- * We return ARCHIVE_FAILED here as we are- * not able to safely write hardlinks- * to symlinks.- */- tail[0] = c;- fsobj_error(a_eno, a_estr, errno,- "Cannot write hardlink to symlink ",- path);- res = ARCHIVE_FAILED;-#endif- break;- } else- if (last) {- /*- * Last element is symlink; remove it- * so we can overwrite it with the- * item being extracted.- */-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)- r = unlinkat(chdir_fd, head, 0);-#else- r = unlink(head);-#endif- if (r != 0) {- tail[0] = c;- fsobj_error(a_eno, a_estr, errno,- "Could not remove symlink ",- path);- res = ARCHIVE_FAILED;- break;- }- /*- * Even if we did remove it, a warning- * is in order. The warning is silly,- * though, if we're just replacing one- * symlink with another symlink.- */- tail[0] = c;- /*- * FIXME: not sure how important this is to- * restore- */- /*- if (!S_ISLNK(path)) {- fsobj_error(a_eno, a_estr, 0,- "Removing symlink ", path);- }- */- /* Symlink gone. No more problem! */- res = ARCHIVE_OK;- break;- } else if (flags & ARCHIVE_EXTRACT_UNLINK) {- /* User asked us to remove problems. */-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)- r = unlinkat(chdir_fd, head, 0);-#else- r = unlink(head);-#endif- if (r != 0) {- tail[0] = c;- fsobj_error(a_eno, a_estr, 0,- "Cannot remove intervening "- "symlink ", path);- res = ARCHIVE_FAILED;- break;- }- tail[0] = c;- } else if ((flags &- ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) {- /*- * We are not the last element and we want to- * follow symlinks if they are a directory.- * - * This is needed to extract hardlinks over- * symlinks.- */-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)- r = fstatat(chdir_fd, head, &st, 0);-#else- r = la_stat(head, &st);-#endif- if (r != 0) {- tail[0] = c;- if (errno == ENOENT) {- break;- } else {- fsobj_error(a_eno, a_estr,- errno,- "Could not stat ", path);- res = (ARCHIVE_FAILED);- break;- }- } else if (S_ISDIR(st.st_mode)) {-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)- fd = la_opendirat(chdir_fd, head);- if (fd < 0)- r = -1;- else {- r = 0;- close(chdir_fd);- chdir_fd = fd;- }-#else- r = chdir(head);-#endif- if (r != 0) {- tail[0] = c;- fsobj_error(a_eno, a_estr,- errno,- "Could not chdir ", path);- res = (ARCHIVE_FATAL);- break;- }- /*- * Our view is now from inside- * this dir:- */- head = tail + 1;- } else {- tail[0] = c;- fsobj_error(a_eno, a_estr, 0,- "Cannot extract through "- "symlink ", path);- res = ARCHIVE_FAILED;- break;- }- } else {- tail[0] = c;- fsobj_error(a_eno, a_estr, 0,- "Cannot extract through symlink ", path);- res = ARCHIVE_FAILED;- break;- }- }- /* be sure to always maintain this */- tail[0] = c;- if (tail[0] != '\0')- tail++; /* Advance to the next segment. */- }- /* Catches loop exits via break */- tail[0] = c;-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)- /* If we operate with openat(), fstatat() and unlinkat() there was- * no chdir(), so just close the fd */- if (chdir_fd >= 0)- close(chdir_fd);-#elif HAVE_FCHDIR- /* If we changed directory above, restore it here. */- if (chdir_fd >= 0) {- r = fchdir(chdir_fd);- if (r != 0) {- fsobj_error(a_eno, a_estr, errno,- "chdir() failure", "");- }- close(chdir_fd);- chdir_fd = -1;- if (r != 0) {- res = (ARCHIVE_FATAL);- }- }-#endif- /* TODO: reintroduce a safe cache here? */- return res;-#endif-}--/*- * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise- * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED}- */-static int-check_symlinks(struct archive_write_disk *a)-{- struct archive_string error_string;- int error_number;- int rc;- archive_string_init(&error_string);- rc = check_symlinks_fsobj(a->name, &error_number, &error_string,- a->flags, 0);- if (rc != ARCHIVE_OK) {- archive_set_error(&a->archive, error_number, "%s",- error_string.s);- }- archive_string_free(&error_string);- a->pst = NULL; /* to be safe */- return rc;-}---#if defined(__CYGWIN__)-/*- * 1. Convert a path separator from '\' to '/' .- * We shouldn't check multibyte character directly because some- * character-set have been using the '\' character for a part of- * its multibyte character code.- * 2. Replace unusable characters in Windows with underscore('_').- * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx- */-static void-cleanup_pathname_win(char *path)-{- wchar_t wc;- char *p;- size_t alen, l;- int mb, complete, utf8;-- alen = 0;- mb = 0;- complete = 1;- utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0;- for (p = path; *p != '\0'; p++) {- ++alen;- if (*p == '\\') {- /* If previous byte is smaller than 128,- * this is not second byte of multibyte characters,- * so we can replace '\' with '/'. */- if (utf8 || !mb)- *p = '/';- else- complete = 0;/* uncompleted. */- } else if (*(unsigned char *)p > 127)- mb = 1;- else- mb = 0;- /* Rewrite the path name if its next character is unusable. */- if (*p == ':' || *p == '*' || *p == '?' || *p == '"' ||- *p == '<' || *p == '>' || *p == '|')- *p = '_';- }- if (complete)- return;-- /*- * Convert path separator in wide-character.- */- p = path;- while (*p != '\0' && alen) {- l = mbtowc(&wc, p, alen);- if (l == (size_t)-1) {- while (*p != '\0') {- if (*p == '\\')- *p = '/';- ++p;- }- break;- }- if (l == 1 && wc == L'\\')- *p = '/';- p += l;- alen -= l;- }-}-#endif--/*- * Canonicalize the pathname. In particular, this strips duplicate- * '/' characters, '.' elements, and trailing '/'. It also raises an- * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is- * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS- * is set) if the path is absolute.- */-static int-cleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr,- int flags)-{- char *dest, *src;- char separator = '\0';-- dest = src = path;- if (*src == '\0') {- fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,- "Invalid empty ", "pathname");- return (ARCHIVE_FAILED);- }--#if defined(__CYGWIN__)- cleanup_pathname_win(path);-#endif- /* Skip leading '/'. */- if (*src == '/') {- if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) {- fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,- "Path is ", "absolute");- return (ARCHIVE_FAILED);- }-- separator = *src++;- }-- /* Scan the pathname one element at a time. */- for (;;) {- /* src points to first char after '/' */- if (src[0] == '\0') {- break;- } else if (src[0] == '/') {- /* Found '//', ignore second one. */- src++;- continue;- } else if (src[0] == '.') {- if (src[1] == '\0') {- /* Ignore trailing '.' */- break;- } else if (src[1] == '/') {- /* Skip './'. */- src += 2;- continue;- } else if (src[1] == '.') {- if (src[2] == '/' || src[2] == '\0') {- /* Conditionally warn about '..' */- if (flags- & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {- fsobj_error(a_eno, a_estr,- ARCHIVE_ERRNO_MISC,- "Path contains ", "'..'");- return (ARCHIVE_FAILED);- }- }- /*- * Note: Under no circumstances do we- * remove '..' elements. In- * particular, restoring- * '/foo/../bar/' should create the- * 'foo' dir as a side-effect.- */- }- }-- /* Copy current element, including leading '/'. */- if (separator)- *dest++ = '/';- while (*src != '\0' && *src != '/') {- *dest++ = *src++;- }-- if (*src == '\0')- break;-- /* Skip '/' separator. */- separator = *src++;- }- /*- * We've just copied zero or more path elements, not including the- * final '/'.- */- if (dest == path) {- /*- * Nothing got copied. The path must have been something- * like '.' or '/' or './' or '/././././/./'.- */- if (separator)- *dest++ = '/';- else- *dest++ = '.';- }- /* Terminate the result. */- *dest = '\0';- return (ARCHIVE_OK);-}--static int-cleanup_pathname(struct archive_write_disk *a)-{- struct archive_string error_string;- int error_number;- int rc;- archive_string_init(&error_string);- rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string,- a->flags);- if (rc != ARCHIVE_OK) {- archive_set_error(&a->archive, error_number, "%s",- error_string.s);- }- archive_string_free(&error_string);- return rc;-}--/*- * Create the parent directory of the specified path, assuming path- * is already in mutable storage.- */-static int-create_parent_dir(struct archive_write_disk *a, char *path)-{- char *slash;- int r;-- /* Remove tail element to obtain parent name. */- slash = strrchr(path, '/');- if (slash == NULL)- return (ARCHIVE_OK);- *slash = '\0';- r = create_dir(a, path);- *slash = '/';- return (r);-}--/*- * Create the specified dir, recursing to create parents as necessary.- *- * Returns ARCHIVE_OK if the path exists when we're done here.- * Otherwise, returns ARCHIVE_FAILED.- * Assumes path is in mutable storage; path is unchanged on exit.- */-static int-create_dir(struct archive_write_disk *a, char *path)-{- struct stat st;- struct fixup_entry *le;- char *slash, *base;- mode_t mode_final, mode;- int r;-- /* Check for special names and just skip them. */- slash = strrchr(path, '/');- if (slash == NULL)- base = path;- else- base = slash + 1;-- if (base[0] == '\0' ||- (base[0] == '.' && base[1] == '\0') ||- (base[0] == '.' && base[1] == '.' && base[2] == '\0')) {- /* Don't bother trying to create null path, '.', or '..'. */- if (slash != NULL) {- *slash = '\0';- r = create_dir(a, path);- *slash = '/';- return (r);- }- return (ARCHIVE_OK);- }-- /*- * Yes, this should be stat() and not lstat(). Using lstat()- * here loses the ability to extract through symlinks. Also note- * that this should not use the a->st cache.- */- if (la_stat(path, &st) == 0) {- if (S_ISDIR(st.st_mode))- return (ARCHIVE_OK);- if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {- archive_set_error(&a->archive, EEXIST,- "Can't create directory '%s'", path);- return (ARCHIVE_FAILED);- }- if (unlink(path) != 0) {- archive_set_error(&a->archive, errno,- "Can't create directory '%s': "- "Conflicting file cannot be removed",- path);- return (ARCHIVE_FAILED);- }- } else if (errno != ENOENT && errno != ENOTDIR) {- /* Stat failed? */- archive_set_error(&a->archive, errno,- "Can't test directory '%s'", path);- return (ARCHIVE_FAILED);- } else if (slash != NULL) {- *slash = '\0';- r = create_dir(a, path);- *slash = '/';- if (r != ARCHIVE_OK)- return (r);- }-- /*- * Mode we want for the final restored directory. Per POSIX,- * implicitly-created dirs must be created obeying the umask.- * There's no mention whether this is different for privileged- * restores (which the rest of this code handles by pretending- * umask=0). I've chosen here to always obey the user's umask for- * implicit dirs, even if _EXTRACT_PERM was specified.- */- mode_final = DEFAULT_DIR_MODE & ~a->user_umask;- /* Mode we want on disk during the restore process. */- mode = mode_final;- mode |= MINIMUM_DIR_MODE;- mode &= MAXIMUM_DIR_MODE;- if (mkdir(path, mode) == 0) {- if (mode != mode_final) {- le = new_fixup(a, path);- if (le == NULL)- return (ARCHIVE_FATAL);- le->fixup |=TODO_MODE_BASE;- le->mode = mode_final;- }- return (ARCHIVE_OK);- }-- /*- * Without the following check, a/b/../b/c/d fails at the- * second visit to 'b', so 'd' can't be created. Note that we- * don't add it to the fixup list here, as it's already been- * added.- */- if (la_stat(path, &st) == 0 && S_ISDIR(st.st_mode))- return (ARCHIVE_OK);-- archive_set_error(&a->archive, errno, "Failed to create dir '%s'",- path);- return (ARCHIVE_FAILED);-}--/*- * Note: Although we can skip setting the user id if the desired user- * id matches the current user, we cannot skip setting the group, as- * many systems set the gid based on the containing directory. So- * we have to perform a chown syscall if we want to set the SGID- * bit. (The alternative is to stat() and then possibly chown(); it's- * more efficient to skip the stat() and just always chown().) Note- * that a successful chown() here clears the TODO_SGID_CHECK bit, which- * allows set_mode to skip the stat() check for the GID.- */-static int-set_ownership(struct archive_write_disk *a)-{-#if !defined(__CYGWIN__) && !defined(__linux__)-/*- * On Linux, a process may have the CAP_CHOWN capability.- * On Windows there is no 'root' user with uid 0.- * Elsewhere we can skip calling chown if we are not root and the desired- * user id does not match the current user.- */- if (a->user_uid != 0 && a->user_uid != a->uid) {- archive_set_error(&a->archive, errno,- "Can't set UID=%jd", (intmax_t)a->uid);- return (ARCHIVE_WARN);- }-#endif--#ifdef HAVE_FCHOWN- /* If we have an fd, we can avoid a race. */- if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) {- /* We've set owner and know uid/gid are correct. */- a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);- return (ARCHIVE_OK);- }-#endif-- /* We prefer lchown() but will use chown() if that's all we have. */- /* Of course, if we have neither, this will always fail. */-#ifdef HAVE_LCHOWN- if (lchown(a->name, a->uid, a->gid) == 0) {- /* We've set owner and know uid/gid are correct. */- a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);- return (ARCHIVE_OK);- }-#elif HAVE_CHOWN- if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) {- /* We've set owner and know uid/gid are correct. */- a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);- return (ARCHIVE_OK);- }-#endif-- archive_set_error(&a->archive, errno,- "Can't set user=%jd/group=%jd for %s",- (intmax_t)a->uid, (intmax_t)a->gid, a->name);- return (ARCHIVE_WARN);-}--/*- * Note: Returns 0 on success, non-zero on failure.- */-static int-set_time(int fd, int mode, const char *name,- time_t atime, long atime_nsec,- time_t mtime, long mtime_nsec)-{- /* Select the best implementation for this platform. */-#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS)- /*- * utimensat() and futimens() are defined in- * POSIX.1-2008. They support ns resolution and setting times- * on fds and symlinks.- */- struct timespec ts[2];- (void)mode; /* UNUSED */- ts[0].tv_sec = atime;- ts[0].tv_nsec = atime_nsec;- ts[1].tv_sec = mtime;- ts[1].tv_nsec = mtime_nsec;- if (fd >= 0)- return futimens(fd, ts);- return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW);--#elif HAVE_UTIMES- /*- * The utimes()-family functions support µs-resolution and- * setting times fds and symlinks. utimes() is documented as- * LEGACY by POSIX, futimes() and lutimes() are not described- * in POSIX.- */- struct timeval times[2];-- times[0].tv_sec = atime;- times[0].tv_usec = atime_nsec / 1000;- times[1].tv_sec = mtime;- times[1].tv_usec = mtime_nsec / 1000;--#ifdef HAVE_FUTIMES- if (fd >= 0)- return (futimes(fd, times));-#else- (void)fd; /* UNUSED */-#endif-#ifdef HAVE_LUTIMES- (void)mode; /* UNUSED */- return (lutimes(name, times));-#else- if (S_ISLNK(mode))- return (0);- return (utimes(name, times));-#endif--#elif defined(HAVE_UTIME)- /*- * utime() is POSIX-standard but only supports 1s resolution and- * does not support fds or symlinks.- */- struct utimbuf times;- (void)fd; /* UNUSED */- (void)name; /* UNUSED */- (void)atime_nsec; /* UNUSED */- (void)mtime_nsec; /* UNUSED */- times.actime = atime;- times.modtime = mtime;- if (S_ISLNK(mode))- return (ARCHIVE_OK);- return (utime(name, ×));--#else- /*- * We don't know how to set the time on this platform.- */- (void)fd; /* UNUSED */- (void)mode; /* UNUSED */- (void)name; /* UNUSED */- (void)atime; /* UNUSED */- (void)atime_nsec; /* UNUSED */- (void)mtime; /* UNUSED */- (void)mtime_nsec; /* UNUSED */- return (ARCHIVE_WARN);-#endif-}--#ifdef F_SETTIMES-static int-set_time_tru64(int fd, int mode, const char *name,- time_t atime, long atime_nsec,- time_t mtime, long mtime_nsec,- time_t ctime, long ctime_nsec)-{- struct attr_timbuf tstamp;- tstamp.atime.tv_sec = atime;- tstamp.mtime.tv_sec = mtime;- tstamp.ctime.tv_sec = ctime;-#if defined (__hpux) && defined (__ia64)- tstamp.atime.tv_nsec = atime_nsec;- tstamp.mtime.tv_nsec = mtime_nsec;- tstamp.ctime.tv_nsec = ctime_nsec;-#else- tstamp.atime.tv_usec = atime_nsec / 1000;- tstamp.mtime.tv_usec = mtime_nsec / 1000;- tstamp.ctime.tv_usec = ctime_nsec / 1000;-#endif- return (fcntl(fd,F_SETTIMES,&tstamp));-}-#endif /* F_SETTIMES */--static int-set_times(struct archive_write_disk *a,- int fd, int mode, const char *name,- time_t atime, long atime_nanos,- time_t birthtime, long birthtime_nanos,- time_t mtime, long mtime_nanos,- time_t cctime, long ctime_nanos)-{- /* Note: set_time doesn't use libarchive return conventions!- * It uses syscall conventions. So 0 here instead of ARCHIVE_OK. */- int r1 = 0, r2 = 0;--#ifdef F_SETTIMES- /*- * on Tru64 try own fcntl first which can restore even the- * ctime, fall back to default code path below if it fails- * or if we are not running as root- */- if (a->user_uid == 0 &&- set_time_tru64(fd, mode, name,- atime, atime_nanos, mtime,- mtime_nanos, cctime, ctime_nanos) == 0) {- return (ARCHIVE_OK);- }-#else /* Tru64 */- (void)cctime; /* UNUSED */- (void)ctime_nanos; /* UNUSED */-#endif /* Tru64 */--#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME- /*- * If you have struct stat.st_birthtime, we assume BSD- * birthtime semantics, in which {f,l,}utimes() updates- * birthtime to earliest mtime. So we set the time twice,- * first using the birthtime, then using the mtime. If- * birthtime == mtime, this isn't necessary, so we skip it.- * If birthtime > mtime, then this won't work, so we skip it.- */- if (birthtime < mtime- || (birthtime == mtime && birthtime_nanos < mtime_nanos))- r1 = set_time(fd, mode, name,- atime, atime_nanos,- birthtime, birthtime_nanos);-#else- (void)birthtime; /* UNUSED */- (void)birthtime_nanos; /* UNUSED */-#endif- r2 = set_time(fd, mode, name,- atime, atime_nanos,- mtime, mtime_nanos);- if (r1 != 0 || r2 != 0) {- archive_set_error(&a->archive, errno,- "Can't restore time");- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-}--static int-set_times_from_entry(struct archive_write_disk *a)-{- time_t atime, birthtime, mtime, cctime;- long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec;-- /* Suitable defaults. */- atime = birthtime = mtime = cctime = a->start_time;- atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0;-- /* If no time was provided, we're done. */- if (!archive_entry_atime_is_set(a->entry)-#if HAVE_STRUCT_STAT_ST_BIRTHTIME- && !archive_entry_birthtime_is_set(a->entry)-#endif- && !archive_entry_mtime_is_set(a->entry))- return (ARCHIVE_OK);-- if (archive_entry_atime_is_set(a->entry)) {- atime = archive_entry_atime(a->entry);- atime_nsec = archive_entry_atime_nsec(a->entry);- }- if (archive_entry_birthtime_is_set(a->entry)) {- birthtime = archive_entry_birthtime(a->entry);- birthtime_nsec = archive_entry_birthtime_nsec(a->entry);- }- if (archive_entry_mtime_is_set(a->entry)) {- mtime = archive_entry_mtime(a->entry);- mtime_nsec = archive_entry_mtime_nsec(a->entry);- }- if (archive_entry_ctime_is_set(a->entry)) {- cctime = archive_entry_ctime(a->entry);- ctime_nsec = archive_entry_ctime_nsec(a->entry);- }-- return set_times(a, a->fd, a->mode, a->name,- atime, atime_nsec,- birthtime, birthtime_nsec,- mtime, mtime_nsec,- cctime, ctime_nsec);-}--static int-set_mode(struct archive_write_disk *a, int mode)-{- int r = ARCHIVE_OK;- int r2;- mode &= 07777; /* Strip off file type bits. */-- if (a->todo & TODO_SGID_CHECK) {- /*- * If we don't know the GID is right, we must stat()- * to verify it. We can't just check the GID of this- * process, since systems sometimes set GID from- * the enclosing dir or based on ACLs.- */- if ((r = lazy_stat(a)) != ARCHIVE_OK)- return (r);- if (a->pst->st_gid != a->gid) {- mode &= ~ S_ISGID;- if (a->flags & ARCHIVE_EXTRACT_OWNER) {- /*- * This is only an error if you- * requested owner restore. If you- * didn't, we'll try to restore- * sgid/suid, but won't consider it a- * problem if we can't.- */- archive_set_error(&a->archive, -1,- "Can't restore SGID bit");- r = ARCHIVE_WARN;- }- }- /* While we're here, double-check the UID. */- if (a->pst->st_uid != a->uid- && (a->todo & TODO_SUID)) {- mode &= ~ S_ISUID;- if (a->flags & ARCHIVE_EXTRACT_OWNER) {- archive_set_error(&a->archive, -1,- "Can't restore SUID bit");- r = ARCHIVE_WARN;- }- }- a->todo &= ~TODO_SGID_CHECK;- a->todo &= ~TODO_SUID_CHECK;- } else if (a->todo & TODO_SUID_CHECK) {- /*- * If we don't know the UID is right, we can just check- * the user, since all systems set the file UID from- * the process UID.- */- if (a->user_uid != a->uid) {- mode &= ~ S_ISUID;- if (a->flags & ARCHIVE_EXTRACT_OWNER) {- archive_set_error(&a->archive, -1,- "Can't make file SUID");- r = ARCHIVE_WARN;- }- }- a->todo &= ~TODO_SUID_CHECK;- }-- if (S_ISLNK(a->mode)) {-#ifdef HAVE_LCHMOD- /*- * If this is a symlink, use lchmod(). If the- * platform doesn't support lchmod(), just skip it. A- * platform that doesn't provide a way to set- * permissions on symlinks probably ignores- * permissions on symlinks, so a failure here has no- * impact.- */- if (lchmod(a->name, mode) != 0) {- switch (errno) {- case ENOTSUP:- case ENOSYS:-#if ENOTSUP != EOPNOTSUPP- case EOPNOTSUPP:-#endif- /*- * if lchmod is defined but the platform- * doesn't support it, silently ignore- * error- */- break;- default:- archive_set_error(&a->archive, errno,- "Can't set permissions to 0%o", (int)mode);- r = ARCHIVE_WARN;- }- }-#endif- } else if (!S_ISDIR(a->mode)) {- /*- * If it's not a symlink and not a dir, then use- * fchmod() or chmod(), depending on whether we have- * an fd. Dirs get their perms set during the- * post-extract fixup, which is handled elsewhere.- */-#ifdef HAVE_FCHMOD- if (a->fd >= 0)- r2 = fchmod(a->fd, mode);- else-#endif- /* If this platform lacks fchmod(), then- * we'll just use chmod(). */- r2 = chmod(a->name, mode);-- if (r2 != 0) {- archive_set_error(&a->archive, errno,- "Can't set permissions to 0%o", (int)mode);- r = ARCHIVE_WARN;- }- }- return (r);-}--static int-set_fflags(struct archive_write_disk *a)-{- struct fixup_entry *le;- unsigned long set, clear;- int r;- mode_t mode = archive_entry_mode(a->entry);- /*- * Make 'critical_flags' hold all file flags that can't be- * immediately restored. For example, on BSD systems,- * SF_IMMUTABLE prevents hardlinks from being created, so- * should not be set until after any hardlinks are created. To- * preserve some semblance of portability, this uses #ifdef- * extensively. Ugly, but it works.- *- * Yes, Virginia, this does create a security race. It's mitigated- * somewhat by the practice of creating dirs 0700 until the extract- * is done, but it would be nice if we could do more than that.- * People restoring critical file systems should be wary of- * other programs that might try to muck with files as they're- * being restored.- */- const int critical_flags = 0-#ifdef SF_IMMUTABLE- | SF_IMMUTABLE-#endif-#ifdef UF_IMMUTABLE- | UF_IMMUTABLE-#endif-#ifdef SF_APPEND- | SF_APPEND-#endif-#ifdef UF_APPEND- | UF_APPEND-#endif-#if defined(FS_APPEND_FL)- | FS_APPEND_FL-#elif defined(EXT2_APPEND_FL)- | EXT2_APPEND_FL-#endif-#if defined(FS_IMMUTABLE_FL)- | FS_IMMUTABLE_FL-#elif defined(EXT2_IMMUTABLE_FL)- | EXT2_IMMUTABLE_FL-#endif-#ifdef FS_JOURNAL_DATA_FL- | FS_JOURNAL_DATA_FL-#endif- ;-- if (a->todo & TODO_FFLAGS) {- archive_entry_fflags(a->entry, &set, &clear);-- /*- * The first test encourages the compiler to eliminate- * all of this if it's not necessary.- */- if ((critical_flags != 0) && (set & critical_flags)) {- le = current_fixup(a, a->name);- if (le == NULL)- return (ARCHIVE_FATAL);- le->filetype = archive_entry_filetype(a->entry);- le->fixup |= TODO_FFLAGS;- le->fflags_set = set;- /* Store the mode if it's not already there. */- if ((le->fixup & TODO_MODE) == 0)- le->mode = mode;- } else {- r = set_fflags_platform(a, a->fd,- a->name, mode, set, clear);- if (r != ARCHIVE_OK)- return (r);- }- }- return (ARCHIVE_OK);-}--static int-clear_nochange_fflags(struct archive_write_disk *a)-{- mode_t mode = archive_entry_mode(a->entry);- const int nochange_flags = 0-#ifdef SF_IMMUTABLE- | SF_IMMUTABLE-#endif-#ifdef UF_IMMUTABLE- | UF_IMMUTABLE-#endif-#ifdef SF_APPEND- | SF_APPEND-#endif-#ifdef UF_APPEND- | UF_APPEND-#endif-#ifdef EXT2_APPEND_FL- | EXT2_APPEND_FL-#endif-#ifdef EXT2_IMMUTABLE_FL- | EXT2_IMMUTABLE_FL-#endif- ;-- return (set_fflags_platform(a, a->fd, a->name, mode, 0,- nochange_flags));-}---#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS)-/*- * BSD reads flags using stat() and sets them with one of {f,l,}chflags()- */-static int-set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,- mode_t mode, unsigned long set, unsigned long clear)-{- int r;- const int sf_mask = 0-#ifdef SF_APPEND- | SF_APPEND-#endif-#ifdef SF_ARCHIVED- | SF_ARCHIVED-#endif-#ifdef SF_IMMUTABLE- | SF_IMMUTABLE-#endif-#ifdef SF_NOUNLINK- | SF_NOUNLINK-#endif- ;- (void)mode; /* UNUSED */-- if (set == 0 && clear == 0)- return (ARCHIVE_OK);-- /*- * XXX Is the stat here really necessary? Or can I just use- * the 'set' flags directly? In particular, I'm not sure- * about the correct approach if we're overwriting an existing- * file that already has flags on it. XXX- */- if ((r = lazy_stat(a)) != ARCHIVE_OK)- return (r);-- a->st.st_flags &= ~clear;- a->st.st_flags |= set;-- /* Only super-user may change SF_* flags */-- if (a->user_uid != 0)- a->st.st_flags &= ~sf_mask;--#ifdef HAVE_FCHFLAGS- /* If platform has fchflags() and we were given an fd, use it. */- if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0)- return (ARCHIVE_OK);-#endif- /*- * If we can't use the fd to set the flags, we'll use the- * pathname to set flags. We prefer lchflags() but will use- * chflags() if we must.- */-#ifdef HAVE_LCHFLAGS- if (lchflags(name, a->st.st_flags) == 0)- return (ARCHIVE_OK);-#elif defined(HAVE_CHFLAGS)- if (S_ISLNK(a->st.st_mode)) {- archive_set_error(&a->archive, errno,- "Can't set file flags on symlink.");- return (ARCHIVE_WARN);- }- if (chflags(name, a->st.st_flags) == 0)- return (ARCHIVE_OK);-#endif- archive_set_error(&a->archive, errno,- "Failed to set file flags");- return (ARCHIVE_WARN);-}--#elif (defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) && \- defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \- (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && \- defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))-/*- * Linux uses ioctl() to read and write file flags.- */-static int-set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,- mode_t mode, unsigned long set, unsigned long clear)-{- int ret;- int myfd = fd;- int newflags, oldflags;- /*- * Linux has no define for the flags that are only settable by- * the root user. This code may seem a little complex, but- * there seem to be some Linux systems that lack these- * defines. (?) The code below degrades reasonably gracefully- * if sf_mask is incomplete.- */- const int sf_mask = 0-#if defined(FS_IMMUTABLE_FL)- | FS_IMMUTABLE_FL-#elif defined(EXT2_IMMUTABLE_FL)- | EXT2_IMMUTABLE_FL-#endif-#if defined(FS_APPEND_FL)- | FS_APPEND_FL-#elif defined(EXT2_APPEND_FL)- | EXT2_APPEND_FL-#endif-#if defined(FS_JOURNAL_DATA_FL)- | FS_JOURNAL_DATA_FL-#endif- ;-- if (set == 0 && clear == 0)- return (ARCHIVE_OK);- /* Only regular files and dirs can have flags. */- if (!S_ISREG(mode) && !S_ISDIR(mode))- return (ARCHIVE_OK);-- /* If we weren't given an fd, open it ourselves. */- if (myfd < 0) {- myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY |- O_CLOEXEC | O_NOFOLLOW);- __archive_ensure_cloexec_flag(myfd);- }- if (myfd < 0)- return (ARCHIVE_OK);-- /*- * XXX As above, this would be way simpler if we didn't have- * to read the current flags from disk. XXX- */- ret = ARCHIVE_OK;-- /* Read the current file flags. */- if (ioctl(myfd,-#ifdef FS_IOC_GETFLAGS- FS_IOC_GETFLAGS,-#else- EXT2_IOC_GETFLAGS,-#endif- &oldflags) < 0)- goto fail;-- /* Try setting the flags as given. */- newflags = (oldflags & ~clear) | set;- if (ioctl(myfd,-#ifdef FS_IOC_SETFLAGS- FS_IOC_SETFLAGS,-#else- EXT2_IOC_SETFLAGS,-#endif- &newflags) >= 0)- goto cleanup;- if (errno != EPERM)- goto fail;-- /* If we couldn't set all the flags, try again with a subset. */- newflags &= ~sf_mask;- oldflags &= sf_mask;- newflags |= oldflags;- if (ioctl(myfd,-#ifdef FS_IOC_SETFLAGS- FS_IOC_SETFLAGS,-#else- EXT2_IOC_SETFLAGS,-#endif- &newflags) >= 0)- goto cleanup;-- /* We couldn't set the flags, so report the failure. */-fail:- archive_set_error(&a->archive, errno,- "Failed to set file flags");- ret = ARCHIVE_WARN;-cleanup:- if (fd < 0)- close(myfd);- return (ret);-}--#else--/*- * Of course, some systems have neither BSD chflags() nor Linux' flags- * support through ioctl().- */-static int-set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,- mode_t mode, unsigned long set, unsigned long clear)-{- (void)a; /* UNUSED */- (void)fd; /* UNUSED */- (void)name; /* UNUSED */- (void)mode; /* UNUSED */- (void)set; /* UNUSED */- (void)clear; /* UNUSED */- return (ARCHIVE_OK);-}--#endif /* __linux */--#ifndef HAVE_COPYFILE_H-/* Default is to simply drop Mac extended metadata. */-static int-set_mac_metadata(struct archive_write_disk *a, const char *pathname,- const void *metadata, size_t metadata_size)-{- (void)a; /* UNUSED */- (void)pathname; /* UNUSED */- (void)metadata; /* UNUSED */- (void)metadata_size; /* UNUSED */- return (ARCHIVE_OK);-}--static int-fixup_appledouble(struct archive_write_disk *a, const char *pathname)-{- (void)a; /* UNUSED */- (void)pathname; /* UNUSED */- return (ARCHIVE_OK);-}-#else--/*- * On Mac OS, we use copyfile() to unpack the metadata and- * apply it to the target file.- */--#if defined(HAVE_SYS_XATTR_H)-static int-copy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd)-{- ssize_t xattr_size;- char *xattr_names = NULL, *xattr_val = NULL;- int ret = ARCHIVE_OK, xattr_i;-- xattr_size = flistxattr(tmpfd, NULL, 0, 0);- if (xattr_size == -1) {- archive_set_error(&a->archive, errno,- "Failed to read metadata(xattr)");- ret = ARCHIVE_WARN;- goto exit_xattr;- }- xattr_names = malloc(xattr_size);- if (xattr_names == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for metadata(xattr)");- ret = ARCHIVE_FATAL;- goto exit_xattr;- }- xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0);- if (xattr_size == -1) {- archive_set_error(&a->archive, errno,- "Failed to read metadata(xattr)");- ret = ARCHIVE_WARN;- goto exit_xattr;- }- for (xattr_i = 0; xattr_i < xattr_size;- xattr_i += strlen(xattr_names + xattr_i) + 1) {- char *xattr_val_saved;- ssize_t s;- int f;-- s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0);- if (s == -1) {- archive_set_error(&a->archive, errno,- "Failed to get metadata(xattr)");- ret = ARCHIVE_WARN;- goto exit_xattr;- }- xattr_val_saved = xattr_val;- xattr_val = realloc(xattr_val, s);- if (xattr_val == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Failed to get metadata(xattr)");- ret = ARCHIVE_WARN;- free(xattr_val_saved);- goto exit_xattr;- }- s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0);- if (s == -1) {- archive_set_error(&a->archive, errno,- "Failed to get metadata(xattr)");- ret = ARCHIVE_WARN;- goto exit_xattr;- }- f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0);- if (f == -1) {- archive_set_error(&a->archive, errno,- "Failed to get metadata(xattr)");- ret = ARCHIVE_WARN;- goto exit_xattr;- }- }-exit_xattr:- free(xattr_names);- free(xattr_val);- return (ret);-}-#endif--static int-copy_acls(struct archive_write_disk *a, int tmpfd, int dffd)-{-#ifndef HAVE_SYS_ACL_H- return 0;-#else- acl_t acl, dfacl = NULL;- int acl_r, ret = ARCHIVE_OK;-- acl = acl_get_fd(tmpfd);- if (acl == NULL) {- if (errno == ENOENT)- /* There are not any ACLs. */- return (ret);- archive_set_error(&a->archive, errno,- "Failed to get metadata(acl)");- ret = ARCHIVE_WARN;- goto exit_acl;- }- dfacl = acl_dup(acl);- acl_r = acl_set_fd(dffd, dfacl);- if (acl_r == -1) {- archive_set_error(&a->archive, errno,- "Failed to get metadata(acl)");- ret = ARCHIVE_WARN;- goto exit_acl;- }-exit_acl:- if (acl)- acl_free(acl);- if (dfacl)- acl_free(dfacl);- return (ret);-#endif-}--static int-create_tempdatafork(struct archive_write_disk *a, const char *pathname)-{- struct archive_string tmpdatafork;- int tmpfd;-- archive_string_init(&tmpdatafork);- archive_strcpy(&tmpdatafork, "tar.md.XXXXXX");- tmpfd = mkstemp(tmpdatafork.s);- if (tmpfd < 0) {- archive_set_error(&a->archive, errno,- "Failed to mkstemp");- archive_string_free(&tmpdatafork);- return (-1);- }- if (copyfile(pathname, tmpdatafork.s, 0,- COPYFILE_UNPACK | COPYFILE_NOFOLLOW- | COPYFILE_ACL | COPYFILE_XATTR) < 0) {- archive_set_error(&a->archive, errno,- "Failed to restore metadata");- close(tmpfd);- tmpfd = -1;- }- unlink(tmpdatafork.s);- archive_string_free(&tmpdatafork);- return (tmpfd);-}--static int-copy_metadata(struct archive_write_disk *a, const char *metadata,- const char *datafork, int datafork_compressed)-{- int ret = ARCHIVE_OK;-- if (datafork_compressed) {- int dffd, tmpfd;-- tmpfd = create_tempdatafork(a, metadata);- if (tmpfd == -1)- return (ARCHIVE_WARN);-- /*- * Do not open the data fork compressed by HFS+ compression- * with at least a writing mode(O_RDWR or O_WRONLY). it- * makes the data fork uncompressed.- */- dffd = open(datafork, 0);- if (dffd == -1) {- archive_set_error(&a->archive, errno,- "Failed to open the data fork for metadata");- close(tmpfd);- return (ARCHIVE_WARN);- }--#if defined(HAVE_SYS_XATTR_H)- ret = copy_xattrs(a, tmpfd, dffd);- if (ret == ARCHIVE_OK)-#endif- ret = copy_acls(a, tmpfd, dffd);- close(tmpfd);- close(dffd);- } else {- if (copyfile(metadata, datafork, 0,- COPYFILE_UNPACK | COPYFILE_NOFOLLOW- | COPYFILE_ACL | COPYFILE_XATTR) < 0) {- archive_set_error(&a->archive, errno,- "Failed to restore metadata");- ret = ARCHIVE_WARN;- }- }- return (ret);-}--static int-set_mac_metadata(struct archive_write_disk *a, const char *pathname,- const void *metadata, size_t metadata_size)-{- struct archive_string tmp;- ssize_t written;- int fd;- int ret = ARCHIVE_OK;-- /* This would be simpler if copyfile() could just accept the- * metadata as a block of memory; then we could sidestep this- * silly dance of writing the data to disk just so that- * copyfile() can read it back in again. */- archive_string_init(&tmp);- archive_strcpy(&tmp, pathname);- archive_strcat(&tmp, ".XXXXXX");- fd = mkstemp(tmp.s);-- if (fd < 0) {- archive_set_error(&a->archive, errno,- "Failed to restore metadata");- archive_string_free(&tmp);- return (ARCHIVE_WARN);- }- written = write(fd, metadata, metadata_size);- close(fd);- if ((size_t)written != metadata_size) {- archive_set_error(&a->archive, errno,- "Failed to restore metadata");- ret = ARCHIVE_WARN;- } else {- int compressed;--#if defined(UF_COMPRESSED)- if ((a->todo & TODO_HFS_COMPRESSION) != 0 &&- (ret = lazy_stat(a)) == ARCHIVE_OK)- compressed = a->st.st_flags & UF_COMPRESSED;- else-#endif- compressed = 0;- ret = copy_metadata(a, tmp.s, pathname, compressed);- }- unlink(tmp.s);- archive_string_free(&tmp);- return (ret);-}--static int-fixup_appledouble(struct archive_write_disk *a, const char *pathname)-{- char buff[8];- struct stat st;- const char *p;- struct archive_string datafork;- int fd = -1, ret = ARCHIVE_OK;-- archive_string_init(&datafork);- /* Check if the current file name is a type of the resource- * fork file. */- p = strrchr(pathname, '/');- if (p == NULL)- p = pathname;- else- p++;- if (p[0] != '.' || p[1] != '_')- goto skip_appledouble;-- /*- * Check if the data fork file exists.- *- * TODO: Check if this write disk object has handled it.- */- archive_strncpy(&datafork, pathname, p - pathname);- archive_strcat(&datafork, p + 2);- if (-#ifdef HAVE_LSTAT- lstat(datafork.s, &st) == -1 ||-#else- la_stat(datafork.s, &st) == -1 ||-#endif- (st.st_mode & AE_IFMT) != AE_IFREG)- goto skip_appledouble;-- /*- * Check if the file is in the AppleDouble form.- */- fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC);- __archive_ensure_cloexec_flag(fd);- if (fd == -1) {- archive_set_error(&a->archive, errno,- "Failed to open a restoring file");- ret = ARCHIVE_WARN;- goto skip_appledouble;- }- if (read(fd, buff, 8) == -1) {- archive_set_error(&a->archive, errno,- "Failed to read a restoring file");- close(fd);- ret = ARCHIVE_WARN;- goto skip_appledouble;- }- close(fd);- /* Check AppleDouble Magic Code. */- if (archive_be32dec(buff) != 0x00051607)- goto skip_appledouble;- /* Check AppleDouble Version. */- if (archive_be32dec(buff+4) != 0x00020000)- goto skip_appledouble;-- ret = copy_metadata(a, pathname, datafork.s,-#if defined(UF_COMPRESSED)- st.st_flags & UF_COMPRESSED);-#else- 0);-#endif- if (ret == ARCHIVE_OK) {- unlink(pathname);- ret = ARCHIVE_EOF;- }-skip_appledouble:- archive_string_free(&datafork);- return (ret);-}-#endif--#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX-/*- * Restore extended attributes - Linux, Darwin and AIX implementations:- * AIX' ea interface is syntaxwise identical to the Linux xattr interface.- */-static int-set_xattrs(struct archive_write_disk *a)-{- struct archive_entry *entry = a->entry;- struct archive_string errlist;- int ret = ARCHIVE_OK;- int i = archive_entry_xattr_reset(entry);- short fail = 0;-- archive_string_init(&errlist);-- while (i--) {- const char *name;- const void *value;- size_t size;- int e;-- archive_entry_xattr_next(entry, &name, &value, &size);-- if (name == NULL)- continue;-#if ARCHIVE_XATTR_LINUX- /* Linux: quietly skip POSIX.1e ACL extended attributes */- if (strncmp(name, "system.", 7) == 0 &&- (strcmp(name + 7, "posix_acl_access") == 0 ||- strcmp(name + 7, "posix_acl_default") == 0))- continue;- if (strncmp(name, "trusted.SGI_", 12) == 0 &&- (strcmp(name + 12, "ACL_DEFAULT") == 0 ||- strcmp(name + 12, "ACL_FILE") == 0))- continue;-- /* Linux: xfsroot namespace is obsolete and unsupported */- if (strncmp(name, "xfsroot.", 8) == 0) {- fail = 1;- archive_strcat(&errlist, name);- archive_strappend_char(&errlist, ' ');- continue;- }-#endif-- if (a->fd >= 0) {-#if ARCHIVE_XATTR_LINUX- e = fsetxattr(a->fd, name, value, size, 0);-#elif ARCHIVE_XATTR_DARWIN- e = fsetxattr(a->fd, name, value, size, 0, 0);-#elif ARCHIVE_XATTR_AIX- e = fsetea(a->fd, name, value, size, 0);-#endif- } else {-#if ARCHIVE_XATTR_LINUX- e = lsetxattr(archive_entry_pathname(entry),- name, value, size, 0);-#elif ARCHIVE_XATTR_DARWIN- e = setxattr(archive_entry_pathname(entry),- name, value, size, 0, XATTR_NOFOLLOW);-#elif ARCHIVE_XATTR_AIX- e = lsetea(archive_entry_pathname(entry),- name, value, size, 0);-#endif- }- if (e == -1) {- ret = ARCHIVE_WARN;- archive_strcat(&errlist, name);- archive_strappend_char(&errlist, ' ');- if (errno != ENOTSUP && errno != ENOSYS)- fail = 1;- }- }-- if (ret == ARCHIVE_WARN) {- if (fail && errlist.length > 0) {- errlist.length--;- errlist.s[errlist.length] = '\0';- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Cannot restore extended attributes: %s",- errlist.s);- } else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Cannot restore extended "- "attributes on this file system.");- }-- archive_string_free(&errlist);- return (ret);-}-#elif ARCHIVE_XATTR_FREEBSD-/*- * Restore extended attributes - FreeBSD implementation- */-static int-set_xattrs(struct archive_write_disk *a)-{- struct archive_entry *entry = a->entry;- struct archive_string errlist;- int ret = ARCHIVE_OK;- int i = archive_entry_xattr_reset(entry);- short fail = 0;-- archive_string_init(&errlist);-- while (i--) {- const char *name;- const void *value;- size_t size;- archive_entry_xattr_next(entry, &name, &value, &size);- if (name != NULL) {- int e;- int namespace;-- namespace = EXTATTR_NAMESPACE_USER;-- if (strncmp(name, "user.", 5) == 0) {- /* "user." attributes go to user namespace */- name += 5;- namespace = EXTATTR_NAMESPACE_USER;- } else if (strncmp(name, "system.", 7) == 0) {- name += 7;- namespace = EXTATTR_NAMESPACE_SYSTEM;- if (!strcmp(name, "nfs4.acl") ||- !strcmp(name, "posix1e.acl_access") ||- !strcmp(name, "posix1e.acl_default"))- continue;- } else {- /* Other namespaces are unsupported */- archive_strcat(&errlist, name);- archive_strappend_char(&errlist, ' ');- fail = 1;- ret = ARCHIVE_WARN;- continue;- }-- if (a->fd >= 0) {- /*- * On FreeBSD, extattr_set_fd does not- * return the same as- * extattr_set_file. It returns zero- * on success, non-zero on failure.- *- * We can detect the failure by- * manually setting errno prior to the- * call and checking after.- *- * If errno remains zero, fake the- * return value by setting e to size.- *- * This is a hack for now until I- * (Shawn Webb) get FreeBSD to fix the- * issue, if that's even possible.- */- errno = 0;- e = extattr_set_fd(a->fd, namespace, name,- value, size);- if (e == 0 && errno == 0) {- e = size;- }- } else {- e = extattr_set_link(- archive_entry_pathname(entry), namespace,- name, value, size);- }- if (e != (int)size) {- archive_strcat(&errlist, name);- archive_strappend_char(&errlist, ' ');- ret = ARCHIVE_WARN;- if (errno != ENOTSUP && errno != ENOSYS)- fail = 1;- }- }- }-- if (ret == ARCHIVE_WARN) {- if (fail && errlist.length > 0) {- errlist.length--;- errlist.s[errlist.length] = '\0';-- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Cannot restore extended attributes: %s",- errlist.s);- } else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Cannot restore extended "- "attributes on this file system.");- }-- archive_string_free(&errlist);- return (ret);-}-#else-/*- * Restore extended attributes - stub implementation for unsupported systems- */-static int-set_xattrs(struct archive_write_disk *a)-{- static int warning_done = 0;-- /* If there aren't any extended attributes, then it's okay not- * to extract them, otherwise, issue a single warning. */- if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) {- warning_done = 1;- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Cannot restore extended attributes on this system");- return (ARCHIVE_WARN);- }- /* Warning was already emitted; suppress further warnings. */- return (ARCHIVE_OK);-}-#endif--/*- * Test if file on disk is older than entry.- */-static int-older(struct stat *st, struct archive_entry *entry)-{- /* First, test the seconds and return if we have a definite answer. */- /* Definitely older. */- if (to_int64_time(st->st_mtime) < to_int64_time(archive_entry_mtime(entry)))- return (1);- /* Definitely younger. */- if (to_int64_time(st->st_mtime) > to_int64_time(archive_entry_mtime(entry)))- return (0);- /* If this platform supports fractional seconds, try those. */-#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC- /* Definitely older. */- if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry))- return (1);-#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC- /* Definitely older. */- if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry))- return (1);-#elif HAVE_STRUCT_STAT_ST_MTIME_N- /* older. */- if (st->st_mtime_n < archive_entry_mtime_nsec(entry))- return (1);-#elif HAVE_STRUCT_STAT_ST_UMTIME- /* older. */- if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry))- return (1);-#elif HAVE_STRUCT_STAT_ST_MTIME_USEC- /* older. */- if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry))- return (1);-#else- /* This system doesn't have high-res timestamps. */-#endif- /* Same age or newer, so not older. */- return (0);-}--#ifndef ARCHIVE_ACL_SUPPORT-int-archive_write_disk_set_acls(struct archive *a, int fd, const char *name,- struct archive_acl *abstract_acl, __LA_MODE_T mode)-{- (void)a; /* UNUSED */- (void)fd; /* UNUSED */- (void)name; /* UNUSED */- (void)abstract_acl; /* UNUSED */- (void)mode; /* UNUSED */- return (ARCHIVE_OK);-}-#endif--/*- * Close the file descriptor if one is open.- */-static void close_file_descriptor(struct archive_write_disk* a)-{- if (a->fd >= 0) {- close(a->fd);- a->fd = -1;- }-}---#endif /* !_WIN32 || __CYGWIN__ */-
− c/archive_write_disk_private.h
@@ -1,45 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD: head/lib/libarchive/archive_write_disk_private.h 201086 2009-12-28 02:17:53Z kientzle $- */--#ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED-#define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--#include "archive_platform_acl.h"-#include "archive_acl_private.h"-#include "archive_entry.h"--struct archive_write_disk;--int archive_write_disk_set_acls(struct archive *, int, const char *,- struct archive_acl *, __LA_MODE_T);--#endif
− c/archive_write_disk_set_standard_lookup.c
@@ -1,263 +0,0 @@-/*-- * 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_disk_set_standard_lookup.c 201083 2009-12-28 02:09:57Z kientzle $");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_GRP_H-#include <grp.h>-#endif-#ifdef HAVE_PWD_H-#include <pwd.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_read_private.h"-#include "archive_write_disk_private.h"--struct bucket {- char *name;- int hash;- id_t id;-};--static const size_t cache_size = 127;-static unsigned int hash(const char *);-static int64_t lookup_gid(void *, const char *uname, int64_t);-static int64_t lookup_uid(void *, const char *uname, int64_t);-static void cleanup(void *);--/*- * Installs functions that use getpwnam()/getgrnam()---along with- * a simple cache to accelerate such lookups---into the archive_write_disk- * object. This is in a separate file because getpwnam()/getgrnam()- * can pull in a LOT of library code (including NIS/LDAP functions, which- * pull in DNS resolvers, etc). This can easily top 500kB, which makes- * it inappropriate for some space-constrained applications.- *- * Applications that are size-sensitive may want to just use the- * real default functions (defined in archive_write_disk.c) that just- * use the uid/gid without the lookup. Or define your own custom functions- * if you prefer.- *- * TODO: Replace these hash tables with simpler move-to-front LRU- * lists with a bounded size (128 items?). The hash is a bit faster,- * but has a bad pathology in which it thrashes a single bucket. Even- * walking a list of 128 items is a lot faster than calling- * getpwnam()!- */-int-archive_write_disk_set_standard_lookup(struct archive *a)-{- struct bucket *ucache = calloc(cache_size, sizeof(struct bucket));- struct bucket *gcache = calloc(cache_size, sizeof(struct bucket));- if (ucache == NULL || gcache == NULL) {- free(ucache);- free(gcache);- return (ARCHIVE_FATAL);- }- archive_write_disk_set_group_lookup(a, gcache, lookup_gid, cleanup);- archive_write_disk_set_user_lookup(a, ucache, lookup_uid, cleanup);- return (ARCHIVE_OK);-}--static int64_t-lookup_gid(void *private_data, const char *gname, int64_t gid)-{- int h;- struct bucket *b;- struct bucket *gcache = (struct bucket *)private_data;-- /* If no gname, just use the gid provided. */- if (gname == NULL || *gname == '\0')- return (gid);-- /* Try to find gname in the cache. */- h = hash(gname);- b = &gcache[h % cache_size ];- if (b->name != NULL && b->hash == h && strcmp(gname, b->name) == 0)- return ((gid_t)b->id);-- /* Free the cache slot for a new entry. */- free(b->name);- b->name = strdup(gname);- /* Note: If strdup fails, that's okay; we just won't cache. */- b->hash = h;-#if HAVE_GRP_H-# if HAVE_GETGRNAM_R- {- char _buffer[128];- size_t bufsize = 128;- char *buffer = _buffer;- char *allocated = NULL;- struct group grent, *result;- int r;-- for (;;) {- result = &grent; /* Old getgrnam_r ignores last arg. */- r = getgrnam_r(gname, &grent, buffer, bufsize, &result);- if (r == 0)- break;- if (r != ERANGE)- break;- bufsize *= 2;- free(allocated);- allocated = malloc(bufsize);- if (allocated == NULL)- break;- buffer = allocated;- }- if (result != NULL)- gid = result->gr_gid;- free(allocated);- }-# else /* HAVE_GETGRNAM_R */- {- struct group *result;-- result = getgrnam(gname);- if (result != NULL)- gid = result->gr_gid;- }-# endif /* HAVE_GETGRNAM_R */-#elif defined(_WIN32) && !defined(__CYGWIN__)- /* TODO: do a gname->gid lookup for Windows. */-#else- #error No way to perform gid lookups on this platform-#endif- b->id = (gid_t)gid;-- return (gid);-}--static int64_t-lookup_uid(void *private_data, const char *uname, int64_t uid)-{- int h;- struct bucket *b;- struct bucket *ucache = (struct bucket *)private_data;-- /* If no uname, just use the uid provided. */- if (uname == NULL || *uname == '\0')- return (uid);-- /* Try to find uname in the cache. */- h = hash(uname);- b = &ucache[h % cache_size ];- if (b->name != NULL && b->hash == h && strcmp(uname, b->name) == 0)- return ((uid_t)b->id);-- /* Free the cache slot for a new entry. */- free(b->name);- b->name = strdup(uname);- /* Note: If strdup fails, that's okay; we just won't cache. */- b->hash = h;-#if HAVE_PWD_H-# if HAVE_GETPWNAM_R- {- char _buffer[128];- size_t bufsize = 128;- char *buffer = _buffer;- char *allocated = NULL;- struct passwd pwent, *result;- int r;-- for (;;) {- result = &pwent; /* Old getpwnam_r ignores last arg. */- r = getpwnam_r(uname, &pwent, buffer, bufsize, &result);- if (r == 0)- break;- if (r != ERANGE)- break;- bufsize *= 2;- free(allocated);- allocated = malloc(bufsize);- if (allocated == NULL)- break;- buffer = allocated;- }- if (result != NULL)- uid = result->pw_uid;- free(allocated);- }-# else /* HAVE_GETPWNAM_R */- {- struct passwd *result;-- result = getpwnam(uname);- if (result != NULL)- uid = result->pw_uid;- }-#endif /* HAVE_GETPWNAM_R */-#elif defined(_WIN32) && !defined(__CYGWIN__)- /* TODO: do a uname->uid lookup for Windows. */-#else- #error No way to look up uids on this platform-#endif- b->id = (uid_t)uid;-- return (uid);-}--static void-cleanup(void *private)-{- size_t i;- struct bucket *cache = (struct bucket *)private;-- for (i = 0; i < cache_size; i++)- free(cache[i].name);- free(cache);-}---static unsigned int-hash(const char *p)-{- /* A 32-bit version of Peter Weinberger's (PJW) hash algorithm,- as used by ELF for hashing function names. */- unsigned g, h = 0;- while (*p != '\0') {- h = (h << 4) + *p++;- if ((g = h & 0xF0000000) != 0) {- h ^= g >> 24;- h &= 0x0FFFFFFF;- }- }- return h;-}
− c/archive_write_disk_windows.c
@@ -1,2911 +0,0 @@-/*-- * Copyright (c) 2003-2010 Tim Kientzle- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#if defined(_WIN32) && !defined(__CYGWIN__)--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_SYS_UTIME_H-#include <sys/utime.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#include <winioctl.h>--/* TODO: Support Mac OS 'quarantine' feature. This is really just a- * standard tag to mark files that have been downloaded as "tainted".- * On Mac OS, we should mark the extracted files as tainted if the- * archive being read was tainted. Windows has a similar feature; we- * should investigate ways to support this generically. */--#include "archive.h"-#include "archive_acl_private.h"-#include "archive_string.h"-#include "archive_entry.h"-#include "archive_private.h"--#ifndef O_BINARY-#define O_BINARY 0-#endif-#ifndef IO_REPARSE_TAG_SYMLINK-/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */-#define IO_REPARSE_TAG_SYMLINK 0xA000000CL-#endif--static BOOL SetFilePointerEx_perso(HANDLE hFile,- LARGE_INTEGER liDistanceToMove,- PLARGE_INTEGER lpNewFilePointer,- DWORD dwMoveMethod)-{- LARGE_INTEGER li;- li.QuadPart = liDistanceToMove.QuadPart;- li.LowPart = SetFilePointer(- hFile, li.LowPart, &li.HighPart, dwMoveMethod);- if(lpNewFilePointer) {- lpNewFilePointer->QuadPart = li.QuadPart;- }- return li.LowPart != (DWORD)-1 || GetLastError() == NO_ERROR;-}--struct fixup_entry {- struct fixup_entry *next;- struct archive_acl acl;- mode_t mode;- int64_t atime;- int64_t birthtime;- int64_t mtime;- int64_t ctime;- unsigned long atime_nanos;- unsigned long birthtime_nanos;- unsigned long mtime_nanos;- unsigned long ctime_nanos;- unsigned long fflags_set;- int fixup; /* bitmask of what needs fixing */- wchar_t *name;-};--/*- * We use a bitmask to track which operations remain to be done for- * this file. In particular, this helps us avoid unnecessary- * operations when it's possible to take care of one step as a- * side-effect of another. For example, mkdir() can specify the mode- * for the newly-created object but symlink() cannot. This means we- * can skip chmod() if mkdir() succeeded, but we must explicitly- * chmod() if we're trying to create a directory that already exists- * (mkdir() failed) or if we're restoring a symlink. Similarly, we- * need to verify UID/GID before trying to restore SUID/SGID bits;- * that verification can occur explicitly through a stat() call or- * implicitly because of a successful chown() call.- */-#define TODO_MODE_FORCE 0x40000000-#define TODO_MODE_BASE 0x20000000-#define TODO_SUID 0x10000000-#define TODO_SUID_CHECK 0x08000000-#define TODO_SGID 0x04000000-#define TODO_SGID_CHECK 0x02000000-#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID)-#define TODO_TIMES ARCHIVE_EXTRACT_TIME-#define TODO_OWNER ARCHIVE_EXTRACT_OWNER-#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS-#define TODO_ACLS ARCHIVE_EXTRACT_ACL-#define TODO_XATTR ARCHIVE_EXTRACT_XATTR-#define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA--struct archive_write_disk {- struct archive archive;-- mode_t user_umask;- struct fixup_entry *fixup_list;- struct fixup_entry *current_fixup;- int64_t user_uid;- int skip_file_set;- int64_t skip_file_dev;- int64_t skip_file_ino;- time_t start_time;-- int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid);- void (*cleanup_gid)(void *private);- void *lookup_gid_data;- int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid);- void (*cleanup_uid)(void *private);- void *lookup_uid_data;-- /*- * Full path of last file to satisfy symlink checks.- */- struct archive_wstring path_safe;-- /*- * Cached stat data from disk for the current entry.- * If this is valid, pst points to st. Otherwise,- * pst is null.- */- BY_HANDLE_FILE_INFORMATION st;- BY_HANDLE_FILE_INFORMATION *pst;-- /* Information about the object being restored right now. */- struct archive_entry *entry; /* Entry being extracted. */- wchar_t *name; /* Name of entry, possibly edited. */- struct archive_wstring _name_data; /* backing store for 'name' */- wchar_t *tmpname; /* Temporary name */- struct archive_wstring _tmpname_data; /* backing store for 'tmpname' */- /* Tasks remaining for this object. */- int todo;- /* Tasks deferred until end-of-archive. */- int deferred;- /* Options requested by the client. */- int flags;- /* Handle for the file we're restoring. */- HANDLE fh;- /* Current offset for writing data to the file. */- int64_t offset;- /* Last offset actually written to disk. */- int64_t fd_offset;- /* Total bytes actually written to files. */- int64_t total_bytes_written;- /* Maximum size of file, -1 if unknown. */- 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. */- mode_t mode;- /* UID/GID to use in restoring this entry. */- int64_t uid;- int64_t gid;-};--/*- * Default mode for dirs created automatically (will be modified by umask).- * Note that POSIX specifies 0777 for implicitly-created dirs, "modified- * by the process' file creation mask."- */-#define DEFAULT_DIR_MODE 0777-/*- * Dir modes are restored in two steps: During the extraction, the permissions- * in the archive are modified to match the following limits. During- * the post-extract fixup pass, the permissions from the archive are- * applied.- */-#define MINIMUM_DIR_MODE 0700-#define MAXIMUM_DIR_MODE 0775--static int disk_unlink(const wchar_t *);-static int disk_rmdir(const wchar_t *);-static int check_symlinks(struct archive_write_disk *);-static int create_filesystem_object(struct archive_write_disk *);-static struct fixup_entry *current_fixup(struct archive_write_disk *,- const wchar_t *pathname);-static int cleanup_pathname(struct archive_write_disk *, wchar_t *);-static int create_dir(struct archive_write_disk *, wchar_t *);-static int create_parent_dir(struct archive_write_disk *, wchar_t *);-static int la_chmod(const wchar_t *, mode_t);-static int la_mktemp(struct archive_write_disk *);-static int older(BY_HANDLE_FILE_INFORMATION *, struct archive_entry *);-static int permissive_name_w(struct archive_write_disk *);-static int restore_entry(struct archive_write_disk *);-static int set_acls(struct archive_write_disk *, HANDLE h,- const wchar_t *, struct archive_acl *);-static int set_xattrs(struct archive_write_disk *);-static int clear_nochange_fflags(struct archive_write_disk *);-static int set_fflags(struct archive_write_disk *);-static int set_fflags_platform(const wchar_t *, unsigned long,- unsigned long);-static int set_ownership(struct archive_write_disk *);-static int set_mode(struct archive_write_disk *, int mode);-static int set_times(struct archive_write_disk *, HANDLE, int,- const wchar_t *, time_t, long, time_t, long, time_t,- long, time_t, long);-static int set_times_from_entry(struct archive_write_disk *);-static struct fixup_entry *sort_dir_list(struct fixup_entry *p);-static ssize_t write_data_block(struct archive_write_disk *,- const char *, size_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, int64_t);--#define bhfi_dev(bhfi) ((bhfi)->dwVolumeSerialNumber)-/* Treat FileIndex as i-node. We should remove a sequence number- * which is high-16-bits of nFileIndexHigh. */-#define bhfi_ino(bhfi) \- ((((int64_t)((bhfi)->nFileIndexHigh & 0x0000FFFFUL)) << 32) \- | (bhfi)->nFileIndexLow)-#define bhfi_size(bhfi) \- ((((int64_t)(bhfi)->nFileSizeHigh) << 32) | (bhfi)->nFileSizeLow)--static int-file_information(struct archive_write_disk *a, wchar_t *path,- BY_HANDLE_FILE_INFORMATION *st, mode_t *mode, int sim_lstat)-{- HANDLE h;- int r;- DWORD flag = FILE_FLAG_BACKUP_SEMANTICS;- WIN32_FIND_DATAW findData;-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;-#endif-- if (sim_lstat || mode != NULL) {- h = FindFirstFileW(path, &findData);- if (h == INVALID_HANDLE_VALUE &&- GetLastError() == ERROR_INVALID_NAME) {- wchar_t *full;- full = __la_win_permissive_name_w(path);- h = FindFirstFileW(full, &findData);- free(full);- }- if (h == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- return (-1);- }- FindClose(h);- }-- /* Is symlink file ? */- if (sim_lstat && - ((findData.dwFileAttributes- & FILE_ATTRIBUTE_REPARSE_POINT) &&- (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)))- flag |= FILE_FLAG_OPEN_REPARSE_POINT;--# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileFlags = flag;- h = CreateFile2(a->name, 0, 0,- OPEN_EXISTING, &createExParams);-#else- h = CreateFileW(a->name, 0, 0, NULL,- OPEN_EXISTING, flag, NULL);-#endif- if (h == INVALID_HANDLE_VALUE &&- GetLastError() == ERROR_INVALID_NAME) {- wchar_t *full;- full = __la_win_permissive_name_w(path);-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- h = CreateFile2(full, 0, 0,- OPEN_EXISTING, &createExParams);-#else- h = CreateFileW(full, 0, 0, NULL,- OPEN_EXISTING, flag, NULL);-#endif- free(full);- }- if (h == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- return (-1);- }- r = GetFileInformationByHandle(h, st);- CloseHandle(h);- if (r == 0) {- la_dosmaperr(GetLastError());- return (-1);- }-- if (mode == NULL)- return (0);-- *mode = S_IRUSR | S_IRGRP | S_IROTH;- if ((st->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)- *mode |= S_IWUSR | S_IWGRP | S_IWOTH;- if ((st->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&- findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)- *mode |= S_IFLNK;- else if (st->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)- *mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;- else {- const wchar_t *p;-- *mode |= S_IFREG;- p = wcsrchr(path, L'.');- if (p != NULL && wcslen(p) == 4) {- switch (p[1]) {- case L'B': case L'b':- if ((p[2] == L'A' || p[2] == L'a' ) &&- (p[3] == L'T' || p[3] == L't' ))- *mode |= S_IXUSR | S_IXGRP | S_IXOTH;- break;- case L'C': case L'c':- if (((p[2] == L'M' || p[2] == L'm' ) &&- (p[3] == L'D' || p[3] == L'd' )))- *mode |= S_IXUSR | S_IXGRP | S_IXOTH;- break;- case L'E': case L'e':- if ((p[2] == L'X' || p[2] == L'x' ) &&- (p[3] == L'E' || p[3] == L'e' ))- *mode |= S_IXUSR | S_IXGRP | S_IXOTH;- break;- default:- break;- }- }- }- return (0);-}--/* - * Note: The path, for example, "aa/a/../b../c" will be converted to "aa/c"- * by GetFullPathNameW() W32 API, which __la_win_permissive_name_w uses.- * It means we cannot handle multiple dirs in one archive_entry.- * So we have to make the full-pathname in another way, which does not- * break "../" path string.- */-static int-permissive_name_w(struct archive_write_disk *a)-{- wchar_t *wn, *wnp;- wchar_t *ws, *wsp;- DWORD l;-- wnp = a->name;- if (wnp[0] == L'\\' && wnp[1] == L'\\' &&- wnp[2] == L'?' && wnp[3] == L'\\')- /* We have already a permissive name. */- return (0);-- if (wnp[0] == L'\\' && wnp[1] == L'\\' &&- wnp[2] == L'.' && wnp[3] == L'\\') {- /* This is a device name */- if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||- (wnp[4] >= L'A' && wnp[4] <= L'Z')) &&- wnp[5] == L':' && wnp[6] == L'\\') {- wnp[2] = L'?';/* Not device name. */- return (0);- }- }-- /*- * A full-pathname starting with a drive name like "C:\abc".- */- if (((wnp[0] >= L'a' && wnp[0] <= L'z') ||- (wnp[0] >= L'A' && wnp[0] <= L'Z')) &&- wnp[1] == L':' && wnp[2] == L'\\') {- wn = _wcsdup(wnp);- if (wn == NULL)- return (-1);- archive_wstring_ensure(&(a->_name_data), 4 + wcslen(wn) + 1);- a->name = a->_name_data.s;- /* Prepend "\\?\" */- archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);- archive_wstrcat(&(a->_name_data), wn);- free(wn);- return (0);- }-- /*- * A full-pathname pointing to a network drive- * like "\\<server-name>\<share-name>\file". - */- if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {- const wchar_t *p = &wnp[2];-- /* Skip server-name letters. */- while (*p != L'\\' && *p != L'\0')- ++p;- if (*p == L'\\') {- const wchar_t *rp = ++p;- /* Skip share-name letters. */- while (*p != L'\\' && *p != L'\0')- ++p;- if (*p == L'\\' && p != rp) {- /* Now, match patterns such as- * "\\server-name\share-name\" */- wn = _wcsdup(wnp);- if (wn == NULL)- return (-1);- archive_wstring_ensure(&(a->_name_data),- 8 + wcslen(wn) + 1);- a->name = a->_name_data.s;- /* Prepend "\\?\UNC\" */- archive_wstrncpy(&(a->_name_data),- L"\\\\?\\UNC\\", 8);- archive_wstrcat(&(a->_name_data), wn+2);- free(wn);- return (0);- }- }- return (0);- }-- /*- * Get current working directory.- */- l = GetCurrentDirectoryW(0, NULL);- if (l == 0)- return (-1);- ws = malloc(l * sizeof(wchar_t));- l = GetCurrentDirectoryW(l, ws);- if (l == 0) {- free(ws);- return (-1);- }- wsp = ws;-- /*- * A full-pathname starting without a drive name like "\abc".- */- if (wnp[0] == L'\\') {- wn = _wcsdup(wnp);- if (wn == NULL)- return (-1);- archive_wstring_ensure(&(a->_name_data),- 4 + 2 + wcslen(wn) + 1);- a->name = a->_name_data.s;- /* Prepend "\\?\" and drive name. */- archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);- archive_wstrncat(&(a->_name_data), wsp, 2);- archive_wstrcat(&(a->_name_data), wn);- free(wsp);- free(wn);- return (0);- }-- wn = _wcsdup(wnp);- if (wn == NULL)- return (-1);- archive_wstring_ensure(&(a->_name_data), 4 + l + 1 + wcslen(wn) + 1);- a->name = a->_name_data.s;- /* Prepend "\\?\" and drive name if not already added. */- if (l > 3 && wsp[0] == L'\\' && wsp[1] == L'\\' &&- wsp[2] == L'?' && wsp[3] == L'\\')- {- archive_wstrncpy(&(a->_name_data), wsp, l);- }- else if (l > 2 && wsp[0] == L'\\' && wsp[1] == L'\\' && wsp[2] != L'\\')- {- archive_wstrncpy(&(a->_name_data), L"\\\\?\\UNC\\", 8);- archive_wstrncat(&(a->_name_data), wsp+2, l-2);- }- else- {- archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);- archive_wstrncat(&(a->_name_data), wsp, l);- }- archive_wstrncat(&(a->_name_data), L"\\", 1);- archive_wstrcat(&(a->_name_data), wn);- a->name = a->_name_data.s;- free(wsp);- free(wn);- return (0);-}--static int-la_chmod(const wchar_t *path, mode_t mode)-{- DWORD attr;- BOOL r;- wchar_t *fullname;- int ret = 0;-- fullname = NULL;- attr = GetFileAttributesW(path);- if (attr == (DWORD)-1 &&- GetLastError() == ERROR_INVALID_NAME) {- fullname = __la_win_permissive_name_w(path);- attr = GetFileAttributesW(fullname);- }- if (attr == (DWORD)-1) {- la_dosmaperr(GetLastError());- ret = -1;- goto exit_chmode;- }- if (mode & _S_IWRITE)- attr &= ~FILE_ATTRIBUTE_READONLY;- else- attr |= FILE_ATTRIBUTE_READONLY;- if (fullname != NULL)- r = SetFileAttributesW(fullname, attr);- else- r = SetFileAttributesW(path, attr);- if (r == 0) {- la_dosmaperr(GetLastError());- ret = -1;- }-exit_chmode:- free(fullname);- return (ret);-}--static int-la_mktemp(struct archive_write_disk *a)-{- int fd;- mode_t mode;-- archive_wstring_empty(&(a->_tmpname_data));- archive_wstrcpy(&(a->_tmpname_data), a->name);- archive_wstrcat(&(a->_tmpname_data), L".XXXXXX");- a->tmpname = a->_tmpname_data.s;-- fd = __archive_mkstemp(a->tmpname);- if (fd == -1)- return -1;-- mode = a->mode & 0777 & ~a->user_umask;- if (la_chmod(a->tmpname, mode) == -1) {- la_dosmaperr(GetLastError());- _close(fd);- return -1;- }- return (fd);-}--#if _WIN32_WINNT < _WIN32_WINNT_VISTA-static void *-la_GetFunctionKernel32(const char *name)-{- static HINSTANCE lib;- static int set;- if (!set) {- set = 1;- lib = LoadLibrary(TEXT("kernel32.dll"));- }- if (lib == NULL) {- fprintf(stderr, "Can't load kernel32.dll?!\n");- exit(1);- }- return (void *)GetProcAddress(lib, name);-}-#endif--static int-la_CreateHardLinkW(wchar_t *linkname, wchar_t *target)-{- static BOOL (WINAPI *f)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);- BOOL ret;--#if _WIN32_WINNT < _WIN32_WINNT_XP- static int set;-/* CreateHardLinkW is available since XP and always loaded */- if (!set) {- set = 1;- f = la_GetFunctionKernel32("CreateHardLinkW");- }-#else- f = CreateHardLinkW;-#endif- if (!f) {- errno = ENOTSUP;- return (0);- }- ret = (*f)(linkname, target, NULL);- if (!ret) {- /* Under windows 2000, it is necessary to remove- * the "\\?\" prefix. */-#define IS_UNC(name) ((name[0] == L'U' || name[0] == L'u') && \- (name[1] == L'N' || name[1] == L'n') && \- (name[2] == L'C' || name[2] == L'c') && \- name[3] == L'\\')- if (!wcsncmp(linkname,L"\\\\?\\", 4)) {- linkname += 4;- if (IS_UNC(linkname))- linkname += 4;- }- if (!wcsncmp(target,L"\\\\?\\", 4)) {- target += 4;- if (IS_UNC(target))- target += 4;- }-#undef IS_UNC- ret = (*f)(linkname, target, NULL);- }- return (ret);-}--/*- * Create file or directory symolic link- *- * If linktype is AE_SYMLINK_TYPE_UNDEFINED (or unknown), guess linktype from- * the link target- */-static int-la_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target,- int linktype) {- static BOOLEAN (WINAPI *f)(LPCWSTR, LPCWSTR, DWORD);- wchar_t *ttarget, *p;- size_t len;- DWORD attrs = 0;- DWORD flags = 0;- DWORD newflags = 0;- BOOL ret = 0;--#if _WIN32_WINNT < _WIN32_WINNT_VISTA-/* CreateSymbolicLinkW is available since Vista and always loaded */- static int set;- if (!set) {- set = 1;- f = la_GetFunctionKernel32("CreateSymbolicLinkW");- }-#else-# if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)- f = CreateSymbolicLinkW;-# else- f = NULL;-# endif-#endif- if (!f)- return (0);-- len = wcslen(target);- if (len == 0) {- errno = EINVAL;- return(0);- }- /*- * When writing path targets, we need to translate slashes- * to backslashes- */- ttarget = malloc((len + 1) * sizeof(wchar_t));- if (ttarget == NULL)- return(0);-- p = ttarget;-- while(*target != L'\0') {- if (*target == L'/')- *p = L'\\';- else- *p = *target;- target++;- p++;- }- *p = L'\0';-- /*- * In case of undefined symlink type we guess it from the target.- * If the target equals ".", "..", ends with a backslash or a- * backslash followed by "." or ".." we assume it is a directory- * symlink. In all other cases we assume a file symlink.- */- if (linktype != AE_SYMLINK_TYPE_FILE && (- linktype == AE_SYMLINK_TYPE_DIRECTORY ||- *(p - 1) == L'\\' || (*(p - 1) == L'.' && (- len == 1 || *(p - 2) == L'\\' || ( *(p - 2) == L'.' && (- len == 2 || *(p - 3) == L'\\')))))) {-#if defined(SYMBOLIC_LINK_FLAG_DIRECTORY)- flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;-#else- flags |= 0x1;-#endif- }--#if defined(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)- newflags = flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;-#else- newflags = flags | 0x2;-#endif-- /*- * Windows won't overwrite existing links- */- attrs = GetFileAttributesW(linkname);- if (attrs != INVALID_FILE_ATTRIBUTES) {- if (attrs & FILE_ATTRIBUTE_DIRECTORY)- disk_rmdir(linkname);- else- disk_unlink(linkname);- }-- ret = (*f)(linkname, ttarget, newflags);- /*- * Prior to Windows 10 calling CreateSymbolicLinkW() will fail- * if SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE is set- */- if (!ret) {- ret = (*f)(linkname, ttarget, flags);- }- free(ttarget);- return (ret);-}--static int-la_ftruncate(HANDLE handle, int64_t length)-{- LARGE_INTEGER distance;-- if (GetFileType(handle) != FILE_TYPE_DISK) {- errno = EBADF;- return (-1);- }- distance.QuadPart = length;- if (!SetFilePointerEx_perso(handle, distance, NULL, FILE_BEGIN)) {- la_dosmaperr(GetLastError());- return (-1);- }- if (!SetEndOfFile(handle)) {- la_dosmaperr(GetLastError());- return (-1);- }- return (0);-}--static int-lazy_stat(struct archive_write_disk *a)-{- if (a->pst != NULL) {- /* Already have stat() data available. */- return (ARCHIVE_OK);- }- if (a->fh != INVALID_HANDLE_VALUE &&- GetFileInformationByHandle(a->fh, &a->st) == 0) {- a->pst = &a->st;- return (ARCHIVE_OK);- }-- /*- * XXX At this point, symlinks should not be hit, otherwise- * XXX a race occurred. Do we want to check explicitly for that?- */- if (file_information(a, a->name, &a->st, NULL, 1) == 0) {- a->pst = &a->st;- return (ARCHIVE_OK);- }- archive_set_error(&a->archive, errno, "Couldn't stat file");- return (ARCHIVE_WARN);-}--static const struct archive_vtable-archive_write_disk_vtable = {- .archive_close = _archive_write_disk_close,- .archive_filter_bytes = _archive_write_disk_filter_bytes,- .archive_free = _archive_write_disk_free,- .archive_write_header = _archive_write_disk_header,- .archive_write_finish_entry = _archive_write_disk_finish_entry,- .archive_write_data = _archive_write_disk_data,- .archive_write_data_block = _archive_write_disk_data_block,-};--static int64_t-_archive_write_disk_filter_bytes(struct archive *_a, int n)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- (void)n; /* UNUSED */- if (n == -1 || n == 0)- return (a->total_bytes_written);- return (-1);-}---int-archive_write_disk_set_options(struct archive *_a, int flags)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;-- a->flags = flags;- return (ARCHIVE_OK);-}---/*- * Extract this entry to disk.- *- * TODO: Validate hardlinks. According to the standards, we're- * supposed to check each extracted hardlink and squawk if it refers- * to a file that we didn't restore. I'm not entirely convinced this- * is a good idea, but more importantly: Is there any way to validate- * hardlinks without keeping a complete list of filenames from the- * entire archive?? Ugh.- *- */-static int-_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;- int ret, r;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_write_disk_header");- archive_clear_error(&a->archive);- if (a->archive.state & ARCHIVE_STATE_DATA) {- r = _archive_write_disk_finish_entry(&a->archive);- if (r == ARCHIVE_FATAL)- return (r);- }-- /* Set up for this particular entry. */- a->pst = NULL;- a->current_fixup = NULL;- a->deferred = 0;- archive_entry_free(a->entry);- a->entry = NULL;- a->entry = archive_entry_clone(entry);- a->fh = INVALID_HANDLE_VALUE;- a->fd_offset = 0;- a->offset = 0;- a->restore_pwd = -1;- a->uid = a->user_uid;- a->mode = archive_entry_mode(a->entry);- if (archive_entry_size_is_set(a->entry))- a->filesize = archive_entry_size(a->entry);- else- a->filesize = -1;- archive_wstrcpy(&(a->_name_data), archive_entry_pathname_w(a->entry));- a->name = a->_name_data.s;- archive_clear_error(&a->archive);-- /*- * Clean up the requested path. This is necessary for correct- * dir restores; the dir restore logic otherwise gets messed- * up by nonsense like "dir/.".- */- ret = cleanup_pathname(a, a->name);- if (ret != ARCHIVE_OK)- return (ret);-- /*- * Generate a full-pathname and use it from here.- */- if (permissive_name_w(a) < 0) {- errno = EINVAL;- return (ARCHIVE_FAILED);- }-- /*- * Query the umask so we get predictable mode settings.- * This gets done on every call to _write_header in case the- * user edits their umask during the extraction for some- * reason.- */- umask(a->user_umask = umask(0));-- /* Figure out what we need to do for this entry. */- a->todo = TODO_MODE_BASE;- if (a->flags & ARCHIVE_EXTRACT_PERM) {- a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */- /*- * SGID requires an extra "check" step because we- * cannot easily predict the GID that the system will- * assign. (Different systems assign GIDs to files- * based on a variety of criteria, including process- * credentials and the gid of the enclosing- * directory.) We can only restore the SGID bit if- * the file has the right GID, and we only know the- * GID if we either set it (see set_ownership) or if- * we've actually called stat() on the file after it- * was restored. Since there are several places at- * which we might verify the GID, we need a TODO bit- * to keep track.- */- if (a->mode & S_ISGID)- a->todo |= TODO_SGID | TODO_SGID_CHECK;- /*- * Verifying the SUID is simpler, but can still be- * done in multiple ways, hence the separate "check" bit.- */- if (a->mode & S_ISUID)- a->todo |= TODO_SUID | TODO_SUID_CHECK;- } else {- /*- * User didn't request full permissions, so don't- * restore SUID, SGID bits and obey umask.- */- a->mode &= ~S_ISUID;- a->mode &= ~S_ISGID;- a->mode &= ~S_ISVTX;- a->mode &= ~a->user_umask;- }-#if 0- if (a->flags & ARCHIVE_EXTRACT_OWNER)- a->todo |= TODO_OWNER;-#endif- if (a->flags & ARCHIVE_EXTRACT_TIME)- a->todo |= TODO_TIMES;- if (a->flags & ARCHIVE_EXTRACT_ACL) {- if (archive_entry_filetype(a->entry) == AE_IFDIR)- a->deferred |= TODO_ACLS;- else- a->todo |= TODO_ACLS;- }- if (a->flags & ARCHIVE_EXTRACT_XATTR)- a->todo |= TODO_XATTR;- if (a->flags & ARCHIVE_EXTRACT_FFLAGS)- a->todo |= TODO_FFLAGS;- if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {- ret = check_symlinks(a);- if (ret != ARCHIVE_OK)- return (ret);- }-- ret = restore_entry(a);-- /*- * TODO: There are rumours that some extended attributes must- * be restored before file data is written. If this is true,- * then we either need to write all extended attributes both- * before and after restoring the data, or find some rule for- * determining which must go first and which last. Due to the- * many ways people are using xattrs, this may prove to be an- * intractable problem.- */-- /*- * Fixup uses the unedited pathname from archive_entry_pathname(),- * because it is relative to the base dir and the edited path- * might be relative to some intermediate dir as a result of the- * deep restore logic.- */- if (a->deferred & TODO_MODE) {- fe = current_fixup(a, archive_entry_pathname_w(entry));- fe->fixup |= TODO_MODE_BASE;- fe->mode = a->mode;- }-- if ((a->deferred & TODO_TIMES)- && (archive_entry_mtime_is_set(entry)- || archive_entry_atime_is_set(entry))) {- fe = current_fixup(a, archive_entry_pathname_w(entry));- fe->mode = a->mode;- fe->fixup |= TODO_TIMES;- if (archive_entry_atime_is_set(entry)) {- fe->atime = archive_entry_atime(entry);- fe->atime_nanos = archive_entry_atime_nsec(entry);- } else {- /* If atime is unset, use start time. */- fe->atime = a->start_time;- fe->atime_nanos = 0;- }- if (archive_entry_mtime_is_set(entry)) {- fe->mtime = archive_entry_mtime(entry);- fe->mtime_nanos = archive_entry_mtime_nsec(entry);- } else {- /* If mtime is unset, use start time. */- fe->mtime = a->start_time;- fe->mtime_nanos = 0;- }- if (archive_entry_birthtime_is_set(entry)) {- fe->birthtime = archive_entry_birthtime(entry);- fe->birthtime_nanos = archive_entry_birthtime_nsec(entry);- } else {- /* If birthtime is unset, use mtime. */- fe->birthtime = fe->mtime;- fe->birthtime_nanos = fe->mtime_nanos;- }- }-- if (a->deferred & TODO_ACLS) {- fe = current_fixup(a, archive_entry_pathname_w(entry));- archive_acl_copy(&fe->acl, archive_entry_acl(entry));- }-- if (a->deferred & TODO_FFLAGS) {- unsigned long set, clear;-- fe = current_fixup(a, archive_entry_pathname_w(entry));- archive_entry_fflags(entry, &set, &clear);- fe->fflags_set = set;- }-- /*- * On Windows, A creating sparse file requires a special mark.- */- if (a->fh != INVALID_HANDLE_VALUE &&- archive_entry_sparse_count(entry) > 0) {- int64_t base = 0, offset, length;- int i, cnt = archive_entry_sparse_reset(entry);- int sparse = 0;-- for (i = 0; i < cnt; i++) {- archive_entry_sparse_next(entry, &offset, &length);- if (offset - base >= 4096) {- sparse = 1;/* we have a hole. */- break;- }- base = offset + length;- }- if (sparse) {- DWORD dmy;- /* Mark this file as sparse. */- DeviceIoControl(a->fh, FSCTL_SET_SPARSE,- NULL, 0, NULL, 0, &dmy, NULL);- }- }-- /* We've created the object and are ready to pour data into it. */- if (ret >= ARCHIVE_WARN)- a->archive.state = ARCHIVE_STATE_DATA;- /*- * If it's not open, tell our client not to try writing.- * In particular, dirs, links, etc, don't get written to.- */- if (a->fh == INVALID_HANDLE_VALUE) {- archive_entry_set_size(entry, 0);- a->filesize = 0;- }-- return (ret);-}--int-archive_write_disk_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file");- a->skip_file_set = 1;- a->skip_file_dev = d;- a->skip_file_ino = i;- return (ARCHIVE_OK);-}--static ssize_t-write_data_block(struct archive_write_disk *a, const char *buff, size_t size)-{- OVERLAPPED ol;- uint64_t start_size = size;- DWORD bytes_written = 0;- ssize_t block_size = 0, bytes_to_write;-- if (size == 0)- return (ARCHIVE_OK);-- if (a->filesize == 0 || a->fh == INVALID_HANDLE_VALUE) {- archive_set_error(&a->archive, 0,- "Attempt to write to an empty file");- return (ARCHIVE_WARN);- }-- if (a->flags & ARCHIVE_EXTRACT_SPARSE) {- /* XXX TODO XXX Is there a more appropriate choice here ? */- /* This needn't match the filesystem allocation size. */- block_size = 16*1024;- }-- /* If this write would run beyond the file size, truncate it. */- if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)- start_size = size = (size_t)(a->filesize - a->offset);-- /* Write the data. */- while (size > 0) {- if (block_size == 0) {- bytes_to_write = size;- } else {- /* We're sparsifying the file. */- const char *p, *end;- int64_t block_end;-- /* Skip leading zero bytes. */- for (p = buff, end = buff + size; p < end; ++p) {- if (*p != '\0')- break;- }- a->offset += p - buff;- size -= p - buff;- buff = p;- if (size == 0)- break;-- /* Calculate next block boundary after offset. */- block_end- = (a->offset / block_size + 1) * block_size;-- /* If the adjusted write would cross block boundary,- * truncate it to the block boundary. */- bytes_to_write = size;- if (a->offset + bytes_to_write > block_end)- bytes_to_write = (DWORD)(block_end - a->offset);- }- memset(&ol, 0, sizeof(ol));- ol.Offset = (DWORD)(a->offset & 0xFFFFFFFF);- ol.OffsetHigh = (DWORD)(a->offset >> 32);- if (!WriteFile(a->fh, buff, (uint32_t)bytes_to_write,- &bytes_written, &ol)) {- DWORD lasterr;-- lasterr = GetLastError();- if (lasterr == ERROR_ACCESS_DENIED)- errno = EBADF;- else- la_dosmaperr(lasterr);- archive_set_error(&a->archive, errno, "Write failed");- return (ARCHIVE_WARN);- }- buff += bytes_written;- size -= bytes_written;- a->total_bytes_written += bytes_written;- a->offset += bytes_written;- a->fd_offset = a->offset;- }- return ((ssize_t)(start_size - size));-}--static ssize_t-_archive_write_disk_data_block(struct archive *_a,- const void *buff, size_t size, int64_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_data_block");-- a->offset = offset;- r = write_data_block(a, buff, size);- if (r < ARCHIVE_OK)- return (r);- if ((size_t)r < size) {- archive_set_error(&a->archive, 0,- "Write request too large");- return (ARCHIVE_WARN);- }-#if ARCHIVE_VERSION_NUMBER < 3999000- return (ARCHIVE_OK);-#else- return (size);-#endif-}--static ssize_t-_archive_write_disk_data(struct archive *_a, const void *buff, size_t size)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_DATA, "archive_write_data");-- return (write_data_block(a, buff, size));-}--static int-_archive_write_disk_finish_entry(struct archive *_a)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- int ret = ARCHIVE_OK;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_write_finish_entry");- if (a->archive.state & ARCHIVE_STATE_HEADER)- return (ARCHIVE_OK);- archive_clear_error(&a->archive);-- /* Pad or truncate file to the right size. */- if (a->fh == INVALID_HANDLE_VALUE) {- /* There's no file. */- } else if (a->filesize < 0) {- /* File size is unknown, so we can't set the size. */- } else if (a->fd_offset == a->filesize) {- /* Last write ended at exactly the filesize; we're done. */- /* Hopefully, this is the common case. */- } else {- if (la_ftruncate(a->fh, a->filesize) == -1) {- archive_set_error(&a->archive, errno,- "File size could not be restored");- CloseHandle(a->fh);- a->fh = INVALID_HANDLE_VALUE;- return (ARCHIVE_FAILED);- }- }-- /* Restore metadata. */-- /*- * Look up the "real" UID only if we're going to need it.- * TODO: the TODO_SGID condition can be dropped here, can't it?- */- if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) {- a->uid = archive_write_disk_uid(&a->archive,- archive_entry_uname(a->entry),- archive_entry_uid(a->entry));- }- /* Look up the "real" GID only if we're going to need it. */- /* TODO: the TODO_SUID condition can be dropped here, can't it? */- if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) {- a->gid = archive_write_disk_gid(&a->archive,- archive_entry_gname(a->entry),- archive_entry_gid(a->entry));- }-- /*- * Restore ownership before set_mode tries to restore suid/sgid- * bits. If we set the owner, we know what it is and can skip- * a stat() call to examine the ownership of the file on disk.- */- if (a->todo & TODO_OWNER)- ret = set_ownership(a);-- /*- * set_mode must precede ACLs on systems such as Solaris and- * FreeBSD where setting the mode implicitly clears extended ACLs- */- if (a->todo & TODO_MODE) {- int r2 = set_mode(a, a->mode);- if (r2 < ret) ret = r2;- }-- /*- * Security-related extended attributes (such as- * security.capability on Linux) have to be restored last,- * since they're implicitly removed by other file changes.- */- if (a->todo & TODO_XATTR) {- int r2 = set_xattrs(a);- if (r2 < ret) ret = r2;- }-- /*- * Some flags prevent file modification; they must be restored after- * file contents are written.- */- if (a->todo & TODO_FFLAGS) {- int r2 = set_fflags(a);- if (r2 < ret) ret = r2;- }-- /*- * Time must follow most other metadata;- * otherwise atime will get changed.- */- if (a->todo & TODO_TIMES) {- int r2 = set_times_from_entry(a);- if (r2 < ret) ret = r2;- }-- /*- * ACLs must be restored after timestamps because there are- * ACLs that prevent attribute changes (including time).- */- if (a->todo & TODO_ACLS) {- int r2 = set_acls(a, a->fh,- archive_entry_pathname_w(a->entry),- archive_entry_acl(a->entry));- if (r2 < ret) ret = r2;- }-- /* If there's an fd, we can close it now. */- if (a->fh != INVALID_HANDLE_VALUE) {- CloseHandle(a->fh);- a->fh = INVALID_HANDLE_VALUE;- if (a->tmpname) {- /* Windows does not support atomic rename */- disk_unlink(a->name);- if (_wrename(a->tmpname, a->name) != 0) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "Failed to rename temporary file");- ret = ARCHIVE_FAILED;- disk_unlink(a->tmpname);- }- a->tmpname = NULL;- }- }- /* If there's an entry, we can release it now. */- archive_entry_free(a->entry);- a->entry = NULL;- a->archive.state = ARCHIVE_STATE_HEADER;- return (ret);-}--int-archive_write_disk_set_group_lookup(struct archive *_a,- void *private_data,- la_int64_t (*lookup_gid)(void *private, const char *gname, la_int64_t gid),- void (*cleanup_gid)(void *private))-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup");-- if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL)- (a->cleanup_gid)(a->lookup_gid_data);-- a->lookup_gid = lookup_gid;- a->cleanup_gid = cleanup_gid;- a->lookup_gid_data = private_data;- return (ARCHIVE_OK);-}--int-archive_write_disk_set_user_lookup(struct archive *_a,- void *private_data,- int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid),- void (*cleanup_uid)(void *private))-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup");-- if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL)- (a->cleanup_uid)(a->lookup_uid_data);-- a->lookup_uid = lookup_uid;- a->cleanup_uid = cleanup_uid;- a->lookup_uid_data = private_data;- return (ARCHIVE_OK);-}--int64_t-archive_write_disk_gid(struct archive *_a, const char *name, la_int64_t id)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_disk_gid");- if (a->lookup_gid)- return (a->lookup_gid)(a->lookup_gid_data, name, id);- return (id);-}- -int64_t-archive_write_disk_uid(struct archive *_a, const char *name, la_int64_t id)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY, "archive_write_disk_uid");- if (a->lookup_uid)- return (a->lookup_uid)(a->lookup_uid_data, name, id);- return (id);-}--/*- * Create a new archive_write_disk object and initialize it with global state.- */-struct archive *-archive_write_disk_new(void)-{- struct archive_write_disk *a;-- a = (struct archive_write_disk *)calloc(1, sizeof(*a));- if (a == NULL)- return (NULL);- a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;- /* We're ready to write a header immediately. */- a->archive.state = ARCHIVE_STATE_HEADER;- a->archive.vtable = &archive_write_disk_vtable;- a->start_time = time(NULL);- /* Query and restore the umask. */- umask(a->user_umask = umask(0));- if (archive_wstring_ensure(&a->path_safe, 512) == NULL) {- free(a);- return (NULL);- }- a->path_safe.s[0] = 0;- return (&a->archive);-}--static int-disk_unlink(const wchar_t *path)-{- wchar_t *fullname;- int r;-- r = _wunlink(path);- if (r != 0 && GetLastError() == ERROR_INVALID_NAME) {- fullname = __la_win_permissive_name_w(path);- r = _wunlink(fullname);- free(fullname);- }- return (r);-}--static int-disk_rmdir(const wchar_t *path)-{- wchar_t *fullname;- int r;-- r = _wrmdir(path);- if (r != 0 && GetLastError() == ERROR_INVALID_NAME) {- fullname = __la_win_permissive_name_w(path);- r = _wrmdir(fullname);- free(fullname);- }- return (r);-}--/*- * The main restore function.- */-static int-restore_entry(struct archive_write_disk *a)-{- int ret = ARCHIVE_OK, en;-- if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) {- /*- * TODO: Fix this. Apparently, there are platforms- * that still allow root to hose the entire filesystem- * by unlinking a dir. The S_ISDIR() test above- * prevents us from using unlink() here if the new- * object is a dir, but that doesn't mean the old- * object isn't a dir.- */- if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)- (void)clear_nochange_fflags(a);- if (disk_unlink(a->name) == 0) {- /* We removed it, reset cached stat. */- a->pst = NULL;- } else if (errno == ENOENT) {- /* File didn't exist, that's just as good. */- } else if (disk_rmdir(a->name) == 0) {- /* It was a dir, but now it's gone. */- a->pst = NULL;- } else {- /* We tried, but couldn't get rid of it. */- archive_set_error(&a->archive, errno,- "Could not unlink");- return(ARCHIVE_FAILED);- }- }-- /* Try creating it first; if this fails, we'll try to recover. */- en = create_filesystem_object(a);-- if ((en == ENOTDIR || en == ENOENT)- && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) {- wchar_t *full;- /* If the parent dir doesn't exist, try creating it. */- create_parent_dir(a, a->name);- /* Now try to create the object again. */- full = __la_win_permissive_name_w(a->name);- if (full == NULL) {- en = EINVAL;- } else {- /* Remove multiple directories such as "a/../b../c" */- archive_wstrcpy(&(a->_name_data), full);- a->name = a->_name_data.s;- free(full);- en = create_filesystem_object(a);- }- }-- if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) {- archive_set_error(&a->archive, en,- "Hard-link target '%s' does not exist.",- archive_entry_hardlink(a->entry));- return (ARCHIVE_FAILED);- }-- if ((en == EISDIR || en == EEXIST)- && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {- /* If we're not overwriting, we're done. */- if (S_ISDIR(a->mode)) {- /* Don't overwrite any settings on existing directories. */- a->todo = 0;- }- archive_entry_unset_size(a->entry);- return (ARCHIVE_OK);- }-- /*- * Some platforms return EISDIR if you call- * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some- * return EEXIST. POSIX is ambiguous, requiring EISDIR- * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT)- * on an existing item.- */- if (en == EISDIR) {- /* A dir is in the way of a non-dir, rmdir it. */- if (disk_rmdir(a->name) != 0) {- archive_set_error(&a->archive, errno,- "Can't remove already-existing dir");- return (ARCHIVE_FAILED);- }- a->pst = NULL;- /* Try again. */- en = create_filesystem_object(a);- } else if (en == EEXIST) {- mode_t st_mode;- mode_t lst_mode;- BY_HANDLE_FILE_INFORMATION lst;- /*- * We know something is in the way, but we don't know what;- * we need to find out before we go any further.- */- int r = 0;- int dirlnk = 0;-- /*- * The SECURE_SYMLINK logic has already removed a- * symlink to a dir if the client wants that. So- * follow the symlink if we're creating a dir.- * If it's not a dir (or it's a broken symlink),- * then don't follow it.- *- * Windows distinguishes file and directory symlinks.- * A file symlink may erroneously point to a directory- * and a directory symlink to a file. Windows does not follow- * such symlinks. We always need both source and target- * information.- */- r = file_information(a, a->name, &lst, &lst_mode, 1);- if (r != 0) {- archive_set_error(&a->archive, errno,- "Can't stat existing object");- return (ARCHIVE_FAILED);- } else if (S_ISLNK(lst_mode)) {- if (lst.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)- dirlnk = 1;- /* In case of a symlink we need target information */- r = file_information(a, a->name, &a->st, &st_mode, 0);- if (r != 0) {- a->st = lst;- st_mode = lst_mode;- }- } else {- a->st = lst;- st_mode = lst_mode;- }-- /*- * NO_OVERWRITE_NEWER doesn't apply to directories.- */- if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER)- && !S_ISDIR(st_mode)) {- if (!older(&(a->st), a->entry)) {- archive_entry_unset_size(a->entry);- return (ARCHIVE_OK);- }- }-- /* If it's our archive, we're done. */- if (a->skip_file_set &&- bhfi_dev(&a->st) == a->skip_file_dev &&- bhfi_ino(&a->st) == a->skip_file_ino) {- archive_set_error(&a->archive, 0,- "Refusing to overwrite archive");- return (ARCHIVE_FAILED);- }-- if (!S_ISDIR(st_mode)) {- if (a->flags &- ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) {- (void)clear_nochange_fflags(a);- }- if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) &&- S_ISREG(st_mode)) {- int fd = la_mktemp(a);-- if (fd == -1) {- la_dosmaperr(GetLastError());- archive_set_error(&a->archive, errno,- "Can't create temporary file");- return (ARCHIVE_FAILED);- }- a->fh = (HANDLE)_get_osfhandle(fd);- if (a->fh == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- return (ARCHIVE_FAILED);- }- a->pst = NULL;- en = 0;- } else {- if (dirlnk) {- /* Edge case: dir symlink pointing- * to a file */- if (disk_rmdir(a->name) != 0) {- archive_set_error(&a->archive,- errno, "Can't unlink "- "directory symlink");- return (ARCHIVE_FAILED);- }- } else {- if (disk_unlink(a->name) != 0) {- /* A non-dir is in the way,- * unlink it. */- archive_set_error(&a->archive,- errno, "Can't unlink "- "already-existing object");- return (ARCHIVE_FAILED);- }- }- a->pst = NULL;- /* Try again. */- en = create_filesystem_object(a);- }- } else if (!S_ISDIR(a->mode)) {- /* A dir is in the way of a non-dir, rmdir it. */- if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)- (void)clear_nochange_fflags(a);- if (disk_rmdir(a->name) != 0) {- archive_set_error(&a->archive, errno,- "Can't remove already-existing dir");- return (ARCHIVE_FAILED);- }- /* Try again. */- en = create_filesystem_object(a);- } else {- /*- * There's a dir in the way of a dir. Don't- * waste time with rmdir()/mkdir(), just fix- * up the permissions on the existing dir.- * Note that we don't change perms on existing- * dirs unless _EXTRACT_PERM is specified.- */- if ((a->mode != st_mode)- && (a->todo & TODO_MODE_FORCE))- a->deferred |= (a->todo & TODO_MODE);- /* Ownership doesn't need deferred fixup. */- en = 0; /* Forget the EEXIST. */- }- }-- if (en) {- /* Everything failed; give up here. */- archive_set_error(&a->archive, en, "Can't create '%ls'",- a->name);- return (ARCHIVE_FAILED);- }-- a->pst = NULL; /* Cached stat data no longer valid. */- return (ret);-}--/*- * Returns 0 if creation succeeds, or else returns errno value from- * the failed system call. Note: This function should only ever perform- * a single system call.- */-static int-create_filesystem_object(struct archive_write_disk *a)-{- /* Create the entry. */- const wchar_t *linkname;- wchar_t *fullname;- mode_t final_mode, mode;- int r;- DWORD attrs = 0;-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;-#endif-- /* We identify hard/symlinks according to the link names. */- /* Since link(2) and symlink(2) don't handle modes, we're done here. */- linkname = archive_entry_hardlink_w(a->entry);- if (linkname != NULL) {- wchar_t *linksanitized, *linkfull, *namefull;- size_t l = (wcslen(linkname) + 1) * sizeof(wchar_t);- linksanitized = malloc(l);- if (linksanitized == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for hardlink target");- return (-1);- }- memcpy(linksanitized, linkname, l);- r = cleanup_pathname(a, linksanitized);- if (r != ARCHIVE_OK) {- free(linksanitized);- return (r);- }- linkfull = __la_win_permissive_name_w(linksanitized);- free(linksanitized);- namefull = __la_win_permissive_name_w(a->name);- if (linkfull == NULL || namefull == NULL) {- errno = EINVAL;- r = -1;- } else {- /*- * Unlinking and linking here is really not atomic,- * but doing it right, would require us to construct- * an mktemplink() function, and then use _wrename().- */- if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) {- attrs = GetFileAttributesW(namefull);- if (attrs != INVALID_FILE_ATTRIBUTES) {- if (attrs & FILE_ATTRIBUTE_DIRECTORY)- disk_rmdir(namefull);- else- disk_unlink(namefull);- }- }- r = la_CreateHardLinkW(namefull, linkfull);- if (r == 0) {- la_dosmaperr(GetLastError());- r = errno;- } else- r = 0;- }- /*- * New cpio and pax formats allow hardlink entries- * to carry data, so we may have to open the file- * for hardlink entries.- *- * If the hardlink was successfully created and- * the archive doesn't have carry data for it,- * consider it to be non-authoritative for meta data.- * This is consistent with GNU tar and BSD pax.- * If the hardlink does carry data, let the last- * archive entry decide ownership.- */- if (r == 0 && a->filesize <= 0) {- a->todo = 0;- a->deferred = 0;- } else if (r == 0 && a->filesize > 0) {-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;- a->fh = CreateFile2(namefull, GENERIC_WRITE, 0,- TRUNCATE_EXISTING, &createExParams);-#else- a->fh = CreateFileW(namefull, GENERIC_WRITE, 0, NULL,- TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);-#endif- if (a->fh == INVALID_HANDLE_VALUE) {- la_dosmaperr(GetLastError());- r = errno;- }- }- free(linkfull);- free(namefull);- return (r);- }- linkname = archive_entry_symlink_w(a->entry);- if (linkname != NULL) {- /*- * Unlinking and linking here is really not atomic,- * but doing it right, would require us to construct- * an mktemplink() function, and then use _wrename().- */- attrs = GetFileAttributesW(a->name);- if (attrs != INVALID_FILE_ATTRIBUTES) {- if (attrs & FILE_ATTRIBUTE_DIRECTORY)- disk_rmdir(a->name);- else- disk_unlink(a->name);- }-#if HAVE_SYMLINK- return symlink(linkname, a->name) ? errno : 0;-#else- errno = 0;- r = la_CreateSymbolicLinkW((const wchar_t *)a->name, linkname,- archive_entry_symlink_type(a->entry));- if (r == 0) {- if (errno == 0)- la_dosmaperr(GetLastError());- r = errno;- } else- r = 0;- return (r);-#endif- }-- /*- * The remaining system calls all set permissions, so let's- * try to take advantage of that to avoid an extra chmod()- * call. (Recall that umask is set to zero right now!)- */-- /* Mode we want for the final restored object (w/o file type bits). */- final_mode = a->mode & 07777;- /*- * The mode that will actually be restored in this step. Note- * that SUID, SGID, etc, require additional work to ensure- * security, so we never restore them at this point.- */- mode = final_mode & 0777 & ~a->user_umask;-- switch (a->mode & AE_IFMT) {- default:- /* POSIX requires that we fall through here. */- /* FALLTHROUGH */- case AE_IFREG:- a->tmpname = NULL;- fullname = a->name;- /* O_WRONLY | O_CREAT | O_EXCL */-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;- a->fh = CreateFile2(fullname, GENERIC_WRITE, 0,- CREATE_NEW, &createExParams);-#else- a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL,- CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);-#endif- if (a->fh == INVALID_HANDLE_VALUE &&- GetLastError() == ERROR_INVALID_NAME &&- fullname == a->name) {- fullname = __la_win_permissive_name_w(a->name);-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- a->fh = CreateFile2(fullname, GENERIC_WRITE, 0,- CREATE_NEW, &createExParams);-#else- a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL,- CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);-#endif- }- if (a->fh == INVALID_HANDLE_VALUE) {- if (GetLastError() == ERROR_ACCESS_DENIED) {- DWORD attr;- /* Simulate an errno of POSIX system. */- attr = GetFileAttributesW(fullname);- if (attr == (DWORD)-1)- la_dosmaperr(GetLastError());- else if (attr & FILE_ATTRIBUTE_DIRECTORY)- errno = EISDIR;- else- errno = EACCES;- } else- la_dosmaperr(GetLastError());- r = 1;- } else- r = 0;- if (fullname != a->name)- free(fullname);- break;- case AE_IFCHR:- case AE_IFBLK:- /* TODO: Find a better way to warn about our inability- * to restore a block device node. */- return (EINVAL);- case AE_IFDIR:- mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE;- fullname = a->name;- r = CreateDirectoryW(fullname, NULL);- if (r == 0 && GetLastError() == ERROR_INVALID_NAME &&- fullname == a->name) {- fullname = __la_win_permissive_name_w(a->name);- r = CreateDirectoryW(fullname, NULL);- }- if (r != 0) {- r = 0;- /* Defer setting dir times. */- a->deferred |= (a->todo & TODO_TIMES);- a->todo &= ~TODO_TIMES;- /* Never use an immediate chmod(). */- /* We can't avoid the chmod() entirely if EXTRACT_PERM- * because of SysV SGID inheritance. */- if ((mode != final_mode)- || (a->flags & ARCHIVE_EXTRACT_PERM))- a->deferred |= (a->todo & TODO_MODE);- a->todo &= ~TODO_MODE;- } else {- la_dosmaperr(GetLastError());- r = -1;- }- if (fullname != a->name)- free(fullname);- break;- case AE_IFIFO:- /* TODO: Find a better way to warn about our inability- * to restore a fifo. */- return (EINVAL);- }-- /* All the system calls above set errno on failure. */- if (r)- return (errno);-- /* If we managed to set the final mode, we've avoided a chmod(). */- if (mode == final_mode)- a->todo &= ~TODO_MODE;- return (0);-}--/*- * Cleanup function for archive_extract. Mostly, this involves processing- * the fixup list, which is used to address a number of problems:- * * Dir permissions might prevent us from restoring a file in that- * dir, so we restore the dir with minimum 0700 permissions first,- * then correct the mode at the end.- * * Similarly, the act of restoring a file touches the directory- * and changes the timestamp on the dir, so we have to touch-up dir- * timestamps at the end as well.- * * Some file flags can interfere with the restore by, for example,- * preventing the creation of hardlinks to those files.- * * Mac OS extended metadata includes ACLs, so must be deferred on dirs.- *- * Note that tar/cpio do not require that archives be in a particular- * order; there is no way to know when the last file has been restored- * within a directory, so there's no way to optimize the memory usage- * here by fixing up the directory any earlier than the- * end-of-archive.- *- * XXX TODO: Directory ACLs should be restored here, for the same- * reason we set directory perms here. XXX- */-static int-_archive_write_disk_close(struct archive *_a)-{- struct archive_write_disk *a = (struct archive_write_disk *)_a;- struct fixup_entry *next, *p;- int ret;-- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_write_disk_close");- 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);-- while (p != NULL) {- a->pst = NULL; /* Mark stat cache as out-of-date. */- if (p->fixup & TODO_TIMES) {- set_times(a, INVALID_HANDLE_VALUE, p->mode, p->name,- p->atime, p->atime_nanos,- p->birthtime, p->birthtime_nanos,- p->mtime, p->mtime_nanos,- p->ctime, p->ctime_nanos);- }- if (p->fixup & TODO_MODE_BASE)- la_chmod(p->name, p->mode);- if (p->fixup & TODO_ACLS)- set_acls(a, INVALID_HANDLE_VALUE, p->name, &p->acl);- if (p->fixup & TODO_FFLAGS)- set_fflags_platform(p->name, p->fflags_set, 0);- next = p->next;- archive_acl_clear(&p->acl);- free(p->name);- free(p);- p = next;- }- a->fixup_list = NULL;- return (ret);-}--static int-_archive_write_disk_free(struct archive *_a)-{- struct archive_write_disk *a;- int ret;- if (_a == NULL)- return (ARCHIVE_OK);- archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC,- ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free");- a = (struct archive_write_disk *)_a;- ret = _archive_write_disk_close(&a->archive);- archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL);- archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL);- archive_entry_free(a->entry);- archive_wstring_free(&a->_name_data);- archive_wstring_free(&a->_tmpname_data);- archive_string_free(&a->archive.error_string);- archive_wstring_free(&a->path_safe);- a->archive.magic = 0;- __archive_clean(&a->archive);- free(a);- return (ret);-}--/*- * Simple O(n log n) merge sort to order the fixup list. In- * particular, we want to restore dir timestamps depth-first.- */-static struct fixup_entry *-sort_dir_list(struct fixup_entry *p)-{- struct fixup_entry *a, *b, *t;-- if (p == NULL)- return (NULL);- /* A one-item list is already sorted. */- if (p->next == NULL)- return (p);-- /* Step 1: split the list. */- t = p;- a = p->next->next;- while (a != NULL) {- /* Step a twice, t once. */- a = a->next;- if (a != NULL)- a = a->next;- t = t->next;- }- /* Now, t is at the mid-point, so break the list here. */- b = t->next;- t->next = NULL;- a = p;-- /* Step 2: Recursively sort the two sub-lists. */- a = sort_dir_list(a);- b = sort_dir_list(b);-- /* Step 3: Merge the returned lists. */- /* Pick the first element for the merged list. */- if (wcscmp(a->name, b->name) > 0) {- t = p = a;- a = a->next;- } else {- t = p = b;- b = b->next;- }-- /* Always put the later element on the list first. */- while (a != NULL && b != NULL) {- if (wcscmp(a->name, b->name) > 0) {- t->next = a;- a = a->next;- } else {- t->next = b;- b = b->next;- }- t = t->next;- }-- /* Only one list is non-empty, so just splice it on. */- if (a != NULL)- t->next = a;- if (b != NULL)- t->next = b;-- return (p);-}--/*- * Returns a new, initialized fixup entry.- *- * TODO: Reduce the memory requirements for this list by using a tree- * structure rather than a simple list of names.- */-static struct fixup_entry *-new_fixup(struct archive_write_disk *a, const wchar_t *pathname)-{- struct fixup_entry *fe;-- fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry));- if (fe == NULL)- return (NULL);- fe->next = a->fixup_list;- a->fixup_list = fe;- fe->fixup = 0;- fe->name = _wcsdup(pathname);- fe->fflags_set = 0;- return (fe);-}--/*- * Returns a fixup structure for the current entry.- */-static struct fixup_entry *-current_fixup(struct archive_write_disk *a, const wchar_t *pathname)-{- if (a->current_fixup == NULL)- a->current_fixup = new_fixup(a, pathname);- return (a->current_fixup);-}--/*- * TODO: The deep-directory support bypasses this; disable deep directory- * support if we're doing symlink checks.- */-/*- * TODO: Someday, integrate this with the deep dir support; they both- * scan the path and both can be optimized by comparing against other- * recent paths.- */-static int-check_symlinks(struct archive_write_disk *a)-{- wchar_t *pn, *p;- wchar_t c;- int r;- BY_HANDLE_FILE_INFORMATION st;- mode_t st_mode;-- /*- * Guard against symlink tricks. Reject any archive entry whose- * destination would be altered by a symlink.- */- /* Whatever we checked last time doesn't need to be re-checked. */- pn = a->name;- p = a->path_safe.s;- while ((*pn != '\0') && (*p == *pn))- ++p, ++pn;- /* Skip leading backslashes */- while (*pn == '\\')- ++pn;- c = pn[0];- /* Keep going until we've checked the entire name. */- while (pn[0] != '\0' && (pn[0] != '\\' || pn[1] != '\0')) {- /* Skip the next path element. */- while (*pn != '\0' && *pn != '\\')- ++pn;- c = pn[0];- pn[0] = '\0';- /* Check that we haven't hit a symlink. */- r = file_information(a, a->name, &st, &st_mode, 1);- if (r != 0) {- /* We've hit a dir that doesn't exist; stop now. */- if (errno == ENOENT)- break;- } else if (S_ISLNK(st_mode)) {- if (c == '\0') {- /*- * Last element is a file or directory symlink.- * Remove it so we can overwrite it with the- * item being extracted.- */- if (a->flags &- ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) {- (void)clear_nochange_fflags(a);- }- if (st.dwFileAttributes &- FILE_ATTRIBUTE_DIRECTORY) {- r = disk_rmdir(a->name);- } else {- r = disk_unlink(a->name);- }- if (r) {- archive_set_error(&a->archive, errno,- "Could not remove symlink %ls",- a->name);- pn[0] = c;- return (ARCHIVE_FAILED);- }- a->pst = NULL;- /*- * Even if we did remove it, a warning- * is in order. The warning is silly,- * though, if we're just replacing one- * symlink with another symlink.- */- if (!S_ISLNK(a->mode)) {- archive_set_error(&a->archive, 0,- "Removing symlink %ls",- a->name);- }- /* Symlink gone. No more problem! */- pn[0] = c;- return (0);- } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) {- /* User asked us to remove problems. */- if (a->flags &- ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) {- (void)clear_nochange_fflags(a);- }- if (st.dwFileAttributes &- FILE_ATTRIBUTE_DIRECTORY) {- r = disk_rmdir(a->name);- } else {- r = disk_unlink(a->name);- }- if (r != 0) {- archive_set_error(&a->archive, 0,- "Cannot remove intervening "- "symlink %ls", a->name);- pn[0] = c;- return (ARCHIVE_FAILED);- }- a->pst = NULL;- } else {- archive_set_error(&a->archive, 0,- "Cannot extract through symlink %ls",- a->name);- pn[0] = c;- return (ARCHIVE_FAILED);- }- }- if (!c)- break;- pn[0] = c;- pn++;- }- pn[0] = c;- /* We've checked and/or cleaned the whole path, so remember it. */- archive_wstrcpy(&a->path_safe, a->name);- return (ARCHIVE_OK);-}--static int-guidword(wchar_t *p, int n)-{- int i;-- for (i = 0; i < n; i++) {- if ((*p >= L'0' && *p <= L'9') ||- (*p >= L'a' && *p <= L'f') ||- (*p >= L'A' && *p <= L'F'))- p++;- else- return (-1);- }- return (0);-}--/*- * Canonicalize the pathname. In particular, this strips duplicate- * '\' characters, '.' elements, and trailing '\'. It also raises an- * error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is- * set) any '..' in the path.- */-static int-cleanup_pathname(struct archive_write_disk *a, wchar_t *name)-{- wchar_t *dest, *src, *p, *top;- wchar_t separator = L'\0';-- p = name;- if (*p == L'\0') {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid empty pathname");- return (ARCHIVE_FAILED);- }-- /* Replace '/' by '\' */- for (; *p != L'\0'; p++) {- if (*p == L'/')- *p = L'\\';- }- p = name;-- /* Skip leading "\\.\" or "\\?\" or "\\?\UNC\" or- * "\\?\Volume{GUID}\"- * (absolute path prefixes used by Windows API) */- if (p[0] == L'\\' && p[1] == L'\\' &&- (p[2] == L'.' || p[2] == L'?') && p[3] == L'\\')- {- /* A path begin with "\\?\UNC\" */- if (p[2] == L'?' &&- (p[4] == L'U' || p[4] == L'u') &&- (p[5] == L'N' || p[5] == L'n') &&- (p[6] == L'C' || p[6] == L'c') &&- p[7] == L'\\')- p += 8;- /* A path begin with "\\?\Volume{GUID}\" */- else if (p[2] == L'?' &&- (p[4] == L'V' || p[4] == L'v') &&- (p[5] == L'O' || p[5] == L'o') &&- (p[6] == L'L' || p[6] == L'l') &&- (p[7] == L'U' || p[7] == L'u') &&- (p[8] == L'M' || p[8] == L'm') &&- (p[9] == L'E' || p[9] == L'e') &&- p[10] == L'{') {- if (guidword(p+11, 8) == 0 && p[19] == L'-' &&- guidword(p+20, 4) == 0 && p[24] == L'-' &&- guidword(p+25, 4) == 0 && p[29] == L'-' &&- guidword(p+30, 4) == 0 && p[34] == L'-' &&- guidword(p+35, 12) == 0 && p[47] == L'}' &&- p[48] == L'\\')- p += 49;- else- p += 4;- /* A path begin with "\\.\PhysicalDriveX" */- } else if (p[2] == L'.' &&- (p[4] == L'P' || p[4] == L'p') &&- (p[5] == L'H' || p[5] == L'h') &&- (p[6] == L'Y' || p[6] == L'y') &&- (p[7] == L'S' || p[7] == L's') &&- (p[8] == L'I' || p[8] == L'i') &&- (p[9] == L'C' || p[9] == L'c') &&- (p[9] == L'A' || p[9] == L'a') &&- (p[9] == L'L' || p[9] == L'l') &&- (p[9] == L'D' || p[9] == L'd') &&- (p[9] == L'R' || p[9] == L'r') &&- (p[9] == L'I' || p[9] == L'i') &&- (p[9] == L'V' || p[9] == L'v') &&- (p[9] == L'E' || p[9] == L'e') &&- (p[10] >= L'0' && p[10] <= L'9') &&- p[11] == L'\0') {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Path is a physical drive name");- return (ARCHIVE_FAILED);- } else- p += 4;- /* Network drive path like "\\<server-name>\<share-name>\file" */- } else if (p[0] == L'\\' && p[1] == L'\\') {- p += 2;- }-- /* Skip leading drive letter from archives created- * on Windows. */- if (((p[0] >= L'a' && p[0] <= L'z') ||- (p[0] >= L'A' && p[0] <= L'Z')) &&- p[1] == L':') {- if (p[2] == L'\0') {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Path is a drive name");- return (ARCHIVE_FAILED);- }- if (p[2] == L'\\')- p += 2;- }-- top = dest = src = p;- /* Rewrite the path name if its character is a unusable. */- for (; *p != L'\0'; p++) {- if (*p == L':' || *p == L'*' || *p == L'?' || *p == L'"' ||- *p == L'<' || *p == L'>' || *p == L'|')- *p = L'_';- }- /* Skip leading '\'. */- if (*src == L'\\')- separator = *src++;-- /* Scan the pathname one element at a time. */- for (;;) {- /* src points to first char after '\' */- if (src[0] == L'\0') {- break;- } else if (src[0] == L'\\') {- /* Found '\\'('//'), ignore second one. */- src++;- continue;- } else if (src[0] == L'.') {- if (src[1] == L'\0') {- /* Ignore trailing '.' */- break;- } else if (src[1] == L'\\') {- /* Skip '.\'. */- src += 2;- continue;- } else if (src[1] == L'.') {- if (src[2] == L'\\' || src[2] == L'\0') {- /* Conditionally warn about '..' */- if (a->flags &- ARCHIVE_EXTRACT_SECURE_NODOTDOT) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Path contains '..'");- return (ARCHIVE_FAILED);- }- }- /*- * Note: Under no circumstances do we- * remove '..' elements. In- * particular, restoring- * '\foo\..\bar\' should create the- * 'foo' dir as a side-effect.- */- }- }-- /* Copy current element, including leading '\'. */- if (separator)- *dest++ = L'\\';- while (*src != L'\0' && *src != L'\\') {- *dest++ = *src++;- }-- if (*src == L'\0')- break;-- /* Skip '\' separator. */- separator = *src++;- }- /*- * We've just copied zero or more path elements, not including the- * final '\'.- */- if (dest == top) {- /*- * Nothing got copied. The path must have been something- * like '.' or '\' or './' or '/././././/./'.- */- if (separator)- *dest++ = L'\\';- else- *dest++ = L'.';- }- /* Terminate the result. */- *dest = L'\0';- return (ARCHIVE_OK);-}--/*- * Create the parent directory of the specified path, assuming path- * is already in mutable storage.- */-static int-create_parent_dir(struct archive_write_disk *a, wchar_t *path)-{- wchar_t *slash;- int r;-- /* Remove tail element to obtain parent name. */- slash = wcsrchr(path, L'\\');- if (slash == NULL)- return (ARCHIVE_OK);- *slash = L'\0';- r = create_dir(a, path);- *slash = L'\\';- return (r);-}--/*- * Create the specified dir, recursing to create parents as necessary.- *- * Returns ARCHIVE_OK if the path exists when we're done here.- * Otherwise, returns ARCHIVE_FAILED.- * Assumes path is in mutable storage; path is unchanged on exit.- */-static int-create_dir(struct archive_write_disk *a, wchar_t *path)-{- BY_HANDLE_FILE_INFORMATION st;- struct fixup_entry *le;- wchar_t *slash, *base, *full;- mode_t mode_final, mode, st_mode;- int r;-- /* Check for special names and just skip them. */- slash = wcsrchr(path, L'\\');- if (slash == NULL)- base = path;- else- base = slash + 1;-- if (base[0] == L'\0' ||- (base[0] == L'.' && base[1] == L'\0') ||- (base[0] == L'.' && base[1] == L'.' && base[2] == L'\0')) {- /* Don't bother trying to create null path, '.', or '..'. */- if (slash != NULL) {- *slash = L'\0';- r = create_dir(a, path);- *slash = L'\\';- return (r);- }- return (ARCHIVE_OK);- }-- /*- * Yes, this should be stat() and not lstat(). Using lstat()- * here loses the ability to extract through symlinks. Also note- * that this should not use the a->st cache.- */- if (file_information(a, path, &st, &st_mode, 0) == 0) {- if (S_ISDIR(st_mode))- return (ARCHIVE_OK);- if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {- archive_set_error(&a->archive, EEXIST,- "Can't create directory '%ls'", path);- return (ARCHIVE_FAILED);- }- if (disk_unlink(path) != 0) {- archive_set_error(&a->archive, errno,- "Can't create directory '%ls': "- "Conflicting file cannot be removed",- path);- return (ARCHIVE_FAILED);- }- } else if (errno != ENOENT && errno != ENOTDIR) {- /* Stat failed? */- archive_set_error(&a->archive, errno,- "Can't test directory '%ls'", path);- return (ARCHIVE_FAILED);- } else if (slash != NULL) {- *slash = '\0';- r = create_dir(a, path);- *slash = '\\';- if (r != ARCHIVE_OK)- return (r);- }-- /*- * Mode we want for the final restored directory. Per POSIX,- * implicitly-created dirs must be created obeying the umask.- * There's no mention whether this is different for privileged- * restores (which the rest of this code handles by pretending- * umask=0). I've chosen here to always obey the user's umask for- * implicit dirs, even if _EXTRACT_PERM was specified.- */- mode_final = DEFAULT_DIR_MODE & ~a->user_umask;- /* Mode we want on disk during the restore process. */- mode = mode_final;- mode |= MINIMUM_DIR_MODE;- mode &= MAXIMUM_DIR_MODE;- /*- * Apply __la_win_permissive_name_w to path in order to- * remove '../' path string.- */- full = __la_win_permissive_name_w(path);- if (full == NULL)- errno = EINVAL;- else if (CreateDirectoryW(full, NULL) != 0) {- if (mode != mode_final) {- le = new_fixup(a, path);- le->fixup |=TODO_MODE_BASE;- le->mode = mode_final;- }- free(full);- return (ARCHIVE_OK);- } else {- la_dosmaperr(GetLastError());- }- free(full);-- /*- * Without the following check, a/b/../b/c/d fails at the- * second visit to 'b', so 'd' can't be created. Note that we- * don't add it to the fixup list here, as it's already been- * added.- */- if (file_information(a, path, &st, &st_mode, 0) == 0 &&- S_ISDIR(st_mode))- return (ARCHIVE_OK);-- archive_set_error(&a->archive, errno, "Failed to create dir '%ls'",- path);- return (ARCHIVE_FAILED);-}--/*- * Note: Although we can skip setting the user id if the desired user- * id matches the current user, we cannot skip setting the group, as- * many systems set the gid based on the containing directory. So- * we have to perform a chown syscall if we want to set the SGID- * bit. (The alternative is to stat() and then possibly chown(); it's- * more efficient to skip the stat() and just always chown().) Note- * that a successful chown() here clears the TODO_SGID_CHECK bit, which- * allows set_mode to skip the stat() check for the GID.- */-static int-set_ownership(struct archive_write_disk *a)-{-/* unfortunately, on win32 there is no 'root' user with uid 0,- so we just have to try the chown and see if it works */-- /* If we know we can't change it, don't bother trying. */- if (a->user_uid != 0 && a->user_uid != a->uid) {- archive_set_error(&a->archive, errno,- "Can't set UID=%jd", (intmax_t)a->uid);- return (ARCHIVE_WARN);- }-- archive_set_error(&a->archive, errno,- "Can't set user=%jd/group=%jd for %ls",- (intmax_t)a->uid, (intmax_t)a->gid, a->name);- return (ARCHIVE_WARN);-}--static int-set_times(struct archive_write_disk *a,- HANDLE h, int mode, const wchar_t *name,- time_t atime, long atime_nanos,- time_t birthtime, long birthtime_nanos,- time_t mtime, long mtime_nanos,- time_t ctime_sec, long ctime_nanos)-{-#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)-#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\- + (((nsec)/1000)*10))-- HANDLE hw = 0;- ULARGE_INTEGER wintm;- FILETIME *pfbtime;- FILETIME fatime, fbtime, fmtime;-- (void)ctime_sec; /* UNUSED */- (void)ctime_nanos; /* UNUSED */-- if (h != INVALID_HANDLE_VALUE) {- hw = NULL;- } else {- wchar_t *ws;-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- CREATEFILE2_EXTENDED_PARAMETERS createExParams;-#endif-- if (S_ISLNK(mode))- return (ARCHIVE_OK);- ws = __la_win_permissive_name_w(name);- if (ws == NULL)- goto settimes_failed;-# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */- ZeroMemory(&createExParams, sizeof(createExParams));- createExParams.dwSize = sizeof(createExParams);- createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;- hw = CreateFile2(ws, FILE_WRITE_ATTRIBUTES, 0,- OPEN_EXISTING, &createExParams);-#else- hw = CreateFileW(ws, FILE_WRITE_ATTRIBUTES,- 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);-#endif- free(ws);- if (hw == INVALID_HANDLE_VALUE)- goto settimes_failed;- h = hw;- }-- wintm.QuadPart = WINTIME(atime, atime_nanos);- fatime.dwLowDateTime = wintm.LowPart;- fatime.dwHighDateTime = wintm.HighPart;- wintm.QuadPart = WINTIME(mtime, mtime_nanos);- fmtime.dwLowDateTime = wintm.LowPart;- fmtime.dwHighDateTime = wintm.HighPart;- /*- * SetFileTime() supports birthtime.- */- if (birthtime > 0 || birthtime_nanos > 0) {- wintm.QuadPart = WINTIME(birthtime, birthtime_nanos);- fbtime.dwLowDateTime = wintm.LowPart;- fbtime.dwHighDateTime = wintm.HighPart;- pfbtime = &fbtime;- } else- pfbtime = NULL;- if (SetFileTime(h, pfbtime, &fatime, &fmtime) == 0)- goto settimes_failed;- CloseHandle(hw);- return (ARCHIVE_OK);--settimes_failed:- CloseHandle(hw);- archive_set_error(&a->archive, EINVAL, "Can't restore time");- return (ARCHIVE_WARN);-}--static int-set_times_from_entry(struct archive_write_disk *a)-{- time_t atime, birthtime, mtime, ctime_sec;- long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec;-- /* Suitable defaults. */- atime = birthtime = mtime = ctime_sec = a->start_time;- atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0;-- /* If no time was provided, we're done. */- if (!archive_entry_atime_is_set(a->entry)- && !archive_entry_birthtime_is_set(a->entry)- && !archive_entry_mtime_is_set(a->entry))- return (ARCHIVE_OK);-- if (archive_entry_atime_is_set(a->entry)) {- atime = archive_entry_atime(a->entry);- atime_nsec = archive_entry_atime_nsec(a->entry);- }- if (archive_entry_birthtime_is_set(a->entry)) {- birthtime = archive_entry_birthtime(a->entry);- birthtime_nsec = archive_entry_birthtime_nsec(a->entry);- }- if (archive_entry_mtime_is_set(a->entry)) {- mtime = archive_entry_mtime(a->entry);- mtime_nsec = archive_entry_mtime_nsec(a->entry);- }- if (archive_entry_ctime_is_set(a->entry)) {- ctime_sec = archive_entry_ctime(a->entry);- ctime_nsec = archive_entry_ctime_nsec(a->entry);- }-- return set_times(a, a->fh, a->mode, a->name,- atime, atime_nsec,- birthtime, birthtime_nsec,- mtime, mtime_nsec,- ctime_sec, ctime_nsec);-}--static int-set_mode(struct archive_write_disk *a, int mode)-{- int r = ARCHIVE_OK;- mode &= 07777; /* Strip off file type bits. */-- if (a->todo & TODO_SGID_CHECK) {- /*- * If we don't know the GID is right, we must stat()- * to verify it. We can't just check the GID of this- * process, since systems sometimes set GID from- * the enclosing dir or based on ACLs.- */- if ((r = lazy_stat(a)) != ARCHIVE_OK)- return (r);- if (0 != a->gid) {- mode &= ~ S_ISGID;- }- /* While we're here, double-check the UID. */- if (0 != a->uid- && (a->todo & TODO_SUID)) {- mode &= ~ S_ISUID;- }- a->todo &= ~TODO_SGID_CHECK;- a->todo &= ~TODO_SUID_CHECK;- } else if (a->todo & TODO_SUID_CHECK) {- /*- * If we don't know the UID is right, we can just check- * the user, since all systems set the file UID from- * the process UID.- */- if (a->user_uid != a->uid) {- mode &= ~ S_ISUID;- }- a->todo &= ~TODO_SUID_CHECK;- }-- if (S_ISLNK(a->mode)) {-#ifdef HAVE_LCHMOD- /*- * If this is a symlink, use lchmod(). If the- * platform doesn't support lchmod(), just skip it. A- * platform that doesn't provide a way to set- * permissions on symlinks probably ignores- * permissions on symlinks, so a failure here has no- * impact.- */- if (lchmod(a->name, mode) != 0) {- archive_set_error(&a->archive, errno,- "Can't set permissions to 0%o", (int)mode);- r = ARCHIVE_WARN;- }-#endif- } else if (!S_ISDIR(a->mode)) {- /*- * If it's not a symlink and not a dir, then use- * fchmod() or chmod(), depending on whether we have- * an fd. Dirs get their perms set during the- * post-extract fixup, which is handled elsewhere.- */-#ifdef HAVE_FCHMOD- if (a->fd >= 0) {- if (fchmod(a->fd, mode) != 0) {- archive_set_error(&a->archive, errno,- "Can't set permissions to 0%o", (int)mode);- r = ARCHIVE_WARN;- }- } else-#endif- /* If this platform lacks fchmod(), then- * we'll just use chmod(). */- if (la_chmod(a->name, mode) != 0) {- archive_set_error(&a->archive, errno,- "Can't set permissions to 0%o", (int)mode);- r = ARCHIVE_WARN;- }- }- return (r);-}--static int set_fflags_platform(const wchar_t *name, unsigned long fflags_set,- unsigned long fflags_clear)-{- DWORD oldflags, newflags;- wchar_t *fullname;-- const DWORD settable_flags =- FILE_ATTRIBUTE_ARCHIVE |- FILE_ATTRIBUTE_HIDDEN |- FILE_ATTRIBUTE_NORMAL |- FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |- FILE_ATTRIBUTE_OFFLINE |- FILE_ATTRIBUTE_READONLY |- FILE_ATTRIBUTE_SYSTEM |- FILE_ATTRIBUTE_TEMPORARY;-- oldflags = GetFileAttributesW(name);- if (oldflags == (DWORD)-1 &&- GetLastError() == ERROR_INVALID_NAME) {- fullname = __la_win_permissive_name_w(name);- oldflags = GetFileAttributesW(fullname);- }- if (oldflags == (DWORD)-1) {- la_dosmaperr(GetLastError());- return (ARCHIVE_WARN);- }- newflags = ((oldflags & ~fflags_clear) | fflags_set) & settable_flags;- if(SetFileAttributesW(name, newflags) == 0)- return (ARCHIVE_WARN);- return (ARCHIVE_OK);-}--static int-clear_nochange_fflags(struct archive_write_disk *a)-{- return (set_fflags_platform(a->name, 0, FILE_ATTRIBUTE_READONLY));-}--static int-set_fflags(struct archive_write_disk *a)-{- unsigned long set, clear;-- if (a->todo & TODO_FFLAGS) {- archive_entry_fflags(a->entry, &set, &clear);- if (set == 0 && clear == 0)- return (ARCHIVE_OK);- return (set_fflags_platform(a->name, set, clear));-- }- return (ARCHIVE_OK);-}--/* Default empty function body to satisfy mainline code. */-static int-set_acls(struct archive_write_disk *a, HANDLE h, const wchar_t *name,- struct archive_acl *acl)-{- (void)a; /* UNUSED */- (void)h; /* UNUSED */- (void)name; /* UNUSED */- (void)acl; /* UNUSED */- return (ARCHIVE_OK);-}--/*- * Restore extended attributes - stub implementation for unsupported systems- */-static int-set_xattrs(struct archive_write_disk *a)-{- static int warning_done = 0;-- /* If there aren't any extended attributes, then it's okay not- * to extract them, otherwise, issue a single warning. */- if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) {- warning_done = 1;- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Cannot restore extended attributes on this system");- return (ARCHIVE_WARN);- }- /* Warning was already emitted; suppress further warnings. */- return (ARCHIVE_OK);-}--static void-fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns)-{- ULARGE_INTEGER utc;-- utc.HighPart = filetime->dwHighDateTime;- utc.LowPart = filetime->dwLowDateTime;- if (utc.QuadPart >= EPOC_TIME) {- utc.QuadPart -= EPOC_TIME;- /* milli seconds base */- *t = (time_t)(utc.QuadPart / 10000000);- /* nano seconds base */- *ns = (long)(utc.QuadPart % 10000000) * 100;- } else {- *t = 0;- *ns = 0;- }-}-/*- * Test if file on disk is older than entry.- */-static int-older(BY_HANDLE_FILE_INFORMATION *st, struct archive_entry *entry)-{- time_t sec;- long nsec;-- fileTimeToUtc(&st->ftLastWriteTime, &sec, &nsec);- /* First, test the seconds and return if we have a definite answer. */- /* Definitely older. */- if (sec < archive_entry_mtime(entry))- return (1);- /* Definitely younger. */- if (sec > archive_entry_mtime(entry))- return (0);- if (nsec < archive_entry_mtime_nsec(entry))- return (1);- /* Same age or newer, so not older. */- return (0);-}--#endif /* _WIN32 && !__CYGWIN__ */-
− c/archive_write_open_fd.c
@@ -1,146 +0,0 @@-/*-- * 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_open_fd.c 201093 2009-12-28 02:28:44Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_IO_H-#include <io.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"--struct write_fd_data {- int fd;-};--static int file_free(struct archive *, void *);-static int file_open(struct archive *, void *);-static ssize_t file_write(struct archive *, void *, const void *buff, size_t);--int-archive_write_open_fd(struct archive *a, int fd)-{- struct write_fd_data *mine;-- mine = (struct write_fd_data *)malloc(sizeof(*mine));- if (mine == NULL) {- archive_set_error(a, ENOMEM, "No memory");- return (ARCHIVE_FATAL);- }- mine->fd = fd;-#if defined(__CYGWIN__) || defined(_WIN32)- setmode(mine->fd, O_BINARY);-#endif- return (archive_write_open2(a, mine,- file_open, file_write, NULL, file_free));-}--static int-file_open(struct archive *a, void *client_data)-{- struct write_fd_data *mine;- struct stat st;-- mine = (struct write_fd_data *)client_data;-- if (fstat(mine->fd, &st) != 0) {- archive_set_error(a, errno, "Couldn't stat fd %d", mine->fd);- return (ARCHIVE_FATAL);- }-- /*- * If this is a regular file, don't add it to itself.- */- if (S_ISREG(st.st_mode))- archive_write_set_skip_file(a, st.st_dev, st.st_ino);-- /*- * If client hasn't explicitly set the last block handling,- * then set it here.- */- if (archive_write_get_bytes_in_last_block(a) < 0) {- /* If the output is a block or character device, fifo,- * or stdout, pad the last block, otherwise leave it- * unpadded. */- if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) ||- S_ISFIFO(st.st_mode) || (mine->fd == 1))- /* Last block will be fully padded. */- archive_write_set_bytes_in_last_block(a, 0);- else- archive_write_set_bytes_in_last_block(a, 1);- }-- return (ARCHIVE_OK);-}--static ssize_t-file_write(struct archive *a, void *client_data, const void *buff, size_t length)-{- struct write_fd_data *mine;- ssize_t bytesWritten;-- mine = (struct write_fd_data *)client_data;- for (;;) {- bytesWritten = write(mine->fd, buff, length);- if (bytesWritten <= 0) {- if (errno == EINTR)- continue;- archive_set_error(a, errno, "Write error");- return (-1);- }- return (bytesWritten);- }-}--static int-file_free(struct archive *a, void *client_data)-{- struct write_fd_data *mine = (struct write_fd_data *)client_data;-- (void)a; /* UNUSED */- if (mine == NULL)- return (ARCHIVE_OK);- free(mine);- return (ARCHIVE_OK);-}
− c/archive_write_open_file.c
@@ -1,111 +0,0 @@-/*-- * 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: src/lib/libarchive/archive_write_open_file.c,v 1.19 2007/01/09 08:05:56 kientzle Exp $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"--struct write_FILE_data {- FILE *f;-};--static int file_free(struct archive *, void *);-static int file_open(struct archive *, void *);-static ssize_t file_write(struct archive *, void *, const void *buff, size_t);--int-archive_write_open_FILE(struct archive *a, FILE *f)-{- struct write_FILE_data *mine;-- mine = (struct write_FILE_data *)malloc(sizeof(*mine));- if (mine == NULL) {- archive_set_error(a, ENOMEM, "No memory");- return (ARCHIVE_FATAL);- }- mine->f = f;- return (archive_write_open2(a, mine, file_open, file_write,- NULL, file_free));-}--static int-file_open(struct archive *a, void *client_data)-{- (void)a; /* UNUSED */- (void)client_data; /* UNUSED */-- return (ARCHIVE_OK);-}--static ssize_t-file_write(struct archive *a, void *client_data, const void *buff, size_t length)-{- struct write_FILE_data *mine;- size_t bytesWritten;-- mine = client_data;- for (;;) {- bytesWritten = fwrite(buff, 1, length, mine->f);- if (bytesWritten <= 0) {- if (errno == EINTR)- continue;- archive_set_error(a, errno, "Write error");- return (-1);- }- return (bytesWritten);- }-}--static int-file_free(struct archive *a, void *client_data)-{- struct write_FILE_data *mine = client_data;-- (void)a; /* UNUSED */- if (mine == NULL)- return (ARCHIVE_OK);- free(mine);- return (ARCHIVE_OK);-}
− c/archive_write_open_filename.c
@@ -1,270 +0,0 @@-/*-- * 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_open_filename.c 191165 2009-04-17 00:39:35Z kientzle $");--#ifdef HAVE_SYS_STAT_H-#include <sys/stat.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_FCNTL_H-#include <fcntl.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_string.h"--#ifndef O_BINARY-#define O_BINARY 0-#endif-#ifndef O_CLOEXEC-#define O_CLOEXEC 0-#endif--struct write_file_data {- int fd;- struct archive_mstring filename;-};--static int file_close(struct archive *, void *);-static int file_free(struct archive *, void *);-static int file_open(struct archive *, void *);-static ssize_t file_write(struct archive *, void *, const void *buff, size_t);-static int open_filename(struct archive *, int, const void *);--int-archive_write_open_file(struct archive *a, const char *filename)-{- return (archive_write_open_filename(a, filename));-}--int-archive_write_open_filename(struct archive *a, const char *filename)-{-- if (filename == NULL || filename[0] == '\0')- return (archive_write_open_fd(a, 1));-- return (open_filename(a, 1, filename));-}--int-archive_write_open_filename_w(struct archive *a, const wchar_t *filename)-{-- if (filename == NULL || filename[0] == L'\0')- return (archive_write_open_fd(a, 1));-- return (open_filename(a, 0, filename));-}--static int-open_filename(struct archive *a, int mbs_fn, const void *filename)-{- struct write_file_data *mine;- int r;-- mine = (struct write_file_data *)calloc(1, sizeof(*mine));- if (mine == NULL) {- archive_set_error(a, ENOMEM, "No memory");- return (ARCHIVE_FATAL);- }- if (mbs_fn)- r = archive_mstring_copy_mbs(&mine->filename, filename);- else- r = archive_mstring_copy_wcs(&mine->filename, filename);- if (r < 0) {- if (errno == ENOMEM) {- archive_set_error(a, ENOMEM, "No memory");- return (ARCHIVE_FATAL);- }- if (mbs_fn)- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Can't convert '%s' to WCS",- (const char *)filename);- else- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Can't convert '%S' to MBS",- (const wchar_t *)filename);- return (ARCHIVE_FAILED);- }- mine->fd = -1;- return (archive_write_open2(a, mine,- file_open, file_write, file_close, file_free));-}--static int-file_open(struct archive *a, void *client_data)-{- int flags;- struct write_file_data *mine;- struct stat st;-#if defined(_WIN32) && !defined(__CYGWIN__)- wchar_t *fullpath;-#endif- const wchar_t *wcs;- const char *mbs;-- mine = (struct write_file_data *)client_data;- flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC;-- /*- * Open the file.- */- mbs = NULL; wcs = NULL;-#if defined(_WIN32) && !defined(__CYGWIN__)- if (archive_mstring_get_wcs(a, &mine->filename, &wcs) != 0) {- if (errno == ENOMEM)- archive_set_error(a, errno, "No memory");- else {- archive_mstring_get_mbs(a, &mine->filename, &mbs);- archive_set_error(a, errno,- "Can't convert '%s' to WCS", mbs);- }- return (ARCHIVE_FATAL);- }- fullpath = __la_win_permissive_name_w(wcs);- if (fullpath != NULL) {- mine->fd = _wopen(fullpath, flags, 0666);- free(fullpath);- } else- mine->fd = _wopen(wcs, flags, 0666);-#else- if (archive_mstring_get_mbs(a, &mine->filename, &mbs) != 0) {- if (errno == ENOMEM)- archive_set_error(a, errno, "No memory");- else {- archive_mstring_get_wcs(a, &mine->filename, &wcs);- archive_set_error(a, errno,- "Can't convert '%S' to MBS", wcs);- }- return (ARCHIVE_FATAL);- }- mine->fd = open(mbs, flags, 0666);- __archive_ensure_cloexec_flag(mine->fd);-#endif- if (mine->fd < 0) {- if (mbs != NULL)- archive_set_error(a, errno, "Failed to open '%s'", mbs);- else- archive_set_error(a, errno, "Failed to open '%S'", wcs);- return (ARCHIVE_FATAL);- }-- if (fstat(mine->fd, &st) != 0) {- if (mbs != NULL)- archive_set_error(a, errno, "Couldn't stat '%s'", mbs);- else- archive_set_error(a, errno, "Couldn't stat '%S'", wcs);- return (ARCHIVE_FATAL);- }-- /*- * Set up default last block handling.- */- if (archive_write_get_bytes_in_last_block(a) < 0) {- if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) ||- S_ISFIFO(st.st_mode))- /* Pad last block when writing to device or FIFO. */- archive_write_set_bytes_in_last_block(a, 0);- else- /* Don't pad last block otherwise. */- archive_write_set_bytes_in_last_block(a, 1);- }-- /*- * If the output file is a regular file, don't add it to- * itself. If it's a device file, it's okay to add the device- * entry to the output archive.- */- if (S_ISREG(st.st_mode))- archive_write_set_skip_file(a, st.st_dev, st.st_ino);-- return (ARCHIVE_OK);-}--static ssize_t-file_write(struct archive *a, void *client_data, const void *buff,- size_t length)-{- struct write_file_data *mine;- ssize_t bytesWritten;-- mine = (struct write_file_data *)client_data;- for (;;) {- bytesWritten = write(mine->fd, buff, length);- if (bytesWritten <= 0) {- if (errno == EINTR)- continue;- archive_set_error(a, errno, "Write error");- return (-1);- }- return (bytesWritten);- }-}--static int-file_close(struct archive *a, void *client_data)-{- struct write_file_data *mine = (struct write_file_data *)client_data;-- (void)a; /* UNUSED */-- if (mine == NULL)- return (ARCHIVE_FATAL);-- if (mine->fd >= 0)- close(mine->fd);-- return (ARCHIVE_OK);-}--static int-file_free(struct archive *a, void *client_data)-{- struct write_file_data *mine = (struct write_file_data *)client_data;-- (void)a; /* UNUSED */-- if (mine == NULL)- return (ARCHIVE_OK);-- archive_mstring_clean(&mine->filename);- free(mine);- return (ARCHIVE_OK);-}
− c/archive_write_open_memory.c
@@ -1,115 +0,0 @@-/*-- * 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: src/lib/libarchive/archive_write_open_memory.c,v 1.3 2007/01/09 08:05:56 kientzle Exp $");--#include <errno.h>-#include <stdlib.h>-#include <string.h>--#include "archive.h"--struct write_memory_data {- size_t used;- size_t size;- size_t * client_size;- unsigned char * buff;-};--static int memory_write_free(struct archive *, void *);-static int memory_write_open(struct archive *, void *);-static ssize_t memory_write(struct archive *, void *, const void *buff, size_t);--/*- * Client provides a pointer to a block of memory to receive- * the data. The 'size' param both tells us the size of the- * client buffer and lets us tell the client the final size.- */-int-archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t *used)-{- struct write_memory_data *mine;-- mine = (struct write_memory_data *)calloc(1, sizeof(*mine));- if (mine == NULL) {- archive_set_error(a, ENOMEM, "No memory");- return (ARCHIVE_FATAL);- }- mine->buff = buff;- mine->size = buffSize;- mine->client_size = used;- return (archive_write_open2(a, mine,- memory_write_open, memory_write, NULL, memory_write_free));-}--static int-memory_write_open(struct archive *a, void *client_data)-{- struct write_memory_data *mine;- mine = client_data;- mine->used = 0;- if (mine->client_size != NULL)- *mine->client_size = mine->used;- /* Disable padding if it hasn't been set explicitly. */- if (-1 == archive_write_get_bytes_in_last_block(a))- archive_write_set_bytes_in_last_block(a, 1);- return (ARCHIVE_OK);-}--/*- * Copy the data into the client buffer.- * Note that we update mine->client_size on every write.- * In particular, this means the client can follow exactly- * how much has been written into their buffer at any time.- */-static ssize_t-memory_write(struct archive *a, void *client_data, const void *buff, size_t length)-{- struct write_memory_data *mine;- mine = client_data;-- if (mine->used + length > mine->size) {- archive_set_error(a, ENOMEM, "Buffer exhausted");- return (ARCHIVE_FATAL);- }- memcpy(mine->buff + mine->used, buff, length);- mine->used += length;- if (mine->client_size != NULL)- *mine->client_size = mine->used;- return (length);-}--static int-memory_write_free(struct archive *a, void *client_data)-{- struct write_memory_data *mine;- (void)a; /* UNUSED */- mine = client_data;- if (mine == NULL)- return (ARCHIVE_OK);- free(mine);- return (ARCHIVE_OK);-}
− c/archive_write_private.h
@@ -1,166 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD: head/lib/libarchive/archive_write_private.h 201155 2009-12-29 05:20:12Z kientzle $- */--#ifndef ARCHIVE_WRITE_PRIVATE_H_INCLUDED-#define ARCHIVE_WRITE_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#ifndef __LIBARCHIVE_TEST-#error This header is only to be used internally to libarchive.-#endif-#endif--#include "archive.h"-#include "archive_string.h"-#include "archive_private.h"--#define ARCHIVE_WRITE_FILTER_STATE_NEW 1U-#define ARCHIVE_WRITE_FILTER_STATE_OPEN 2U-#define ARCHIVE_WRITE_FILTER_STATE_CLOSED 4U-#define ARCHIVE_WRITE_FILTER_STATE_FATAL 0x8000U--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 (*flush)(struct archive_write_filter *);- 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;- int state;-};--#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_nulls(struct archive_write *, size_t);-int __archive_write_filter(struct archive_write_filter *, const void *, size_t);--struct archive_write {- struct archive archive;-- /* Dev/ino of the archive being written. */- int skip_file_set;- int64_t skip_file_dev;- int64_t skip_file_ino;-- /* Utility: Pointer to a block of nulls. */- const unsigned char *nulls;- size_t null_length;-- /* Callbacks to open/read/write/close archive stream. */- archive_open_callback *client_opener;- archive_write_callback *client_writer;- archive_close_callback *client_closer;- archive_free_callback *client_freer;- void *client_data;-- /*- * Blocking information. Note that bytes_in_last_block is- * misleadingly named; I should find a better name. These- * control the final output from all compressors, including- * compression_none.- */- int bytes_per_block;- int bytes_in_last_block;-- /*- * First and last write filters in the pipeline.- */- struct archive_write_filter *filter_first;- struct archive_write_filter *filter_last;-- /*- * Pointers to format-specific functions for writing. They're- * initialized by archive_write_set_format_XXX() calls.- */- void *format_data;- const char *format_name;- int (*format_init)(struct archive_write *);- int (*format_options)(struct archive_write *,- const char *key, const char *value);- int (*format_finish_entry)(struct archive_write *);- int (*format_write_header)(struct archive_write *,- struct archive_entry *);- ssize_t (*format_write_data)(struct archive_write *,- const void *buff, size_t);- int (*format_close)(struct archive_write *);- int (*format_free)(struct archive_write *);--- /*- * Encryption passphrase.- */- char *passphrase;- archive_passphrase_callback *passphrase_callback;- void *passphrase_client_data;-};--/*- * Utility function to format a USTAR header into a buffer. If- * "strict" is set, this tries to create the absolutely most portable- * version of a ustar header. If "strict" is set to 0, then it will- * relax certain requirements.- *- * Generally, format-specific declarations don't belong in this- * header; this is a rare example of a function that is shared by- * two very similar formats (ustar and pax).- */-int-__archive_write_format_header_ustar(struct archive_write *, char buff[512],- struct archive_entry *, int tartype, int strict,- struct archive_string_conv *);--struct archive_write_program_data;-struct archive_write_program_data * __archive_write_program_allocate(const char *program_name);-int __archive_write_program_free(struct archive_write_program_data *);-int __archive_write_program_open(struct archive_write_filter *,- struct archive_write_program_data *, const char *);-int __archive_write_program_close(struct archive_write_filter *,- struct archive_write_program_data *);-int __archive_write_program_write(struct archive_write_filter *,- struct archive_write_program_data *, const void *, size_t);--/*- * Get a encryption passphrase.- */-const char * __archive_write_get_passphrase(struct archive_write *a);-#endif
− c/archive_write_set_format.c
@@ -1,125 +0,0 @@-/*-- * 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_format.c 201168 2009-12-29 06:15:32Z kientzle $");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif--#include "archive.h"-#include "archive_private.h"-#include "archive_write_set_format_private.h"--/* A table that maps format codes to functions. */-static const-struct { int code; int (*setter)(struct archive *); } codes[] =-{- { ARCHIVE_FORMAT_7ZIP, archive_write_set_format_7zip },- { ARCHIVE_FORMAT_CPIO, archive_write_set_format_cpio },- { ARCHIVE_FORMAT_CPIO_BIN_LE, archive_write_set_format_cpio_bin },- { ARCHIVE_FORMAT_CPIO_PWB, archive_write_set_format_cpio_pwb },- { ARCHIVE_FORMAT_CPIO_POSIX, archive_write_set_format_cpio_odc },- { ARCHIVE_FORMAT_CPIO_SVR4_NOCRC, archive_write_set_format_cpio_newc },- { ARCHIVE_FORMAT_ISO9660, archive_write_set_format_iso9660 },- { ARCHIVE_FORMAT_MTREE, archive_write_set_format_mtree },- { ARCHIVE_FORMAT_RAW, archive_write_set_format_raw },- { ARCHIVE_FORMAT_SHAR, archive_write_set_format_shar },- { ARCHIVE_FORMAT_SHAR_BASE, archive_write_set_format_shar },- { ARCHIVE_FORMAT_SHAR_DUMP, archive_write_set_format_shar_dump },- { ARCHIVE_FORMAT_TAR, archive_write_set_format_pax_restricted },- { ARCHIVE_FORMAT_TAR_GNUTAR, archive_write_set_format_gnutar },- { ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE, archive_write_set_format_pax },- { ARCHIVE_FORMAT_TAR_PAX_RESTRICTED,- archive_write_set_format_pax_restricted },- { ARCHIVE_FORMAT_TAR_USTAR, archive_write_set_format_ustar },- { ARCHIVE_FORMAT_WARC, archive_write_set_format_warc },- { ARCHIVE_FORMAT_XAR, archive_write_set_format_xar },- { ARCHIVE_FORMAT_ZIP, archive_write_set_format_zip },- { 0, NULL }-};--int-archive_write_set_format(struct archive *a, int code)-{- int i;-- for (i = 0; codes[i].code != 0; i++) {- if (code == codes[i].code)- return ((codes[i].setter)(a));- }-- archive_set_error(a, EINVAL, "No such format");- return (ARCHIVE_FATAL);-}--void-__archive_write_entry_filetype_unsupported(struct archive *a,- struct archive_entry *entry, const char *format)-{- const char *name = NULL;-- switch (archive_entry_filetype(entry)) {- /*- * All formats should be able to archive regular files (AE_IFREG)- */- case AE_IFDIR:- name = "directories";- break;- case AE_IFLNK:- name = "symbolic links";- break;- case AE_IFCHR:- name = "character devices";- break;- case AE_IFBLK:- name = "block devices";- break;- case AE_IFIFO:- name = "named pipes";- break;- case AE_IFSOCK:- name = "sockets";- break;- default:- break;- }-- if (name != NULL) {- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,- "%s: %s format cannot archive %s",- archive_entry_pathname(entry), format, name);- } else {- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,- "%s: %s format cannot archive files with mode 0%lo",- archive_entry_pathname(entry), format,- (unsigned long)archive_entry_mode(entry));- }-}
− c/archive_write_set_format_7zip.c
@@ -1,2322 +0,0 @@-/*-- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#include <stdlib.h>-#ifdef HAVE_BZLIB_H-#include <bzlib.h>-#endif-#if HAVE_LZMA_H-#include <lzma.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif--#include "archive.h"-#ifndef HAVE_ZLIB_H-#include "archive_crc32.h"-#endif-#include "archive_endian.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_ppmd7_private.h"-#include "archive_private.h"-#include "archive_rb.h"-#include "archive_string.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--/*- * Codec ID- */-#define _7Z_COPY 0-#define _7Z_LZMA1 0x030101-#define _7Z_LZMA2 0x21-#define _7Z_DEFLATE 0x040108-#define _7Z_BZIP2 0x040202-#define _7Z_PPMD 0x030401--/*- * 7-Zip header property IDs.- */-#define kEnd 0x00-#define kHeader 0x01-#define kArchiveProperties 0x02-#define kAdditionalStreamsInfo 0x03-#define kMainStreamsInfo 0x04-#define kFilesInfo 0x05-#define kPackInfo 0x06-#define kUnPackInfo 0x07-#define kSubStreamsInfo 0x08-#define kSize 0x09-#define kCRC 0x0A-#define kFolder 0x0B-#define kCodersUnPackSize 0x0C-#define kNumUnPackStream 0x0D-#define kEmptyStream 0x0E-#define kEmptyFile 0x0F-#define kAnti 0x10-#define kName 0x11-#define kCTime 0x12-#define kATime 0x13-#define kMTime 0x14-#define kAttributes 0x15-#define kEncodedHeader 0x17--enum la_zaction {- ARCHIVE_Z_FINISH,- ARCHIVE_Z_RUN-};--/*- * A stream object of universal compressor.- */-struct la_zstream {- const uint8_t *next_in;- size_t avail_in;- uint64_t total_in;-- uint8_t *next_out;- size_t avail_out;- uint64_t total_out;-- uint32_t prop_size;- uint8_t *props;-- int valid;- void *real_stream;- int (*code) (struct archive *a,- struct la_zstream *lastrm,- enum la_zaction action);- int (*end)(struct archive *a,- struct la_zstream *lastrm);-};--#define PPMD7_DEFAULT_ORDER 6-#define PPMD7_DEFAULT_MEM_SIZE (1 << 24)--struct ppmd_stream {- int stat;- CPpmd7 ppmd7_context;- CPpmd7z_RangeEnc range_enc;- IByteOut byteout;- uint8_t *buff;- uint8_t *buff_ptr;- uint8_t *buff_end;- size_t buff_bytes;-};--struct coder {- unsigned codec;- size_t prop_size;- uint8_t *props;-};--struct file {- struct archive_rb_node rbnode;-- struct file *next;- unsigned name_len;- uint8_t *utf16name;/* UTF16-LE name. */- uint64_t size;- unsigned flg;-#define MTIME_IS_SET (1<<0)-#define ATIME_IS_SET (1<<1)-#define CTIME_IS_SET (1<<2)-#define CRC32_IS_SET (1<<3)-#define HAS_STREAM (1<<4)-- struct {- time_t time;- long time_ns;- } times[3];-#define MTIME 0-#define ATIME 1-#define CTIME 2-- mode_t mode;- uint32_t crc32;-- unsigned dir:1;-};--struct _7zip {- int temp_fd;- uint64_t temp_offset;-- struct file *cur_file;- size_t total_number_entry;- size_t total_number_nonempty_entry;- size_t total_number_empty_entry;- size_t total_number_dir_entry;- size_t total_bytes_entry_name;- size_t total_number_time_defined[3];- uint64_t total_bytes_compressed;- uint64_t total_bytes_uncompressed;- uint64_t entry_bytes_remaining;- uint32_t entry_crc32;- uint32_t precode_crc32;- uint32_t encoded_crc32;- int crc32flg;-#define PRECODE_CRC32 1-#define ENCODED_CRC32 2-- unsigned opt_compression;- int opt_compression_level;-- struct la_zstream stream;- struct coder coder;-- struct archive_string_conv *sconv;-- /*- * Compressed data buffer.- */- unsigned char wbuff[512 * 20 * 6];- size_t wbuff_remaining;-- /*- * The list of the file entries which has its contents is used to- * manage struct file objects.- * We use 'next' (a member of struct file) to chain.- */- struct {- struct file *first;- struct file **last;- } file_list, empty_list;- struct archive_rb_tree rbtree;/* for empty files */-};--static int _7z_options(struct archive_write *,- const char *, const char *);-static int _7z_write_header(struct archive_write *,- struct archive_entry *);-static ssize_t _7z_write_data(struct archive_write *,- const void *, size_t);-static int _7z_finish_entry(struct archive_write *);-static int _7z_close(struct archive_write *);-static int _7z_free(struct archive_write *);-static int file_cmp_node(const struct archive_rb_node *,- const struct archive_rb_node *);-static int file_cmp_key(const struct archive_rb_node *, const void *);-static int file_new(struct archive_write *a, struct archive_entry *,- struct file **);-static void file_free(struct file *);-static void file_register(struct _7zip *, struct file *);-static void file_register_empty(struct _7zip *, struct file *);-static void file_init_register(struct _7zip *);-static void file_init_register_empty(struct _7zip *);-static void file_free_register(struct _7zip *);-static ssize_t compress_out(struct archive_write *, const void *, size_t ,- enum la_zaction);-static int compression_init_encoder_copy(struct archive *,- struct la_zstream *);-static int compression_code_copy(struct archive *,- struct la_zstream *, enum la_zaction);-static int compression_end_copy(struct archive *, struct la_zstream *);-static int compression_init_encoder_deflate(struct archive *,- struct la_zstream *, int, int);-#ifdef HAVE_ZLIB_H-static int compression_code_deflate(struct archive *,- struct la_zstream *, enum la_zaction);-static int compression_end_deflate(struct archive *, struct la_zstream *);-#endif-static int compression_init_encoder_bzip2(struct archive *,- struct la_zstream *, int);-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)-static int compression_code_bzip2(struct archive *,- struct la_zstream *, enum la_zaction);-static int compression_end_bzip2(struct archive *, struct la_zstream *);-#endif-static int compression_init_encoder_lzma1(struct archive *,- struct la_zstream *, int);-static int compression_init_encoder_lzma2(struct archive *,- struct la_zstream *, int);-#if defined(HAVE_LZMA_H)-static int compression_code_lzma(struct archive *,- struct la_zstream *, enum la_zaction);-static int compression_end_lzma(struct archive *, struct la_zstream *);-#endif-static int compression_init_encoder_ppmd(struct archive *,- struct la_zstream *, unsigned, uint32_t);-static int compression_code_ppmd(struct archive *,- struct la_zstream *, enum la_zaction);-static int compression_end_ppmd(struct archive *, struct la_zstream *);-static int _7z_compression_init_encoder(struct archive_write *, unsigned,- int);-static int compression_code(struct archive *,- struct la_zstream *, enum la_zaction);-static int compression_end(struct archive *,- struct la_zstream *);-static int enc_uint64(struct archive_write *, uint64_t);-static int make_header(struct archive_write *, uint64_t, uint64_t,- uint64_t, int, struct coder *);-static int make_streamsInfo(struct archive_write *, uint64_t, uint64_t,- uint64_t, int, struct coder *, int, uint32_t);--int-archive_write_set_format_7zip(struct archive *_a)-{- static const struct archive_rb_tree_ops rb_ops = {- file_cmp_node, file_cmp_key- };- struct archive_write *a = (struct archive_write *)_a;- struct _7zip *zip;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_7zip");-- /* If another format was already registered, unregister it. */- if (a->format_free != NULL)- (a->format_free)(a);-- zip = calloc(1, sizeof(*zip));- if (zip == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate 7-Zip data");- return (ARCHIVE_FATAL);- }- zip->temp_fd = -1;- __archive_rb_tree_init(&(zip->rbtree), &rb_ops);- file_init_register(zip);- file_init_register_empty(zip);-- /* Set default compression type and its level. */-#if HAVE_LZMA_H- zip->opt_compression = _7Z_LZMA1;-#elif defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- zip->opt_compression = _7Z_BZIP2;-#elif defined(HAVE_ZLIB_H)- zip->opt_compression = _7Z_DEFLATE;-#else- zip->opt_compression = _7Z_COPY;-#endif- zip->opt_compression_level = 6;-- a->format_data = zip;-- a->format_name = "7zip";- a->format_options = _7z_options;- a->format_write_header = _7z_write_header;- a->format_write_data = _7z_write_data;- a->format_finish_entry = _7z_finish_entry;- a->format_close = _7z_close;- a->format_free = _7z_free;- a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;- a->archive.archive_format_name = "7zip";-- return (ARCHIVE_OK);-}--static int-_7z_options(struct archive_write *a, const char *key, const char *value)-{- struct _7zip *zip;-- zip = (struct _7zip *)a->format_data;-- if (strcmp(key, "compression") == 0) {- const char *name = NULL;-- if (value == NULL || strcmp(value, "copy") == 0 ||- strcmp(value, "COPY") == 0 ||- strcmp(value, "store") == 0 ||- strcmp(value, "STORE") == 0)- zip->opt_compression = _7Z_COPY;- else if (strcmp(value, "deflate") == 0 ||- strcmp(value, "DEFLATE") == 0)-#if HAVE_ZLIB_H- zip->opt_compression = _7Z_DEFLATE;-#else- name = "deflate";-#endif- else if (strcmp(value, "bzip2") == 0 ||- strcmp(value, "BZIP2") == 0)-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- zip->opt_compression = _7Z_BZIP2;-#else- name = "bzip2";-#endif- else if (strcmp(value, "lzma1") == 0 ||- strcmp(value, "LZMA1") == 0)-#if HAVE_LZMA_H- zip->opt_compression = _7Z_LZMA1;-#else- name = "lzma1";-#endif- else if (strcmp(value, "lzma2") == 0 ||- strcmp(value, "LZMA2") == 0)-#if HAVE_LZMA_H- zip->opt_compression = _7Z_LZMA2;-#else- name = "lzma2";-#endif- else if (strcmp(value, "ppmd") == 0 ||- strcmp(value, "PPMD") == 0 ||- strcmp(value, "PPMd") == 0)- zip->opt_compression = _7Z_PPMD;- else {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Unknown compression name: `%s'",- value);- return (ARCHIVE_FAILED);- }- if (name != NULL) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "`%s' compression not supported "- "on this platform",- name);- return (ARCHIVE_FAILED);- }- return (ARCHIVE_OK);- }- if (strcmp(key, "compression-level") == 0) {- if (value == NULL ||- !(value[0] >= '0' && value[0] <= '9') ||- value[1] != '\0') {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Illegal value `%s'",- value);- return (ARCHIVE_FAILED);- }- zip->opt_compression_level = value[0] - '0';- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-_7z_write_header(struct archive_write *a, struct archive_entry *entry)-{- struct _7zip *zip;- struct file *file;- int r;-- zip = (struct _7zip *)a->format_data;- zip->cur_file = NULL;- zip->entry_bytes_remaining = 0;-- if (zip->sconv == NULL) {- zip->sconv = archive_string_conversion_to_charset(- &a->archive, "UTF-16LE", 1);- if (zip->sconv == NULL)- return (ARCHIVE_FATAL);- }-- r = file_new(a, entry, &file);- if (r < ARCHIVE_WARN) {- if (file != NULL)- file_free(file);- return (r);- }- if (file->size == 0 && file->dir) {- if (!__archive_rb_tree_insert_node(&(zip->rbtree),- (struct archive_rb_node *)file)) {- /* We have already had the same file. */- file_free(file);- return (ARCHIVE_OK);- }- }-- if (file->flg & MTIME_IS_SET)- zip->total_number_time_defined[MTIME]++;- if (file->flg & CTIME_IS_SET)- zip->total_number_time_defined[CTIME]++;- if (file->flg & ATIME_IS_SET)- zip->total_number_time_defined[ATIME]++;-- zip->total_number_entry++;- zip->total_bytes_entry_name += file->name_len + 2;- if (file->size == 0) {- /* Count up the number of empty files. */- zip->total_number_empty_entry++;- if (file->dir)- zip->total_number_dir_entry++;- else- file_register_empty(zip, file);- return (r);- }-- /*- * Init compression.- */- if ((zip->total_number_entry - zip->total_number_empty_entry) == 1) {- r = _7z_compression_init_encoder(a, zip->opt_compression,- zip->opt_compression_level);- if (r < 0) {- file_free(file);- return (ARCHIVE_FATAL);- }- }-- /* Register a non-empty file. */- file_register(zip, file);-- /*- * Set the current file to cur_file to read its contents.- */- zip->cur_file = file;--- /* Save a offset of current file in temporary file. */- zip->entry_bytes_remaining = file->size;- zip->entry_crc32 = 0;-- /*- * Store a symbolic link name as file contents.- */- if (archive_entry_filetype(entry) == AE_IFLNK) {- ssize_t bytes;- const void *p = (const void *)archive_entry_symlink(entry);- bytes = compress_out(a, p, (size_t)file->size, ARCHIVE_Z_RUN);- if (bytes < 0)- return ((int)bytes);- zip->entry_crc32 = crc32(zip->entry_crc32, p, (unsigned)bytes);- zip->entry_bytes_remaining -= bytes;- }-- return (r);-}--/*- * Write data to a temporary file.- */-static int-write_to_temp(struct archive_write *a, const void *buff, size_t s)-{- struct _7zip *zip;- const unsigned char *p;- ssize_t ws;-- zip = (struct _7zip *)a->format_data;-- /*- * Open a temporary file.- */- if (zip->temp_fd == -1) {- zip->temp_offset = 0;- zip->temp_fd = __archive_mktemp(NULL);- if (zip->temp_fd < 0) {- archive_set_error(&a->archive, errno,- "Couldn't create temporary file");- return (ARCHIVE_FATAL);- }- }-- p = (const unsigned char *)buff;- while (s) {- ws = write(zip->temp_fd, p, s);- if (ws < 0) {- archive_set_error(&(a->archive), errno,- "fwrite function failed");- return (ARCHIVE_FATAL);- }- s -= ws;- p += ws;- zip->temp_offset += ws;- }- return (ARCHIVE_OK);-}--static ssize_t-compress_out(struct archive_write *a, const void *buff, size_t s,- enum la_zaction run)-{- struct _7zip *zip = (struct _7zip *)a->format_data;- int r;-- if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)- return (0);-- if ((zip->crc32flg & PRECODE_CRC32) && s)- zip->precode_crc32 = crc32(zip->precode_crc32, buff,- (unsigned)s);- zip->stream.next_in = (const unsigned char *)buff;- zip->stream.avail_in = s;- for (;;) {- /* Compress file data. */- r = compression_code(&(a->archive), &(zip->stream), run);- if (r != ARCHIVE_OK && r != ARCHIVE_EOF)- return (ARCHIVE_FATAL);- if (zip->stream.avail_out == 0) {- if (write_to_temp(a, zip->wbuff, sizeof(zip->wbuff))- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- zip->stream.next_out = zip->wbuff;- zip->stream.avail_out = sizeof(zip->wbuff);- if (zip->crc32flg & ENCODED_CRC32)- zip->encoded_crc32 = crc32(zip->encoded_crc32,- zip->wbuff, sizeof(zip->wbuff));- if (run == ARCHIVE_Z_FINISH && r != ARCHIVE_EOF)- continue;- }- if (zip->stream.avail_in == 0)- break;- }- if (run == ARCHIVE_Z_FINISH) {- uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out;- if (write_to_temp(a, zip->wbuff, (size_t)bytes) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- if ((zip->crc32flg & ENCODED_CRC32) && bytes)- zip->encoded_crc32 = crc32(zip->encoded_crc32,- zip->wbuff, (unsigned)bytes);- }-- return (s);-}--static ssize_t-_7z_write_data(struct archive_write *a, const void *buff, size_t s)-{- struct _7zip *zip;- ssize_t bytes;-- zip = (struct _7zip *)a->format_data;-- if (s > zip->entry_bytes_remaining)- s = (size_t)zip->entry_bytes_remaining;- if (s == 0 || zip->cur_file == NULL)- return (0);- bytes = compress_out(a, buff, s, ARCHIVE_Z_RUN);- if (bytes < 0)- return (bytes);- zip->entry_crc32 = crc32(zip->entry_crc32, buff, (unsigned)bytes);- zip->entry_bytes_remaining -= bytes;- return (bytes);-}--static int-_7z_finish_entry(struct archive_write *a)-{- struct _7zip *zip;- size_t s;- ssize_t r;-- zip = (struct _7zip *)a->format_data;- if (zip->cur_file == NULL)- return (ARCHIVE_OK);-- while (zip->entry_bytes_remaining > 0) {- s = (size_t)zip->entry_bytes_remaining;- if (s > a->null_length)- s = a->null_length;- r = _7z_write_data(a, a->nulls, s);- if (r < 0)- return ((int)r);- }- zip->total_bytes_compressed += zip->stream.total_in;- zip->total_bytes_uncompressed += zip->stream.total_out;- zip->cur_file->crc32 = zip->entry_crc32;- zip->cur_file = NULL;-- return (ARCHIVE_OK);-}--static int-flush_wbuff(struct archive_write *a)-{- struct _7zip *zip;- int r;- size_t s;-- zip = (struct _7zip *)a->format_data;- s = sizeof(zip->wbuff) - zip->wbuff_remaining;- r = __archive_write_output(a, zip->wbuff, s);- if (r != ARCHIVE_OK)- return (r);- zip->wbuff_remaining = sizeof(zip->wbuff);- return (r);-}--static int-copy_out(struct archive_write *a, uint64_t offset, uint64_t length)-{- struct _7zip *zip;- int r;-- zip = (struct _7zip *)a->format_data;- if (zip->temp_offset > 0 &&- lseek(zip->temp_fd, offset, SEEK_SET) < 0) {- archive_set_error(&(a->archive), errno, "lseek failed");- return (ARCHIVE_FATAL);- }- while (length) {- size_t rsize;- ssize_t rs;- unsigned char *wb;-- if (length > zip->wbuff_remaining)- rsize = zip->wbuff_remaining;- else- rsize = (size_t)length;- wb = zip->wbuff + (sizeof(zip->wbuff) - zip->wbuff_remaining);- rs = read(zip->temp_fd, wb, rsize);- if (rs < 0) {- archive_set_error(&(a->archive), errno,- "Can't read temporary file(%jd)",- (intmax_t)rs);- return (ARCHIVE_FATAL);- }- if (rs == 0) {- archive_set_error(&(a->archive), 0,- "Truncated 7-Zip archive");- return (ARCHIVE_FATAL);- }- zip->wbuff_remaining -= rs;- length -= rs;- if (zip->wbuff_remaining == 0) {- r = flush_wbuff(a);- if (r != ARCHIVE_OK)- return (r);- }- }- return (ARCHIVE_OK);-}--static int-_7z_close(struct archive_write *a)-{- struct _7zip *zip;- unsigned char *wb;- uint64_t header_offset, header_size, header_unpacksize;- uint64_t length;- uint32_t header_crc32;- int r;-- zip = (struct _7zip *)a->format_data;-- if (zip->total_number_entry > 0) {- struct archive_rb_node *n;- uint64_t data_offset, data_size, data_unpacksize;- unsigned header_compression;-- r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);- if (r < 0)- return (r);- data_offset = 0;- data_size = zip->stream.total_out;- data_unpacksize = zip->stream.total_in;- zip->coder.codec = zip->opt_compression;- zip->coder.prop_size = zip->stream.prop_size;- zip->coder.props = zip->stream.props;- zip->stream.prop_size = 0;- zip->stream.props = NULL;- zip->total_number_nonempty_entry =- zip->total_number_entry - zip->total_number_empty_entry;-- /* Connect an empty file list. */- if (zip->empty_list.first != NULL) {- *zip->file_list.last = zip->empty_list.first;- zip->file_list.last = zip->empty_list.last;- }- /* Connect a directory file list. */- ARCHIVE_RB_TREE_FOREACH(n, &(zip->rbtree)) {- file_register(zip, (struct file *)n);- }-- /*- * NOTE: 7z command supports just LZMA1, LZMA2 and COPY for- * the compression type for encoding the header.- */-#if HAVE_LZMA_H- header_compression = _7Z_LZMA1;- if(zip->opt_compression == _7Z_LZMA2 ||- zip->opt_compression == _7Z_COPY)- header_compression = zip->opt_compression;-- /* If the stored file is only one, do not encode the header.- * This is the same way 7z command does. */- if (zip->total_number_entry == 1)- header_compression = _7Z_COPY;-#else- header_compression = _7Z_COPY;-#endif- r = _7z_compression_init_encoder(a, header_compression,- zip->opt_compression_level);- if (r < 0)- return (r);- zip->crc32flg = PRECODE_CRC32;- zip->precode_crc32 = 0;- r = make_header(a, data_offset, data_size, data_unpacksize,- 1, &(zip->coder));- if (r < 0)- return (r);- r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);- if (r < 0)- return (r);- header_offset = data_offset + data_size;- header_size = zip->stream.total_out;- header_crc32 = zip->precode_crc32;- header_unpacksize = zip->stream.total_in;-- if (header_compression != _7Z_COPY) {- /*- * Encode the header in order to reduce the size- * of the archive.- */- free(zip->coder.props);- zip->coder.codec = header_compression;- zip->coder.prop_size = zip->stream.prop_size;- zip->coder.props = zip->stream.props;- zip->stream.prop_size = 0;- zip->stream.props = NULL;-- r = _7z_compression_init_encoder(a, _7Z_COPY, 0);- if (r < 0)- return (r);- zip->crc32flg = ENCODED_CRC32;- zip->encoded_crc32 = 0;-- /*- * Make EncodedHeader.- */- r = enc_uint64(a, kEncodedHeader);- if (r < 0)- return (r);- r = make_streamsInfo(a, header_offset, header_size,- header_unpacksize, 1, &(zip->coder), 0,- header_crc32);- if (r < 0)- return (r);- r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);- if (r < 0)- return (r);- header_offset = header_offset + header_size;- header_size = zip->stream.total_out;- header_crc32 = zip->encoded_crc32;- }- zip->crc32flg = 0;- } else {- header_offset = header_size = 0;- header_crc32 = 0;- }- - length = zip->temp_offset;-- /*- * Make the zip header on wbuff(write buffer).- */- wb = zip->wbuff;- zip->wbuff_remaining = sizeof(zip->wbuff);- memcpy(&wb[0], "7z\xBC\xAF\x27\x1C", 6);- wb[6] = 0;/* Major version. */- wb[7] = 3;/* Minor version. */- archive_le64enc(&wb[12], header_offset);/* Next Header Offset */- archive_le64enc(&wb[20], header_size);/* Next Header Size */- archive_le32enc(&wb[28], header_crc32);/* Next Header CRC */- archive_le32enc(&wb[8], crc32(0, &wb[12], 20));/* Start Header CRC */- zip->wbuff_remaining -= 32;-- /*- * Read all file contents and an encoded header from the temporary- * file and write out it.- */- r = copy_out(a, 0, length);- if (r != ARCHIVE_OK)- return (r);- r = flush_wbuff(a);- return (r);-}--/*- * Encode 64 bits value into 7-Zip's encoded UINT64 value.- */-static int-enc_uint64(struct archive_write *a, uint64_t val)-{- unsigned mask = 0x80;- uint8_t numdata[9];- int i;-- numdata[0] = 0;- for (i = 1; i < (int)sizeof(numdata); i++) {- if (val < mask) {- numdata[0] |= (uint8_t)val;- break;- }- numdata[i] = (uint8_t)val;- val >>= 8;- numdata[0] |= mask;- mask >>= 1;- }- return ((int)compress_out(a, numdata, i, ARCHIVE_Z_RUN));-}--static int-make_substreamsInfo(struct archive_write *a, struct coder *coders)-{- struct _7zip *zip = (struct _7zip *)a->format_data;- struct file *file;- int r;-- /*- * Make SubStreamsInfo.- */- r = enc_uint64(a, kSubStreamsInfo);- if (r < 0)- return (r);-- if (zip->total_number_nonempty_entry > 1 && coders->codec != _7Z_COPY) {- /*- * Make NumUnPackStream.- */- r = enc_uint64(a, kNumUnPackStream);- if (r < 0)- return (r);-- /* Write numUnpackStreams */- r = enc_uint64(a, zip->total_number_nonempty_entry);- if (r < 0)- return (r);-- /*- * Make kSize.- */- r = enc_uint64(a, kSize);- if (r < 0)- return (r);- file = zip->file_list.first;- for (;file != NULL; file = file->next) {- if (file->next == NULL ||- file->next->size == 0)- break;- r = enc_uint64(a, file->size);- if (r < 0)- return (r);- }- }-- /*- * Make CRC.- */- r = enc_uint64(a, kCRC);- if (r < 0)- return (r);--- /* All are defined */- r = enc_uint64(a, 1);- if (r < 0)- return (r);- file = zip->file_list.first;- for (;file != NULL; file = file->next) {- uint8_t crc[4];- if (file->size == 0)- break;- archive_le32enc(crc, file->crc32);- r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- }-- /* Write End. */- r = enc_uint64(a, kEnd);- if (r < 0)- return (r);- return (ARCHIVE_OK);-}--static int-make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,- uint64_t unpack_size, int num_coder, struct coder *coders, int substrm,- uint32_t header_crc)-{- struct _7zip *zip = (struct _7zip *)a->format_data;- uint8_t codec_buff[8];- int numFolders, fi;- int codec_size;- int i, r;-- if (coders->codec == _7Z_COPY)- numFolders = (int)zip->total_number_nonempty_entry;- else- numFolders = 1;-- /*- * Make PackInfo.- */- r = enc_uint64(a, kPackInfo);- if (r < 0)- return (r);-- /* Write PackPos. */- r = enc_uint64(a, offset);- if (r < 0)- return (r);-- /* Write NumPackStreams. */- r = enc_uint64(a, numFolders);- if (r < 0)- return (r);-- /* Make Size. */- r = enc_uint64(a, kSize);- if (r < 0)- return (r);-- if (numFolders > 1) {- struct file *file = zip->file_list.first;- for (;file != NULL; file = file->next) {- if (file->size == 0)- break;- r = enc_uint64(a, file->size);- if (r < 0)- return (r);- }- } else {- /* Write size. */- r = enc_uint64(a, pack_size);- if (r < 0)- return (r);- }-- r = enc_uint64(a, kEnd);- if (r < 0)- return (r);-- /*- * Make UnPackInfo.- */- r = enc_uint64(a, kUnPackInfo);- if (r < 0)- return (r);-- /*- * Make Folder.- */- r = enc_uint64(a, kFolder);- if (r < 0)- return (r);-- /* Write NumFolders. */- r = enc_uint64(a, numFolders);- if (r < 0)- return (r);-- /* Write External. */- r = enc_uint64(a, 0);- if (r < 0)- return (r);-- for (fi = 0; fi < numFolders; fi++) {- /* Write NumCoders. */- r = enc_uint64(a, num_coder);- if (r < 0)- return (r);-- for (i = 0; i < num_coder; i++) {- unsigned codec_id = coders[i].codec;-- /* Write Codec flag. */- archive_be64enc(codec_buff, codec_id);- for (codec_size = 8; codec_size > 0; codec_size--) {- if (codec_buff[8 - codec_size])- break;- }- if (codec_size == 0)- codec_size = 1;- if (coders[i].prop_size)- r = enc_uint64(a, codec_size | 0x20);- else- r = enc_uint64(a, codec_size);- if (r < 0)- return (r);-- /* Write Codec ID. */- codec_size &= 0x0f;- r = (int)compress_out(a, &codec_buff[8-codec_size],- codec_size, ARCHIVE_Z_RUN);- if (r < 0)- return (r);-- if (coders[i].prop_size) {- /* Write Codec property size. */- r = enc_uint64(a, coders[i].prop_size);- if (r < 0)- return (r);-- /* Write Codec properties. */- r = (int)compress_out(a, coders[i].props,- coders[i].prop_size, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- }- }- }-- /*- * Make CodersUnPackSize.- */- r = enc_uint64(a, kCodersUnPackSize);- if (r < 0)- return (r);-- if (numFolders > 1) {- struct file *file = zip->file_list.first;- for (;file != NULL; file = file->next) {- if (file->size == 0)- break;- r = enc_uint64(a, file->size);- if (r < 0)- return (r);- }-- } else {- /* Write UnPackSize. */- r = enc_uint64(a, unpack_size);- if (r < 0)- return (r);- }-- if (!substrm) {- uint8_t crc[4];- /*- * Make CRC.- */- r = enc_uint64(a, kCRC);- if (r < 0)- return (r);-- /* All are defined */- r = enc_uint64(a, 1);- if (r < 0)- return (r);- archive_le32enc(crc, header_crc);- r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- }-- /* Write End. */- r = enc_uint64(a, kEnd);- if (r < 0)- return (r);-- if (substrm) {- /*- * Make SubStreamsInfo.- */- r = make_substreamsInfo(a, coders);- if (r < 0)- return (r);- }--- /* Write End. */- r = enc_uint64(a, kEnd);- if (r < 0)- return (r);-- return (ARCHIVE_OK);-}---#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)-static uint64_t-utcToFiletime(time_t t, long ns)-{- uint64_t fileTime;-- fileTime = t;- fileTime *= 10000000;- fileTime += ns / 100;- fileTime += EPOC_TIME;- return (fileTime);-}--static int-make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)-{- uint8_t filetime[8];- struct _7zip *zip = (struct _7zip *)a->format_data;- struct file *file;- int r;- uint8_t b, mask;-- /*- * Make Time Bools.- */- if (zip->total_number_time_defined[ti] == zip->total_number_entry) {- /* Write Time Type. */- r = enc_uint64(a, type);- if (r < 0)- return (r);- /* Write EmptyStream Size. */- r = enc_uint64(a, 2 + zip->total_number_entry * 8);- if (r < 0)- return (r);- /* All are defined. */- r = enc_uint64(a, 1);- if (r < 0)- return (r);- } else {- if (zip->total_number_time_defined[ti] == 0)- return (ARCHIVE_OK);-- /* Write Time Type. */- r = enc_uint64(a, type);- if (r < 0)- return (r);- /* Write EmptyStream Size. */- r = enc_uint64(a, 2 + ((zip->total_number_entry + 7) >> 3)- + zip->total_number_time_defined[ti] * 8);- if (r < 0)- return (r);-- /* All are not defined. */- r = enc_uint64(a, 0);- if (r < 0)- return (r);-- b = 0;- mask = 0x80;- file = zip->file_list.first;- for (;file != NULL; file = file->next) {- if (file->flg & flg)- b |= mask;- mask >>= 1;- if (mask == 0) {- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- mask = 0x80;- b = 0;- }- }- if (mask != 0x80) {- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- }- }-- /* External. */- r = enc_uint64(a, 0);- if (r < 0)- return (r);--- /*- * Make Times.- */- file = zip->file_list.first;- for (;file != NULL; file = file->next) {- if ((file->flg & flg) == 0)- continue;- archive_le64enc(filetime, utcToFiletime(file->times[ti].time,- file->times[ti].time_ns));- r = (int)compress_out(a, filetime, 8, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- }-- return (ARCHIVE_OK);-}--static int-make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,- uint64_t unpack_size, int codernum, struct coder *coders)-{- struct _7zip *zip = (struct _7zip *)a->format_data;- struct file *file;- int r;- uint8_t b, mask;-- /*- * Make FilesInfo.- */- r = enc_uint64(a, kHeader);- if (r < 0)- return (r);-- /*- * If there are empty files only, do not write MainStreamInfo.- */- if (zip->total_number_nonempty_entry) {- /*- * Make MainStreamInfo.- */- r = enc_uint64(a, kMainStreamsInfo);- if (r < 0)- return (r);- r = make_streamsInfo(a, offset, pack_size, unpack_size,- codernum, coders, 1, 0);- if (r < 0)- return (r);- }-- /*- * Make FilesInfo.- */- r = enc_uint64(a, kFilesInfo);- if (r < 0)- return (r);-- /* Write numFiles. */- r = enc_uint64(a, zip->total_number_entry);- if (r < 0)- return (r);-- if (zip->total_number_empty_entry > 0) {- /* Make EmptyStream. */- r = enc_uint64(a, kEmptyStream);- if (r < 0)- return (r);-- /* Write EmptyStream Size. */- r = enc_uint64(a, (zip->total_number_entry+7)>>3);- if (r < 0)- return (r);-- b = 0;- mask = 0x80;- file = zip->file_list.first;- for (;file != NULL; file = file->next) {- if (file->size == 0)- b |= mask;- mask >>= 1;- if (mask == 0) {- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- mask = 0x80;- b = 0;- }- }- if (mask != 0x80) {- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- }- }-- if (zip->total_number_empty_entry > zip->total_number_dir_entry) {- /* Make EmptyFile. */- r = enc_uint64(a, kEmptyFile);- if (r < 0)- return (r);-- /* Write EmptyFile Size. */- r = enc_uint64(a, (zip->total_number_empty_entry + 7) >> 3);- if (r < 0)- return (r);-- b = 0;- mask = 0x80;- file = zip->file_list.first;- for (;file != NULL; file = file->next) {- if (file->size)- continue;- if (!file->dir)- b |= mask;- mask >>= 1;- if (mask == 0) {- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- mask = 0x80;- b = 0;- }- }- if (mask != 0x80) {- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- }- }-- /* Make Name. */- r = enc_uint64(a, kName);- if (r < 0)- return (r);-- /* Write Name size. */- r = enc_uint64(a, zip->total_bytes_entry_name+1);- if (r < 0)- return (r);-- /* Write dmy byte. */- r = enc_uint64(a, 0);- if (r < 0)- return (r);-- file = zip->file_list.first;- for (;file != NULL; file = file->next) {- r = (int)compress_out(a, file->utf16name, file->name_len+2,- ARCHIVE_Z_RUN);- if (r < 0)- return (r);- }-- /* Make MTime. */- r = make_time(a, kMTime, MTIME_IS_SET, MTIME);- if (r < 0)- return (r);-- /* Make CTime. */- r = make_time(a, kCTime, CTIME_IS_SET, CTIME);- if (r < 0)- return (r);-- /* Make ATime. */- r = make_time(a, kATime, ATIME_IS_SET, ATIME);- if (r < 0)- return (r);-- /* Make Attributes. */- r = enc_uint64(a, kAttributes);- if (r < 0)- return (r);-- /* Write Attributes size. */- r = enc_uint64(a, 2 + zip->total_number_entry * 4);- if (r < 0)- return (r);-- /* Write "All Are Defined". */- r = enc_uint64(a, 1);- if (r < 0)- return (r);-- /* Write dmy byte. */- r = enc_uint64(a, 0);- if (r < 0)- return (r);-- file = zip->file_list.first;- for (;file != NULL; file = file->next) {- /*- * High 16bits is unix mode.- * Low 16bits is Windows attributes.- */- uint32_t encattr, attr;- if (file->dir)- attr = 0x8010;- else- attr = 0x8020;- if ((file->mode & 0222) == 0)- attr |= 1;/* Read Only. */- attr |= ((uint32_t)file->mode) << 16;- archive_le32enc(&encattr, attr);- r = (int)compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);- if (r < 0)- return (r);- }-- /* Write End. */- r = enc_uint64(a, kEnd);- if (r < 0)- return (r);-- /* Write End. */- r = enc_uint64(a, kEnd);- if (r < 0)- return (r);-- return (ARCHIVE_OK);-}---static int-_7z_free(struct archive_write *a)-{- struct _7zip *zip = (struct _7zip *)a->format_data;-- /* Close the temporary file. */- if (zip->temp_fd >= 0)- close(zip->temp_fd);-- file_free_register(zip);- compression_end(&(a->archive), &(zip->stream));- free(zip->coder.props);- free(zip);-- return (ARCHIVE_OK);-}--static int-file_cmp_node(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- const struct file *f1 = (const struct file *)n1;- const struct file *f2 = (const struct file *)n2;-- if (f1->name_len == f2->name_len)- return (memcmp(f1->utf16name, f2->utf16name, f1->name_len));- return (f1->name_len > f2->name_len)?1:-1;-}- -static int-file_cmp_key(const struct archive_rb_node *n, const void *key)-{- const struct file *f = (const struct file *)n;-- return (f->name_len - *(const char *)key);-}--static int-file_new(struct archive_write *a, struct archive_entry *entry,- struct file **newfile)-{- struct _7zip *zip;- struct file *file;- const char *u16;- size_t u16len;- int ret = ARCHIVE_OK;-- zip = (struct _7zip *)a->format_data;- *newfile = NULL;-- file = calloc(1, sizeof(*file));- if (file == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }-- if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) {- if (errno == ENOMEM) {- free(file);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for UTF-16LE");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "A filename cannot be converted to UTF-16LE;"- "You should disable making Joliet extension");- ret = ARCHIVE_WARN;- }- file->utf16name = malloc(u16len + 2);- if (file->utf16name == NULL) {- free(file);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Name");- return (ARCHIVE_FATAL);- }- memcpy(file->utf16name, u16, u16len);- file->utf16name[u16len+0] = 0;- file->utf16name[u16len+1] = 0;- file->name_len = (unsigned)u16len;- file->mode = archive_entry_mode(entry);- if (archive_entry_filetype(entry) == AE_IFREG)- file->size = archive_entry_size(entry);- else- archive_entry_set_size(entry, 0);- if (archive_entry_filetype(entry) == AE_IFDIR)- file->dir = 1;- else if (archive_entry_filetype(entry) == AE_IFLNK)- file->size = strlen(archive_entry_symlink(entry));- if (archive_entry_mtime_is_set(entry)) {- file->flg |= MTIME_IS_SET;- file->times[MTIME].time = archive_entry_mtime(entry);- file->times[MTIME].time_ns = archive_entry_mtime_nsec(entry);- }- if (archive_entry_atime_is_set(entry)) {- file->flg |= ATIME_IS_SET;- file->times[ATIME].time = archive_entry_atime(entry);- file->times[ATIME].time_ns = archive_entry_atime_nsec(entry);- }- if (archive_entry_ctime_is_set(entry)) {- file->flg |= CTIME_IS_SET;- file->times[CTIME].time = archive_entry_ctime(entry);- file->times[CTIME].time_ns = archive_entry_ctime_nsec(entry);- }-- *newfile = file;- return (ret);-}--static void-file_free(struct file *file)-{- free(file->utf16name);- free(file);-}--static void-file_register(struct _7zip *zip, struct file *file)-{- file->next = NULL;- *zip->file_list.last = file;- zip->file_list.last = &(file->next);-}--static void-file_init_register(struct _7zip *zip)-{- zip->file_list.first = NULL;- zip->file_list.last = &(zip->file_list.first);-}--static void-file_free_register(struct _7zip *zip)-{- struct file *file, *file_next;-- file = zip->file_list.first;- while (file != NULL) {- file_next = file->next;- file_free(file);- file = file_next;- }-}--static void-file_register_empty(struct _7zip *zip, struct file *file)-{- file->next = NULL;- *zip->empty_list.last = file;- zip->empty_list.last = &(file->next);-}--static void-file_init_register_empty(struct _7zip *zip)-{- zip->empty_list.first = NULL;- zip->empty_list.last = &(zip->empty_list.first);-}--#if !defined(HAVE_ZLIB_H) || !defined(HAVE_BZLIB_H) ||\- !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)-static int-compression_unsupported_encoder(struct archive *a,- struct la_zstream *lastrm, const char *name)-{-- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "%s compression not supported on this platform", name);- lastrm->valid = 0;- lastrm->real_stream = NULL;- return (ARCHIVE_FAILED);-}-#endif--/*- * _7_COPY compressor.- */-static int-compression_init_encoder_copy(struct archive *a, struct la_zstream *lastrm)-{-- if (lastrm->valid)- compression_end(a, lastrm);- lastrm->valid = 1;- lastrm->code = compression_code_copy;- lastrm->end = compression_end_copy;- return (ARCHIVE_OK);-}--static int-compression_code_copy(struct archive *a,- struct la_zstream *lastrm, enum la_zaction action)-{- size_t bytes;-- (void)a; /* UNUSED */- if (lastrm->avail_out > lastrm->avail_in)- bytes = lastrm->avail_in;- else- bytes = lastrm->avail_out;- if (bytes) {- memcpy(lastrm->next_out, lastrm->next_in, bytes);- lastrm->next_in += bytes;- lastrm->avail_in -= bytes;- lastrm->total_in += bytes;- lastrm->next_out += bytes;- lastrm->avail_out -= bytes;- lastrm->total_out += bytes;- }- if (action == ARCHIVE_Z_FINISH && lastrm->avail_in == 0)- return (ARCHIVE_EOF);- return (ARCHIVE_OK);-}--static int-compression_end_copy(struct archive *a, struct la_zstream *lastrm)-{- (void)a; /* UNUSED */- lastrm->valid = 0;- return (ARCHIVE_OK);-}--/*- * _7_DEFLATE compressor.- */-#ifdef HAVE_ZLIB_H-static int-compression_init_encoder_deflate(struct archive *a,- struct la_zstream *lastrm, int level, int withheader)-{- z_stream *strm;-- if (lastrm->valid)- compression_end(a, lastrm);- strm = calloc(1, sizeof(*strm));- if (strm == NULL) {- archive_set_error(a, ENOMEM,- "Can't allocate memory for gzip stream");- return (ARCHIVE_FATAL);- }- /* zlib.h is not const-correct, so we need this one bit- * of ugly hackery to convert a const * pointer to- * a non-const pointer. */- strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;- strm->avail_in = (uInt)lastrm->avail_in;- strm->total_in = (uLong)lastrm->total_in;- strm->next_out = lastrm->next_out;- strm->avail_out = (uInt)lastrm->avail_out;- strm->total_out = (uLong)lastrm->total_out;- if (deflateInit2(strm, level, Z_DEFLATED,- (withheader)?15:-15,- 8, Z_DEFAULT_STRATEGY) != Z_OK) {- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Internal error initializing compression library");- return (ARCHIVE_FATAL);- }- lastrm->real_stream = strm;- lastrm->valid = 1;- lastrm->code = compression_code_deflate;- lastrm->end = compression_end_deflate;- return (ARCHIVE_OK);-}--static int-compression_code_deflate(struct archive *a,- struct la_zstream *lastrm, enum la_zaction action)-{- z_stream *strm;- int r;-- strm = (z_stream *)lastrm->real_stream;- /* zlib.h is not const-correct, so we need this one bit- * of ugly hackery to convert a const * pointer to- * a non-const pointer. */- strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;- strm->avail_in = (uInt)lastrm->avail_in;- strm->total_in = (uLong)lastrm->total_in;- strm->next_out = lastrm->next_out;- strm->avail_out = (uInt)lastrm->avail_out;- strm->total_out = (uLong)lastrm->total_out;- r = deflate(strm,- (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);- lastrm->next_in = strm->next_in;- lastrm->avail_in = strm->avail_in;- lastrm->total_in = strm->total_in;- lastrm->next_out = strm->next_out;- lastrm->avail_out = strm->avail_out;- lastrm->total_out = strm->total_out;- switch (r) {- case Z_OK:- return (ARCHIVE_OK);- case Z_STREAM_END:- return (ARCHIVE_EOF);- default:- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "GZip compression failed:"- " deflate() call returned status %d", r);- return (ARCHIVE_FATAL);- }-}--static int-compression_end_deflate(struct archive *a, struct la_zstream *lastrm)-{- z_stream *strm;- int r;-- strm = (z_stream *)lastrm->real_stream;- r = deflateEnd(strm);- free(strm);- lastrm->real_stream = NULL;- lastrm->valid = 0;- if (r != Z_OK) {- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Failed to clean up compressor");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}-#else-static int-compression_init_encoder_deflate(struct archive *a,- struct la_zstream *lastrm, int level, int withheader)-{-- (void) level; /* UNUSED */- (void) withheader; /* UNUSED */- if (lastrm->valid)- compression_end(a, lastrm);- return (compression_unsupported_encoder(a, lastrm, "deflate"));-}-#endif--/*- * _7_BZIP2 compressor.- */-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)-static int-compression_init_encoder_bzip2(struct archive *a,- struct la_zstream *lastrm, int level)-{- bz_stream *strm;-- if (lastrm->valid)- compression_end(a, lastrm);- strm = calloc(1, sizeof(*strm));- if (strm == NULL) {- archive_set_error(a, ENOMEM,- "Can't allocate memory for bzip2 stream");- return (ARCHIVE_FATAL);- }- /* bzlib.h is not const-correct, so we need this one bit- * of ugly hackery to convert a const * pointer to- * a non-const pointer. */- strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;- strm->avail_in = (uint32_t)lastrm->avail_in;- strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);- strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);- strm->next_out = (char *)lastrm->next_out;- strm->avail_out = (uint32_t)lastrm->avail_out;- strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);- strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);- if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Internal error initializing compression library");- return (ARCHIVE_FATAL);- }- lastrm->real_stream = strm;- lastrm->valid = 1;- lastrm->code = compression_code_bzip2;- lastrm->end = compression_end_bzip2;- return (ARCHIVE_OK);-}--static int-compression_code_bzip2(struct archive *a,- struct la_zstream *lastrm, enum la_zaction action)-{- bz_stream *strm;- int r;-- strm = (bz_stream *)lastrm->real_stream;- /* bzlib.h is not const-correct, so we need this one bit- * of ugly hackery to convert a const * pointer to- * a non-const pointer. */- strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;- strm->avail_in = (uint32_t)lastrm->avail_in;- strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);- strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);- strm->next_out = (char *)lastrm->next_out;- strm->avail_out = (uint32_t)lastrm->avail_out;- strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);- strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);- r = BZ2_bzCompress(strm,- (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);- lastrm->next_in = (const unsigned char *)strm->next_in;- lastrm->avail_in = strm->avail_in;- lastrm->total_in =- (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)- + (uint64_t)(uint32_t)strm->total_in_lo32;- lastrm->next_out = (unsigned char *)strm->next_out;- lastrm->avail_out = strm->avail_out;- lastrm->total_out =- (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)- + (uint64_t)(uint32_t)strm->total_out_lo32;- switch (r) {- case BZ_RUN_OK: /* Non-finishing */- case BZ_FINISH_OK: /* Finishing: There's more work to do */- return (ARCHIVE_OK);- case BZ_STREAM_END: /* Finishing: all done */- /* Only occurs in finishing case */- return (ARCHIVE_EOF);- default:- /* Any other return value indicates an error */- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Bzip2 compression failed:"- " BZ2_bzCompress() call returned status %d", r);- return (ARCHIVE_FATAL);- }-}--static int-compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)-{- bz_stream *strm;- int r;-- strm = (bz_stream *)lastrm->real_stream;- r = BZ2_bzCompressEnd(strm);- free(strm);- lastrm->real_stream = NULL;- lastrm->valid = 0;- if (r != BZ_OK) {- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Failed to clean up compressor");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}--#else-static int-compression_init_encoder_bzip2(struct archive *a,- struct la_zstream *lastrm, int level)-{-- (void) level; /* UNUSED */- if (lastrm->valid)- compression_end(a, lastrm);- return (compression_unsupported_encoder(a, lastrm, "bzip2"));-}-#endif--/*- * _7_LZMA1, _7_LZMA2 compressor.- */-#if defined(HAVE_LZMA_H)-static int-compression_init_encoder_lzma(struct archive *a,- struct la_zstream *lastrm, int level, uint64_t filter_id)-{- static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;- lzma_stream *strm;- lzma_filter *lzmafilters;- lzma_options_lzma lzma_opt;- int r;-- if (lastrm->valid)- compression_end(a, lastrm);- strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);- if (strm == NULL) {- archive_set_error(a, ENOMEM,- "Can't allocate memory for lzma stream");- return (ARCHIVE_FATAL);- }- lzmafilters = (lzma_filter *)(strm+1);- if (level > 9)- level = 9;- if (lzma_lzma_preset(&lzma_opt, level)) {- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ENOMEM,- "Internal error initializing compression library");- return (ARCHIVE_FATAL);- }- lzmafilters[0].id = filter_id;- lzmafilters[0].options = &lzma_opt;- lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */-- r = lzma_properties_size(&(lastrm->prop_size), lzmafilters);- if (r != LZMA_OK) {- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "lzma_properties_size failed");- return (ARCHIVE_FATAL);- }- if (lastrm->prop_size) {- lastrm->props = malloc(lastrm->prop_size);- if (lastrm->props == NULL) {- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ENOMEM,- "Cannot allocate memory");- return (ARCHIVE_FATAL);- }- r = lzma_properties_encode(lzmafilters, lastrm->props);- if (r != LZMA_OK) {- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "lzma_properties_encode failed");- return (ARCHIVE_FATAL);- }- }-- *strm = lzma_init_data;- r = lzma_raw_encoder(strm, lzmafilters);- switch (r) {- case LZMA_OK:- lastrm->real_stream = strm;- lastrm->valid = 1;- lastrm->code = compression_code_lzma;- lastrm->end = compression_end_lzma;- r = ARCHIVE_OK;- break;- case LZMA_MEM_ERROR:- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ENOMEM,- "Internal error initializing compression library: "- "Cannot allocate memory");- r = ARCHIVE_FATAL;- break;- default:- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Internal error initializing compression library: "- "It's a bug in liblzma");- r = ARCHIVE_FATAL;- break;- }- return (r);-}--static int-compression_init_encoder_lzma1(struct archive *a,- struct la_zstream *lastrm, int level)-{- return compression_init_encoder_lzma(a, lastrm, level,- LZMA_FILTER_LZMA1);-}--static int-compression_init_encoder_lzma2(struct archive *a,- struct la_zstream *lastrm, int level)-{- return compression_init_encoder_lzma(a, lastrm, level,- LZMA_FILTER_LZMA2);-}--static int-compression_code_lzma(struct archive *a,- struct la_zstream *lastrm, enum la_zaction action)-{- lzma_stream *strm;- int r;-- strm = (lzma_stream *)lastrm->real_stream;- strm->next_in = lastrm->next_in;- strm->avail_in = lastrm->avail_in;- strm->total_in = lastrm->total_in;- strm->next_out = lastrm->next_out;- strm->avail_out = lastrm->avail_out;- strm->total_out = lastrm->total_out;- r = lzma_code(strm,- (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);- lastrm->next_in = strm->next_in;- lastrm->avail_in = strm->avail_in;- lastrm->total_in = strm->total_in;- lastrm->next_out = strm->next_out;- lastrm->avail_out = strm->avail_out;- lastrm->total_out = strm->total_out;- switch (r) {- case LZMA_OK:- /* Non-finishing case */- return (ARCHIVE_OK);- case LZMA_STREAM_END:- /* This return can only occur in finishing case. */- return (ARCHIVE_EOF);- case LZMA_MEMLIMIT_ERROR:- archive_set_error(a, ENOMEM,- "lzma compression error:"- " %ju MiB would have been needed",- (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)- / (1024 * 1024)));- return (ARCHIVE_FATAL);- default:- /* Any other return value indicates an error */- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "lzma compression failed:"- " lzma_code() call returned status %d", r);- return (ARCHIVE_FATAL);- }-}--static int-compression_end_lzma(struct archive *a, struct la_zstream *lastrm)-{- lzma_stream *strm;-- (void)a; /* UNUSED */- strm = (lzma_stream *)lastrm->real_stream;- lzma_end(strm);- free(strm);- lastrm->valid = 0;- lastrm->real_stream = NULL;- return (ARCHIVE_OK);-}-#else-static int-compression_init_encoder_lzma1(struct archive *a,- struct la_zstream *lastrm, int level)-{-- (void) level; /* UNUSED */- if (lastrm->valid)- compression_end(a, lastrm);- return (compression_unsupported_encoder(a, lastrm, "lzma"));-}-static int-compression_init_encoder_lzma2(struct archive *a,- struct la_zstream *lastrm, int level)-{-- (void) level; /* UNUSED */- if (lastrm->valid)- compression_end(a, lastrm);- return (compression_unsupported_encoder(a, lastrm, "lzma"));-}-#endif--/*- * _7_PPMD compressor.- */-static void-ppmd_write(void *p, Byte b)-{- struct archive_write *a = ((IByteOut *)p)->a;- struct _7zip *zip = (struct _7zip *)(a->format_data);- struct la_zstream *lastrm = &(zip->stream);- struct ppmd_stream *strm;-- if (lastrm->avail_out) {- *lastrm->next_out++ = b;- lastrm->avail_out--;- lastrm->total_out++;- return;- }- strm = (struct ppmd_stream *)lastrm->real_stream;- if (strm->buff_ptr < strm->buff_end) {- *strm->buff_ptr++ = b;- strm->buff_bytes++;- }-}--static int-compression_init_encoder_ppmd(struct archive *a,- struct la_zstream *lastrm, unsigned maxOrder, uint32_t msize)-{- struct ppmd_stream *strm;- uint8_t *props;- int r;-- if (lastrm->valid)- compression_end(a, lastrm);- strm = calloc(1, sizeof(*strm));- if (strm == NULL) {- archive_set_error(a, ENOMEM,- "Can't allocate memory for PPMd");- return (ARCHIVE_FATAL);- }- strm->buff = malloc(32);- if (strm->buff == NULL) {- free(strm);- archive_set_error(a, ENOMEM,- "Can't allocate memory for PPMd");- return (ARCHIVE_FATAL);- }- strm->buff_ptr = strm->buff;- strm->buff_end = strm->buff + 32;-- props = malloc(1+4);- if (props == NULL) {- free(strm->buff);- free(strm);- archive_set_error(a, ENOMEM,- "Coludn't allocate memory for PPMd");- return (ARCHIVE_FATAL);- }- props[0] = maxOrder;- archive_le32enc(props+1, msize);- __archive_ppmd7_functions.Ppmd7_Construct(&strm->ppmd7_context);- r = __archive_ppmd7_functions.Ppmd7_Alloc(- &strm->ppmd7_context, msize);- if (r == 0) {- free(strm->buff);- free(strm);- free(props);- archive_set_error(a, ENOMEM,- "Coludn't allocate memory for PPMd");- return (ARCHIVE_FATAL);- }- __archive_ppmd7_functions.Ppmd7_Init(&(strm->ppmd7_context), maxOrder);- strm->byteout.a = (struct archive_write *)a;- strm->byteout.Write = ppmd_write;- strm->range_enc.Stream = &(strm->byteout);- __archive_ppmd7_functions.Ppmd7z_RangeEnc_Init(&(strm->range_enc));- strm->stat = 0;-- lastrm->real_stream = strm;- lastrm->valid = 1;- lastrm->code = compression_code_ppmd;- lastrm->end = compression_end_ppmd;- lastrm->prop_size = 5;- lastrm->props = props;- return (ARCHIVE_OK);-}--static int-compression_code_ppmd(struct archive *a,- struct la_zstream *lastrm, enum la_zaction action)-{- struct ppmd_stream *strm;-- (void)a; /* UNUSED */-- strm = (struct ppmd_stream *)lastrm->real_stream;-- /* Copy encoded data if there are remaining bytes from previous call. */- if (strm->buff_bytes) {- uint8_t *p = strm->buff_ptr - strm->buff_bytes;- while (lastrm->avail_out && strm->buff_bytes) {- *lastrm->next_out++ = *p++;- lastrm->avail_out--;- lastrm->total_out++;- strm->buff_bytes--;- }- if (strm->buff_bytes)- return (ARCHIVE_OK);- if (strm->stat == 1)- return (ARCHIVE_EOF);- strm->buff_ptr = strm->buff;- }- while (lastrm->avail_in && lastrm->avail_out) {- __archive_ppmd7_functions.Ppmd7_EncodeSymbol(- &(strm->ppmd7_context), &(strm->range_enc),- *lastrm->next_in++);- lastrm->avail_in--;- lastrm->total_in++;- }- if (lastrm->avail_in == 0 && action == ARCHIVE_Z_FINISH) {- __archive_ppmd7_functions.Ppmd7z_RangeEnc_FlushData(- &(strm->range_enc));- strm->stat = 1;- /* Return EOF if there are no remaining bytes. */- if (strm->buff_bytes == 0)- return (ARCHIVE_EOF);- }- return (ARCHIVE_OK);-}--static int-compression_end_ppmd(struct archive *a, struct la_zstream *lastrm)-{- struct ppmd_stream *strm;-- (void)a; /* UNUSED */-- strm = (struct ppmd_stream *)lastrm->real_stream;- __archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context);- free(strm->buff);- free(strm);- lastrm->real_stream = NULL;- lastrm->valid = 0;- return (ARCHIVE_OK);-}--/*- * Universal compressor initializer.- */-static int-_7z_compression_init_encoder(struct archive_write *a, unsigned compression,- int compression_level)-{- struct _7zip *zip;- int r;-- zip = (struct _7zip *)a->format_data;- switch (compression) {- case _7Z_DEFLATE:- r = compression_init_encoder_deflate(- &(a->archive), &(zip->stream),- compression_level, 0);- break;- case _7Z_BZIP2:- r = compression_init_encoder_bzip2(- &(a->archive), &(zip->stream),- compression_level);- break;- case _7Z_LZMA1:- r = compression_init_encoder_lzma1(- &(a->archive), &(zip->stream),- compression_level);- break;- case _7Z_LZMA2:- r = compression_init_encoder_lzma2(- &(a->archive), &(zip->stream),- compression_level);- break;- case _7Z_PPMD:- r = compression_init_encoder_ppmd(- &(a->archive), &(zip->stream),- PPMD7_DEFAULT_ORDER, PPMD7_DEFAULT_MEM_SIZE);- break;- case _7Z_COPY:- default:- r = compression_init_encoder_copy(- &(a->archive), &(zip->stream));- break;- }- if (r == ARCHIVE_OK) {- zip->stream.total_in = 0;- zip->stream.next_out = zip->wbuff;- zip->stream.avail_out = sizeof(zip->wbuff);- zip->stream.total_out = 0;- }-- return (r);-}--static int-compression_code(struct archive *a, struct la_zstream *lastrm,- enum la_zaction action)-{- if (lastrm->valid)- return (lastrm->code(a, lastrm, action));- return (ARCHIVE_OK);-}--static int-compression_end(struct archive *a, struct la_zstream *lastrm)-{- if (lastrm->valid) {- lastrm->prop_size = 0;- free(lastrm->props);- lastrm->props = NULL;- return (lastrm->end(a, lastrm));- }- return (ARCHIVE_OK);-}--
− c/archive_write_set_format_ar.c
@@ -1,570 +0,0 @@-/*-- * Copyright (c) 2007 Kai Wang- * Copyright (c) 2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer- * in this position and unchanged.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_ar.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 "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--struct ar_w {- uint64_t entry_bytes_remaining;- uint64_t entry_padding;- int is_strtab;- int has_strtab;- char wrote_global_header;- char *strtab;-};--/*- * Define structure of the "ar" header.- */-#define AR_name_offset 0-#define AR_name_size 16-#define AR_date_offset 16-#define AR_date_size 12-#define AR_uid_offset 28-#define AR_uid_size 6-#define AR_gid_offset 34-#define AR_gid_size 6-#define AR_mode_offset 40-#define AR_mode_size 8-#define AR_size_offset 48-#define AR_size_size 10-#define AR_fmag_offset 58-#define AR_fmag_size 2--static int archive_write_set_format_ar(struct archive_write *);-static int archive_write_ar_header(struct archive_write *,- struct archive_entry *);-static ssize_t archive_write_ar_data(struct archive_write *,- const void *buff, size_t s);-static int archive_write_ar_free(struct archive_write *);-static int archive_write_ar_close(struct archive_write *);-static int archive_write_ar_finish_entry(struct archive_write *);-static const char *ar_basename(const char *path);-static int format_octal(int64_t v, char *p, int s);-static int format_decimal(int64_t v, char *p, int s);--int-archive_write_set_format_ar_bsd(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- int r;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_ar_bsd");- r = archive_write_set_format_ar(a);- if (r == ARCHIVE_OK) {- a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD;- a->archive.archive_format_name = "ar (BSD)";- }- return (r);-}--int-archive_write_set_format_ar_svr4(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- int r;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_ar_svr4");- r = archive_write_set_format_ar(a);- if (r == ARCHIVE_OK) {- a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU;- a->archive.archive_format_name = "ar (GNU/SVR4)";- }- return (r);-}--/*- * Generic initialization.- */-static int-archive_write_set_format_ar(struct archive_write *a)-{- struct ar_w *ar;-- /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);-- ar = (struct ar_w *)calloc(1, sizeof(*ar));- if (ar == NULL) {- archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data");- return (ARCHIVE_FATAL);- }- a->format_data = ar;-- a->format_name = "ar";- a->format_write_header = archive_write_ar_header;- a->format_write_data = archive_write_ar_data;- a->format_close = archive_write_ar_close;- a->format_free = archive_write_ar_free;- a->format_finish_entry = archive_write_ar_finish_entry;- return (ARCHIVE_OK);-}--static int-archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)-{- int ret, append_fn;- char buff[60];- char *ss, *se;- struct ar_w *ar;- const char *pathname;- const char *filename;- int64_t size;-- append_fn = 0;- ar = (struct ar_w *)a->format_data;- ar->is_strtab = 0;- filename = NULL;- size = archive_entry_size(entry);--- /*- * Reject files with empty name.- */- pathname = archive_entry_pathname(entry);- if (pathname == NULL || *pathname == '\0') {- archive_set_error(&a->archive, EINVAL,- "Invalid filename");- return (ARCHIVE_WARN);- }-- /*- * If we are now at the beginning of the archive,- * we need first write the ar global header.- */- if (!ar->wrote_global_header) {- __archive_write_output(a, "!<arch>\n", 8);- ar->wrote_global_header = 1;- }-- memset(buff, ' ', 60);- memcpy(&buff[AR_fmag_offset], "`\n", 2);-- if (strcmp(pathname, "/") == 0 ) {- /* Entry is archive symbol table in GNU format */- buff[AR_name_offset] = '/';- goto stat;- }- if (strcmp(pathname, "/SYM64/") == 0) {- /* Entry is archive symbol table in GNU 64-bit format */- memcpy(buff + AR_name_offset, "/SYM64/", 7);- goto stat;- }- if (strcmp(pathname, "__.SYMDEF") == 0) {- /* Entry is archive symbol table in BSD format */- memcpy(buff + AR_name_offset, "__.SYMDEF", 9);- goto stat;- }- if (strcmp(pathname, "//") == 0) {- /*- * Entry is archive filename table, inform that we should- * collect strtab in next _data call.- */- ar->is_strtab = 1;- buff[AR_name_offset] = buff[AR_name_offset + 1] = '/';- /*- * For archive string table, only ar_size field should- * be set.- */- goto size;- }-- /*- * Otherwise, entry is a normal archive member.- * Strip leading paths from filenames, if any.- */- if ((filename = ar_basename(pathname)) == NULL) {- /* Reject filenames with trailing "/" */- archive_set_error(&a->archive, EINVAL,- "Invalid filename");- return (ARCHIVE_WARN);- }-- if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) {- /*- * SVR4/GNU variant use a "/" to mark then end of the filename,- * make it possible to have embedded spaces in the filename.- * So, the longest filename here (without extension) is- * actually 15 bytes.- */- if (strlen(filename) <= 15) {- memcpy(&buff[AR_name_offset],- filename, strlen(filename));- buff[AR_name_offset + strlen(filename)] = '/';- } else {- /*- * For filename longer than 15 bytes, GNU variant- * makes use of a string table and instead stores the- * offset of the real filename to in the ar_name field.- * The string table should have been written before.- */- if (ar->has_strtab <= 0) {- archive_set_error(&a->archive, EINVAL,- "Can't find string table");- return (ARCHIVE_WARN);- }-- se = (char *)malloc(strlen(filename) + 3);- if (se == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate filename buffer");- return (ARCHIVE_FATAL);- }-- memcpy(se, filename, strlen(filename));- strcpy(se + strlen(filename), "/\n");-- ss = strstr(ar->strtab, se);- free(se);-- if (ss == NULL) {- archive_set_error(&a->archive, EINVAL,- "Invalid string table");- return (ARCHIVE_WARN);- }-- /*- * GNU variant puts "/" followed by digits into- * ar_name field. These digits indicates the real- * filename string's offset to the string table.- */- buff[AR_name_offset] = '/';- if (format_decimal(ss - ar->strtab,- buff + AR_name_offset + 1,- AR_name_size - 1)) {- archive_set_error(&a->archive, ERANGE,- "string table offset too large");- return (ARCHIVE_WARN);- }- }- } else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) {- /*- * BSD variant: for any file name which is more than- * 16 chars or contains one or more embedded space(s), the- * string "#1/" followed by the ASCII length of the name is- * put into the ar_name field. The file size (stored in the- * ar_size field) is incremented by the length of the name.- * The name is then written immediately following the- * archive header.- */- if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) {- memcpy(&buff[AR_name_offset], filename, strlen(filename));- buff[AR_name_offset + strlen(filename)] = ' ';- }- else {- memcpy(buff + AR_name_offset, "#1/", 3);- if (format_decimal(strlen(filename),- buff + AR_name_offset + 3,- AR_name_size - 3)) {- archive_set_error(&a->archive, ERANGE,- "File name too long");- return (ARCHIVE_WARN);- }- append_fn = 1;- size += strlen(filename);- }- }--stat:- if (format_decimal(archive_entry_mtime(entry), buff + AR_date_offset, AR_date_size)) {- archive_set_error(&a->archive, ERANGE,- "File modification time too large");- return (ARCHIVE_WARN);- }- if (format_decimal(archive_entry_uid(entry), buff + AR_uid_offset, AR_uid_size)) {- archive_set_error(&a->archive, ERANGE,- "Numeric user ID too large");- return (ARCHIVE_WARN);- }- if (format_decimal(archive_entry_gid(entry), buff + AR_gid_offset, AR_gid_size)) {- archive_set_error(&a->archive, ERANGE,- "Numeric group ID too large");- return (ARCHIVE_WARN);- }- if (format_octal(archive_entry_mode(entry), buff + AR_mode_offset, AR_mode_size)) {- archive_set_error(&a->archive, ERANGE,- "Numeric mode too large");- return (ARCHIVE_WARN);- }- /*- * Sanity Check: A non-pseudo archive member should always be- * a regular file.- */- if (filename != NULL && archive_entry_filetype(entry) != AE_IFREG) {- archive_set_error(&a->archive, EINVAL,- "Regular file required for non-pseudo member");- return (ARCHIVE_WARN);- }--size:- if (format_decimal(size, buff + AR_size_offset, AR_size_size)) {- archive_set_error(&a->archive, ERANGE,- "File size out of range");- return (ARCHIVE_WARN);- }-- ret = __archive_write_output(a, buff, 60);- if (ret != ARCHIVE_OK)- return (ret);-- ar->entry_bytes_remaining = size;- ar->entry_padding = ar->entry_bytes_remaining % 2;-- if (append_fn > 0) {- ret = __archive_write_output(a, filename, strlen(filename));- if (ret != ARCHIVE_OK)- return (ret);- ar->entry_bytes_remaining -= strlen(filename);- }-- return (ARCHIVE_OK);-}--static ssize_t-archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)-{- struct ar_w *ar;- int ret;-- ar = (struct ar_w *)a->format_data;- if (s > ar->entry_bytes_remaining)- s = (size_t)ar->entry_bytes_remaining;-- if (ar->is_strtab > 0) {- if (ar->has_strtab > 0) {- archive_set_error(&a->archive, EINVAL,- "More than one string tables exist");- return (ARCHIVE_WARN);- }-- ar->strtab = (char *)malloc(s + 1);- if (ar->strtab == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate strtab buffer");- return (ARCHIVE_FATAL);- }- memcpy(ar->strtab, buff, s);- ar->strtab[s] = '\0';- ar->has_strtab = 1;- }-- ret = __archive_write_output(a, buff, s);- if (ret != ARCHIVE_OK)- return (ret);-- ar->entry_bytes_remaining -= s;- return (s);-}--static int-archive_write_ar_free(struct archive_write *a)-{- struct ar_w *ar;-- ar = (struct ar_w *)a->format_data;-- if (ar == NULL)- return (ARCHIVE_OK);-- if (ar->has_strtab > 0) {- free(ar->strtab);- ar->strtab = NULL;- }-- free(ar);- a->format_data = NULL;- return (ARCHIVE_OK);-}--static int-archive_write_ar_close(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.- */- 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_OK);-}--static int-archive_write_ar_finish_entry(struct archive_write *a)-{- struct ar_w *ar;- int ret;-- ar = (struct ar_w *)a->format_data;-- if (ar->entry_bytes_remaining != 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Entry remaining bytes larger than 0");- return (ARCHIVE_WARN);- }-- if (ar->entry_padding == 0) {- return (ARCHIVE_OK);- }-- if (ar->entry_padding != 1) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Padding wrong size: %ju should be 1 or 0",- (uintmax_t)ar->entry_padding);- return (ARCHIVE_WARN);- }-- ret = __archive_write_output(a, "\n", 1);- return (ret);-}--/*- * Format a number into the specified field using base-8.- * NB: This version is slightly different from the one in- * _ustar.c- */-static int-format_octal(int64_t v, char *p, int s)-{- int len;- char *h;-- len = s;- h = p;-- /* Octal values can't be negative, so use 0. */- if (v < 0) {- while (len-- > 0)- *p++ = '0';- return (-1);- }-- p += s; /* Start at the end and work backwards. */- do {- *--p = (char)('0' + (v & 7));- v >>= 3;- } while (--s > 0 && v > 0);-- if (v == 0) {- memmove(h, p, len - s);- p = h + len - s;- while (s-- > 0)- *p++ = ' ';- return (0);- }- /* If it overflowed, fill field with max value. */- while (len-- > 0)- *p++ = '7';-- return (-1);-}--/*- * Format a number into the specified field using base-10.- */-static int-format_decimal(int64_t v, char *p, int s)-{- int len;- char *h;-- len = s;- h = p;-- /* Negative values in ar header are meaningless, so use 0. */- if (v < 0) {- while (len-- > 0)- *p++ = '0';- return (-1);- }-- p += s;- do {- *--p = (char)('0' + (v % 10));- v /= 10;- } while (--s > 0 && v > 0);-- if (v == 0) {- memmove(h, p, len - s);- p = h + len - s;- while (s-- > 0)- *p++ = ' ';- return (0);- }- /* If it overflowed, fill field with max value. */- while (len-- > 0)- *p++ = '9';-- return (-1);-}--static const char *-ar_basename(const char *path)-{- const char *endp, *startp;-- endp = path + strlen(path) - 1;- /*- * For filename with trailing slash(es), we return- * NULL indicating an error.- */- if (*endp == '/')- return (NULL);-- /* Find the start of the base */- startp = endp;- while (startp > path && *(startp - 1) != '/')- startp--;- - return (startp);-}
− c/archive_write_set_format_by_name.c
@@ -1,94 +0,0 @@-/*-- * 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_format_by_name.c 201168 2009-12-29 06:15:32Z kientzle $");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_private.h"--/* A table that maps names to functions. */-static const-struct { const char *name; int (*setter)(struct archive *); } names[] =-{- { "7zip", archive_write_set_format_7zip },- { "ar", archive_write_set_format_ar_bsd },- { "arbsd", archive_write_set_format_ar_bsd },- { "argnu", archive_write_set_format_ar_svr4 },- { "arsvr4", archive_write_set_format_ar_svr4 },- { "bin", archive_write_set_format_cpio_bin },- { "bsdtar", archive_write_set_format_pax_restricted },- { "cd9660", archive_write_set_format_iso9660 },- { "cpio", archive_write_set_format_cpio },- { "gnutar", archive_write_set_format_gnutar },- { "iso", archive_write_set_format_iso9660 },- { "iso9660", archive_write_set_format_iso9660 },- { "mtree", archive_write_set_format_mtree },- { "mtree-classic", archive_write_set_format_mtree_classic },- { "newc", archive_write_set_format_cpio_newc },- { "odc", archive_write_set_format_cpio_odc },- { "oldtar", archive_write_set_format_v7tar },- { "pax", archive_write_set_format_pax },- { "paxr", archive_write_set_format_pax_restricted },- { "posix", archive_write_set_format_pax },- { "pwb", archive_write_set_format_cpio_pwb },- { "raw", archive_write_set_format_raw },- { "rpax", archive_write_set_format_pax_restricted },- { "shar", archive_write_set_format_shar },- { "shardump", archive_write_set_format_shar_dump },- { "ustar", archive_write_set_format_ustar },- { "v7tar", archive_write_set_format_v7tar },- { "v7", archive_write_set_format_v7tar },- { "warc", archive_write_set_format_warc },- { "xar", archive_write_set_format_xar },- { "zip", archive_write_set_format_zip },- { NULL, NULL }-};--int-archive_write_set_format_by_name(struct archive *a, const char *name)-{- int i;-- for (i = 0; names[i].name != NULL; i++) {- if (strcmp(name, names[i].name) == 0)- return ((names[i].setter)(a));- }-- archive_set_error(a, EINVAL, "No such format '%s'", name);- a->state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);-}
− c/archive_write_set_format_cpio.c
@@ -1,11 +0,0 @@-#include "archive_platform.h"-#include "archive.h"--/*- * Set output format to the default 'cpio' format.- */-int-archive_write_set_format_cpio(struct archive *_a)-{- return archive_write_set_format_cpio_odc(_a);-}
− c/archive_write_set_format_cpio_binary.c
@@ -1,610 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z 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--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--static ssize_t archive_write_binary_data(struct archive_write *,- const void *buff, size_t s);-static int archive_write_binary_close(struct archive_write *);-static int archive_write_binary_free(struct archive_write *);-static int archive_write_binary_finish_entry(struct archive_write *);-static int archive_write_binary_header(struct archive_write *,- struct archive_entry *);-static int archive_write_binary_options(struct archive_write *,- const char *, const char *);-static int write_header(struct archive_write *, struct archive_entry *);--struct cpio {- uint64_t entry_bytes_remaining;-- int64_t ino_next;-- struct { int64_t old; int new;} *ino_list;- size_t ino_list_size;- size_t ino_list_next;-- struct archive_string_conv *opt_sconv;- struct archive_string_conv *sconv_default;- int init_default_conversion;-};--/* This struct needs to be packed to get the header right */--#if defined(__GNUC__)-#define PACKED(x) x __attribute__((packed))-#elif defined(_MSC_VER)-#define PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))-#else-#define PACKED(x) x-#endif--#define HSIZE 26--PACKED(struct cpio_binary_header {- uint16_t h_magic;- uint16_t h_dev;- uint16_t h_ino;- uint16_t h_mode;- uint16_t h_uid;- uint16_t h_gid;- uint16_t h_nlink;- uint16_t h_majmin;- uint32_t h_mtime;- uint16_t h_namesize;- uint32_t h_filesize;-});--/* Back in the day, the 7th Edition cpio.c had this, to- * adapt to, as the comment said, "VAX, Interdata, ...":- *- * union { long l; short s[2]; char c[4]; } U;- * #define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];}- * long mklong(v)- * short v[];- * {- * U.l = 1;- * if(U.c[0])- * U.s[0] = v[1], U.s[1] = v[0];- * else- * U.s[0] = v[0], U.s[1] = v[1];- * return U.l;- * }- *- * Of course, that assumes that all machines have little-endian shorts,- * and just adapts the others to the special endianness of the PDP-11.- *- * Now, we could do this:- *- * union { uint32_t l; uint16_t s[2]; uint8_t c[4]; } U;- * #define PUTI16(v,sv) {U.s[0]=1;if(U.c[0]) v=sv; else U.s[0]=sv,U.c[2]=U.c[1],U.c[3]=U.c[0],v=U.s[1];}- * #define PUTI32(v,lv) {char_t Ut;U.l=1;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,Ut=U.c[0],U.c[0]=U.c[1],U.c[1]=Ut,Ut=U.c[2],U.c[2]=U.c[3],U.c[3]=Ut,v[0]=U.s[0],v[1]=U.s[1];}- *- * ...but it feels a little better to do it like this:- */--static uint16_t la_swap16(uint16_t in) {- union {- uint16_t s[2];- uint8_t c[4];- } U;- U.s[0] = 1;- if (U.c[0])- return in;- else {- U.s[0] = in;- U.c[2] = U.c[1];- U.c[3] = U.c[0];- return U.s[1];- }- /* NOTREACHED */-}--static uint32_t la_swap32(uint32_t in) {- union {- uint32_t l;- uint16_t s[2];- uint8_t c[4];- } U;- U.l = 1;- if (U.c[0]) { /* Little-endian */- uint16_t t;- U.l = in;- t = U.s[0];- U.s[0] = U.s[1];- U.s[1] = t;- } else if (U.c[3]) { /* Big-endian */- U.l = in;- U.s[0] = la_swap16(U.s[0]);- U.s[1] = la_swap16(U.s[1]);- } else { /* PDP-endian */- U.l = in;- }- return U.l;-}--/*- * Set output format to the selected binary variant- */-static int-archive_write_set_format_cpio_binary(struct archive *_a, int format)-{- struct archive_write *a = (struct archive_write *)_a;- struct cpio *cpio;-- if (sizeof(struct cpio_binary_header) != HSIZE) {- archive_set_error(&a->archive, EINVAL,- "Binary cpio format not supported on this platform");- return (ARCHIVE_FATAL);- }-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_binary");-- /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);-- cpio = (struct cpio *)calloc(1, sizeof(*cpio));- if (cpio == NULL) {- archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");- return (ARCHIVE_FATAL);- }- a->format_data = cpio;- a->format_name = "cpio";- a->format_options = archive_write_binary_options;- a->format_write_header = archive_write_binary_header;- a->format_write_data = archive_write_binary_data;- a->format_finish_entry = archive_write_binary_finish_entry;- a->format_close = archive_write_binary_close;- a->format_free = archive_write_binary_free;- a->archive.archive_format = format;- switch (format) {- case ARCHIVE_FORMAT_CPIO_PWB:- a->archive.archive_format_name = "PWB cpio";- break;- case ARCHIVE_FORMAT_CPIO_BIN_LE:- a->archive.archive_format_name = "7th Edition cpio";- break;- default:- archive_set_error(&a->archive, EINVAL, "binary format must be 'pwb' or 'bin'");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}--/*- * Set output format to PWB (6th Edition) binary format- */-int-archive_write_set_format_cpio_pwb(struct archive *_a)-{- return archive_write_set_format_cpio_binary(_a, ARCHIVE_FORMAT_CPIO_PWB);-}--/*- * Set output format to 7th Edition binary format- */-int-archive_write_set_format_cpio_bin(struct archive *_a)-{- return archive_write_set_format_cpio_binary(_a, ARCHIVE_FORMAT_CPIO_BIN_LE);-}--static int-archive_write_binary_options(struct archive_write *a, const char *key,- const char *val)-{- struct cpio *cpio = (struct cpio *)a->format_data;- int ret = ARCHIVE_FAILED;-- if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: hdrcharset option needs a character-set name",- a->format_name);- else {- cpio->opt_sconv = archive_string_conversion_to_charset(- &a->archive, val, 0);- if (cpio->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--/*- * Ino values are as long as 64 bits on some systems; cpio format- * only allows 16 bits and relies on the ino values to identify hardlinked- * files. So, we can't merely "hash" the ino numbers since collisions- * would corrupt the archive. Instead, we generate synthetic ino values- * to store in the archive and maintain a map of original ino values to- * synthetic ones so we can preserve hardlink information.- *- * TODO: Make this more efficient. It's not as bad as it looks (most- * files don't have any hardlinks and we don't do any work here for those),- * but it wouldn't be hard to do better.- *- * TODO: Work with dev/ino pairs here instead of just ino values.- */-static int-synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)-{- int64_t ino = archive_entry_ino64(entry);- int ino_new;- size_t i;-- /*- * If no index number was given, don't assign one. In- * particular, this handles the end-of-archive marker- * correctly by giving it a zero index value. (This is also- * why we start our synthetic index numbers with one below.)- */- if (ino == 0)- return (0);-- /* Don't store a mapping if we don't need to. */- if (archive_entry_nlink(entry) < 2) {- return (int)(++cpio->ino_next);- }-- /* Look up old ino; if we have it, this is a hardlink- * and we reuse the same value. */- for (i = 0; i < cpio->ino_list_next; ++i) {- if (cpio->ino_list[i].old == ino)- return (cpio->ino_list[i].new);- }-- /* Assign a new index number. */- ino_new = (int)(++cpio->ino_next);-- /* Ensure space for the new mapping. */- if (cpio->ino_list_size <= cpio->ino_list_next) {- size_t newsize = cpio->ino_list_size < 512- ? 512 : cpio->ino_list_size * 2;- void *newlist = realloc(cpio->ino_list,- sizeof(cpio->ino_list[0]) * newsize);- if (newlist == NULL)- return (-1);-- cpio->ino_list_size = newsize;- cpio->ino_list = newlist;- }-- /* Record and return the new value. */- cpio->ino_list[cpio->ino_list_next].old = ino;- cpio->ino_list[cpio->ino_list_next].new = ino_new;- ++cpio->ino_list_next;- return (ino_new);-}---static struct archive_string_conv *-get_sconv(struct archive_write *a)-{- struct cpio *cpio;- struct archive_string_conv *sconv;-- cpio = (struct cpio *)a->format_data;- sconv = cpio->opt_sconv;- if (sconv == NULL) {- if (!cpio->init_default_conversion) {- cpio->sconv_default =- archive_string_default_conversion_for_write(- &(a->archive));- cpio->init_default_conversion = 1;- }- sconv = cpio->sconv_default;- }- return (sconv);-}--static int-archive_write_binary_header(struct archive_write *a, struct archive_entry *entry)-{- const char *path;- size_t len;-- if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {- archive_set_error(&a->archive, -1, "Filetype required");- return (ARCHIVE_FAILED);- }-- if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0- && errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- if (len == 0 || path == NULL || path[0] == '\0') {- archive_set_error(&a->archive, -1, "Pathname required");- return (ARCHIVE_FAILED);- }-- if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) {- archive_set_error(&a->archive, -1, "Size required");- return (ARCHIVE_FAILED);- }- return write_header(a, entry);-}--static int-write_header(struct archive_write *a, struct archive_entry *entry)-{- struct cpio *cpio;- const char *p, *path;- int pathlength, ret, ret_final;- int64_t ino;- struct cpio_binary_header h;- struct archive_string_conv *sconv;- struct archive_entry *entry_main;- size_t len;-- cpio = (struct cpio *)a->format_data;- ret_final = ARCHIVE_OK;- sconv = get_sconv(a);--#if defined(_WIN32) && !defined(__CYGWIN__)- /* Make sure the path separators in pathname, hardlink and symlink- * are all slash '/', not the Windows path separator '\'. */- entry_main = __la_win_entry_in_posix_pathseparator(entry);- if (entry_main == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ustar data");- return(ARCHIVE_FATAL);- }- if (entry != entry_main)- entry = entry_main;- else- entry_main = NULL;-#else- entry_main = NULL;-#endif-- ret = archive_entry_pathname_l(entry, &path, &len, sconv);- if (ret != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate pathname '%s' to %s",- archive_entry_pathname(entry),- archive_string_conversion_charset_name(sconv));- ret_final = ARCHIVE_WARN;- }- /* Include trailing null */- pathlength = (int)len + 1;-- h.h_magic = la_swap16(070707);- h.h_dev = la_swap16(archive_entry_dev(entry));-- ino = synthesize_ino_value(cpio, entry);- if (ino < 0) {- archive_set_error(&a->archive, ENOMEM,- "No memory for ino translation table");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- } else if (ino > 077777) {- archive_set_error(&a->archive, ERANGE,- "Too many files for this cpio format");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- h.h_ino = la_swap16((uint16_t)ino);-- h.h_mode = archive_entry_mode(entry);- if (((h.h_mode & AE_IFMT) == AE_IFSOCK) || ((h.h_mode & AE_IFMT) == AE_IFIFO)) {- archive_set_error(&a->archive, EINVAL,- "sockets and fifos cannot be represented in the binary cpio formats");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) {- if ((h.h_mode & AE_IFMT) == AE_IFLNK) {- archive_set_error(&a->archive, EINVAL,- "symbolic links cannot be represented in the PWB cpio format");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- /* we could turn off AE_IFREG here, but it does no harm, */- /* and allows v7 cpio to read the entry without confusion */- }- h.h_mode = la_swap16(h.h_mode);-- h.h_uid = la_swap16((uint16_t)archive_entry_uid(entry));- h.h_gid = la_swap16((uint16_t)archive_entry_gid(entry));- h.h_nlink = la_swap16((uint16_t)archive_entry_nlink(entry));-- if (archive_entry_filetype(entry) == AE_IFBLK- || archive_entry_filetype(entry) == AE_IFCHR)- h.h_majmin = la_swap16(archive_entry_rdev(entry));- else- h.h_majmin = 0;-- h.h_mtime = la_swap32((uint32_t)archive_entry_mtime(entry));- h.h_namesize = la_swap16(pathlength);-- /* Non-regular files don't store bodies. */- if (archive_entry_filetype(entry) != AE_IFREG)- archive_entry_set_size(entry, 0);-- /* Symlinks get the link written as the body of the entry. */- ret = archive_entry_symlink_l(entry, &p, &len, sconv);- if (ret != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s",- archive_entry_symlink(entry),- archive_string_conversion_charset_name(sconv));- ret_final = ARCHIVE_WARN;- }-- if (len > 0 && p != NULL && *p != '\0') {- if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) {- archive_set_error(&a->archive, EINVAL,- "symlinks are not supported by UNIX V6 or by PWB cpio");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- h.h_filesize = la_swap32((uint32_t)strlen(p)); /* symlink */- } else {- if ((a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) &&- (archive_entry_size(entry) > 256*256*256-1)) {- archive_set_error(&a->archive, ERANGE,- "File is too large for PWB binary cpio format.");- ret_final = ARCHIVE_FAILED;- goto exit_write_header;- } else if (archive_entry_size(entry) > INT32_MAX) {- archive_set_error(&a->archive, ERANGE,- "File is too large for binary cpio format.");- ret_final = ARCHIVE_FAILED;- goto exit_write_header;- }- h.h_filesize = la_swap32((uint32_t)archive_entry_size(entry)); /* file */- }-- ret = __archive_write_output(a, &h, HSIZE);- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }-- ret = __archive_write_output(a, path, pathlength);- if ((ret == ARCHIVE_OK) && ((pathlength % 2) != 0))- ret = __archive_write_nulls(a, 1);- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }-- cpio->entry_bytes_remaining = archive_entry_size(entry);- if ((cpio->entry_bytes_remaining % 2) != 0)- cpio->entry_bytes_remaining++;-- /* Write the symlink now. */- if (p != NULL && *p != '\0') {- ret = __archive_write_output(a, p, strlen(p));- if ((ret == ARCHIVE_OK) && ((strlen(p) % 2) != 0))- ret = __archive_write_nulls(a, 1);- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- }--exit_write_header:- archive_entry_free(entry_main);- return (ret_final);-}--static ssize_t-archive_write_binary_data(struct archive_write *a, const void *buff, size_t s)-{- struct cpio *cpio;- int ret;-- cpio = (struct cpio *)a->format_data;- if (s > cpio->entry_bytes_remaining)- s = (size_t)cpio->entry_bytes_remaining;-- ret = __archive_write_output(a, buff, s);- cpio->entry_bytes_remaining -= s;- if (ret >= 0)- return (s);- else- return (ret);-}--static int-archive_write_binary_close(struct archive_write *a)-{- int er;- struct archive_entry *trailer;-- trailer = archive_entry_new2(NULL);- /* nlink = 1 here for GNU cpio compat. */- archive_entry_set_nlink(trailer, 1);- archive_entry_set_size(trailer, 0);- archive_entry_set_pathname(trailer, "TRAILER!!!");- er = write_header(a, trailer);- archive_entry_free(trailer);- return (er);-}--static int-archive_write_binary_free(struct archive_write *a)-{- struct cpio *cpio;-- cpio = (struct cpio *)a->format_data;- free(cpio->ino_list);- free(cpio);- a->format_data = NULL;- return (ARCHIVE_OK);-}--static int-archive_write_binary_finish_entry(struct archive_write *a)-{- struct cpio *cpio;-- cpio = (struct cpio *)a->format_data;- return (__archive_write_nulls(a,- (size_t)cpio->entry_bytes_remaining));-}
− c/archive_write_set_format_cpio_newc.c
@@ -1,457 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2006 Rudolf Marek SYSGO s.r.o.- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio_newc.c 201160 2009-12-29 05:41:57Z 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--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--static ssize_t archive_write_newc_data(struct archive_write *,- const void *buff, size_t s);-static int archive_write_newc_close(struct archive_write *);-static int archive_write_newc_free(struct archive_write *);-static int archive_write_newc_finish_entry(struct archive_write *);-static int archive_write_newc_header(struct archive_write *,- struct archive_entry *);-static int archive_write_newc_options(struct archive_write *,- const char *, const char *);-static int format_hex(int64_t, void *, int);-static int64_t format_hex_recursive(int64_t, char *, int);-static int write_header(struct archive_write *, struct archive_entry *);--struct cpio {- uint64_t entry_bytes_remaining;- int padding;-- struct archive_string_conv *opt_sconv;- struct archive_string_conv *sconv_default;- int init_default_conversion;-};--#define c_magic_offset 0-#define c_magic_size 6-#define c_ino_offset 6-#define c_ino_size 8-#define c_mode_offset 14-#define c_mode_size 8-#define c_uid_offset 22-#define c_uid_size 8-#define c_gid_offset 30-#define c_gid_size 8-#define c_nlink_offset 38-#define c_nlink_size 8-#define c_mtime_offset 46-#define c_mtime_size 8-#define c_filesize_offset 54-#define c_filesize_size 8-#define c_devmajor_offset 62-#define c_devmajor_size 8-#define c_devminor_offset 70-#define c_devminor_size 8-#define c_rdevmajor_offset 78-#define c_rdevmajor_size 8-#define c_rdevminor_offset 86-#define c_rdevminor_size 8-#define c_namesize_offset 94-#define c_namesize_size 8-#define c_checksum_offset 102-#define c_checksum_size 8-#define c_header_size 110--/* Logic trick: difference between 'n' and next multiple of 4 */-#define PAD4(n) (3 & (1 + ~(n)))--/*- * Set output format to 'cpio' format.- */-int-archive_write_set_format_cpio_newc(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct cpio *cpio;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_newc");-- /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);-- cpio = (struct cpio *)calloc(1, sizeof(*cpio));- if (cpio == NULL) {- archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");- return (ARCHIVE_FATAL);- }- a->format_data = cpio;- a->format_name = "cpio";- a->format_options = archive_write_newc_options;- a->format_write_header = archive_write_newc_header;- a->format_write_data = archive_write_newc_data;- a->format_finish_entry = archive_write_newc_finish_entry;- a->format_close = archive_write_newc_close;- a->format_free = archive_write_newc_free;- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;- a->archive.archive_format_name = "SVR4 cpio nocrc";- return (ARCHIVE_OK);-}--static int-archive_write_newc_options(struct archive_write *a, const char *key,- const char *val)-{- struct cpio *cpio = (struct cpio *)a->format_data;- int ret = ARCHIVE_FAILED;-- if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: hdrcharset option needs a character-set name",- a->format_name);- else {- cpio->opt_sconv = archive_string_conversion_to_charset(- &a->archive, val, 0);- if (cpio->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static struct archive_string_conv *-get_sconv(struct archive_write *a)-{- struct cpio *cpio;- struct archive_string_conv *sconv;-- cpio = (struct cpio *)a->format_data;- sconv = cpio->opt_sconv;- if (sconv == NULL) {- if (!cpio->init_default_conversion) {- cpio->sconv_default =- archive_string_default_conversion_for_write(- &(a->archive));- cpio->init_default_conversion = 1;- }- sconv = cpio->sconv_default;- }- return (sconv);-}--static int-archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)-{- const char *path;- size_t len;-- if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {- archive_set_error(&a->archive, -1, "Filetype required");- return (ARCHIVE_FAILED);- }-- if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0- && errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- if (len == 0 || path == NULL || path[0] == '\0') {- archive_set_error(&a->archive, -1, "Pathname required");- return (ARCHIVE_FAILED);- }-- if (archive_entry_hardlink(entry) == NULL- && (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0)) {- archive_set_error(&a->archive, -1, "Size required");- return (ARCHIVE_FAILED);- }- return write_header(a, entry);-}--static int-write_header(struct archive_write *a, struct archive_entry *entry)-{- int64_t ino;- struct cpio *cpio;- const char *p, *path;- int pathlength, ret, ret_final;- char h[c_header_size];- struct archive_string_conv *sconv;- struct archive_entry *entry_main;- size_t len;- int pad;-- cpio = (struct cpio *)a->format_data;- ret_final = ARCHIVE_OK;- sconv = get_sconv(a);--#if defined(_WIN32) && !defined(__CYGWIN__)- /* Make sure the path separators in pathname, hardlink and symlink- * are all slash '/', not the Windows path separator '\'. */- entry_main = __la_win_entry_in_posix_pathseparator(entry);- if (entry_main == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ustar data");- return(ARCHIVE_FATAL);- }- if (entry != entry_main)- entry = entry_main;- else- entry_main = NULL;-#else- entry_main = NULL;-#endif-- ret = archive_entry_pathname_l(entry, &path, &len, sconv);- if (ret != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate pathname '%s' to %s",- archive_entry_pathname(entry),- archive_string_conversion_charset_name(sconv));- ret_final = ARCHIVE_WARN;- }- pathlength = (int)len + 1; /* Include trailing null. */-- memset(h, 0, c_header_size);- format_hex(0x070701, h + c_magic_offset, c_magic_size);- format_hex(archive_entry_devmajor(entry), h + c_devmajor_offset,- c_devmajor_size);- format_hex(archive_entry_devminor(entry), h + c_devminor_offset,- c_devminor_size);-- ino = archive_entry_ino64(entry);- if (ino > 0xffffffff) {- archive_set_error(&a->archive, ERANGE,- "large inode number truncated");- ret_final = ARCHIVE_WARN;- }-- /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */- format_hex(ino & 0xffffffff, h + c_ino_offset, c_ino_size);- format_hex(archive_entry_mode(entry), h + c_mode_offset, c_mode_size);- format_hex(archive_entry_uid(entry), h + c_uid_offset, c_uid_size);- format_hex(archive_entry_gid(entry), h + c_gid_offset, c_gid_size);- format_hex(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);- if (archive_entry_filetype(entry) == AE_IFBLK- || archive_entry_filetype(entry) == AE_IFCHR) {- format_hex(archive_entry_rdevmajor(entry), h + c_rdevmajor_offset, c_rdevmajor_size);- format_hex(archive_entry_rdevminor(entry), h + c_rdevminor_offset, c_rdevminor_size);- } else {- format_hex(0, h + c_rdevmajor_offset, c_rdevmajor_size);- format_hex(0, h + c_rdevminor_offset, c_rdevminor_size);- }- format_hex(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);- format_hex(pathlength, h + c_namesize_offset, c_namesize_size);- format_hex(0, h + c_checksum_offset, c_checksum_size);-- /* Non-regular files don't store bodies. */- if (archive_entry_filetype(entry) != AE_IFREG)- archive_entry_set_size(entry, 0);-- /* Symlinks get the link written as the body of the entry. */- ret = archive_entry_symlink_l(entry, &p, &len, sconv);- if (ret != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Likname");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s",- archive_entry_symlink(entry),- archive_string_conversion_charset_name(sconv));- ret_final = ARCHIVE_WARN;- }- if (len > 0 && p != NULL && *p != '\0')- ret = format_hex(strlen(p), h + c_filesize_offset,- c_filesize_size);- else- ret = format_hex(archive_entry_size(entry),- h + c_filesize_offset, c_filesize_size);- if (ret) {- archive_set_error(&a->archive, ERANGE,- "File is too large for this format.");- ret_final = ARCHIVE_FAILED;- goto exit_write_header;- }-- ret = __archive_write_output(a, h, c_header_size);- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }-- /* Pad pathname to even length. */- ret = __archive_write_output(a, path, pathlength);- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- pad = PAD4(pathlength + c_header_size);- if (pad) {- ret = __archive_write_output(a, "\0\0\0", pad);- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- }-- cpio->entry_bytes_remaining = archive_entry_size(entry);- cpio->padding = (int)PAD4(cpio->entry_bytes_remaining);-- /* Write the symlink now. */- if (p != NULL && *p != '\0') {- ret = __archive_write_output(a, p, strlen(p));- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- pad = PAD4(strlen(p));- ret = __archive_write_output(a, "\0\0\0", pad);- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- }-exit_write_header:- archive_entry_free(entry_main);- return (ret_final);-}--static ssize_t-archive_write_newc_data(struct archive_write *a, const void *buff, size_t s)-{- struct cpio *cpio;- int ret;-- cpio = (struct cpio *)a->format_data;- if (s > cpio->entry_bytes_remaining)- s = (size_t)cpio->entry_bytes_remaining;-- ret = __archive_write_output(a, buff, s);- cpio->entry_bytes_remaining -= s;- if (ret >= 0)- return (s);- else- return (ret);-}--/*- * Format a number into the specified field.- */-static int-format_hex(int64_t v, void *p, int digits)-{- int64_t max;- int ret;-- max = (((int64_t)1) << (digits * 4)) - 1;- if (v >= 0 && v <= max) {- format_hex_recursive(v, (char *)p, digits);- ret = 0;- } else {- format_hex_recursive(max, (char *)p, digits);- ret = -1;- }- return (ret);-}--static int64_t-format_hex_recursive(int64_t v, char *p, int s)-{- if (s == 0)- return (v);- v = format_hex_recursive(v, p+1, s-1);- *p = "0123456789abcdef"[v & 0xf];- return (v >> 4);-}--static int-archive_write_newc_close(struct archive_write *a)-{- int er;- struct archive_entry *trailer;-- trailer = archive_entry_new();- archive_entry_set_nlink(trailer, 1);- archive_entry_set_size(trailer, 0);- archive_entry_set_pathname(trailer, "TRAILER!!!");- /* Bypass the required data checks. */- er = write_header(a, trailer);- archive_entry_free(trailer);- return (er);-}--static int-archive_write_newc_free(struct archive_write *a)-{- struct cpio *cpio;-- cpio = (struct cpio *)a->format_data;- free(cpio);- a->format_data = NULL;- return (ARCHIVE_OK);-}--static int-archive_write_newc_finish_entry(struct archive_write *a)-{- struct cpio *cpio;-- cpio = (struct cpio *)a->format_data;- return (__archive_write_nulls(a,- (size_t)cpio->entry_bytes_remaining + cpio->padding));-}
− c/archive_write_set_format_cpio_odc.c
@@ -1,500 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z 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--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--static ssize_t archive_write_odc_data(struct archive_write *,- const void *buff, size_t s);-static int archive_write_odc_close(struct archive_write *);-static int archive_write_odc_free(struct archive_write *);-static int archive_write_odc_finish_entry(struct archive_write *);-static int archive_write_odc_header(struct archive_write *,- struct archive_entry *);-static int archive_write_odc_options(struct archive_write *,- const char *, const char *);-static int format_octal(int64_t, void *, int);-static int64_t format_octal_recursive(int64_t, char *, int);-static int write_header(struct archive_write *, struct archive_entry *);--struct cpio {- uint64_t entry_bytes_remaining;-- int64_t ino_next;-- struct { int64_t old; int new;} *ino_list;- size_t ino_list_size;- size_t ino_list_next;-- struct archive_string_conv *opt_sconv;- struct archive_string_conv *sconv_default;- int init_default_conversion;-};--#define c_magic_offset 0-#define c_magic_size 6-#define c_dev_offset 6-#define c_dev_size 6-#define c_ino_offset 12-#define c_ino_size 6-#define c_mode_offset 18-#define c_mode_size 6-#define c_uid_offset 24-#define c_uid_size 6-#define c_gid_offset 30-#define c_gid_size 6-#define c_nlink_offset 36-#define c_nlink_size 6-#define c_rdev_offset 42-#define c_rdev_size 6-#define c_mtime_offset 48-#define c_mtime_size 11-#define c_namesize_offset 59-#define c_namesize_size 6-#define c_filesize_offset 65-#define c_filesize_size 11--/*- * Set output format to 'cpio' format.- */-int-archive_write_set_format_cpio_odc(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct cpio *cpio;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_odc");-- /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);-- cpio = (struct cpio *)calloc(1, sizeof(*cpio));- if (cpio == NULL) {- archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");- return (ARCHIVE_FATAL);- }- a->format_data = cpio;- a->format_name = "cpio";- a->format_options = archive_write_odc_options;- a->format_write_header = archive_write_odc_header;- a->format_write_data = archive_write_odc_data;- a->format_finish_entry = archive_write_odc_finish_entry;- a->format_close = archive_write_odc_close;- a->format_free = archive_write_odc_free;- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;- a->archive.archive_format_name = "POSIX cpio";- return (ARCHIVE_OK);-}--static int-archive_write_odc_options(struct archive_write *a, const char *key,- const char *val)-{- struct cpio *cpio = (struct cpio *)a->format_data;- int ret = ARCHIVE_FAILED;-- if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: hdrcharset option needs a character-set name",- a->format_name);- else {- cpio->opt_sconv = archive_string_conversion_to_charset(- &a->archive, val, 0);- if (cpio->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--/*- * Ino values are as long as 64 bits on some systems; cpio format- * only allows 18 bits and relies on the ino values to identify hardlinked- * files. So, we can't merely "hash" the ino numbers since collisions- * would corrupt the archive. Instead, we generate synthetic ino values- * to store in the archive and maintain a map of original ino values to- * synthetic ones so we can preserve hardlink information.- *- * TODO: Make this more efficient. It's not as bad as it looks (most- * files don't have any hardlinks and we don't do any work here for those),- * but it wouldn't be hard to do better.- *- * TODO: Work with dev/ino pairs here instead of just ino values.- */-static int-synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)-{- int64_t ino = archive_entry_ino64(entry);- int ino_new;- size_t i;-- /*- * If no index number was given, don't assign one. In- * particular, this handles the end-of-archive marker- * correctly by giving it a zero index value. (This is also- * why we start our synthetic index numbers with one below.)- */- if (ino == 0)- return (0);-- /* Don't store a mapping if we don't need to. */- if (archive_entry_nlink(entry) < 2) {- return (int)(++cpio->ino_next);- }-- /* Look up old ino; if we have it, this is a hardlink- * and we reuse the same value. */- for (i = 0; i < cpio->ino_list_next; ++i) {- if (cpio->ino_list[i].old == ino)- return (cpio->ino_list[i].new);- }-- /* Assign a new index number. */- ino_new = (int)(++cpio->ino_next);-- /* Ensure space for the new mapping. */- if (cpio->ino_list_size <= cpio->ino_list_next) {- size_t newsize = cpio->ino_list_size < 512- ? 512 : cpio->ino_list_size * 2;- void *newlist = realloc(cpio->ino_list,- sizeof(cpio->ino_list[0]) * newsize);- if (newlist == NULL)- return (-1);-- cpio->ino_list_size = newsize;- cpio->ino_list = newlist;- }-- /* Record and return the new value. */- cpio->ino_list[cpio->ino_list_next].old = ino;- cpio->ino_list[cpio->ino_list_next].new = ino_new;- ++cpio->ino_list_next;- return (ino_new);-}---static struct archive_string_conv *-get_sconv(struct archive_write *a)-{- struct cpio *cpio;- struct archive_string_conv *sconv;-- cpio = (struct cpio *)a->format_data;- sconv = cpio->opt_sconv;- if (sconv == NULL) {- if (!cpio->init_default_conversion) {- cpio->sconv_default =- archive_string_default_conversion_for_write(- &(a->archive));- cpio->init_default_conversion = 1;- }- sconv = cpio->sconv_default;- }- return (sconv);-}--static int-archive_write_odc_header(struct archive_write *a, struct archive_entry *entry)-{- const char *path;- size_t len;-- if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {- archive_set_error(&a->archive, -1, "Filetype required");- return (ARCHIVE_FAILED);- }-- if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0- && errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- if (len == 0 || path == NULL || path[0] == '\0') {- archive_set_error(&a->archive, -1, "Pathname required");- return (ARCHIVE_FAILED);- }-- if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) {- archive_set_error(&a->archive, -1, "Size required");- return (ARCHIVE_FAILED);- }- return write_header(a, entry);-}--static int-write_header(struct archive_write *a, struct archive_entry *entry)-{- struct cpio *cpio;- const char *p, *path;- int pathlength, ret, ret_final;- int64_t ino;- char h[76];- struct archive_string_conv *sconv;- struct archive_entry *entry_main;- size_t len;-- cpio = (struct cpio *)a->format_data;- ret_final = ARCHIVE_OK;- sconv = get_sconv(a);--#if defined(_WIN32) && !defined(__CYGWIN__)- /* Make sure the path separators in pathname, hardlink and symlink- * are all slash '/', not the Windows path separator '\'. */- entry_main = __la_win_entry_in_posix_pathseparator(entry);- if (entry_main == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ustar data");- return(ARCHIVE_FATAL);- }- if (entry != entry_main)- entry = entry_main;- else- entry_main = NULL;-#else- entry_main = NULL;-#endif-- ret = archive_entry_pathname_l(entry, &path, &len, sconv);- if (ret != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate pathname '%s' to %s",- archive_entry_pathname(entry),- archive_string_conversion_charset_name(sconv));- ret_final = ARCHIVE_WARN;- }- /* Include trailing null. */- pathlength = (int)len + 1;-- memset(h, 0, sizeof(h));- format_octal(070707, h + c_magic_offset, c_magic_size);- format_octal(archive_entry_dev(entry), h + c_dev_offset, c_dev_size);-- ino = synthesize_ino_value(cpio, entry);- if (ino < 0) {- archive_set_error(&a->archive, ENOMEM,- "No memory for ino translation table");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- } else if (ino > 0777777) {- archive_set_error(&a->archive, ERANGE,- "Too many files for this cpio format");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- format_octal(ino & 0777777, h + c_ino_offset, c_ino_size);-- /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */- format_octal(archive_entry_mode(entry), h + c_mode_offset, c_mode_size);- format_octal(archive_entry_uid(entry), h + c_uid_offset, c_uid_size);- format_octal(archive_entry_gid(entry), h + c_gid_offset, c_gid_size);- format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);- if (archive_entry_filetype(entry) == AE_IFBLK- || archive_entry_filetype(entry) == AE_IFCHR)- format_octal(archive_entry_rdev(entry), h + c_rdev_offset, c_rdev_size);- else- format_octal(0, h + c_rdev_offset, c_rdev_size);- format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);- format_octal(pathlength, h + c_namesize_offset, c_namesize_size);-- /* Non-regular files don't store bodies. */- if (archive_entry_filetype(entry) != AE_IFREG)- archive_entry_set_size(entry, 0);-- /* Symlinks get the link written as the body of the entry. */- ret = archive_entry_symlink_l(entry, &p, &len, sconv);- if (ret != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s",- archive_entry_symlink(entry),- archive_string_conversion_charset_name(sconv));- ret_final = ARCHIVE_WARN;- }- if (len > 0 && p != NULL && *p != '\0')- ret = format_octal(strlen(p), h + c_filesize_offset,- c_filesize_size);- else- ret = format_octal(archive_entry_size(entry),- h + c_filesize_offset, c_filesize_size);- if (ret) {- archive_set_error(&a->archive, ERANGE,- "File is too large for cpio format.");- ret_final = ARCHIVE_FAILED;- goto exit_write_header;- }-- ret = __archive_write_output(a, h, sizeof(h));- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }-- ret = __archive_write_output(a, path, pathlength);- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }-- cpio->entry_bytes_remaining = archive_entry_size(entry);-- /* Write the symlink now. */- if (p != NULL && *p != '\0') {- ret = __archive_write_output(a, p, strlen(p));- if (ret != ARCHIVE_OK) {- ret_final = ARCHIVE_FATAL;- goto exit_write_header;- }- }-exit_write_header:- archive_entry_free(entry_main);- return (ret_final);-}--static ssize_t-archive_write_odc_data(struct archive_write *a, const void *buff, size_t s)-{- struct cpio *cpio;- int ret;-- cpio = (struct cpio *)a->format_data;- if (s > cpio->entry_bytes_remaining)- s = (size_t)cpio->entry_bytes_remaining;-- ret = __archive_write_output(a, buff, s);- cpio->entry_bytes_remaining -= s;- if (ret >= 0)- return (s);- else- return (ret);-}--/*- * Format a number into the specified field.- */-static int-format_octal(int64_t v, void *p, int digits)-{- int64_t max;- int ret;-- max = (((int64_t)1) << (digits * 3)) - 1;- if (v >= 0 && v <= max) {- format_octal_recursive(v, (char *)p, digits);- ret = 0;- } else {- format_octal_recursive(max, (char *)p, digits);- ret = -1;- }- return (ret);-}--static int64_t-format_octal_recursive(int64_t v, char *p, int s)-{- if (s == 0)- return (v);- v = format_octal_recursive(v, p+1, s-1);- *p = '0' + ((char)v & 7);- return (v >> 3);-}--static int-archive_write_odc_close(struct archive_write *a)-{- int er;- struct archive_entry *trailer;-- trailer = archive_entry_new2(NULL);- /* nlink = 1 here for GNU cpio compat. */- archive_entry_set_nlink(trailer, 1);- archive_entry_set_size(trailer, 0);- archive_entry_set_pathname(trailer, "TRAILER!!!");- er = write_header(a, trailer);- archive_entry_free(trailer);- return (er);-}--static int-archive_write_odc_free(struct archive_write *a)-{- struct cpio *cpio;-- cpio = (struct cpio *)a->format_data;- free(cpio->ino_list);- free(cpio);- a->format_data = NULL;- return (ARCHIVE_OK);-}--static int-archive_write_odc_finish_entry(struct archive_write *a)-{- struct cpio *cpio;-- cpio = (struct cpio *)a->format_data;- return (__archive_write_nulls(a,- (size_t)cpio->entry_bytes_remaining));-}
− c/archive_write_set_format_filter_by_ext.c
@@ -1,142 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2015 Okhotnikov Kirill- * 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_format_by_name.c 201168 2009-12-29 06:15:32Z kientzle $");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif--#include "archive.h"-#include "archive_private.h"--/* A table that maps names to functions. */-static const-struct { const char *name; int (*format)(struct archive *); int (*filter)(struct archive *); } names[] =-{- { ".7z", archive_write_set_format_7zip, archive_write_add_filter_none},- { ".zip", archive_write_set_format_zip, archive_write_add_filter_none},- { ".jar", archive_write_set_format_zip, archive_write_add_filter_none},- { ".cpio", archive_write_set_format_cpio, archive_write_add_filter_none},- { ".iso", archive_write_set_format_iso9660, archive_write_add_filter_none},-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)- { ".a", archive_write_set_format_ar_bsd, archive_write_add_filter_none},- { ".ar", archive_write_set_format_ar_bsd, archive_write_add_filter_none},-#else - { ".a", archive_write_set_format_ar_svr4, archive_write_add_filter_none},- { ".ar", archive_write_set_format_ar_svr4, archive_write_add_filter_none},-#endif - { ".tar", archive_write_set_format_pax_restricted, archive_write_add_filter_none},- { ".tgz", archive_write_set_format_pax_restricted, archive_write_add_filter_gzip},- { ".tar.gz", archive_write_set_format_pax_restricted, archive_write_add_filter_gzip},- { ".tar.bz2", archive_write_set_format_pax_restricted, archive_write_add_filter_bzip2},- { ".tar.xz", archive_write_set_format_pax_restricted, archive_write_add_filter_xz},- { NULL, NULL, NULL }-};--static -int cmpsuff(const char *str, const char *suffix)-{- size_t length_str, length_suffix;-- if ((str == NULL) || (suffix == NULL))- return -1;-- length_str = strlen(str);- length_suffix = strlen(suffix);-- if (length_str >= length_suffix) {- return strcmp(str + (length_str - length_suffix), suffix);- } else {- return -1;- }-}--static int get_array_index(const char *name)-{- int i;-- for (i = 0; names[i].name != NULL; i++) - {- if (cmpsuff(name, names[i].name) == 0)- return i;- } - return -1;- -}--int-archive_write_set_format_filter_by_ext(struct archive *a, const char *filename)-{- int names_index = get_array_index(filename);- - if (names_index >= 0)- { - int format_state = (names[names_index].format)(a);- if (format_state == ARCHIVE_OK)- return ((names[names_index].filter)(a));- else- return format_state;- } -- archive_set_error(a, EINVAL, "No such format '%s'", filename);- a->state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);-}--int-archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext)-{- int names_index = get_array_index(filename);- - if (names_index < 0)- names_index = get_array_index(def_ext);- - if (names_index >= 0)- { - int format_state = (names[names_index].format)(a);- if (format_state == ARCHIVE_OK)- return ((names[names_index].filter)(a));- else- return format_state;- } -- archive_set_error(a, EINVAL, "No such format '%s'", filename);- a->state = ARCHIVE_STATE_FATAL;- return (ARCHIVE_FATAL);-}----
− c/archive_write_set_format_gnutar.c
@@ -1,755 +0,0 @@-/*-- * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).- * Author: Jonas Gastal <jgastal@profusion.mobi>- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- *- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_gnu_tar.c 191579 2009-04-27 18:35:03Z gastal $");---#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--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--struct gnutar {- uint64_t entry_bytes_remaining;- uint64_t entry_padding;- const char * linkname;- size_t linkname_length;- const char * pathname;- size_t pathname_length;- const char * uname;- size_t uname_length;- const char * gname;- size_t gname_length;- struct archive_string_conv *opt_sconv;- struct archive_string_conv *sconv_default;- int init_default_conversion;-};--/*- * Define structure of GNU tar header.- */-#define GNUTAR_name_offset 0-#define GNUTAR_name_size 100-#define GNUTAR_mode_offset 100-#define GNUTAR_mode_size 7-#define GNUTAR_mode_max_size 8-#define GNUTAR_uid_offset 108-#define GNUTAR_uid_size 7-#define GNUTAR_uid_max_size 8-#define GNUTAR_gid_offset 116-#define GNUTAR_gid_size 7-#define GNUTAR_gid_max_size 8-#define GNUTAR_size_offset 124-#define GNUTAR_size_size 11-#define GNUTAR_size_max_size 12-#define GNUTAR_mtime_offset 136-#define GNUTAR_mtime_size 11-#define GNUTAR_mtime_max_size 11-#define GNUTAR_checksum_offset 148-#define GNUTAR_checksum_size 8-#define GNUTAR_typeflag_offset 156-#define GNUTAR_typeflag_size 1-#define GNUTAR_linkname_offset 157-#define GNUTAR_linkname_size 100-#define GNUTAR_magic_offset 257-#define GNUTAR_magic_size 6-#define GNUTAR_version_offset 263-#define GNUTAR_version_size 2-#define GNUTAR_uname_offset 265-#define GNUTAR_uname_size 32-#define GNUTAR_gname_offset 297-#define GNUTAR_gname_size 32-#define GNUTAR_rdevmajor_offset 329-#define GNUTAR_rdevmajor_size 6-#define GNUTAR_rdevmajor_max_size 8-#define GNUTAR_rdevminor_offset 337-#define GNUTAR_rdevminor_size 6-#define GNUTAR_rdevminor_max_size 8--/*- * A filled-in copy of the header for initialization.- */-static const char template_header[] = {- /* name: 100 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,- /* Mode, null termination: 8 bytes */- '0','0','0','0','0','0', '0','\0',- /* uid, null termination: 8 bytes */- '0','0','0','0','0','0', '0','\0',- /* gid, null termination: 8 bytes */- '0','0','0','0','0','0', '0','\0',- /* size, space termination: 12 bytes */- '0','0','0','0','0','0','0','0','0','0','0', '\0',- /* mtime, space termination: 12 bytes */- '0','0','0','0','0','0','0','0','0','0','0', '\0',- /* Initial checksum value: 8 spaces */- ' ',' ',' ',' ',' ',' ',' ',' ',- /* Typeflag: 1 byte */- '0', /* '0' = regular file */- /* Linkname: 100 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,- /* Magic: 8 bytes */- 'u','s','t','a','r',' ', ' ','\0',- /* Uname: 32 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- /* Gname: 32 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- /* rdevmajor + null padding: 8 bytes */- '\0','\0','\0','\0','\0','\0', '\0','\0',- /* rdevminor + null padding: 8 bytes */- '\0','\0','\0','\0','\0','\0', '\0','\0',- /* Padding: 167 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0-};--static int archive_write_gnutar_options(struct archive_write *,- const char *, const char *);-static int archive_format_gnutar_header(struct archive_write *, char h[512],- struct archive_entry *, int tartype);-static int archive_write_gnutar_header(struct archive_write *,- struct archive_entry *entry);-static ssize_t archive_write_gnutar_data(struct archive_write *a, const void *buff,- size_t s);-static int archive_write_gnutar_free(struct archive_write *);-static int archive_write_gnutar_close(struct archive_write *);-static int archive_write_gnutar_finish_entry(struct archive_write *);-static int format_256(int64_t, char *, int);-static int format_number(int64_t, char *, int size, int maxsize);-static int format_octal(int64_t, char *, int);--/*- * Set output format to 'GNU tar' format.- */-int-archive_write_set_format_gnutar(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct gnutar *gnutar;-- gnutar = (struct gnutar *)calloc(1, sizeof(*gnutar));- if (gnutar == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate gnutar data");- return (ARCHIVE_FATAL);- }- a->format_data = gnutar;- a->format_name = "gnutar";- a->format_options = archive_write_gnutar_options;- a->format_write_header = archive_write_gnutar_header;- a->format_write_data = archive_write_gnutar_data;- a->format_close = archive_write_gnutar_close;- a->format_free = archive_write_gnutar_free;- a->format_finish_entry = archive_write_gnutar_finish_entry;- a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;- a->archive.archive_format_name = "GNU tar";- return (ARCHIVE_OK);-}--static int-archive_write_gnutar_options(struct archive_write *a, const char *key,- const char *val)-{- struct gnutar *gnutar = (struct gnutar *)a->format_data;- int ret = ARCHIVE_FAILED;-- if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: hdrcharset option needs a character-set name",- a->format_name);- else {- gnutar->opt_sconv = archive_string_conversion_to_charset(- &a->archive, val, 0);- if (gnutar->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-archive_write_gnutar_close(struct archive_write *a)-{- return (__archive_write_nulls(a, 512*2));-}--static int-archive_write_gnutar_free(struct archive_write *a)-{- struct gnutar *gnutar;-- gnutar = (struct gnutar *)a->format_data;- free(gnutar);- a->format_data = NULL;- return (ARCHIVE_OK);-}--static int-archive_write_gnutar_finish_entry(struct archive_write *a)-{- struct gnutar *gnutar;- int ret;-- gnutar = (struct gnutar *)a->format_data;- ret = __archive_write_nulls(a, (size_t)- (gnutar->entry_bytes_remaining + gnutar->entry_padding));- gnutar->entry_bytes_remaining = gnutar->entry_padding = 0;- return (ret);-}--static ssize_t-archive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s)-{- struct gnutar *gnutar;- int ret;-- gnutar = (struct gnutar *)a->format_data;- if (s > gnutar->entry_bytes_remaining)- s = (size_t)gnutar->entry_bytes_remaining;- ret = __archive_write_output(a, buff, s);- gnutar->entry_bytes_remaining -= s;- if (ret != ARCHIVE_OK)- return (ret);- return (s);-}--static int-archive_write_gnutar_header(struct archive_write *a,- struct archive_entry *entry)-{- char buff[512];- int r, ret, ret2 = ARCHIVE_OK;- int tartype;- struct gnutar *gnutar;- struct archive_string_conv *sconv;- struct archive_entry *entry_main;-- gnutar = (struct gnutar *)a->format_data;-- /* Setup default string conversion. */- if (gnutar->opt_sconv == NULL) {- if (!gnutar->init_default_conversion) {- gnutar->sconv_default =- archive_string_default_conversion_for_write(- &(a->archive));- gnutar->init_default_conversion = 1;- }- sconv = gnutar->sconv_default;- } else- sconv = gnutar->opt_sconv;-- /* Only regular files (not hardlinks) have data. */- if (archive_entry_hardlink(entry) != NULL ||- archive_entry_symlink(entry) != NULL ||- !(archive_entry_filetype(entry) == AE_IFREG))- archive_entry_set_size(entry, 0);-- if (AE_IFDIR == archive_entry_filetype(entry)) {- const char *p;- size_t path_length;- /*- * Ensure a trailing '/'. Modify the entry so- * the client sees the change.- */-#if defined(_WIN32) && !defined(__CYGWIN__)- const wchar_t *wp;-- wp = archive_entry_pathname_w(entry);- if (wp != NULL && wp[wcslen(wp) -1] != L'/') {- struct archive_wstring ws;-- archive_string_init(&ws);- path_length = wcslen(wp);- if (archive_wstring_ensure(&ws,- path_length + 2) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ustar data");- archive_wstring_free(&ws);- return(ARCHIVE_FATAL);- }- /* Should we keep '\' ? */- if (wp[path_length -1] == L'\\')- path_length--;- archive_wstrncpy(&ws, wp, path_length);- archive_wstrappend_wchar(&ws, L'/');- archive_entry_copy_pathname_w(entry, ws.s);- archive_wstring_free(&ws);- p = NULL;- } else-#endif- p = archive_entry_pathname(entry);- /*- * On Windows, this is a backup operation just in- * case getting WCS failed. On POSIX, this is a- * normal operation.- */- if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {- struct archive_string as;-- archive_string_init(&as);- path_length = strlen(p);- if (archive_string_ensure(&as,- path_length + 2) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ustar data");- archive_string_free(&as);- return(ARCHIVE_FATAL);- }-#if defined(_WIN32) && !defined(__CYGWIN__)- /* NOTE: This might break the pathname- * if the current code page is CP932 and- * the pathname includes a character '\'- * as a part of its multibyte pathname. */- if (p[strlen(p) -1] == '\\')- path_length--;- else-#endif- archive_strncpy(&as, p, path_length);- archive_strappend_char(&as, '/');- archive_entry_copy_pathname(entry, as.s);- archive_string_free(&as);- }- }--#if defined(_WIN32) && !defined(__CYGWIN__)- /* Make sure the path separators in pathname, hardlink and symlink- * are all slash '/', not the Windows path separator '\'. */- entry_main = __la_win_entry_in_posix_pathseparator(entry);- if (entry_main == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ustar data");- return(ARCHIVE_FATAL);- }- if (entry != entry_main)- entry = entry_main;- else- entry_main = NULL;-#else- entry_main = NULL;-#endif- r = archive_entry_pathname_l(entry, &(gnutar->pathname),- &(gnutar->pathname_length), sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathame");- ret = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate pathname '%s' to %s",- archive_entry_pathname(entry),- archive_string_conversion_charset_name(sconv));- ret2 = ARCHIVE_WARN;- }- r = archive_entry_uname_l(entry, &(gnutar->uname),- &(gnutar->uname_length), sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Uname");- ret = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate uname '%s' to %s",- archive_entry_uname(entry),- archive_string_conversion_charset_name(sconv));- ret2 = ARCHIVE_WARN;- }- r = archive_entry_gname_l(entry, &(gnutar->gname),- &(gnutar->gname_length), sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Gname");- ret = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate gname '%s' to %s",- archive_entry_gname(entry),- archive_string_conversion_charset_name(sconv));- ret2 = ARCHIVE_WARN;- }-- /* If linkname is longer than 100 chars we need to add a 'K' header. */- r = archive_entry_hardlink_l(entry, &(gnutar->linkname),- &(gnutar->linkname_length), sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- ret = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s",- archive_entry_hardlink(entry),- archive_string_conversion_charset_name(sconv));- ret2 = ARCHIVE_WARN;- }- if (gnutar->linkname_length == 0) {- r = archive_entry_symlink_l(entry, &(gnutar->linkname),- &(gnutar->linkname_length), sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- ret = ARCHIVE_FATAL;- goto exit_write_header;- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s",- archive_entry_hardlink(entry),- archive_string_conversion_charset_name(sconv));- ret2 = ARCHIVE_WARN;- }- }- if (gnutar->linkname_length > GNUTAR_linkname_size) {- size_t length = gnutar->linkname_length + 1;- struct archive_entry *temp = archive_entry_new2(&a->archive);-- /* Uname/gname here don't really matter since no one reads them;- * these are the values that GNU tar happens to use on FreeBSD. */- archive_entry_set_uname(temp, "root");- archive_entry_set_gname(temp, "wheel");-- archive_entry_set_pathname(temp, "././@LongLink");- archive_entry_set_size(temp, length);- ret = archive_format_gnutar_header(a, buff, temp, 'K');- archive_entry_free(temp);- if (ret < ARCHIVE_WARN)- goto exit_write_header;- ret = __archive_write_output(a, buff, 512);- if (ret < ARCHIVE_WARN)- goto exit_write_header;- /* Write name and trailing null byte. */- ret = __archive_write_output(a, gnutar->linkname, length);- if (ret < ARCHIVE_WARN)- goto exit_write_header;- /* Pad to 512 bytes */- ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));- if (ret < ARCHIVE_WARN)- goto exit_write_header;- }-- /* If pathname is longer than 100 chars we need to add an 'L' header. */- if (gnutar->pathname_length > GNUTAR_name_size) {- const char *pathname = gnutar->pathname;- size_t length = gnutar->pathname_length + 1;- struct archive_entry *temp = archive_entry_new2(&a->archive);-- /* Uname/gname here don't really matter since no one reads them;- * these are the values that GNU tar happens to use on FreeBSD. */- archive_entry_set_uname(temp, "root");- archive_entry_set_gname(temp, "wheel");-- archive_entry_set_pathname(temp, "././@LongLink");- archive_entry_set_size(temp, length);- ret = archive_format_gnutar_header(a, buff, temp, 'L');- archive_entry_free(temp);- if (ret < ARCHIVE_WARN)- goto exit_write_header;- ret = __archive_write_output(a, buff, 512);- if(ret < ARCHIVE_WARN)- goto exit_write_header;- /* Write pathname + trailing null byte. */- ret = __archive_write_output(a, pathname, length);- if(ret < ARCHIVE_WARN)- goto exit_write_header;- /* Pad to multiple of 512 bytes. */- ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));- if (ret < ARCHIVE_WARN)- goto exit_write_header;- }-- if (archive_entry_hardlink(entry) != NULL) {- tartype = '1';- } else- switch (archive_entry_filetype(entry)) {- case AE_IFREG: tartype = '0' ; break;- case AE_IFLNK: tartype = '2' ; break;- case AE_IFCHR: tartype = '3' ; break;- case AE_IFBLK: tartype = '4' ; break;- case AE_IFDIR: tartype = '5' ; break;- case AE_IFIFO: tartype = '6' ; break;- default: /* AE_IFSOCK and unknown */- __archive_write_entry_filetype_unsupported(- &a->archive, entry, "gnutar");- ret = ARCHIVE_FAILED;- goto exit_write_header;- }-- ret = archive_format_gnutar_header(a, buff, entry, tartype);- if (ret < ARCHIVE_WARN)- goto exit_write_header;- if (ret2 < ret)- ret = ret2;- ret2 = __archive_write_output(a, buff, 512);- if (ret2 < ARCHIVE_WARN) {- ret = ret2;- goto exit_write_header;- }- if (ret2 < ret)- ret = ret2;-- gnutar->entry_bytes_remaining = archive_entry_size(entry);- gnutar->entry_padding = 0x1ff & (-(int64_t)gnutar->entry_bytes_remaining);-exit_write_header:- archive_entry_free(entry_main);- return (ret);-}--static int-archive_format_gnutar_header(struct archive_write *a, char h[512],- struct archive_entry *entry, int tartype)-{- unsigned int checksum;- int i, ret;- size_t copy_length;- const char *p;- struct gnutar *gnutar;-- gnutar = (struct gnutar *)a->format_data;-- ret = 0;-- /*- * The "template header" already includes the signature,- * various end-of-field markers, and other required elements.- */- memcpy(h, &template_header, 512);-- /*- * Because the block is already null-filled, and strings- * are allowed to exactly fill their destination (without null),- * I use memcpy(dest, src, strlen()) here a lot to copy strings.- */-- if (tartype == 'K' || tartype == 'L') {- p = archive_entry_pathname(entry);- copy_length = strlen(p);- } else {- p = gnutar->pathname;- copy_length = gnutar->pathname_length;- }- if (copy_length > GNUTAR_name_size)- copy_length = GNUTAR_name_size;- memcpy(h + GNUTAR_name_offset, p, copy_length);-- if ((copy_length = gnutar->linkname_length) > 0) {- if (copy_length > GNUTAR_linkname_size)- copy_length = GNUTAR_linkname_size;- memcpy(h + GNUTAR_linkname_offset, gnutar->linkname,- copy_length);- }-- /* TODO: How does GNU tar handle unames longer than GNUTAR_uname_size? */- if (tartype == 'K' || tartype == 'L') {- p = archive_entry_uname(entry);- copy_length = strlen(p);- } else {- p = gnutar->uname;- copy_length = gnutar->uname_length;- }- if (copy_length > 0) {- if (copy_length > GNUTAR_uname_size)- copy_length = GNUTAR_uname_size;- memcpy(h + GNUTAR_uname_offset, p, copy_length);- }-- /* TODO: How does GNU tar handle gnames longer than GNUTAR_gname_size? */- if (tartype == 'K' || tartype == 'L') {- p = archive_entry_gname(entry);- copy_length = strlen(p);- } else {- p = gnutar->gname;- copy_length = gnutar->gname_length;- }- if (copy_length > 0) {- if (strlen(p) > GNUTAR_gname_size)- copy_length = GNUTAR_gname_size;- memcpy(h + GNUTAR_gname_offset, p, copy_length);- }-- /* By truncating the mode here, we ensure it always fits. */- format_octal(archive_entry_mode(entry) & 07777,- h + GNUTAR_mode_offset, GNUTAR_mode_size);-- /* GNU tar supports base-256 here, so should never overflow. */- if (format_number(archive_entry_uid(entry), h + GNUTAR_uid_offset,- GNUTAR_uid_size, GNUTAR_uid_max_size)) {- archive_set_error(&a->archive, ERANGE,- "Numeric user ID %jd too large",- (intmax_t)archive_entry_uid(entry));- ret = ARCHIVE_FAILED;- }-- /* GNU tar supports base-256 here, so should never overflow. */- if (format_number(archive_entry_gid(entry), h + GNUTAR_gid_offset,- GNUTAR_gid_size, GNUTAR_gid_max_size)) {- archive_set_error(&a->archive, ERANGE,- "Numeric group ID %jd too large",- (intmax_t)archive_entry_gid(entry));- ret = ARCHIVE_FAILED;- }-- /* GNU tar supports base-256 here, so should never overflow. */- if (format_number(archive_entry_size(entry), h + GNUTAR_size_offset,- GNUTAR_size_size, GNUTAR_size_max_size)) {- archive_set_error(&a->archive, ERANGE,- "File size out of range");- ret = ARCHIVE_FAILED;- }-- /* Shouldn't overflow before 2106, since mtime field is 33 bits. */- format_octal(archive_entry_mtime(entry),- h + GNUTAR_mtime_offset, GNUTAR_mtime_size);-- if (archive_entry_filetype(entry) == AE_IFBLK- || archive_entry_filetype(entry) == AE_IFCHR) {- if (format_octal(archive_entry_rdevmajor(entry),- h + GNUTAR_rdevmajor_offset,- GNUTAR_rdevmajor_size)) {- archive_set_error(&a->archive, ERANGE,- "Major device number too large");- ret = ARCHIVE_FAILED;- }-- if (format_octal(archive_entry_rdevminor(entry),- h + GNUTAR_rdevminor_offset,- GNUTAR_rdevminor_size)) {- archive_set_error(&a->archive, ERANGE,- "Minor device number too large");- ret = ARCHIVE_FAILED;- }- }-- h[GNUTAR_typeflag_offset] = tartype;-- checksum = 0;- for (i = 0; i < 512; i++)- checksum += 255 & (unsigned int)h[i];- h[GNUTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */- /* h[GNUTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */- format_octal(checksum, h + GNUTAR_checksum_offset, 6);- return (ret);-}--/*- * Format a number into a field, falling back to base-256 if necessary.- */-static int-format_number(int64_t v, char *p, int s, int maxsize)-{- int64_t limit = ((int64_t)1 << (s*3));-- if (v < limit)- return (format_octal(v, p, s));- return (format_256(v, p, maxsize));-}--/*- * Format a number into the specified field using base-256.- */-static int-format_256(int64_t v, char *p, int s)-{- p += s;- while (s-- > 0) {- *--p = (char)(v & 0xff);- v >>= 8;- }- *p |= 0x80; /* Set the base-256 marker bit. */- return (0);-}--/*- * Format a number into the specified field using octal.- */-static int-format_octal(int64_t v, char *p, int s)-{- int len = s;-- /* Octal values can't be negative, so use 0. */- if (v < 0)- v = 0;-- p += s; /* Start at the end and work backwards. */- while (s-- > 0) {- *--p = (char)('0' + (v & 7));- v >>= 3;- }-- if (v == 0)- return (0);-- /* If it overflowed, fill field with max value. */- while (len-- > 0)- *p++ = '7';-- return (-1);-}
− c/archive_write_set_format_iso9660.c
@@ -1,8161 +0,0 @@-/*-- * Copyright (c) 2009-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#ifdef HAVE_SYS_UTSNAME_H-#include <sys/utsname.h>-#endif-#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#include <stdio.h>-#include <stdarg.h>-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#include <time.h>-#ifdef HAVE_UNISTD_H-#include <unistd.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif--#include "archive.h"-#include "archive_endian.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_rb.h"-#include "archive_write_private.h"--#if defined(_WIN32) && !defined(__CYGWIN__)-#define getuid() 0-#define getgid() 0-#endif--/*#define DEBUG 1*/-#ifdef DEBUG-/* To compare to the ISO image file made by mkisofs. */-#define COMPAT_MKISOFS 1-#endif--#define LOGICAL_BLOCK_BITS 11-#define LOGICAL_BLOCK_SIZE 2048-#define PATH_TABLE_BLOCK_SIZE 4096--#define SYSTEM_AREA_BLOCK 16-#define PRIMARY_VOLUME_DESCRIPTOR_BLOCK 1-#define SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK 1-#define BOOT_RECORD_DESCRIPTOR_BLOCK 1-#define VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK 1-#define NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK 1-#define RRIP_ER_BLOCK 1-#define PADDING_BLOCK 150--#define FD_1_2M_SIZE (1024 * 1200)-#define FD_1_44M_SIZE (1024 * 1440)-#define FD_2_88M_SIZE (1024 * 2880)-#define MULTI_EXTENT_SIZE (ARCHIVE_LITERAL_LL(1) << 32) /* 4Gi bytes. */-#define MAX_DEPTH 8-#define RR_CE_SIZE 28 /* SUSP "CE" extension size */--#define FILE_FLAG_EXISTENCE 0x01-#define FILE_FLAG_DIRECTORY 0x02-#define FILE_FLAG_ASSOCIATED 0x04-#define FILE_FLAG_RECORD 0x08-#define FILE_FLAG_PROTECTION 0x10-#define FILE_FLAG_MULTI_EXTENT 0x80--static const char rrip_identifier[] =- "RRIP_1991A";-static const char rrip_descriptor[] =- "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR "- "POSIX FILE SYSTEM SEMANTICS";-static const char rrip_source[] =- "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. "- "SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR "- "CONTACT INFORMATION.";-#define RRIP_ER_ID_SIZE (sizeof(rrip_identifier)-1)-#define RRIP_ER_DSC_SIZE (sizeof(rrip_descriptor)-1)-#define RRIP_ER_SRC_SIZE (sizeof(rrip_source)-1)-#define RRIP_ER_SIZE (8 + RRIP_ER_ID_SIZE + \- RRIP_ER_DSC_SIZE + RRIP_ER_SRC_SIZE)--static const unsigned char zisofs_magic[8] = {- 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07-};--#define ZF_HEADER_SIZE 16 /* zisofs header size. */-#define ZF_LOG2_BS 15 /* log2 block size; 32K bytes. */-#define ZF_BLOCK_SIZE (1UL << ZF_LOG2_BS)--/*- * Manage extra records.- */-struct extr_rec {- int location;- int offset;- unsigned char buf[LOGICAL_BLOCK_SIZE];- struct extr_rec *next;-};--struct ctl_extr_rec {- int use_extr;- unsigned char *bp;- struct isoent *isoent;- unsigned char *ce_ptr;- int cur_len;- int dr_len;- int limit;- int extr_off;- int extr_loc;-};-#define DR_SAFETY RR_CE_SIZE-#define DR_LIMIT (254 - DR_SAFETY)--/*- * The relation of struct isofile and isoent and archive_entry.- *- * Primary volume tree --> struct isoent- * |- * v- * struct isofile --> archive_entry- * ^- * |- * Joliet volume tree --> struct isoent- *- * struct isoent has specific information for volume.- */--struct isofile {- /* Used for managing struct isofile list. */- struct isofile *allnext;- struct isofile *datanext;- /* Used for managing a hardlinked struct isofile list. */- struct isofile *hlnext;- struct isofile *hardlink_target;-- struct archive_entry *entry;-- /*- * Used for making a directory tree.- */- struct archive_string parentdir;- struct archive_string basename;- struct archive_string basename_utf16;- struct archive_string symlink;- int dircnt; /* The number of elements of- * its parent directory */-- /*- * Used for a Directory Record.- */- struct content {- int64_t offset_of_temp;- int64_t size;- int blocks;- uint32_t location;- /*- * One extent equals one content.- * If this entry has multi extent, `next' variable points- * next content data.- */- struct content *next; /* next content */- } content, *cur_content;- int write_content;-- enum {- NO = 0,- BOOT_CATALOG,- BOOT_IMAGE- } boot;-- /*- * Used for a zisofs.- */- struct {- unsigned char header_size;- unsigned char log2_bs;- uint32_t uncompressed_size;- } zisofs;-};--struct isoent {- /* Keep `rbnode' at the first member of struct isoent. */- struct archive_rb_node rbnode;-- struct isofile *file;-- struct isoent *parent;- /* A list of children.(use chnext) */- struct {- struct isoent *first;- struct isoent **last;- int cnt;- } children;- struct archive_rb_tree rbtree;-- /* A list of sub directories.(use drnext) */- struct {- struct isoent *first;- struct isoent **last;- int cnt;- } subdirs;- /* A sorted list of sub directories. */- struct isoent **children_sorted;- /* Used for managing struct isoent list. */- struct isoent *chnext;- struct isoent *drnext;- struct isoent *ptnext;-- /*- * Used for making a Directory Record.- */- int dir_number;- struct {- int vd;- int self;- int parent;- int normal;- } dr_len;- uint32_t dir_location;- int dir_block;-- /*- * Identifier:- * on primary, ISO9660 file/directory name.- * on joliet, UCS2 file/directory name.- * ext_off : offset of identifier extension.- * ext_len : length of identifier extension.- * id_len : byte size of identifier.- * on primary, this is ext_off + ext_len + version length.- * on joliet, this is ext_off + ext_len.- * mb_len : length of multibyte-character of identifier.- * on primary, mb_len and id_len are always the same.- * on joliet, mb_len and id_len are different.- */- char *identifier;- int ext_off;- int ext_len;- int id_len;- int mb_len;-- /*- * Used for making a Rockridge extension.- * This is a part of Directory Records.- */- struct isoent *rr_parent;- struct isoent *rr_child;-- /* Extra Record.(which we call in this source file)- * A maximum size of the Directory Record is 254.- * so, if generated RRIP data of a file cannot into a Directory- * Record because of its size, that surplus data relocate this- * Extra Record.- */- struct {- struct extr_rec *first;- struct extr_rec **last;- struct extr_rec *current;- } extr_rec_list;-- unsigned int virtual:1;- /* If set to one, this file type is a directory.- * A convenience flag to be used as- * "archive_entry_filetype(isoent->file->entry) == AE_IFDIR".- */- unsigned int dir:1;-};--struct hardlink {- struct archive_rb_node rbnode;- int nlink;- struct {- struct isofile *first;- struct isofile **last;- } file_list;-};--/*- * ISO writer options- */-struct iso_option {- /*- * Usage : abstract-file=<value>- * Type : string, max 37 bytes- * Default: Not specified- * COMPAT : mkisofs -abstract <value>- *- * Specifies Abstract Filename.- * This file shall be described in the Root Directory- * and containing a abstract statement.- */- unsigned int abstract_file:1;-#define OPT_ABSTRACT_FILE_DEFAULT 0 /* Not specified */-#define ABSTRACT_FILE_SIZE 37-- /*- * Usage : application-id=<value>- * Type : string, max 128 bytes- * Default: Not specified- * COMPAT : mkisofs -A/-appid <value>.- *- * Specifies Application Identifier.- * If the first byte is set to '_'(5F), the remaining- * bytes of this option shall specify an identifier- * for a file containing the identification of the- * application.- * This file shall be described in the Root Directory.- */- unsigned int application_id:1;-#define OPT_APPLICATION_ID_DEFAULT 0 /* Use default identifier */-#define APPLICATION_IDENTIFIER_SIZE 128-- /*- * Usage : !allow-vernum- * Type : boolean- * Default: Enabled- * : Violates the ISO9660 standard if disable.- * COMPAT: mkisofs -N- *- * Allow filenames to use version numbers.- */- unsigned int allow_vernum:1;-#define OPT_ALLOW_VERNUM_DEFAULT 1 /* Enabled */-- /*- * Usage : biblio-file=<value>- * Type : string, max 37 bytes- * Default: Not specified- * COMPAT : mkisofs -biblio <value>- *- * Specifies Bibliographic Filename.- * This file shall be described in the Root Directory- * and containing bibliographic records.- */- unsigned int biblio_file:1;-#define OPT_BIBLIO_FILE_DEFAULT 0 /* Not specified */-#define BIBLIO_FILE_SIZE 37-- /*- * Usage : boot=<value>- * Type : string- * Default: Not specified- * COMPAT : mkisofs -b/-eltorito-boot <value>- *- * Specifies "El Torito" boot image file to make- * a bootable CD.- */- unsigned int boot:1;-#define OPT_BOOT_DEFAULT 0 /* Not specified */-- /*- * Usage : boot-catalog=<value>- * Type : string- * Default: "boot.catalog"- * COMPAT : mkisofs -c/-eltorito-catalog <value>- *- * Specifies a fullpath of El Torito boot catalog.- */- unsigned int boot_catalog:1;-#define OPT_BOOT_CATALOG_DEFAULT 0 /* Not specified */-- /*- * Usage : boot-info-table- * Type : boolean- * Default: Disabled- * COMPAT : mkisofs -boot-info-table- *- * Modify the boot image file specified by `boot'- * option; ISO writer stores boot file information- * into the boot file in ISO image at offset 8- * through offset 64.- */- unsigned int boot_info_table:1;-#define OPT_BOOT_INFO_TABLE_DEFAULT 0 /* Disabled */-- /*- * Usage : boot-load-seg=<value>- * Type : hexadecimal- * Default: Not specified- * COMPAT : mkisofs -boot-load-seg <value>- *- * Specifies a load segment for boot image.- * This is used with no-emulation mode.- */- unsigned int boot_load_seg:1;-#define OPT_BOOT_LOAD_SEG_DEFAULT 0 /* Not specified */-- /*- * Usage : boot-load-size=<value>- * Type : decimal- * Default: Not specified- * COMPAT : mkisofs -boot-load-size <value>- *- * Specifies a sector count for boot image.- * This is used with no-emulation mode.- */- unsigned int boot_load_size:1;-#define OPT_BOOT_LOAD_SIZE_DEFAULT 0 /* Not specified */-- /*- * Usage : boot-type=<boot-media-type>- * : 'no-emulation' : 'no emulation' image- * : 'fd' : floppy disk image- * : 'hard-disk' : hard disk image- * Type : string- * Default: Auto detect- * : We check a size of boot image;- * : If the size is just 1.22M/1.44M/2.88M,- * : we assume boot_type is 'fd';- * : otherwise boot_type is 'no-emulation'.- * COMPAT :- * boot=no-emulation- * mkisofs -no-emul-boot- * boot=fd- * This is a default on the mkisofs.- * boot=hard-disk- * mkisofs -hard-disk-boot- *- * Specifies a type of "El Torito" boot image.- */- unsigned int boot_type:2;-#define OPT_BOOT_TYPE_AUTO 0 /* auto detect */-#define OPT_BOOT_TYPE_NO_EMU 1 /* ``no emulation'' image */-#define OPT_BOOT_TYPE_FD 2 /* floppy disk image */-#define OPT_BOOT_TYPE_HARD_DISK 3 /* hard disk image */-#define OPT_BOOT_TYPE_DEFAULT OPT_BOOT_TYPE_AUTO-- /*- * Usage : compression-level=<value>- * Type : decimal- * Default: Not specified- * COMPAT : NONE- *- * Specifies compression level for option zisofs=direct.- */- unsigned int compression_level:1;-#define OPT_COMPRESSION_LEVEL_DEFAULT 0 /* Not specified */-- /*- * Usage : copyright-file=<value>- * Type : string, max 37 bytes- * Default: Not specified- * COMPAT : mkisofs -copyright <value>- *- * Specifies Copyright Filename.- * This file shall be described in the Root Directory- * and containing a copyright statement.- */- unsigned int copyright_file:1;-#define OPT_COPYRIGHT_FILE_DEFAULT 0 /* Not specified */-#define COPYRIGHT_FILE_SIZE 37-- /*- * Usage : gid=<value>- * Type : decimal- * Default: Not specified- * COMPAT : mkisofs -gid <value>- *- * Specifies a group id to rewrite the group id of all files.- */- unsigned int gid:1;-#define OPT_GID_DEFAULT 0 /* Not specified */-- /*- * Usage : iso-level=[1234]- * Type : decimal- * Default: 1- * COMPAT : mkisofs -iso-level <value>- *- * Specifies ISO9600 Level.- * Level 1: [DEFAULT]- * - limits each file size less than 4Gi bytes;- * - a File Name shall not contain more than eight- * d-characters or eight d1-characters;- * - a File Name Extension shall not contain more than- * three d-characters or three d1-characters;- * - a Directory Identifier shall not contain more- * than eight d-characters or eight d1-characters.- * Level 2:- * - limits each file size less than 4Giga bytes;- * - a File Name shall not contain more than thirty- * d-characters or thirty d1-characters;- * - a File Name Extension shall not contain more than- * thirty d-characters or thirty d1-characters;- * - a Directory Identifier shall not contain more- * than thirty-one d-characters or thirty-one- * d1-characters.- * Level 3:- * - no limit of file size; use multi extent.- * Level 4:- * - this level 4 simulates mkisofs option- * '-iso-level 4';- * - crate a enhanced volume as mkisofs doing;- * - allow a File Name to have leading dot;- * - allow a File Name to have all ASCII letters;- * - allow a File Name to have multiple dots;- * - allow more then 8 depths of directory trees;- * - disable a version number to a File Name;- * - disable a forced period to the tail of a File Name;- * - the maximum length of files and directories is raised to 193.- * if rockridge option is disabled, raised to 207.- */- unsigned int iso_level:3;-#define OPT_ISO_LEVEL_DEFAULT 1 /* ISO Level 1 */-- /*- * Usage : joliet[=long]- * : !joliet- * : Do not generate Joliet Volume and Records.- * : joliet [DEFAULT]- * : Generates Joliet Volume and Directory Records.- * : [COMPAT: mkisofs -J/-joliet]- * : joliet=long- * : The joliet filenames are up to 103 Unicode- * : characters.- * : This option breaks the Joliet specification.- * : [COMPAT: mkisofs -J -joliet-long]- * Type : boolean/string- * Default: Enabled- * COMPAT : mkisofs -J / -joliet-long- *- * Generates Joliet Volume and Directory Records.- */- unsigned int joliet:2;-#define OPT_JOLIET_DISABLE 0 /* Not generate Joliet Records. */-#define OPT_JOLIET_ENABLE 1 /* Generate Joliet Records. */-#define OPT_JOLIET_LONGNAME 2 /* Use long joliet filenames.*/-#define OPT_JOLIET_DEFAULT OPT_JOLIET_ENABLE-- /*- * Usage : !limit-depth- * Type : boolean- * Default: Enabled- * : Violates the ISO9660 standard if disable.- * COMPAT : mkisofs -D/-disable-deep-relocation- *- * The number of levels in hierarchy cannot exceed eight.- */- unsigned int limit_depth:1;-#define OPT_LIMIT_DEPTH_DEFAULT 1 /* Enabled */-- /*- * Usage : !limit-dirs- * Type : boolean- * Default: Enabled- * : Violates the ISO9660 standard if disable.- * COMPAT : mkisofs -no-limit-pathtables- *- * Limits the number of directories less than 65536 due- * to the size of the Parent Directory Number of Path- * Table.- */- unsigned int limit_dirs:1;-#define OPT_LIMIT_DIRS_DEFAULT 1 /* Enabled */-- /*- * Usage : !pad- * Type : boolean- * Default: Enabled- * COMPAT : -pad/-no-pad- *- * Pads the end of the ISO image by null of 300Ki bytes.- */- unsigned int pad:1;-#define OPT_PAD_DEFAULT 1 /* Enabled */-- /*- * Usage : publisher=<value>- * Type : string, max 128 bytes- * Default: Not specified- * COMPAT : mkisofs -publisher <value>- *- * Specifies Publisher Identifier.- * If the first byte is set to '_'(5F), the remaining- * bytes of this option shall specify an identifier- * for a file containing the identification of the user.- * This file shall be described in the Root Directory.- */- unsigned int publisher:1;-#define OPT_PUBLISHER_DEFAULT 0 /* Not specified */-#define PUBLISHER_IDENTIFIER_SIZE 128-- /*- * Usage : rockridge- * : !rockridge- * : disable to generate SUSP and RR records.- * : rockridge- * : the same as 'rockridge=useful'.- * : rockridge=strict- * : generate SUSP and RR records.- * : [COMPAT: mkisofs -R]- * : rockridge=useful [DEFAULT]- * : generate SUSP and RR records.- * : [COMPAT: mkisofs -r]- * : NOTE Our rockridge=useful option does not set a zero- * : to uid and gid, you should use application- * : option such as --gid,--gname,--uid and --uname- * : bsdtar options instead.- * Type : boolean/string- * Default: Enabled as rockridge=useful- * COMPAT : mkisofs -r / -R- *- * Generates SUSP and RR records.- */- unsigned int rr:2;-#define OPT_RR_DISABLED 0-#define OPT_RR_STRICT 1-#define OPT_RR_USEFUL 2-#define OPT_RR_DEFAULT OPT_RR_USEFUL-- /*- * Usage : volume-id=<value>- * Type : string, max 32 bytes- * Default: Not specified- * COMPAT : mkisofs -V <value>- *- * Specifies Volume Identifier.- */- unsigned int volume_id:1;-#define OPT_VOLUME_ID_DEFAULT 0 /* Use default identifier */-#define VOLUME_IDENTIFIER_SIZE 32-- /*- * Usage : !zisofs [DEFAULT]- * : Disable to generate RRIP 'ZF' extension.- * : zisofs- * : Make files zisofs file and generate RRIP 'ZF'- * : extension. So you do not need mkzftree utility- * : for making zisofs.- * : When the file size is less than one Logical Block- * : size, that file will not zisofs'ed since it does- * : reduce an ISO-image size.- * :- * : When you specify option 'boot=<boot-image>', that- * : 'boot-image' file won't be converted to zisofs file.- * Type : boolean- * Default: Disabled- *- * Generates RRIP 'ZF' System Use Entry.- */- unsigned int zisofs:1;-#define OPT_ZISOFS_DISABLED 0-#define OPT_ZISOFS_DIRECT 1-#define OPT_ZISOFS_DEFAULT OPT_ZISOFS_DISABLED--};--struct iso9660 {- /* The creation time of ISO image. */- time_t birth_time;- /* A file stream of a temporary file, which file contents- * save to until ISO image can be created. */- int temp_fd;-- struct isofile *cur_file;- struct isoent *cur_dirent;- struct archive_string cur_dirstr;- uint64_t bytes_remaining;- int need_multi_extent;-- /* Temporary string buffer for Joliet extension. */- struct archive_string utf16be;- struct archive_string mbs;-- struct archive_string_conv *sconv_to_utf16be;- struct archive_string_conv *sconv_from_utf16be;-- /* A list of all of struct isofile entries. */- struct {- struct isofile *first;- struct isofile **last;- } all_file_list;-- /* A list of struct isofile entries which have its- * contents and are not a directory, a hardlinked file- * and a symlink file. */- struct {- struct isofile *first;- struct isofile **last;- } data_file_list;-- /* Used for managing to find hardlinking files. */- struct archive_rb_tree hardlink_rbtree;-- /* Used for making the Path Table Record. */- struct vdd {- /* the root of entry tree. */- struct isoent *rootent;- enum vdd_type {- VDD_PRIMARY,- VDD_JOLIET,- VDD_ENHANCED- } vdd_type;-- struct path_table {- struct isoent *first;- struct isoent **last;- struct isoent **sorted;- int cnt;- } *pathtbl;- int max_depth;-- int path_table_block;- int path_table_size;- int location_type_L_path_table;- int location_type_M_path_table;- int total_dir_block;- } primary, joliet;-- /* Used for making a Volume Descriptor. */- int volume_space_size;- int volume_sequence_number;- int total_file_block;- struct archive_string volume_identifier;- struct archive_string publisher_identifier;- struct archive_string data_preparer_identifier;- struct archive_string application_identifier;- struct archive_string copyright_file_identifier;- struct archive_string abstract_file_identifier;- struct archive_string bibliographic_file_identifier;-- /* Used for making rockridge extensions. */- int location_rrip_er;-- /* Used for making zisofs. */- struct {- unsigned int detect_magic:1;- unsigned int making:1;- unsigned int allzero:1;- unsigned char magic_buffer[64];- int magic_cnt;--#ifdef HAVE_ZLIB_H- /*- * Copy a compressed file to iso9660.zisofs.temp_fd- * and also copy a uncompressed file(original file) to- * iso9660.temp_fd . If the number of logical block- * of the compressed file is less than the number of- * logical block of the uncompressed file, use it and- * remove the copy of the uncompressed file.- * but if not, we use uncompressed file and remove- * the copy of the compressed file.- */- uint32_t *block_pointers;- size_t block_pointers_allocated;- int block_pointers_cnt;- int block_pointers_idx;- int64_t total_size;- int64_t block_offset;-- z_stream stream;- int stream_valid;- int64_t remaining;- int compression_level;-#endif- } zisofs;-- struct isoent *directories_too_deep;- int dircnt_max;-- /* Write buffer. */-#define wb_buffmax() (LOGICAL_BLOCK_SIZE * 32)-#define wb_remaining(a) (((struct iso9660 *)(a)->format_data)->wbuff_remaining)-#define wb_offset(a) (((struct iso9660 *)(a)->format_data)->wbuff_offset \- + wb_buffmax() - wb_remaining(a))- unsigned char wbuff[LOGICAL_BLOCK_SIZE * 32];- size_t wbuff_remaining;- enum {- WB_TO_STREAM,- WB_TO_TEMP- } wbuff_type;- int64_t wbuff_offset;- int64_t wbuff_written;- int64_t wbuff_tail;-- /* 'El Torito' boot data. */- struct {- /* boot catalog file */- struct archive_string catalog_filename;- struct isoent *catalog;- /* boot image file */- struct archive_string boot_filename;- struct isoent *boot;-- unsigned char platform_id;-#define BOOT_PLATFORM_X86 0-#define BOOT_PLATFORM_PPC 1-#define BOOT_PLATFORM_MAC 2- struct archive_string id;- unsigned char media_type;-#define BOOT_MEDIA_NO_EMULATION 0-#define BOOT_MEDIA_1_2M_DISKETTE 1-#define BOOT_MEDIA_1_44M_DISKETTE 2-#define BOOT_MEDIA_2_88M_DISKETTE 3-#define BOOT_MEDIA_HARD_DISK 4- unsigned char system_type;- uint16_t boot_load_seg;- uint16_t boot_load_size;-#define BOOT_LOAD_SIZE 4- } el_torito;-- struct iso_option opt;-};--/*- * Types of Volume Descriptor- */-enum VD_type {- VDT_BOOT_RECORD=0, /* Boot Record Volume Descriptor */- VDT_PRIMARY=1, /* Primary Volume Descriptor */- VDT_SUPPLEMENTARY=2, /* Supplementary Volume Descriptor */- VDT_TERMINATOR=255 /* Volume Descriptor Set Terminator */-};--/*- * Types of Directory Record- */-enum dir_rec_type {- DIR_REC_VD, /* Stored in Volume Descriptor. */- DIR_REC_SELF, /* Stored as Current Directory. */- DIR_REC_PARENT, /* Stored as Parent Directory. */- DIR_REC_NORMAL /* Stored as Child. */-};--/*- * Kinds of Volume Descriptor Character- */-enum vdc {- VDC_STD,- VDC_LOWERCASE,- VDC_UCS2,- VDC_UCS2_DIRECT-};--/*- * IDentifier Resolver.- * Used for resolving duplicated filenames.- */-struct idr {- struct idrent {- struct archive_rb_node rbnode;- /* Used in wait_list. */- struct idrent *wnext;- struct idrent *avail;-- struct isoent *isoent;- int weight;- int noff;- int rename_num;- } *idrent_pool;-- struct archive_rb_tree rbtree;-- struct {- struct idrent *first;- struct idrent **last;- } wait_list;-- int pool_size;- int pool_idx;- int num_size;- int null_size;-- char char_map[0x80];-};--enum char_type {- A_CHAR,- D_CHAR-};---static int iso9660_options(struct archive_write *,- const char *, const char *);-static int iso9660_write_header(struct archive_write *,- struct archive_entry *);-static ssize_t iso9660_write_data(struct archive_write *,- const void *, size_t);-static int iso9660_finish_entry(struct archive_write *);-static int iso9660_close(struct archive_write *);-static int iso9660_free(struct archive_write *);--static void get_system_identitier(char *, size_t);-static void set_str(unsigned char *, const char *, size_t, char,- const char *);-static inline int joliet_allowed_char(unsigned char, unsigned char);-static int set_str_utf16be(struct archive_write *, unsigned char *,- const char *, size_t, uint16_t, enum vdc);-static int set_str_a_characters_bp(struct archive_write *,- unsigned char *, int, int, const char *, enum vdc);-static int set_str_d_characters_bp(struct archive_write *,- unsigned char *, int, int, const char *, enum vdc);-static void set_VD_bp(unsigned char *, enum VD_type, unsigned char);-static inline void set_unused_field_bp(unsigned char *, int, int);--static unsigned char *extra_open_record(unsigned char *, int,- struct isoent *, struct ctl_extr_rec *);-static void extra_close_record(struct ctl_extr_rec *, int);-static unsigned char * extra_next_record(struct ctl_extr_rec *, int);-static unsigned char *extra_get_record(struct isoent *, int *, int *, int *);-static void extra_tell_used_size(struct ctl_extr_rec *, int);-static int extra_setup_location(struct isoent *, int);-static int set_directory_record_rr(unsigned char *, int,- struct isoent *, struct iso9660 *, enum dir_rec_type);-static int set_directory_record(unsigned char *, size_t,- struct isoent *, struct iso9660 *, enum dir_rec_type,- enum vdd_type);-static inline int get_dir_rec_size(struct iso9660 *, struct isoent *,- enum dir_rec_type, enum vdd_type);-static inline unsigned char *wb_buffptr(struct archive_write *);-static int wb_write_out(struct archive_write *);-static int wb_consume(struct archive_write *, size_t);-#ifdef HAVE_ZLIB_H-static int wb_set_offset(struct archive_write *, int64_t);-#endif-static int write_null(struct archive_write *, size_t);-static int write_VD_terminator(struct archive_write *);-static int set_file_identifier(unsigned char *, int, int, enum vdc,- struct archive_write *, struct vdd *,- struct archive_string *, const char *, int,- enum char_type);-static int write_VD(struct archive_write *, struct vdd *);-static int write_VD_boot_record(struct archive_write *);-static int write_information_block(struct archive_write *);-static int write_path_table(struct archive_write *, int,- struct vdd *);-static int write_directory_descriptors(struct archive_write *,- struct vdd *);-static int write_file_descriptors(struct archive_write *);-static int write_rr_ER(struct archive_write *);-static void calculate_path_table_size(struct vdd *);--static void isofile_init_entry_list(struct iso9660 *);-static void isofile_add_entry(struct iso9660 *, struct isofile *);-static void isofile_free_all_entries(struct iso9660 *);-static void isofile_init_entry_data_file_list(struct iso9660 *);-static void isofile_add_data_file(struct iso9660 *, struct isofile *);-static struct isofile * isofile_new(struct archive_write *,- struct archive_entry *);-static void isofile_free(struct isofile *);-static int isofile_gen_utility_names(struct archive_write *,- struct isofile *);-static int isofile_register_hardlink(struct archive_write *,- struct isofile *);-static void isofile_connect_hardlink_files(struct iso9660 *);-static void isofile_init_hardlinks(struct iso9660 *);-static void isofile_free_hardlinks(struct iso9660 *);--static struct isoent *isoent_new(struct isofile *);-static int isoent_clone_tree(struct archive_write *,- struct isoent **, struct isoent *);-static void _isoent_free(struct isoent *isoent);-static void isoent_free_all(struct isoent *);-static struct isoent * isoent_create_virtual_dir(struct archive_write *,- struct iso9660 *, const char *);-static int isoent_cmp_node(const struct archive_rb_node *,- const struct archive_rb_node *);-static int isoent_cmp_key(const struct archive_rb_node *,- const void *);-static int isoent_add_child_head(struct isoent *, struct isoent *);-static int isoent_add_child_tail(struct isoent *, struct isoent *);-static void isoent_remove_child(struct isoent *, struct isoent *);-static void isoent_setup_directory_location(struct iso9660 *,- int, struct vdd *);-static void isoent_setup_file_location(struct iso9660 *, int);-static int get_path_component(char *, size_t, const char *);-static int isoent_tree(struct archive_write *, struct isoent **);-static struct isoent *isoent_find_child(struct isoent *, const char *);-static struct isoent *isoent_find_entry(struct isoent *, const char *);-static void idr_relaxed_filenames(char *);-static void idr_init(struct iso9660 *, struct vdd *, struct idr *);-static void idr_cleanup(struct idr *);-static int idr_ensure_poolsize(struct archive_write *, struct idr *,- int);-static int idr_start(struct archive_write *, struct idr *,- int, int, int, int, const struct archive_rb_tree_ops *);-static void idr_register(struct idr *, struct isoent *, int,- int);-static void idr_extend_identifier(struct idrent *, int, int);-static void idr_resolve(struct idr *, void (*)(unsigned char *, int));-static void idr_set_num(unsigned char *, int);-static void idr_set_num_beutf16(unsigned char *, int);-static int isoent_gen_iso9660_identifier(struct archive_write *,- struct isoent *, struct idr *);-static int isoent_gen_joliet_identifier(struct archive_write *,- struct isoent *, struct idr *);-static int isoent_cmp_iso9660_identifier(const struct isoent *,- const struct isoent *);-static int isoent_cmp_node_iso9660(const struct archive_rb_node *,- const struct archive_rb_node *);-static int isoent_cmp_key_iso9660(const struct archive_rb_node *,- const void *);-static int isoent_cmp_joliet_identifier(const struct isoent *,- const struct isoent *);-static int isoent_cmp_node_joliet(const struct archive_rb_node *,- const struct archive_rb_node *);-static int isoent_cmp_key_joliet(const struct archive_rb_node *,- const void *);-static inline void path_table_add_entry(struct path_table *, struct isoent *);-static inline struct isoent * path_table_last_entry(struct path_table *);-static int isoent_make_path_table(struct archive_write *);-static int isoent_find_out_boot_file(struct archive_write *,- struct isoent *);-static int isoent_create_boot_catalog(struct archive_write *,- struct isoent *);-static size_t fd_boot_image_size(int);-static int make_boot_catalog(struct archive_write *);-static int setup_boot_information(struct archive_write *);--static int zisofs_init(struct archive_write *, struct isofile *);-static void zisofs_detect_magic(struct archive_write *,- const void *, size_t);-static int zisofs_write_to_temp(struct archive_write *,- const void *, size_t);-static int zisofs_finish_entry(struct archive_write *);-static int zisofs_rewind_boot_file(struct archive_write *);-static int zisofs_free(struct archive_write *);--int-archive_write_set_format_iso9660(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct iso9660 *iso9660;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_iso9660");-- /* If another format was already registered, unregister it. */- if (a->format_free != NULL)- (a->format_free)(a);-- iso9660 = calloc(1, sizeof(*iso9660));- if (iso9660 == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate iso9660 data");- return (ARCHIVE_FATAL);- }- iso9660->birth_time = 0;- iso9660->temp_fd = -1;- iso9660->cur_file = NULL;- iso9660->primary.max_depth = 0;- iso9660->primary.vdd_type = VDD_PRIMARY;- iso9660->primary.pathtbl = NULL;- iso9660->joliet.rootent = NULL;- iso9660->joliet.max_depth = 0;- iso9660->joliet.vdd_type = VDD_JOLIET;- iso9660->joliet.pathtbl = NULL;- isofile_init_entry_list(iso9660);- isofile_init_entry_data_file_list(iso9660);- isofile_init_hardlinks(iso9660);- iso9660->directories_too_deep = NULL;- iso9660->dircnt_max = 1;- iso9660->wbuff_remaining = wb_buffmax();- iso9660->wbuff_type = WB_TO_TEMP;- iso9660->wbuff_offset = 0;- iso9660->wbuff_written = 0;- iso9660->wbuff_tail = 0;- archive_string_init(&(iso9660->utf16be));- archive_string_init(&(iso9660->mbs));-- /*- * Init Identifiers used for PVD and SVD.- */- archive_string_init(&(iso9660->volume_identifier));- archive_strcpy(&(iso9660->volume_identifier), "CDROM");- archive_string_init(&(iso9660->publisher_identifier));- archive_string_init(&(iso9660->data_preparer_identifier));- archive_string_init(&(iso9660->application_identifier));- archive_strcpy(&(iso9660->application_identifier),- archive_version_string());- archive_string_init(&(iso9660->copyright_file_identifier));- archive_string_init(&(iso9660->abstract_file_identifier));- archive_string_init(&(iso9660->bibliographic_file_identifier));-- /*- * Init El Torito bootable CD variables.- */- archive_string_init(&(iso9660->el_torito.catalog_filename));- iso9660->el_torito.catalog = NULL;- /* Set default file name of boot catalog */- archive_strcpy(&(iso9660->el_torito.catalog_filename),- "boot.catalog");- archive_string_init(&(iso9660->el_torito.boot_filename));- iso9660->el_torito.boot = NULL;- iso9660->el_torito.platform_id = BOOT_PLATFORM_X86;- archive_string_init(&(iso9660->el_torito.id));- iso9660->el_torito.boot_load_seg = 0;- iso9660->el_torito.boot_load_size = BOOT_LOAD_SIZE;-- /*- * Init zisofs variables.- */-#ifdef HAVE_ZLIB_H- iso9660->zisofs.block_pointers = NULL;- iso9660->zisofs.block_pointers_allocated = 0;- iso9660->zisofs.stream_valid = 0;- iso9660->zisofs.compression_level = 9;- memset(&(iso9660->zisofs.stream), 0,- sizeof(iso9660->zisofs.stream));-#endif-- /*- * Set default value of iso9660 options.- */- iso9660->opt.abstract_file = OPT_ABSTRACT_FILE_DEFAULT;- iso9660->opt.application_id = OPT_APPLICATION_ID_DEFAULT;- iso9660->opt.allow_vernum = OPT_ALLOW_VERNUM_DEFAULT;- iso9660->opt.biblio_file = OPT_BIBLIO_FILE_DEFAULT;- iso9660->opt.boot = OPT_BOOT_DEFAULT;- iso9660->opt.boot_catalog = OPT_BOOT_CATALOG_DEFAULT;- iso9660->opt.boot_info_table = OPT_BOOT_INFO_TABLE_DEFAULT;- iso9660->opt.boot_load_seg = OPT_BOOT_LOAD_SEG_DEFAULT;- iso9660->opt.boot_load_size = OPT_BOOT_LOAD_SIZE_DEFAULT;- iso9660->opt.boot_type = OPT_BOOT_TYPE_DEFAULT;- iso9660->opt.compression_level = OPT_COMPRESSION_LEVEL_DEFAULT;- iso9660->opt.copyright_file = OPT_COPYRIGHT_FILE_DEFAULT;- iso9660->opt.iso_level = OPT_ISO_LEVEL_DEFAULT;- iso9660->opt.joliet = OPT_JOLIET_DEFAULT;- iso9660->opt.limit_depth = OPT_LIMIT_DEPTH_DEFAULT;- iso9660->opt.limit_dirs = OPT_LIMIT_DIRS_DEFAULT;- iso9660->opt.pad = OPT_PAD_DEFAULT;- iso9660->opt.publisher = OPT_PUBLISHER_DEFAULT;- iso9660->opt.rr = OPT_RR_DEFAULT;- iso9660->opt.volume_id = OPT_VOLUME_ID_DEFAULT;- iso9660->opt.zisofs = OPT_ZISOFS_DEFAULT;-- /* Create the root directory. */- iso9660->primary.rootent =- isoent_create_virtual_dir(a, iso9660, "");- if (iso9660->primary.rootent == NULL) {- free(iso9660);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- iso9660->primary.rootent->parent = iso9660->primary.rootent;- iso9660->cur_dirent = iso9660->primary.rootent;- archive_string_init(&(iso9660->cur_dirstr));- archive_string_ensure(&(iso9660->cur_dirstr), 1);- iso9660->cur_dirstr.s[0] = 0;- iso9660->sconv_to_utf16be = NULL;- iso9660->sconv_from_utf16be = NULL;-- a->format_data = iso9660;- a->format_name = "iso9660";- a->format_options = iso9660_options;- a->format_write_header = iso9660_write_header;- a->format_write_data = iso9660_write_data;- a->format_finish_entry = iso9660_finish_entry;- a->format_close = iso9660_close;- a->format_free = iso9660_free;- a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;- a->archive.archive_format_name = "ISO9660";-- return (ARCHIVE_OK);-}--static int-get_str_opt(struct archive_write *a, struct archive_string *s,- size_t maxsize, const char *key, const char *value)-{-- if (strlen(value) > maxsize) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Value is longer than %zu characters "- "for option ``%s''", maxsize, key);- return (ARCHIVE_FATAL);- }- archive_strcpy(s, value);- return (ARCHIVE_OK);-}--static int-get_num_opt(struct archive_write *a, int *num, int high, int low,- const char *key, const char *value)-{- const char *p = value;- int data = 0;- int neg = 0;-- if (p == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid value(empty) for option ``%s''", key);- return (ARCHIVE_FATAL);- }- if (*p == '-') {- neg = 1;- p++;- }- while (*p) {- if (*p >= '0' && *p <= '9')- data = data * 10 + *p - '0';- else {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid value for option ``%s''", key);- return (ARCHIVE_FATAL);- }- if (data > high) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid value(over %d) for "- "option ``%s''", high, key);- return (ARCHIVE_FATAL);- }- if (data < low) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid value(under %d) for "- "option ``%s''", low, key);- return (ARCHIVE_FATAL);- }- p++;- }- if (neg)- data *= -1;- *num = data;-- return (ARCHIVE_OK);-}--static int-iso9660_options(struct archive_write *a, const char *key, const char *value)-{- struct iso9660 *iso9660 = a->format_data;- const char *p;- int r;-- switch (key[0]) {- case 'a':- if (strcmp(key, "abstract-file") == 0) {- r = get_str_opt(a,- &(iso9660->abstract_file_identifier),- ABSTRACT_FILE_SIZE, key, value);- iso9660->opt.abstract_file = r == ARCHIVE_OK;- return (r);- }- if (strcmp(key, "application-id") == 0) {- r = get_str_opt(a,- &(iso9660->application_identifier),- APPLICATION_IDENTIFIER_SIZE, key, value);- iso9660->opt.application_id = r == ARCHIVE_OK;- return (r);- }- if (strcmp(key, "allow-vernum") == 0) {- iso9660->opt.allow_vernum = value != NULL;- return (ARCHIVE_OK);- }- break;- case 'b':- if (strcmp(key, "biblio-file") == 0) {- r = get_str_opt(a,- &(iso9660->bibliographic_file_identifier),- BIBLIO_FILE_SIZE, key, value);- iso9660->opt.biblio_file = r == ARCHIVE_OK;- return (r);- }- if (strcmp(key, "boot") == 0) {- if (value == NULL)- iso9660->opt.boot = 0;- else {- iso9660->opt.boot = 1;- archive_strcpy(- &(iso9660->el_torito.boot_filename),- value);- }- return (ARCHIVE_OK);- }- if (strcmp(key, "boot-catalog") == 0) {- r = get_str_opt(a,- &(iso9660->el_torito.catalog_filename),- 1024, key, value);- iso9660->opt.boot_catalog = r == ARCHIVE_OK;- return (r);- }- if (strcmp(key, "boot-info-table") == 0) {- iso9660->opt.boot_info_table = value != NULL;- return (ARCHIVE_OK);- }- if (strcmp(key, "boot-load-seg") == 0) {- uint32_t seg;-- iso9660->opt.boot_load_seg = 0;- if (value == NULL)- goto invalid_value;- seg = 0;- p = value;- if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))- p += 2;- while (*p) {- if (seg)- seg <<= 4;- if (*p >= 'A' && *p <= 'F')- seg += *p - 'A' + 0x0a;- else if (*p >= 'a' && *p <= 'f')- seg += *p - 'a' + 0x0a;- else if (*p >= '0' && *p <= '9')- seg += *p - '0';- else- goto invalid_value;- if (seg > 0xffff) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Invalid value(over 0xffff) for "- "option ``%s''", key);- return (ARCHIVE_FATAL);- }- p++;- }- iso9660->el_torito.boot_load_seg = (uint16_t)seg;- iso9660->opt.boot_load_seg = 1;- return (ARCHIVE_OK);- }- if (strcmp(key, "boot-load-size") == 0) {- int num = 0;- r = get_num_opt(a, &num, 0xffff, 1, key, value);- iso9660->opt.boot_load_size = r == ARCHIVE_OK;- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);- iso9660->el_torito.boot_load_size = (uint16_t)num;- return (ARCHIVE_OK);- }- if (strcmp(key, "boot-type") == 0) {- if (value == NULL)- goto invalid_value;- if (strcmp(value, "no-emulation") == 0)- iso9660->opt.boot_type = OPT_BOOT_TYPE_NO_EMU;- else if (strcmp(value, "fd") == 0)- iso9660->opt.boot_type = OPT_BOOT_TYPE_FD;- else if (strcmp(value, "hard-disk") == 0)- iso9660->opt.boot_type = OPT_BOOT_TYPE_HARD_DISK;- else- goto invalid_value;- return (ARCHIVE_OK);- }- break;- case 'c':- if (strcmp(key, "compression-level") == 0) {-#ifdef HAVE_ZLIB_H- if (value == NULL ||- !(value[0] >= '0' && value[0] <= '9') ||- value[1] != '\0')- goto invalid_value;- iso9660->zisofs.compression_level = value[0] - '0';- iso9660->opt.compression_level = 1;- return (ARCHIVE_OK);-#else- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Option ``%s'' "- "is not supported on this platform.", key);- return (ARCHIVE_FATAL);-#endif- }- if (strcmp(key, "copyright-file") == 0) {- r = get_str_opt(a,- &(iso9660->copyright_file_identifier),- COPYRIGHT_FILE_SIZE, key, value);- iso9660->opt.copyright_file = r == ARCHIVE_OK;- return (r);- }-#ifdef DEBUG- /* Specifies Volume creation date and time;- * year(4),month(2),day(2),hour(2),minute(2),second(2).- * e.g. "20090929033757"- */- if (strcmp(key, "creation") == 0) {- struct tm tm;- char buf[5];-- p = value;- if (p == NULL || strlen(p) < 14)- goto invalid_value;- memset(&tm, 0, sizeof(tm));- memcpy(buf, p, 4); buf[4] = '\0'; p += 4;- tm.tm_year = strtol(buf, NULL, 10) - 1900;- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;- tm.tm_mon = strtol(buf, NULL, 10) - 1;- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;- tm.tm_mday = strtol(buf, NULL, 10);- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;- tm.tm_hour = strtol(buf, NULL, 10);- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;- tm.tm_min = strtol(buf, NULL, 10);- memcpy(buf, p, 2); buf[2] = '\0';- tm.tm_sec = strtol(buf, NULL, 10);- iso9660->birth_time = mktime(&tm);- return (ARCHIVE_OK);- }-#endif- break;- case 'i':- if (strcmp(key, "iso-level") == 0) {- if (value != NULL && value[1] == '\0' &&- (value[0] >= '1' && value[0] <= '4')) {- iso9660->opt.iso_level = value[0]-'0';- return (ARCHIVE_OK);- }- goto invalid_value;- }- break;- case 'j':- if (strcmp(key, "joliet") == 0) {- if (value == NULL)- iso9660->opt.joliet = OPT_JOLIET_DISABLE;- else if (strcmp(value, "1") == 0)- iso9660->opt.joliet = OPT_JOLIET_ENABLE;- else if (strcmp(value, "long") == 0)- iso9660->opt.joliet = OPT_JOLIET_LONGNAME;- else- goto invalid_value;- return (ARCHIVE_OK);- }- break;- case 'l':- if (strcmp(key, "limit-depth") == 0) {- iso9660->opt.limit_depth = value != NULL;- return (ARCHIVE_OK);- }- if (strcmp(key, "limit-dirs") == 0) {- iso9660->opt.limit_dirs = value != NULL;- return (ARCHIVE_OK);- }- break;- case 'p':- if (strcmp(key, "pad") == 0) {- iso9660->opt.pad = value != NULL;- return (ARCHIVE_OK);- }- if (strcmp(key, "publisher") == 0) {- r = get_str_opt(a,- &(iso9660->publisher_identifier),- PUBLISHER_IDENTIFIER_SIZE, key, value);- iso9660->opt.publisher = r == ARCHIVE_OK;- return (r);- }- break;- case 'r':- if (strcmp(key, "rockridge") == 0 ||- strcmp(key, "Rockridge") == 0) {- if (value == NULL)- iso9660->opt.rr = OPT_RR_DISABLED;- else if (strcmp(value, "1") == 0)- iso9660->opt.rr = OPT_RR_USEFUL;- else if (strcmp(value, "strict") == 0)- iso9660->opt.rr = OPT_RR_STRICT;- else if (strcmp(value, "useful") == 0)- iso9660->opt.rr = OPT_RR_USEFUL;- else- goto invalid_value;- return (ARCHIVE_OK);- }- break;- case 'v':- if (strcmp(key, "volume-id") == 0) {- r = get_str_opt(a, &(iso9660->volume_identifier),- VOLUME_IDENTIFIER_SIZE, key, value);- iso9660->opt.volume_id = r == ARCHIVE_OK;- return (r);- }- break;- case 'z':- if (strcmp(key, "zisofs") == 0) {- if (value == NULL)- iso9660->opt.zisofs = OPT_ZISOFS_DISABLED;- else {-#ifdef HAVE_ZLIB_H- iso9660->opt.zisofs = OPT_ZISOFS_DIRECT;-#else- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "``zisofs'' "- "is not supported on this platform.");- return (ARCHIVE_FATAL);-#endif- }- return (ARCHIVE_OK);- }- break;- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);--invalid_value:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid value for option ``%s''", key);- return (ARCHIVE_FAILED);-}--static int-iso9660_write_header(struct archive_write *a, struct archive_entry *entry)-{- struct iso9660 *iso9660;- struct isofile *file;- struct isoent *isoent;- int r, ret = ARCHIVE_OK;-- iso9660 = a->format_data;-- iso9660->cur_file = NULL;- iso9660->bytes_remaining = 0;- iso9660->need_multi_extent = 0;- if (archive_entry_filetype(entry) == AE_IFLNK- && iso9660->opt.rr == OPT_RR_DISABLED) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Ignore symlink file.");- iso9660->cur_file = NULL;- return (ARCHIVE_WARN);- }- if (archive_entry_filetype(entry) == AE_IFREG &&- archive_entry_size(entry) >= MULTI_EXTENT_SIZE) {- if (iso9660->opt.iso_level < 3) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Ignore over %lld bytes file. "- "This file too large.",- MULTI_EXTENT_SIZE);- iso9660->cur_file = NULL;- return (ARCHIVE_WARN);- }- iso9660->need_multi_extent = 1;- }-- file = isofile_new(a, entry);- if (file == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate data");- return (ARCHIVE_FATAL);- }- r = isofile_gen_utility_names(a, file);- if (r < ARCHIVE_WARN) {- isofile_free(file);- return (r);- }- else if (r < ret)- ret = r;-- /*- * Ignore a path which looks like the top of directory name- * since we have already made the root directory of an ISO image.- */- if (archive_strlen(&(file->parentdir)) == 0 &&- archive_strlen(&(file->basename)) == 0) {- isofile_free(file);- return (r);- }-- isofile_add_entry(iso9660, file);- isoent = isoent_new(file);- if (isoent == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate data");- return (ARCHIVE_FATAL);- }- if (isoent->file->dircnt > iso9660->dircnt_max)- iso9660->dircnt_max = isoent->file->dircnt;-- /* Add the current file into tree */- r = isoent_tree(a, &isoent);- if (r != ARCHIVE_OK)- return (r);-- /* If there is the same file in tree and- * the current file is older than the file in tree.- * So we don't need the current file data anymore. */- if (isoent->file != file)- return (ARCHIVE_OK);-- /* Non regular files contents are unneeded to be saved to- * temporary files. */- if (archive_entry_filetype(file->entry) != AE_IFREG)- return (ret);-- /*- * Set the current file to cur_file to read its contents.- */- iso9660->cur_file = file;-- if (archive_entry_nlink(file->entry) > 1) {- r = isofile_register_hardlink(a, file);- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- /*- * Prepare to save the contents of the file.- */- if (iso9660->temp_fd < 0) {- iso9660->temp_fd = __archive_mktemp(NULL);- if (iso9660->temp_fd < 0) {- archive_set_error(&a->archive, errno,- "Couldn't create temporary file");- return (ARCHIVE_FATAL);- }- }-- /* Save an offset of current file in temporary file. */- file->content.offset_of_temp = wb_offset(a);- file->cur_content = &(file->content);- r = zisofs_init(a, file);- if (r < ret)- ret = r;- iso9660->bytes_remaining = archive_entry_size(file->entry);-- return (ret);-}--static int-write_to_temp(struct archive_write *a, const void *buff, size_t s)-{- struct iso9660 *iso9660 = a->format_data;- ssize_t written;- const unsigned char *b;-- b = (const unsigned char *)buff;- while (s) {- written = write(iso9660->temp_fd, b, s);- if (written < 0) {- archive_set_error(&a->archive, errno,- "Can't write to temporary file");- return (ARCHIVE_FATAL);- }- s -= written;- b += written;- }- return (ARCHIVE_OK);-}--static int-wb_write_to_temp(struct archive_write *a, const void *buff, size_t s)-{- const char *xp = buff;- size_t xs = s;-- /*- * If a written data size is big enough to use system-call- * and there is no waiting data, this calls write_to_temp() in- * order to reduce a extra memory copy.- */- if (wb_remaining(a) == wb_buffmax() && s > (1024 * 16)) {- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;- xs = s % LOGICAL_BLOCK_SIZE;- iso9660->wbuff_offset += s - xs;- if (write_to_temp(a, buff, s - xs) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- if (xs == 0)- return (ARCHIVE_OK);- xp += s - xs;- }-- while (xs) {- size_t size = xs;- if (size > wb_remaining(a))- size = wb_remaining(a);- memcpy(wb_buffptr(a), xp, size);- if (wb_consume(a, size) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- xs -= size;- xp += size;- }- return (ARCHIVE_OK);-}--static int-wb_write_padding_to_temp(struct archive_write *a, int64_t csize)-{- size_t ns;- int ret;-- ns = (size_t)(csize % LOGICAL_BLOCK_SIZE);- if (ns != 0)- ret = write_null(a, LOGICAL_BLOCK_SIZE - ns);- else- ret = ARCHIVE_OK;- return (ret);-}--static ssize_t-write_iso9660_data(struct archive_write *a, const void *buff, size_t s)-{- struct iso9660 *iso9660 = a->format_data;- size_t ws;-- if (iso9660->temp_fd < 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Couldn't create temporary file");- return (ARCHIVE_FATAL);- }-- ws = s;- if (iso9660->need_multi_extent &&- (iso9660->cur_file->cur_content->size + ws) >=- (MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE)) {- struct content *con;- size_t ts;-- ts = (size_t)(MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE -- iso9660->cur_file->cur_content->size);-- if (iso9660->zisofs.detect_magic)- zisofs_detect_magic(a, buff, ts);-- if (iso9660->zisofs.making) {- if (zisofs_write_to_temp(a, buff, ts) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- } else {- if (wb_write_to_temp(a, buff, ts) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- iso9660->cur_file->cur_content->size += ts;- }-- /* Write padding. */- if (wb_write_padding_to_temp(a,- iso9660->cur_file->cur_content->size) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Compute the logical block number. */- iso9660->cur_file->cur_content->blocks = (int)- ((iso9660->cur_file->cur_content->size- + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);-- /*- * Make next extent.- */- ws -= ts;- buff = (const void *)(((const unsigned char *)buff) + ts);- /* Make a content for next extent. */- con = calloc(1, sizeof(*con));- if (con == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate content data");- return (ARCHIVE_FATAL);- }- con->offset_of_temp = wb_offset(a);- iso9660->cur_file->cur_content->next = con;- iso9660->cur_file->cur_content = con;-#ifdef HAVE_ZLIB_H- iso9660->zisofs.block_offset = 0;-#endif- }-- if (iso9660->zisofs.detect_magic)- zisofs_detect_magic(a, buff, ws);-- if (iso9660->zisofs.making) {- if (zisofs_write_to_temp(a, buff, ws) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- } else {- if (wb_write_to_temp(a, buff, ws) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- iso9660->cur_file->cur_content->size += ws;- }-- return (s);-}--static ssize_t-iso9660_write_data(struct archive_write *a, const void *buff, size_t s)-{- struct iso9660 *iso9660 = a->format_data;- ssize_t r;-- if (iso9660->cur_file == NULL)- return (0);- if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)- return (0);- if (s > iso9660->bytes_remaining)- s = (size_t)iso9660->bytes_remaining;- if (s == 0)- return (0);-- r = write_iso9660_data(a, buff, s);- if (r > 0)- iso9660->bytes_remaining -= r;- return (r);-}--static int-iso9660_finish_entry(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;-- if (iso9660->cur_file == NULL)- return (ARCHIVE_OK);- if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)- return (ARCHIVE_OK);- if (iso9660->cur_file->content.size == 0)- return (ARCHIVE_OK);-- /* If there are unwritten data, write null data instead. */- while (iso9660->bytes_remaining > 0) {- size_t s;-- s = (iso9660->bytes_remaining > a->null_length)?- a->null_length: (size_t)iso9660->bytes_remaining;- if (write_iso9660_data(a, a->nulls, s) < 0)- return (ARCHIVE_FATAL);- iso9660->bytes_remaining -= s;- }-- if (iso9660->zisofs.making && zisofs_finish_entry(a) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Write padding. */- if (wb_write_padding_to_temp(a, iso9660->cur_file->cur_content->size)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Compute the logical block number. */- iso9660->cur_file->cur_content->blocks = (int)- ((iso9660->cur_file->cur_content->size- + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);-- /* Add the current file to data file list. */- isofile_add_data_file(iso9660, iso9660->cur_file);-- return (ARCHIVE_OK);-}--static int-iso9660_close(struct archive_write *a)-{- struct iso9660 *iso9660;- int ret, blocks;-- iso9660 = a->format_data;-- /*- * Write remaining data out to the temporary file.- */- if (wb_remaining(a) > 0) {- ret = wb_write_out(a);- if (ret < 0)- return (ret);- }-- /*- * Preparations...- */-#ifdef DEBUG- if (iso9660->birth_time == 0)-#endif- time(&(iso9660->birth_time));-- /*- * Prepare a bootable ISO image.- */- if (iso9660->opt.boot) {- /* Find out the boot file entry. */- ret = isoent_find_out_boot_file(a, iso9660->primary.rootent);- if (ret < 0)- return (ret);- /* Reconvert the boot file from zisofs'ed form to- * plain form. */- ret = zisofs_rewind_boot_file(a);- if (ret < 0)- return (ret);- /* Write remaining data out to the temporary file. */- if (wb_remaining(a) > 0) {- ret = wb_write_out(a);- if (ret < 0)- return (ret);- }- /* Create the boot catalog. */- ret = isoent_create_boot_catalog(a, iso9660->primary.rootent);- if (ret < 0)- return (ret);- }-- /*- * Prepare joliet extensions.- */- if (iso9660->opt.joliet) {- /* Make a new tree for joliet. */- ret = isoent_clone_tree(a, &(iso9660->joliet.rootent),- iso9660->primary.rootent);- if (ret < 0)- return (ret);- /* Make sure we have UTF-16BE converters.- * if there is no file entry, converters are still- * uninitialized. */- if (iso9660->sconv_to_utf16be == NULL) {- iso9660->sconv_to_utf16be =- archive_string_conversion_to_charset(- &(a->archive), "UTF-16BE", 1);- if (iso9660->sconv_to_utf16be == NULL)- /* Couldn't allocate memory */- return (ARCHIVE_FATAL);- iso9660->sconv_from_utf16be =- archive_string_conversion_from_charset(- &(a->archive), "UTF-16BE", 1);- if (iso9660->sconv_from_utf16be == NULL)- /* Couldn't allocate memory */- return (ARCHIVE_FATAL);- }- }-- /*- * Make Path Tables.- */- ret = isoent_make_path_table(a);- if (ret < 0)- return (ret);-- /*- * Calculate a total volume size and setup all locations of- * contents of an iso9660 image.- */- blocks = SYSTEM_AREA_BLOCK- + PRIMARY_VOLUME_DESCRIPTOR_BLOCK- + VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK- + NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;- if (iso9660->opt.boot)- blocks += BOOT_RECORD_DESCRIPTOR_BLOCK;- if (iso9660->opt.joliet)- blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;- if (iso9660->opt.iso_level == 4)- blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;-- /* Setup the locations of Path Table. */- iso9660->primary.location_type_L_path_table = blocks;- blocks += iso9660->primary.path_table_block;- iso9660->primary.location_type_M_path_table = blocks;- blocks += iso9660->primary.path_table_block;- if (iso9660->opt.joliet) {- iso9660->joliet.location_type_L_path_table = blocks;- blocks += iso9660->joliet.path_table_block;- iso9660->joliet.location_type_M_path_table = blocks;- blocks += iso9660->joliet.path_table_block;- }-- /* Setup the locations of directories. */- isoent_setup_directory_location(iso9660, blocks,- &(iso9660->primary));- blocks += iso9660->primary.total_dir_block;- if (iso9660->opt.joliet) {- isoent_setup_directory_location(iso9660, blocks,- &(iso9660->joliet));- blocks += iso9660->joliet.total_dir_block;- }-- if (iso9660->opt.rr) {- iso9660->location_rrip_er = blocks;- blocks += RRIP_ER_BLOCK;- }-- /* Setup the locations of all file contents. */- isoent_setup_file_location(iso9660, blocks);- blocks += iso9660->total_file_block;- if (iso9660->opt.boot && iso9660->opt.boot_info_table) {- ret = setup_boot_information(a);- if (ret < 0)- return (ret);- }-- /* Now we have a total volume size. */- iso9660->volume_space_size = blocks;- if (iso9660->opt.pad)- iso9660->volume_space_size += PADDING_BLOCK;- iso9660->volume_sequence_number = 1;--- /*- * Write an ISO 9660 image.- */-- /* Switch to start using wbuff as file buffer. */- iso9660->wbuff_remaining = wb_buffmax();- iso9660->wbuff_type = WB_TO_STREAM;- iso9660->wbuff_offset = 0;- iso9660->wbuff_written = 0;- iso9660->wbuff_tail = 0;-- /* Write The System Area */- ret = write_null(a, SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Write Primary Volume Descriptor */- ret = write_VD(a, &(iso9660->primary));- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- if (iso9660->opt.boot) {- /* Write Boot Record Volume Descriptor */- ret = write_VD_boot_record(a);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- if (iso9660->opt.iso_level == 4) {- /* Write Enhanced Volume Descriptor */- iso9660->primary.vdd_type = VDD_ENHANCED;- ret = write_VD(a, &(iso9660->primary));- iso9660->primary.vdd_type = VDD_PRIMARY;- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- if (iso9660->opt.joliet) {- ret = write_VD(a, &(iso9660->joliet));- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- /* Write Volume Descriptor Set Terminator */- ret = write_VD_terminator(a);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Write Non-ISO File System Information */- ret = write_information_block(a);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Write Type L Path Table */- ret = write_path_table(a, 0, &(iso9660->primary));- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Write Type M Path Table */- ret = write_path_table(a, 1, &(iso9660->primary));- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- if (iso9660->opt.joliet) {- /* Write Type L Path Table */- ret = write_path_table(a, 0, &(iso9660->joliet));- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Write Type M Path Table */- ret = write_path_table(a, 1, &(iso9660->joliet));- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- /* Write Directory Descriptors */- ret = write_directory_descriptors(a, &(iso9660->primary));- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- if (iso9660->opt.joliet) {- ret = write_directory_descriptors(a, &(iso9660->joliet));- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- if (iso9660->opt.rr) {- /* Write Rockridge ER(Extensions Reference) */- ret = write_rr_ER(a);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- /* Write File Descriptors */- ret = write_file_descriptors(a);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Write Padding */- if (iso9660->opt.pad) {- ret = write_null(a, PADDING_BLOCK * LOGICAL_BLOCK_SIZE);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- if (iso9660->directories_too_deep != NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: Directories too deep.",- archive_entry_pathname(- iso9660->directories_too_deep->file->entry));- return (ARCHIVE_WARN);- }-- /* Write remaining data out. */- ret = wb_write_out(a);-- return (ret);-}--static int-iso9660_free(struct archive_write *a)-{- struct iso9660 *iso9660;- int i, ret;-- iso9660 = a->format_data;-- /* Close the temporary file. */- if (iso9660->temp_fd >= 0)- close(iso9660->temp_fd);-- /* Free some stuff for zisofs operations. */- ret = zisofs_free(a);-- /* Remove directory entries in tree which includes file entries. */- isoent_free_all(iso9660->primary.rootent);- for (i = 0; i < iso9660->primary.max_depth; i++)- free(iso9660->primary.pathtbl[i].sorted);- free(iso9660->primary.pathtbl);-- if (iso9660->opt.joliet) {- isoent_free_all(iso9660->joliet.rootent);- for (i = 0; i < iso9660->joliet.max_depth; i++)- free(iso9660->joliet.pathtbl[i].sorted);- free(iso9660->joliet.pathtbl);- }-- /* Remove isofile entries. */- isofile_free_all_entries(iso9660);- isofile_free_hardlinks(iso9660);-- archive_string_free(&(iso9660->cur_dirstr));- archive_string_free(&(iso9660->volume_identifier));- archive_string_free(&(iso9660->publisher_identifier));- archive_string_free(&(iso9660->data_preparer_identifier));- archive_string_free(&(iso9660->application_identifier));- archive_string_free(&(iso9660->copyright_file_identifier));- archive_string_free(&(iso9660->abstract_file_identifier));- archive_string_free(&(iso9660->bibliographic_file_identifier));- archive_string_free(&(iso9660->el_torito.catalog_filename));- archive_string_free(&(iso9660->el_torito.boot_filename));- archive_string_free(&(iso9660->el_torito.id));- archive_string_free(&(iso9660->utf16be));- archive_string_free(&(iso9660->mbs));-- free(iso9660);- a->format_data = NULL;-- return (ret);-}--/*- * Get the System Identifier- */-static void-get_system_identitier(char *system_id, size_t size)-{-#if defined(HAVE_SYS_UTSNAME_H)- struct utsname u;-- uname(&u);- strncpy(system_id, u.sysname, size-1);- system_id[size-1] = '\0';-#elif defined(_WIN32) && !defined(__CYGWIN__)- strncpy(system_id, "Windows", size-1);- system_id[size-1] = '\0';-#else- strncpy(system_id, "Unknown", size-1);- system_id[size-1] = '\0';-#endif-}--static void-set_str(unsigned char *p, const char *s, size_t l, char f, const char *map)-{- unsigned char c;-- if (s == NULL)- s = "";- while ((c = *s++) != 0 && l > 0) {- if (c >= 0x80 || map[c] == 0)- {- /* illegal character */- if (c >= 'a' && c <= 'z') {- /* convert c from a-z to A-Z */- c -= 0x20;- } else- c = 0x5f;- }- *p++ = c;- l--;- }- /* If l isn't zero, fill p buffer by the character- * which indicated by f. */- if (l > 0)- memset(p , f, l);-}--static inline int-joliet_allowed_char(unsigned char high, unsigned char low)-{- int utf16 = (high << 8) | low;-- if (utf16 <= 0x001F)- return (0);-- switch (utf16) {- case 0x002A: /* '*' */- case 0x002F: /* '/' */- case 0x003A: /* ':' */- case 0x003B: /* ';' */- case 0x003F: /* '?' */- case 0x005C: /* '\' */- return (0);/* Not allowed. */- }- return (1);-}--static int-set_str_utf16be(struct archive_write *a, unsigned char *p, const char *s,- size_t l, uint16_t uf, enum vdc vdc)-{- size_t size, i;- int onepad;-- if (s == NULL)- s = "";- if (l & 0x01) {- onepad = 1;- l &= ~1;- } else- onepad = 0;- if (vdc == VDC_UCS2) {- struct iso9660 *iso9660 = a->format_data;- if (archive_strncpy_l(&iso9660->utf16be, s, strlen(s),- iso9660->sconv_to_utf16be) != 0 && errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for UTF-16BE");- return (ARCHIVE_FATAL);- }- size = iso9660->utf16be.length;- if (size > l)- size = l;- memcpy(p, iso9660->utf16be.s, size);- } else {- const uint16_t *u16 = (const uint16_t *)s;-- size = 0;- while (*u16++)- size += 2;- if (size > l)- size = l;- memcpy(p, s, size);- }- for (i = 0; i < size; i += 2, p += 2) {- if (!joliet_allowed_char(p[0], p[1]))- archive_be16enc(p, 0x005F);/* '_' */- }- l -= size;- while (l > 0) {- archive_be16enc(p, uf);- p += 2;- l -= 2;- }- if (onepad)- *p = 0;- return (ARCHIVE_OK);-}--static const char a_characters_map[0x80] = {-/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */- 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */-};--static const char a1_characters_map[0x80] = {-/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */- 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */-};--static const char d_characters_map[0x80] = {-/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */-};--static const char d1_characters_map[0x80] = {-/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */-};--static int-set_str_a_characters_bp(struct archive_write *a, unsigned char *bp,- int from, int to, const char *s, enum vdc vdc)-{- int r;-- switch (vdc) {- case VDC_STD:- set_str(bp+from, s, to - from + 1, 0x20,- a_characters_map);- r = ARCHIVE_OK;- break;- case VDC_LOWERCASE:- set_str(bp+from, s, to - from + 1, 0x20,- a1_characters_map);- r = ARCHIVE_OK;- break;- case VDC_UCS2:- case VDC_UCS2_DIRECT:- r = set_str_utf16be(a, bp+from, s, to - from + 1,- 0x0020, vdc);- break;- default:- r = ARCHIVE_FATAL;- }- return (r);-}--static int-set_str_d_characters_bp(struct archive_write *a, unsigned char *bp,- int from, int to, const char *s, enum vdc vdc)-{- int r;-- switch (vdc) {- case VDC_STD:- set_str(bp+from, s, to - from + 1, 0x20,- d_characters_map);- r = ARCHIVE_OK;- break;- case VDC_LOWERCASE:- set_str(bp+from, s, to - from + 1, 0x20,- d1_characters_map);- r = ARCHIVE_OK;- break;- case VDC_UCS2:- case VDC_UCS2_DIRECT:- r = set_str_utf16be(a, bp+from, s, to - from + 1,- 0x0020, vdc);- break;- default:- r = ARCHIVE_FATAL;- }- return (r);-}--static void-set_VD_bp(unsigned char *bp, enum VD_type type, unsigned char ver)-{-- /* Volume Descriptor Type */- bp[1] = (unsigned char)type;- /* Standard Identifier */- memcpy(bp + 2, "CD001", 5);- /* Volume Descriptor Version */- bp[7] = ver;-}--static inline void-set_unused_field_bp(unsigned char *bp, int from, int to)-{- memset(bp + from, 0, to - from + 1);-}--/*- * 8-bit unsigned numerical values.- * ISO9660 Standard 7.1.1- */-static inline void-set_num_711(unsigned char *p, unsigned char value)-{- *p = value;-}--/*- * 8-bit signed numerical values.- * ISO9660 Standard 7.1.2- */-static inline void-set_num_712(unsigned char *p, char value)-{- *((char *)p) = value;-}--/*- * Least significant byte first.- * ISO9660 Standard 7.2.1- */-static inline void-set_num_721(unsigned char *p, uint16_t value)-{- archive_le16enc(p, value);-}--/*- * Most significant byte first.- * ISO9660 Standard 7.2.2- */-static inline void-set_num_722(unsigned char *p, uint16_t value)-{- archive_be16enc(p, value);-}--/*- * Both-byte orders.- * ISO9660 Standard 7.2.3- */-static void-set_num_723(unsigned char *p, uint16_t value)-{- archive_le16enc(p, value);- archive_be16enc(p+2, value);-}--/*- * Least significant byte first.- * ISO9660 Standard 7.3.1- */-static inline void-set_num_731(unsigned char *p, uint32_t value)-{- archive_le32enc(p, value);-}--/*- * Most significant byte first.- * ISO9660 Standard 7.3.2- */-static inline void-set_num_732(unsigned char *p, uint32_t value)-{- archive_be32enc(p, value);-}--/*- * Both-byte orders.- * ISO9660 Standard 7.3.3- */-static inline void-set_num_733(unsigned char *p, uint32_t value)-{- archive_le32enc(p, value);- archive_be32enc(p+4, value);-}--static void-set_digit(unsigned char *p, size_t s, int value)-{-- while (s--) {- p[s] = '0' + (value % 10);- value /= 10;- }-}--#if defined(HAVE_STRUCT_TM_TM_GMTOFF)-#define get_gmoffset(tm) ((tm)->tm_gmtoff)-#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)-#define get_gmoffset(tm) ((tm)->__tm_gmtoff)-#else-static long-get_gmoffset(struct tm *tm)-{- long offset;--#if defined(HAVE__GET_TIMEZONE)- _get_timezone(&offset);-#elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)- offset = _timezone;-#else- offset = timezone;-#endif- offset *= -1;- if (tm->tm_isdst)- offset += 3600;- return (offset);-}-#endif--static void-get_tmfromtime(struct tm *tm, time_t *t)-{-#if HAVE_LOCALTIME_S- localtime_s(tm, t);-#elif HAVE_LOCALTIME_R- tzset();- localtime_r(t, tm);-#else- memcpy(tm, localtime(t), sizeof(*tm));-#endif-}--/*- * Date and Time Format.- * ISO9660 Standard 8.4.26.1- */-static void-set_date_time(unsigned char *p, time_t t)-{- struct tm tm;-- get_tmfromtime(&tm, &t);- set_digit(p, 4, tm.tm_year + 1900);- set_digit(p+4, 2, tm.tm_mon + 1);- set_digit(p+6, 2, tm.tm_mday);- set_digit(p+8, 2, tm.tm_hour);- set_digit(p+10, 2, tm.tm_min);- set_digit(p+12, 2, tm.tm_sec);- set_digit(p+14, 2, 0);- set_num_712(p+16, (char)(get_gmoffset(&tm)/(60*15)));-}--static void-set_date_time_null(unsigned char *p)-{- memset(p, (int)'0', 16);- p[16] = 0;-}--static void-set_time_915(unsigned char *p, time_t t)-{- struct tm tm;-- get_tmfromtime(&tm, &t);- set_num_711(p+0, tm.tm_year);- set_num_711(p+1, tm.tm_mon+1);- set_num_711(p+2, tm.tm_mday);- set_num_711(p+3, tm.tm_hour);- set_num_711(p+4, tm.tm_min);- set_num_711(p+5, tm.tm_sec);- set_num_712(p+6, (char)(get_gmoffset(&tm)/(60*15)));-}---/*- * Write SUSP "CE" System Use Entry.- */-static int-set_SUSP_CE(unsigned char *p, int location, int offset, int size)-{- unsigned char *bp = p -1;- /* Extend the System Use Area- * "CE" Format:- * len ver- * +----+----+----+----+-----------+-----------+- * | 'C'| 'E'| 1C | 01 | LOCATION1 | LOCATION2 |- * +----+----+----+----+-----------+-----------+- * 0 1 2 3 4 12 20- * +-----------+- * | LOCATION3 |- * +-----------+- * 20 28- * LOCATION1 : Location of Continuation of System Use Area.- * LOCATION2 : Offset to Start of Continuation.- * LOCATION3 : Length of the Continuation.- */-- bp[1] = 'C';- bp[2] = 'E';- bp[3] = RR_CE_SIZE; /* length */- bp[4] = 1; /* version */- set_num_733(bp+5, location);- set_num_733(bp+13, offset);- set_num_733(bp+21, size);- return (RR_CE_SIZE);-}--/*- * The functions, which names are beginning with extra_, are used to- * control extra records.- * The maximum size of a Directory Record is 254. When a filename is- * very long, all of RRIP data of a file won't stored to the Directory- * Record and so remaining RRIP data store to an extra record instead.- */-static unsigned char *-extra_open_record(unsigned char *bp, int dr_len, struct isoent *isoent,- struct ctl_extr_rec *ctl)-{- ctl->bp = bp;- if (bp != NULL)- bp += dr_len;- ctl->use_extr = 0;- ctl->isoent = isoent;- ctl->ce_ptr = NULL;- ctl->cur_len = ctl->dr_len = dr_len;- ctl->limit = DR_LIMIT;-- return (bp);-}--static void-extra_close_record(struct ctl_extr_rec *ctl, int ce_size)-{- int padding = 0;-- if (ce_size > 0)- extra_tell_used_size(ctl, ce_size);- /* Padding. */- if (ctl->cur_len & 0x01) {- ctl->cur_len++;- if (ctl->bp != NULL)- ctl->bp[ctl->cur_len] = 0;- padding = 1;- }- if (ctl->use_extr) {- if (ctl->ce_ptr != NULL)- set_SUSP_CE(ctl->ce_ptr, ctl->extr_loc,- ctl->extr_off, ctl->cur_len - padding);- } else- ctl->dr_len = ctl->cur_len;-}--#define extra_space(ctl) ((ctl)->limit - (ctl)->cur_len)--static unsigned char *-extra_next_record(struct ctl_extr_rec *ctl, int length)-{- int cur_len = ctl->cur_len;/* save cur_len */-- /* Close the current extra record or Directory Record. */- extra_close_record(ctl, RR_CE_SIZE);-- /* Get a next extra record. */- ctl->use_extr = 1;- if (ctl->bp != NULL) {- /* Storing data into an extra record. */- unsigned char *p;-- /* Save the pointer where a CE extension will be- * stored to. */- ctl->ce_ptr = &ctl->bp[cur_len+1];- p = extra_get_record(ctl->isoent,- &ctl->limit, &ctl->extr_off, &ctl->extr_loc);- ctl->bp = p - 1;/* the base of bp offset is 1. */- } else- /* Calculating the size of an extra record. */- (void)extra_get_record(ctl->isoent,- &ctl->limit, NULL, NULL);- ctl->cur_len = 0;- /* Check if an extra record is almost full.- * If so, get a next one. */- if (extra_space(ctl) < length)- (void)extra_next_record(ctl, length);-- return (ctl->bp);-}--static inline struct extr_rec *-extra_last_record(struct isoent *isoent)-{- if (isoent->extr_rec_list.first == NULL)- return (NULL);- return ((struct extr_rec *)(void *)- ((char *)(isoent->extr_rec_list.last)- - offsetof(struct extr_rec, next)));-}--static unsigned char *-extra_get_record(struct isoent *isoent, int *space, int *off, int *loc)-{- struct extr_rec *rec;-- isoent = isoent->parent;- if (off != NULL) {- /* Storing data into an extra record. */- rec = isoent->extr_rec_list.current;- if (DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset)- rec = rec->next;- } else {- /* Calculating the size of an extra record. */- rec = extra_last_record(isoent);- if (rec == NULL ||- DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset) {- rec = malloc(sizeof(*rec));- if (rec == NULL)- return (NULL);- rec->location = 0;- rec->offset = 0;- /* Insert `rec` into the tail of isoent->extr_rec_list */- rec->next = NULL;- /*- * Note: testing isoent->extr_rec_list.last == NULL- * here is really unneeded since it has been already- * initialized at isoent_new function but Clang Static- * Analyzer claims that it is dereference of null- * pointer.- */- if (isoent->extr_rec_list.last == NULL)- isoent->extr_rec_list.last =- &(isoent->extr_rec_list.first);- *isoent->extr_rec_list.last = rec;- isoent->extr_rec_list.last = &(rec->next);- }- }- *space = LOGICAL_BLOCK_SIZE - rec->offset - DR_SAFETY;- if (*space & 0x01)- *space -= 1;/* Keep padding space. */- if (off != NULL)- *off = rec->offset;- if (loc != NULL)- *loc = rec->location;- isoent->extr_rec_list.current = rec;-- return (&rec->buf[rec->offset]);-}--static void-extra_tell_used_size(struct ctl_extr_rec *ctl, int size)-{- struct isoent *isoent;- struct extr_rec *rec;-- if (ctl->use_extr) {- isoent = ctl->isoent->parent;- rec = isoent->extr_rec_list.current;- if (rec != NULL)- rec->offset += size;- }- ctl->cur_len += size;-}--static int-extra_setup_location(struct isoent *isoent, int location)-{- struct extr_rec *rec;- int cnt;-- cnt = 0;- rec = isoent->extr_rec_list.first;- isoent->extr_rec_list.current = rec;- while (rec) {- cnt++;- rec->location = location++;- rec->offset = 0;- rec = rec->next;- }- return (cnt);-}--/*- * Create the RRIP entries.- */-static int-set_directory_record_rr(unsigned char *bp, int dr_len,- struct isoent *isoent, struct iso9660 *iso9660, enum dir_rec_type t)-{- /* Flags(BP 5) of the Rockridge "RR" System Use Field */- unsigned char rr_flag;-#define RR_USE_PX 0x01-#define RR_USE_PN 0x02-#define RR_USE_SL 0x04-#define RR_USE_NM 0x08-#define RR_USE_CL 0x10-#define RR_USE_PL 0x20-#define RR_USE_RE 0x40-#define RR_USE_TF 0x80- int length;- struct ctl_extr_rec ctl;- struct isoent *rr_parent, *pxent;- struct isofile *file;-- bp = extra_open_record(bp, dr_len, isoent, &ctl);-- if (t == DIR_REC_PARENT) {- rr_parent = isoent->rr_parent;- pxent = isoent->parent;- if (rr_parent != NULL)- isoent = rr_parent;- else- isoent = isoent->parent;- } else {- rr_parent = NULL;- pxent = isoent;- }- file = isoent->file;-- if (t != DIR_REC_NORMAL) {- rr_flag = RR_USE_PX | RR_USE_TF;- if (rr_parent != NULL)- rr_flag |= RR_USE_PL;- } else {- rr_flag = RR_USE_PX | RR_USE_NM | RR_USE_TF;- if (archive_entry_filetype(file->entry) == AE_IFLNK)- rr_flag |= RR_USE_SL;- if (isoent->rr_parent != NULL)- rr_flag |= RR_USE_RE;- if (isoent->rr_child != NULL)- rr_flag |= RR_USE_CL;- if (archive_entry_filetype(file->entry) == AE_IFCHR ||- archive_entry_filetype(file->entry) == AE_IFBLK)- rr_flag |= RR_USE_PN;-#ifdef COMPAT_MKISOFS- /*- * mkisofs 2.01.01a63 records "RE" extension to- * the entry of "rr_moved" directory.- * I don't understand this behavior.- */- if (isoent->virtual &&- isoent->parent == iso9660->primary.rootent &&- strcmp(isoent->file->basename.s, "rr_moved") == 0)- rr_flag |= RR_USE_RE;-#endif- }-- /* Write "SP" System Use Entry. */- if (t == DIR_REC_SELF && isoent == isoent->parent) {- length = 7;- if (bp != NULL) {- bp[1] = 'S';- bp[2] = 'P';- bp[3] = length;- bp[4] = 1; /* version */- bp[5] = 0xBE; /* Check Byte */- bp[6] = 0xEF; /* Check Byte */- bp[7] = 0;- bp += length;- }- extra_tell_used_size(&ctl, length);- }-- /* Write "RR" System Use Entry. */- length = 5;- if (extra_space(&ctl) < length)- bp = extra_next_record(&ctl, length);- if (bp != NULL) {- bp[1] = 'R';- bp[2] = 'R';- bp[3] = length;- bp[4] = 1; /* version */- bp[5] = rr_flag;- bp += length;- }- extra_tell_used_size(&ctl, length);-- /* Write "NM" System Use Entry. */- if (rr_flag & RR_USE_NM) {- /*- * "NM" Format:- * e.g. a basename is 'foo'- * len ver flg- * +----+----+----+----+----+----+----+----+- * | 'N'| 'M'| 08 | 01 | 00 | 'f'| 'o'| 'o'|- * +----+----+----+----+----+----+----+----+- * <----------------- len ----------------->- */- size_t nmlen = file->basename.length;- const char *nm = file->basename.s;- size_t nmmax;-- if (extra_space(&ctl) < 6)- bp = extra_next_record(&ctl, 6);- if (bp != NULL) {- bp[1] = 'N';- bp[2] = 'M';- bp[4] = 1; /* version */- }- nmmax = extra_space(&ctl);- if (nmmax > 0xff)- nmmax = 0xff;- while (nmlen + 5 > nmmax) {- length = (int)nmmax;- if (bp != NULL) {- bp[3] = length;- bp[5] = 0x01;/* Alternate Name continues- * in next "NM" field */- memcpy(bp+6, nm, length - 5);- bp += length;- }- nmlen -= length - 5;- nm += length - 5;- extra_tell_used_size(&ctl, length);- if (extra_space(&ctl) < 6) {- bp = extra_next_record(&ctl, 6);- nmmax = extra_space(&ctl);- if (nmmax > 0xff)- nmmax = 0xff;- }- if (bp != NULL) {- bp[1] = 'N';- bp[2] = 'M';- bp[4] = 1; /* version */- }- }- length = 5 + (int)nmlen;- if (bp != NULL) {- bp[3] = length;- bp[5] = 0;- memcpy(bp+6, nm, nmlen);- bp += length;- }- extra_tell_used_size(&ctl, length);- }-- /* Write "PX" System Use Entry. */- if (rr_flag & RR_USE_PX) {- /*- * "PX" Format:- * len ver- * +----+----+----+----+-----------+-----------+- * | 'P'| 'X'| 2C | 01 | FILE MODE | LINKS |- * +----+----+----+----+-----------+-----------+- * 0 1 2 3 4 12 20- * +-----------+-----------+------------------+- * | USER ID | GROUP ID |FILE SERIAL NUMBER|- * +-----------+-----------+------------------+- * 20 28 36 44- */- length = 44;- if (extra_space(&ctl) < length)- bp = extra_next_record(&ctl, length);- if (bp != NULL) {- mode_t mode;- int64_t uid;- int64_t gid;-- mode = archive_entry_mode(file->entry);- uid = archive_entry_uid(file->entry);- gid = archive_entry_gid(file->entry);- if (iso9660->opt.rr == OPT_RR_USEFUL) {- /*- * This action is similar to mkisofs -r option- * but our rockridge=useful option does not- * set a zero to uid and gid.- */- /* set all read bit ON */- mode |= 0444;-#if !defined(_WIN32) && !defined(__CYGWIN__)- if (mode & 0111)-#endif- /* set all exec bit ON */- mode |= 0111;- /* clear all write bits. */- mode &= ~0222;- /* clear setuid,setgid,sticky bits. */- mode &= ~07000;- }-- bp[1] = 'P';- bp[2] = 'X';- bp[3] = length;- bp[4] = 1; /* version */- /* file mode */- set_num_733(bp+5, mode);- /* file links (stat.st_nlink) */- set_num_733(bp+13,- archive_entry_nlink(file->entry));- set_num_733(bp+21, (uint32_t)uid);- set_num_733(bp+29, (uint32_t)gid);- /* File Serial Number */- if (pxent->dir)- set_num_733(bp+37, pxent->dir_location);- else if (file->hardlink_target != NULL)- set_num_733(bp+37,- file->hardlink_target->cur_content->location);- else- set_num_733(bp+37,- file->cur_content->location);- bp += length;- }- extra_tell_used_size(&ctl, length);- }-- /* Write "SL" System Use Entry. */- if (rr_flag & RR_USE_SL) {- /*- * "SL" Format:- * e.g. a symbolic name is 'foo/bar'- * len ver flg- * +----+----+----+----+----+------------+- * | 'S'| 'L'| 0F | 01 | 00 | components |- * +----+----+----+----+----+-----+------+- * 0 1 2 3 4 5 ...|... 15- * <----------------- len --------+------>- * components : |- * cflg clen |- * +----+----+----+----+----+ |- * | 00 | 03 | 'f'| 'o'| 'o'| <---+- * +----+----+----+----+----+ |- * 5 6 7 8 9 10 |- * cflg clen |- * +----+----+----+----+----+ |- * | 00 | 03 | 'b'| 'a'| 'r'| <---+- * +----+----+----+----+----+- * 10 11 12 13 14 15- *- * - cflg : flag of component- * - clen : length of component- */- const char *sl;- char sl_last;-- if (extra_space(&ctl) < 7)- bp = extra_next_record(&ctl, 7);- sl = file->symlink.s;- sl_last = '\0';- if (bp != NULL) {- bp[1] = 'S';- bp[2] = 'L';- bp[4] = 1; /* version */- }- for (;;) {- unsigned char *nc, *cf, *cl, cldmy = 0;- int sllen, slmax;-- slmax = extra_space(&ctl);- if (slmax > 0xff)- slmax = 0xff;- if (bp != NULL)- nc = &bp[6];- else- nc = NULL;- cf = cl = NULL;- sllen = 0;- while (*sl && sllen + 11 < slmax) {- if (sl_last == '\0' && sl[0] == '/') {- /*- * flg len- * +----+----+- * | 08 | 00 | ROOT component.- * +----+----+ ("/")- *- * Root component has to appear- * at the first component only.- */- if (nc != NULL) {- cf = nc++;- *cf = 0x08; /* ROOT */- *nc++ = 0;- }- sllen += 2;- sl++;- sl_last = '/';- cl = NULL;- continue;- }- if (((sl_last == '\0' || sl_last == '/') &&- sl[0] == '.' && sl[1] == '.' &&- (sl[2] == '/' || sl[2] == '\0')) ||- (sl[0] == '/' &&- sl[1] == '.' && sl[2] == '.' &&- (sl[3] == '/' || sl[3] == '\0'))) {- /*- * flg len- * +----+----+- * | 04 | 00 | PARENT component.- * +----+----+ ("..")- */- if (nc != NULL) {- cf = nc++;- *cf = 0x04; /* PARENT */- *nc++ = 0;- }- sllen += 2;- if (sl[0] == '/')- sl += 3;/* skip "/.." */- else- sl += 2;/* skip ".." */- sl_last = '.';- cl = NULL;- continue;- }- if (((sl_last == '\0' || sl_last == '/') &&- sl[0] == '.' &&- (sl[1] == '/' || sl[1] == '\0')) ||- (sl[0] == '/' && sl[1] == '.' &&- (sl[2] == '/' || sl[2] == '\0'))) {- /*- * flg len- * +----+----+- * | 02 | 00 | CURRENT component.- * +----+----+ (".")- */- if (nc != NULL) {- cf = nc++;- *cf = 0x02; /* CURRENT */- *nc++ = 0;- }- sllen += 2;- if (sl[0] == '/')- sl += 2;/* skip "/." */- else- sl ++; /* skip "." */- sl_last = '.';- cl = NULL;- continue;- }- if (sl[0] == '/' || cl == NULL) {- if (nc != NULL) {- cf = nc++;- *cf = 0;- cl = nc++;- *cl = 0;- } else- cl = &cldmy;- sllen += 2;- if (sl[0] == '/') {- sl_last = *sl++;- continue;- }- }- sl_last = *sl++;- if (nc != NULL) {- *nc++ = sl_last;- (*cl) ++;- }- sllen++;- }- if (*sl) {- length = 5 + sllen;- if (bp != NULL) {- /*- * Mark flg as CONTINUE component.- */- *cf |= 0x01;- /*- * len ver flg- * +----+----+----+----+----+-- * | 'S'| 'L'| XX | 01 | 01 |- * +----+----+----+----+----+-- * ^- * continues in next "SL"- */- bp[3] = length;- bp[5] = 0x01;/* This Symbolic Link- * continues in next- * "SL" field */- bp += length;- }- extra_tell_used_size(&ctl, length);- if (extra_space(&ctl) < 11)- bp = extra_next_record(&ctl, 11);- if (bp != NULL) {- /* Next 'SL' */- bp[1] = 'S';- bp[2] = 'L';- bp[4] = 1; /* version */- }- } else {- length = 5 + sllen;- if (bp != NULL) {- bp[3] = length;- bp[5] = 0;- bp += length;- }- extra_tell_used_size(&ctl, length);- break;- }- }- }-- /* Write "TF" System Use Entry. */- if (rr_flag & RR_USE_TF) {- /*- * "TF" Format:- * len ver- * +----+----+----+----+-----+-------------+- * | 'T'| 'F'| XX | 01 |FLAGS| TIME STAMPS |- * +----+----+----+----+-----+-------------+- * 0 1 2 3 4 5 XX- * TIME STAMPS : ISO 9660 Standard 9.1.5.- * If TF_LONG_FORM FLAGS is set,- * use ISO9660 Standard 8.4.26.1.- */-#define TF_CREATION 0x01 /* Creation time recorded */-#define TF_MODIFY 0x02 /* Modification time recorded */-#define TF_ACCESS 0x04 /* Last Access time recorded */-#define TF_ATTRIBUTES 0x08 /* Last Attribute Change time recorded */-#define TF_BACKUP 0x10 /* Last Backup time recorded */-#define TF_EXPIRATION 0x20 /* Expiration time recorded */-#define TF_EFFECTIVE 0x40 /* Effective time recorded */-#define TF_LONG_FORM 0x80 /* ISO 9660 17-byte time format used */- unsigned char tf_flags;-- length = 5;- tf_flags = 0;-#ifndef COMPAT_MKISOFS- if (archive_entry_birthtime_is_set(file->entry) &&- archive_entry_birthtime(file->entry) <=- archive_entry_mtime(file->entry)) {- length += 7;- tf_flags |= TF_CREATION;- }-#endif- if (archive_entry_mtime_is_set(file->entry)) {- length += 7;- tf_flags |= TF_MODIFY;- }- if (archive_entry_atime_is_set(file->entry)) {- length += 7;- tf_flags |= TF_ACCESS;- }- if (archive_entry_ctime_is_set(file->entry)) {- length += 7;- tf_flags |= TF_ATTRIBUTES;- }- if (extra_space(&ctl) < length)- bp = extra_next_record(&ctl, length);- if (bp != NULL) {- bp[1] = 'T';- bp[2] = 'F';- bp[3] = length;- bp[4] = 1; /* version */- bp[5] = tf_flags;- bp += 5;- /* Creation time */- if (tf_flags & TF_CREATION) {- set_time_915(bp+1,- archive_entry_birthtime(file->entry));- bp += 7;- }- /* Modification time */- if (tf_flags & TF_MODIFY) {- set_time_915(bp+1,- archive_entry_mtime(file->entry));- bp += 7;- }- /* Last Access time */- if (tf_flags & TF_ACCESS) {- set_time_915(bp+1,- archive_entry_atime(file->entry));- bp += 7;- }- /* Last Attribute Change time */- if (tf_flags & TF_ATTRIBUTES) {- set_time_915(bp+1,- archive_entry_ctime(file->entry));- bp += 7;- }- }- extra_tell_used_size(&ctl, length);- }-- /* Write "RE" System Use Entry. */- if (rr_flag & RR_USE_RE) {- /*- * "RE" Format:- * len ver- * +----+----+----+----+- * | 'R'| 'E'| 04 | 01 |- * +----+----+----+----+- * 0 1 2 3 4- */- length = 4;- if (extra_space(&ctl) < length)- bp = extra_next_record(&ctl, length);- if (bp != NULL) {- bp[1] = 'R';- bp[2] = 'E';- bp[3] = length;- bp[4] = 1; /* version */- bp += length;- }- extra_tell_used_size(&ctl, length);- }-- /* Write "PL" System Use Entry. */- if (rr_flag & RR_USE_PL) {- /*- * "PL" Format:- * len ver- * +----+----+----+----+------------+- * | 'P'| 'L'| 0C | 01 | *LOCATION |- * +----+----+----+----+------------+- * 0 1 2 3 4 12- * *LOCATION: location of parent directory- */- length = 12;- if (extra_space(&ctl) < length)- bp = extra_next_record(&ctl, length);- if (bp != NULL) {- bp[1] = 'P';- bp[2] = 'L';- bp[3] = length;- bp[4] = 1; /* version */- set_num_733(bp + 5,- rr_parent->dir_location);- bp += length;- }- extra_tell_used_size(&ctl, length);- }-- /* Write "CL" System Use Entry. */- if (rr_flag & RR_USE_CL) {- /*- * "CL" Format:- * len ver- * +----+----+----+----+------------+- * | 'C'| 'L'| 0C | 01 | *LOCATION |- * +----+----+----+----+------------+- * 0 1 2 3 4 12- * *LOCATION: location of child directory- */- length = 12;- if (extra_space(&ctl) < length)- bp = extra_next_record(&ctl, length);- if (bp != NULL) {- bp[1] = 'C';- bp[2] = 'L';- bp[3] = length;- bp[4] = 1; /* version */- set_num_733(bp + 5,- isoent->rr_child->dir_location);- bp += length;- }- extra_tell_used_size(&ctl, length);- }-- /* Write "PN" System Use Entry. */- if (rr_flag & RR_USE_PN) {- /*- * "PN" Format:- * len ver- * +----+----+----+----+------------+------------+- * | 'P'| 'N'| 14 | 01 | dev_t high | dev_t low |- * +----+----+----+----+------------+------------+- * 0 1 2 3 4 12 20- */- length = 20;- if (extra_space(&ctl) < length)- bp = extra_next_record(&ctl, length);- if (bp != NULL) {- uint64_t dev;-- bp[1] = 'P';- bp[2] = 'N';- bp[3] = length;- bp[4] = 1; /* version */- dev = (uint64_t)archive_entry_rdev(file->entry);- set_num_733(bp + 5, (uint32_t)(dev >> 32));- set_num_733(bp + 13, (uint32_t)(dev & 0xFFFFFFFF));- bp += length;- }- extra_tell_used_size(&ctl, length);- }-- /* Write "ZF" System Use Entry. */- if (file->zisofs.header_size) {- /*- * "ZF" Format:- * len ver- * +----+----+----+----+----+----+-------------+- * | 'Z'| 'F'| 10 | 01 | 'p'| 'z'| Header Size |- * +----+----+----+----+----+----+-------------+- * 0 1 2 3 4 5 6 7- * +--------------------+-------------------+- * | Log2 of block Size | Uncompressed Size |- * +--------------------+-------------------+- * 7 8 16- */- length = 16;- if (extra_space(&ctl) < length)- bp = extra_next_record(&ctl, length);- if (bp != NULL) {- bp[1] = 'Z';- bp[2] = 'F';- bp[3] = length;- bp[4] = 1; /* version */- bp[5] = 'p';- bp[6] = 'z';- bp[7] = file->zisofs.header_size;- bp[8] = file->zisofs.log2_bs;- set_num_733(bp + 9, file->zisofs.uncompressed_size);- bp += length;- }- extra_tell_used_size(&ctl, length);- }-- /* Write "CE" System Use Entry. */- if (t == DIR_REC_SELF && isoent == isoent->parent) {- length = RR_CE_SIZE;- if (bp != NULL)- set_SUSP_CE(bp+1, iso9660->location_rrip_er,- 0, RRIP_ER_SIZE);- extra_tell_used_size(&ctl, length);- }-- extra_close_record(&ctl, 0);-- return (ctl.dr_len);-}--/*- * Write data of a Directory Record or calculate writing bytes itself.- * If parameter `p' is NULL, calculates the size of writing data, which- * a Directory Record needs to write, then it saved and return- * the calculated size.- * Parameter `n' is a remaining size of buffer. when parameter `p' is- * not NULL, check whether that `n' is not less than the saved size.- * if that `n' is small, return zero.- *- * This format of the Directory Record is according to- * ISO9660 Standard 9.1- */-static int-set_directory_record(unsigned char *p, size_t n, struct isoent *isoent,- struct iso9660 *iso9660, enum dir_rec_type t,- enum vdd_type vdd_type)-{- unsigned char *bp;- size_t dr_len;- size_t fi_len;-- if (p != NULL) {- /*- * Check whether a write buffer size is less than the- * saved size which is needed to write this Directory- * Record.- */- switch (t) {- case DIR_REC_VD:- dr_len = isoent->dr_len.vd; break;- case DIR_REC_SELF:- dr_len = isoent->dr_len.self; break;- case DIR_REC_PARENT:- dr_len = isoent->dr_len.parent; break;- case DIR_REC_NORMAL:- default:- dr_len = isoent->dr_len.normal; break;- }- if (dr_len > n)- return (0);/* Needs more buffer size. */- }-- if (t == DIR_REC_NORMAL && isoent->identifier != NULL)- fi_len = isoent->id_len;- else- fi_len = 1;-- if (p != NULL) {- struct isoent *xisoent;- struct isofile *file;- unsigned char flag;-- if (t == DIR_REC_PARENT)- xisoent = isoent->parent;- else- xisoent = isoent;- file = isoent->file;- if (file->hardlink_target != NULL)- file = file->hardlink_target;- /* Make a file flag. */- if (xisoent->dir)- flag = FILE_FLAG_DIRECTORY;- else {- if (file->cur_content->next != NULL)- flag = FILE_FLAG_MULTI_EXTENT;- else- flag = 0;- }-- bp = p -1;- /* Extended Attribute Record Length */- set_num_711(bp+2, 0);- /* Location of Extent */- if (xisoent->dir)- set_num_733(bp+3, xisoent->dir_location);- else- set_num_733(bp+3, file->cur_content->location);- /* Data Length */- if (xisoent->dir)- set_num_733(bp+11,- xisoent->dir_block * LOGICAL_BLOCK_SIZE);- else- set_num_733(bp+11, (uint32_t)file->cur_content->size);- /* Recording Date and Time */- /* NOTE:- * If a file type is symbolic link, you are seeing this- * field value is different from a value mkisofs makes.- * libarchive uses lstat to get this one, but it- * seems mkisofs uses stat to get.- */- set_time_915(bp+19,- archive_entry_mtime(xisoent->file->entry));- /* File Flags */- bp[26] = flag;- /* File Unit Size */- set_num_711(bp+27, 0);- /* Interleave Gap Size */- set_num_711(bp+28, 0);- /* Volume Sequence Number */- set_num_723(bp+29, iso9660->volume_sequence_number);- /* Length of File Identifier */- set_num_711(bp+33, (unsigned char)fi_len);- /* File Identifier */- switch (t) {- case DIR_REC_VD:- case DIR_REC_SELF:- set_num_711(bp+34, 0);- break;- case DIR_REC_PARENT:- set_num_711(bp+34, 1);- break;- case DIR_REC_NORMAL:- if (isoent->identifier != NULL)- memcpy(bp+34, isoent->identifier, fi_len);- else- set_num_711(bp+34, 0);- break;- }- } else- bp = NULL;- dr_len = 33 + fi_len;- /* Padding Field */- if (dr_len & 0x01) {- dr_len ++;- if (p != NULL)- bp[dr_len] = 0;- }-- /* Volume Descriptor does not record extension. */- if (t == DIR_REC_VD) {- if (p != NULL)- /* Length of Directory Record */- set_num_711(p, (unsigned char)dr_len);- else- isoent->dr_len.vd = (int)dr_len;- return ((int)dr_len);- }-- /* Rockridge */- if (iso9660->opt.rr && vdd_type != VDD_JOLIET)- dr_len = set_directory_record_rr(bp, (int)dr_len,- isoent, iso9660, t);-- if (p != NULL)- /* Length of Directory Record */- set_num_711(p, (unsigned char)dr_len);- else {- /*- * Save the size which is needed to write this- * Directory Record.- */- switch (t) {- case DIR_REC_VD:- /* This case does not come, but compiler- * complains that DIR_REC_VD not handled- * in switch .... */- break;- case DIR_REC_SELF:- isoent->dr_len.self = (int)dr_len; break;- case DIR_REC_PARENT:- isoent->dr_len.parent = (int)dr_len; break;- case DIR_REC_NORMAL:- isoent->dr_len.normal = (int)dr_len; break;- }- }-- return ((int)dr_len);-}--/*- * Calculate the size of a directory record.- */-static inline int-get_dir_rec_size(struct iso9660 *iso9660, struct isoent *isoent,- enum dir_rec_type t, enum vdd_type vdd_type)-{-- return (set_directory_record(NULL, SIZE_MAX,- isoent, iso9660, t, vdd_type));-}--/*- * Manage to write ISO-image data with wbuff to reduce calling- * __archive_write_output() for performance.- */---static inline unsigned char *-wb_buffptr(struct archive_write *a)-{- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;-- return (&(iso9660->wbuff[sizeof(iso9660->wbuff)- - iso9660->wbuff_remaining]));-}--static int-wb_write_out(struct archive_write *a)-{- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;- size_t wsize, nw;- int r;-- wsize = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;- nw = wsize % LOGICAL_BLOCK_SIZE;- if (iso9660->wbuff_type == WB_TO_STREAM)- r = __archive_write_output(a, iso9660->wbuff, wsize - nw);- else- r = write_to_temp(a, iso9660->wbuff, wsize - nw);- /* Increase the offset. */- iso9660->wbuff_offset += wsize - nw;- if (iso9660->wbuff_offset > iso9660->wbuff_written)- iso9660->wbuff_written = iso9660->wbuff_offset;- iso9660->wbuff_remaining = sizeof(iso9660->wbuff);- if (nw) {- iso9660->wbuff_remaining -= nw;- memmove(iso9660->wbuff, iso9660->wbuff + wsize - nw, nw);- }- return (r);-}--static int-wb_consume(struct archive_write *a, size_t size)-{- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;-- if (size > iso9660->wbuff_remaining ||- iso9660->wbuff_remaining == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Internal Programming error: iso9660:wb_consume()"- " size=%jd, wbuff_remaining=%jd",- (intmax_t)size, (intmax_t)iso9660->wbuff_remaining);- return (ARCHIVE_FATAL);- }- iso9660->wbuff_remaining -= size;- if (iso9660->wbuff_remaining < LOGICAL_BLOCK_SIZE)- return (wb_write_out(a));- return (ARCHIVE_OK);-}--#ifdef HAVE_ZLIB_H--static int-wb_set_offset(struct archive_write *a, int64_t off)-{- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;- int64_t used, ext_bytes;-- if (iso9660->wbuff_type != WB_TO_TEMP) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Internal Programming error: iso9660:wb_set_offset()");- return (ARCHIVE_FATAL);- }-- used = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;- if (iso9660->wbuff_offset + used > iso9660->wbuff_tail)- iso9660->wbuff_tail = iso9660->wbuff_offset + used;- if (iso9660->wbuff_offset < iso9660->wbuff_written) {- if (used > 0 &&- write_to_temp(a, iso9660->wbuff, (size_t)used) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- iso9660->wbuff_offset = iso9660->wbuff_written;- lseek(iso9660->temp_fd, iso9660->wbuff_offset, SEEK_SET);- iso9660->wbuff_remaining = sizeof(iso9660->wbuff);- used = 0;- }- if (off < iso9660->wbuff_offset) {- /*- * Write out waiting data.- */- if (used > 0) {- if (wb_write_out(a) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }- lseek(iso9660->temp_fd, off, SEEK_SET);- iso9660->wbuff_offset = off;- iso9660->wbuff_remaining = sizeof(iso9660->wbuff);- } else if (off <= iso9660->wbuff_tail) {- iso9660->wbuff_remaining = (size_t)- (sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset));- } else {- ext_bytes = off - iso9660->wbuff_tail;- iso9660->wbuff_remaining = (size_t)(sizeof(iso9660->wbuff)- - (iso9660->wbuff_tail - iso9660->wbuff_offset));- while (ext_bytes >= (int64_t)iso9660->wbuff_remaining) {- if (write_null(a, (size_t)iso9660->wbuff_remaining)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);- ext_bytes -= iso9660->wbuff_remaining;- }- if (ext_bytes > 0) {- if (write_null(a, (size_t)ext_bytes) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }- }- return (ARCHIVE_OK);-}--#endif /* HAVE_ZLIB_H */--static int-write_null(struct archive_write *a, size_t size)-{- size_t remaining;- unsigned char *p, *old;- int r;-- remaining = wb_remaining(a);- p = wb_buffptr(a);- if (size <= remaining) {- memset(p, 0, size);- return (wb_consume(a, size));- }- memset(p, 0, remaining);- r = wb_consume(a, remaining);- if (r != ARCHIVE_OK)- return (r);- size -= remaining;- old = p;- p = wb_buffptr(a);- memset(p, 0, old - p);- remaining = wb_remaining(a);- while (size) {- size_t wsize = size;-- if (wsize > remaining)- wsize = remaining;- r = wb_consume(a, wsize);- if (r != ARCHIVE_OK)- return (r);- size -= wsize;- }- return (ARCHIVE_OK);-}--/*- * Write Volume Descriptor Set Terminator- */-static int-write_VD_terminator(struct archive_write *a)-{- unsigned char *bp;-- bp = wb_buffptr(a) -1;- set_VD_bp(bp, VDT_TERMINATOR, 1);- set_unused_field_bp(bp, 8, LOGICAL_BLOCK_SIZE);-- return (wb_consume(a, LOGICAL_BLOCK_SIZE));-}--static int-set_file_identifier(unsigned char *bp, int from, int to, enum vdc vdc,- struct archive_write *a, struct vdd *vdd, struct archive_string *id,- const char *label, int leading_under, enum char_type char_type)-{- char identifier[256];- struct isoent *isoent;- const char *ids;- size_t len;- int r;-- if (id->length > 0 && leading_under && id->s[0] != '_') {- if (char_type == A_CHAR)- r = set_str_a_characters_bp(a, bp, from, to, id->s, vdc);- else- r = set_str_d_characters_bp(a, bp, from, to, id->s, vdc);- } else if (id->length > 0) {- ids = id->s;- if (leading_under)- ids++;- isoent = isoent_find_entry(vdd->rootent, ids);- if (isoent == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Not Found %s `%s'.",- label, ids);- return (ARCHIVE_FATAL);- }- len = isoent->ext_off + isoent->ext_len;- if (vdd->vdd_type == VDD_JOLIET) {- if (len > sizeof(identifier)-2)- len = sizeof(identifier)-2;- } else {- if (len > sizeof(identifier)-1)- len = sizeof(identifier)-1;- }- memcpy(identifier, isoent->identifier, len);- identifier[len] = '\0';- if (vdd->vdd_type == VDD_JOLIET) {- identifier[len+1] = 0;- vdc = VDC_UCS2_DIRECT;- }- if (char_type == A_CHAR)- r = set_str_a_characters_bp(a, bp, from, to,- identifier, vdc);- else- r = set_str_d_characters_bp(a, bp, from, to,- identifier, vdc);- } else {- if (char_type == A_CHAR)- r = set_str_a_characters_bp(a, bp, from, to, NULL, vdc);- else- r = set_str_d_characters_bp(a, bp, from, to, NULL, vdc);- }- return (r);-}--/*- * Write Primary/Supplementary Volume Descriptor- */-static int-write_VD(struct archive_write *a, struct vdd *vdd)-{- struct iso9660 *iso9660;- unsigned char *bp;- uint16_t volume_set_size = 1;- char identifier[256];- enum VD_type vdt;- enum vdc vdc;- unsigned char vd_ver, fst_ver;- int r;-- iso9660 = a->format_data;- switch (vdd->vdd_type) {- case VDD_JOLIET:- vdt = VDT_SUPPLEMENTARY;- vd_ver = fst_ver = 1;- vdc = VDC_UCS2;- break;- case VDD_ENHANCED:- vdt = VDT_SUPPLEMENTARY;- vd_ver = fst_ver = 2;- vdc = VDC_LOWERCASE;- break;- case VDD_PRIMARY:- default:- vdt = VDT_PRIMARY;- vd_ver = fst_ver = 1;-#ifdef COMPAT_MKISOFS- vdc = VDC_LOWERCASE;-#else- vdc = VDC_STD;-#endif- break;- }-- bp = wb_buffptr(a) -1;- /* Volume Descriptor Type */- set_VD_bp(bp, vdt, vd_ver);- /* Unused Field */- set_unused_field_bp(bp, 8, 8);- /* System Identifier */- get_system_identitier(identifier, sizeof(identifier));- r = set_str_a_characters_bp(a, bp, 9, 40, identifier, vdc);- if (r != ARCHIVE_OK)- return (r);- /* Volume Identifier */- r = set_str_d_characters_bp(a, bp, 41, 72,- iso9660->volume_identifier.s, vdc);- if (r != ARCHIVE_OK)- return (r);- /* Unused Field */- set_unused_field_bp(bp, 73, 80);- /* Volume Space Size */- set_num_733(bp+81, iso9660->volume_space_size);- if (vdd->vdd_type == VDD_JOLIET) {- /* Escape Sequences */- bp[89] = 0x25;/* UCS-2 Level 3 */- bp[90] = 0x2F;- bp[91] = 0x45;- memset(bp + 92, 0, 120 - 92 + 1);- } else {- /* Unused Field */- set_unused_field_bp(bp, 89, 120);- }- /* Volume Set Size */- set_num_723(bp+121, volume_set_size);- /* Volume Sequence Number */- set_num_723(bp+125, iso9660->volume_sequence_number);- /* Logical Block Size */- set_num_723(bp+129, LOGICAL_BLOCK_SIZE);- /* Path Table Size */- set_num_733(bp+133, vdd->path_table_size);- /* Location of Occurrence of Type L Path Table */- set_num_731(bp+141, vdd->location_type_L_path_table);- /* Location of Optional Occurrence of Type L Path Table */- set_num_731(bp+145, 0);- /* Location of Occurrence of Type M Path Table */- set_num_732(bp+149, vdd->location_type_M_path_table);- /* Location of Optional Occurrence of Type M Path Table */- set_num_732(bp+153, 0);- /* Directory Record for Root Directory(BP 157 to 190) */- set_directory_record(bp+157, 190-157+1, vdd->rootent,- iso9660, DIR_REC_VD, vdd->vdd_type);- /* Volume Set Identifier */- r = set_str_d_characters_bp(a, bp, 191, 318, "", vdc);- if (r != ARCHIVE_OK)- return (r);- /* Publisher Identifier */- r = set_file_identifier(bp, 319, 446, vdc, a, vdd,- &(iso9660->publisher_identifier),- "Publisher File", 1, A_CHAR);- if (r != ARCHIVE_OK)- return (r);- /* Data Preparer Identifier */- r = set_file_identifier(bp, 447, 574, vdc, a, vdd,- &(iso9660->data_preparer_identifier),- "Data Preparer File", 1, A_CHAR);- if (r != ARCHIVE_OK)- return (r);- /* Application Identifier */- r = set_file_identifier(bp, 575, 702, vdc, a, vdd,- &(iso9660->application_identifier),- "Application File", 1, A_CHAR);- if (r != ARCHIVE_OK)- return (r);- /* Copyright File Identifier */- r = set_file_identifier(bp, 703, 739, vdc, a, vdd,- &(iso9660->copyright_file_identifier),- "Copyright File", 0, D_CHAR);- if (r != ARCHIVE_OK)- return (r);- /* Abstract File Identifier */- r = set_file_identifier(bp, 740, 776, vdc, a, vdd,- &(iso9660->abstract_file_identifier),- "Abstract File", 0, D_CHAR);- if (r != ARCHIVE_OK)- return (r);- /* Bibliographic File Identifier */- r = set_file_identifier(bp, 777, 813, vdc, a, vdd,- &(iso9660->bibliographic_file_identifier),- "Bibliongraphic File", 0, D_CHAR);- if (r != ARCHIVE_OK)- return (r);- /* Volume Creation Date and Time */- set_date_time(bp+814, iso9660->birth_time);- /* Volume Modification Date and Time */- set_date_time(bp+831, iso9660->birth_time);- /* Volume Expiration Date and Time(obsolete) */- set_date_time_null(bp+848);- /* Volume Effective Date and Time */- set_date_time(bp+865, iso9660->birth_time);- /* File Structure Version */- bp[882] = fst_ver;- /* Reserved */- bp[883] = 0;- /* Application Use */- memset(bp + 884, 0x20, 1395 - 884 + 1);- /* Reserved */- set_unused_field_bp(bp, 1396, LOGICAL_BLOCK_SIZE);-- return (wb_consume(a, LOGICAL_BLOCK_SIZE));-}--/*- * Write Boot Record Volume Descriptor- */-static int-write_VD_boot_record(struct archive_write *a)-{- struct iso9660 *iso9660;- unsigned char *bp;-- iso9660 = a->format_data;- bp = wb_buffptr(a) -1;- /* Volume Descriptor Type */- set_VD_bp(bp, VDT_BOOT_RECORD, 1);- /* Boot System Identifier */- memcpy(bp+8, "EL TORITO SPECIFICATION", 23);- set_unused_field_bp(bp, 8+23, 39);- /* Unused */- set_unused_field_bp(bp, 40, 71);- /* Absolute pointer to first sector of Boot Catalog */- set_num_731(bp+72,- iso9660->el_torito.catalog->file->content.location);- /* Unused */- set_unused_field_bp(bp, 76, LOGICAL_BLOCK_SIZE);-- return (wb_consume(a, LOGICAL_BLOCK_SIZE));-}--enum keytype {- KEY_FLG,- KEY_STR,- KEY_INT,- KEY_HEX-};-static void-set_option_info(struct archive_string *info, int *opt, const char *key,- enum keytype type, ...)-{- va_list ap;- char prefix;- const char *s;- int d;-- prefix = (*opt==0)? ' ':',';- va_start(ap, type);- switch (type) {- case KEY_FLG:- d = va_arg(ap, int);- archive_string_sprintf(info, "%c%s%s",- prefix, (d == 0)?"!":"", key);- break;- case KEY_STR:- s = va_arg(ap, const char *);- archive_string_sprintf(info, "%c%s=%s",- prefix, key, s);- break;- case KEY_INT:- d = va_arg(ap, int);- archive_string_sprintf(info, "%c%s=%d",- prefix, key, d);- break;- case KEY_HEX:- d = va_arg(ap, int);- archive_string_sprintf(info, "%c%s=%x",- prefix, key, d);- break;- }- va_end(ap);-- *opt = 1;-}--/*- * Make Non-ISO File System Information- */-static int-write_information_block(struct archive_write *a)-{- struct iso9660 *iso9660;- char buf[128];- const char *v;- int opt, r;- struct archive_string info;- size_t info_size = LOGICAL_BLOCK_SIZE *- NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;-- iso9660 = (struct iso9660 *)a->format_data;- if (info_size > wb_remaining(a)) {- r = wb_write_out(a);- if (r != ARCHIVE_OK)- return (r);- }- archive_string_init(&info);- if (archive_string_ensure(&info, info_size) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- memset(info.s, 0, info_size);- opt = 0;-#if defined(HAVE_CTIME_S)- ctime_s(buf, sizeof(buf), &(iso9660->birth_time));-#elif defined(HAVE_CTIME_R)- ctime_r(&(iso9660->birth_time), buf);-#else- strncpy(buf, ctime(&(iso9660->birth_time)), sizeof(buf)-1);- buf[sizeof(buf)-1] = '\0';-#endif- archive_string_sprintf(&info,- "INFO %s%s", buf, archive_version_string());- if (iso9660->opt.abstract_file != OPT_ABSTRACT_FILE_DEFAULT)- set_option_info(&info, &opt, "abstract-file",- KEY_STR, iso9660->abstract_file_identifier.s);- if (iso9660->opt.application_id != OPT_APPLICATION_ID_DEFAULT)- set_option_info(&info, &opt, "application-id",- KEY_STR, iso9660->application_identifier.s);- if (iso9660->opt.allow_vernum != OPT_ALLOW_VERNUM_DEFAULT)- set_option_info(&info, &opt, "allow-vernum",- KEY_FLG, iso9660->opt.allow_vernum);- if (iso9660->opt.biblio_file != OPT_BIBLIO_FILE_DEFAULT)- set_option_info(&info, &opt, "biblio-file",- KEY_STR, iso9660->bibliographic_file_identifier.s);- if (iso9660->opt.boot != OPT_BOOT_DEFAULT)- set_option_info(&info, &opt, "boot",- KEY_STR, iso9660->el_torito.boot_filename.s);- if (iso9660->opt.boot_catalog != OPT_BOOT_CATALOG_DEFAULT)- set_option_info(&info, &opt, "boot-catalog",- KEY_STR, iso9660->el_torito.catalog_filename.s);- if (iso9660->opt.boot_info_table != OPT_BOOT_INFO_TABLE_DEFAULT)- set_option_info(&info, &opt, "boot-info-table",- KEY_FLG, iso9660->opt.boot_info_table);- if (iso9660->opt.boot_load_seg != OPT_BOOT_LOAD_SEG_DEFAULT)- set_option_info(&info, &opt, "boot-load-seg",- KEY_HEX, iso9660->el_torito.boot_load_seg);- if (iso9660->opt.boot_load_size != OPT_BOOT_LOAD_SIZE_DEFAULT)- set_option_info(&info, &opt, "boot-load-size",- KEY_INT, iso9660->el_torito.boot_load_size);- if (iso9660->opt.boot_type != OPT_BOOT_TYPE_DEFAULT) {- v = "no-emulation";- if (iso9660->opt.boot_type == OPT_BOOT_TYPE_FD)- v = "fd";- if (iso9660->opt.boot_type == OPT_BOOT_TYPE_HARD_DISK)- v = "hard-disk";- set_option_info(&info, &opt, "boot-type",- KEY_STR, v);- }-#ifdef HAVE_ZLIB_H- if (iso9660->opt.compression_level != OPT_COMPRESSION_LEVEL_DEFAULT)- set_option_info(&info, &opt, "compression-level",- KEY_INT, iso9660->zisofs.compression_level);-#endif- if (iso9660->opt.copyright_file != OPT_COPYRIGHT_FILE_DEFAULT)- set_option_info(&info, &opt, "copyright-file",- KEY_STR, iso9660->copyright_file_identifier.s);- if (iso9660->opt.iso_level != OPT_ISO_LEVEL_DEFAULT)- set_option_info(&info, &opt, "iso-level",- KEY_INT, iso9660->opt.iso_level);- if (iso9660->opt.joliet != OPT_JOLIET_DEFAULT) {- if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)- set_option_info(&info, &opt, "joliet",- KEY_STR, "long");- else- set_option_info(&info, &opt, "joliet",- KEY_FLG, iso9660->opt.joliet);- }- if (iso9660->opt.limit_depth != OPT_LIMIT_DEPTH_DEFAULT)- set_option_info(&info, &opt, "limit-depth",- KEY_FLG, iso9660->opt.limit_depth);- if (iso9660->opt.limit_dirs != OPT_LIMIT_DIRS_DEFAULT)- set_option_info(&info, &opt, "limit-dirs",- KEY_FLG, iso9660->opt.limit_dirs);- if (iso9660->opt.pad != OPT_PAD_DEFAULT)- set_option_info(&info, &opt, "pad",- KEY_FLG, iso9660->opt.pad);- if (iso9660->opt.publisher != OPT_PUBLISHER_DEFAULT)- set_option_info(&info, &opt, "publisher",- KEY_STR, iso9660->publisher_identifier.s);- if (iso9660->opt.rr != OPT_RR_DEFAULT) {- if (iso9660->opt.rr == OPT_RR_DISABLED)- set_option_info(&info, &opt, "rockridge",- KEY_FLG, iso9660->opt.rr);- else if (iso9660->opt.rr == OPT_RR_STRICT)- set_option_info(&info, &opt, "rockridge",- KEY_STR, "strict");- else if (iso9660->opt.rr == OPT_RR_USEFUL)- set_option_info(&info, &opt, "rockridge",- KEY_STR, "useful");- }- if (iso9660->opt.volume_id != OPT_VOLUME_ID_DEFAULT)- set_option_info(&info, &opt, "volume-id",- KEY_STR, iso9660->volume_identifier.s);- if (iso9660->opt.zisofs != OPT_ZISOFS_DEFAULT)- set_option_info(&info, &opt, "zisofs",- KEY_FLG, iso9660->opt.zisofs);-- memcpy(wb_buffptr(a), info.s, info_size);- archive_string_free(&info);- return (wb_consume(a, info_size));-}--static int-write_rr_ER(struct archive_write *a)-{- unsigned char *p;-- p = wb_buffptr(a);-- memset(p, 0, LOGICAL_BLOCK_SIZE);- p[0] = 'E';- p[1] = 'R';- p[3] = 0x01;- p[2] = RRIP_ER_SIZE;- p[4] = RRIP_ER_ID_SIZE;- p[5] = RRIP_ER_DSC_SIZE;- p[6] = RRIP_ER_SRC_SIZE;- p[7] = 0x01;- memcpy(&p[8], rrip_identifier, p[4]);- memcpy(&p[8+p[4]], rrip_descriptor, p[5]);- memcpy(&p[8+p[4]+p[5]], rrip_source, p[6]);-- return (wb_consume(a, LOGICAL_BLOCK_SIZE));-}--static void-calculate_path_table_size(struct vdd *vdd)-{- int depth, size;- struct path_table *pt;-- pt = vdd->pathtbl;- size = 0;- for (depth = 0; depth < vdd->max_depth; depth++) {- struct isoent **ptbl;- int i, cnt;-- if ((cnt = pt[depth].cnt) == 0)- break;-- ptbl = pt[depth].sorted;- for (i = 0; i < cnt; i++) {- int len;-- if (ptbl[i]->identifier == NULL)- len = 1; /* root directory */- else- len = ptbl[i]->id_len;- if (len & 0x01)- len++; /* Padding Field */- size += 8 + len;- }- }- vdd->path_table_size = size;- vdd->path_table_block =- ((size + PATH_TABLE_BLOCK_SIZE -1) /- PATH_TABLE_BLOCK_SIZE) *- (PATH_TABLE_BLOCK_SIZE / LOGICAL_BLOCK_SIZE);-}--static int-_write_path_table(struct archive_write *a, int type_m, int depth,- struct vdd *vdd)-{- unsigned char *bp, *wb;- struct isoent **ptbl;- size_t wbremaining;- int i, r, wsize;-- if (vdd->pathtbl[depth].cnt == 0)- return (0);-- wsize = 0;- wb = wb_buffptr(a);- wbremaining = wb_remaining(a);- bp = wb - 1;- ptbl = vdd->pathtbl[depth].sorted;- for (i = 0; i < vdd->pathtbl[depth].cnt; i++) {- struct isoent *np;- size_t len;-- np = ptbl[i];- if (np->identifier == NULL)- len = 1; /* root directory */- else- len = np->id_len;- if (wbremaining - ((bp+1) - wb) < (len + 1 + 8)) {- r = wb_consume(a, (bp+1) - wb);- if (r < 0)- return (r);- wb = wb_buffptr(a);- wbremaining = wb_remaining(a);- bp = wb -1;- }- /* Length of Directory Identifier */- set_num_711(bp+1, (unsigned char)len);- /* Extended Attribute Record Length */- set_num_711(bp+2, 0);- /* Location of Extent */- if (type_m)- set_num_732(bp+3, np->dir_location);- else- set_num_731(bp+3, np->dir_location);- /* Parent Directory Number */- if (type_m)- set_num_722(bp+7, np->parent->dir_number);- else- set_num_721(bp+7, np->parent->dir_number);- /* Directory Identifier */- if (np->identifier == NULL)- bp[9] = 0;- else- memcpy(&bp[9], np->identifier, len);- if (len & 0x01) {- /* Padding Field */- bp[9+len] = 0;- len++;- }- wsize += 8 + (int)len;- bp += 8 + len;- }- if ((bp + 1) > wb) {- r = wb_consume(a, (bp+1)-wb);- if (r < 0)- return (r);- }- return (wsize);-}--static int-write_path_table(struct archive_write *a, int type_m, struct vdd *vdd)-{- int depth, r;- size_t path_table_size;-- r = ARCHIVE_OK;- path_table_size = 0;- for (depth = 0; depth < vdd->max_depth; depth++) {- r = _write_path_table(a, type_m, depth, vdd);- if (r < 0)- return (r);- path_table_size += r;- }-- /* Write padding data. */- path_table_size = path_table_size % PATH_TABLE_BLOCK_SIZE;- if (path_table_size > 0)- r = write_null(a, PATH_TABLE_BLOCK_SIZE - path_table_size);- return (r);-}--static int-calculate_directory_descriptors(struct iso9660 *iso9660, struct vdd *vdd,- struct isoent *isoent, int depth)-{- struct isoent **enttbl;- int bs, block, i;-- block = 1;- bs = get_dir_rec_size(iso9660, isoent, DIR_REC_SELF, vdd->vdd_type);- bs += get_dir_rec_size(iso9660, isoent, DIR_REC_PARENT, vdd->vdd_type);-- if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&- !iso9660->opt.rr && depth + 1 >= vdd->max_depth))- return (block);-- enttbl = isoent->children_sorted;- for (i = 0; i < isoent->children.cnt; i++) {- struct isoent *np = enttbl[i];- struct isofile *file;-- file = np->file;- if (file->hardlink_target != NULL)- file = file->hardlink_target;- file->cur_content = &(file->content);- do {- int dr_l;-- dr_l = get_dir_rec_size(iso9660, np, DIR_REC_NORMAL,- vdd->vdd_type);- if ((bs + dr_l) > LOGICAL_BLOCK_SIZE) {- block ++;- bs = dr_l;- } else- bs += dr_l;- file->cur_content = file->cur_content->next;- } while (file->cur_content != NULL);- }- return (block);-}--static int-_write_directory_descriptors(struct archive_write *a, struct vdd *vdd,- struct isoent *isoent, int depth)-{- struct iso9660 *iso9660 = a->format_data;- struct isoent **enttbl;- unsigned char *p, *wb;- int i, r;- int dr_l;-- p = wb = wb_buffptr(a);-#define WD_REMAINING (LOGICAL_BLOCK_SIZE - (p - wb))- p += set_directory_record(p, WD_REMAINING, isoent,- iso9660, DIR_REC_SELF, vdd->vdd_type);- p += set_directory_record(p, WD_REMAINING, isoent,- iso9660, DIR_REC_PARENT, vdd->vdd_type);-- if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&- !iso9660->opt.rr && depth + 1 >= vdd->max_depth)) {- memset(p, 0, WD_REMAINING);- return (wb_consume(a, LOGICAL_BLOCK_SIZE));- }-- enttbl = isoent->children_sorted;- for (i = 0; i < isoent->children.cnt; i++) {- struct isoent *np = enttbl[i];- struct isofile *file = np->file;-- if (file->hardlink_target != NULL)- file = file->hardlink_target;- file->cur_content = &(file->content);- do {- dr_l = set_directory_record(p, WD_REMAINING,- np, iso9660, DIR_REC_NORMAL,- vdd->vdd_type);- if (dr_l == 0) {- memset(p, 0, WD_REMAINING);- r = wb_consume(a, LOGICAL_BLOCK_SIZE);- if (r < 0)- return (r);- p = wb = wb_buffptr(a);- dr_l = set_directory_record(p,- WD_REMAINING, np, iso9660,- DIR_REC_NORMAL, vdd->vdd_type);- }- p += dr_l;- file->cur_content = file->cur_content->next;- } while (file->cur_content != NULL);- }- memset(p, 0, WD_REMAINING);- return (wb_consume(a, LOGICAL_BLOCK_SIZE));-}--static int-write_directory_descriptors(struct archive_write *a, struct vdd *vdd)-{- struct isoent *np;- int depth, r;-- depth = 0;- np = vdd->rootent;- do {- struct extr_rec *extr;-- r = _write_directory_descriptors(a, vdd, np, depth);- if (r < 0)- return (r);- if (vdd->vdd_type != VDD_JOLIET) {- /*- * This extract record is used by SUSP,RRIP.- * Not for joliet.- */- for (extr = np->extr_rec_list.first;- extr != NULL;- extr = extr->next) {- unsigned char *wb;-- wb = wb_buffptr(a);- memcpy(wb, extr->buf, extr->offset);- memset(wb + extr->offset, 0,- LOGICAL_BLOCK_SIZE - extr->offset);- r = wb_consume(a, LOGICAL_BLOCK_SIZE);- if (r < 0)- return (r);- }- }-- if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {- /* Enter to sub directories. */- np = np->subdirs.first;- depth++;- continue;- }- while (np != np->parent) {- if (np->drnext == NULL) {- /* Return to the parent directory. */- np = np->parent;- depth--;- } else {- np = np->drnext;- break;- }- }- } while (np != np->parent);-- return (ARCHIVE_OK);-}--/*- * Read file contents from the temporary file, and write it.- */-static int-write_file_contents(struct archive_write *a, int64_t offset, int64_t size)-{- struct iso9660 *iso9660 = a->format_data;- int r;-- lseek(iso9660->temp_fd, offset, SEEK_SET);-- while (size) {- size_t rsize;- ssize_t rs;- unsigned char *wb;-- wb = wb_buffptr(a);- rsize = wb_remaining(a);- if (rsize > (size_t)size)- rsize = (size_t)size;- rs = read(iso9660->temp_fd, wb, rsize);- if (rs <= 0) {- archive_set_error(&a->archive, errno,- "Can't read temporary file(%jd)", (intmax_t)rs);- return (ARCHIVE_FATAL);- }- size -= rs;- r = wb_consume(a, rs);- if (r < 0)- return (r);- }- return (ARCHIVE_OK);-}--static int-write_file_descriptors(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;- struct isofile *file;- int64_t blocks, offset;- int r;-- blocks = 0;- offset = 0;-- /* Make the boot catalog contents, and write it. */- if (iso9660->el_torito.catalog != NULL) {- r = make_boot_catalog(a);- if (r < 0)- return (r);- }-- /* Write the boot file contents. */- if (iso9660->el_torito.boot != NULL) {- file = iso9660->el_torito.boot->file;- blocks = file->content.blocks;- offset = file->content.offset_of_temp;- if (offset != 0) {- r = write_file_contents(a, offset,- blocks << LOGICAL_BLOCK_BITS);- if (r < 0)- return (r);- blocks = 0;- offset = 0;- }- }-- /* Write out all file contents. */- for (file = iso9660->data_file_list.first;- file != NULL; file = file->datanext) {-- if (!file->write_content)- continue;-- if ((offset + (blocks << LOGICAL_BLOCK_BITS)) <- file->content.offset_of_temp) {- if (blocks > 0) {- r = write_file_contents(a, offset,- blocks << LOGICAL_BLOCK_BITS);- if (r < 0)- return (r);- }- blocks = 0;- offset = file->content.offset_of_temp;- }-- file->cur_content = &(file->content);- do {- blocks += file->cur_content->blocks;- /* Next fragment */- file->cur_content = file->cur_content->next;- } while (file->cur_content != NULL);- }-- /* Flush out remaining blocks. */- if (blocks > 0) {- r = write_file_contents(a, offset,- blocks << LOGICAL_BLOCK_BITS);- if (r < 0)- return (r);- }-- return (ARCHIVE_OK);-}--static void-isofile_init_entry_list(struct iso9660 *iso9660)-{- iso9660->all_file_list.first = NULL;- iso9660->all_file_list.last = &(iso9660->all_file_list.first);-}--static void-isofile_add_entry(struct iso9660 *iso9660, struct isofile *file)-{- file->allnext = NULL;- *iso9660->all_file_list.last = file;- iso9660->all_file_list.last = &(file->allnext);-}--static void-isofile_free_all_entries(struct iso9660 *iso9660)-{- struct isofile *file, *file_next;-- file = iso9660->all_file_list.first;- while (file != NULL) {- file_next = file->allnext;- isofile_free(file);- file = file_next;- }-}--static void-isofile_init_entry_data_file_list(struct iso9660 *iso9660)-{- iso9660->data_file_list.first = NULL;- iso9660->data_file_list.last = &(iso9660->data_file_list.first);-}--static void-isofile_add_data_file(struct iso9660 *iso9660, struct isofile *file)-{- file->datanext = NULL;- *iso9660->data_file_list.last = file;- iso9660->data_file_list.last = &(file->datanext);-}---static struct isofile *-isofile_new(struct archive_write *a, struct archive_entry *entry)-{- struct isofile *file;-- file = calloc(1, sizeof(*file));- if (file == NULL)- return (NULL);-- if (entry != NULL)- file->entry = archive_entry_clone(entry);- else- file->entry = archive_entry_new2(&a->archive);- if (file->entry == NULL) {- free(file);- return (NULL);- }- archive_string_init(&(file->parentdir));- archive_string_init(&(file->basename));- archive_string_init(&(file->basename_utf16));- archive_string_init(&(file->symlink));- file->cur_content = &(file->content);-- return (file);-}--static void-isofile_free(struct isofile *file)-{- struct content *con, *tmp;-- con = file->content.next;- while (con != NULL) {- tmp = con;- con = con->next;- free(tmp);- }- archive_entry_free(file->entry);- archive_string_free(&(file->parentdir));- archive_string_free(&(file->basename));- archive_string_free(&(file->basename_utf16));- archive_string_free(&(file->symlink));- free(file);-}--#if defined(_WIN32) || defined(__CYGWIN__)-static int-cleanup_backslash_1(char *p)-{- int mb, dos;-- mb = dos = 0;- while (*p) {- if (*(unsigned char *)p > 127)- mb = 1;- if (*p == '\\') {- /* If we have not met any multi-byte characters,- * we can replace '\' with '/'. */- if (!mb)- *p = '/';- dos = 1;- }- p++;- }- if (!mb || !dos)- return (0);- return (-1);-}--static void-cleanup_backslash_2(wchar_t *p)-{-- /* Convert a path-separator from '\' to '/' */- while (*p != L'\0') {- if (*p == L'\\')- *p = L'/';- p++;- }-}-#endif--/*- * Generate a parent directory name and a base name from a pathname.- */-static int-isofile_gen_utility_names(struct archive_write *a, struct isofile *file)-{- struct iso9660 *iso9660;- const char *pathname;- char *p, *dirname, *slash;- size_t len;- int ret = ARCHIVE_OK;-- iso9660 = a->format_data;-- archive_string_empty(&(file->parentdir));- archive_string_empty(&(file->basename));- archive_string_empty(&(file->basename_utf16));- archive_string_empty(&(file->symlink));-- pathname = archive_entry_pathname(file->entry);- if (pathname == NULL || pathname[0] == '\0') {/* virtual root */- file->dircnt = 0;- return (ret);- }-- /*- * Make a UTF-16BE basename if Joliet extension enabled.- */- if (iso9660->opt.joliet) {- const char *u16, *ulast;- size_t u16len, ulen_last;-- if (iso9660->sconv_to_utf16be == NULL) {- iso9660->sconv_to_utf16be =- archive_string_conversion_to_charset(- &(a->archive), "UTF-16BE", 1);- if (iso9660->sconv_to_utf16be == NULL)- /* Couldn't allocate memory */- return (ARCHIVE_FATAL);- iso9660->sconv_from_utf16be =- archive_string_conversion_from_charset(- &(a->archive), "UTF-16BE", 1);- if (iso9660->sconv_from_utf16be == NULL)- /* Couldn't allocate memory */- return (ARCHIVE_FATAL);- }-- /*- * Convert a filename to UTF-16BE.- */- if (0 > archive_entry_pathname_l(file->entry, &u16, &u16len,- iso9660->sconv_to_utf16be)) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for UTF-16BE");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "A filename cannot be converted to UTF-16BE;"- "You should disable making Joliet extension");- ret = ARCHIVE_WARN;- }-- /*- * Make sure a path separator is not in the last;- * Remove trailing '/'.- */- while (u16len >= 2) {-#if defined(_WIN32) || defined(__CYGWIN__)- if (u16[u16len-2] == 0 &&- (u16[u16len-1] == '/' || u16[u16len-1] == '\\'))-#else- if (u16[u16len-2] == 0 && u16[u16len-1] == '/')-#endif- {- u16len -= 2;- } else- break;- }-- /*- * Find a basename in UTF-16BE.- */- ulast = u16;- u16len >>= 1;- ulen_last = u16len;- while (u16len > 0) {-#if defined(_WIN32) || defined(__CYGWIN__)- if (u16[0] == 0 && (u16[1] == '/' || u16[1] == '\\'))-#else- if (u16[0] == 0 && u16[1] == '/')-#endif- {- ulast = u16 + 2;- ulen_last = u16len -1;- }- u16 += 2;- u16len --;- }- ulen_last <<= 1;- if (archive_string_ensure(&(file->basename_utf16),- ulen_last) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for UTF-16BE");- return (ARCHIVE_FATAL);- }-- /*- * Set UTF-16BE basename.- */- memcpy(file->basename_utf16.s, ulast, ulen_last);- file->basename_utf16.length = ulen_last;- }-- archive_strcpy(&(file->parentdir), pathname);-#if defined(_WIN32) || defined(__CYGWIN__)- /*- * Convert a path-separator from '\' to '/'- */- if (cleanup_backslash_1(file->parentdir.s) != 0) {- const wchar_t *wp = archive_entry_pathname_w(file->entry);- struct archive_wstring ws;-- if (wp != NULL) {- int r;- archive_string_init(&ws);- archive_wstrcpy(&ws, wp);- cleanup_backslash_2(ws.s);- archive_string_empty(&(file->parentdir));- r = archive_string_append_from_wcs(&(file->parentdir),- ws.s, ws.length);- archive_wstring_free(&ws);- if (r < 0 && errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- }- }-#endif-- len = file->parentdir.length;- p = dirname = file->parentdir.s;-- /*- * Remove leading '/', '../' and './' elements- */- while (*p) {- if (p[0] == '/') {- p++;- len--;- } else if (p[0] != '.')- break;- else if (p[1] == '.' && p[2] == '/') {- p += 3;- len -= 3;- } else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {- p += 2;- len -= 2;- } else if (p[1] == '\0') {- p++;- len--;- } else- break;- }- if (p != dirname) {- memmove(dirname, p, len+1);- p = dirname;- }- /*- * Remove "/","/." and "/.." elements from tail.- */- while (len > 0) {- size_t ll = len;-- if (len > 0 && p[len-1] == '/') {- p[len-1] = '\0';- len--;- }- if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {- p[len-2] = '\0';- len -= 2;- }- if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&- p[len-1] == '.') {- p[len-3] = '\0';- len -= 3;- }- if (ll == len)- break;- }- while (*p) {- if (p[0] == '/') {- if (p[1] == '/')- /* Convert '//' --> '/' */- memmove(p, p+1, strlen(p+1) + 1);- else if (p[1] == '.' && p[2] == '/')- /* Convert '/./' --> '/' */- memmove(p, p+2, strlen(p+2) + 1);- else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {- /* Convert 'dir/dir1/../dir2/'- * --> 'dir/dir2/'- */- char *rp = p -1;- while (rp >= dirname) {- if (*rp == '/')- break;- --rp;- }- if (rp > dirname) {- strcpy(rp, p+3);- p = rp;- } else {- strcpy(dirname, p+4);- p = dirname;- }- } else- p++;- } else- p++;- }- p = dirname;- len = strlen(p);-- if (archive_entry_filetype(file->entry) == AE_IFLNK) {- /* Convert symlink name too. */- pathname = archive_entry_symlink(file->entry);- archive_strcpy(&(file->symlink), pathname);-#if defined(_WIN32) || defined(__CYGWIN__)- /*- * Convert a path-separator from '\' to '/'- */- if (archive_strlen(&(file->symlink)) > 0 &&- cleanup_backslash_1(file->symlink.s) != 0) {- const wchar_t *wp =- archive_entry_symlink_w(file->entry);- struct archive_wstring ws;-- if (wp != NULL) {- int r;- archive_string_init(&ws);- archive_wstrcpy(&ws, wp);- cleanup_backslash_2(ws.s);- archive_string_empty(&(file->symlink));- r = archive_string_append_from_wcs(- &(file->symlink),- ws.s, ws.length);- archive_wstring_free(&ws);- if (r < 0 && errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- }- }-#endif- }- /*- * - Count up directory elements.- * - Find out the position which points the last position of- * path separator('/').- */- slash = NULL;- file->dircnt = 0;- for (; *p != '\0'; p++)- if (*p == '/') {- slash = p;- file->dircnt++;- }- if (slash == NULL) {- /* The pathname doesn't have a parent directory. */- file->parentdir.length = len;- archive_string_copy(&(file->basename), &(file->parentdir));- archive_string_empty(&(file->parentdir));- *file->parentdir.s = '\0';- return (ret);- }-- /* Make a basename from dirname and slash */- *slash = '\0';- file->parentdir.length = slash - dirname;- archive_strcpy(&(file->basename), slash + 1);- if (archive_entry_filetype(file->entry) == AE_IFDIR)- file->dircnt ++;- return (ret);-}--/*- * Register a entry to get a hardlink target.- */-static int-isofile_register_hardlink(struct archive_write *a, struct isofile *file)-{- struct iso9660 *iso9660 = a->format_data;- struct hardlink *hl;- const char *pathname;-- archive_entry_set_nlink(file->entry, 1);- pathname = archive_entry_hardlink(file->entry);- if (pathname == NULL) {- /* This `file` is a hardlink target. */- hl = malloc(sizeof(*hl));- if (hl == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- hl->nlink = 1;- /* A hardlink target must be the first position. */- file->hlnext = NULL;- hl->file_list.first = file;- hl->file_list.last = &(file->hlnext);- __archive_rb_tree_insert_node(&(iso9660->hardlink_rbtree),- (struct archive_rb_node *)hl);- } else {- hl = (struct hardlink *)__archive_rb_tree_find_node(- &(iso9660->hardlink_rbtree), pathname);- if (hl != NULL) {- /* Insert `file` entry into the tail. */- file->hlnext = NULL;- *hl->file_list.last = file;- hl->file_list.last = &(file->hlnext);- hl->nlink++;- }- archive_entry_unset_size(file->entry);- }-- return (ARCHIVE_OK);-}--/*- * Hardlinked files have to have the same location of extent.- * We have to find out hardlink target entries for the entries- * which have a hardlink target name.- */-static void-isofile_connect_hardlink_files(struct iso9660 *iso9660)-{- struct archive_rb_node *n;- struct hardlink *hl;- struct isofile *target, *nf;-- ARCHIVE_RB_TREE_FOREACH(n, &(iso9660->hardlink_rbtree)) {- hl = (struct hardlink *)n;-- /* The first entry must be a hardlink target. */- target = hl->file_list.first;- archive_entry_set_nlink(target->entry, hl->nlink);- /* Set a hardlink target to reference entries. */- for (nf = target->hlnext;- nf != NULL; nf = nf->hlnext) {- nf->hardlink_target = target;- archive_entry_set_nlink(nf->entry, hl->nlink);- }- }-}--static int-isofile_hd_cmp_node(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- const struct hardlink *h1 = (const struct hardlink *)n1;- const struct hardlink *h2 = (const struct hardlink *)n2;-- return (strcmp(archive_entry_pathname(h1->file_list.first->entry),- archive_entry_pathname(h2->file_list.first->entry)));-}--static int-isofile_hd_cmp_key(const struct archive_rb_node *n, const void *key)-{- const struct hardlink *h = (const struct hardlink *)n;-- return (strcmp(archive_entry_pathname(h->file_list.first->entry),- (const char *)key));-}--static void-isofile_init_hardlinks(struct iso9660 *iso9660)-{- static const struct archive_rb_tree_ops rb_ops = {- isofile_hd_cmp_node, isofile_hd_cmp_key,- };-- __archive_rb_tree_init(&(iso9660->hardlink_rbtree), &rb_ops);-}--static void-isofile_free_hardlinks(struct iso9660 *iso9660)-{- struct archive_rb_node *n, *tmp;-- ARCHIVE_RB_TREE_FOREACH_SAFE(n, &(iso9660->hardlink_rbtree), tmp) {- __archive_rb_tree_remove_node(&(iso9660->hardlink_rbtree), n);- free(n);- }-}--static struct isoent *-isoent_new(struct isofile *file)-{- struct isoent *isoent;- static const struct archive_rb_tree_ops rb_ops = {- isoent_cmp_node, isoent_cmp_key,- };-- isoent = calloc(1, sizeof(*isoent));- if (isoent == NULL)- return (NULL);- isoent->file = file;- isoent->children.first = NULL;- isoent->children.last = &(isoent->children.first);- __archive_rb_tree_init(&(isoent->rbtree), &rb_ops);- isoent->subdirs.first = NULL;- isoent->subdirs.last = &(isoent->subdirs.first);- isoent->extr_rec_list.first = NULL;- isoent->extr_rec_list.last = &(isoent->extr_rec_list.first);- isoent->extr_rec_list.current = NULL;- if (archive_entry_filetype(file->entry) == AE_IFDIR)- isoent->dir = 1;-- return (isoent);-}--static inline struct isoent *-isoent_clone(struct isoent *src)-{- return (isoent_new(src->file));-}--static void-_isoent_free(struct isoent *isoent)-{- struct extr_rec *er, *er_next;-- free(isoent->children_sorted);- free(isoent->identifier);- er = isoent->extr_rec_list.first;- while (er != NULL) {- er_next = er->next;- free(er);- er = er_next;- }- free(isoent);-}--static void-isoent_free_all(struct isoent *isoent)-{- struct isoent *np, *np_temp;-- if (isoent == NULL)- return;- np = isoent;- for (;;) {- if (np->dir) {- if (np->children.first != NULL) {- /* Enter to sub directories. */- np = np->children.first;- continue;- }- }- for (;;) {- np_temp = np;- if (np->chnext == NULL) {- /* Return to the parent directory. */- np = np->parent;- _isoent_free(np_temp);- if (np == np_temp)- return;- } else {- np = np->chnext;- _isoent_free(np_temp);- break;- }- }- }-}--static struct isoent *-isoent_create_virtual_dir(struct archive_write *a, struct iso9660 *iso9660, const char *pathname)-{- struct isofile *file;- struct isoent *isoent;-- file = isofile_new(a, NULL);- if (file == NULL)- return (NULL);- archive_entry_set_pathname(file->entry, pathname);- archive_entry_unset_mtime(file->entry);- archive_entry_unset_atime(file->entry);- archive_entry_unset_ctime(file->entry);- archive_entry_set_uid(file->entry, getuid());- archive_entry_set_gid(file->entry, getgid());- archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);- archive_entry_set_nlink(file->entry, 2);- if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {- isofile_free(file);- return (NULL);- }- isofile_add_entry(iso9660, file);-- isoent = isoent_new(file);- if (isoent == NULL)- return (NULL);- isoent->dir = 1;- isoent->virtual = 1;-- return (isoent);-}--static int-isoent_cmp_node(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- const struct isoent *e1 = (const struct isoent *)n1;- const struct isoent *e2 = (const struct isoent *)n2;-- return (strcmp(e1->file->basename.s, e2->file->basename.s));-}--static int-isoent_cmp_key(const struct archive_rb_node *n, const void *key)-{- const struct isoent *e = (const struct isoent *)n;-- return (strcmp(e->file->basename.s, (const char *)key));-}--static int-isoent_add_child_head(struct isoent *parent, struct isoent *child)-{-- if (!__archive_rb_tree_insert_node(- &(parent->rbtree), (struct archive_rb_node *)child))- return (0);- if ((child->chnext = parent->children.first) == NULL)- parent->children.last = &(child->chnext);- parent->children.first = child;- parent->children.cnt++;- child->parent = parent;-- /* Add a child to a sub-directory chain */- if (child->dir) {- if ((child->drnext = parent->subdirs.first) == NULL)- parent->subdirs.last = &(child->drnext);- parent->subdirs.first = child;- parent->subdirs.cnt++;- child->parent = parent;- } else- child->drnext = NULL;- return (1);-}--static int-isoent_add_child_tail(struct isoent *parent, struct isoent *child)-{-- if (!__archive_rb_tree_insert_node(- &(parent->rbtree), (struct archive_rb_node *)child))- return (0);- child->chnext = NULL;- *parent->children.last = child;- parent->children.last = &(child->chnext);- parent->children.cnt++;- child->parent = parent;-- /* Add a child to a sub-directory chain */- child->drnext = NULL;- if (child->dir) {- *parent->subdirs.last = child;- parent->subdirs.last = &(child->drnext);- parent->subdirs.cnt++;- child->parent = parent;- }- return (1);-}--static void-isoent_remove_child(struct isoent *parent, struct isoent *child)-{- struct isoent *ent;-- /* Remove a child entry from children chain. */- ent = parent->children.first;- while (ent->chnext != child)- ent = ent->chnext;- if ((ent->chnext = ent->chnext->chnext) == NULL)- parent->children.last = &(ent->chnext);- parent->children.cnt--;-- if (child->dir) {- /* Remove a child entry from sub-directory chain. */- ent = parent->subdirs.first;- while (ent->drnext != child)- ent = ent->drnext;- if ((ent->drnext = ent->drnext->drnext) == NULL)- parent->subdirs.last = &(ent->drnext);- parent->subdirs.cnt--;- }-- __archive_rb_tree_remove_node(&(parent->rbtree),- (struct archive_rb_node *)child);-}--static int-isoent_clone_tree(struct archive_write *a, struct isoent **nroot,- struct isoent *root)-{- struct isoent *np, *xroot, *newent;-- np = root;- xroot = NULL;- do {- newent = isoent_clone(np);- if (newent == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- if (xroot == NULL) {- *nroot = xroot = newent;- newent->parent = xroot;- } else- isoent_add_child_tail(xroot, newent);- if (np->dir && np->children.first != NULL) {- /* Enter to sub directories. */- np = np->children.first;- xroot = newent;- continue;- }- while (np != np->parent) {- if (np->chnext == NULL) {- /* Return to the parent directory. */- np = np->parent;- xroot = xroot->parent;- } else {- np = np->chnext;- break;- }- }- } while (np != np->parent);-- return (ARCHIVE_OK);-}--/*- * Setup directory locations.- */-static void-isoent_setup_directory_location(struct iso9660 *iso9660, int location,- struct vdd *vdd)-{- struct isoent *np;- int depth;-- vdd->total_dir_block = 0;- depth = 0;- np = vdd->rootent;- do {- int block;-- np->dir_block = calculate_directory_descriptors(- iso9660, vdd, np, depth);- vdd->total_dir_block += np->dir_block;- np->dir_location = location;- location += np->dir_block;- block = extra_setup_location(np, location);- vdd->total_dir_block += block;- location += block;-- if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {- /* Enter to sub directories. */- np = np->subdirs.first;- depth++;- continue;- }- while (np != np->parent) {- if (np->drnext == NULL) {- /* Return to the parent directory. */- np = np->parent;- depth--;- } else {- np = np->drnext;- break;- }- }- } while (np != np->parent);-}--static void-_isoent_file_location(struct iso9660 *iso9660, struct isoent *isoent,- int *symlocation)-{- struct isoent **children;- int n;-- if (isoent->children.cnt == 0)- return;-- children = isoent->children_sorted;- for (n = 0; n < isoent->children.cnt; n++) {- struct isoent *np;- struct isofile *file;-- np = children[n];- if (np->dir)- continue;- if (np == iso9660->el_torito.boot)- continue;- file = np->file;- if (file->boot || file->hardlink_target != NULL)- continue;- if (archive_entry_filetype(file->entry) == AE_IFLNK ||- file->content.size == 0) {- /*- * Do not point a valid location.- * Make sure entry is not hardlink file.- */- file->content.location = (*symlocation)--;- continue;- }-- file->write_content = 1;- }-}--/*- * Setup file locations.- */-static void-isoent_setup_file_location(struct iso9660 *iso9660, int location)-{- struct isoent *isoent;- struct isoent *np;- struct isofile *file;- size_t size;- int block;- int depth;- int joliet;- int symlocation;- int total_block;-- iso9660->total_file_block = 0;- if ((isoent = iso9660->el_torito.catalog) != NULL) {- isoent->file->content.location = location;- block = (int)((archive_entry_size(isoent->file->entry) +- LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);- location += block;- iso9660->total_file_block += block;- }- if ((isoent = iso9660->el_torito.boot) != NULL) {- isoent->file->content.location = location;- size = fd_boot_image_size(iso9660->el_torito.media_type);- if (size == 0)- size = (size_t)archive_entry_size(isoent->file->entry);- block = ((int)size + LOGICAL_BLOCK_SIZE -1)- >> LOGICAL_BLOCK_BITS;- location += block;- iso9660->total_file_block += block;- isoent->file->content.blocks = block;- }-- depth = 0;- symlocation = -16;- if (!iso9660->opt.rr && iso9660->opt.joliet) {- joliet = 1;- np = iso9660->joliet.rootent;- } else {- joliet = 0;- np = iso9660->primary.rootent;- }- do {- _isoent_file_location(iso9660, np, &symlocation);-- if (np->subdirs.first != NULL &&- (joliet ||- ((iso9660->opt.rr == OPT_RR_DISABLED &&- depth + 2 < iso9660->primary.max_depth) ||- (iso9660->opt.rr &&- depth + 1 < iso9660->primary.max_depth)))) {- /* Enter to sub directories. */- np = np->subdirs.first;- depth++;- continue;- }- while (np != np->parent) {- if (np->drnext == NULL) {- /* Return to the parent directory. */- np = np->parent;- depth--;- } else {- np = np->drnext;- break;- }- }- } while (np != np->parent);-- total_block = 0;- for (file = iso9660->data_file_list.first;- file != NULL; file = file->datanext) {-- if (!file->write_content)- continue;-- file->cur_content = &(file->content);- do {- file->cur_content->location = location;- location += file->cur_content->blocks;- total_block += file->cur_content->blocks;- /* Next fragment */- file->cur_content = file->cur_content->next;- } while (file->cur_content != NULL);- }- iso9660->total_file_block += total_block;-}--static int-get_path_component(char *name, size_t n, const char *fn)-{- char *p;- size_t l;-- p = strchr(fn, '/');- if (p == NULL) {- if ((l = strlen(fn)) == 0)- return (0);- } else- l = p - fn;- if (l > n -1)- return (-1);- memcpy(name, fn, l);- name[l] = '\0';-- return ((int)l);-}--/*- * Add a new entry into the tree.- */-static int-isoent_tree(struct archive_write *a, struct isoent **isoentpp)-{-#if defined(_WIN32) && !defined(__CYGWIN__)- char name[_MAX_FNAME];/* Included null terminator size. */-#elif defined(NAME_MAX) && NAME_MAX >= 255- char name[NAME_MAX+1];-#else- char name[256];-#endif- struct iso9660 *iso9660 = a->format_data;- struct isoent *dent, *isoent, *np;- struct isofile *f1, *f2;- const char *fn, *p;- int l;-- isoent = *isoentpp;- dent = iso9660->primary.rootent;- if (isoent->file->parentdir.length > 0)- fn = p = isoent->file->parentdir.s;- else- fn = p = "";-- /*- * If the path of the parent directory of `isoent' entry is- * the same as the path of `cur_dirent', add isoent to- * `cur_dirent'.- */- if (archive_strlen(&(iso9660->cur_dirstr))- == archive_strlen(&(isoent->file->parentdir)) &&- strcmp(iso9660->cur_dirstr.s, fn) == 0) {- if (!isoent_add_child_tail(iso9660->cur_dirent, isoent)) {- np = (struct isoent *)__archive_rb_tree_find_node(- &(iso9660->cur_dirent->rbtree),- isoent->file->basename.s);- goto same_entry;- }- return (ARCHIVE_OK);- }-- for (;;) {- l = get_path_component(name, sizeof(name), fn);- if (l == 0) {- np = NULL;- break;- }- if (l < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "A name buffer is too small");- _isoent_free(isoent);- return (ARCHIVE_FATAL);- }-- np = isoent_find_child(dent, name);- if (np == NULL || fn[0] == '\0')- break;-- /* Find next subdirectory. */- if (!np->dir) {- /* NOT Directory! */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "`%s' is not directory, we cannot insert `%s' ",- archive_entry_pathname(np->file->entry),- archive_entry_pathname(isoent->file->entry));- _isoent_free(isoent);- *isoentpp = NULL;- return (ARCHIVE_FAILED);- }- fn += l;- if (fn[0] == '/')- fn++;- dent = np;- }- if (np == NULL) {- /*- * Create virtual parent directories.- */- while (fn[0] != '\0') {- struct isoent *vp;- struct archive_string as;-- archive_string_init(&as);- archive_strncat(&as, p, fn - p + l);- if (as.s[as.length-1] == '/') {- as.s[as.length-1] = '\0';- as.length--;- }- vp = isoent_create_virtual_dir(a, iso9660, as.s);- if (vp == NULL) {- archive_string_free(&as);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- _isoent_free(isoent);- *isoentpp = NULL;- return (ARCHIVE_FATAL);- }- archive_string_free(&as);-- if (vp->file->dircnt > iso9660->dircnt_max)- iso9660->dircnt_max = vp->file->dircnt;- isoent_add_child_tail(dent, vp);- np = vp;-- fn += l;- if (fn[0] == '/')- fn++;- l = get_path_component(name, sizeof(name), fn);- if (l < 0) {- archive_string_free(&as);- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "A name buffer is too small");- _isoent_free(isoent);- *isoentpp = NULL;- return (ARCHIVE_FATAL);- }- dent = np;- }-- /* Found out the parent directory where isoent can be- * inserted. */- iso9660->cur_dirent = dent;- archive_string_empty(&(iso9660->cur_dirstr));- archive_string_ensure(&(iso9660->cur_dirstr),- archive_strlen(&(dent->file->parentdir)) +- archive_strlen(&(dent->file->basename)) + 2);- if (archive_strlen(&(dent->file->parentdir)) +- archive_strlen(&(dent->file->basename)) == 0)- iso9660->cur_dirstr.s[0] = 0;- else {- if (archive_strlen(&(dent->file->parentdir)) > 0) {- archive_string_copy(&(iso9660->cur_dirstr),- &(dent->file->parentdir));- archive_strappend_char(&(iso9660->cur_dirstr), '/');- }- archive_string_concat(&(iso9660->cur_dirstr),- &(dent->file->basename));- }-- if (!isoent_add_child_tail(dent, isoent)) {- np = (struct isoent *)__archive_rb_tree_find_node(- &(dent->rbtree), isoent->file->basename.s);- goto same_entry;- }- return (ARCHIVE_OK);- }--same_entry:- /*- * We have already has the entry the filename of which is- * the same.- */- f1 = np->file;- f2 = isoent->file;-- /* If the file type of entries is different,- * we cannot handle it. */- if (archive_entry_filetype(f1->entry) !=- archive_entry_filetype(f2->entry)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Found duplicate entries `%s' and its file type is "- "different",- archive_entry_pathname(f1->entry));- _isoent_free(isoent);- *isoentpp = NULL;- return (ARCHIVE_FAILED);- }-- /* Swap file entries. */- np->file = f2;- isoent->file = f1;- np->virtual = 0;-- _isoent_free(isoent);- *isoentpp = np;- return (ARCHIVE_OK);-}--/*- * Find a entry from `isoent'- */-static struct isoent *-isoent_find_child(struct isoent *isoent, const char *child_name)-{- struct isoent *np;-- np = (struct isoent *)__archive_rb_tree_find_node(- &(isoent->rbtree), child_name);- return (np);-}--/*- * Find a entry full-path of which is specified by `fn' parameter,- * in the tree.- */-static struct isoent *-isoent_find_entry(struct isoent *rootent, const char *fn)-{-#if defined(_WIN32) && !defined(__CYGWIN__)- char name[_MAX_FNAME];/* Included null terminator size. */-#elif defined(NAME_MAX) && NAME_MAX >= 255- char name[NAME_MAX+1];-#else- char name[256];-#endif- struct isoent *isoent, *np;- int l;-- isoent = rootent;- np = NULL;- for (;;) {- l = get_path_component(name, sizeof(name), fn);- if (l == 0)- break;- fn += l;- if (fn[0] == '/')- fn++;-- np = isoent_find_child(isoent, name);- if (np == NULL)- break;- if (fn[0] == '\0')- break;/* We found out the entry */-- /* Try sub directory. */- isoent = np;- np = NULL;- if (!isoent->dir)- break;/* Not directory */- }-- return (np);-}--/*- * Following idr_* functions are used for resolving duplicated filenames- * and unreceivable filenames to generate ISO9660/Joliet Identifiers.- */--static void-idr_relaxed_filenames(char *map)-{- int i;-- for (i = 0x21; i <= 0x2F; i++)- map[i] = 1;- for (i = 0x3A; i <= 0x41; i++)- map[i] = 1;- for (i = 0x5B; i <= 0x5E; i++)- map[i] = 1;- map[0x60] = 1;- for (i = 0x7B; i <= 0x7E; i++)- map[i] = 1;-}--static void-idr_init(struct iso9660 *iso9660, struct vdd *vdd, struct idr *idr)-{-- idr->idrent_pool = NULL;- idr->pool_size = 0;- if (vdd->vdd_type != VDD_JOLIET) {- if (iso9660->opt.iso_level <= 3) {- memcpy(idr->char_map, d_characters_map,- sizeof(idr->char_map));- } else {- memcpy(idr->char_map, d1_characters_map,- sizeof(idr->char_map));- idr_relaxed_filenames(idr->char_map);- }- }-}--static void-idr_cleanup(struct idr *idr)-{- free(idr->idrent_pool);-}--static int-idr_ensure_poolsize(struct archive_write *a, struct idr *idr,- int cnt)-{-- if (idr->pool_size < cnt) {- void *p;- const int bk = (1 << 7) - 1;- int psize;-- psize = (cnt + bk) & ~bk;- p = realloc(idr->idrent_pool, sizeof(struct idrent) * psize);- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- idr->idrent_pool = (struct idrent *)p;- idr->pool_size = psize;- }- return (ARCHIVE_OK);-}--static int-idr_start(struct archive_write *a, struct idr *idr, int cnt, int ffmax,- int num_size, int null_size, const struct archive_rb_tree_ops *rbt_ops)-{- int r;-- (void)ffmax; /* UNUSED */-- r = idr_ensure_poolsize(a, idr, cnt);- if (r != ARCHIVE_OK)- return (r);- __archive_rb_tree_init(&(idr->rbtree), rbt_ops);- idr->wait_list.first = NULL;- idr->wait_list.last = &(idr->wait_list.first);- idr->pool_idx = 0;- idr->num_size = num_size;- idr->null_size = null_size;- return (ARCHIVE_OK);-}--static void-idr_register(struct idr *idr, struct isoent *isoent, int weight, int noff)-{- struct idrent *idrent, *n;-- idrent = &(idr->idrent_pool[idr->pool_idx++]);- idrent->wnext = idrent->avail = NULL;- idrent->isoent = isoent;- idrent->weight = weight;- idrent->noff = noff;- idrent->rename_num = 0;-- if (!__archive_rb_tree_insert_node(&(idr->rbtree), &(idrent->rbnode))) {- n = (struct idrent *)__archive_rb_tree_find_node(- &(idr->rbtree), idrent->isoent);- if (n != NULL) {- /* this `idrent' needs to rename. */- idrent->avail = n;- *idr->wait_list.last = idrent;- idr->wait_list.last = &(idrent->wnext);- }- }-}--static void-idr_extend_identifier(struct idrent *wnp, int numsize, int nullsize)-{- unsigned char *p;- int wnp_ext_off;-- wnp_ext_off = wnp->isoent->ext_off;- if (wnp->noff + numsize != wnp_ext_off) {- p = (unsigned char *)wnp->isoent->identifier;- /* Extend the filename; foo.c --> foo___.c */- memmove(p + wnp->noff + numsize, p + wnp_ext_off,- wnp->isoent->ext_len + nullsize);- wnp->isoent->ext_off = wnp_ext_off = wnp->noff + numsize;- wnp->isoent->id_len = wnp_ext_off + wnp->isoent->ext_len;- }-}--static void-idr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))-{- struct idrent *n;- unsigned char *p;-- for (n = idr->wait_list.first; n != NULL; n = n->wnext) {- idr_extend_identifier(n, idr->num_size, idr->null_size);- p = (unsigned char *)n->isoent->identifier + n->noff;- do {- fsetnum(p, n->avail->rename_num++);- } while (!__archive_rb_tree_insert_node(- &(idr->rbtree), &(n->rbnode)));- }-}--static void-idr_set_num(unsigned char *p, int num)-{- static const char xdig[] = {- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',- 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',- 'U', 'V', 'W', 'X', 'Y', 'Z'- };-- num %= sizeof(xdig) * sizeof(xdig) * sizeof(xdig);- p[0] = xdig[(num / (sizeof(xdig) * sizeof(xdig)))];- num %= sizeof(xdig) * sizeof(xdig);- p[1] = xdig[ (num / sizeof(xdig))];- num %= sizeof(xdig);- p[2] = xdig[num];-}--static void-idr_set_num_beutf16(unsigned char *p, int num)-{- static const uint16_t xdig[] = {- 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,- 0x0036, 0x0037, 0x0038, 0x0039,- 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046,- 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C,- 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052,- 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,- 0x0059, 0x005A- };-#define XDIG_CNT (sizeof(xdig)/sizeof(xdig[0]))-- num %= XDIG_CNT * XDIG_CNT * XDIG_CNT;- archive_be16enc(p, xdig[(num / (XDIG_CNT * XDIG_CNT))]);- num %= XDIG_CNT * XDIG_CNT;- archive_be16enc(p+2, xdig[ (num / XDIG_CNT)]);- num %= XDIG_CNT;- archive_be16enc(p+4, xdig[num]);-}--/*- * Generate ISO9660 Identifier.- */-static int-isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,- struct idr *idr)-{- struct iso9660 *iso9660;- struct isoent *np;- char *p;- int l, r;- const char *char_map;- char allow_ldots, allow_multidot, allow_period, allow_vernum;- int fnmax, ffmax, dnmax;- static const struct archive_rb_tree_ops rb_ops = {- isoent_cmp_node_iso9660, isoent_cmp_key_iso9660- };-- if (isoent->children.cnt == 0)- return (0);-- iso9660 = a->format_data;- char_map = idr->char_map;- if (iso9660->opt.iso_level <= 3) {- allow_ldots = 0;- allow_multidot = 0;- allow_period = 1;- allow_vernum = iso9660->opt.allow_vernum;- if (iso9660->opt.iso_level == 1) {- fnmax = 8;- ffmax = 12;/* fnmax + '.' + 3 */- dnmax = 8;- } else {- fnmax = 30;- ffmax = 31;- dnmax = 31;- }- } else {- allow_ldots = allow_multidot = 1;- allow_period = allow_vernum = 0;- if (iso9660->opt.rr)- /*- * MDR : The maximum size of Directory Record(254).- * DRL : A Directory Record Length(33).- * CE : A size of SUSP CE System Use Entry(28).- * MDR - DRL - CE = 254 - 33 - 28 = 193.- */- fnmax = ffmax = dnmax = 193;- else- /*- * XA : CD-ROM XA System Use Extension- * Information(14).- * MDR - DRL - XA = 254 - 33 -14 = 207.- */- fnmax = ffmax = dnmax = 207;- }-- r = idr_start(a, idr, isoent->children.cnt, ffmax, 3, 1, &rb_ops);- if (r < 0)- return (r);-- for (np = isoent->children.first; np != NULL; np = np->chnext) {- char *dot, *xdot;- int ext_off, noff, weight;-- l = (int)np->file->basename.length;- p = malloc(l+31+2+1);- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- memcpy(p, np->file->basename.s, l);- p[l] = '\0';- np->identifier = p;-- dot = xdot = NULL;- if (!allow_ldots) {- /*- * If there is a '.' character at the first byte,- * it has to be replaced by '_' character.- */- if (*p == '.')- *p++ = '_';- }- for (;*p; p++) {- if (*p & 0x80) {- *p = '_';- continue;- }- if (char_map[(unsigned char)*p]) {- /* if iso-level is '4', a character '.' is- * allowed by char_map. */- if (*p == '.') {- xdot = dot;- dot = p;- }- continue;- }- if (*p >= 'a' && *p <= 'z') {- *p -= 'a' - 'A';- continue;- }- if (*p == '.') {- xdot = dot;- dot = p;- if (allow_multidot)- continue;- }- *p = '_';- }- p = np->identifier;- weight = -1;- if (dot == NULL) {- int nammax;-- if (np->dir)- nammax = dnmax;- else- nammax = fnmax;-- if (l > nammax) {- p[nammax] = '\0';- weight = nammax;- ext_off = nammax;- } else- ext_off = l;- } else {- *dot = '.';- ext_off = (int)(dot - p);-- if (iso9660->opt.iso_level == 1) {- if (dot - p <= 8) {- if (strlen(dot) > 4) {- /* A length of a file extension- * must be less than 4 */- dot[4] = '\0';- weight = 0;- }- } else {- p[8] = dot[0];- p[9] = dot[1];- p[10] = dot[2];- p[11] = dot[3];- p[12] = '\0';- weight = 8;- ext_off = 8;- }- } else if (np->dir) {- if (l > dnmax) {- p[dnmax] = '\0';- weight = dnmax;- if (ext_off > dnmax)- ext_off = dnmax;- }- } else if (l > ffmax) {- int extlen = (int)strlen(dot);- int xdoff;-- if (xdot != NULL)- xdoff = (int)(xdot - p);- else- xdoff = 0;-- if (extlen > 1 && xdoff < fnmax-1) {- int off;-- if (extlen > ffmax)- extlen = ffmax;- off = ffmax - extlen;- if (off == 0) {- /* A dot('.') character- * doesn't place to the first- * byte of identifier. */- off ++;- extlen --;- }- memmove(p+off, dot, extlen);- p[ffmax] = '\0';- ext_off = off;- weight = off;-#ifdef COMPAT_MKISOFS- } else if (xdoff >= fnmax-1) {- /* Simulate a bug(?) of mkisofs. */- p[fnmax-1] = '\0';- ext_off = fnmax-1;- weight = fnmax-1;-#endif- } else {- p[fnmax] = '\0';- ext_off = fnmax;- weight = fnmax;- }- }- }- /* Save an offset of a file name extension to sort files. */- np->ext_off = ext_off;- np->ext_len = (int)strlen(&p[ext_off]);- np->id_len = l = ext_off + np->ext_len;-- /* Make an offset of the number which is used to be set- * hexadecimal number to avoid duplicate identifier. */- if (iso9660->opt.iso_level == 1) {- if (ext_off >= 5)- noff = 5;- else- noff = ext_off;- } else {- if (l == ffmax)- noff = ext_off - 3;- else if (l == ffmax-1)- noff = ext_off - 2;- else if (l == ffmax-2)- noff = ext_off - 1;- else- noff = ext_off;- }- /* Register entry to the identifier resolver. */- idr_register(idr, np, weight, noff);- }-- /* Resolve duplicate identifier. */- idr_resolve(idr, idr_set_num);-- /* Add a period and a version number to identifiers. */- for (np = isoent->children.first; np != NULL; np = np->chnext) {- if (!np->dir && np->rr_child == NULL) {- p = np->identifier + np->ext_off + np->ext_len;- if (np->ext_len == 0 && allow_period) {- *p++ = '.';- np->ext_len = 1;- }- if (np->ext_len == 1 && !allow_period) {- *--p = '\0';- np->ext_len = 0;- }- np->id_len = np->ext_off + np->ext_len;- if (allow_vernum) {- *p++ = ';';- *p++ = '1';- np->id_len += 2;- }- *p = '\0';- } else- np->id_len = np->ext_off + np->ext_len;- np->mb_len = np->id_len;- }- return (ARCHIVE_OK);-}--/*- * Generate Joliet Identifier.- */-static int-isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,- struct idr *idr)-{- struct iso9660 *iso9660;- struct isoent *np;- unsigned char *p;- size_t l;- int r;- size_t ffmax, parent_len;- static const struct archive_rb_tree_ops rb_ops = {- isoent_cmp_node_joliet, isoent_cmp_key_joliet- };-- if (isoent->children.cnt == 0)- return (0);-- iso9660 = a->format_data;- if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)- ffmax = 206;- else- ffmax = 128;-- r = idr_start(a, idr, isoent->children.cnt, (int)ffmax, 6, 2, &rb_ops);- if (r < 0)- return (r);-- parent_len = 1;- for (np = isoent; np->parent != np; np = np->parent)- parent_len += np->mb_len + 1;-- for (np = isoent->children.first; np != NULL; np = np->chnext) {- unsigned char *dot;- int ext_off, noff, weight;- size_t lt;-- if ((l = np->file->basename_utf16.length) > ffmax)- l = ffmax;-- p = malloc((l+1)*2);- if (p == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- memcpy(p, np->file->basename_utf16.s, l);- p[l] = 0;- p[l+1] = 0;-- np->identifier = (char *)p;- lt = l;- dot = p + l;- weight = 0;- while (lt > 0) {- if (!joliet_allowed_char(p[0], p[1]))- archive_be16enc(p, 0x005F); /* '_' */- else if (p[0] == 0 && p[1] == 0x2E) /* '.' */- dot = p;- p += 2;- lt -= 2;- }- ext_off = (int)(dot - (unsigned char *)np->identifier);- np->ext_off = ext_off;- np->ext_len = (int)l - ext_off;- np->id_len = (int)l;-- /*- * Get a length of MBS of a full-pathname.- */- if (np->file->basename_utf16.length > ffmax) {- if (archive_strncpy_l(&iso9660->mbs,- (const char *)np->identifier, l,- iso9660->sconv_from_utf16be) != 0 &&- errno == ENOMEM) {- archive_set_error(&a->archive, errno,- "No memory");- return (ARCHIVE_FATAL);- }- np->mb_len = (int)iso9660->mbs.length;- if (np->mb_len != (int)np->file->basename.length)- weight = np->mb_len;- } else- np->mb_len = (int)np->file->basename.length;-- /* If a length of full-pathname is longer than 240 bytes,- * it violates Joliet extensions regulation. */- if (parent_len > 240- || np->mb_len > 240- || parent_len + np->mb_len > 240) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "The regulation of Joliet extensions;"- " A length of a full-pathname of `%s' is "- "longer than 240 bytes, (p=%d, b=%d)",- archive_entry_pathname(np->file->entry),- (int)parent_len, (int)np->mb_len);- return (ARCHIVE_FATAL);- }-- /* Make an offset of the number which is used to be set- * hexadecimal number to avoid duplicate identifier. */- if (l == ffmax)- noff = ext_off - 6;- else if (l == ffmax-2)- noff = ext_off - 4;- else if (l == ffmax-4)- noff = ext_off - 2;- else- noff = ext_off;- /* Register entry to the identifier resolver. */- idr_register(idr, np, weight, noff);- }-- /* Resolve duplicate identifier with Joliet Volume. */- idr_resolve(idr, idr_set_num_beutf16);-- return (ARCHIVE_OK);-}--/*- * This comparing rule is according to ISO9660 Standard 9.3- */-static int-isoent_cmp_iso9660_identifier(const struct isoent *p1, const struct isoent *p2)-{- const char *s1, *s2;- int cmp;- int l;-- s1 = p1->identifier;- s2 = p2->identifier;-- /* Compare File Name */- l = p1->ext_off;- if (l > p2->ext_off)- l = p2->ext_off;- cmp = memcmp(s1, s2, l);- if (cmp != 0)- return (cmp);- if (p1->ext_off < p2->ext_off) {- s2 += l;- l = p2->ext_off - p1->ext_off;- while (l--)- if (0x20 != *s2++)- return (0x20- - *(const unsigned char *)(s2 - 1));- } else if (p1->ext_off > p2->ext_off) {- s1 += l;- l = p1->ext_off - p2->ext_off;- while (l--)- if (0x20 != *s1++)- return (*(const unsigned char *)(s1 - 1)- - 0x20);- }- /* Compare File Name Extension */- if (p1->ext_len == 0 && p2->ext_len == 0)- return (0);- if (p1->ext_len == 1 && p2->ext_len == 1)- return (0);- if (p1->ext_len <= 1)- return (-1);- if (p2->ext_len <= 1)- return (1);- l = p1->ext_len;- if (l > p2->ext_len)- l = p2->ext_len;- s1 = p1->identifier + p1->ext_off;- s2 = p2->identifier + p2->ext_off;- if (l > 1) {- cmp = memcmp(s1, s2, l);- if (cmp != 0)- return (cmp);- }- if (p1->ext_len < p2->ext_len) {- s2 += l;- l = p2->ext_len - p1->ext_len;- while (l--)- if (0x20 != *s2++)- return (0x20- - *(const unsigned char *)(s2 - 1));- } else if (p1->ext_len > p2->ext_len) {- s1 += l;- l = p1->ext_len - p2->ext_len;- while (l--)- if (0x20 != *s1++)- return (*(const unsigned char *)(s1 - 1)- - 0x20);- }- /* Compare File Version Number */- /* No operation. The File Version Number is always one. */-- return (cmp);-}--static int-isoent_cmp_node_iso9660(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- const struct idrent *e1 = (const struct idrent *)n1;- const struct idrent *e2 = (const struct idrent *)n2;-- return (isoent_cmp_iso9660_identifier(e2->isoent, e1->isoent));-}--static int-isoent_cmp_key_iso9660(const struct archive_rb_node *node, const void *key)-{- const struct isoent *isoent = (const struct isoent *)key;- const struct idrent *idrent = (const struct idrent *)node;-- return (isoent_cmp_iso9660_identifier(isoent, idrent->isoent));-}--static int-isoent_cmp_joliet_identifier(const struct isoent *p1, const struct isoent *p2)-{- const unsigned char *s1, *s2;- int cmp;- int l;-- s1 = (const unsigned char *)p1->identifier;- s2 = (const unsigned char *)p2->identifier;-- /* Compare File Name */- l = p1->ext_off;- if (l > p2->ext_off)- l = p2->ext_off;- cmp = memcmp(s1, s2, l);- if (cmp != 0)- return (cmp);- if (p1->ext_off < p2->ext_off) {- s2 += l;- l = p2->ext_off - p1->ext_off;- while (l--)- if (0 != *s2++)- return (- *(const unsigned char *)(s2 - 1));- } else if (p1->ext_off > p2->ext_off) {- s1 += l;- l = p1->ext_off - p2->ext_off;- while (l--)- if (0 != *s1++)- return (*(const unsigned char *)(s1 - 1));- }- /* Compare File Name Extension */- if (p1->ext_len == 0 && p2->ext_len == 0)- return (0);- if (p1->ext_len == 2 && p2->ext_len == 2)- return (0);- if (p1->ext_len <= 2)- return (-1);- if (p2->ext_len <= 2)- return (1);- l = p1->ext_len;- if (l > p2->ext_len)- l = p2->ext_len;- s1 = (unsigned char *)(p1->identifier + p1->ext_off);- s2 = (unsigned char *)(p2->identifier + p2->ext_off);- if (l > 1) {- cmp = memcmp(s1, s2, l);- if (cmp != 0)- return (cmp);- }- if (p1->ext_len < p2->ext_len) {- s2 += l;- l = p2->ext_len - p1->ext_len;- while (l--)- if (0 != *s2++)- return (- *(const unsigned char *)(s2 - 1));- } else if (p1->ext_len > p2->ext_len) {- s1 += l;- l = p1->ext_len - p2->ext_len;- while (l--)- if (0 != *s1++)- return (*(const unsigned char *)(s1 - 1));- }- /* Compare File Version Number */- /* No operation. The File Version Number is always one. */-- return (cmp);-}--static int-isoent_cmp_node_joliet(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- const struct idrent *e1 = (const struct idrent *)n1;- const struct idrent *e2 = (const struct idrent *)n2;-- return (isoent_cmp_joliet_identifier(e2->isoent, e1->isoent));-}--static int-isoent_cmp_key_joliet(const struct archive_rb_node *node, const void *key)-{- const struct isoent *isoent = (const struct isoent *)key;- const struct idrent *idrent = (const struct idrent *)node;-- return (isoent_cmp_joliet_identifier(isoent, idrent->isoent));-}--static int-isoent_make_sorted_files(struct archive_write *a, struct isoent *isoent,- struct idr *idr)-{- struct archive_rb_node *rn;- struct isoent **children;-- children = malloc(isoent->children.cnt * sizeof(struct isoent *));- if (children == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- isoent->children_sorted = children;-- ARCHIVE_RB_TREE_FOREACH(rn, &(idr->rbtree)) {- struct idrent *idrent = (struct idrent *)rn;- *children ++ = idrent->isoent;- }- return (ARCHIVE_OK);-}--/*- * - Generate ISO9660 and Joliet identifiers from basenames.- * - Sort files by each directory.- */-static int-isoent_traverse_tree(struct archive_write *a, struct vdd* vdd)-{- struct iso9660 *iso9660 = a->format_data;- struct isoent *np;- struct idr idr;- int depth;- int r;- int (*genid)(struct archive_write *, struct isoent *, struct idr *);-- idr_init(iso9660, vdd, &idr);- np = vdd->rootent;- depth = 0;- if (vdd->vdd_type == VDD_JOLIET)- genid = isoent_gen_joliet_identifier;- else- genid = isoent_gen_iso9660_identifier;- do {- if (np->virtual &&- !archive_entry_mtime_is_set(np->file->entry)) {- /* Set properly times to virtual directory */- archive_entry_set_mtime(np->file->entry,- iso9660->birth_time, 0);- archive_entry_set_atime(np->file->entry,- iso9660->birth_time, 0);- archive_entry_set_ctime(np->file->entry,- iso9660->birth_time, 0);- }- if (np->children.first != NULL) {- if (vdd->vdd_type != VDD_JOLIET &&- !iso9660->opt.rr && depth + 1 >= vdd->max_depth) {- if (np->children.cnt > 0)- iso9660->directories_too_deep = np;- } else {- /* Generate Identifier */- r = genid(a, np, &idr);- if (r < 0)- goto exit_traverse_tree;- r = isoent_make_sorted_files(a, np, &idr);- if (r < 0)- goto exit_traverse_tree;-- if (np->subdirs.first != NULL &&- depth + 1 < vdd->max_depth) {- /* Enter to sub directories. */- np = np->subdirs.first;- depth++;- continue;- }- }- }- while (np != np->parent) {- if (np->drnext == NULL) {- /* Return to the parent directory. */- np = np->parent;- depth--;- } else {- np = np->drnext;- break;- }- }- } while (np != np->parent);-- r = ARCHIVE_OK;-exit_traverse_tree:- idr_cleanup(&idr);-- return (r);-}--/*- * Collect directory entries into path_table by a directory depth.- */-static int-isoent_collect_dirs(struct vdd *vdd, struct isoent *rootent, int depth)-{- struct isoent *np;-- if (rootent == NULL)- rootent = vdd->rootent;- np = rootent;- do {- /* Register current directory to pathtable. */- path_table_add_entry(&(vdd->pathtbl[depth]), np);-- if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {- /* Enter to sub directories. */- np = np->subdirs.first;- depth++;- continue;- }- while (np != rootent) {- if (np->drnext == NULL) {- /* Return to the parent directory. */- np = np->parent;- depth--;- } else {- np = np->drnext;- break;- }- }- } while (np != rootent);-- return (ARCHIVE_OK);-}--/*- * The entry whose number of levels in a directory hierarchy is- * large than eight relocate to rr_move directory.- */-static int-isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,- struct isoent *curent, struct isoent **newent)-{- struct iso9660 *iso9660 = a->format_data;- struct isoent *rrmoved, *mvent, *np;-- if ((rrmoved = *rr_moved) == NULL) {- struct isoent *rootent = iso9660->primary.rootent;- /* There isn't rr_move entry.- * Create rr_move entry and insert it into the root entry.- */- rrmoved = isoent_create_virtual_dir(a, iso9660, "rr_moved");- if (rrmoved == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- /* Add "rr_moved" entry to the root entry. */- isoent_add_child_head(rootent, rrmoved);- archive_entry_set_nlink(rootent->file->entry,- archive_entry_nlink(rootent->file->entry) + 1);- /* Register "rr_moved" entry to second level pathtable. */- path_table_add_entry(&(iso9660->primary.pathtbl[1]), rrmoved);- /* Save rr_moved. */- *rr_moved = rrmoved;- }- /*- * Make a clone of curent which is going to be relocated- * to rr_moved.- */- mvent = isoent_clone(curent);- if (mvent == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- /* linking.. and use for creating "CL", "PL" and "RE" */- mvent->rr_parent = curent->parent;- curent->rr_child = mvent;- /*- * Move subdirectories from the curent to mvent- */- if (curent->children.first != NULL) {- *mvent->children.last = curent->children.first;- mvent->children.last = curent->children.last;- }- for (np = mvent->children.first; np != NULL; np = np->chnext)- np->parent = mvent;- mvent->children.cnt = curent->children.cnt;- curent->children.cnt = 0;- curent->children.first = NULL;- curent->children.last = &curent->children.first;-- if (curent->subdirs.first != NULL) {- *mvent->subdirs.last = curent->subdirs.first;- mvent->subdirs.last = curent->subdirs.last;- }- mvent->subdirs.cnt = curent->subdirs.cnt;- curent->subdirs.cnt = 0;- curent->subdirs.first = NULL;- curent->subdirs.last = &curent->subdirs.first;-- /*- * The mvent becomes a child of the rr_moved entry.- */- isoent_add_child_tail(rrmoved, mvent);- archive_entry_set_nlink(rrmoved->file->entry,- archive_entry_nlink(rrmoved->file->entry) + 1);- /*- * This entry which relocated to the rr_moved directory- * has to set the flag as a file.- * See also RRIP 4.1.5.1 Description of the "CL" System Use Entry.- */- curent->dir = 0;-- *newent = mvent;-- return (ARCHIVE_OK);-}--static int-isoent_rr_move(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;- struct path_table *pt;- struct isoent *rootent, *rr_moved;- struct isoent *np, *last;- int r;-- pt = &(iso9660->primary.pathtbl[MAX_DEPTH-1]);- /* There aren't level 8 directories reaching a deeper level. */- if (pt->cnt == 0)- return (ARCHIVE_OK);-- rootent = iso9660->primary.rootent;- /* If "rr_moved" directory is already existing,- * we have to use it. */- rr_moved = isoent_find_child(rootent, "rr_moved");- if (rr_moved != NULL &&- rr_moved != rootent->children.first) {- /*- * It's necessary that rr_move is the first entry- * of the root.- */- /* Remove "rr_moved" entry from children chain. */- isoent_remove_child(rootent, rr_moved);-- /* Add "rr_moved" entry into the head of children chain. */- isoent_add_child_head(rootent, rr_moved);- }-- /*- * Check level 8 path_table.- * If find out sub directory entries, that entries move to rr_move.- */- np = pt->first;- while (np != NULL) {- last = path_table_last_entry(pt);- for (; np != NULL; np = np->ptnext) {- struct isoent *mvent;- struct isoent *newent;-- if (!np->dir)- continue;- for (mvent = np->subdirs.first;- mvent != NULL; mvent = mvent->drnext) {- r = isoent_rr_move_dir(a, &rr_moved,- mvent, &newent);- if (r < 0)- return (r);- isoent_collect_dirs(&(iso9660->primary),- newent, 2);- }- }- /* If new entries are added to level 8 path_talbe,- * its sub directory entries move to rr_move too.- */- np = last->ptnext;- }-- return (ARCHIVE_OK);-}--/*- * This comparing rule is according to ISO9660 Standard 6.9.1- */-static int-__LA_LIBC_CC-_compare_path_table(const void *v1, const void *v2)-{- const struct isoent *p1, *p2;- const char *s1, *s2;- int cmp, l;-- p1 = *((const struct isoent **)(uintptr_t)v1);- p2 = *((const struct isoent **)(uintptr_t)v2);-- /* Compare parent directory number */- cmp = p1->parent->dir_number - p2->parent->dir_number;- if (cmp != 0)- return (cmp);-- /* Compare identifier */- s1 = p1->identifier;- s2 = p2->identifier;- l = p1->ext_off;- if (l > p2->ext_off)- l = p2->ext_off;- cmp = strncmp(s1, s2, l);- if (cmp != 0)- return (cmp);- if (p1->ext_off < p2->ext_off) {- s2 += l;- l = p2->ext_off - p1->ext_off;- while (l--)- if (0x20 != *s2++)- return (0x20- - *(const unsigned char *)(s2 - 1));- } else if (p1->ext_off > p2->ext_off) {- s1 += l;- l = p1->ext_off - p2->ext_off;- while (l--)- if (0x20 != *s1++)- return (*(const unsigned char *)(s1 - 1)- - 0x20);- }- return (0);-}--static int-__LA_LIBC_CC-_compare_path_table_joliet(const void *v1, const void *v2)-{- const struct isoent *p1, *p2;- const unsigned char *s1, *s2;- int cmp, l;-- p1 = *((const struct isoent **)(uintptr_t)v1);- p2 = *((const struct isoent **)(uintptr_t)v2);-- /* Compare parent directory number */- cmp = p1->parent->dir_number - p2->parent->dir_number;- if (cmp != 0)- return (cmp);-- /* Compare identifier */- s1 = (const unsigned char *)p1->identifier;- s2 = (const unsigned char *)p2->identifier;- l = p1->ext_off;- if (l > p2->ext_off)- l = p2->ext_off;- cmp = memcmp(s1, s2, l);- if (cmp != 0)- return (cmp);- if (p1->ext_off < p2->ext_off) {- s2 += l;- l = p2->ext_off - p1->ext_off;- while (l--)- if (0 != *s2++)- return (- *(const unsigned char *)(s2 - 1));- } else if (p1->ext_off > p2->ext_off) {- s1 += l;- l = p1->ext_off - p2->ext_off;- while (l--)- if (0 != *s1++)- return (*(const unsigned char *)(s1 - 1));- }- return (0);-}--static inline void-path_table_add_entry(struct path_table *pathtbl, struct isoent *ent)-{- ent->ptnext = NULL;- *pathtbl->last = ent;- pathtbl->last = &(ent->ptnext);- pathtbl->cnt ++;-}--static inline struct isoent *-path_table_last_entry(struct path_table *pathtbl)-{- if (pathtbl->first == NULL)- return (NULL);- return (((struct isoent *)(void *)- ((char *)(pathtbl->last) - offsetof(struct isoent, ptnext))));-}--/*- * Sort directory entries in path_table- * and assign directory number to each entries.- */-static int-isoent_make_path_table_2(struct archive_write *a, struct vdd *vdd,- int depth, int *dir_number)-{- struct isoent *np;- struct isoent **enttbl;- struct path_table *pt;- int i;-- pt = &vdd->pathtbl[depth];- if (pt->cnt == 0) {- pt->sorted = NULL;- return (ARCHIVE_OK);- }- enttbl = malloc(pt->cnt * sizeof(struct isoent *));- if (enttbl == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- pt->sorted = enttbl;- for (np = pt->first; np != NULL; np = np->ptnext)- *enttbl ++ = np;- enttbl = pt->sorted;-- switch (vdd->vdd_type) {- case VDD_PRIMARY:- case VDD_ENHANCED:-#ifdef __COMPAR_FN_T- qsort(enttbl, pt->cnt, sizeof(struct isoent *),- (__compar_fn_t)_compare_path_table);-#else- qsort(enttbl, pt->cnt, sizeof(struct isoent *),- _compare_path_table);-#endif- break;- case VDD_JOLIET:-#ifdef __COMPAR_FN_T- qsort(enttbl, pt->cnt, sizeof(struct isoent *),- (__compar_fn_t)_compare_path_table_joliet);-#else- qsort(enttbl, pt->cnt, sizeof(struct isoent *),- _compare_path_table_joliet);-#endif- break;- }- for (i = 0; i < pt->cnt; i++)- enttbl[i]->dir_number = (*dir_number)++;-- return (ARCHIVE_OK);-}--static int-isoent_alloc_path_table(struct archive_write *a, struct vdd *vdd,- int max_depth)-{- int i;-- vdd->max_depth = max_depth;- vdd->pathtbl = malloc(sizeof(*vdd->pathtbl) * vdd->max_depth);- if (vdd->pathtbl == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- for (i = 0; i < vdd->max_depth; i++) {- vdd->pathtbl[i].first = NULL;- vdd->pathtbl[i].last = &(vdd->pathtbl[i].first);- vdd->pathtbl[i].sorted = NULL;- vdd->pathtbl[i].cnt = 0;- }- return (ARCHIVE_OK);-}--/*- * Make Path Tables- */-static int-isoent_make_path_table(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;- int depth, r;- int dir_number;-- /*- * Init Path Table.- */- if (iso9660->dircnt_max >= MAX_DEPTH &&- (!iso9660->opt.limit_depth || iso9660->opt.iso_level == 4))- r = isoent_alloc_path_table(a, &(iso9660->primary),- iso9660->dircnt_max + 1);- else- /* The number of levels in the hierarchy cannot exceed- * eight. */- r = isoent_alloc_path_table(a, &(iso9660->primary),- MAX_DEPTH);- if (r < 0)- return (r);- if (iso9660->opt.joliet) {- r = isoent_alloc_path_table(a, &(iso9660->joliet),- iso9660->dircnt_max + 1);- if (r < 0)- return (r);- }-- /* Step 0.- * - Collect directories for primary and joliet.- */- isoent_collect_dirs(&(iso9660->primary), NULL, 0);- if (iso9660->opt.joliet)- isoent_collect_dirs(&(iso9660->joliet), NULL, 0);- /*- * Rockridge; move deeper depth directories to rr_moved.- */- if (iso9660->opt.rr) {- r = isoent_rr_move(a);- if (r < 0)- return (r);- }-- /* Update nlink. */- isofile_connect_hardlink_files(iso9660);-- /* Step 1.- * - Renew a value of the depth of that directories.- * - Resolve hardlinks.- * - Convert pathnames to ISO9660 name or UCS2(joliet).- * - Sort files by each directory.- */- r = isoent_traverse_tree(a, &(iso9660->primary));- if (r < 0)- return (r);- if (iso9660->opt.joliet) {- r = isoent_traverse_tree(a, &(iso9660->joliet));- if (r < 0)- return (r);- }-- /* Step 2.- * - Sort directories.- * - Assign all directory number.- */- dir_number = 1;- for (depth = 0; depth < iso9660->primary.max_depth; depth++) {- r = isoent_make_path_table_2(a, &(iso9660->primary),- depth, &dir_number);- if (r < 0)- return (r);- }- if (iso9660->opt.joliet) {- dir_number = 1;- for (depth = 0; depth < iso9660->joliet.max_depth; depth++) {- r = isoent_make_path_table_2(a, &(iso9660->joliet),- depth, &dir_number);- if (r < 0)- return (r);- }- }- if (iso9660->opt.limit_dirs && dir_number > 0xffff) {- /*- * Maximum number of directories is 65535(0xffff)- * doe to size(16bit) of Parent Directory Number of- * the Path Table.- * See also ISO9660 Standard 9.4.- */- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Too many directories(%d) over 65535.", dir_number);- return (ARCHIVE_FATAL);- }-- /* Get the size of the Path Table. */- calculate_path_table_size(&(iso9660->primary));- if (iso9660->opt.joliet)- calculate_path_table_size(&(iso9660->joliet));-- return (ARCHIVE_OK);-}--static int-isoent_find_out_boot_file(struct archive_write *a, struct isoent *rootent)-{- struct iso9660 *iso9660 = a->format_data;-- /* Find a isoent of the boot file. */- iso9660->el_torito.boot = isoent_find_entry(rootent,- iso9660->el_torito.boot_filename.s);- if (iso9660->el_torito.boot == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't find the boot image file ``%s''",- iso9660->el_torito.boot_filename.s);- return (ARCHIVE_FATAL);- }- iso9660->el_torito.boot->file->boot = BOOT_IMAGE;- return (ARCHIVE_OK);-}--static int-isoent_create_boot_catalog(struct archive_write *a, struct isoent *rootent)-{- struct iso9660 *iso9660 = a->format_data;- struct isofile *file;- struct isoent *isoent;- struct archive_entry *entry;-- (void)rootent; /* UNUSED */- /*- * Create the entry which is the "boot.catalog" file.- */- file = isofile_new(a, NULL);- if (file == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- archive_entry_set_pathname(file->entry,- iso9660->el_torito.catalog_filename.s);- archive_entry_set_size(file->entry, LOGICAL_BLOCK_SIZE);- archive_entry_set_mtime(file->entry, iso9660->birth_time, 0);- archive_entry_set_atime(file->entry, iso9660->birth_time, 0);- archive_entry_set_ctime(file->entry, iso9660->birth_time, 0);- archive_entry_set_uid(file->entry, getuid());- archive_entry_set_gid(file->entry, getgid());- archive_entry_set_mode(file->entry, AE_IFREG | 0444);- archive_entry_set_nlink(file->entry, 1);-- if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {- isofile_free(file);- return (ARCHIVE_FATAL);- }- file->boot = BOOT_CATALOG;- file->content.size = LOGICAL_BLOCK_SIZE;- isofile_add_entry(iso9660, file);-- isoent = isoent_new(file);- if (isoent == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- isoent->virtual = 1;-- /* Add the "boot.catalog" entry into tree */- if (isoent_tree(a, &isoent) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- iso9660->el_torito.catalog = isoent;- /*- * Get a boot media type.- */- switch (iso9660->opt.boot_type) {- default:- case OPT_BOOT_TYPE_AUTO:- /* Try detecting a media type of the boot image. */- entry = iso9660->el_torito.boot->file->entry;- if (archive_entry_size(entry) == FD_1_2M_SIZE)- iso9660->el_torito.media_type =- BOOT_MEDIA_1_2M_DISKETTE;- else if (archive_entry_size(entry) == FD_1_44M_SIZE)- iso9660->el_torito.media_type =- BOOT_MEDIA_1_44M_DISKETTE;- else if (archive_entry_size(entry) == FD_2_88M_SIZE)- iso9660->el_torito.media_type =- BOOT_MEDIA_2_88M_DISKETTE;- else- /* We cannot decide whether the boot image is- * hard-disk. */- iso9660->el_torito.media_type =- BOOT_MEDIA_NO_EMULATION;- break;- case OPT_BOOT_TYPE_NO_EMU:- iso9660->el_torito.media_type = BOOT_MEDIA_NO_EMULATION;- break;- case OPT_BOOT_TYPE_HARD_DISK:- iso9660->el_torito.media_type = BOOT_MEDIA_HARD_DISK;- break;- case OPT_BOOT_TYPE_FD:- entry = iso9660->el_torito.boot->file->entry;- if (archive_entry_size(entry) <= FD_1_2M_SIZE)- iso9660->el_torito.media_type =- BOOT_MEDIA_1_2M_DISKETTE;- else if (archive_entry_size(entry) <= FD_1_44M_SIZE)- iso9660->el_torito.media_type =- BOOT_MEDIA_1_44M_DISKETTE;- else if (archive_entry_size(entry) <= FD_2_88M_SIZE)- iso9660->el_torito.media_type =- BOOT_MEDIA_2_88M_DISKETTE;- else {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Boot image file(``%s'') size is too big "- "for fd type.",- iso9660->el_torito.boot_filename.s);- return (ARCHIVE_FATAL);- }- break;- }-- /*- * Get a system type.- * TODO: `El Torito' specification says "A copy of byte 5 from the- * Partition Table found in the boot image".- */- iso9660->el_torito.system_type = 0;-- /*- * Get an ID.- */- if (iso9660->opt.publisher)- archive_string_copy(&(iso9660->el_torito.id),- &(iso9660->publisher_identifier));--- return (ARCHIVE_OK);-}--/*- * If a media type is floppy, return its image size.- * otherwise return 0.- */-static size_t-fd_boot_image_size(int media_type)-{- switch (media_type) {- case BOOT_MEDIA_1_2M_DISKETTE:- return (FD_1_2M_SIZE);- case BOOT_MEDIA_1_44M_DISKETTE:- return (FD_1_44M_SIZE);- case BOOT_MEDIA_2_88M_DISKETTE:- return (FD_2_88M_SIZE);- default:- return (0);- }-}--/*- * Make a boot catalog image data.- */-static int-make_boot_catalog(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;- unsigned char *block;- unsigned char *p;- uint16_t sum, *wp;-- block = wb_buffptr(a);- memset(block, 0, LOGICAL_BLOCK_SIZE);- p = block;- /*- * Validation Entry- */- /* Header ID */- p[0] = 1;- /* Platform ID */- p[1] = iso9660->el_torito.platform_id;- /* Reserved */- p[2] = p[3] = 0;- /* ID */- if (archive_strlen(&(iso9660->el_torito.id)) > 0)- strncpy((char *)p+4, iso9660->el_torito.id.s, 23);- p[27] = 0;- /* Checksum */- p[28] = p[29] = 0;- /* Key */- p[30] = 0x55;- p[31] = 0xAA;-- sum = 0;- wp = (uint16_t *)block;- while (wp < (uint16_t *)&block[32])- sum += archive_le16dec(wp++);- set_num_721(&block[28], (~sum) + 1);-- /*- * Initial/Default Entry- */- p = &block[32];- /* Boot Indicator */- p[0] = 0x88;- /* Boot media type */- p[1] = iso9660->el_torito.media_type;- /* Load Segment */- if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)- set_num_721(&p[2], iso9660->el_torito.boot_load_seg);- else- set_num_721(&p[2], 0);- /* System Type */- p[4] = iso9660->el_torito.system_type;- /* Unused */- p[5] = 0;- /* Sector Count */- if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)- set_num_721(&p[6], iso9660->el_torito.boot_load_size);- else- set_num_721(&p[6], 1);- /* Load RBA */- set_num_731(&p[8],- iso9660->el_torito.boot->file->content.location);- /* Unused */- memset(&p[12], 0, 20);-- return (wb_consume(a, LOGICAL_BLOCK_SIZE));-}--static int-setup_boot_information(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;- struct isoent *np;- int64_t size;- uint32_t sum;- unsigned char buff[4096];-- np = iso9660->el_torito.boot;- lseek(iso9660->temp_fd,- np->file->content.offset_of_temp + 64, SEEK_SET);- size = archive_entry_size(np->file->entry) - 64;- if (size <= 0) {- archive_set_error(&a->archive, errno,- "Boot file(%jd) is too small", (intmax_t)size + 64);- return (ARCHIVE_FATAL);- }- sum = 0;- while (size > 0) {- size_t rsize;- ssize_t i, rs;-- if (size > (int64_t)sizeof(buff))- rsize = sizeof(buff);- else- rsize = (size_t)size;-- rs = read(iso9660->temp_fd, buff, rsize);- if (rs <= 0) {- archive_set_error(&a->archive, errno,- "Can't read temporary file(%jd)",- (intmax_t)rs);- return (ARCHIVE_FATAL);- }- for (i = 0; i < rs; i += 4)- sum += archive_le32dec(buff + i);- size -= rs;- }- /* Set the location of Primary Volume Descriptor. */- set_num_731(buff, SYSTEM_AREA_BLOCK);- /* Set the location of the boot file. */- set_num_731(buff+4, np->file->content.location);- /* Set the size of the boot file. */- size = fd_boot_image_size(iso9660->el_torito.media_type);- if (size == 0)- size = archive_entry_size(np->file->entry);- set_num_731(buff+8, (uint32_t)size);- /* Set the sum of the boot file. */- set_num_731(buff+12, sum);- /* Clear reserved bytes. */- memset(buff+16, 0, 40);-- /* Overwrite the boot file. */- lseek(iso9660->temp_fd,- np->file->content.offset_of_temp + 8, SEEK_SET);- return (write_to_temp(a, buff, 56));-}--#ifdef HAVE_ZLIB_H--static int-zisofs_init_zstream(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;- int r;-- iso9660->zisofs.stream.next_in = NULL;- iso9660->zisofs.stream.avail_in = 0;- iso9660->zisofs.stream.total_in = 0;- iso9660->zisofs.stream.total_out = 0;- if (iso9660->zisofs.stream_valid)- r = deflateReset(&(iso9660->zisofs.stream));- else {- r = deflateInit(&(iso9660->zisofs.stream),- iso9660->zisofs.compression_level);- iso9660->zisofs.stream_valid = 1;- }- switch (r) {- case Z_OK:- break;- default:- case Z_STREAM_ERROR:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Internal error initializing "- "compression library: invalid setup parameter");- return (ARCHIVE_FATAL);- case Z_MEM_ERROR:- archive_set_error(&a->archive, ENOMEM,- "Internal error initializing "- "compression library");- return (ARCHIVE_FATAL);- case Z_VERSION_ERROR:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Internal error initializing "- "compression library: invalid library version");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}--#endif /* HAVE_ZLIB_H */--static int-zisofs_init(struct archive_write *a, struct isofile *file)-{- struct iso9660 *iso9660 = a->format_data;-#ifdef HAVE_ZLIB_H- uint64_t tsize;- size_t _ceil, bpsize;- int r;-#endif-- iso9660->zisofs.detect_magic = 0;- iso9660->zisofs.making = 0;-- if (!iso9660->opt.rr || !iso9660->opt.zisofs)- return (ARCHIVE_OK);-- if (archive_entry_size(file->entry) >= 24 &&- archive_entry_size(file->entry) < MULTI_EXTENT_SIZE) {- /* Acceptable file size for zisofs. */- iso9660->zisofs.detect_magic = 1;- iso9660->zisofs.magic_cnt = 0;- }- if (!iso9660->zisofs.detect_magic)- return (ARCHIVE_OK);--#ifdef HAVE_ZLIB_H- /* The number of Logical Blocks which uncompressed data- * will use in iso-image file is the same as the number of- * Logical Blocks which zisofs(compressed) data will use- * in ISO-image file. It won't reduce iso-image file size. */- if (archive_entry_size(file->entry) <= LOGICAL_BLOCK_SIZE)- return (ARCHIVE_OK);-- /* Initialize compression library */- r = zisofs_init_zstream(a);- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Mark file->zisofs to create RRIP 'ZF' Use Entry. */- file->zisofs.header_size = ZF_HEADER_SIZE >> 2;- file->zisofs.log2_bs = ZF_LOG2_BS;- file->zisofs.uncompressed_size =- (uint32_t)archive_entry_size(file->entry);-- /* Calculate a size of Block Pointers of zisofs. */- _ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)- >> file->zisofs.log2_bs;- iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1;- iso9660->zisofs.block_pointers_idx = 0;-- /* Ensure a buffer size used for Block Pointers */- bpsize = iso9660->zisofs.block_pointers_cnt *- sizeof(iso9660->zisofs.block_pointers[0]);- if (iso9660->zisofs.block_pointers_allocated < bpsize) {- free(iso9660->zisofs.block_pointers);- iso9660->zisofs.block_pointers = malloc(bpsize);- if (iso9660->zisofs.block_pointers == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate data");- return (ARCHIVE_FATAL);- }- iso9660->zisofs.block_pointers_allocated = bpsize;- }-- /*- * Skip zisofs header and Block Pointers, which we will write- * after all compressed data of a file written to the temporary- * file.- */- tsize = ZF_HEADER_SIZE + bpsize;- if (write_null(a, (size_t)tsize) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /*- * Initialize some variables to make zisofs.- */- archive_le32enc(&(iso9660->zisofs.block_pointers[0]),- (uint32_t)tsize);- iso9660->zisofs.remaining = file->zisofs.uncompressed_size;- iso9660->zisofs.making = 1;- iso9660->zisofs.allzero = 1;- iso9660->zisofs.block_offset = tsize;- iso9660->zisofs.total_size = tsize;- iso9660->cur_file->cur_content->size = tsize;-#endif-- return (ARCHIVE_OK);-}--static void-zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)-{- struct iso9660 *iso9660 = a->format_data;- struct isofile *file = iso9660->cur_file;- const unsigned char *p, *endp;- const unsigned char *magic_buff;- uint32_t uncompressed_size;- unsigned char header_size;- unsigned char log2_bs;- size_t _ceil, doff;- uint32_t bst, bed;- int magic_max;- int64_t entry_size;-- entry_size = archive_entry_size(file->entry);- if ((int64_t)sizeof(iso9660->zisofs.magic_buffer) > entry_size)- magic_max = (int)entry_size;- else- magic_max = sizeof(iso9660->zisofs.magic_buffer);-- if (iso9660->zisofs.magic_cnt == 0 && s >= (size_t)magic_max)- /* It's unnecessary we copy buffer. */- magic_buff = buff;- else {- if (iso9660->zisofs.magic_cnt < magic_max) {- size_t l;-- l = sizeof(iso9660->zisofs.magic_buffer)- - iso9660->zisofs.magic_cnt;- if (l > s)- l = s;- memcpy(iso9660->zisofs.magic_buffer- + iso9660->zisofs.magic_cnt, buff, l);- iso9660->zisofs.magic_cnt += (int)l;- if (iso9660->zisofs.magic_cnt < magic_max)- return;- }- magic_buff = iso9660->zisofs.magic_buffer;- }- iso9660->zisofs.detect_magic = 0;- p = magic_buff;-- /* Check the magic code of zisofs. */- if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)- /* This is not zisofs file which made by mkzftree. */- return;- p += sizeof(zisofs_magic);-- /* Read a zisofs header. */- uncompressed_size = archive_le32dec(p);- header_size = p[4];- log2_bs = p[5];- if (uncompressed_size < 24 || header_size != 4 ||- log2_bs > 30 || log2_bs < 7)- return;/* Invalid or not supported header. */-- /* Calculate a size of Block Pointers of zisofs. */- _ceil = (uncompressed_size +- (ARCHIVE_LITERAL_LL(1) << log2_bs) -1) >> log2_bs;- doff = (_ceil + 1) * 4 + 16;- if (entry_size < (int64_t)doff)- return;/* Invalid data. */-- /* Check every Block Pointer has valid value. */- p = magic_buff + 16;- endp = magic_buff + magic_max;- while (_ceil && p + 8 <= endp) {- bst = archive_le32dec(p);- if (bst != doff)- return;/* Invalid data. */- p += 4;- bed = archive_le32dec(p);- if (bed < bst || bed > entry_size)- return;/* Invalid data. */- doff += bed - bst;- _ceil--;- }-- file->zisofs.uncompressed_size = uncompressed_size;- file->zisofs.header_size = header_size;- file->zisofs.log2_bs = log2_bs;-- /* Disable making a zisofs image. */- iso9660->zisofs.making = 0;-}--#ifdef HAVE_ZLIB_H--/*- * Compress data and write it to a temporary file.- */-static int-zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)-{- struct iso9660 *iso9660 = a->format_data;- struct isofile *file = iso9660->cur_file;- const unsigned char *b;- z_stream *zstrm;- size_t avail, csize;- int flush, r;-- zstrm = &(iso9660->zisofs.stream);- zstrm->next_out = wb_buffptr(a);- zstrm->avail_out = (uInt)wb_remaining(a);- b = (const unsigned char *)buff;- do {- avail = ZF_BLOCK_SIZE - zstrm->total_in;- if (s < avail) {- avail = s;- flush = Z_NO_FLUSH;- } else- flush = Z_FINISH;- iso9660->zisofs.remaining -= avail;- if (iso9660->zisofs.remaining <= 0)- flush = Z_FINISH;-- zstrm->next_in = (Bytef *)(uintptr_t)(const void *)b;- zstrm->avail_in = (uInt)avail;-- /*- * Check if current data block are all zero.- */- if (iso9660->zisofs.allzero) {- const unsigned char *nonzero = b;- const unsigned char *nonzeroend = b + avail;-- while (nonzero < nonzeroend)- if (*nonzero++) {- iso9660->zisofs.allzero = 0;- break;- }- }- b += avail;- s -= avail;-- /*- * If current data block are all zero, we do not use- * compressed data.- */- if (flush == Z_FINISH && iso9660->zisofs.allzero &&- avail + zstrm->total_in == ZF_BLOCK_SIZE) {- if (iso9660->zisofs.block_offset !=- file->cur_content->size) {- int64_t diff;-- r = wb_set_offset(a,- file->cur_content->offset_of_temp +- iso9660->zisofs.block_offset);- if (r != ARCHIVE_OK)- return (r);- diff = file->cur_content->size -- iso9660->zisofs.block_offset;- file->cur_content->size -= diff;- iso9660->zisofs.total_size -= diff;- }- zstrm->avail_in = 0;- }-- /*- * Compress file data.- */- while (zstrm->avail_in > 0) {- csize = zstrm->total_out;- r = deflate(zstrm, flush);- switch (r) {- case Z_OK:- case Z_STREAM_END:- csize = zstrm->total_out - csize;- if (wb_consume(a, csize) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- iso9660->zisofs.total_size += csize;- iso9660->cur_file->cur_content->size += csize;- zstrm->next_out = wb_buffptr(a);- zstrm->avail_out = (uInt)wb_remaining(a);- break;- default:- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Compression failed:"- " deflate() call returned status %d",- r);- return (ARCHIVE_FATAL);- }- }-- if (flush == Z_FINISH) {- /*- * Save the information of one zisofs block.- */- iso9660->zisofs.block_pointers_idx ++;- archive_le32enc(&(iso9660->zisofs.block_pointers[- iso9660->zisofs.block_pointers_idx]),- (uint32_t)iso9660->zisofs.total_size);- r = zisofs_init_zstream(a);- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);- iso9660->zisofs.allzero = 1;- iso9660->zisofs.block_offset = file->cur_content->size;- }- } while (s);-- return (ARCHIVE_OK);-}--static int-zisofs_finish_entry(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;- struct isofile *file = iso9660->cur_file;- unsigned char buff[16];- size_t s;- int64_t tail;-- /* Direct temp file stream to zisofs temp file stream. */- archive_entry_set_size(file->entry, iso9660->zisofs.total_size);-- /*- * Save a file pointer which points the end of current zisofs data.- */- tail = wb_offset(a);-- /*- * Make a header.- *- * +-----------------+----------------+-----------------+- * | Header 16 bytes | Block Pointers | Compressed data |- * +-----------------+----------------+-----------------+- * 0 16 +X- * Block Pointers :- * 4 * (((Uncompressed file size + block_size -1) / block_size) + 1)- *- * Write zisofs header.- * Magic number- * +----+----+----+----+----+----+----+----+- * | 37 | E4 | 53 | 96 | C9 | DB | D6 | 07 |- * +----+----+----+----+----+----+----+----+- * 0 1 2 3 4 5 6 7 8- *- * +------------------------+------------------+- * | Uncompressed file size | header_size >> 2 |- * +------------------------+------------------+- * 8 12 13- *- * +-----------------+----------------+- * | log2 block_size | Reserved(0000) |- * +-----------------+----------------+- * 13 14 16- */- memcpy(buff, zisofs_magic, 8);- set_num_731(buff+8, file->zisofs.uncompressed_size);- buff[12] = file->zisofs.header_size;- buff[13] = file->zisofs.log2_bs;- buff[14] = buff[15] = 0;/* Reserved */-- /* Move to the right position to write the header. */- wb_set_offset(a, file->content.offset_of_temp);-- /* Write the header. */- if (wb_write_to_temp(a, buff, 16) != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /*- * Write zisofs Block Pointers.- */- s = iso9660->zisofs.block_pointers_cnt *- sizeof(iso9660->zisofs.block_pointers[0]);- if (wb_write_to_temp(a, iso9660->zisofs.block_pointers, s)- != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Set a file pointer back to the end of the temporary file. */- wb_set_offset(a, tail);-- return (ARCHIVE_OK);-}--static int-zisofs_free(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;- int ret = ARCHIVE_OK;-- free(iso9660->zisofs.block_pointers);- if (iso9660->zisofs.stream_valid &&- deflateEnd(&(iso9660->zisofs.stream)) != Z_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to clean up compressor");- ret = ARCHIVE_FATAL;- }- iso9660->zisofs.block_pointers = NULL;- iso9660->zisofs.stream_valid = 0;- return (ret);-}--struct zisofs_extract {- int pz_log2_bs; /* Log2 of block size */- uint64_t pz_uncompressed_size;- size_t uncompressed_buffer_size;-- unsigned int initialized:1;- unsigned int header_passed:1;-- uint32_t pz_offset;- unsigned char *block_pointers;- size_t block_pointers_size;- size_t block_pointers_avail;- size_t block_off;- uint32_t block_avail;-- z_stream stream;- int stream_valid;-};--static ssize_t-zisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs,- const unsigned char *p, size_t bytes)-{- size_t avail = bytes;- size_t _ceil, xsize;-- /* Allocate block pointers buffer. */- _ceil = (size_t)((zisofs->pz_uncompressed_size +- (((int64_t)1) << zisofs->pz_log2_bs) - 1)- >> zisofs->pz_log2_bs);- xsize = (_ceil + 1) * 4;- if (zisofs->block_pointers == NULL) {- size_t alloc = ((xsize >> 10) + 1) << 10;- zisofs->block_pointers = malloc(alloc);- if (zisofs->block_pointers == NULL) {- archive_set_error(&a->archive, ENOMEM,- "No memory for zisofs decompression");- return (ARCHIVE_FATAL);- }- }- zisofs->block_pointers_size = xsize;-- /* Allocate uncompressed data buffer. */- zisofs->uncompressed_buffer_size = (size_t)1UL << zisofs->pz_log2_bs;-- /*- * Read the file header, and check the magic code of zisofs.- */- if (!zisofs->header_passed) {- int err = 0;- if (avail < 16) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Illegal zisofs file body");- return (ARCHIVE_FATAL);- }-- if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)- err = 1;- else if (archive_le32dec(p + 8) != zisofs->pz_uncompressed_size)- err = 1;- else if (p[12] != 4 || p[13] != zisofs->pz_log2_bs)- err = 1;- if (err) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Illegal zisofs file body");- return (ARCHIVE_FATAL);- }- avail -= 16;- p += 16;- zisofs->header_passed = 1;- }-- /*- * Read block pointers.- */- if (zisofs->header_passed &&- zisofs->block_pointers_avail < zisofs->block_pointers_size) {- xsize = zisofs->block_pointers_size- - zisofs->block_pointers_avail;- if (avail < xsize)- xsize = avail;- memcpy(zisofs->block_pointers- + zisofs->block_pointers_avail, p, xsize);- zisofs->block_pointers_avail += xsize;- avail -= xsize;- if (zisofs->block_pointers_avail- == zisofs->block_pointers_size) {- /* We've got all block pointers and initialize- * related variables. */- zisofs->block_off = 0;- zisofs->block_avail = 0;- /* Complete a initialization */- zisofs->initialized = 1;- }- }- return ((ssize_t)avail);-}--static ssize_t-zisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs,- const unsigned char *p, size_t bytes)-{- size_t avail;- int r;-- if (!zisofs->initialized) {- ssize_t rs = zisofs_extract_init(a, zisofs, p, bytes);- if (rs < 0)- return (rs);- if (!zisofs->initialized) {- /* We need more data. */- zisofs->pz_offset += (uint32_t)bytes;- return (bytes);- }- avail = rs;- p += bytes - avail;- } else- avail = bytes;-- /*- * Get block offsets from block pointers.- */- if (zisofs->block_avail == 0) {- uint32_t bst, bed;-- if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {- /* There isn't a pair of offsets. */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Illegal zisofs block pointers");- return (ARCHIVE_FATAL);- }- bst = archive_le32dec(- zisofs->block_pointers + zisofs->block_off);- if (bst != zisofs->pz_offset + (bytes - avail)) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Illegal zisofs block pointers(cannot seek)");- return (ARCHIVE_FATAL);- }- bed = archive_le32dec(- zisofs->block_pointers + zisofs->block_off + 4);- if (bed < bst) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Illegal zisofs block pointers");- return (ARCHIVE_FATAL);- }- zisofs->block_avail = bed - bst;- zisofs->block_off += 4;-- /* Initialize compression library for new block. */- if (zisofs->stream_valid)- r = inflateReset(&zisofs->stream);- else- r = inflateInit(&zisofs->stream);- if (r != Z_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't initialize zisofs decompression.");- return (ARCHIVE_FATAL);- }- zisofs->stream_valid = 1;- zisofs->stream.total_in = 0;- zisofs->stream.total_out = 0;- }-- /*- * Make uncompressed data.- */- if (zisofs->block_avail == 0) {- /*- * It's basically 32K bytes NUL data.- */- unsigned char *wb;- size_t size, wsize;-- size = zisofs->uncompressed_buffer_size;- while (size) {- wb = wb_buffptr(a);- if (size > wb_remaining(a))- wsize = wb_remaining(a);- else- wsize = size;- memset(wb, 0, wsize);- r = wb_consume(a, wsize);- if (r < 0)- return (r);- size -= wsize;- }- } else {- zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;- if (avail > zisofs->block_avail)- zisofs->stream.avail_in = zisofs->block_avail;- else- zisofs->stream.avail_in = (uInt)avail;- zisofs->stream.next_out = wb_buffptr(a);- zisofs->stream.avail_out = (uInt)wb_remaining(a);-- r = inflate(&zisofs->stream, 0);- switch (r) {- case Z_OK: /* Decompressor made some progress.*/- case Z_STREAM_END: /* Found end of stream. */- break;- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "zisofs decompression failed (%d)", r);- return (ARCHIVE_FATAL);- }- avail -= zisofs->stream.next_in - p;- zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);- r = wb_consume(a, wb_remaining(a) - zisofs->stream.avail_out);- if (r < 0)- return (r);- }- zisofs->pz_offset += (uint32_t)bytes;- return (bytes - avail);-}--static int-zisofs_rewind_boot_file(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;- struct isofile *file;- unsigned char *rbuff;- ssize_t r;- size_t remaining, rbuff_size;- struct zisofs_extract zext;- int64_t read_offset, write_offset, new_offset;- int fd, ret = ARCHIVE_OK;-- file = iso9660->el_torito.boot->file;- /*- * There is nothing to do if this boot file does not have- * zisofs header.- */- if (file->zisofs.header_size == 0)- return (ARCHIVE_OK);-- /*- * Uncompress the zisofs'ed file contents.- */- memset(&zext, 0, sizeof(zext));- zext.pz_uncompressed_size = file->zisofs.uncompressed_size;- zext.pz_log2_bs = file->zisofs.log2_bs;-- fd = iso9660->temp_fd;- new_offset = wb_offset(a);- read_offset = file->content.offset_of_temp;- remaining = (size_t)file->content.size;- if (remaining > 1024 * 32)- rbuff_size = 1024 * 32;- else- rbuff_size = remaining;-- rbuff = malloc(rbuff_size);- if (rbuff == NULL) {- archive_set_error(&a->archive, ENOMEM, "Can't allocate memory");- return (ARCHIVE_FATAL);- }- while (remaining) {- size_t rsize;- ssize_t rs;-- /* Get the current file pointer. */- write_offset = lseek(fd, 0, SEEK_CUR);-- /* Change the file pointer to read. */- lseek(fd, read_offset, SEEK_SET);-- rsize = rbuff_size;- if (rsize > remaining)- rsize = remaining;- rs = read(iso9660->temp_fd, rbuff, rsize);- if (rs <= 0) {- archive_set_error(&a->archive, errno,- "Can't read temporary file(%jd)", (intmax_t)rs);- ret = ARCHIVE_FATAL;- break;- }- remaining -= rs;- read_offset += rs;-- /* Put the file pointer back to write. */- lseek(fd, write_offset, SEEK_SET);-- r = zisofs_extract(a, &zext, rbuff, rs);- if (r < 0) {- ret = (int)r;- break;- }- }-- if (ret == ARCHIVE_OK) {- /*- * Change the boot file content from zisofs'ed data- * to plain data.- */- file->content.offset_of_temp = new_offset;- file->content.size = file->zisofs.uncompressed_size;- archive_entry_set_size(file->entry, file->content.size);- /* Set to be no zisofs. */- file->zisofs.header_size = 0;- file->zisofs.log2_bs = 0;- file->zisofs.uncompressed_size = 0;- r = wb_write_padding_to_temp(a, file->content.size);- if (r < 0)- ret = ARCHIVE_FATAL;- }-- /*- * Free the resource we used in this function only.- */- free(rbuff);- free(zext.block_pointers);- if (zext.stream_valid && inflateEnd(&(zext.stream)) != Z_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to clean up compressor");- ret = ARCHIVE_FATAL;- }-- return (ret);-}--#else--static int-zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)-{- (void)buff; /* UNUSED */- (void)s; /* UNUSED */- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Programming error");- return (ARCHIVE_FATAL);-}--static int-zisofs_rewind_boot_file(struct archive_write *a)-{- struct iso9660 *iso9660 = a->format_data;-- if (iso9660->el_torito.boot->file->zisofs.header_size != 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "We cannot extract the zisofs imaged boot file;"- " this may not boot in being zisofs imaged");- return (ARCHIVE_FAILED);- }- return (ARCHIVE_OK);-}--static int-zisofs_finish_entry(struct archive_write *a)-{- (void)a; /* UNUSED */- return (ARCHIVE_OK);-}--static int-zisofs_free(struct archive_write *a)-{- (void)a; /* UNUSED */- return (ARCHIVE_OK);-}--#endif /* HAVE_ZLIB_H */-
− c/archive_write_set_format_mtree.c
@@ -1,2217 +0,0 @@-/*-- * Copyright (c) 2008 Joerg Sonnenberger- * Copyright (c) 2009-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171 2009-12-29 06:39:07Z kientzle $");--#ifdef HAVE_SYS_TYPES_H-#include <sys/types.h>-#endif-#include <errno.h>-#include <stdlib.h>-#include <string.h>--#include "archive.h"-#include "archive_digest_private.h"-#include "archive_entry.h"-#include "archive_entry_private.h"-#include "archive_private.h"-#include "archive_rb.h"-#include "archive_string.h"-#include "archive_write_private.h"--#define INDENTNAMELEN 15-#define MAXLINELEN 80-#define SET_KEYS \- (F_FLAGS | F_GID | F_GNAME | F_MODE | F_TYPE | F_UID | F_UNAME)--struct attr_counter {- struct attr_counter *prev;- struct attr_counter *next;- struct mtree_entry *m_entry;- int count;-};--struct att_counter_set {- struct attr_counter *uid_list;- struct attr_counter *gid_list;- struct attr_counter *mode_list;- struct attr_counter *flags_list;-};--struct mtree_chain {- struct mtree_entry *first;- struct mtree_entry **last;-};--/*- * The Data only for a directory file.- */-struct dir_info {- struct archive_rb_tree rbtree;- struct mtree_chain children;- struct mtree_entry *chnext;- int virtual;-};--/*- * The Data only for a regular file.- */-struct reg_info {- int compute_sum;- uint32_t crc;- struct ae_digest digest;-};--struct mtree_entry {- struct archive_rb_node rbnode;- struct mtree_entry *next;- struct mtree_entry *parent;- struct dir_info *dir_info;- struct reg_info *reg_info;-- struct archive_string parentdir;- struct archive_string basename;- struct archive_string pathname;- struct archive_string symlink;- struct archive_string uname;- struct archive_string gname;- struct archive_string fflags_text;- unsigned int nlink;- mode_t filetype;- mode_t mode;- int64_t size;- int64_t uid;- int64_t gid;- time_t mtime;- long mtime_nsec;- unsigned long fflags_set;- unsigned long fflags_clear;- dev_t rdevmajor;- dev_t rdevminor;- dev_t devmajor;- dev_t devminor;- int64_t ino;-};--struct mtree_writer {- struct mtree_entry *mtree_entry;- struct mtree_entry *root;- struct mtree_entry *cur_dirent;- struct archive_string cur_dirstr;- struct mtree_chain file_list;-- struct archive_string ebuf;- struct archive_string buf;- int first;- uint64_t entry_bytes_remaining;-- /*- * Set global value.- */- struct {- int processing;- mode_t type;- int keys;- int64_t uid;- int64_t gid;- mode_t mode;- unsigned long fflags_set;- unsigned long fflags_clear;- } set;- struct att_counter_set acs;- int classic;- int depth;-- /* check sum */- int compute_sum;- uint32_t crc;- uint64_t crc_len;-#ifdef ARCHIVE_HAS_MD5- archive_md5_ctx md5ctx;-#endif-#ifdef ARCHIVE_HAS_RMD160- archive_rmd160_ctx rmd160ctx;-#endif-#ifdef ARCHIVE_HAS_SHA1- archive_sha1_ctx sha1ctx;-#endif-#ifdef ARCHIVE_HAS_SHA256- archive_sha256_ctx sha256ctx;-#endif-#ifdef ARCHIVE_HAS_SHA384- archive_sha384_ctx sha384ctx;-#endif-#ifdef ARCHIVE_HAS_SHA512- archive_sha512_ctx sha512ctx;-#endif- /* Keyword options */- int keys;-#define F_CKSUM 0x00000001 /* checksum */-#define F_DEV 0x00000002 /* device type */-#define F_DONE 0x00000004 /* directory done */-#define F_FLAGS 0x00000008 /* file flags */-#define F_GID 0x00000010 /* gid */-#define F_GNAME 0x00000020 /* group name */-#define F_IGN 0x00000040 /* ignore */-#define F_MAGIC 0x00000080 /* name has magic chars */-#define F_MD5 0x00000100 /* MD5 digest */-#define F_MODE 0x00000200 /* mode */-#define F_NLINK 0x00000400 /* number of links */-#define F_NOCHANGE 0x00000800 /* If owner/mode "wrong", do- * not change */-#define F_OPT 0x00001000 /* existence optional */-#define F_RMD160 0x00002000 /* RIPEMD160 digest */-#define F_SHA1 0x00004000 /* SHA-1 digest */-#define F_SIZE 0x00008000 /* size */-#define F_SLINK 0x00010000 /* symbolic link */-#define F_TAGS 0x00020000 /* tags */-#define F_TIME 0x00040000 /* modification time */-#define F_TYPE 0x00080000 /* file type */-#define F_UID 0x00100000 /* uid */-#define F_UNAME 0x00200000 /* user name */-#define F_VISIT 0x00400000 /* file visited */-#define F_SHA256 0x00800000 /* SHA-256 digest */-#define F_SHA384 0x01000000 /* SHA-384 digest */-#define F_SHA512 0x02000000 /* SHA-512 digest */-#define F_INO 0x04000000 /* inode number */-#define F_RESDEV 0x08000000 /* device ID on which the- * entry resides */-- /* Options */- int dironly; /* If it is set, ignore all files except- * directory files, like mtree(8) -d option. */- int indent; /* If it is set, indent output data. */- int output_global_set; /* If it is set, use /set keyword to set- * global values. When generating mtree- * classic format, it is set by default. */-};--#define DEFAULT_KEYS (F_DEV | F_FLAGS | F_GID | F_GNAME | F_SLINK | F_MODE\- | F_NLINK | F_SIZE | F_TIME | F_TYPE | F_UID\- | F_UNAME)-#define attr_counter_set_reset attr_counter_set_free--static void attr_counter_free(struct attr_counter **);-static int attr_counter_inc(struct attr_counter **, struct attr_counter *,- struct attr_counter *, struct mtree_entry *);-static struct attr_counter * attr_counter_new(struct mtree_entry *,- struct attr_counter *);-static int attr_counter_set_collect(struct mtree_writer *,- struct mtree_entry *);-static void attr_counter_set_free(struct mtree_writer *);-static int get_global_set_keys(struct mtree_writer *, struct mtree_entry *);-static int mtree_entry_add_child_tail(struct mtree_entry *,- struct mtree_entry *);-static int mtree_entry_create_virtual_dir(struct archive_write *, const char *,- struct mtree_entry **);-static int mtree_entry_cmp_node(const struct archive_rb_node *,- const struct archive_rb_node *);-static int mtree_entry_cmp_key(const struct archive_rb_node *, const void *);-static int mtree_entry_exchange_same_entry(struct archive_write *,- struct mtree_entry *, struct mtree_entry *);-static void mtree_entry_free(struct mtree_entry *);-static int mtree_entry_new(struct archive_write *, struct archive_entry *,- struct mtree_entry **);-static void mtree_entry_register_free(struct mtree_writer *);-static void mtree_entry_register_init(struct mtree_writer *);-static int mtree_entry_setup_filenames(struct archive_write *,- struct mtree_entry *, struct archive_entry *);-static int mtree_entry_tree_add(struct archive_write *, struct mtree_entry **);-static void sum_init(struct mtree_writer *);-static void sum_update(struct mtree_writer *, const void *, size_t);-static void sum_final(struct mtree_writer *, struct reg_info *);-static void sum_write(struct archive_string *, struct reg_info *);-static int write_mtree_entry(struct archive_write *, struct mtree_entry *);-static int write_dot_dot_entry(struct archive_write *, struct mtree_entry *);--#define COMPUTE_CRC(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]-static const uint32_t crctab[] = {- 0x0,- 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,- 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,- 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,- 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,- 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,- 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,- 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,- 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,- 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,- 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,- 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,- 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,- 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,- 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,- 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,- 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,- 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,- 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,- 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,- 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,- 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,- 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,- 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,- 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,- 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,- 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,- 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,- 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,- 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,- 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,- 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,- 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,- 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,- 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,- 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,- 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,- 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,- 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,- 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,- 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,- 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,- 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,- 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,- 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,- 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,- 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,- 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,- 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,- 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,- 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,- 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4-};--static const unsigned char safe_char[256] = {- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */- /* !"$%&'()*+,-./ EXCLUSION:0x20( ) 0x23(#) */- 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */- /* 0123456789:;<>? EXCLUSION:0x3d(=) */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */- /* @ABCDEFGHIJKLMNO */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */- /* PQRSTUVWXYZ[]^_ EXCLUSION:0x5c(\) */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 50 - 5F */- /* `abcdefghijklmno */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */- /* pqrstuvwxyz{|}~ */- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */-};--static void-mtree_quote(struct archive_string *s, const char *str)-{- const char *start;- char buf[4];- unsigned char c;-- for (start = str; *str != '\0'; ++str) {- if (safe_char[*(const unsigned char *)str])- continue;- if (start != str)- archive_strncat(s, start, str - start);- c = (unsigned char)*str;- buf[0] = '\\';- buf[1] = (c / 64) + '0';- buf[2] = (c / 8 % 8) + '0';- buf[3] = (c % 8) + '0';- archive_strncat(s, buf, 4);- start = str + 1;- }-- if (start != str)- archive_strncat(s, start, str - start);-}--/*- * Indent a line as the mtree utility does so it is readable for people.- */-static void-mtree_indent(struct mtree_writer *mtree)-{- int i, fn, nd, pd;- const char *r, *s, *x;-- if (mtree->classic) {- if (mtree->indent) {- nd = 0;- pd = mtree->depth * 4;- } else {- nd = mtree->depth?4:0;- pd = 0;- }- } else- nd = pd = 0;- fn = 1;- s = r = mtree->ebuf.s;- x = NULL;- while (*r == ' ')- r++;- while ((r = strchr(r, ' ')) != NULL) {- if (fn) {- fn = 0;- for (i = 0; i < nd + pd; i++)- archive_strappend_char(&mtree->buf, ' ');- archive_strncat(&mtree->buf, s, r - s);- if (nd + (r -s) > INDENTNAMELEN) {- archive_strncat(&mtree->buf, " \\\n", 3);- for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)- archive_strappend_char(&mtree->buf, ' ');- } else {- for (i = (int)(r -s + nd);- i < (INDENTNAMELEN + 1); i++)- archive_strappend_char(&mtree->buf, ' ');- }- s = ++r;- x = NULL;- continue;- }- if (pd + (r - s) <= MAXLINELEN - 3 - INDENTNAMELEN)- x = r++;- else {- if (x == NULL)- x = r;- archive_strncat(&mtree->buf, s, x - s);- archive_strncat(&mtree->buf, " \\\n", 3);- for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)- archive_strappend_char(&mtree->buf, ' ');- s = r = ++x;- x = NULL;- }- }- if (fn) {- for (i = 0; i < nd + pd; i++)- archive_strappend_char(&mtree->buf, ' ');- archive_strcat(&mtree->buf, s);- s += strlen(s);- }- if (x != NULL && pd + strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) {- /* Last keyword is longer. */- archive_strncat(&mtree->buf, s, x - s);- archive_strncat(&mtree->buf, " \\\n", 3);- for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)- archive_strappend_char(&mtree->buf, ' ');- s = ++x;- }- archive_strcat(&mtree->buf, s);- archive_string_empty(&mtree->ebuf);-}--/*- * Write /set keyword.- * Set the most used value of uid, gid, mode and fflags, which are- * collected by the attr_counter_set_collect() function.- */-static void-write_global(struct mtree_writer *mtree)-{- struct archive_string setstr;- struct archive_string unsetstr;- struct att_counter_set *acs;- int keys, oldkeys, effkeys;-- archive_string_init(&setstr);- archive_string_init(&unsetstr);- keys = mtree->keys & SET_KEYS;- oldkeys = mtree->set.keys;- effkeys = keys;- acs = &mtree->acs;- if (mtree->set.processing) {- /*- * Check if the global data needs updating.- */- effkeys &= ~F_TYPE;- if (acs->uid_list == NULL)- effkeys &= ~(F_UNAME | F_UID);- else if (oldkeys & (F_UNAME | F_UID)) {- if (acs->uid_list->count < 2 ||- mtree->set.uid == acs->uid_list->m_entry->uid)- effkeys &= ~(F_UNAME | F_UID);- }- if (acs->gid_list == NULL)- effkeys &= ~(F_GNAME | F_GID);- else if (oldkeys & (F_GNAME | F_GID)) {- if (acs->gid_list->count < 2 ||- mtree->set.gid == acs->gid_list->m_entry->gid)- effkeys &= ~(F_GNAME | F_GID);- }- if (acs->mode_list == NULL)- effkeys &= ~F_MODE;- else if (oldkeys & F_MODE) {- if (acs->mode_list->count < 2 ||- mtree->set.mode == acs->mode_list->m_entry->mode)- effkeys &= ~F_MODE;- }- if (acs->flags_list == NULL)- effkeys &= ~F_FLAGS;- else if ((oldkeys & F_FLAGS) != 0) {- if (acs->flags_list->count < 2 ||- (acs->flags_list->m_entry->fflags_set ==- mtree->set.fflags_set &&- acs->flags_list->m_entry->fflags_clear ==- mtree->set.fflags_clear))- effkeys &= ~F_FLAGS;- }- } else {- if (acs->uid_list == NULL)- keys &= ~(F_UNAME | F_UID);- if (acs->gid_list == NULL)- keys &= ~(F_GNAME | F_GID);- if (acs->mode_list == NULL)- keys &= ~F_MODE;- if (acs->flags_list == NULL)- keys &= ~F_FLAGS;- }- if ((keys & effkeys & F_TYPE) != 0) {- if (mtree->dironly) {- archive_strcat(&setstr, " type=dir");- mtree->set.type = AE_IFDIR;- } else {- archive_strcat(&setstr, " type=file");- mtree->set.type = AE_IFREG;- }- }- if ((keys & effkeys & F_UNAME) != 0) {- if (archive_strlen(&(acs->uid_list->m_entry->uname)) > 0) {- archive_strcat(&setstr, " uname=");- mtree_quote(&setstr, acs->uid_list->m_entry->uname.s);- } else {- keys &= ~F_UNAME;- if ((oldkeys & F_UNAME) != 0)- archive_strcat(&unsetstr, " uname");- }- }- if ((keys & effkeys & F_UID) != 0) {- mtree->set.uid = acs->uid_list->m_entry->uid;- archive_string_sprintf(&setstr, " uid=%jd",- (intmax_t)mtree->set.uid);- }- if ((keys & effkeys & F_GNAME) != 0) {- if (archive_strlen(&(acs->gid_list->m_entry->gname)) > 0) {- archive_strcat(&setstr, " gname=");- mtree_quote(&setstr, acs->gid_list->m_entry->gname.s);- } else {- keys &= ~F_GNAME;- if ((oldkeys & F_GNAME) != 0)- archive_strcat(&unsetstr, " gname");- }- }- if ((keys & effkeys & F_GID) != 0) {- mtree->set.gid = acs->gid_list->m_entry->gid;- archive_string_sprintf(&setstr, " gid=%jd",- (intmax_t)mtree->set.gid);- }- if ((keys & effkeys & F_MODE) != 0) {- mtree->set.mode = acs->mode_list->m_entry->mode;- archive_string_sprintf(&setstr, " mode=%o",- (unsigned int)mtree->set.mode);- }- if ((keys & effkeys & F_FLAGS) != 0) {- if (archive_strlen(- &(acs->flags_list->m_entry->fflags_text)) > 0) {- archive_strcat(&setstr, " flags=");- mtree_quote(&setstr,- acs->flags_list->m_entry->fflags_text.s);- mtree->set.fflags_set =- acs->flags_list->m_entry->fflags_set;- mtree->set.fflags_clear =- acs->flags_list->m_entry->fflags_clear;- } else {- keys &= ~F_FLAGS;- if ((oldkeys & F_FLAGS) != 0)- archive_strcat(&unsetstr, " flags");- }- }- if (unsetstr.length > 0)- archive_string_sprintf(&mtree->buf, "/unset%s\n", unsetstr.s);- archive_string_free(&unsetstr);- if (setstr.length > 0)- archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s);- archive_string_free(&setstr);- mtree->set.keys = keys;- mtree->set.processing = 1;-}--static struct attr_counter *-attr_counter_new(struct mtree_entry *me, struct attr_counter *prev)-{- struct attr_counter *ac;-- ac = malloc(sizeof(*ac));- if (ac != NULL) {- ac->prev = prev;- ac->next = NULL;- ac->count = 1;- ac->m_entry = me;- }- return (ac);-}--static void-attr_counter_free(struct attr_counter **top)-{- struct attr_counter *ac, *tac;-- if (*top == NULL)- return;- ac = *top;- while (ac != NULL) {- tac = ac->next;- free(ac);- ac = tac;- }- *top = NULL;-}--static int-attr_counter_inc(struct attr_counter **top, struct attr_counter *ac,- struct attr_counter *last, struct mtree_entry *me)-{- struct attr_counter *pac;-- if (ac != NULL) {- ac->count++;- if (*top == ac || ac->prev->count >= ac->count)- return (0);- for (pac = ac->prev; pac; pac = pac->prev) {- if (pac->count >= ac->count)- break;- }- ac->prev->next = ac->next;- if (ac->next != NULL)- ac->next->prev = ac->prev;- if (pac != NULL) {- ac->prev = pac;- ac->next = pac->next;- pac->next = ac;- if (ac->next != NULL)- ac->next->prev = ac;- } else {- ac->prev = NULL;- ac->next = *top;- *top = ac;- ac->next->prev = ac;- }- } else if (last != NULL) {- ac = attr_counter_new(me, last);- if (ac == NULL)- return (-1);- last->next = ac;- }- return (0);-}--/*- * Tabulate uid, gid, mode and fflags of a entry in order to be used for /set.- */-static int-attr_counter_set_collect(struct mtree_writer *mtree, struct mtree_entry *me)-{- struct attr_counter *ac, *last;- struct att_counter_set *acs = &mtree->acs;- int keys = mtree->keys;-- if (keys & (F_UNAME | F_UID)) {- if (acs->uid_list == NULL) {- acs->uid_list = attr_counter_new(me, NULL);- if (acs->uid_list == NULL)- return (-1);- } else {- last = NULL;- for (ac = acs->uid_list; ac; ac = ac->next) {- if (ac->m_entry->uid == me->uid)- break;- last = ac;- }- if (attr_counter_inc(&acs->uid_list, ac, last, me) < 0)- return (-1);- }- }- if (keys & (F_GNAME | F_GID)) {- if (acs->gid_list == NULL) {- acs->gid_list = attr_counter_new(me, NULL);- if (acs->gid_list == NULL)- return (-1);- } else {- last = NULL;- for (ac = acs->gid_list; ac; ac = ac->next) {- if (ac->m_entry->gid == me->gid)- break;- last = ac;- }- if (attr_counter_inc(&acs->gid_list, ac, last, me) < 0)- return (-1);- }- }- if (keys & F_MODE) {- if (acs->mode_list == NULL) {- acs->mode_list = attr_counter_new(me, NULL);- if (acs->mode_list == NULL)- return (-1);- } else {- last = NULL;- for (ac = acs->mode_list; ac; ac = ac->next) {- if (ac->m_entry->mode == me->mode)- break;- last = ac;- }- if (attr_counter_inc(&acs->mode_list, ac, last, me) < 0)- return (-1);- }- }- if (keys & F_FLAGS) {- if (acs->flags_list == NULL) {- acs->flags_list = attr_counter_new(me, NULL);- if (acs->flags_list == NULL)- return (-1);- } else {- last = NULL;- for (ac = acs->flags_list; ac; ac = ac->next) {- if (ac->m_entry->fflags_set == me->fflags_set &&- ac->m_entry->fflags_clear ==- me->fflags_clear)- break;- last = ac;- }- if (attr_counter_inc(&acs->flags_list, ac, last, me) < 0)- return (-1);- }- }-- return (0);-}--static void-attr_counter_set_free(struct mtree_writer *mtree)-{- struct att_counter_set *acs = &mtree->acs;-- attr_counter_free(&acs->uid_list);- attr_counter_free(&acs->gid_list);- attr_counter_free(&acs->mode_list);- attr_counter_free(&acs->flags_list);-}--static int-get_global_set_keys(struct mtree_writer *mtree, struct mtree_entry *me)-{- int keys;-- keys = mtree->keys;-- /*- * If a keyword has been set by /set, we do not need to- * output it.- */- if (mtree->set.keys == 0)- return (keys);/* /set is not used. */-- if ((mtree->set.keys & (F_GNAME | F_GID)) != 0 &&- mtree->set.gid == me->gid)- keys &= ~(F_GNAME | F_GID);- if ((mtree->set.keys & (F_UNAME | F_UID)) != 0 &&- mtree->set.uid == me->uid)- keys &= ~(F_UNAME | F_UID);- if (mtree->set.keys & F_FLAGS) {- if (mtree->set.fflags_set == me->fflags_set &&- mtree->set.fflags_clear == me->fflags_clear)- keys &= ~F_FLAGS;- }- if ((mtree->set.keys & F_MODE) != 0 && mtree->set.mode == me->mode)- keys &= ~F_MODE;-- switch (me->filetype) {- case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:- case AE_IFBLK: case AE_IFIFO:- break;- case AE_IFDIR:- if ((mtree->set.keys & F_TYPE) != 0 &&- mtree->set.type == AE_IFDIR)- keys &= ~F_TYPE;- break;- case AE_IFREG:- default: /* Handle unknown file types as regular files. */- if ((mtree->set.keys & F_TYPE) != 0 &&- mtree->set.type == AE_IFREG)- keys &= ~F_TYPE;- break;- }-- return (keys);-}--static int-mtree_entry_new(struct archive_write *a, struct archive_entry *entry,- struct mtree_entry **m_entry)-{- struct mtree_entry *me;- const char *s;- int r;- static const struct archive_rb_tree_ops rb_ops = {- mtree_entry_cmp_node, mtree_entry_cmp_key- };-- me = calloc(1, sizeof(*me));- if (me == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for a mtree entry");- *m_entry = NULL;- return (ARCHIVE_FATAL);- }-- r = mtree_entry_setup_filenames(a, me, entry);- if (r < ARCHIVE_WARN) {- mtree_entry_free(me);- *m_entry = NULL;- return (r);- }-- if ((s = archive_entry_symlink(entry)) != NULL)- archive_strcpy(&me->symlink, s);- me->nlink = archive_entry_nlink(entry);- me->filetype = archive_entry_filetype(entry);- me->mode = archive_entry_mode(entry) & 07777;- me->uid = archive_entry_uid(entry);- me->gid = archive_entry_gid(entry);- if ((s = archive_entry_uname(entry)) != NULL)- archive_strcpy(&me->uname, s);- if ((s = archive_entry_gname(entry)) != NULL)- archive_strcpy(&me->gname, s);- if ((s = archive_entry_fflags_text(entry)) != NULL)- archive_strcpy(&me->fflags_text, s);- archive_entry_fflags(entry, &me->fflags_set, &me->fflags_clear);- me->mtime = archive_entry_mtime(entry);- me->mtime_nsec = archive_entry_mtime_nsec(entry);- me->rdevmajor = archive_entry_rdevmajor(entry);- me->rdevminor = archive_entry_rdevminor(entry);- me->devmajor = archive_entry_devmajor(entry);- me->devminor = archive_entry_devminor(entry);- me->ino = archive_entry_ino(entry);- me->size = archive_entry_size(entry);- if (me->filetype == AE_IFDIR) {- me->dir_info = calloc(1, sizeof(*me->dir_info));- if (me->dir_info == NULL) {- mtree_entry_free(me);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for a mtree entry");- *m_entry = NULL;- return (ARCHIVE_FATAL);- }- __archive_rb_tree_init(&me->dir_info->rbtree, &rb_ops);- me->dir_info->children.first = NULL;- me->dir_info->children.last = &(me->dir_info->children.first);- me->dir_info->chnext = NULL;- } else if (me->filetype == AE_IFREG) {- me->reg_info = calloc(1, sizeof(*me->reg_info));- if (me->reg_info == NULL) {- mtree_entry_free(me);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for a mtree entry");- *m_entry = NULL;- return (ARCHIVE_FATAL);- }- me->reg_info->compute_sum = 0;- }-- *m_entry = me;- return (ARCHIVE_OK);-}--static void-mtree_entry_free(struct mtree_entry *me)-{- archive_string_free(&me->parentdir);- archive_string_free(&me->basename);- archive_string_free(&me->pathname);- archive_string_free(&me->symlink);- archive_string_free(&me->uname);- archive_string_free(&me->gname);- archive_string_free(&me->fflags_text);- free(me->dir_info);- free(me->reg_info);- free(me);-}--static int-archive_write_mtree_header(struct archive_write *a,- struct archive_entry *entry)-{- struct mtree_writer *mtree= a->format_data;- struct mtree_entry *mtree_entry;- int r, r2;-- if (mtree->first) {- mtree->first = 0;- archive_strcat(&mtree->buf, "#mtree\n");- if ((mtree->keys & SET_KEYS) == 0)- mtree->output_global_set = 0;/* Disabled. */- }-- mtree->entry_bytes_remaining = archive_entry_size(entry);-- /* While directory only mode, we do not handle non directory files. */- if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR)- return (ARCHIVE_OK);-- r2 = mtree_entry_new(a, entry, &mtree_entry);- if (r2 < ARCHIVE_WARN)- return (r2);- r = mtree_entry_tree_add(a, &mtree_entry);- if (r < ARCHIVE_WARN) {- mtree_entry_free(mtree_entry);- return (r);- }- mtree->mtree_entry = mtree_entry;-- /* If the current file is a regular file, we have to- * compute the sum of its content.- * Initialize a bunch of checksum context. */- if (mtree_entry->reg_info)- sum_init(mtree);-- return (r2);-}--static int-write_mtree_entry(struct archive_write *a, struct mtree_entry *me)-{- struct mtree_writer *mtree = a->format_data;- struct archive_string *str;- int keys, ret;-- if (me->dir_info) {- if (mtree->classic) {- /*- * Output a comment line to describe the full- * pathname of the entry as mtree utility does- * while generating classic format.- */- if (!mtree->dironly)- archive_strappend_char(&mtree->buf, '\n');- if (me->parentdir.s)- archive_string_sprintf(&mtree->buf,- "# %s/%s\n",- me->parentdir.s, me->basename.s);- else- archive_string_sprintf(&mtree->buf,- "# %s\n",- me->basename.s);- }- if (mtree->output_global_set)- write_global(mtree);- }- archive_string_empty(&mtree->ebuf);- str = (mtree->indent || mtree->classic)? &mtree->ebuf : &mtree->buf;-- if (!mtree->classic && me->parentdir.s) {- /*- * If generating format is not classic one(v1), output- * a full pathname.- */- mtree_quote(str, me->parentdir.s);- archive_strappend_char(str, '/');- }- mtree_quote(str, me->basename.s);-- keys = get_global_set_keys(mtree, me);- if ((keys & F_NLINK) != 0 &&- me->nlink != 1 && me->filetype != AE_IFDIR)- archive_string_sprintf(str, " nlink=%u", me->nlink);-- if ((keys & F_GNAME) != 0 && archive_strlen(&me->gname) > 0) {- archive_strcat(str, " gname=");- mtree_quote(str, me->gname.s);- }- if ((keys & F_UNAME) != 0 && archive_strlen(&me->uname) > 0) {- archive_strcat(str, " uname=");- mtree_quote(str, me->uname.s);- }- if ((keys & F_FLAGS) != 0) {- if (archive_strlen(&me->fflags_text) > 0) {- archive_strcat(str, " flags=");- mtree_quote(str, me->fflags_text.s);- } else if (mtree->set.processing &&- (mtree->set.keys & F_FLAGS) != 0)- /* Overwrite the global parameter. */- archive_strcat(str, " flags=none");- }- if ((keys & F_TIME) != 0)- archive_string_sprintf(str, " time=%jd.%jd",- (intmax_t)me->mtime, (intmax_t)me->mtime_nsec);- if ((keys & F_MODE) != 0)- archive_string_sprintf(str, " mode=%o", (unsigned int)me->mode);- if ((keys & F_GID) != 0)- archive_string_sprintf(str, " gid=%jd", (intmax_t)me->gid);- if ((keys & F_UID) != 0)- archive_string_sprintf(str, " uid=%jd", (intmax_t)me->uid);-- if ((keys & F_INO) != 0)- archive_string_sprintf(str, " inode=%jd", (intmax_t)me->ino);- if ((keys & F_RESDEV) != 0) {- archive_string_sprintf(str,- " resdevice=native,%ju,%ju",- (uintmax_t)me->devmajor,- (uintmax_t)me->devminor);- }-- switch (me->filetype) {- case AE_IFLNK:- if ((keys & F_TYPE) != 0)- archive_strcat(str, " type=link");- if ((keys & F_SLINK) != 0) {- archive_strcat(str, " link=");- mtree_quote(str, me->symlink.s);- }- break;- case AE_IFSOCK:- if ((keys & F_TYPE) != 0)- archive_strcat(str, " type=socket");- break;- case AE_IFCHR:- if ((keys & F_TYPE) != 0)- archive_strcat(str, " type=char");- if ((keys & F_DEV) != 0) {- archive_string_sprintf(str,- " device=native,%ju,%ju",- (uintmax_t)me->rdevmajor,- (uintmax_t)me->rdevminor);- }- break;- case AE_IFBLK:- if ((keys & F_TYPE) != 0)- archive_strcat(str, " type=block");- if ((keys & F_DEV) != 0) {- archive_string_sprintf(str,- " device=native,%ju,%ju",- (uintmax_t)me->rdevmajor,- (uintmax_t)me->rdevminor);- }- break;- case AE_IFDIR:- if ((keys & F_TYPE) != 0)- archive_strcat(str, " type=dir");- break;- case AE_IFIFO:- if ((keys & F_TYPE) != 0)- archive_strcat(str, " type=fifo");- break;- case AE_IFREG:- default: /* Handle unknown file types as regular files. */- if ((keys & F_TYPE) != 0)- archive_strcat(str, " type=file");- if ((keys & F_SIZE) != 0)- archive_string_sprintf(str, " size=%jd",- (intmax_t)me->size);- break;- }-- /* Write a bunch of sum. */- if (me->reg_info)- sum_write(str, me->reg_info);-- archive_strappend_char(str, '\n');- if (mtree->indent || mtree->classic)- mtree_indent(mtree);-- if (mtree->buf.length > 32768) {- ret = __archive_write_output(- a, mtree->buf.s, mtree->buf.length);- archive_string_empty(&mtree->buf);- } else- ret = ARCHIVE_OK;- return (ret);-}--static int-write_dot_dot_entry(struct archive_write *a, struct mtree_entry *n)-{- struct mtree_writer *mtree = a->format_data;- int ret;-- if (n->parentdir.s) {- if (mtree->indent) {- int i, pd = mtree->depth * 4;- for (i = 0; i < pd; i++)- archive_strappend_char(&mtree->buf, ' ');- }- archive_string_sprintf(&mtree->buf, "# %s/%s\n",- n->parentdir.s, n->basename.s);- }-- if (mtree->indent) {- archive_string_empty(&mtree->ebuf);- archive_strncat(&mtree->ebuf, "..\n\n", (mtree->dironly)?3:4);- mtree_indent(mtree);- } else- archive_strncat(&mtree->buf, "..\n\n", (mtree->dironly)?3:4);-- if (mtree->buf.length > 32768) {- ret = __archive_write_output(- a, mtree->buf.s, mtree->buf.length);- archive_string_empty(&mtree->buf);- } else- ret = ARCHIVE_OK;- return (ret);-}--/*- * Write mtree entries saved at attr_counter_set_collect() function.- */-static int-write_mtree_entry_tree(struct archive_write *a)-{- struct mtree_writer *mtree = a->format_data;- struct mtree_entry *np = mtree->root;- struct archive_rb_node *n;- int ret;-- do {- if (mtree->output_global_set) {- /*- * Collect attribute information to know which value- * is frequently used among the children.- */- attr_counter_set_reset(mtree);- ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) {- struct mtree_entry *e = (struct mtree_entry *)n;- if (attr_counter_set_collect(mtree, e) < 0) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- }- }- if (!np->dir_info->virtual || mtree->classic) {- ret = write_mtree_entry(a, np);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- } else {- /* Whenever output_global_set is enabled- * output global value(/set keywords)- * even if the directory entry is not allowed- * to be written because the global values- * can be used for the children. */- if (mtree->output_global_set)- write_global(mtree);- }- /*- * Output the attribute of all files except directory files.- */- mtree->depth++;- ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) {- struct mtree_entry *e = (struct mtree_entry *)n;-- if (e->dir_info)- mtree_entry_add_child_tail(np, e);- else {- ret = write_mtree_entry(a, e);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }- }- mtree->depth--;-- if (np->dir_info->children.first != NULL) {- /*- * Descend the tree.- */- np = np->dir_info->children.first;- if (mtree->indent)- mtree->depth++;- continue;- } else if (mtree->classic) {- /*- * While printing mtree classic, if there are not- * any directory files(except "." and "..") in the- * directory, output two dots ".." as returning- * the parent directory.- */- ret = write_dot_dot_entry(a, np);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- while (np != np->parent) {- if (np->dir_info->chnext == NULL) {- /*- * Ascend the tree; go back to the parent.- */- if (mtree->indent)- mtree->depth--;- if (mtree->classic) {- ret = write_dot_dot_entry(a,- np->parent);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }- np = np->parent;- } else {- /*- * Switch to next mtree entry in the directory.- */- np = np->dir_info->chnext;- break;- }- }- } while (np != np->parent); -- return (ARCHIVE_OK);-}--static int-archive_write_mtree_finish_entry(struct archive_write *a)-{- struct mtree_writer *mtree = a->format_data;- struct mtree_entry *me;-- if ((me = mtree->mtree_entry) == NULL)- return (ARCHIVE_OK);- mtree->mtree_entry = NULL;-- if (me->reg_info)- sum_final(mtree, me->reg_info);-- return (ARCHIVE_OK);-}--static int-archive_write_mtree_close(struct archive_write *a)-{- struct mtree_writer *mtree= a->format_data;- int ret;-- if (mtree->root != NULL) {- ret = write_mtree_entry_tree(a);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- archive_write_set_bytes_in_last_block(&a->archive, 1);-- return __archive_write_output(a, mtree->buf.s, mtree->buf.length);-}--static ssize_t-archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)-{- struct mtree_writer *mtree= a->format_data;-- if (n > mtree->entry_bytes_remaining)- n = (size_t)mtree->entry_bytes_remaining;- mtree->entry_bytes_remaining -= n;-- /* We don't need to compute a regular file sum */- if (mtree->mtree_entry == NULL)- return (n);-- if (mtree->mtree_entry->filetype == AE_IFREG)- sum_update(mtree, buff, n);-- return (n);-}--static int-archive_write_mtree_free(struct archive_write *a)-{- struct mtree_writer *mtree= a->format_data;-- if (mtree == NULL)- return (ARCHIVE_OK);-- /* Make sure we do not leave any entries. */- mtree_entry_register_free(mtree);- archive_string_free(&mtree->cur_dirstr);- archive_string_free(&mtree->ebuf);- archive_string_free(&mtree->buf);- attr_counter_set_free(mtree);- free(mtree);- a->format_data = NULL;- return (ARCHIVE_OK);-}--static int-archive_write_mtree_options(struct archive_write *a, const char *key,- const char *value)-{- struct mtree_writer *mtree= a->format_data;- int keybit = 0;-- switch (key[0]) {- case 'a':- if (strcmp(key, "all") == 0)- keybit = ~0;- break;- case 'c':- if (strcmp(key, "cksum") == 0)- keybit = F_CKSUM;- break;- case 'd':- if (strcmp(key, "device") == 0)- keybit = F_DEV;- else if (strcmp(key, "dironly") == 0) {- mtree->dironly = (value != NULL)? 1: 0;- return (ARCHIVE_OK);- }- break;- case 'f':- if (strcmp(key, "flags") == 0)- keybit = F_FLAGS;- break;- case 'g':- if (strcmp(key, "gid") == 0)- keybit = F_GID;- else if (strcmp(key, "gname") == 0)- keybit = F_GNAME;- break;- case 'i':- if (strcmp(key, "indent") == 0) {- mtree->indent = (value != NULL)? 1: 0;- return (ARCHIVE_OK);- } else if (strcmp(key, "inode") == 0) {- keybit = F_INO;- }- break;- case 'l':- if (strcmp(key, "link") == 0)- keybit = F_SLINK;- break;- case 'm':- if (strcmp(key, "md5") == 0 ||- strcmp(key, "md5digest") == 0)- keybit = F_MD5;- if (strcmp(key, "mode") == 0)- keybit = F_MODE;- break;- case 'n':- if (strcmp(key, "nlink") == 0)- keybit = F_NLINK;- break;- case 'r':- if (strcmp(key, "resdevice") == 0) {- keybit = F_RESDEV;- } else if (strcmp(key, "ripemd160digest") == 0 ||- strcmp(key, "rmd160") == 0 ||- strcmp(key, "rmd160digest") == 0)- keybit = F_RMD160;- break;- case 's':- if (strcmp(key, "sha1") == 0 ||- strcmp(key, "sha1digest") == 0)- keybit = F_SHA1;- if (strcmp(key, "sha256") == 0 ||- strcmp(key, "sha256digest") == 0)- keybit = F_SHA256;- if (strcmp(key, "sha384") == 0 ||- strcmp(key, "sha384digest") == 0)- keybit = F_SHA384;- if (strcmp(key, "sha512") == 0 ||- strcmp(key, "sha512digest") == 0)- keybit = F_SHA512;- if (strcmp(key, "size") == 0)- keybit = F_SIZE;- break;- case 't':- if (strcmp(key, "time") == 0)- keybit = F_TIME;- else if (strcmp(key, "type") == 0)- keybit = F_TYPE;- break;- case 'u':- if (strcmp(key, "uid") == 0)- keybit = F_UID;- else if (strcmp(key, "uname") == 0)- keybit = F_UNAME;- else if (strcmp(key, "use-set") == 0) {- mtree->output_global_set = (value != NULL)? 1: 0;- return (ARCHIVE_OK);- }- break;- }- if (keybit != 0) {- if (value != NULL)- mtree->keys |= keybit;- else- mtree->keys &= ~keybit;- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-archive_write_set_format_mtree_default(struct archive *_a, const char *fn)-{- struct archive_write *a = (struct archive_write *)_a;- struct mtree_writer *mtree;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, fn);-- if (a->format_free != NULL)- (a->format_free)(a);-- if ((mtree = calloc(1, sizeof(*mtree))) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate mtree data");- return (ARCHIVE_FATAL);- }-- mtree->mtree_entry = NULL;- mtree->first = 1;- memset(&(mtree->set), 0, sizeof(mtree->set));- mtree->keys = DEFAULT_KEYS;- mtree->dironly = 0;- mtree->indent = 0;- archive_string_init(&mtree->ebuf);- archive_string_init(&mtree->buf);- mtree_entry_register_init(mtree);- a->format_data = mtree;- a->format_free = archive_write_mtree_free;- a->format_name = "mtree";- a->format_options = archive_write_mtree_options;- a->format_write_header = archive_write_mtree_header;- a->format_close = archive_write_mtree_close;- a->format_write_data = archive_write_mtree_data;- a->format_finish_entry = archive_write_mtree_finish_entry;- a->archive.archive_format = ARCHIVE_FORMAT_MTREE;- a->archive.archive_format_name = "mtree";-- return (ARCHIVE_OK);-}--int-archive_write_set_format_mtree(struct archive *_a)-{- return archive_write_set_format_mtree_default(_a,- "archive_write_set_format_mtree");-}--int-archive_write_set_format_mtree_classic(struct archive *_a)-{- int r;-- r = archive_write_set_format_mtree_default(_a,- "archive_write_set_format_mtree_classic");- if (r == ARCHIVE_OK) {- struct archive_write *a = (struct archive_write *)_a;- struct mtree_writer *mtree;-- mtree = (struct mtree_writer *)a->format_data;-- /* Set to output a mtree archive in classic format. */- mtree->classic = 1;- /* Basically, mtree classic format uses '/set' global- * value. */- mtree->output_global_set = 1;- }- return (r);-}--static void-sum_init(struct mtree_writer *mtree)-{-- mtree->compute_sum = 0;-- if (mtree->keys & F_CKSUM) {- mtree->compute_sum |= F_CKSUM;- mtree->crc = 0;- mtree->crc_len = 0;- }-#ifdef ARCHIVE_HAS_MD5- if (mtree->keys & F_MD5) {- if (archive_md5_init(&mtree->md5ctx) == ARCHIVE_OK)- mtree->compute_sum |= F_MD5;- else- mtree->keys &= ~F_MD5;/* Not supported. */- }-#endif-#ifdef ARCHIVE_HAS_RMD160- if (mtree->keys & F_RMD160) {- if (archive_rmd160_init(&mtree->rmd160ctx) == ARCHIVE_OK)- mtree->compute_sum |= F_RMD160;- else- mtree->keys &= ~F_RMD160;/* Not supported. */- }-#endif-#ifdef ARCHIVE_HAS_SHA1- if (mtree->keys & F_SHA1) {- if (archive_sha1_init(&mtree->sha1ctx) == ARCHIVE_OK)- mtree->compute_sum |= F_SHA1;- else- mtree->keys &= ~F_SHA1;/* Not supported. */- }-#endif-#ifdef ARCHIVE_HAS_SHA256- if (mtree->keys & F_SHA256) {- if (archive_sha256_init(&mtree->sha256ctx) == ARCHIVE_OK)- mtree->compute_sum |= F_SHA256;- else- mtree->keys &= ~F_SHA256;/* Not supported. */- }-#endif-#ifdef ARCHIVE_HAS_SHA384- if (mtree->keys & F_SHA384) {- if (archive_sha384_init(&mtree->sha384ctx) == ARCHIVE_OK)- mtree->compute_sum |= F_SHA384;- else- mtree->keys &= ~F_SHA384;/* Not supported. */- }-#endif-#ifdef ARCHIVE_HAS_SHA512- if (mtree->keys & F_SHA512) {- if (archive_sha512_init(&mtree->sha512ctx) == ARCHIVE_OK)- mtree->compute_sum |= F_SHA512;- else- mtree->keys &= ~F_SHA512;/* Not supported. */- }-#endif-}--static void-sum_update(struct mtree_writer *mtree, const void *buff, size_t n)-{- if (mtree->compute_sum & F_CKSUM) {- /*- * Compute a POSIX 1003.2 checksum- */- const unsigned char *p;- size_t nn;-- for (nn = n, p = buff; nn--; ++p)- COMPUTE_CRC(mtree->crc, *p);- mtree->crc_len += n;- }-#ifdef ARCHIVE_HAS_MD5- if (mtree->compute_sum & F_MD5)- archive_md5_update(&mtree->md5ctx, buff, n);-#endif-#ifdef ARCHIVE_HAS_RMD160- if (mtree->compute_sum & F_RMD160)- archive_rmd160_update(&mtree->rmd160ctx, buff, n);-#endif-#ifdef ARCHIVE_HAS_SHA1- if (mtree->compute_sum & F_SHA1)- archive_sha1_update(&mtree->sha1ctx, buff, n);-#endif-#ifdef ARCHIVE_HAS_SHA256- if (mtree->compute_sum & F_SHA256)- archive_sha256_update(&mtree->sha256ctx, buff, n);-#endif-#ifdef ARCHIVE_HAS_SHA384- if (mtree->compute_sum & F_SHA384)- archive_sha384_update(&mtree->sha384ctx, buff, n);-#endif-#ifdef ARCHIVE_HAS_SHA512- if (mtree->compute_sum & F_SHA512)- archive_sha512_update(&mtree->sha512ctx, buff, n);-#endif-}--static void-sum_final(struct mtree_writer *mtree, struct reg_info *reg)-{-- if (mtree->compute_sum & F_CKSUM) {- uint64_t len;- /* Include the length of the file. */- for (len = mtree->crc_len; len != 0; len >>= 8)- COMPUTE_CRC(mtree->crc, len & 0xff);- reg->crc = ~mtree->crc;- }-#ifdef ARCHIVE_HAS_MD5- if (mtree->compute_sum & F_MD5)- archive_md5_final(&mtree->md5ctx, reg->digest.md5);-#endif-#ifdef ARCHIVE_HAS_RMD160- if (mtree->compute_sum & F_RMD160)- archive_rmd160_final(&mtree->rmd160ctx, reg->digest.rmd160);-#endif-#ifdef ARCHIVE_HAS_SHA1- if (mtree->compute_sum & F_SHA1)- archive_sha1_final(&mtree->sha1ctx, reg->digest.sha1);-#endif-#ifdef ARCHIVE_HAS_SHA256- if (mtree->compute_sum & F_SHA256)- archive_sha256_final(&mtree->sha256ctx, reg->digest.sha256);-#endif-#ifdef ARCHIVE_HAS_SHA384- if (mtree->compute_sum & F_SHA384)- archive_sha384_final(&mtree->sha384ctx, reg->digest.sha384);-#endif-#ifdef ARCHIVE_HAS_SHA512- if (mtree->compute_sum & F_SHA512)- archive_sha512_final(&mtree->sha512ctx, reg->digest.sha512);-#endif- /* Save what types of sum are computed. */- reg->compute_sum = mtree->compute_sum;-}--#if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \- defined(ARCHIVE_HAS_SHA1) || defined(ARCHIVE_HAS_SHA256) || \- defined(ARCHIVE_HAS_SHA384) || defined(ARCHIVE_HAS_SHA512)-static void-strappend_bin(struct archive_string *s, const unsigned char *bin, int n)-{- static const char hex[] = "0123456789abcdef";- int i;-- for (i = 0; i < n; i++) {- archive_strappend_char(s, hex[bin[i] >> 4]);- archive_strappend_char(s, hex[bin[i] & 0x0f]);- }-}-#endif--static void-sum_write(struct archive_string *str, struct reg_info *reg)-{-- if (reg->compute_sum & F_CKSUM) {- archive_string_sprintf(str, " cksum=%ju",- (uintmax_t)reg->crc);- }--#define append_digest(_s, _r, _t) \- strappend_bin(_s, _r->digest._t, sizeof(_r->digest._t))--#ifdef ARCHIVE_HAS_MD5- if (reg->compute_sum & F_MD5) {- archive_strcat(str, " md5digest=");- append_digest(str, reg, md5);- }-#endif-#ifdef ARCHIVE_HAS_RMD160- if (reg->compute_sum & F_RMD160) {- archive_strcat(str, " rmd160digest=");- append_digest(str, reg, rmd160);- }-#endif-#ifdef ARCHIVE_HAS_SHA1- if (reg->compute_sum & F_SHA1) {- archive_strcat(str, " sha1digest=");- append_digest(str, reg, sha1);- }-#endif-#ifdef ARCHIVE_HAS_SHA256- if (reg->compute_sum & F_SHA256) {- archive_strcat(str, " sha256digest=");- append_digest(str, reg, sha256);- }-#endif-#ifdef ARCHIVE_HAS_SHA384- if (reg->compute_sum & F_SHA384) {- archive_strcat(str, " sha384digest=");- append_digest(str, reg, sha384);- }-#endif-#ifdef ARCHIVE_HAS_SHA512- if (reg->compute_sum & F_SHA512) {- archive_strcat(str, " sha512digest=");- append_digest(str, reg, sha512);- }-#endif-#undef append_digest-}--static int-mtree_entry_cmp_node(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- const struct mtree_entry *e1 = (const struct mtree_entry *)n1;- const struct mtree_entry *e2 = (const struct mtree_entry *)n2;-- return (strcmp(e2->basename.s, e1->basename.s));-}--static int-mtree_entry_cmp_key(const struct archive_rb_node *n, const void *key)-{- const struct mtree_entry *e = (const struct mtree_entry *)n;-- return (strcmp((const char *)key, e->basename.s));-}--#if defined(_WIN32) || defined(__CYGWIN__)-static int-cleanup_backslash_1(char *p)-{- int mb, dos;-- mb = dos = 0;- while (*p) {- if (*(unsigned char *)p > 127)- mb = 1;- if (*p == '\\') {- /* If we have not met any multi-byte characters,- * we can replace '\' with '/'. */- if (!mb)- *p = '/';- dos = 1;- }- p++;- }- if (!mb || !dos)- return (0);- return (-1);-}--static void-cleanup_backslash_2(wchar_t *p)-{-- /* Convert a path-separator from '\' to '/' */- while (*p != L'\0') {- if (*p == L'\\')- *p = L'/';- p++;- }-}-#endif--/*- * Generate a parent directory name and a base name from a pathname.- */-static int-mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file,- struct archive_entry *entry)-{- const char *pathname;- char *p, *dirname, *slash;- size_t len;- int ret = ARCHIVE_OK;-- archive_strcpy(&file->pathname, archive_entry_pathname(entry));-#if defined(_WIN32) || defined(__CYGWIN__)- /*- * Convert a path-separator from '\' to '/'- */- if (cleanup_backslash_1(file->pathname.s) != 0) {- const wchar_t *wp = archive_entry_pathname_w(entry);- struct archive_wstring ws;-- if (wp != NULL) {- int r;- archive_string_init(&ws);- archive_wstrcpy(&ws, wp);- cleanup_backslash_2(ws.s);- archive_string_empty(&(file->pathname));- r = archive_string_append_from_wcs(&(file->pathname),- ws.s, ws.length);- archive_wstring_free(&ws);- if (r < 0 && errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- }- }-#else- (void)a; /* UNUSED */-#endif- pathname = file->pathname.s;- if (strcmp(pathname, ".") == 0) {- archive_strcpy(&file->basename, ".");- return (ARCHIVE_OK);- }-- archive_strcpy(&(file->parentdir), pathname);-- len = file->parentdir.length;- p = dirname = file->parentdir.s;-- /*- * Remove leading '/' and '../' elements- */- while (*p) {- if (p[0] == '/') {- p++;- len--;- } else if (p[0] != '.')- break;- else if (p[1] == '.' && p[2] == '/') {- p += 3;- len -= 3;- } else- break;- }- if (p != dirname) {- memmove(dirname, p, len+1);- p = dirname;- }- /*- * Remove "/","/." and "/.." elements from tail.- */- while (len > 0) {- size_t ll = len;-- if (len > 0 && p[len-1] == '/') {- p[len-1] = '\0';- len--;- }- if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {- p[len-2] = '\0';- len -= 2;- }- if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&- p[len-1] == '.') {- p[len-3] = '\0';- len -= 3;- }- if (ll == len)- break;- }- while (*p) {- if (p[0] == '/') {- if (p[1] == '/')- /* Convert '//' --> '/' */- memmove(p, p+1, strlen(p+1) + 1);- else if (p[1] == '.' && p[2] == '/')- /* Convert '/./' --> '/' */- memmove(p, p+2, strlen(p+2) + 1);- else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {- /* Convert 'dir/dir1/../dir2/'- * --> 'dir/dir2/'- */- char *rp = p -1;- while (rp >= dirname) {- if (*rp == '/')- break;- --rp;- }- if (rp > dirname) {- strcpy(rp, p+3);- p = rp;- } else {- strcpy(dirname, p+4);- p = dirname;- }- } else- p++;- } else- p++;- }- p = dirname;- len = strlen(p);-- /*- * Add "./" prefix.- * NOTE: If the pathname does not have a path separator, we have- * to add "./" to the head of the pathname because mtree reader- * will suppose that it is v1(a.k.a classic) mtree format and- * change the directory unexpectedly and so it will make a wrong- * path.- */- if (strcmp(p, ".") != 0 && strncmp(p, "./", 2) != 0) {- struct archive_string as;- archive_string_init(&as);- archive_strcpy(&as, "./");- archive_strncat(&as, p, len);- archive_string_empty(&file->parentdir);- archive_string_concat(&file->parentdir, &as);- archive_string_free(&as);- p = file->parentdir.s;- len = archive_strlen(&file->parentdir);- }-- /*- * Find out the position which points the last position of- * path separator('/').- */- slash = NULL;- for (; *p != '\0'; p++) {- if (*p == '/')- slash = p;- }- if (slash == NULL) {- /* The pathname doesn't have a parent directory. */- file->parentdir.length = len;- archive_string_copy(&(file->basename), &(file->parentdir));- archive_string_empty(&(file->parentdir));- *file->parentdir.s = '\0';- return (ret);- }-- /* Make a basename from file->parentdir.s and slash */- *slash = '\0';- file->parentdir.length = slash - file->parentdir.s;- archive_strcpy(&(file->basename), slash + 1);- return (ret);-}--static int-mtree_entry_create_virtual_dir(struct archive_write *a, const char *pathname,- struct mtree_entry **m_entry)-{- struct archive_entry *entry;- struct mtree_entry *file;- int r;-- entry = archive_entry_new();- if (entry == NULL) {- *m_entry = NULL;- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- archive_entry_copy_pathname(entry, pathname);- archive_entry_set_mode(entry, AE_IFDIR | 0755);- archive_entry_set_mtime(entry, time(NULL), 0);-- r = mtree_entry_new(a, entry, &file);- archive_entry_free(entry);- if (r < ARCHIVE_WARN) {- *m_entry = NULL;- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }-- file->dir_info->virtual = 1;-- *m_entry = file;- return (ARCHIVE_OK);-}--static void-mtree_entry_register_add(struct mtree_writer *mtree, struct mtree_entry *file)-{- file->next = NULL;- *mtree->file_list.last = file;- mtree->file_list.last = &(file->next);-}--static void-mtree_entry_register_init(struct mtree_writer *mtree)-{- mtree->file_list.first = NULL;- mtree->file_list.last = &(mtree->file_list.first);-}--static void-mtree_entry_register_free(struct mtree_writer *mtree)-{- struct mtree_entry *file, *file_next;-- file = mtree->file_list.first;- while (file != NULL) {- file_next = file->next;- mtree_entry_free(file);- file = file_next;- }-}--static int-mtree_entry_add_child_tail(struct mtree_entry *parent,- struct mtree_entry *child)-{- child->dir_info->chnext = NULL;- *parent->dir_info->children.last = child;- parent->dir_info->children.last = &(child->dir_info->chnext);- return (1);-}--/*- * Find a entry from a parent entry with the name.- */-static struct mtree_entry *-mtree_entry_find_child(struct mtree_entry *parent, const char *child_name)-{- struct mtree_entry *np;-- if (parent == NULL)- return (NULL);- np = (struct mtree_entry *)__archive_rb_tree_find_node(- &(parent->dir_info->rbtree), child_name);- return (np);-}--static int-get_path_component(char *name, size_t n, const char *fn)-{- char *p;- size_t l;-- p = strchr(fn, '/');- if (p == NULL) {- if ((l = strlen(fn)) == 0)- return (0);- } else- l = p - fn;- if (l > n -1)- return (-1);- memcpy(name, fn, l);- name[l] = '\0';-- return ((int)l);-}--/*- * Add a new entry into the tree.- */-static int-mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep)-{-#if defined(_WIN32) && !defined(__CYGWIN__)- char name[_MAX_FNAME];/* Included null terminator size. */-#elif defined(NAME_MAX) && NAME_MAX >= 255- char name[NAME_MAX+1];-#else- char name[256];-#endif- struct mtree_writer *mtree = (struct mtree_writer *)a->format_data;- struct mtree_entry *dent, *file, *np;- const char *fn, *p;- int l, r;-- file = *filep;- if (file->parentdir.length == 0 && file->basename.length == 1 &&- file->basename.s[0] == '.') {- file->parent = file;- if (mtree->root != NULL) {- np = mtree->root;- goto same_entry;- }- mtree->root = file;- mtree_entry_register_add(mtree, file);- return (ARCHIVE_OK);- }-- if (file->parentdir.length == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Internal programming error "- "in generating canonical name for %s",- file->pathname.s);- return (ARCHIVE_FAILED);- }-- fn = p = file->parentdir.s;-- /*- * If the path of the parent directory of `file' entry is- * the same as the path of `cur_dirent', add `file' entry to- * `cur_dirent'.- */- if (archive_strlen(&(mtree->cur_dirstr))- == archive_strlen(&(file->parentdir)) &&- strcmp(mtree->cur_dirstr.s, fn) == 0) {- if (!__archive_rb_tree_insert_node(- &(mtree->cur_dirent->dir_info->rbtree),- (struct archive_rb_node *)file)) {- /* There is the same name in the tree. */- np = (struct mtree_entry *)__archive_rb_tree_find_node(- &(mtree->cur_dirent->dir_info->rbtree),- file->basename.s);- goto same_entry;- }- file->parent = mtree->cur_dirent;- mtree_entry_register_add(mtree, file);- return (ARCHIVE_OK);- }-- dent = mtree->root;- for (;;) {- l = get_path_component(name, sizeof(name), fn);- if (l == 0) {- np = NULL;- break;- }- if (l < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "A name buffer is too small");- return (ARCHIVE_FATAL);- }- if (l == 1 && name[0] == '.' && dent != NULL &&- dent == mtree->root) {- fn += l;- if (fn[0] == '/')- fn++;- continue;- }-- np = mtree_entry_find_child(dent, name);- if (np == NULL || fn[0] == '\0')- break;-- /* Find next sub directory. */- if (!np->dir_info) {- /* NOT Directory! */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "`%s' is not directory, we cannot insert `%s' ",- np->pathname.s, file->pathname.s);- return (ARCHIVE_FAILED);- }- fn += l;- if (fn[0] == '/')- fn++;- dent = np;- }- if (np == NULL) {- /*- * Create virtual parent directories.- */- while (fn[0] != '\0') {- struct mtree_entry *vp;- struct archive_string as;-- archive_string_init(&as);- archive_strncat(&as, p, fn - p + l);- if (as.s[as.length-1] == '/') {- as.s[as.length-1] = '\0';- as.length--;- }- r = mtree_entry_create_virtual_dir(a, as.s, &vp);- archive_string_free(&as);- if (r < ARCHIVE_WARN)- return (r);-- if (strcmp(vp->pathname.s, ".") == 0) {- vp->parent = vp;- mtree->root = vp;- } else {- __archive_rb_tree_insert_node(- &(dent->dir_info->rbtree),- (struct archive_rb_node *)vp);- vp->parent = dent;- }- mtree_entry_register_add(mtree, vp);- np = vp;-- fn += l;- if (fn[0] == '/')- fn++;- l = get_path_component(name, sizeof(name), fn);- if (l < 0) {- archive_string_free(&as);- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "A name buffer is too small");- return (ARCHIVE_FATAL);- }- dent = np;- }-- /* Found out the parent directory where `file' can be- * inserted. */- mtree->cur_dirent = dent;- archive_string_empty(&(mtree->cur_dirstr));- archive_string_ensure(&(mtree->cur_dirstr),- archive_strlen(&(dent->parentdir)) +- archive_strlen(&(dent->basename)) + 2);- if (archive_strlen(&(dent->parentdir)) +- archive_strlen(&(dent->basename)) == 0)- mtree->cur_dirstr.s[0] = 0;- else {- if (archive_strlen(&(dent->parentdir)) > 0) {- archive_string_copy(&(mtree->cur_dirstr),- &(dent->parentdir));- archive_strappend_char(- &(mtree->cur_dirstr), '/');- }- archive_string_concat(&(mtree->cur_dirstr),- &(dent->basename));- }-- if (!__archive_rb_tree_insert_node(- &(dent->dir_info->rbtree),- (struct archive_rb_node *)file)) {- np = (struct mtree_entry *)__archive_rb_tree_find_node(- &(dent->dir_info->rbtree), file->basename.s);- goto same_entry;- }- file->parent = dent;- mtree_entry_register_add(mtree, file);- return (ARCHIVE_OK);- }--same_entry:- /*- * We have already has the entry the filename of which is- * the same.- */- r = mtree_entry_exchange_same_entry(a, np, file);- if (r < ARCHIVE_WARN)- return (r);- if (np->dir_info)- np->dir_info->virtual = 0;- *filep = np;- mtree_entry_free(file);- return (ARCHIVE_WARN);-}--static int-mtree_entry_exchange_same_entry(struct archive_write *a, struct mtree_entry *np,- struct mtree_entry *file)-{-- if ((np->mode & AE_IFMT) != (file->mode & AE_IFMT)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Found duplicate entries `%s' and its file type is "- "different",- np->pathname.s);- return (ARCHIVE_FAILED);- }-- /* Update the existent mtree entry's attributes by the new one's. */- archive_string_empty(&np->symlink);- archive_string_concat(&np->symlink, &file->symlink);- archive_string_empty(&np->uname);- archive_string_concat(&np->uname, &file->uname);- archive_string_empty(&np->gname);- archive_string_concat(&np->gname, &file->gname);- archive_string_empty(&np->fflags_text);- archive_string_concat(&np->fflags_text, &file->fflags_text);- np->nlink = file->nlink;- np->filetype = file->filetype;- np->mode = file->mode;- np->size = file->size;- np->uid = file->uid;- np->gid = file->gid;- np->fflags_set = file->fflags_set;- np->fflags_clear = file->fflags_clear;- np->mtime = file->mtime;- np->mtime_nsec = file->mtime_nsec;- np->rdevmajor = file->rdevmajor;- np->rdevminor = file->rdevminor;- np->devmajor = file->devmajor;- np->devminor = file->devminor;- np->ino = file->ino;-- return (ARCHIVE_WARN);-}
− c/archive_write_set_format_pax.c
@@ -1,2063 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2010-2012 Michihiro NAKAJIMA- * Copyright (c) 2016 Martin Matuska- * 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_format_pax.c 201162 2009-12-29 05:47:46Z 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 "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--struct sparse_block {- struct sparse_block *next;- int is_hole;- uint64_t offset;- uint64_t remaining;-};--struct pax {- uint64_t entry_bytes_remaining;- uint64_t entry_padding;- struct archive_string l_url_encoded_name;- struct archive_string pax_header;- struct archive_string sparse_map;- size_t sparse_map_padding;- struct sparse_block *sparse_list;- struct sparse_block *sparse_tail;- struct archive_string_conv *sconv_utf8;- int opt_binary;-- unsigned flags;-#define WRITE_SCHILY_XATTR (1 << 0)-#define WRITE_LIBARCHIVE_XATTR (1 << 1)-};--static void add_pax_attr(struct archive_string *, const char *key,- const char *value);-static void add_pax_attr_binary(struct archive_string *,- const char *key,- const char *value, size_t value_len);-static void add_pax_attr_int(struct archive_string *,- const char *key, int64_t value);-static void add_pax_attr_time(struct archive_string *,- const char *key, int64_t sec,- unsigned long nanos);-static int add_pax_acl(struct archive_write *,- struct archive_entry *, struct pax *, int);-static ssize_t archive_write_pax_data(struct archive_write *,- const void *, size_t);-static int archive_write_pax_close(struct archive_write *);-static int archive_write_pax_free(struct archive_write *);-static int archive_write_pax_finish_entry(struct archive_write *);-static int archive_write_pax_header(struct archive_write *,- struct archive_entry *);-static int archive_write_pax_options(struct archive_write *,- const char *, const char *);-static char *base64_encode(const char *src, size_t len);-static char *build_gnu_sparse_name(char *dest, const char *src);-static char *build_pax_attribute_name(char *dest, const char *src);-static char *build_ustar_entry_name(char *dest, const char *src,- size_t src_length, const char *insert);-static char *format_int(char *dest, int64_t);-static int has_non_ASCII(const char *);-static void sparse_list_clear(struct pax *);-static int sparse_list_add(struct pax *, int64_t, int64_t);-static char *url_encode(const char *in);-static time_t get_ustar_max_mtime(void);--/*- * Set output format to 'restricted pax' format.- *- * This is the same as normal 'pax', but tries to suppress- * the pax header whenever possible. This is the default for- * bsdtar, for instance.- */-int-archive_write_set_format_pax_restricted(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- int r;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_pax_restricted");-- r = archive_write_set_format_pax(&a->archive);- a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED;- a->archive.archive_format_name = "restricted POSIX pax interchange";- return (r);-}--/*- * Set output format to 'pax' format.- */-int-archive_write_set_format_pax(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct pax *pax;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_pax");-- if (a->format_free != NULL)- (a->format_free)(a);-- pax = (struct pax *)calloc(1, sizeof(*pax));- if (pax == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate pax data");- return (ARCHIVE_FATAL);- }- pax->flags = WRITE_LIBARCHIVE_XATTR | WRITE_SCHILY_XATTR;-- a->format_data = pax;- a->format_name = "pax";- a->format_options = archive_write_pax_options;- a->format_write_header = archive_write_pax_header;- a->format_write_data = archive_write_pax_data;- a->format_close = archive_write_pax_close;- a->format_free = archive_write_pax_free;- a->format_finish_entry = archive_write_pax_finish_entry;- a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;- a->archive.archive_format_name = "POSIX pax interchange";- return (ARCHIVE_OK);-}--static int-archive_write_pax_options(struct archive_write *a, const char *key,- const char *val)-{- struct pax *pax = (struct pax *)a->format_data;- int ret = ARCHIVE_FAILED;-- if (strcmp(key, "hdrcharset") == 0) {- /*- * The character-set we can use are defined in- * IEEE Std 1003.1-2001- */- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "pax: hdrcharset option needs a character-set name");- else if (strcmp(val, "BINARY") == 0 ||- strcmp(val, "binary") == 0) {- /*- * Specify binary mode. We will not convert- * filenames, uname and gname to any charsets.- */- pax->opt_binary = 1;- ret = ARCHIVE_OK;- } else if (strcmp(val, "UTF-8") == 0) {- /*- * Specify UTF-8 character-set to be used for- * filenames. This is almost the test that- * running platform supports the string conversion.- * Especially libarchive_test needs this trick for- * its test.- */- pax->sconv_utf8 = archive_string_conversion_to_charset(- &(a->archive), "UTF-8", 0);- if (pax->sconv_utf8 == NULL)- ret = ARCHIVE_FATAL;- else- ret = ARCHIVE_OK;- } else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "pax: invalid charset name");- return (ret);- } else if (strcmp(key, "xattrheader") == 0) {- if (val == NULL || val[0] == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "pax: xattrheader requires a value");- } else if (strcmp(val, "ALL") == 0 ||- strcmp(val, "all") == 0) {- pax->flags |= WRITE_LIBARCHIVE_XATTR | WRITE_SCHILY_XATTR;- ret = ARCHIVE_OK;- } else if (strcmp(val, "SCHILY") == 0 ||- strcmp(val, "schily") == 0) {- pax->flags |= WRITE_SCHILY_XATTR;- pax->flags &= ~WRITE_LIBARCHIVE_XATTR;- ret = ARCHIVE_OK;- } else if (strcmp(val, "LIBARCHIVE") == 0 ||- strcmp(val, "libarchive") == 0) {- pax->flags |= WRITE_LIBARCHIVE_XATTR;- pax->flags &= ~WRITE_SCHILY_XATTR;- ret = ARCHIVE_OK;- } else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "pax: invalid xattr header name");- return (ret);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--/*- * Note: This code assumes that 'nanos' has the same sign as 'sec',- * which implies that sec=-1, nanos=200000000 represents -1.2 seconds- * and not -0.8 seconds. This is a pretty pedantic point, as we're- * unlikely to encounter many real files created before Jan 1, 1970,- * much less ones with timestamps recorded to sub-second resolution.- */-static void-add_pax_attr_time(struct archive_string *as, const char *key,- int64_t sec, unsigned long nanos)-{- int digit, i;- char *t;- /*- * Note that each byte contributes fewer than 3 base-10- * digits, so this will always be big enough.- */- char tmp[1 + 3*sizeof(sec) + 1 + 3*sizeof(nanos)];-- tmp[sizeof(tmp) - 1] = 0;- t = tmp + sizeof(tmp) - 1;-- /* Skip trailing zeros in the fractional part. */- for (digit = 0, i = 10; i > 0 && digit == 0; i--) {- digit = nanos % 10;- nanos /= 10;- }-- /* Only format the fraction if it's non-zero. */- if (i > 0) {- while (i > 0) {- *--t = "0123456789"[digit];- digit = nanos % 10;- nanos /= 10;- i--;- }- *--t = '.';- }- t = format_int(t, sec);-- add_pax_attr(as, key, t);-}--static char *-format_int(char *t, int64_t i)-{- uint64_t ui;-- if (i < 0) - ui = (i == INT64_MIN) ? (uint64_t)(INT64_MAX) + 1 : (uint64_t)(-i);- else- ui = i;-- do {- *--t = "0123456789"[ui % 10];- } while (ui /= 10);- if (i < 0)- *--t = '-';- return (t);-}--static void-add_pax_attr_int(struct archive_string *as, const char *key, int64_t value)-{- char tmp[1 + 3 * sizeof(value)];-- tmp[sizeof(tmp) - 1] = 0;- add_pax_attr(as, key, format_int(tmp + sizeof(tmp) - 1, value));-}--/*- * Add a key/value attribute to the pax header. This function handles- * the length field and various other syntactic requirements.- */-static void-add_pax_attr(struct archive_string *as, const char *key, const char *value)-{- add_pax_attr_binary(as, key, value, strlen(value));-}--/*- * Add a key/value attribute to the pax header. This function handles- * binary values.- */-static void-add_pax_attr_binary(struct archive_string *as, const char *key,- const char *value, size_t value_len)-{- int digits, i, len, next_ten;- char tmp[1 + 3 * sizeof(int)]; /* < 3 base-10 digits per byte */-- /*-- * PAX attributes have the following layout:- * <len> <space> <key> <=> <value> <nl>- */- len = 1 + (int)strlen(key) + 1 + (int)value_len + 1;-- /*- * The <len> field includes the length of the <len> field, so- * computing the correct length is tricky. I start by- * counting the number of base-10 digits in 'len' and- * computing the next higher power of 10.- */- next_ten = 1;- digits = 0;- i = len;- while (i > 0) {- i = i / 10;- digits++;- next_ten = next_ten * 10;- }- /*- * For example, if string without the length field is 99- * chars, then adding the 2 digit length "99" will force the- * total length past 100, requiring an extra digit. The next- * statement adjusts for this effect.- */- if (len + digits >= next_ten)- digits++;-- /* Now, we have the right length so we can build the line. */- tmp[sizeof(tmp) - 1] = 0; /* Null-terminate the work area. */- archive_strcat(as, format_int(tmp + sizeof(tmp) - 1, len + digits));- archive_strappend_char(as, ' ');- archive_strcat(as, key);- archive_strappend_char(as, '=');- archive_array_append(as, value, value_len);- archive_strappend_char(as, '\n');-}--static void-archive_write_pax_header_xattr(struct pax *pax, const char *encoded_name,- const void *value, size_t value_len)-{- struct archive_string s;- char *encoded_value;-- if (pax->flags & WRITE_LIBARCHIVE_XATTR) {- encoded_value = base64_encode((const char *)value, value_len);-- if (encoded_name != NULL && encoded_value != NULL) {- archive_string_init(&s);- archive_strcpy(&s, "LIBARCHIVE.xattr.");- archive_strcat(&s, encoded_name);- add_pax_attr(&(pax->pax_header), s.s, encoded_value);- archive_string_free(&s);- }- free(encoded_value);- }- if (pax->flags & WRITE_SCHILY_XATTR) {- archive_string_init(&s);- archive_strcpy(&s, "SCHILY.xattr.");- archive_strcat(&s, encoded_name);- add_pax_attr_binary(&(pax->pax_header), s.s, value, value_len);- archive_string_free(&s);- }-}--static int-archive_write_pax_header_xattrs(struct archive_write *a,- struct pax *pax, struct archive_entry *entry)-{- int i = archive_entry_xattr_reset(entry);-- while (i--) {- const char *name;- const void *value;- char *url_encoded_name = NULL, *encoded_name = NULL;- size_t size;- int r;-- archive_entry_xattr_next(entry, &name, &value, &size);- url_encoded_name = url_encode(name);- if (url_encoded_name != NULL) {- /* Convert narrow-character to UTF-8. */- r = archive_strcpy_l(&(pax->l_url_encoded_name),- url_encoded_name, pax->sconv_utf8);- free(url_encoded_name); /* Done with this. */- if (r == 0)- encoded_name = pax->l_url_encoded_name.s;- else if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- return (ARCHIVE_FATAL);- }- }-- archive_write_pax_header_xattr(pax, encoded_name,- value, size);-- }- return (ARCHIVE_OK);-}--static int-get_entry_hardlink(struct archive_write *a, struct archive_entry *entry,- const char **name, size_t *length, struct archive_string_conv *sc)-{- int r;- - r = archive_entry_hardlink_l(entry, name, length, sc);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-}--static int-get_entry_pathname(struct archive_write *a, struct archive_entry *entry,- const char **name, size_t *length, struct archive_string_conv *sc)-{- int r;-- r = archive_entry_pathname_l(entry, name, length, sc);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-}--static int-get_entry_uname(struct archive_write *a, struct archive_entry *entry,- const char **name, size_t *length, struct archive_string_conv *sc)-{- int r;-- r = archive_entry_uname_l(entry, name, length, sc);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Uname");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-}--static int-get_entry_gname(struct archive_write *a, struct archive_entry *entry,- const char **name, size_t *length, struct archive_string_conv *sc)-{- int r;-- r = archive_entry_gname_l(entry, name, length, sc);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Gname");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-}--static int-get_entry_symlink(struct archive_write *a, struct archive_entry *entry,- const char **name, size_t *length, struct archive_string_conv *sc)-{- int r;-- r = archive_entry_symlink_l(entry, name, length, sc);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_WARN);- }- return (ARCHIVE_OK);-}--/* Add ACL to pax header */-static int-add_pax_acl(struct archive_write *a,- struct archive_entry *entry, struct pax *pax, int flags)-{- char *p;- const char *attr;- int acl_types;-- acl_types = archive_entry_acl_types(entry);-- if ((acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)- attr = "SCHILY.acl.ace";- else if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)- attr = "SCHILY.acl.access";- else if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)- attr = "SCHILY.acl.default";- else- return (ARCHIVE_FATAL);-- p = archive_entry_acl_to_text_l(entry, NULL, flags, pax->sconv_utf8);- if (p == NULL) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM, "%s %s",- "Can't allocate memory for ", attr);- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT, "%s %s %s",- "Can't translate ", attr, " to UTF-8");- return(ARCHIVE_WARN);- }-- if (*p != '\0') {- add_pax_attr(&(pax->pax_header),- attr, p);- }- free(p);- return(ARCHIVE_OK);-}--/*- * TODO: Consider adding 'comment' and 'charset' fields to- * archive_entry so that clients can specify them. Also, consider- * adding generic key/value tags so clients can add arbitrary- * key/value data.- *- * TODO: Break up this 700-line function!!!! Yowza!- */-static int-archive_write_pax_header(struct archive_write *a,- struct archive_entry *entry_original)-{- struct archive_entry *entry_main;- const char *p;- const char *suffix;- int need_extension, r, ret;- int acl_types;- int sparse_count;- uint64_t sparse_total, real_size;- struct pax *pax;- const char *hardlink;- const char *path = NULL, *linkpath = NULL;- const char *uname = NULL, *gname = NULL;- const void *mac_metadata;- size_t mac_metadata_size;- struct archive_string_conv *sconv;- size_t hardlink_length, path_length, linkpath_length;- size_t uname_length, gname_length;-- char paxbuff[512];- char ustarbuff[512];- char ustar_entry_name[256];- char pax_entry_name[256];- char gnu_sparse_name[256];- struct archive_string entry_name;-- ret = ARCHIVE_OK;- need_extension = 0;- pax = (struct pax *)a->format_data;-- const time_t ustar_max_mtime = get_ustar_max_mtime();-- /* Sanity check. */- if (archive_entry_pathname(entry_original) == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't record entry in tar file without pathname");- return (ARCHIVE_FAILED);- }-- /*- * Choose a header encoding.- */- if (pax->opt_binary)- sconv = NULL;/* Binary mode. */- else {- /* Header encoding is UTF-8. */- if (pax->sconv_utf8 == NULL) {- /* Initialize the string conversion object- * we must need */- pax->sconv_utf8 = archive_string_conversion_to_charset(- &(a->archive), "UTF-8", 1);- if (pax->sconv_utf8 == NULL)- /* Couldn't allocate memory */- return (ARCHIVE_FAILED);- }- sconv = pax->sconv_utf8;- }-- r = get_entry_hardlink(a, entry_original, &hardlink,- &hardlink_length, sconv);- if (r == ARCHIVE_FATAL)- return (r);- else if (r != ARCHIVE_OK) {- r = get_entry_hardlink(a, entry_original, &hardlink,- &hardlink_length, NULL);- if (r == ARCHIVE_FATAL)- return (r);- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s", hardlink,- archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- sconv = NULL;/* The header charset switches to binary mode. */- }-- /* Make sure this is a type of entry that we can handle here */- if (hardlink == NULL) {- switch (archive_entry_filetype(entry_original)) {- case AE_IFBLK:- case AE_IFCHR:- case AE_IFIFO:- case AE_IFLNK:- case AE_IFREG:- break;- case AE_IFDIR:- {- /*- * Ensure a trailing '/'. Modify the original- * entry so the client sees the change.- */-#if defined(_WIN32) && !defined(__CYGWIN__)- const wchar_t *wp;-- wp = archive_entry_pathname_w(entry_original);- if (wp != NULL && wp[wcslen(wp) -1] != L'/') {- struct archive_wstring ws;-- archive_string_init(&ws);- path_length = wcslen(wp);- if (archive_wstring_ensure(&ws,- path_length + 2) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate pax data");- archive_wstring_free(&ws);- return(ARCHIVE_FATAL);- }- /* Should we keep '\' ? */- if (wp[path_length -1] == L'\\')- path_length--;- archive_wstrncpy(&ws, wp, path_length);- archive_wstrappend_wchar(&ws, L'/');- archive_entry_copy_pathname_w(- entry_original, ws.s);- archive_wstring_free(&ws);- p = NULL;- } else-#endif- p = archive_entry_pathname(entry_original);- /*- * On Windows, this is a backup operation just in- * case getting WCS failed. On POSIX, this is a- * normal operation.- */- if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {- struct archive_string as;-- archive_string_init(&as);- path_length = strlen(p);- if (archive_string_ensure(&as,- path_length + 2) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate pax data");- archive_string_free(&as);- return(ARCHIVE_FATAL);- }-#if defined(_WIN32) && !defined(__CYGWIN__)- /* NOTE: This might break the pathname- * if the current code page is CP932 and- * the pathname includes a character '\'- * as a part of its multibyte pathname. */- if (p[strlen(p) -1] == '\\')- path_length--;- else-#endif- archive_strncpy(&as, p, path_length);- archive_strappend_char(&as, '/');- archive_entry_copy_pathname(- entry_original, as.s);- archive_string_free(&as);- }- break;- }- default: /* AE_IFSOCK and unknown */- __archive_write_entry_filetype_unsupported(- &a->archive, entry_original, "pax");- return (ARCHIVE_FAILED);- }- }-- /*- * If Mac OS metadata blob is here, recurse to write that- * as a separate entry. This is really a pretty poor design:- * In particular, it doubles the overhead for long filenames.- * TODO: Help Apple folks design something better and figure- * out how to transition from this legacy format.- *- * Note that this code is present on every platform; clients- * on non-Mac are unlikely to ever provide this data, but- * applications that copy entries from one archive to another- * should not lose data just because the local filesystem- * can't store it.- */- mac_metadata =- archive_entry_mac_metadata(entry_original, &mac_metadata_size);- if (mac_metadata != NULL) {- const char *oname;- char *name, *bname;- size_t name_length;- struct archive_entry *extra = archive_entry_new2(&a->archive);-- oname = archive_entry_pathname(entry_original);- name_length = strlen(oname);- name = malloc(name_length + 3);- if (name == NULL || extra == NULL) {- /* XXX error message */- archive_entry_free(extra);- free(name);- return (ARCHIVE_FAILED);- }- strcpy(name, oname);- /* Find last '/'; strip trailing '/' characters */- bname = strrchr(name, '/');- while (bname != NULL && bname[1] == '\0') {- *bname = '\0';- bname = strrchr(name, '/');- }- if (bname == NULL) {- memmove(name + 2, name, name_length + 1);- memmove(name, "._", 2);- } else {- bname += 1;- memmove(bname + 2, bname, strlen(bname) + 1);- memmove(bname, "._", 2);- }- archive_entry_copy_pathname(extra, name);- free(name);-- archive_entry_set_size(extra, mac_metadata_size);- archive_entry_set_filetype(extra, AE_IFREG);- archive_entry_set_perm(extra,- archive_entry_perm(entry_original));- archive_entry_set_mtime(extra,- archive_entry_mtime(entry_original),- archive_entry_mtime_nsec(entry_original));- archive_entry_set_gid(extra,- archive_entry_gid(entry_original));- archive_entry_set_gname(extra,- archive_entry_gname(entry_original));- archive_entry_set_uid(extra,- archive_entry_uid(entry_original));- archive_entry_set_uname(extra,- archive_entry_uname(entry_original));-- /* Recurse to write the special copyfile entry. */- r = archive_write_pax_header(a, extra);- archive_entry_free(extra);- if (r < ARCHIVE_WARN)- return (r);- if (r < ret)- ret = r;- r = (int)archive_write_pax_data(a, mac_metadata,- mac_metadata_size);- if (r < ARCHIVE_WARN)- return (r);- if (r < ret)- ret = r;- r = archive_write_pax_finish_entry(a);- if (r < ARCHIVE_WARN)- return (r);- if (r < ret)- ret = r;- }-- /* Copy entry so we can modify it as needed. */-#if defined(_WIN32) && !defined(__CYGWIN__)- /* Make sure the path separators in pathname, hardlink and symlink- * are all slash '/', not the Windows path separator '\'. */- entry_main = __la_win_entry_in_posix_pathseparator(entry_original);- if (entry_main == entry_original)- entry_main = archive_entry_clone(entry_original);-#else- entry_main = archive_entry_clone(entry_original);-#endif- if (entry_main == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate pax data");- return(ARCHIVE_FATAL);- }- archive_string_empty(&(pax->pax_header)); /* Blank our work area. */- archive_string_empty(&(pax->sparse_map));- sparse_total = 0;- sparse_list_clear(pax);-- if (hardlink == NULL &&- archive_entry_filetype(entry_main) == AE_IFREG)- sparse_count = archive_entry_sparse_reset(entry_main);- else- sparse_count = 0;- if (sparse_count) {- int64_t offset, length, last_offset = 0;- /* Get the last entry of sparse block. */- while (archive_entry_sparse_next(- entry_main, &offset, &length) == ARCHIVE_OK)- last_offset = offset + length;-- /* If the last sparse block does not reach the end of file,- * We have to add a empty sparse block as the last entry to- * manage storing file data. */- if (last_offset < archive_entry_size(entry_main))- archive_entry_sparse_add_entry(entry_main,- archive_entry_size(entry_main), 0);- sparse_count = archive_entry_sparse_reset(entry_main);- }-- /*- * First, check the name fields and see if any of them- * require binary coding. If any of them does, then all of- * them do.- */- r = get_entry_pathname(a, entry_main, &path, &path_length, sconv);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- } else if (r != ARCHIVE_OK) {- r = get_entry_pathname(a, entry_main, &path,- &path_length, NULL);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate pathname '%s' to %s", path,- archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- sconv = NULL;/* The header charset switches to binary mode. */- }- r = get_entry_uname(a, entry_main, &uname, &uname_length, sconv);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- } else if (r != ARCHIVE_OK) {- r = get_entry_uname(a, entry_main, &uname, &uname_length, NULL);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate uname '%s' to %s", uname,- archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- sconv = NULL;/* The header charset switches to binary mode. */- }- r = get_entry_gname(a, entry_main, &gname, &gname_length, sconv);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- } else if (r != ARCHIVE_OK) {- r = get_entry_gname(a, entry_main, &gname, &gname_length, NULL);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate gname '%s' to %s", gname,- archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- sconv = NULL;/* The header charset switches to binary mode. */- }- linkpath = hardlink;- linkpath_length = hardlink_length;- if (linkpath == NULL) {- r = get_entry_symlink(a, entry_main, &linkpath,- &linkpath_length, sconv);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- } else if (r != ARCHIVE_OK) {- r = get_entry_symlink(a, entry_main, &linkpath,- &linkpath_length, NULL);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s", linkpath,- archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- sconv = NULL;- }- }-- /* If any string conversions failed, get all attributes- * in binary-mode. */- if (sconv == NULL && !pax->opt_binary) {- if (hardlink != NULL) {- r = get_entry_hardlink(a, entry_main, &hardlink,- &hardlink_length, NULL);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- }- linkpath = hardlink;- linkpath_length = hardlink_length;- }- r = get_entry_pathname(a, entry_main, &path,- &path_length, NULL);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- }- r = get_entry_uname(a, entry_main, &uname, &uname_length, NULL);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- }- r = get_entry_gname(a, entry_main, &gname, &gname_length, NULL);- if (r == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- return (r);- }- }-- /* Store the header encoding first, to be nice to readers. */- if (sconv == NULL)- add_pax_attr(&(pax->pax_header), "hdrcharset", "BINARY");--- /*- * If name is too long, or has non-ASCII characters, add- * 'path' to pax extended attrs. (Note that an unconvertible- * name must have non-ASCII characters.)- */- if (has_non_ASCII(path)) {- /* We have non-ASCII characters. */- add_pax_attr(&(pax->pax_header), "path", path);- archive_entry_set_pathname(entry_main,- build_ustar_entry_name(ustar_entry_name,- path, path_length, NULL));- need_extension = 1;- } else {- /* We have an all-ASCII path; we'd like to just store- * it in the ustar header if it will fit. Yes, this- * duplicates some of the logic in- * archive_write_set_format_ustar.c- */- if (path_length <= 100) {- /* Fits in the old 100-char tar name field. */- } else {- /* Find largest suffix that will fit. */- /* Note: strlen() > 100, so strlen() - 100 - 1 >= 0 */- suffix = strchr(path + path_length - 100 - 1, '/');- /* Don't attempt an empty prefix. */- if (suffix == path)- suffix = strchr(suffix + 1, '/');- /* We can put it in the ustar header if it's- * all ASCII and it's either <= 100 characters- * or can be split at a '/' into a prefix <=- * 155 chars and a suffix <= 100 chars. (Note- * the strchr() above will return NULL exactly- * when the path can't be split.)- */- if (suffix == NULL /* Suffix > 100 chars. */- || suffix[1] == '\0' /* empty suffix */- || suffix - path > 155) /* Prefix > 155 chars */- {- add_pax_attr(&(pax->pax_header), "path", path);- archive_entry_set_pathname(entry_main,- build_ustar_entry_name(ustar_entry_name,- path, path_length, NULL));- need_extension = 1;- }- }- }-- if (linkpath != NULL) {- /* If link name is too long or has non-ASCII characters, add- * 'linkpath' to pax extended attrs. */- if (linkpath_length > 100 || has_non_ASCII(linkpath)) {- add_pax_attr(&(pax->pax_header), "linkpath", linkpath);- if (linkpath_length > 100) {- if (hardlink != NULL)- archive_entry_set_hardlink(entry_main,- "././@LongHardLink");- else- archive_entry_set_symlink(entry_main,- "././@LongSymLink");- }- need_extension = 1;- }- }- /* Save a pathname since it will be renamed if `entry_main` has- * sparse blocks. */- archive_string_init(&entry_name);- archive_strcpy(&entry_name, archive_entry_pathname(entry_main));-- /* If file size is too large, we need pax extended attrs. */- if (archive_entry_size(entry_main) >= (((int64_t)1) << 33)) {- need_extension = 1;- }-- /* If numeric GID is too large, add 'gid' to pax extended attrs. */- if ((unsigned int)archive_entry_gid(entry_main) >= (1 << 18)) {- add_pax_attr_int(&(pax->pax_header), "gid",- archive_entry_gid(entry_main));- need_extension = 1;- }-- /* If group name is too large or has non-ASCII characters, add- * 'gname' to pax extended attrs. */- if (gname != NULL) {- if (gname_length > 31 || has_non_ASCII(gname)) {- add_pax_attr(&(pax->pax_header), "gname", gname);- need_extension = 1;- }- }-- /* If numeric UID is too large, add 'uid' to pax extended attrs. */- if ((unsigned int)archive_entry_uid(entry_main) >= (1 << 18)) {- add_pax_attr_int(&(pax->pax_header), "uid",- archive_entry_uid(entry_main));- need_extension = 1;- }-- /* Add 'uname' to pax extended attrs if necessary. */- if (uname != NULL) {- if (uname_length > 31 || has_non_ASCII(uname)) {- add_pax_attr(&(pax->pax_header), "uname", uname);- need_extension = 1;- }- }-- /*- * POSIX/SUSv3 doesn't provide a standard key for large device- * numbers. I use the same keys here that Joerg Schilling- * used for 'star.' (Which, somewhat confusingly, are called- * "devXXX" even though they code "rdev" values.) No doubt,- * other implementations use other keys. Note that there's no- * reason we can't write the same information into a number of- * different keys.- *- * Of course, this is only needed for block or char device entries.- */- if (archive_entry_filetype(entry_main) == AE_IFBLK- || archive_entry_filetype(entry_main) == AE_IFCHR) {- /*- * If rdevmajor is too large, add 'SCHILY.devmajor' to- * extended attributes.- */- int rdevmajor, rdevminor;- rdevmajor = archive_entry_rdevmajor(entry_main);- rdevminor = archive_entry_rdevminor(entry_main);- if (rdevmajor >= (1 << 18)) {- add_pax_attr_int(&(pax->pax_header), "SCHILY.devmajor",- rdevmajor);- /*- * Non-strict formatting below means we don't- * have to truncate here. Not truncating improves- * the chance that some more modern tar archivers- * (such as GNU tar 1.13) can restore the full- * value even if they don't understand the pax- * extended attributes. See my rant below about- * file size fields for additional details.- */- /* archive_entry_set_rdevmajor(entry_main,- rdevmajor & ((1 << 18) - 1)); */- need_extension = 1;- }-- /*- * If devminor is too large, add 'SCHILY.devminor' to- * extended attributes.- */- if (rdevminor >= (1 << 18)) {- add_pax_attr_int(&(pax->pax_header), "SCHILY.devminor",- rdevminor);- /* Truncation is not necessary here, either. */- /* archive_entry_set_rdevminor(entry_main,- rdevminor & ((1 << 18) - 1)); */- need_extension = 1;- }- }-- /*- * Yes, this check is duplicated just below; this helps to- * avoid writing an mtime attribute just to handle a- * high-resolution timestamp in "restricted pax" mode.- */- if (!need_extension &&- ((archive_entry_mtime(entry_main) < 0)- || (archive_entry_mtime(entry_main) >= ustar_max_mtime)))- need_extension = 1;-- /* I use a star-compatible file flag attribute. */- p = archive_entry_fflags_text(entry_main);- if (!need_extension && p != NULL && *p != '\0')- need_extension = 1;-- /* If there are extended attributes, we need an extension */- if (!need_extension && archive_entry_xattr_count(entry_original) > 0)- need_extension = 1;-- /* If there are sparse info, we need an extension */- if (!need_extension && sparse_count > 0)- need_extension = 1;-- acl_types = archive_entry_acl_types(entry_original);-- /* If there are any ACL entries, we need an extension */- if (!need_extension && acl_types != 0)- need_extension = 1;-- /* If the symlink type is defined, we need an extension */- if (!need_extension && archive_entry_symlink_type(entry_main) > 0)- need_extension = 1;-- /*- * Libarchive used to include these in extended headers for- * restricted pax format, but that confused people who- * expected ustar-like time semantics. So now we only include- * them in full pax format.- */- if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED) {- if (archive_entry_ctime(entry_main) != 0 ||- archive_entry_ctime_nsec(entry_main) != 0)- add_pax_attr_time(&(pax->pax_header), "ctime",- archive_entry_ctime(entry_main),- archive_entry_ctime_nsec(entry_main));-- if (archive_entry_atime(entry_main) != 0 ||- archive_entry_atime_nsec(entry_main) != 0)- add_pax_attr_time(&(pax->pax_header), "atime",- archive_entry_atime(entry_main),- archive_entry_atime_nsec(entry_main));-- /* Store birth/creationtime only if it's earlier than mtime */- if (archive_entry_birthtime_is_set(entry_main) &&- archive_entry_birthtime(entry_main)- < archive_entry_mtime(entry_main))- add_pax_attr_time(&(pax->pax_header),- "LIBARCHIVE.creationtime",- archive_entry_birthtime(entry_main),- archive_entry_birthtime_nsec(entry_main));- }-- /*- * The following items are handled differently in "pax- * restricted" format. In particular, in "pax restricted"- * format they won't be added unless need_extension is- * already set (we're already generating an extended header, so- * may as well include these).- */- if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED ||- need_extension) {- if (archive_entry_mtime(entry_main) < 0 ||- archive_entry_mtime(entry_main) >= ustar_max_mtime ||- archive_entry_mtime_nsec(entry_main) != 0)- add_pax_attr_time(&(pax->pax_header), "mtime",- archive_entry_mtime(entry_main),- archive_entry_mtime_nsec(entry_main));-- /* I use a star-compatible file flag attribute. */- p = archive_entry_fflags_text(entry_main);- if (p != NULL && *p != '\0')- add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);-- /* I use star-compatible ACL attributes. */- if ((acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {- ret = add_pax_acl(a, entry_original, pax,- ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |- ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA |- ARCHIVE_ENTRY_ACL_STYLE_COMPACT);- if (ret == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (ARCHIVE_FATAL);- }- }- if (acl_types & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {- ret = add_pax_acl(a, entry_original, pax,- ARCHIVE_ENTRY_ACL_TYPE_ACCESS |- ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |- ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA);- if (ret == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (ARCHIVE_FATAL);- }- }- if (acl_types & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) {- ret = add_pax_acl(a, entry_original, pax,- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |- ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |- ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA);- if (ret == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (ARCHIVE_FATAL);- }- }-- /* We use GNU-tar-compatible sparse attributes. */- if (sparse_count > 0) {- int64_t soffset, slength;-- add_pax_attr_int(&(pax->pax_header),- "GNU.sparse.major", 1);- add_pax_attr_int(&(pax->pax_header),- "GNU.sparse.minor", 0);- /*- * Make sure to store the original path, since- * truncation to ustar limit happened already.- */- add_pax_attr(&(pax->pax_header),- "GNU.sparse.name", path);- add_pax_attr_int(&(pax->pax_header),- "GNU.sparse.realsize",- archive_entry_size(entry_main));-- /* Rename the file name which will be used for- * ustar header to a special name, which GNU- * PAX Format 1.0 requires */- archive_entry_set_pathname(entry_main,- build_gnu_sparse_name(gnu_sparse_name,- entry_name.s));-- /*- * - Make a sparse map, which will precede a file data.- * - Get the total size of available data of sparse.- */- archive_string_sprintf(&(pax->sparse_map), "%d\n",- sparse_count);- while (archive_entry_sparse_next(entry_main,- &soffset, &slength) == ARCHIVE_OK) {- archive_string_sprintf(&(pax->sparse_map),- "%jd\n%jd\n",- (intmax_t)soffset,- (intmax_t)slength);- sparse_total += slength;- if (sparse_list_add(pax, soffset, slength)- != ARCHIVE_OK) {- archive_set_error(&a->archive,- ENOMEM,- "Can't allocate memory");- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (ARCHIVE_FATAL);- }- }- }-- /* Store extended attributes */- if (archive_write_pax_header_xattrs(a, pax, entry_original)- == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (ARCHIVE_FATAL);- }-- /* Store extended symlink information */- if (archive_entry_symlink_type(entry_main) ==- AE_SYMLINK_TYPE_FILE) {- add_pax_attr(&(pax->pax_header),- "LIBARCHIVE.symlinktype", "file");- } else if (archive_entry_symlink_type(entry_main) ==- AE_SYMLINK_TYPE_DIRECTORY) {- add_pax_attr(&(pax->pax_header),- "LIBARCHIVE.symlinktype", "dir");- }- }-- /* Only regular files have data. */- if (archive_entry_filetype(entry_main) != AE_IFREG)- archive_entry_set_size(entry_main, 0);-- /*- * Pax-restricted does not store data for hardlinks, in order- * to improve compatibility with ustar.- */- if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&- hardlink != NULL)- archive_entry_set_size(entry_main, 0);-- /*- * XXX Full pax interchange format does permit a hardlink- * entry to have data associated with it. I'm not supporting- * that here because the client expects me to tell them whether- * or not this format expects data for hardlinks. If I- * don't check here, then every pax archive will end up with- * duplicated data for hardlinks. Someday, there may be- * need to select this behavior, in which case the following- * will need to be revisited. XXX- */- if (hardlink != NULL)- archive_entry_set_size(entry_main, 0);-- /* Save a real file size. */- real_size = archive_entry_size(entry_main);- /*- * Overwrite a file size by the total size of sparse blocks and- * the size of sparse map info. That file size is the length of- * the data, which we will exactly store into an archive file.- */- if (archive_strlen(&(pax->sparse_map))) {- size_t mapsize = archive_strlen(&(pax->sparse_map));- pax->sparse_map_padding = 0x1ff & (-(ssize_t)mapsize);- archive_entry_set_size(entry_main,- mapsize + pax->sparse_map_padding + sparse_total);- }-- /* If file size is too large, add 'size' to pax extended attrs. */- if (archive_entry_size(entry_main) >= (((int64_t)1) << 33)) {- add_pax_attr_int(&(pax->pax_header), "size",- archive_entry_size(entry_main));- }-- /* Format 'ustar' header for main entry.- *- * The trouble with file size: If the reader can't understand- * the file size, they may not be able to locate the next- * entry and the rest of the archive is toast. Pax-compliant- * readers are supposed to ignore the file size in the main- * header, so the question becomes how to maximize portability- * for readers that don't support pax attribute extensions.- * For maximum compatibility, I permit numeric extensions in- * the main header so that the file size stored will always be- * correct, even if it's in a format that only some- * implementations understand. The technique used here is:- *- * a) If possible, follow the standard exactly. This handles- * files up to 8 gigabytes minus 1.- *- * b) If that fails, try octal but omit the field terminator.- * That handles files up to 64 gigabytes minus 1.- *- * c) Otherwise, use base-256 extensions. That handles files- * up to 2^63 in this implementation, with the potential to- * go up to 2^94. That should hold us for a while. ;-)- *- * The non-strict formatter uses similar logic for other- * numeric fields, though they're less critical.- */- if (__archive_write_format_header_ustar(a, ustarbuff, entry_main, -1, 0,- NULL) == ARCHIVE_FATAL) {- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (ARCHIVE_FATAL);- }-- /* If we built any extended attributes, write that entry first. */- if (archive_strlen(&(pax->pax_header)) > 0) {- struct archive_entry *pax_attr_entry;- time_t s;- int64_t uid, gid;- int mode;-- pax_attr_entry = archive_entry_new2(&a->archive);- p = entry_name.s;- archive_entry_set_pathname(pax_attr_entry,- build_pax_attribute_name(pax_entry_name, p));- archive_entry_set_size(pax_attr_entry,- archive_strlen(&(pax->pax_header)));- /* Copy uid/gid (but clip to ustar limits). */- uid = archive_entry_uid(entry_main);- if (uid >= 1 << 18)- uid = (1 << 18) - 1;- archive_entry_set_uid(pax_attr_entry, uid);- gid = archive_entry_gid(entry_main);- if (gid >= 1 << 18)- gid = (1 << 18) - 1;- archive_entry_set_gid(pax_attr_entry, gid);- /* Copy mode over (but not setuid/setgid bits) */- mode = archive_entry_mode(entry_main);-#ifdef S_ISUID- mode &= ~S_ISUID;-#endif-#ifdef S_ISGID- mode &= ~S_ISGID;-#endif-#ifdef S_ISVTX- mode &= ~S_ISVTX;-#endif- archive_entry_set_mode(pax_attr_entry, mode);-- /* Copy uname/gname. */- archive_entry_set_uname(pax_attr_entry,- archive_entry_uname(entry_main));- archive_entry_set_gname(pax_attr_entry,- archive_entry_gname(entry_main));-- /* Copy mtime, but clip to ustar limits. */- s = archive_entry_mtime(entry_main);- if (s < 0) { s = 0; }- if (s > ustar_max_mtime) { s = ustar_max_mtime; }- archive_entry_set_mtime(pax_attr_entry, s, 0);-- /* Standard ustar doesn't support atime. */- archive_entry_set_atime(pax_attr_entry, 0, 0);-- /* Standard ustar doesn't support ctime. */- archive_entry_set_ctime(pax_attr_entry, 0, 0);-- r = __archive_write_format_header_ustar(a, paxbuff,- pax_attr_entry, 'x', 1, NULL);-- archive_entry_free(pax_attr_entry);-- /* Note that the 'x' header shouldn't ever fail to format */- if (r < ARCHIVE_WARN) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "archive_write_pax_header: "- "'x' header failed?! This can't happen.\n");- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (ARCHIVE_FATAL);- } else if (r < ret)- ret = r;- r = __archive_write_output(a, paxbuff, 512);- if (r != ARCHIVE_OK) {- sparse_list_clear(pax);- pax->entry_bytes_remaining = 0;- pax->entry_padding = 0;- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (ARCHIVE_FATAL);- }-- pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header));- pax->entry_padding =- 0x1ff & (-(int64_t)pax->entry_bytes_remaining);-- 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. */- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (ARCHIVE_FATAL);- }- /* Pad out the end of the entry. */- r = __archive_write_nulls(a, (size_t)pax->entry_padding);- if (r != ARCHIVE_OK) {- /* If a write fails, we're pretty much toast. */- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (ARCHIVE_FATAL);- }- pax->entry_bytes_remaining = pax->entry_padding = 0;- }-- /* Write the header for main entry. */- r = __archive_write_output(a, ustarbuff, 512);- if (r != ARCHIVE_OK) {- archive_entry_free(entry_main);- archive_string_free(&entry_name);- return (r);- }-- /*- * Inform the client of the on-disk size we're using, so- * they can avoid unnecessarily writing a body for something- * that we're just going to ignore.- */- archive_entry_set_size(entry_original, real_size);- if (pax->sparse_list == NULL && real_size > 0) {- /* This is not a sparse file but we handle its data as- * a sparse block. */- sparse_list_add(pax, 0, real_size);- sparse_total = real_size;- }- pax->entry_padding = 0x1ff & (-(int64_t)sparse_total);- archive_entry_free(entry_main);- archive_string_free(&entry_name);-- return (ret);-}--/*- * We need a valid name for the regular 'ustar' entry. This routine- * tries to hack something more-or-less reasonable.- *- * The approach here tries to preserve leading dir names. We do so by- * working with four sections:- * 1) "prefix" directory names,- * 2) "suffix" directory names,- * 3) inserted dir name (optional),- * 4) filename.- *- * These sections must satisfy the following requirements:- * * Parts 1 & 2 together form an initial portion of the dir name.- * * Part 3 is specified by the caller. (It should not contain a leading- * or trailing '/'.)- * * Part 4 forms an initial portion of the base filename.- * * The filename must be <= 99 chars to fit the ustar 'name' field.- * * Parts 2, 3, 4 together must be <= 99 chars to fit the ustar 'name' fld.- * * Part 1 must be <= 155 chars to fit the ustar 'prefix' field.- * * If the original name ends in a '/', the new name must also end in a '/'- * * Trailing '/.' sequences may be stripped.- *- * Note: Recall that the ustar format does not store the '/' separating- * parts 1 & 2, but does store the '/' separating parts 2 & 3.- */-static char *-build_ustar_entry_name(char *dest, const char *src, size_t src_length,- const char *insert)-{- const char *prefix, *prefix_end;- const char *suffix, *suffix_end;- const char *filename, *filename_end;- char *p;- int need_slash = 0; /* Was there a trailing slash? */- size_t suffix_length = 99;- size_t insert_length;-- /* Length of additional dir element to be added. */- if (insert == NULL)- insert_length = 0;- else- /* +2 here allows for '/' before and after the insert. */- insert_length = strlen(insert) + 2;-- /* Step 0: Quick bailout in a common case. */- if (src_length < 100 && insert == NULL) {- strncpy(dest, src, src_length);- dest[src_length] = '\0';- return (dest);- }-- /* Step 1: Locate filename and enforce the length restriction. */- filename_end = src + src_length;- /* Remove trailing '/' chars and '/.' pairs. */- for (;;) {- if (filename_end > src && filename_end[-1] == '/') {- filename_end --;- need_slash = 1; /* Remember to restore trailing '/'. */- continue;- }- if (filename_end > src + 1 && filename_end[-1] == '.'- && filename_end[-2] == '/') {- filename_end -= 2;- need_slash = 1; /* "foo/." will become "foo/" */- continue;- }- break;- }- if (need_slash)- suffix_length--;- /* Find start of filename. */- filename = filename_end - 1;- while ((filename > src) && (*filename != '/'))- filename --;- if ((*filename == '/') && (filename < filename_end - 1))- filename ++;- /* Adjust filename_end so that filename + insert fits in 99 chars. */- suffix_length -= insert_length;- if (filename_end > filename + suffix_length)- filename_end = filename + suffix_length;- /* Calculate max size for "suffix" section (#3 above). */- suffix_length -= filename_end - filename;-- /* Step 2: Locate the "prefix" section of the dirname, including- * trailing '/'. */- prefix = src;- prefix_end = prefix + 155;- if (prefix_end > filename)- prefix_end = filename;- while (prefix_end > prefix && *prefix_end != '/')- prefix_end--;- if ((prefix_end < filename) && (*prefix_end == '/'))- prefix_end++;-- /* Step 3: Locate the "suffix" section of the dirname,- * including trailing '/'. */- suffix = prefix_end;- suffix_end = suffix + suffix_length; /* Enforce limit. */- if (suffix_end > filename)- suffix_end = filename;- if (suffix_end < suffix)- suffix_end = suffix;- while (suffix_end > suffix && *suffix_end != '/')- suffix_end--;- if ((suffix_end < filename) && (*suffix_end == '/'))- suffix_end++;-- /* Step 4: Build the new name. */- /* The OpenBSD strlcpy function is safer, but less portable. */- /* Rather than maintain two versions, just use the strncpy version. */- p = dest;- if (prefix_end > prefix) {- strncpy(p, prefix, prefix_end - prefix);- p += prefix_end - prefix;- }- if (suffix_end > suffix) {- strncpy(p, suffix, suffix_end - suffix);- p += suffix_end - suffix;- }- if (insert != NULL) {- /* Note: assume insert does not have leading or trailing '/' */- strcpy(p, insert);- p += strlen(insert);- *p++ = '/';- }- strncpy(p, filename, filename_end - filename);- p += filename_end - filename;- if (need_slash)- *p++ = '/';- *p = '\0';-- return (dest);-}--/*- * The ustar header for the pax extended attributes must have a- * reasonable name: SUSv3 requires 'dirname'/PaxHeader.'pid'/'filename'- * where 'pid' is the PID of the archiving process. Unfortunately,- * that makes testing a pain since the output varies for each run,- * so I'm sticking with the simpler 'dirname'/PaxHeader/'filename'- * for now. (Someday, I'll make this settable. Then I can use the- * SUS recommendation as default and test harnesses can override it- * to get predictable results.)- *- * Joerg Schilling has argued that this is unnecessary because, in- * practice, if the pax extended attributes get extracted as regular- * files, no one is going to bother reading those attributes to- * manually restore them. Based on this, 'star' uses- * /tmp/PaxHeader/'basename' as the ustar header name. This is a- * tempting argument, in part because it's simpler than the SUSv3- * recommendation, but I'm not entirely convinced. I'm also- * uncomfortable with the fact that "/tmp" is a Unix-ism.- *- * The following routine leverages build_ustar_entry_name() above and- * so is simpler than you might think. It just needs to provide the- * additional path element and handle a few pathological cases).- */-static char *-build_pax_attribute_name(char *dest, const char *src)-{- char buff[64];- const char *p;-- /* Handle the null filename case. */- if (src == NULL || *src == '\0') {- strcpy(dest, "PaxHeader/blank");- return (dest);- }-- /* Prune final '/' and other unwanted final elements. */- p = src + strlen(src);- for (;;) {- /* Ends in "/", remove the '/' */- if (p > src && p[-1] == '/') {- --p;- continue;- }- /* Ends in "/.", remove the '.' */- if (p > src + 1 && p[-1] == '.'- && p[-2] == '/') {- --p;- continue;- }- break;- }-- /* Pathological case: After above, there was nothing left.- * This includes "/." "/./." "/.//./." etc. */- if (p == src) {- strcpy(dest, "/PaxHeader/rootdir");- return (dest);- }-- /* Convert unadorned "." into a suitable filename. */- if (*src == '.' && p == src + 1) {- strcpy(dest, "PaxHeader/currentdir");- return (dest);- }-- /*- * TODO: Push this string into the 'pax' structure to avoid- * recomputing it every time. That will also open the door- * to having clients override it.- */-#if HAVE_GETPID && 0 /* Disable this for now; see above comment. */- snprintf(buff, sizeof(buff), "PaxHeader.%d", getpid());-#else- /* If the platform can't fetch the pid, don't include it. */- strcpy(buff, "PaxHeader");-#endif- /* General case: build a ustar-compatible name adding- * "/PaxHeader/". */- build_ustar_entry_name(dest, src, p - src, buff);-- return (dest);-}--/*- * GNU PAX Format 1.0 requires the special name, which pattern is:- * <dir>/GNUSparseFile.<pid>/<original file name>- *- * Since reproducible archives are more important, use 0 as pid.- *- * This function is used for only Sparse file, a file type of which- * is regular file.- */-static char *-build_gnu_sparse_name(char *dest, const char *src)-{- const char *p;-- /* Handle the null filename case. */- if (src == NULL || *src == '\0') {- strcpy(dest, "GNUSparseFile/blank");- return (dest);- }-- /* Prune final '/' and other unwanted final elements. */- p = src + strlen(src);- for (;;) {- /* Ends in "/", remove the '/' */- if (p > src && p[-1] == '/') {- --p;- continue;- }- /* Ends in "/.", remove the '.' */- if (p > src + 1 && p[-1] == '.'- && p[-2] == '/') {- --p;- continue;- }- break;- }-- /* General case: build a ustar-compatible name adding- * "/GNUSparseFile/". */- build_ustar_entry_name(dest, src, p - src, "GNUSparseFile.0");-- return (dest);-}--/* Write two null blocks for the end of archive */-static int-archive_write_pax_close(struct archive_write *a)-{- return (__archive_write_nulls(a, 512 * 2));-}--static int-archive_write_pax_free(struct archive_write *a)-{- struct pax *pax;-- pax = (struct pax *)a->format_data;- if (pax == NULL)- return (ARCHIVE_OK);-- archive_string_free(&pax->pax_header);- archive_string_free(&pax->sparse_map);- archive_string_free(&pax->l_url_encoded_name);- sparse_list_clear(pax);- free(pax);- a->format_data = NULL;- return (ARCHIVE_OK);-}--static int-archive_write_pax_finish_entry(struct archive_write *a)-{- struct pax *pax;- uint64_t remaining;- int ret;-- pax = (struct pax *)a->format_data;- remaining = pax->entry_bytes_remaining;- if (remaining == 0) {- while (pax->sparse_list) {- struct sparse_block *sb;- if (!pax->sparse_list->is_hole)- remaining += pax->sparse_list->remaining;- sb = pax->sparse_list->next;- free(pax->sparse_list);- pax->sparse_list = sb;- }- }- ret = __archive_write_nulls(a, (size_t)(remaining + pax->entry_padding));- pax->entry_bytes_remaining = pax->entry_padding = 0;- return (ret);-}--static ssize_t-archive_write_pax_data(struct archive_write *a, const void *buff, size_t s)-{- struct pax *pax;- size_t ws;- size_t total;- int ret;-- pax = (struct pax *)a->format_data;-- /*- * According to GNU PAX format 1.0, write a sparse map- * before the body.- */- if (archive_strlen(&(pax->sparse_map))) {- ret = __archive_write_output(a, pax->sparse_map.s,- archive_strlen(&(pax->sparse_map)));- if (ret != ARCHIVE_OK)- return (ret);- ret = __archive_write_nulls(a, pax->sparse_map_padding);- if (ret != ARCHIVE_OK)- return (ret);- archive_string_empty(&(pax->sparse_map));- }-- total = 0;- while (total < s) {- const unsigned char *p;-- while (pax->sparse_list != NULL &&- pax->sparse_list->remaining == 0) {- struct sparse_block *sb = pax->sparse_list->next;- free(pax->sparse_list);- pax->sparse_list = sb;- }-- if (pax->sparse_list == NULL)- return (total);-- p = ((const unsigned char *)buff) + total;- ws = s - total;- if (ws > pax->sparse_list->remaining)- ws = (size_t)pax->sparse_list->remaining;-- if (pax->sparse_list->is_hole) {- /* Current block is hole thus we do not write- * the body. */- pax->sparse_list->remaining -= ws;- total += ws;- continue;- }-- ret = __archive_write_output(a, p, ws);- pax->sparse_list->remaining -= ws;- total += ws;- if (ret != ARCHIVE_OK)- return (ret);- }- return (total);-}--static int-has_non_ASCII(const char *_p)-{- const unsigned char *p = (const unsigned char *)_p;-- if (p == NULL)- return (1);- while (*p != '\0' && *p < 128)- p++;- return (*p != '\0');-}--/*- * Used by extended attribute support; encodes the name- * so that there will be no '=' characters in the result.- */-static char *-url_encode(const char *in)-{- const char *s;- char *d;- int out_len = 0;- char *out;-- for (s = in; *s != '\0'; s++) {- if (*s < 33 || *s > 126 || *s == '%' || *s == '=')- out_len += 3;- else- out_len++;- }-- out = (char *)malloc(out_len + 1);- if (out == NULL)- return (NULL);-- for (s = in, d = out; *s != '\0'; s++) {- /* encode any non-printable ASCII character or '%' or '=' */- if (*s < 33 || *s > 126 || *s == '%' || *s == '=') {- /* URL encoding is '%' followed by two hex digits */- *d++ = '%';- *d++ = "0123456789ABCDEF"[0x0f & (*s >> 4)];- *d++ = "0123456789ABCDEF"[0x0f & *s];- } else {- *d++ = *s;- }- }- *d = '\0';- return (out);-}--/*- * Encode a sequence of bytes into a C string using base-64 encoding.- *- * Returns a null-terminated C string allocated with malloc(); caller- * is responsible for freeing the result.- */-static char *-base64_encode(const char *s, size_t len)-{- static const char digits[64] =- { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',- 'P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d',- 'e','f','g','h','i','j','k','l','m','n','o','p','q','r','s',- 't','u','v','w','x','y','z','0','1','2','3','4','5','6','7',- '8','9','+','/' };- int v;- char *d, *out;-- /* 3 bytes becomes 4 chars, but round up and allow for trailing NUL */- out = (char *)malloc((len * 4 + 2) / 3 + 1);- if (out == NULL)- return (NULL);- d = out;-- /* Convert each group of 3 bytes into 4 characters. */- while (len >= 3) {- v = (((int)s[0] << 16) & 0xff0000)- | (((int)s[1] << 8) & 0xff00)- | (((int)s[2]) & 0x00ff);- s += 3;- len -= 3;- *d++ = digits[(v >> 18) & 0x3f];- *d++ = digits[(v >> 12) & 0x3f];- *d++ = digits[(v >> 6) & 0x3f];- *d++ = digits[(v) & 0x3f];- }- /* Handle final group of 1 byte (2 chars) or 2 bytes (3 chars). */- switch (len) {- case 0: break;- case 1:- v = (((int)s[0] << 16) & 0xff0000);- *d++ = digits[(v >> 18) & 0x3f];- *d++ = digits[(v >> 12) & 0x3f];- break;- case 2:- v = (((int)s[0] << 16) & 0xff0000)- | (((int)s[1] << 8) & 0xff00);- *d++ = digits[(v >> 18) & 0x3f];- *d++ = digits[(v >> 12) & 0x3f];- *d++ = digits[(v >> 6) & 0x3f];- break;- }- /* Add trailing NUL character so output is a valid C string. */- *d = '\0';- return (out);-}--static void-sparse_list_clear(struct pax *pax)-{- while (pax->sparse_list != NULL) {- struct sparse_block *sb = pax->sparse_list;- pax->sparse_list = sb->next;- free(sb);- }- pax->sparse_tail = NULL;-}--static int-_sparse_list_add_block(struct pax *pax, int64_t offset, int64_t length,- int is_hole)-{- struct sparse_block *sb;-- sb = (struct sparse_block *)malloc(sizeof(*sb));- if (sb == NULL)- return (ARCHIVE_FATAL);- sb->next = NULL;- sb->is_hole = is_hole;- sb->offset = offset;- sb->remaining = length;- if (pax->sparse_list == NULL || pax->sparse_tail == NULL)- pax->sparse_list = pax->sparse_tail = sb;- else {- pax->sparse_tail->next = sb;- pax->sparse_tail = sb;- }- return (ARCHIVE_OK);-}--static int-sparse_list_add(struct pax *pax, int64_t offset, int64_t length)-{- int64_t last_offset;- int r;-- if (pax->sparse_tail == NULL)- last_offset = 0;- else {- last_offset = pax->sparse_tail->offset +- pax->sparse_tail->remaining;- }- if (last_offset < offset) {- /* Add a hole block. */- r = _sparse_list_add_block(pax, last_offset,- offset - last_offset, 1);- if (r != ARCHIVE_OK)- return (r);- }- /* Add data block. */- return (_sparse_list_add_block(pax, offset, length, 0));-}--static time_t-get_ustar_max_mtime(void)-{- /*- * Technically, the mtime field in the ustar header can- * support 33 bits. We are using all of them to keep- * tar/test/test_option_C_mtree.c simple and passing after 2038.- * For platforms that use signed 32-bit time values we- * use the 32-bit maximum.- */- if (sizeof(time_t) > sizeof(int32_t))- return (time_t)0x1ffffffff;- else- return (time_t)0x7fffffff;-}
− c/archive_write_set_format_private.h
@@ -1,42 +0,0 @@-/*-- * Copyright (c) 2020 Martin Matuska- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- */--#ifndef ARCHIVE_WRITE_SET_FORMAT_PRIVATE_H_INCLUDED-#define ARCHIVE_WRITE_SET_FORMAT_PRIVATE_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#ifndef __LIBARCHIVE_TEST-#error This header is only to be used internally to libarchive.-#endif-#endif--#include "archive.h"-#include "archive_entry.h"--void __archive_write_entry_filetype_unsupported(struct archive *a,- struct archive_entry *entry, const char *format);-#endif
− c/archive_write_set_format_raw.c
@@ -1,125 +0,0 @@-/*-- * Copyright (c) 2013 Marek Kubica- * 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"--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif--#include "archive_entry.h"-#include "archive_write_private.h"--static ssize_t archive_write_raw_data(struct archive_write *,- const void *buff, size_t s);-static int archive_write_raw_free(struct archive_write *);-static int archive_write_raw_header(struct archive_write *,- struct archive_entry *);--struct raw {- int entries_written;-};--/*- * Set output format to 'raw' format.- */-int-archive_write_set_format_raw(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct raw *raw;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_raw");-- /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);-- raw = (struct raw *)calloc(1, sizeof(*raw));- if (raw == NULL) {- archive_set_error(&a->archive, ENOMEM, "Can't allocate raw data");- return (ARCHIVE_FATAL);- }- raw->entries_written = 0;- a->format_data = raw;- a->format_name = "raw";- /* no options exist for this format */- a->format_options = NULL;- a->format_write_header = archive_write_raw_header;- a->format_write_data = archive_write_raw_data;- a->format_finish_entry = NULL;- /* nothing needs to be done on closing */- a->format_close = NULL;- a->format_free = archive_write_raw_free;- a->archive.archive_format = ARCHIVE_FORMAT_RAW;- a->archive.archive_format_name = "RAW";- return (ARCHIVE_OK);-}--static int-archive_write_raw_header(struct archive_write *a, struct archive_entry *entry)-{- struct raw *raw = (struct raw *)a->format_data;-- if (archive_entry_filetype(entry) != AE_IFREG) {- archive_set_error(&a->archive, ERANGE,- "Raw format only supports filetype AE_IFREG");- return (ARCHIVE_FATAL);- }--- if (raw->entries_written > 0) {- archive_set_error(&a->archive, ERANGE,- "Raw format only supports one entry per archive");- return (ARCHIVE_FATAL);- }- raw->entries_written++;-- return (ARCHIVE_OK);-}--static ssize_t-archive_write_raw_data(struct archive_write *a, const void *buff, size_t s)-{- int ret;-- ret = __archive_write_output(a, buff, s);- if (ret >= 0)- return (s);- else- return (ret);-}--static int-archive_write_raw_free(struct archive_write *a)-{- struct raw *raw;-- raw = (struct raw *)a->format_data;- free(raw);- a->format_data = NULL;- return (ARCHIVE_OK);-}
− c/archive_write_set_format_shar.c
@@ -1,641 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2008 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_format_shar.c 189438 2009-03-06 05:58:56Z 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--#include "archive.h"-#include "archive_entry.h"-#include "archive_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--struct shar {- int dump;- int end_of_line;- struct archive_entry *entry;- int has_data;- char *last_dir;-- /* Line buffer for uuencoded dump format */- char outbuff[45];- size_t outpos;-- int wrote_header;- struct archive_string work;- struct archive_string quoted_name;-};--static int archive_write_shar_close(struct archive_write *);-static int archive_write_shar_free(struct archive_write *);-static int archive_write_shar_header(struct archive_write *,- struct archive_entry *);-static ssize_t archive_write_shar_data_sed(struct archive_write *,- const void * buff, size_t);-static ssize_t archive_write_shar_data_uuencode(struct archive_write *,- const void * buff, size_t);-static int archive_write_shar_finish_entry(struct archive_write *);--/*- * Copy the given string to the buffer, quoting all shell meta characters- * found.- */-static void-shar_quote(struct archive_string *buf, const char *str, int in_shell)-{- static const char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";- size_t len;-- while (*str != '\0') {- if ((len = strcspn(str, meta)) != 0) {- archive_strncat(buf, str, len);- str += len;- } else if (*str == '\n') {- if (in_shell)- archive_strcat(buf, "\"\n\"");- else- archive_strcat(buf, "\\n");- ++str;- } else {- archive_strappend_char(buf, '\\');- archive_strappend_char(buf, *str);- ++str;- }- }-}--/*- * Set output format to 'shar' format.- */-int-archive_write_set_format_shar(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct shar *shar;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_shar");-- /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);-- shar = (struct shar *)calloc(1, sizeof(*shar));- if (shar == NULL) {- archive_set_error(&a->archive, ENOMEM, "Can't allocate shar data");- return (ARCHIVE_FATAL);- }- archive_string_init(&shar->work);- archive_string_init(&shar->quoted_name);- a->format_data = shar;- a->format_name = "shar";- a->format_write_header = archive_write_shar_header;- a->format_close = archive_write_shar_close;- a->format_free = archive_write_shar_free;- a->format_write_data = archive_write_shar_data_sed;- a->format_finish_entry = archive_write_shar_finish_entry;- a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE;- a->archive.archive_format_name = "shar";- return (ARCHIVE_OK);-}--/*- * An alternate 'shar' that uses uudecode instead of 'sed' to encode- * file contents and can therefore be used to archive binary files.- * In addition, this variant also attempts to restore ownership, file modes,- * and other extended file information.- */-int-archive_write_set_format_shar_dump(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct shar *shar;-- archive_write_set_format_shar(&a->archive);- shar = (struct shar *)a->format_data;- shar->dump = 1;- a->format_write_data = archive_write_shar_data_uuencode;- a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP;- a->archive.archive_format_name = "shar dump";- return (ARCHIVE_OK);-}--static int-archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)-{- const char *linkname;- const char *name;- char *p, *pp;- struct shar *shar;-- shar = (struct shar *)a->format_data;- if (!shar->wrote_header) {- archive_strcat(&shar->work, "#!/bin/sh\n");- archive_strcat(&shar->work, "# This is a shell archive\n");- shar->wrote_header = 1;- }-- /* Save the entry for the closing. */- archive_entry_free(shar->entry);- shar->entry = archive_entry_clone(entry);- name = archive_entry_pathname(entry);-- /* Handle some preparatory issues. */- switch(archive_entry_filetype(entry)) {- case AE_IFREG:- /* Only regular files have non-zero size. */- break;- case AE_IFDIR:- archive_entry_set_size(entry, 0);- /* Don't bother trying to recreate '.' */- if (strcmp(name, ".") == 0 || strcmp(name, "./") == 0)- return (ARCHIVE_OK);- break;- case AE_IFIFO:- case AE_IFCHR:- case AE_IFBLK:- /* All other file types have zero size in the archive. */- archive_entry_set_size(entry, 0);- break;- default:- archive_entry_set_size(entry, 0);- if (archive_entry_hardlink(entry) == NULL &&- archive_entry_symlink(entry) == NULL) {- __archive_write_entry_filetype_unsupported(- &a->archive, entry, "shar");- return (ARCHIVE_WARN);- }- }-- archive_string_empty(&shar->quoted_name);- shar_quote(&shar->quoted_name, name, 1);-- /* Stock preparation for all file types. */- archive_string_sprintf(&shar->work, "echo x %s\n", shar->quoted_name.s);-- if (archive_entry_filetype(entry) != AE_IFDIR) {- /* Try to create the dir. */- p = strdup(name);- pp = strrchr(p, '/');- /* If there is a / character, try to create the dir. */- if (pp != NULL) {- *pp = '\0';-- /* Try to avoid a lot of redundant mkdir commands. */- if (strcmp(p, ".") == 0) {- /* Don't try to "mkdir ." */- free(p);- } else if (shar->last_dir == NULL) {- archive_strcat(&shar->work, "mkdir -p ");- shar_quote(&shar->work, p, 1);- archive_strcat(&shar->work,- " > /dev/null 2>&1\n");- shar->last_dir = p;- } else if (strcmp(p, shar->last_dir) == 0) {- /* We've already created this exact dir. */- free(p);- } else if (strlen(p) < strlen(shar->last_dir) &&- strncmp(p, shar->last_dir, strlen(p)) == 0) {- /* We've already created a subdir. */- free(p);- } else {- archive_strcat(&shar->work, "mkdir -p ");- shar_quote(&shar->work, p, 1);- archive_strcat(&shar->work,- " > /dev/null 2>&1\n");- shar->last_dir = p;- }- } else {- free(p);- }- }-- /* Handle file-type specific issues. */- shar->has_data = 0;- if ((linkname = archive_entry_hardlink(entry)) != NULL) {- archive_strcat(&shar->work, "ln -f ");- shar_quote(&shar->work, linkname, 1);- archive_string_sprintf(&shar->work, " %s\n",- shar->quoted_name.s);- } else if ((linkname = archive_entry_symlink(entry)) != NULL) {- archive_strcat(&shar->work, "ln -fs ");- shar_quote(&shar->work, linkname, 1);- archive_string_sprintf(&shar->work, " %s\n",- shar->quoted_name.s);- } else {- switch(archive_entry_filetype(entry)) {- case AE_IFREG:- if (archive_entry_size(entry) == 0) {- /* More portable than "touch." */- archive_string_sprintf(&shar->work,- "test -e \"%s\" || :> \"%s\"\n",- shar->quoted_name.s, shar->quoted_name.s);- } else {- if (shar->dump) {- unsigned int mode = archive_entry_mode(entry) & 0777;- archive_string_sprintf(&shar->work,- "uudecode -p > %s << 'SHAR_END'\n",- shar->quoted_name.s);- archive_string_sprintf(&shar->work,- "begin %o ", mode);- shar_quote(&shar->work, name, 0);- archive_strcat(&shar->work, "\n");- } else {- archive_string_sprintf(&shar->work,- "sed 's/^X//' > %s << 'SHAR_END'\n",- shar->quoted_name.s);- }- shar->has_data = 1;- shar->end_of_line = 1;- shar->outpos = 0;- }- break;- case AE_IFDIR:- archive_string_sprintf(&shar->work,- "mkdir -p %s > /dev/null 2>&1\n",- shar->quoted_name.s);- /* Record that we just created this directory. */- free(shar->last_dir);-- shar->last_dir = strdup(name);- /* Trim a trailing '/'. */- pp = strrchr(shar->last_dir, '/');- if (pp != NULL && pp[1] == '\0')- *pp = '\0';- /*- * TODO: Put dir name/mode on a list to be fixed- * up at end of archive.- */- break;- case AE_IFIFO:- archive_string_sprintf(&shar->work,- "mkfifo %s\n", shar->quoted_name.s);- break;- case AE_IFCHR:- archive_string_sprintf(&shar->work,- "mknod %s c %ju %ju\n", shar->quoted_name.s,- (uintmax_t)archive_entry_rdevmajor(entry),- (uintmax_t)archive_entry_rdevminor(entry));- break;- case AE_IFBLK:- archive_string_sprintf(&shar->work,- "mknod %s b %ju %ju\n", shar->quoted_name.s,- (uintmax_t)archive_entry_rdevmajor(entry),- (uintmax_t)archive_entry_rdevminor(entry));- break;- default:- return (ARCHIVE_WARN);- }- }-- return (ARCHIVE_OK);-}--static ssize_t-archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n)-{- static const size_t ensured = 65533;- struct shar *shar;- const char *src;- char *buf, *buf_end;- int ret;- size_t written = n;-- shar = (struct shar *)a->format_data;- if (!shar->has_data || n == 0)- return (0);-- src = (const char *)buff;-- /*- * ensure is the number of bytes in buffer before expanding the- * current character. Each operation writes the current character- * and optionally the start-of-new-line marker. This can happen- * twice before entering the loop, so make sure three additional- * bytes can be written.- */- if (archive_string_ensure(&shar->work, ensured + 3) == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }-- if (shar->work.length > ensured) {- ret = __archive_write_output(a, shar->work.s,- shar->work.length);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- archive_string_empty(&shar->work);- }- buf = shar->work.s + shar->work.length;- buf_end = shar->work.s + ensured;-- if (shar->end_of_line) {- *buf++ = 'X';- shar->end_of_line = 0;- }-- while (n-- != 0) {- if ((*buf++ = *src++) == '\n') {- if (n == 0)- shar->end_of_line = 1;- else- *buf++ = 'X';- }-- if (buf >= buf_end) {- shar->work.length = buf - shar->work.s;- ret = __archive_write_output(a, shar->work.s,- shar->work.length);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- archive_string_empty(&shar->work);- buf = shar->work.s;- }- }-- shar->work.length = buf - shar->work.s;-- return (written);-}--#define UUENC(c) (((c)!=0) ? ((c) & 077) + ' ': '`')--static void-uuencode_group(const char _in[3], char out[4])-{- const unsigned char *in = (const unsigned char *)_in;- int t;-- t = (in[0] << 16) | (in[1] << 8) | in[2];- out[0] = UUENC( 0x3f & (t >> 18) );- out[1] = UUENC( 0x3f & (t >> 12) );- out[2] = UUENC( 0x3f & (t >> 6) );- out[3] = UUENC( 0x3f & t );-}--static int-_uuencode_line(struct archive_write *a, struct shar *shar, const char *inbuf, size_t len)-{- char *buf;- size_t alloc_len;-- /* len <= 45 -> expanded to 60 + len byte + new line */- alloc_len = shar->work.length + 62;- if (archive_string_ensure(&shar->work, alloc_len) == NULL) {- archive_set_error(&a->archive, ENOMEM, "Out of memory");- return (ARCHIVE_FATAL);- }-- buf = shar->work.s + shar->work.length;- *buf++ = UUENC(len);- while (len >= 3) {- uuencode_group(inbuf, buf);- len -= 3;- inbuf += 3;- buf += 4;- }- if (len != 0) {- char tmp_buf[3];- tmp_buf[0] = inbuf[0];- if (len == 1)- tmp_buf[1] = '\0';- else- tmp_buf[1] = inbuf[1];- tmp_buf[2] = '\0';- uuencode_group(tmp_buf, buf);- buf += 4;- }- *buf++ = '\n';- if ((buf - shar->work.s) > (ptrdiff_t)(shar->work.length + 62)) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC, "Buffer overflow");- return (ARCHIVE_FATAL);- }- shar->work.length = buf - shar->work.s;- return (ARCHIVE_OK);-}--#define uuencode_line(__a, __shar, __inbuf, __len) \- do { \- int r = _uuencode_line(__a, __shar, __inbuf, __len); \- if (r != ARCHIVE_OK) \- return (ARCHIVE_FATAL); \- } while (0)--static ssize_t-archive_write_shar_data_uuencode(struct archive_write *a, const void *buff,- size_t length)-{- struct shar *shar;- const char *src;- size_t n;- int ret;-- shar = (struct shar *)a->format_data;- if (!shar->has_data)- return (ARCHIVE_OK);- src = (const char *)buff;-- if (shar->outpos != 0) {- n = 45 - shar->outpos;- if (n > length)- n = length;- memcpy(shar->outbuff + shar->outpos, src, n);- if (shar->outpos + n < 45) {- shar->outpos += n;- return length;- }- uuencode_line(a, shar, shar->outbuff, 45);- src += n;- n = length - n;- } else {- n = length;- }-- while (n >= 45) {- uuencode_line(a, shar, src, 45);- src += 45;- n -= 45;-- if (shar->work.length < 65536)- continue;- ret = __archive_write_output(a, shar->work.s,- shar->work.length);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- archive_string_empty(&shar->work);- }- if (n != 0) {- memcpy(shar->outbuff, src, n);- shar->outpos = n;- }- return (length);-}--static int-archive_write_shar_finish_entry(struct archive_write *a)-{- const char *g, *p, *u;- struct shar *shar;- int ret;-- shar = (struct shar *)a->format_data;- if (shar->entry == NULL)- return (0);-- if (shar->dump) {- /* Finish uuencoded data. */- if (shar->has_data) {- if (shar->outpos > 0)- uuencode_line(a, shar, shar->outbuff,- shar->outpos);- archive_strcat(&shar->work, "`\nend\n");- archive_strcat(&shar->work, "SHAR_END\n");- }- /* Restore file mode, owner, flags. */- /*- * TODO: Don't immediately restore mode for- * directories; defer that to end of script.- */- archive_string_sprintf(&shar->work, "chmod %o ",- (unsigned int)(archive_entry_mode(shar->entry) & 07777));- shar_quote(&shar->work, archive_entry_pathname(shar->entry), 1);- archive_strcat(&shar->work, "\n");-- u = archive_entry_uname(shar->entry);- g = archive_entry_gname(shar->entry);- if (u != NULL || g != NULL) {- archive_strcat(&shar->work, "chown ");- if (u != NULL)- shar_quote(&shar->work, u, 1);- if (g != NULL) {- archive_strcat(&shar->work, ":");- shar_quote(&shar->work, g, 1);- }- archive_strcat(&shar->work, " ");- shar_quote(&shar->work,- archive_entry_pathname(shar->entry), 1);- archive_strcat(&shar->work, "\n");- }-- if ((p = archive_entry_fflags_text(shar->entry)) != NULL) {- archive_string_sprintf(&shar->work, "chflags %s ", p);- shar_quote(&shar->work,- archive_entry_pathname(shar->entry), 1);- archive_strcat(&shar->work, "\n");- }-- /* TODO: restore ACLs */-- } else {- if (shar->has_data) {- /* Finish sed-encoded data: ensure last line ends. */- if (!shar->end_of_line)- archive_strappend_char(&shar->work, '\n');- archive_strcat(&shar->work, "SHAR_END\n");- }- }-- archive_entry_free(shar->entry);- shar->entry = NULL;-- if (shar->work.length < 65536)- return (ARCHIVE_OK);-- ret = __archive_write_output(a, shar->work.s, shar->work.length);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- archive_string_empty(&shar->work);-- return (ARCHIVE_OK);-}--static int-archive_write_shar_close(struct archive_write *a)-{- struct shar *shar;- int ret;-- /*- * TODO: Accumulate list of directory names/modes and- * fix them all up at end-of-archive.- */-- shar = (struct shar *)a->format_data;-- /*- * Only write the end-of-archive markers if the archive was- * actually started. This avoids problems if someone sets- * shar format, then sets another format (which would invoke- * shar_finish to free the format-specific data).- */- if (shar->wrote_header == 0)- return (ARCHIVE_OK);-- archive_strcat(&shar->work, "exit\n");-- ret = __archive_write_output(a, shar->work.s, shar->work.length);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);-- /* Shar output is never padded. */- archive_write_set_bytes_in_last_block(&a->archive, 1);- /*- * TODO: shar should also suppress padding of- * uncompressed data within gzip/bzip2 streams.- */-- return (ARCHIVE_OK);-}--static int-archive_write_shar_free(struct archive_write *a)-{- struct shar *shar;-- shar = (struct shar *)a->format_data;- if (shar == NULL)- return (ARCHIVE_OK);-- archive_entry_free(shar->entry);- free(shar->last_dir);- archive_string_free(&(shar->work));- archive_string_free(&(shar->quoted_name));- free(shar);- a->format_data = NULL;- return (ARCHIVE_OK);-}
− c/archive_write_set_format_ustar.c
@@ -1,758 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_ustar.c 191579 2009-04-27 18:35:03Z 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--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--struct ustar {- uint64_t entry_bytes_remaining;- uint64_t entry_padding;-- struct archive_string_conv *opt_sconv;- struct archive_string_conv *sconv_default;- int init_default_conversion;-};--/*- * Define structure of POSIX 'ustar' tar header.- */-#define USTAR_name_offset 0-#define USTAR_name_size 100-#define USTAR_mode_offset 100-#define USTAR_mode_size 6-#define USTAR_mode_max_size 8-#define USTAR_uid_offset 108-#define USTAR_uid_size 6-#define USTAR_uid_max_size 8-#define USTAR_gid_offset 116-#define USTAR_gid_size 6-#define USTAR_gid_max_size 8-#define USTAR_size_offset 124-#define USTAR_size_size 11-#define USTAR_size_max_size 12-#define USTAR_mtime_offset 136-#define USTAR_mtime_size 11-#define USTAR_mtime_max_size 11-#define USTAR_checksum_offset 148-#define USTAR_checksum_size 8-#define USTAR_typeflag_offset 156-#define USTAR_typeflag_size 1-#define USTAR_linkname_offset 157-#define USTAR_linkname_size 100-#define USTAR_magic_offset 257-#define USTAR_magic_size 6-#define USTAR_version_offset 263-#define USTAR_version_size 2-#define USTAR_uname_offset 265-#define USTAR_uname_size 32-#define USTAR_gname_offset 297-#define USTAR_gname_size 32-#define USTAR_rdevmajor_offset 329-#define USTAR_rdevmajor_size 6-#define USTAR_rdevmajor_max_size 8-#define USTAR_rdevminor_offset 337-#define USTAR_rdevminor_size 6-#define USTAR_rdevminor_max_size 8-#define USTAR_prefix_offset 345-#define USTAR_prefix_size 155-#define USTAR_padding_offset 500-#define USTAR_padding_size 12--/*- * A filled-in copy of the header for initialization.- */-static const char template_header[] = {- /* name: 100 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,- /* Mode, space-null termination: 8 bytes */- '0','0','0','0','0','0', ' ','\0',- /* uid, space-null termination: 8 bytes */- '0','0','0','0','0','0', ' ','\0',- /* gid, space-null termination: 8 bytes */- '0','0','0','0','0','0', ' ','\0',- /* size, space termination: 12 bytes */- '0','0','0','0','0','0','0','0','0','0','0', ' ',- /* mtime, space termination: 12 bytes */- '0','0','0','0','0','0','0','0','0','0','0', ' ',- /* Initial checksum value: 8 spaces */- ' ',' ',' ',' ',' ',' ',' ',' ',- /* Typeflag: 1 byte */- '0', /* '0' = regular file */- /* Linkname: 100 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,- /* Magic: 6 bytes, Version: 2 bytes */- 'u','s','t','a','r','\0', '0','0',- /* Uname: 32 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- /* Gname: 32 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- /* rdevmajor + space/null padding: 8 bytes */- '0','0','0','0','0','0', ' ','\0',- /* rdevminor + space/null padding: 8 bytes */- '0','0','0','0','0','0', ' ','\0',- /* Prefix: 155 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,- /* Padding: 12 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0-};--static ssize_t archive_write_ustar_data(struct archive_write *a, const void *buff,- size_t s);-static int archive_write_ustar_free(struct archive_write *);-static int archive_write_ustar_close(struct archive_write *);-static int archive_write_ustar_finish_entry(struct archive_write *);-static int archive_write_ustar_header(struct archive_write *,- struct archive_entry *entry);-static int archive_write_ustar_options(struct archive_write *,- const char *, const char *);-static int format_256(int64_t, char *, int);-static int format_number(int64_t, char *, int size, int max, int strict);-static int format_octal(int64_t, char *, int);--/*- * Set output format to 'ustar' format.- */-int-archive_write_set_format_ustar(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct ustar *ustar;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_ustar");-- /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);-- /* Basic internal sanity test. */- if (sizeof(template_header) != 512) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Internal: template_header wrong size: %zu should be 512",- sizeof(template_header));- return (ARCHIVE_FATAL);- }-- ustar = (struct ustar *)calloc(1, sizeof(*ustar));- if (ustar == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ustar data");- return (ARCHIVE_FATAL);- }- a->format_data = ustar;- a->format_name = "ustar";- a->format_options = archive_write_ustar_options;- a->format_write_header = archive_write_ustar_header;- a->format_write_data = archive_write_ustar_data;- a->format_close = archive_write_ustar_close;- a->format_free = archive_write_ustar_free;- a->format_finish_entry = archive_write_ustar_finish_entry;- a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR;- a->archive.archive_format_name = "POSIX ustar";- return (ARCHIVE_OK);-}--static int-archive_write_ustar_options(struct archive_write *a, const char *key,- const char *val)-{- struct ustar *ustar = (struct ustar *)a->format_data;- int ret = ARCHIVE_FAILED;-- if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: hdrcharset option needs a character-set name",- a->format_name);- else {- ustar->opt_sconv = archive_string_conversion_to_charset(- &a->archive, val, 0);- if (ustar->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)-{- char buff[512];- int ret, ret2;- struct ustar *ustar;- struct archive_entry *entry_main;- struct archive_string_conv *sconv;-- ustar = (struct ustar *)a->format_data;-- /* Setup default string conversion. */- if (ustar->opt_sconv == NULL) {- if (!ustar->init_default_conversion) {- ustar->sconv_default =- archive_string_default_conversion_for_write(&(a->archive));- ustar->init_default_conversion = 1;- }- sconv = ustar->sconv_default;- } else- sconv = ustar->opt_sconv;-- /* Sanity check. */- if (archive_entry_pathname(entry) == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't record entry in tar file without pathname");- return (ARCHIVE_FAILED);- }-- /* Only regular files (not hardlinks) have data. */- if (archive_entry_hardlink(entry) != NULL ||- archive_entry_symlink(entry) != NULL ||- !(archive_entry_filetype(entry) == AE_IFREG))- archive_entry_set_size(entry, 0);-- if (AE_IFDIR == archive_entry_filetype(entry)) {- const char *p;- size_t path_length;- /*- * Ensure a trailing '/'. Modify the entry so- * the client sees the change.- */-#if defined(_WIN32) && !defined(__CYGWIN__)- const wchar_t *wp;-- wp = archive_entry_pathname_w(entry);- if (wp != NULL && wp[wcslen(wp) -1] != L'/') {- struct archive_wstring ws;-- archive_string_init(&ws);- path_length = wcslen(wp);- if (archive_wstring_ensure(&ws,- path_length + 2) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ustar data");- archive_wstring_free(&ws);- return(ARCHIVE_FATAL);- }- /* Should we keep '\' ? */- if (wp[path_length -1] == L'\\')- path_length--;- archive_wstrncpy(&ws, wp, path_length);- archive_wstrappend_wchar(&ws, L'/');- archive_entry_copy_pathname_w(entry, ws.s);- archive_wstring_free(&ws);- p = NULL;- } else-#endif- p = archive_entry_pathname(entry);- /*- * On Windows, this is a backup operation just in- * case getting WCS failed. On POSIX, this is a- * normal operation.- */- if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {- struct archive_string as;-- archive_string_init(&as);- path_length = strlen(p);- if (archive_string_ensure(&as,- path_length + 2) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ustar data");- archive_string_free(&as);- return(ARCHIVE_FATAL);- }-#if defined(_WIN32) && !defined(__CYGWIN__)- /* NOTE: This might break the pathname- * if the current code page is CP932 and- * the pathname includes a character '\'- * as a part of its multibyte pathname. */- if (p[strlen(p) -1] == '\\')- path_length--;- else-#endif- archive_strncpy(&as, p, path_length);- archive_strappend_char(&as, '/');- archive_entry_copy_pathname(entry, as.s);- archive_string_free(&as);- }- }--#if defined(_WIN32) && !defined(__CYGWIN__)- /* Make sure the path separators in pathname, hardlink and symlink- * are all slash '/', not the Windows path separator '\'. */- entry_main = __la_win_entry_in_posix_pathseparator(entry);- if (entry_main == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate ustar data");- return(ARCHIVE_FATAL);- }- if (entry != entry_main)- entry = entry_main;- else- entry_main = NULL;-#else- entry_main = NULL;-#endif- ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1, sconv);- if (ret < ARCHIVE_WARN) {- archive_entry_free(entry_main);- return (ret);- }- ret2 = __archive_write_output(a, buff, 512);- if (ret2 < ARCHIVE_WARN) {- archive_entry_free(entry_main);- return (ret2);- }- if (ret2 < ret)- ret = ret2;-- ustar->entry_bytes_remaining = archive_entry_size(entry);- ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining);- archive_entry_free(entry_main);- return (ret);-}--/*- * Format a basic 512-byte "ustar" header.- *- * Returns -1 if format failed (due to field overflow).- * Note that this always formats as much of the header as possible.- * If "strict" is set to zero, it will extend numeric fields as- * necessary (overwriting terminators or using base-256 extensions).- *- * This is exported so that other 'tar' formats can use it.- */-int-__archive_write_format_header_ustar(struct archive_write *a, char h[512],- struct archive_entry *entry, int tartype, int strict,- struct archive_string_conv *sconv)-{- unsigned int checksum;- int i, r, ret;- size_t copy_length;- const char *p, *pp;- int mytartype;-- ret = 0;- mytartype = -1;- /*- * The "template header" already includes the "ustar"- * signature, various end-of-field markers and other required- * elements.- */- memcpy(h, &template_header, 512);-- /*- * Because the block is already null-filled, and strings- * are allowed to exactly fill their destination (without null),- * I use memcpy(dest, src, strlen()) here a lot to copy strings.- */- r = archive_entry_pathname_l(entry, &pp, ©_length, sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate pathname '%s' to %s",- pp, archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- }- if (copy_length <= USTAR_name_size)- memcpy(h + USTAR_name_offset, pp, copy_length);- else {- /* Store in two pieces, splitting at a '/'. */- p = strchr(pp + copy_length - USTAR_name_size - 1, '/');- /*- * Look for the next '/' if we chose the first character- * as the separator. (ustar format doesn't permit- * an empty prefix.)- */- if (p == pp)- p = strchr(p + 1, '/');- /* Fail if the name won't fit. */- if (!p) {- /* No separator. */- archive_set_error(&a->archive, ENAMETOOLONG,- "Pathname too long");- ret = ARCHIVE_FAILED;- } else if (p[1] == '\0') {- /*- * The only feasible separator is a final '/';- * this would result in a non-empty prefix and- * an empty name, which POSIX doesn't- * explicitly forbid, but it just feels wrong.- */- archive_set_error(&a->archive, ENAMETOOLONG,- "Pathname too long");- ret = ARCHIVE_FAILED;- } else if (p > pp + USTAR_prefix_size) {- /* Prefix is too long. */- archive_set_error(&a->archive, ENAMETOOLONG,- "Pathname too long");- ret = ARCHIVE_FAILED;- } else {- /* Copy prefix and remainder to appropriate places */- memcpy(h + USTAR_prefix_offset, pp, p - pp);- memcpy(h + USTAR_name_offset, p + 1,- pp + copy_length - p - 1);- }- }-- r = archive_entry_hardlink_l(entry, &p, ©_length, sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s",- p, archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- }- if (copy_length > 0)- mytartype = '1';- else {- r = archive_entry_symlink_l(entry, &p, ©_length, sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s",- p, archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- }- }- if (copy_length > 0) {- if (copy_length > USTAR_linkname_size) {- archive_set_error(&a->archive, ENAMETOOLONG,- "Link contents too long");- ret = ARCHIVE_FAILED;- copy_length = USTAR_linkname_size;- }- memcpy(h + USTAR_linkname_offset, p, copy_length);- }-- r = archive_entry_uname_l(entry, &p, ©_length, sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Uname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate uname '%s' to %s",- p, archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- }- if (copy_length > 0) {- if (copy_length > USTAR_uname_size) {- if (tartype != 'x') {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC, "Username too long");- ret = ARCHIVE_FAILED;- }- copy_length = USTAR_uname_size;- }- memcpy(h + USTAR_uname_offset, p, copy_length);- }-- r = archive_entry_gname_l(entry, &p, ©_length, sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Gname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate gname '%s' to %s",- p, archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- }- if (copy_length > 0) {- if (strlen(p) > USTAR_gname_size) {- if (tartype != 'x') {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC, "Group name too long");- ret = ARCHIVE_FAILED;- }- copy_length = USTAR_gname_size;- }- memcpy(h + USTAR_gname_offset, p, copy_length);- }-- if (format_number(archive_entry_mode(entry) & 07777,- h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "Numeric mode too large");- ret = ARCHIVE_FAILED;- }-- if (format_number(archive_entry_uid(entry),- h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "Numeric user ID too large");- ret = ARCHIVE_FAILED;- }-- if (format_number(archive_entry_gid(entry),- h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "Numeric group ID too large");- ret = ARCHIVE_FAILED;- }-- if (format_number(archive_entry_size(entry),- h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "File size out of range");- ret = ARCHIVE_FAILED;- }-- if (format_number(archive_entry_mtime(entry),- h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "File modification time too large");- ret = ARCHIVE_FAILED;- }-- if (archive_entry_filetype(entry) == AE_IFBLK- || archive_entry_filetype(entry) == AE_IFCHR) {- if (format_number(archive_entry_rdevmajor(entry),- h + USTAR_rdevmajor_offset, USTAR_rdevmajor_size,- USTAR_rdevmajor_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "Major device number too large");- ret = ARCHIVE_FAILED;- }-- if (format_number(archive_entry_rdevminor(entry),- h + USTAR_rdevminor_offset, USTAR_rdevminor_size,- USTAR_rdevminor_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "Minor device number too large");- ret = ARCHIVE_FAILED;- }- }-- if (tartype >= 0) {- h[USTAR_typeflag_offset] = tartype;- } else if (mytartype >= 0) {- h[USTAR_typeflag_offset] = mytartype;- } else {- switch (archive_entry_filetype(entry)) {- case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break;- case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break;- case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break;- case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break;- case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break;- case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break;- default: /* AE_IFSOCK and unknown */- __archive_write_entry_filetype_unsupported(- &a->archive, entry, "ustar");- ret = ARCHIVE_FAILED;- }- }-- checksum = 0;- for (i = 0; i < 512; i++)- checksum += 255 & (unsigned int)h[i];- h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */- /* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */- format_octal(checksum, h + USTAR_checksum_offset, 6);- return (ret);-}--/*- * Format a number into a field, with some intelligence.- */-static int-format_number(int64_t v, char *p, int s, int maxsize, int strict)-{- int64_t limit;-- limit = ((int64_t)1 << (s*3));-- /* "Strict" only permits octal values with proper termination. */- if (strict)- return (format_octal(v, p, s));-- /*- * In non-strict mode, we allow the number to overwrite one or- * more bytes of the field termination. Even old tar- * implementations should be able to handle this with no- * problem.- */- if (v >= 0) {- while (s <= maxsize) {- if (v < limit)- return (format_octal(v, p, s));- s++;- limit <<= 3;- }- }-- /* Base-256 can handle any number, positive or negative. */- return (format_256(v, p, maxsize));-}--/*- * Format a number into the specified field using base-256.- */-static int-format_256(int64_t v, char *p, int s)-{- p += s;- while (s-- > 0) {- *--p = (char)(v & 0xff);- v >>= 8;- }- *p |= 0x80; /* Set the base-256 marker bit. */- return (0);-}--/*- * Format a number into the specified field.- */-static int-format_octal(int64_t v, char *p, int s)-{- int len;-- len = s;-- /* Octal values can't be negative, so use 0. */- if (v < 0) {- while (len-- > 0)- *p++ = '0';- return (-1);- }-- p += s; /* Start at the end and work backwards. */- while (s-- > 0) {- *--p = (char)('0' + (v & 7));- v >>= 3;- }-- if (v == 0)- return (0);-- /* If it overflowed, fill field with max value. */- while (len-- > 0)- *p++ = '7';-- return (-1);-}--static int-archive_write_ustar_close(struct archive_write *a)-{- return (__archive_write_nulls(a, 512*2));-}--static int-archive_write_ustar_free(struct archive_write *a)-{- struct ustar *ustar;-- ustar = (struct ustar *)a->format_data;- free(ustar);- a->format_data = NULL;- return (ARCHIVE_OK);-}--static int-archive_write_ustar_finish_entry(struct archive_write *a)-{- struct ustar *ustar;- int ret;-- ustar = (struct ustar *)a->format_data;- ret = __archive_write_nulls(a,- (size_t)(ustar->entry_bytes_remaining + ustar->entry_padding));- ustar->entry_bytes_remaining = ustar->entry_padding = 0;- return (ret);-}--static ssize_t-archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)-{- struct ustar *ustar;- int ret;-- ustar = (struct ustar *)a->format_data;- if (s > ustar->entry_bytes_remaining)- s = (size_t)ustar->entry_bytes_remaining;- ret = __archive_write_output(a, buff, s);- ustar->entry_bytes_remaining -= s;- if (ret != ARCHIVE_OK)- return (ret);- return (s);-}
− c/archive_write_set_format_v7tar.c
@@ -1,638 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * Copyright (c) 2011-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");---#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--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--struct v7tar {- uint64_t entry_bytes_remaining;- uint64_t entry_padding;-- struct archive_string_conv *opt_sconv;- struct archive_string_conv *sconv_default;- int init_default_conversion;-};--/*- * Define structure of POSIX 'v7tar' tar header.- */-#define V7TAR_name_offset 0-#define V7TAR_name_size 100-#define V7TAR_mode_offset 100-#define V7TAR_mode_size 6-#define V7TAR_mode_max_size 8-#define V7TAR_uid_offset 108-#define V7TAR_uid_size 6-#define V7TAR_uid_max_size 8-#define V7TAR_gid_offset 116-#define V7TAR_gid_size 6-#define V7TAR_gid_max_size 8-#define V7TAR_size_offset 124-#define V7TAR_size_size 11-#define V7TAR_size_max_size 12-#define V7TAR_mtime_offset 136-#define V7TAR_mtime_size 11-#define V7TAR_mtime_max_size 12-#define V7TAR_checksum_offset 148-#define V7TAR_checksum_size 8-#define V7TAR_typeflag_offset 156-#define V7TAR_typeflag_size 1-#define V7TAR_linkname_offset 157-#define V7TAR_linkname_size 100-#define V7TAR_padding_offset 257-#define V7TAR_padding_size 255--/*- * A filled-in copy of the header for initialization.- */-static const char template_header[] = {- /* name: 100 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,- /* Mode, space-null termination: 8 bytes */- '0','0','0','0','0','0', ' ','\0',- /* uid, space-null termination: 8 bytes */- '0','0','0','0','0','0', ' ','\0',- /* gid, space-null termination: 8 bytes */- '0','0','0','0','0','0', ' ','\0',- /* size, space termination: 12 bytes */- '0','0','0','0','0','0','0','0','0','0','0', ' ',- /* mtime, space termination: 12 bytes */- '0','0','0','0','0','0','0','0','0','0','0', ' ',- /* Initial checksum value: 8 spaces */- ' ',' ',' ',' ',' ',' ',' ',' ',- /* Typeflag: 1 byte */- 0,- /* Linkname: 100 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,- /* Padding: 255 bytes */- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0-};--static ssize_t archive_write_v7tar_data(struct archive_write *a, const void *buff,- size_t s);-static int archive_write_v7tar_free(struct archive_write *);-static int archive_write_v7tar_close(struct archive_write *);-static int archive_write_v7tar_finish_entry(struct archive_write *);-static int archive_write_v7tar_header(struct archive_write *,- struct archive_entry *entry);-static int archive_write_v7tar_options(struct archive_write *,- const char *, const char *);-static int format_256(int64_t, char *, int);-static int format_number(int64_t, char *, int size, int max, int strict);-static int format_octal(int64_t, char *, int);-static int format_header_v7tar(struct archive_write *, char h[512],- struct archive_entry *, int, struct archive_string_conv *);--/*- * Set output format to 'v7tar' format.- */-int-archive_write_set_format_v7tar(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct v7tar *v7tar;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar");-- /* If someone else was already registered, unregister them. */- if (a->format_free != NULL)- (a->format_free)(a);-- /* Basic internal sanity test. */- if (sizeof(template_header) != 512) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Internal: template_header wrong size: %zu should be 512",- sizeof(template_header));- return (ARCHIVE_FATAL);- }-- v7tar = (struct v7tar *)calloc(1, sizeof(*v7tar));- if (v7tar == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate v7tar data");- return (ARCHIVE_FATAL);- }- a->format_data = v7tar;- a->format_name = "tar (non-POSIX)";- a->format_options = archive_write_v7tar_options;- a->format_write_header = archive_write_v7tar_header;- a->format_write_data = archive_write_v7tar_data;- a->format_close = archive_write_v7tar_close;- a->format_free = archive_write_v7tar_free;- a->format_finish_entry = archive_write_v7tar_finish_entry;- a->archive.archive_format = ARCHIVE_FORMAT_TAR;- a->archive.archive_format_name = "tar (non-POSIX)";- return (ARCHIVE_OK);-}--static int-archive_write_v7tar_options(struct archive_write *a, const char *key,- const char *val)-{- struct v7tar *v7tar = (struct v7tar *)a->format_data;- int ret = ARCHIVE_FAILED;-- if (strcmp(key, "hdrcharset") == 0) {- if (val == NULL || val[0] == 0)- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: hdrcharset option needs a character-set name",- a->format_name);- else {- v7tar->opt_sconv = archive_string_conversion_to_charset(- &a->archive, val, 0);- if (v7tar->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)-{- char buff[512];- int ret, ret2;- struct v7tar *v7tar;- struct archive_entry *entry_main;- struct archive_string_conv *sconv;-- v7tar = (struct v7tar *)a->format_data;-- /* Setup default string conversion. */- if (v7tar->opt_sconv == NULL) {- if (!v7tar->init_default_conversion) {- v7tar->sconv_default =- archive_string_default_conversion_for_write(- &(a->archive));- v7tar->init_default_conversion = 1;- }- sconv = v7tar->sconv_default;- } else- sconv = v7tar->opt_sconv;-- /* Sanity check. */- if (archive_entry_pathname(entry) == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't record entry in tar file without pathname");- return (ARCHIVE_FAILED);- }-- /* Only regular files (not hardlinks) have data. */- if (archive_entry_hardlink(entry) != NULL ||- archive_entry_symlink(entry) != NULL ||- !(archive_entry_filetype(entry) == AE_IFREG))- archive_entry_set_size(entry, 0);-- if (AE_IFDIR == archive_entry_filetype(entry)) {- const char *p;- size_t path_length;- /*- * Ensure a trailing '/'. Modify the entry so- * the client sees the change.- */-#if defined(_WIN32) && !defined(__CYGWIN__)- const wchar_t *wp;-- wp = archive_entry_pathname_w(entry);- if (wp != NULL && wp[wcslen(wp) -1] != L'/') {- struct archive_wstring ws;-- archive_string_init(&ws);- path_length = wcslen(wp);- if (archive_wstring_ensure(&ws,- path_length + 2) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate v7tar data");- archive_wstring_free(&ws);- return(ARCHIVE_FATAL);- }- /* Should we keep '\' ? */- if (wp[path_length -1] == L'\\')- path_length--;- archive_wstrncpy(&ws, wp, path_length);- archive_wstrappend_wchar(&ws, L'/');- archive_entry_copy_pathname_w(entry, ws.s);- archive_wstring_free(&ws);- p = NULL;- } else-#endif- p = archive_entry_pathname(entry);- /*- * On Windows, this is a backup operation just in- * case getting WCS failed. On POSIX, this is a- * normal operation.- */- if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {- struct archive_string as;-- archive_string_init(&as);- path_length = strlen(p);- if (archive_string_ensure(&as,- path_length + 2) == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate v7tar data");- archive_string_free(&as);- return(ARCHIVE_FATAL);- }-#if defined(_WIN32) && !defined(__CYGWIN__)- /* NOTE: This might break the pathname- * if the current code page is CP932 and- * the pathname includes a character '\'- * as a part of its multibyte pathname. */- if (p[strlen(p) -1] == '\\')- path_length--;- else-#endif- archive_strncpy(&as, p, path_length);- archive_strappend_char(&as, '/');- archive_entry_copy_pathname(entry, as.s);- archive_string_free(&as);- }- }--#if defined(_WIN32) && !defined(__CYGWIN__)- /* Make sure the path separators in pathname, hardlink and symlink- * are all slash '/', not the Windows path separator '\'. */- entry_main = __la_win_entry_in_posix_pathseparator(entry);- if (entry_main == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate v7tar data");- return(ARCHIVE_FATAL);- }- if (entry != entry_main)- entry = entry_main;- else- entry_main = NULL;-#else- entry_main = NULL;-#endif- ret = format_header_v7tar(a, buff, entry, 1, sconv);- if (ret < ARCHIVE_WARN) {- archive_entry_free(entry_main);- return (ret);- }- ret2 = __archive_write_output(a, buff, 512);- if (ret2 < ARCHIVE_WARN) {- archive_entry_free(entry_main);- return (ret2);- }- if (ret2 < ret)- ret = ret2;-- v7tar->entry_bytes_remaining = archive_entry_size(entry);- v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);- archive_entry_free(entry_main);- return (ret);-}--/*- * Format a basic 512-byte "v7tar" header.- *- * Returns -1 if format failed (due to field overflow).- * Note that this always formats as much of the header as possible.- * If "strict" is set to zero, it will extend numeric fields as- * necessary (overwriting terminators or using base-256 extensions).- *- */-static int-format_header_v7tar(struct archive_write *a, char h[512],- struct archive_entry *entry, int strict,- struct archive_string_conv *sconv)-{- unsigned int checksum;- int i, r, ret;- size_t copy_length;- const char *p, *pp;- int mytartype;-- ret = 0;- mytartype = -1;- /*- * The "template header" already includes the "v7tar"- * signature, various end-of-field markers and other required- * elements.- */- memcpy(h, &template_header, 512);-- /*- * Because the block is already null-filled, and strings- * are allowed to exactly fill their destination (without null),- * I use memcpy(dest, src, strlen()) here a lot to copy strings.- */- r = archive_entry_pathname_l(entry, &pp, ©_length, sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate pathname '%s' to %s",- pp, archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- }- if (strict && copy_length < V7TAR_name_size)- memcpy(h + V7TAR_name_offset, pp, copy_length);- else if (!strict && copy_length <= V7TAR_name_size)- memcpy(h + V7TAR_name_offset, pp, copy_length);- else {- /* Prefix is too long. */- archive_set_error(&a->archive, ENAMETOOLONG,- "Pathname too long");- ret = ARCHIVE_FAILED;- }-- r = archive_entry_hardlink_l(entry, &p, ©_length, sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s",- p, archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- }- if (copy_length > 0)- mytartype = '1';- else {- r = archive_entry_symlink_l(entry, &p, ©_length, sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate linkname '%s' to %s",- p, archive_string_conversion_charset_name(sconv));- ret = ARCHIVE_WARN;- }- }- if (copy_length > 0) {- if (copy_length >= V7TAR_linkname_size) {- archive_set_error(&a->archive, ENAMETOOLONG,- "Link contents too long");- ret = ARCHIVE_FAILED;- copy_length = V7TAR_linkname_size;- }- memcpy(h + V7TAR_linkname_offset, p, copy_length);- }-- if (format_number(archive_entry_mode(entry) & 07777,- h + V7TAR_mode_offset, V7TAR_mode_size,- V7TAR_mode_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "Numeric mode too large");- ret = ARCHIVE_FAILED;- }-- if (format_number(archive_entry_uid(entry),- h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "Numeric user ID too large");- ret = ARCHIVE_FAILED;- }-- if (format_number(archive_entry_gid(entry),- h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "Numeric group ID too large");- ret = ARCHIVE_FAILED;- }-- if (format_number(archive_entry_size(entry),- h + V7TAR_size_offset, V7TAR_size_size,- V7TAR_size_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "File size out of range");- ret = ARCHIVE_FAILED;- }-- if (format_number(archive_entry_mtime(entry),- h + V7TAR_mtime_offset, V7TAR_mtime_size,- V7TAR_mtime_max_size, strict)) {- archive_set_error(&a->archive, ERANGE,- "File modification time too large");- ret = ARCHIVE_FAILED;- }-- if (mytartype >= 0) {- h[V7TAR_typeflag_offset] = mytartype;- } else {- switch (archive_entry_filetype(entry)) {- case AE_IFREG: case AE_IFDIR:- break;- case AE_IFLNK:- h[V7TAR_typeflag_offset] = '2';- break;- default:- /* AE_IFBLK, AE_IFCHR, AE_IFIFO, AE_IFSOCK- * and unknown */- __archive_write_entry_filetype_unsupported(- &a->archive, entry, "v7tar");- ret = ARCHIVE_FAILED;- }- }-- checksum = 0;- for (i = 0; i < 512; i++)- checksum += 255 & (unsigned int)h[i];- format_octal(checksum, h + V7TAR_checksum_offset, 6);- /* Can't be pre-set in the template. */- h[V7TAR_checksum_offset + 6] = '\0';- return (ret);-}--/*- * Format a number into a field, with some intelligence.- */-static int-format_number(int64_t v, char *p, int s, int maxsize, int strict)-{- int64_t limit;-- limit = ((int64_t)1 << (s*3));-- /* "Strict" only permits octal values with proper termination. */- if (strict)- return (format_octal(v, p, s));-- /*- * In non-strict mode, we allow the number to overwrite one or- * more bytes of the field termination. Even old tar- * implementations should be able to handle this with no- * problem.- */- if (v >= 0) {- while (s <= maxsize) {- if (v < limit)- return (format_octal(v, p, s));- s++;- limit <<= 3;- }- }-- /* Base-256 can handle any number, positive or negative. */- return (format_256(v, p, maxsize));-}--/*- * Format a number into the specified field using base-256.- */-static int-format_256(int64_t v, char *p, int s)-{- p += s;- while (s-- > 0) {- *--p = (char)(v & 0xff);- v >>= 8;- }- *p |= 0x80; /* Set the base-256 marker bit. */- return (0);-}--/*- * Format a number into the specified field.- */-static int-format_octal(int64_t v, char *p, int s)-{- int len;-- len = s;-- /* Octal values can't be negative, so use 0. */- if (v < 0) {- while (len-- > 0)- *p++ = '0';- return (-1);- }-- p += s; /* Start at the end and work backwards. */- while (s-- > 0) {- *--p = (char)('0' + (v & 7));- v >>= 3;- }-- if (v == 0)- return (0);-- /* If it overflowed, fill field with max value. */- while (len-- > 0)- *p++ = '7';-- return (-1);-}--static int-archive_write_v7tar_close(struct archive_write *a)-{- return (__archive_write_nulls(a, 512*2));-}--static int-archive_write_v7tar_free(struct archive_write *a)-{- struct v7tar *v7tar;-- v7tar = (struct v7tar *)a->format_data;- free(v7tar);- a->format_data = NULL;- return (ARCHIVE_OK);-}--static int-archive_write_v7tar_finish_entry(struct archive_write *a)-{- struct v7tar *v7tar;- int ret;-- v7tar = (struct v7tar *)a->format_data;- ret = __archive_write_nulls(a,- (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));- v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;- return (ret);-}--static ssize_t-archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)-{- struct v7tar *v7tar;- int ret;-- v7tar = (struct v7tar *)a->format_data;- if (s > v7tar->entry_bytes_remaining)- s = (size_t)v7tar->entry_bytes_remaining;- ret = __archive_write_output(a, buff, s);- v7tar->entry_bytes_remaining -= s;- if (ret != ARCHIVE_OK)- return (ret);- return (s);-}
− c/archive_write_set_format_warc.c
@@ -1,444 +0,0 @@-/*-- * Copyright (c) 2014 Sebastian Freundt- * Author: Sebastian Freundt <devel@fresse.org>- *- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_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_TIME_H-#include <time.h>-#endif--#include "archive.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_random_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--struct warc_s {- unsigned int omit_warcinfo:1;-- time_t now;- mode_t typ;- unsigned int rng;- /* populated size */- uint64_t populz;-};--static const char warcinfo[] =- "software: libarchive/" ARCHIVE_VERSION_ONLY_STRING "\r\n"- "format: WARC file version 1.0\r\n";--typedef enum {- WT_NONE,- /* warcinfo */- WT_INFO,- /* metadata */- WT_META,- /* resource */- WT_RSRC,- /* request, unsupported */- WT_REQ,- /* response, unsupported */- WT_RSP,- /* revisit, unsupported */- WT_RVIS,- /* conversion, unsupported */- WT_CONV,- /* continuation, unsupported at the moment */- WT_CONT,- /* invalid type */- LAST_WT-} warc_type_t;--typedef struct {- warc_type_t type;- const char *tgturi;- const char *recid;- time_t rtime;- time_t mtime;- const char *cnttyp;- uint64_t cntlen;-} warc_essential_hdr_t;--typedef struct {- unsigned int u[4U];-} warc_uuid_t;--static int _warc_options(struct archive_write*, const char *key, const char *v);-static int _warc_header(struct archive_write *a, struct archive_entry *entry);-static ssize_t _warc_data(struct archive_write *a, const void *buf, size_t sz);-static int _warc_finish_entry(struct archive_write *a);-static int _warc_close(struct archive_write *a);-static int _warc_free(struct archive_write *a);--/* private routines */-static ssize_t _popul_ehdr(struct archive_string *t, size_t z, warc_essential_hdr_t);-static int _gen_uuid(warc_uuid_t *tgt);---/*- * Set output format to ISO 28500 (aka WARC) format.- */-int-archive_write_set_format_warc(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct warc_s *w;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_warc");-- /* If another format was already registered, unregister it. */- if (a->format_free != NULL) {- (a->format_free)(a);- }-- w = malloc(sizeof(*w));- if (w == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate warc data");- return (ARCHIVE_FATAL);- }- /* by default we're emitting a file wide header */- w->omit_warcinfo = 0U;- /* obtain current time for date fields */- w->now = time(NULL);- /* reset file type info */- w->typ = 0;- /* also initialise our rng */- w->rng = (unsigned int)w->now;-- a->format_data = w;- a->format_name = "WARC/1.0";- a->format_options = _warc_options;- a->format_write_header = _warc_header;- a->format_write_data = _warc_data;- a->format_close = _warc_close;- a->format_free = _warc_free;- a->format_finish_entry = _warc_finish_entry;- a->archive.archive_format = ARCHIVE_FORMAT_WARC;- a->archive.archive_format_name = "WARC/1.0";- return (ARCHIVE_OK);-}---/* archive methods */-static int-_warc_options(struct archive_write *a, const char *key, const char *val)-{- struct warc_s *w = a->format_data;-- if (strcmp(key, "omit-warcinfo") == 0) {- if (val == NULL || strcmp(val, "true") == 0) {- /* great */- w->omit_warcinfo = 1U;- return (ARCHIVE_OK);- }- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-_warc_header(struct archive_write *a, struct archive_entry *entry)-{- struct warc_s *w = a->format_data;- struct archive_string hdr;-#define MAX_HDR_SIZE 512-- /* check whether warcinfo record needs outputting */- if (!w->omit_warcinfo) {- ssize_t r;- warc_essential_hdr_t wi = {- WT_INFO,- /*uri*/NULL,- /*urn*/NULL,- /*rtm*/0,- /*mtm*/0,- /*cty*/"application/warc-fields",- /*len*/sizeof(warcinfo) - 1U,- };- wi.rtime = w->now;- wi.mtime = w->now;-- archive_string_init(&hdr);- r = _popul_ehdr(&hdr, MAX_HDR_SIZE, wi);- if (r >= 0) {- /* jackpot! */- /* now also use HDR buffer for the actual warcinfo */- archive_strncat(&hdr, warcinfo, sizeof(warcinfo) -1);-- /* append end-of-record indicator */- archive_strncat(&hdr, "\r\n\r\n", 4);-- /* write to output stream */- __archive_write_output(a, hdr.s, archive_strlen(&hdr));- }- /* indicate we're done with file header writing */- w->omit_warcinfo = 1U;- archive_string_free(&hdr);- }-- if (archive_entry_pathname(entry) == NULL) {- archive_set_error(&a->archive, EINVAL,- "Invalid filename");- return (ARCHIVE_WARN);- }-- w->typ = archive_entry_filetype(entry);- w->populz = 0U;- if (w->typ == AE_IFREG) {- warc_essential_hdr_t rh = {- WT_RSRC,- /*uri*/NULL,- /*urn*/NULL,- /*rtm*/0,- /*mtm*/0,- /*cty*/NULL,- /*len*/0,- };- ssize_t r;- rh.tgturi = archive_entry_pathname(entry);- rh.rtime = w->now;- rh.mtime = archive_entry_mtime(entry);- rh.cntlen = (size_t)archive_entry_size(entry);-- archive_string_init(&hdr);- r = _popul_ehdr(&hdr, MAX_HDR_SIZE, rh);- if (r < 0) {- /* don't bother */- archive_set_error(- &a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "cannot archive file");- return (ARCHIVE_WARN);- }- /* otherwise append to output stream */- __archive_write_output(a, hdr.s, r);- /* and let subsequent calls to _data() know about the size */- w->populz = rh.cntlen;- archive_string_free(&hdr);- return (ARCHIVE_OK);- }- /* just resort to erroring as per Tim's advice */- __archive_write_entry_filetype_unsupported(- &a->archive, entry, "WARC");- return (ARCHIVE_FAILED);-}--static ssize_t-_warc_data(struct archive_write *a, const void *buf, size_t len)-{- struct warc_s *w = a->format_data;-- if (w->typ == AE_IFREG) {- int rc;-- /* never write more bytes than announced */- if (len > w->populz) {- len = (size_t)w->populz;- }-- /* now then, out we put the whole shebang */- rc = __archive_write_output(a, buf, len);- if (rc != ARCHIVE_OK) {- return rc;- }- }- return len;-}--static int-_warc_finish_entry(struct archive_write *a)-{- static const char _eor[] = "\r\n\r\n";- struct warc_s *w = a->format_data;-- if (w->typ == AE_IFREG) {- int rc = __archive_write_output(a, _eor, sizeof(_eor) - 1U);-- if (rc != ARCHIVE_OK) {- return rc;- }- }- /* reset type info */- w->typ = 0;- return (ARCHIVE_OK);-}--static int-_warc_close(struct archive_write *a)-{- (void)a; /* UNUSED */- return (ARCHIVE_OK);-}--static int-_warc_free(struct archive_write *a)-{- struct warc_s *w = a->format_data;-- free(w);- a->format_data = NULL;- return (ARCHIVE_OK);-}---/* private routines */-static void-xstrftime(struct archive_string *as, const char *fmt, time_t t)-{-/** like strftime(3) but for time_t objects */- struct tm *rt;-#if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S)- struct tm timeHere;-#endif- char strtime[100];- size_t len;--#if defined(HAVE_GMTIME_S)- rt = gmtime_s(&timeHere, &t) ? NULL : &timeHere;-#elif defined(HAVE_GMTIME_R)- rt = gmtime_r(&t, &timeHere);-#else- rt = gmtime(&t);-#endif- if (!rt)- return;- /* leave the hard yacker to our role model strftime() */- len = strftime(strtime, sizeof(strtime)-1, fmt, rt);- archive_strncat(as, strtime, len);-}--static ssize_t-_popul_ehdr(struct archive_string *tgt, size_t tsz, warc_essential_hdr_t hdr)-{- static const char _ver[] = "WARC/1.0\r\n";- static const char * const _typ[LAST_WT] = {- NULL, "warcinfo", "metadata", "resource", NULL- };- char std_uuid[48U];-- if (hdr.type == WT_NONE || hdr.type > WT_RSRC) {- /* brilliant, how exactly did we get here? */- return -1;- }-- archive_strcpy(tgt, _ver);-- archive_string_sprintf(tgt, "WARC-Type: %s\r\n", _typ[hdr.type]);-- if (hdr.tgturi != NULL) {- /* check if there's a xyz:// */- static const char _uri[] = "";- static const char _fil[] = "file://";- const char *u;- char *chk = strchr(hdr.tgturi, ':');-- if (chk != NULL && chk[1U] == '/' && chk[2U] == '/') {- /* yep, it's definitely a URI */- u = _uri;- } else {- /* hm, best to prepend file:// then */- u = _fil;- }- archive_string_sprintf(tgt,- "WARC-Target-URI: %s%s\r\n", u, hdr.tgturi);- }-- /* record time is usually when the http is sent off,- * just treat the archive writing as such for a moment */- xstrftime(tgt, "WARC-Date: %Y-%m-%dT%H:%M:%SZ\r\n", hdr.rtime);-- /* while we're at it, record the mtime */- xstrftime(tgt, "Last-Modified: %Y-%m-%dT%H:%M:%SZ\r\n", hdr.mtime);-- if (hdr.recid == NULL) {- /* generate one, grrrr */- warc_uuid_t u;-- _gen_uuid(&u);- /* Unfortunately, archive_string_sprintf does not- * handle the minimum number following '%'.- * So we have to use snprintf function here instead- * of archive_string_snprintf function. */-#if defined(_WIN32) && !defined(__CYGWIN__) && !( defined(_MSC_VER) && _MSC_VER >= 1900)-#define snprintf _snprintf-#endif- snprintf(- std_uuid, sizeof(std_uuid),- "<urn:uuid:%08x-%04x-%04x-%04x-%04x%08x>",- u.u[0U],- u.u[1U] >> 16U, u.u[1U] & 0xffffU,- u.u[2U] >> 16U, u.u[2U] & 0xffffU,- u.u[3U]);- hdr.recid = std_uuid;- }-- /* record-id is mandatory, fingers crossed we won't fail */- archive_string_sprintf(tgt, "WARC-Record-ID: %s\r\n", hdr.recid);-- if (hdr.cnttyp != NULL) {- archive_string_sprintf(tgt, "Content-Type: %s\r\n", hdr.cnttyp);- }-- /* next one is mandatory */- archive_string_sprintf(tgt, "Content-Length: %ju\r\n", (uintmax_t)hdr.cntlen);- /**/- archive_strncat(tgt, "\r\n", 2);-- return (archive_strlen(tgt) >= tsz)? -1: (ssize_t)archive_strlen(tgt);-}--static int-_gen_uuid(warc_uuid_t *tgt)-{- archive_random(tgt->u, sizeof(tgt->u));- /* obey uuid version 4 rules */- tgt->u[1U] &= 0xffff0fffU;- tgt->u[1U] |= 0x4000U;- tgt->u[2U] &= 0x3fffffffU;- tgt->u[2U] |= 0x80000000U;- return 0;-}--/* archive_write_set_format_warc.c ends here */
− c/archive_write_set_format_xar.c
@@ -1,3255 +0,0 @@-/*-- * Copyright (c) 2010-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_LIMITS_H-#include <limits.h>-#endif-#include <stdlib.h>-#if HAVE_LIBXML_XMLWRITER_H-#include <libxml/xmlwriter.h>-#endif-#ifdef HAVE_BZLIB_H-#include <bzlib.h>-#endif-#if HAVE_LZMA_H-#include <lzma.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif--#include "archive.h"-#include "archive_digest_private.h"-#include "archive_endian.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_private.h"-#include "archive_rb.h"-#include "archive_string.h"-#include "archive_write_private.h"--/*- * Differences to xar utility.- * - Subdocument is not supported yet.- * - ACL is not supported yet.- * - When writing an XML element <link type="<file-type>">, <file-type>- * which is a file type a symbolic link is referencing is always marked- * as "broken". Xar utility uses stat(2) to get the file type, but, in- * libarchive format writer, we should not use it; if it is needed, we- * should get about it at archive_read_disk.c.- * - It is possible to appear both <flags> and <ext2> elements.- * Xar utility generates <flags> on BSD platform and <ext2> on Linux- * platform.- *- */--#if !(defined(HAVE_LIBXML_XMLWRITER_H) && defined(LIBXML_VERSION) &&\- LIBXML_VERSION >= 20703) ||\- !defined(HAVE_ZLIB_H) || \- !defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)-/*- * xar needs several external libraries.- * o libxml2- * o openssl or MD5/SHA1 hash function- * o zlib- * o bzlib2 (option)- * o liblzma (option)- */-int-archive_write_set_format_xar(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;-- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Xar not supported on this platform");- return (ARCHIVE_WARN);-}--#else /* Support xar format */--/*#define DEBUG_PRINT_TOC 1 */--#define BAD_CAST_CONST (const xmlChar *)--#define HEADER_MAGIC 0x78617221-#define HEADER_SIZE 28-#define HEADER_VERSION 1--enum sumalg {- CKSUM_NONE = 0,- CKSUM_SHA1 = 1,- CKSUM_MD5 = 2-};--#define MD5_SIZE 16-#define SHA1_SIZE 20-#define MAX_SUM_SIZE 20-#define MD5_NAME "md5"-#define SHA1_NAME "sha1"--enum enctype {- NONE,- GZIP,- BZIP2,- LZMA,- XZ,-};--struct chksumwork {- enum sumalg alg;-#ifdef ARCHIVE_HAS_MD5- archive_md5_ctx md5ctx;-#endif-#ifdef ARCHIVE_HAS_SHA1- archive_sha1_ctx sha1ctx;-#endif-};--enum la_zaction {- ARCHIVE_Z_FINISH,- ARCHIVE_Z_RUN-};--/*- * Universal zstream.- */-struct la_zstream {- const unsigned char *next_in;- size_t avail_in;- uint64_t total_in;-- unsigned char *next_out;- size_t avail_out;- uint64_t total_out;-- int valid;- void *real_stream;- int (*code) (struct archive *a,- struct la_zstream *lastrm,- enum la_zaction action);- int (*end)(struct archive *a,- struct la_zstream *lastrm);-};--struct chksumval {- enum sumalg alg;- size_t len;- unsigned char val[MAX_SUM_SIZE];-};--struct heap_data {- int id;- struct heap_data *next;- uint64_t temp_offset;- uint64_t length; /* archived size. */- uint64_t size; /* extracted size. */- enum enctype compression;- struct chksumval a_sum; /* archived checksum. */- struct chksumval e_sum; /* extracted checksum. */-};--struct file {- struct archive_rb_node rbnode;-- int id;- struct archive_entry *entry;-- struct archive_rb_tree rbtree;- struct file *next;- struct file *chnext;- struct file *hlnext;- /* For hardlinked files.- * Use only when archive_entry_nlink() > 1 */- struct file *hardlink_target;- struct file *parent; /* parent directory entry */- /*- * To manage sub directory files.- * We use 'chnext' (a member of struct file) to chain.- */- struct {- struct file *first;- struct file **last;- } children;-- /* For making a directory tree. */- struct archive_string parentdir;- struct archive_string basename;- struct archive_string symlink;-- int ea_idx;- struct {- struct heap_data *first;- struct heap_data **last;- } xattr;- struct heap_data data;- struct archive_string script;-- unsigned int virtual:1;- unsigned int dir:1;-};--struct hardlink {- struct archive_rb_node rbnode;- int nlink;- struct {- struct file *first;- struct file **last;- } file_list;-};--struct xar {- int temp_fd;- uint64_t temp_offset;-- int file_idx;- struct file *root;- struct file *cur_dirent;- struct archive_string cur_dirstr;- struct file *cur_file;- uint64_t bytes_remaining;- struct archive_string tstr;- struct archive_string vstr;-- enum sumalg opt_toc_sumalg;- enum sumalg opt_sumalg;- enum enctype opt_compression;- int opt_compression_level;- uint32_t opt_threads;-- struct chksumwork a_sumwrk; /* archived checksum. */- struct chksumwork e_sumwrk; /* extracted checksum. */- struct la_zstream stream;- struct archive_string_conv *sconv;- /*- * Compressed data buffer.- */- unsigned char wbuff[1024 * 64];- size_t wbuff_remaining;-- struct heap_data toc;- /*- * The list of all file entries is used to manage struct file- * objects.- * We use 'next' (a member of struct file) to chain.- */- struct {- struct file *first;- struct file **last;- } file_list;- /*- * The list of hard-linked file entries.- * We use 'hlnext' (a member of struct file) to chain.- */- struct archive_rb_tree hardlink_rbtree;-};--static int xar_options(struct archive_write *,- const char *, const char *);-static int xar_write_header(struct archive_write *,- struct archive_entry *);-static ssize_t xar_write_data(struct archive_write *,- const void *, size_t);-static int xar_finish_entry(struct archive_write *);-static int xar_close(struct archive_write *);-static int xar_free(struct archive_write *);--static struct file *file_new(struct archive_write *a, struct archive_entry *);-static void file_free(struct file *);-static struct file *file_create_virtual_dir(struct archive_write *a, struct xar *,- const char *);-static int file_add_child_tail(struct file *, struct file *);-static struct file *file_find_child(struct file *, const char *);-static int file_gen_utility_names(struct archive_write *,- struct file *);-static int get_path_component(char *, int, const char *);-static int file_tree(struct archive_write *, struct file **);-static void file_register(struct xar *, struct file *);-static void file_init_register(struct xar *);-static void file_free_register(struct xar *);-static int file_register_hardlink(struct archive_write *,- struct file *);-static void file_connect_hardlink_files(struct xar *);-static void file_init_hardlinks(struct xar *);-static void file_free_hardlinks(struct xar *);--static void checksum_init(struct chksumwork *, enum sumalg);-static void checksum_update(struct chksumwork *, const void *, size_t);-static void checksum_final(struct chksumwork *, struct chksumval *);-static int compression_init_encoder_gzip(struct archive *,- struct la_zstream *, int, int);-static int compression_code_gzip(struct archive *,- struct la_zstream *, enum la_zaction);-static int compression_end_gzip(struct archive *, struct la_zstream *);-static int compression_init_encoder_bzip2(struct archive *,- struct la_zstream *, int);-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)-static int compression_code_bzip2(struct archive *,- struct la_zstream *, enum la_zaction);-static int compression_end_bzip2(struct archive *, struct la_zstream *);-#endif-static int compression_init_encoder_lzma(struct archive *,- struct la_zstream *, int);-static int compression_init_encoder_xz(struct archive *,- struct la_zstream *, int, int);-#if defined(HAVE_LZMA_H)-static int compression_code_lzma(struct archive *,- struct la_zstream *, enum la_zaction);-static int compression_end_lzma(struct archive *, struct la_zstream *);-#endif-static int xar_compression_init_encoder(struct archive_write *);-static int compression_code(struct archive *,- struct la_zstream *, enum la_zaction);-static int compression_end(struct archive *,- struct la_zstream *);-static int save_xattrs(struct archive_write *, struct file *);-static int getalgsize(enum sumalg);-static const char *getalgname(enum sumalg);--int-archive_write_set_format_xar(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct xar *xar;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_xar");-- /* If another format was already registered, unregister it. */- if (a->format_free != NULL)- (a->format_free)(a);-- xar = calloc(1, sizeof(*xar));- if (xar == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate xar data");- return (ARCHIVE_FATAL);- }- xar->temp_fd = -1;- file_init_register(xar);- file_init_hardlinks(xar);- archive_string_init(&(xar->tstr));- archive_string_init(&(xar->vstr));-- /*- * Create the root directory.- */- xar->root = file_create_virtual_dir(a, xar, "");- if (xar->root == NULL) {- free(xar);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate xar data");- return (ARCHIVE_FATAL);- }- xar->root->parent = xar->root;- file_register(xar, xar->root);- xar->cur_dirent = xar->root;- archive_string_init(&(xar->cur_dirstr));- archive_string_ensure(&(xar->cur_dirstr), 1);- xar->cur_dirstr.s[0] = 0;-- /*- * Initialize option.- */- /* Set default checksum type. */- xar->opt_toc_sumalg = CKSUM_SHA1;- xar->opt_sumalg = CKSUM_SHA1;- /* Set default compression type, level, and number of threads. */- xar->opt_compression = GZIP;- xar->opt_compression_level = 6;- xar->opt_threads = 1;-- a->format_data = xar;-- a->format_name = "xar";- a->format_options = xar_options;- a->format_write_header = xar_write_header;- a->format_write_data = xar_write_data;- a->format_finish_entry = xar_finish_entry;- a->format_close = xar_close;- a->format_free = xar_free;- a->archive.archive_format = ARCHIVE_FORMAT_XAR;- a->archive.archive_format_name = "xar";-- return (ARCHIVE_OK);-}--static int-xar_options(struct archive_write *a, const char *key, const char *value)-{- struct xar *xar;-- xar = (struct xar *)a->format_data;-- if (strcmp(key, "checksum") == 0) {- if (value == NULL)- xar->opt_sumalg = CKSUM_NONE;- else if (strcmp(value, "none") == 0)- xar->opt_sumalg = CKSUM_NONE;- else if (strcmp(value, "sha1") == 0)- xar->opt_sumalg = CKSUM_SHA1;- else if (strcmp(value, "md5") == 0)- xar->opt_sumalg = CKSUM_MD5;- else {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Unknown checksum name: `%s'",- value);- return (ARCHIVE_FAILED);- }- return (ARCHIVE_OK);- }- if (strcmp(key, "compression") == 0) {- const char *name = NULL;-- if (value == NULL)- xar->opt_compression = NONE;- else if (strcmp(value, "none") == 0)- xar->opt_compression = NONE;- else if (strcmp(value, "gzip") == 0)- xar->opt_compression = GZIP;- else if (strcmp(value, "bzip2") == 0)-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)- xar->opt_compression = BZIP2;-#else- name = "bzip2";-#endif- else if (strcmp(value, "lzma") == 0)-#if HAVE_LZMA_H- xar->opt_compression = LZMA;-#else- name = "lzma";-#endif- else if (strcmp(value, "xz") == 0)-#if HAVE_LZMA_H- xar->opt_compression = XZ;-#else- name = "xz";-#endif- else {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Unknown compression name: `%s'",- value);- return (ARCHIVE_FAILED);- }- if (name != NULL) {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "`%s' compression not supported "- "on this platform",- name);- return (ARCHIVE_FAILED);- }- return (ARCHIVE_OK);- }- if (strcmp(key, "compression-level") == 0) {- if (value == NULL ||- !(value[0] >= '0' && value[0] <= '9') ||- value[1] != '\0') {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Illegal value `%s'",- value);- return (ARCHIVE_FAILED);- }- xar->opt_compression_level = value[0] - '0';- return (ARCHIVE_OK);- }- if (strcmp(key, "toc-checksum") == 0) {- if (value == NULL)- xar->opt_toc_sumalg = CKSUM_NONE;- else if (strcmp(value, "none") == 0)- xar->opt_toc_sumalg = CKSUM_NONE;- else if (strcmp(value, "sha1") == 0)- xar->opt_toc_sumalg = CKSUM_SHA1;- else if (strcmp(value, "md5") == 0)- xar->opt_toc_sumalg = CKSUM_MD5;- else {- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Unknown checksum name: `%s'",- value);- return (ARCHIVE_FAILED);- }- return (ARCHIVE_OK);- }- if (strcmp(key, "threads") == 0) {- char *endptr;-- if (value == NULL)- return (ARCHIVE_FAILED);- errno = 0;- xar->opt_threads = (int)strtoul(value, &endptr, 10);- if (errno != 0 || *endptr != '\0') {- xar->opt_threads = 1;- archive_set_error(&(a->archive),- ARCHIVE_ERRNO_MISC,- "Illegal value `%s'",- value);- return (ARCHIVE_FAILED);- }- if (xar->opt_threads == 0) {-#ifdef HAVE_LZMA_STREAM_ENCODER_MT- xar->opt_threads = lzma_cputhreads();-#else- xar->opt_threads = 1;-#endif- }- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--static int-xar_write_header(struct archive_write *a, struct archive_entry *entry)-{- struct xar *xar;- struct file *file;- struct archive_entry *file_entry;- int r, r2;-- xar = (struct xar *)a->format_data;- xar->cur_file = NULL;- xar->bytes_remaining = 0;-- if (xar->sconv == NULL) {- xar->sconv = archive_string_conversion_to_charset(- &a->archive, "UTF-8", 1);- if (xar->sconv == NULL)- return (ARCHIVE_FATAL);- }-- file = file_new(a, entry);- if (file == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate data");- return (ARCHIVE_FATAL);- }- r2 = file_gen_utility_names(a, file);- if (r2 < ARCHIVE_WARN)- return (r2);-- /*- * Ignore a path which looks like the top of directory name- * since we have already made the root directory of an Xar archive.- */- if (archive_strlen(&(file->parentdir)) == 0 &&- archive_strlen(&(file->basename)) == 0) {- file_free(file);- return (r2);- }-- /* Add entry into tree */- file_entry = file->entry;- r = file_tree(a, &file);- if (r != ARCHIVE_OK)- return (r);- /* There is the same file in tree and- * the current file is older than the file in tree.- * So we don't need the current file data anymore. */- if (file->entry != file_entry)- return (r2);- if (file->id == 0)- file_register(xar, file);-- /* A virtual file, which is a directory, does not have- * any contents and we won't store it into a archive- * file other than its name. */- if (file->virtual)- return (r2);-- /*- * Prepare to save the contents of the file.- */- if (xar->temp_fd == -1) {- int algsize;- xar->temp_offset = 0;- xar->temp_fd = __archive_mktemp(NULL);- if (xar->temp_fd < 0) {- archive_set_error(&a->archive, errno,- "Couldn't create temporary file");- return (ARCHIVE_FATAL);- }- algsize = getalgsize(xar->opt_toc_sumalg);- if (algsize > 0) {- if (lseek(xar->temp_fd, algsize, SEEK_SET) < 0) {- archive_set_error(&(a->archive), errno,- "lseek failed");- return (ARCHIVE_FATAL);- }- xar->temp_offset = algsize;- }- }-- if (archive_entry_hardlink(file->entry) == NULL) {- r = save_xattrs(a, file);- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- /* Non regular files contents are unneeded to be saved to- * a temporary file. */- if (archive_entry_filetype(file->entry) != AE_IFREG)- return (r2);-- /*- * Set the current file to cur_file to read its contents.- */- xar->cur_file = file;-- if (archive_entry_nlink(file->entry) > 1) {- r = file_register_hardlink(a, file);- if (r != ARCHIVE_OK)- return (r);- if (archive_entry_hardlink(file->entry) != NULL) {- archive_entry_unset_size(file->entry);- return (r2);- }- }-- /* Save a offset of current file in temporary file. */- file->data.temp_offset = xar->temp_offset;- file->data.size = archive_entry_size(file->entry);- file->data.compression = xar->opt_compression;- xar->bytes_remaining = archive_entry_size(file->entry);- checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);- checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);- r = xar_compression_init_encoder(a);-- if (r != ARCHIVE_OK)- return (r);- else- return (r2);-}--static int-write_to_temp(struct archive_write *a, const void *buff, size_t s)-{- struct xar *xar;- const unsigned char *p;- ssize_t ws;-- xar = (struct xar *)a->format_data;- p = (const unsigned char *)buff;- while (s) {- ws = write(xar->temp_fd, p, s);- if (ws < 0) {- archive_set_error(&(a->archive), errno,- "fwrite function failed");- return (ARCHIVE_FATAL);- }- s -= ws;- p += ws;- xar->temp_offset += ws;- }- return (ARCHIVE_OK);-}--static ssize_t-xar_write_data(struct archive_write *a, const void *buff, size_t s)-{- struct xar *xar;- enum la_zaction run;- size_t size = 0;- size_t rsize;- int r;-- xar = (struct xar *)a->format_data;-- if (s > xar->bytes_remaining)- s = (size_t)xar->bytes_remaining;- if (s == 0 || xar->cur_file == NULL)- return (0);- if (xar->cur_file->data.compression == NONE) {- checksum_update(&(xar->e_sumwrk), buff, s);- checksum_update(&(xar->a_sumwrk), buff, s);- size = rsize = s;- } else {- xar->stream.next_in = (const unsigned char *)buff;- xar->stream.avail_in = s;- if (xar->bytes_remaining > s)- run = ARCHIVE_Z_RUN;- else- run = ARCHIVE_Z_FINISH;- /* Compress file data. */- for (;;) {- r = compression_code(&(a->archive), &(xar->stream),- run);- if (r != ARCHIVE_OK && r != ARCHIVE_EOF)- return (ARCHIVE_FATAL);- if (xar->stream.avail_out == 0 ||- run == ARCHIVE_Z_FINISH) {- size = sizeof(xar->wbuff) -- xar->stream.avail_out;- checksum_update(&(xar->a_sumwrk), xar->wbuff,- size);- xar->cur_file->data.length += size;- if (write_to_temp(a, xar->wbuff,- size) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- if (r == ARCHIVE_OK) {- /* Output buffer was full */- xar->stream.next_out = xar->wbuff;- xar->stream.avail_out =- sizeof(xar->wbuff);- } else {- /* ARCHIVE_EOF - We are done */- break;- }- } else {- /* Compressor wants more input */- break;- }- }- rsize = s - xar->stream.avail_in;- checksum_update(&(xar->e_sumwrk), buff, rsize);- }-#if !defined(_WIN32) || defined(__CYGWIN__)- if (xar->bytes_remaining ==- (uint64_t)archive_entry_size(xar->cur_file->entry)) {- /*- * Get the path of a shell script if so.- */- const unsigned char *b = (const unsigned char *)buff;-- archive_string_empty(&(xar->cur_file->script));- if (rsize > 2 && b[0] == '#' && b[1] == '!') {- size_t i, end, off;-- off = 2;- if (b[off] == ' ')- off++;-#ifdef PATH_MAX- if ((rsize - off) > PATH_MAX)- end = off + PATH_MAX;- else-#endif- end = rsize;- /* Find the end of a script path. */- for (i = off; i < end && b[i] != '\0' &&- b[i] != '\n' && b[i] != '\r' &&- b[i] != ' ' && b[i] != '\t'; i++)- ;- archive_strncpy(&(xar->cur_file->script), b + off,- i - off);- }- }-#endif-- if (xar->cur_file->data.compression == NONE) {- if (write_to_temp(a, buff, size) != ARCHIVE_OK)- return (ARCHIVE_FATAL);- xar->cur_file->data.length += size;- }- xar->bytes_remaining -= rsize;-- return (rsize);-}--static int-xar_finish_entry(struct archive_write *a)-{- struct xar *xar;- struct file *file;- size_t s;- ssize_t w;-- xar = (struct xar *)a->format_data;- if (xar->cur_file == NULL)- return (ARCHIVE_OK);-- while (xar->bytes_remaining > 0) {- s = (size_t)xar->bytes_remaining;- if (s > a->null_length)- s = a->null_length;- w = xar_write_data(a, a->nulls, s);- if (w > 0)- xar->bytes_remaining -= w;- else- return (w);- }- file = xar->cur_file;- checksum_final(&(xar->e_sumwrk), &(file->data.e_sum));- checksum_final(&(xar->a_sumwrk), &(file->data.a_sum));- xar->cur_file = NULL;-- return (ARCHIVE_OK);-}--static int-xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,- const char *key, const char *value,- const char *attrkey, const char *attrvalue)-{- int r;-- r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- if (attrkey != NULL && attrvalue != NULL) {- r = xmlTextWriterWriteAttribute(writer,- BAD_CAST_CONST(attrkey), BAD_CAST_CONST(attrvalue));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterWriteAttribute() failed: %d", r);- return (ARCHIVE_FATAL);- }- }- if (value != NULL) {- r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterWriteString() failed: %d", r);- return (ARCHIVE_FATAL);- }- }- r = xmlTextWriterEndElement(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}--static int-xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,- const char *key, const char *value)-{- int r;-- if (value == NULL)- return (ARCHIVE_OK);-- r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- if (value != NULL) {- r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterWriteString() failed: %d", r);- return (ARCHIVE_FATAL);- }- }- r = xmlTextWriterEndElement(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}--static int-xmlwrite_fstring(struct archive_write *a, xmlTextWriterPtr writer,- const char *key, const char *fmt, ...)-{- struct xar *xar;- va_list ap;-- xar = (struct xar *)a->format_data;- va_start(ap, fmt);- archive_string_empty(&xar->vstr);- archive_string_vsprintf(&xar->vstr, fmt, ap);- va_end(ap);- return (xmlwrite_string(a, writer, key, xar->vstr.s));-}--static int-xmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer,- const char *key, time_t t, int z)-{- char timestr[100];- struct tm tm;--#if defined(HAVE_GMTIME_S)- gmtime_s(&tm, &t);-#elif defined(HAVE_GMTIME_R)- gmtime_r(&t, &tm);-#else- memcpy(&tm, gmtime(&t), sizeof(tm));-#endif- memset(×tr, 0, sizeof(timestr));- /* Do not use %F and %T for portability. */- strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S", &tm);- if (z)- strcat(timestr, "Z");- return (xmlwrite_string(a, writer, key, timestr));-}--static int-xmlwrite_mode(struct archive_write *a, xmlTextWriterPtr writer,- const char *key, mode_t mode)-{- char ms[5];-- ms[0] = '0';- ms[1] = '0' + ((mode >> 6) & 07);- ms[2] = '0' + ((mode >> 3) & 07);- ms[3] = '0' + (mode & 07);- ms[4] = '\0';-- return (xmlwrite_string(a, writer, key, ms));-}--static int-xmlwrite_sum(struct archive_write *a, xmlTextWriterPtr writer,- const char *key, struct chksumval *sum)-{- const char *algname;- int algsize;- char buff[MAX_SUM_SIZE*2 + 1];- char *p;- unsigned char *s;- int i, r;-- if (sum->len > 0) {- algname = getalgname(sum->alg);- algsize = getalgsize(sum->alg);- if (algname != NULL) {- const char *hex = "0123456789abcdef";- p = buff;- s = sum->val;- for (i = 0; i < algsize; i++) {- *p++ = hex[(*s >> 4)];- *p++ = hex[(*s & 0x0f)];- s++;- }- *p = '\0';- r = xmlwrite_string_attr(a, writer,- key, buff,- "style", algname);- if (r < 0)- return (ARCHIVE_FATAL);- }- }- return (ARCHIVE_OK);-}--static int-xmlwrite_heap(struct archive_write *a, xmlTextWriterPtr writer,- struct heap_data *heap)-{- const char *encname;- int r;-- r = xmlwrite_fstring(a, writer, "length", "%ju", heap->length);- if (r < 0)- return (ARCHIVE_FATAL);- r = xmlwrite_fstring(a, writer, "offset", "%ju", heap->temp_offset);- if (r < 0)- return (ARCHIVE_FATAL);- r = xmlwrite_fstring(a, writer, "size", "%ju", heap->size);- if (r < 0)- return (ARCHIVE_FATAL);- switch (heap->compression) {- case GZIP:- encname = "application/x-gzip"; break;- case BZIP2:- encname = "application/x-bzip2"; break;- case LZMA:- encname = "application/x-lzma"; break;- case XZ:- encname = "application/x-xz"; break;- default:- encname = "application/octet-stream"; break;- }- r = xmlwrite_string_attr(a, writer, "encoding", NULL,- "style", encname);- if (r < 0)- return (ARCHIVE_FATAL);- r = xmlwrite_sum(a, writer, "archived-checksum", &(heap->a_sum));- if (r < 0)- return (ARCHIVE_FATAL);- r = xmlwrite_sum(a, writer, "extracted-checksum", &(heap->e_sum));- if (r < 0)- return (ARCHIVE_FATAL);- return (ARCHIVE_OK);-}--/*- * xar utility records fflags as following xml elements:- * <flags>- * <UserNoDump/>- * .....- * </flags>- * or- * <ext2>- * <NoDump/>- * .....- * </ext2>- * If xar is running on BSD platform, records <flags>..</flags>;- * if xar is running on linux platform, records <ext2>..</ext2>;- * otherwise does not record.- *- * Our implements records both <flags> and <ext2> if it's necessary.- */-static int-make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer,- const char *element, const char *fflags_text)-{- static const struct flagentry {- const char *name;- const char *xarname;- }- flagbsd[] = {- { "sappnd", "SystemAppend"},- { "sappend", "SystemAppend"},- { "arch", "SystemArchived"},- { "archived", "SystemArchived"},- { "schg", "SystemImmutable"},- { "schange", "SystemImmutable"},- { "simmutable", "SystemImmutable"},- { "nosunlnk", "SystemNoUnlink"},- { "nosunlink", "SystemNoUnlink"},- { "snapshot", "SystemSnapshot"},- { "uappnd", "UserAppend"},- { "uappend", "UserAppend"},- { "uchg", "UserImmutable"},- { "uchange", "UserImmutable"},- { "uimmutable", "UserImmutable"},- { "nodump", "UserNoDump"},- { "noopaque", "UserOpaque"},- { "nouunlnk", "UserNoUnlink"},- { "nouunlink", "UserNoUnlink"},- { NULL, NULL}- },- flagext2[] = {- { "sappnd", "AppendOnly"},- { "sappend", "AppendOnly"},- { "schg", "Immutable"},- { "schange", "Immutable"},- { "simmutable", "Immutable"},- { "nodump", "NoDump"},- { "nouunlnk", "Undelete"},- { "nouunlink", "Undelete"},- { "btree", "BTree"},- { "comperr", "CompError"},- { "compress", "Compress"},- { "noatime", "NoAtime"},- { "compdirty", "CompDirty"},- { "comprblk", "CompBlock"},- { "dirsync", "DirSync"},- { "hashidx", "HashIndexed"},- { "imagic", "iMagic"},- { "journal", "Journaled"},- { "securedeletion", "SecureDeletion"},- { "sync", "Synchronous"},- { "notail", "NoTail"},- { "topdir", "TopDir"},- { "reserved", "Reserved"},- { NULL, NULL}- };- const struct flagentry *fe, *flagentry;-#define FLAGENTRY_MAXSIZE ((sizeof(flagbsd)+sizeof(flagext2))/sizeof(flagbsd))- const struct flagentry *avail[FLAGENTRY_MAXSIZE];- const char *p;- int i, n, r;-- if (strcmp(element, "ext2") == 0)- flagentry = flagext2;- else- flagentry = flagbsd;- n = 0;- p = fflags_text;- do {- const char *cp;-- cp = strchr(p, ',');- if (cp == NULL)- cp = p + strlen(p);-- for (fe = flagentry; fe->name != NULL; fe++) {- if (fe->name[cp - p] != '\0'- || p[0] != fe->name[0])- continue;- if (strncmp(p, fe->name, cp - p) == 0) {- avail[n++] = fe;- break;- }- }- if (*cp == ',')- p = cp + 1;- else- p = NULL;- } while (p != NULL);-- if (n > 0) {- r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(element));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- for (i = 0; i < n; i++) {- r = xmlwrite_string(a, writer,- avail[i]->xarname, NULL);- if (r != ARCHIVE_OK)- return (r);- }-- r = xmlTextWriterEndElement(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- }- return (ARCHIVE_OK);-}--static int-make_file_entry(struct archive_write *a, xmlTextWriterPtr writer,- struct file *file)-{- struct xar *xar;- const char *filetype, *filelink, *fflags;- struct archive_string linkto;- struct heap_data *heap;- unsigned char *tmp;- const char *p;- size_t len;- int r, r2, l, ll;-- xar = (struct xar *)a->format_data;- r2 = ARCHIVE_OK;-- /*- * Make a file name entry, "<name>".- */- l = ll = archive_strlen(&(file->basename));- tmp = malloc(l);- if (tmp == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- r = UTF8Toisolat1(tmp, &l, BAD_CAST(file->basename.s), &ll);- free(tmp);- if (r < 0) {- r = xmlTextWriterStartElement(writer, BAD_CAST("name"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- r = xmlTextWriterWriteAttribute(writer,- BAD_CAST("enctype"), BAD_CAST("base64"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterWriteAttribute() failed: %d", r);- return (ARCHIVE_FATAL);- }- r = xmlTextWriterWriteBase64(writer, file->basename.s,- 0, archive_strlen(&(file->basename)));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterWriteBase64() failed: %d", r);- return (ARCHIVE_FATAL);- }- r = xmlTextWriterEndElement(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- } else {- r = xmlwrite_string(a, writer, "name", file->basename.s);- if (r < 0)- return (ARCHIVE_FATAL);- }-- /*- * Make a file type entry, "<type>".- */- filelink = NULL;- archive_string_init(&linkto);- switch (archive_entry_filetype(file->entry)) {- case AE_IFDIR:- filetype = "directory"; break;- case AE_IFLNK:- filetype = "symlink"; break;- case AE_IFCHR:- filetype = "character special"; break;- case AE_IFBLK:- filetype = "block special"; break;- case AE_IFSOCK:- filetype = "socket"; break;- case AE_IFIFO:- filetype = "fifo"; break;- case AE_IFREG:- default:- if (file->hardlink_target != NULL) {- filetype = "hardlink";- filelink = "link";- if (file->hardlink_target == file)- archive_strcpy(&linkto, "original");- else- archive_string_sprintf(&linkto, "%d",- file->hardlink_target->id);- } else- filetype = "file";- break;- }- r = xmlwrite_string_attr(a, writer, "type", filetype,- filelink, linkto.s);- archive_string_free(&linkto);- if (r < 0)- return (ARCHIVE_FATAL);-- /*- * On a virtual directory, we record "name" and "type" only.- */- if (file->virtual)- return (ARCHIVE_OK);-- switch (archive_entry_filetype(file->entry)) {- case AE_IFLNK:- /*- * xar utility has checked a file type, which- * a symbolic-link file has referenced.- * For example:- * <link type="directory">../ref/</link>- * The symlink target file is "../ref/" and its- * file type is a directory.- *- * <link type="file">../f</link>- * The symlink target file is "../f" and its- * file type is a regular file.- *- * But our implementation cannot do it, and then we- * always record that a attribute "type" is "broken",- * for example:- * <link type="broken">foo/bar</link>- * It means "foo/bar" is not reachable.- */- r = xmlwrite_string_attr(a, writer, "link",- file->symlink.s,- "type", "broken");- if (r < 0)- return (ARCHIVE_FATAL);- break;- case AE_IFCHR:- case AE_IFBLK:- r = xmlTextWriterStartElement(writer, BAD_CAST("device"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- r = xmlwrite_fstring(a, writer, "major",- "%d", archive_entry_rdevmajor(file->entry));- if (r < 0)- return (ARCHIVE_FATAL);- r = xmlwrite_fstring(a, writer, "minor",- "%d", archive_entry_rdevminor(file->entry));- if (r < 0)- return (ARCHIVE_FATAL);- r = xmlTextWriterEndElement(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- break;- default:- break;- }-- /*- * Make a inode entry, "<inode>".- */- r = xmlwrite_fstring(a, writer, "inode",- "%jd", archive_entry_ino64(file->entry));- if (r < 0)- return (ARCHIVE_FATAL);- if (archive_entry_dev(file->entry) != 0) {- r = xmlwrite_fstring(a, writer, "deviceno",- "%d", archive_entry_dev(file->entry));- if (r < 0)- return (ARCHIVE_FATAL);- }-- /*- * Make a file mode entry, "<mode>".- */- r = xmlwrite_mode(a, writer, "mode",- archive_entry_mode(file->entry));- if (r < 0)- return (ARCHIVE_FATAL);-- /*- * Make a user entry, "<uid>" and "<user>.- */- r = xmlwrite_fstring(a, writer, "uid",- "%d", archive_entry_uid(file->entry));- if (r < 0)- return (ARCHIVE_FATAL);- r = archive_entry_uname_l(file->entry, &p, &len, xar->sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Uname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate uname '%s' to UTF-8",- archive_entry_uname(file->entry));- r2 = ARCHIVE_WARN;- }- if (len > 0) {- r = xmlwrite_string(a, writer, "user", p);- if (r < 0)- return (ARCHIVE_FATAL);- }-- /*- * Make a group entry, "<gid>" and "<group>.- */- r = xmlwrite_fstring(a, writer, "gid",- "%d", archive_entry_gid(file->entry));- if (r < 0)- return (ARCHIVE_FATAL);- r = archive_entry_gname_l(file->entry, &p, &len, xar->sconv);- if (r != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Gname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate gname '%s' to UTF-8",- archive_entry_gname(file->entry));- r2 = ARCHIVE_WARN;- }- if (len > 0) {- r = xmlwrite_string(a, writer, "group", p);- if (r < 0)- return (ARCHIVE_FATAL);- }-- /*- * Make a ctime entry, "<ctime>".- */- if (archive_entry_ctime_is_set(file->entry)) {- r = xmlwrite_time(a, writer, "ctime",- archive_entry_ctime(file->entry), 1);- if (r < 0)- return (ARCHIVE_FATAL);- }-- /*- * Make a mtime entry, "<mtime>".- */- if (archive_entry_mtime_is_set(file->entry)) {- r = xmlwrite_time(a, writer, "mtime",- archive_entry_mtime(file->entry), 1);- if (r < 0)- return (ARCHIVE_FATAL);- }-- /*- * Make a atime entry, "<atime>".- */- if (archive_entry_atime_is_set(file->entry)) {- r = xmlwrite_time(a, writer, "atime",- archive_entry_atime(file->entry), 1);- if (r < 0)- return (ARCHIVE_FATAL);- }-- /*- * Make fflags entries, "<flags>" and "<ext2>".- */- fflags = archive_entry_fflags_text(file->entry);- if (fflags != NULL) {- r = make_fflags_entry(a, writer, "flags", fflags);- if (r < 0)- return (r);- r = make_fflags_entry(a, writer, "ext2", fflags);- if (r < 0)- return (r);- }-- /*- * Make extended attribute entries, "<ea>".- */- archive_entry_xattr_reset(file->entry);- for (heap = file->xattr.first; heap != NULL; heap = heap->next) {- const char *name;- const void *value;- size_t size;-- archive_entry_xattr_next(file->entry,- &name, &value, &size);- r = xmlTextWriterStartElement(writer, BAD_CAST("ea"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- r = xmlTextWriterWriteFormatAttribute(writer,- BAD_CAST("id"), "%d", heap->id);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterWriteAttribute() failed: %d", r);- return (ARCHIVE_FATAL);- }- r = xmlwrite_heap(a, writer, heap);- if (r < 0)- return (ARCHIVE_FATAL);- r = xmlwrite_string(a, writer, "name", name);- if (r < 0)- return (ARCHIVE_FATAL);-- r = xmlTextWriterEndElement(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- }-- /*- * Make a file data entry, "<data>".- */- if (file->data.length > 0) {- r = xmlTextWriterStartElement(writer, BAD_CAST("data"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() failed: %d", r);- return (ARCHIVE_FATAL);- }-- r = xmlwrite_heap(a, writer, &(file->data));- if (r < 0)- return (ARCHIVE_FATAL);-- r = xmlTextWriterEndElement(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- }-- if (archive_strlen(&file->script) > 0) {- r = xmlTextWriterStartElement(writer, BAD_CAST("content"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() failed: %d", r);- return (ARCHIVE_FATAL);- }-- r = xmlwrite_string(a, writer,- "interpreter", file->script.s);- if (r < 0)- return (ARCHIVE_FATAL);-- r = xmlwrite_string(a, writer, "type", "script");- if (r < 0)- return (ARCHIVE_FATAL);-- r = xmlTextWriterEndElement(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndElement() failed: %d", r);- return (ARCHIVE_FATAL);- }- }-- return (r2);-}--/*- * Make the TOC- */-static int-make_toc(struct archive_write *a)-{- struct xar *xar;- struct file *np;- xmlBufferPtr bp;- xmlTextWriterPtr writer;- int algsize;- int r, ret;-- xar = (struct xar *)a->format_data;-- ret = ARCHIVE_FATAL;-- /*- * Initialize xml writer.- */- writer = NULL;- bp = xmlBufferCreate();- if (bp == NULL) {- archive_set_error(&a->archive, ENOMEM,- "xmlBufferCreate() "- "couldn't create xml buffer");- goto exit_toc;- }- writer = xmlNewTextWriterMemory(bp, 0);- if (writer == NULL) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlNewTextWriterMemory() "- "couldn't create xml writer");- goto exit_toc;- }- r = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartDocument() failed: %d", r);- goto exit_toc;- }- r = xmlTextWriterSetIndent(writer, 4);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterSetIndent() failed: %d", r);- goto exit_toc;- }-- /*- * Start recording TOC- */- r = xmlTextWriterStartElement(writer, BAD_CAST("xar"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() failed: %d", r);- goto exit_toc;- }- r = xmlTextWriterStartElement(writer, BAD_CAST("toc"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartDocument() failed: %d", r);- goto exit_toc;- }-- /*- * Record the creation time of the archive file.- */- r = xmlwrite_time(a, writer, "creation-time", time(NULL), 0);- if (r < 0)- goto exit_toc;-- /*- * Record the checksum value of TOC- */- algsize = getalgsize(xar->opt_toc_sumalg);- if (algsize) {- /*- * Record TOC checksum- */- r = xmlTextWriterStartElement(writer, BAD_CAST("checksum"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() failed: %d", r);- goto exit_toc;- }- r = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"),- BAD_CAST_CONST(getalgname(xar->opt_toc_sumalg)));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterWriteAttribute() failed: %d", r);- goto exit_toc;- }-- /*- * Record the offset of the value of checksum of TOC- */- r = xmlwrite_string(a, writer, "offset", "0");- if (r < 0)- goto exit_toc;-- /*- * Record the size of the value of checksum of TOC- */- r = xmlwrite_fstring(a, writer, "size", "%d", algsize);- if (r < 0)- goto exit_toc;-- r = xmlTextWriterEndElement(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndElement() failed: %d", r);- goto exit_toc;- }- }-- np = xar->root;- do {- if (np != np->parent) {- r = make_file_entry(a, writer, np);- if (r != ARCHIVE_OK)- goto exit_toc;- }-- if (np->dir && np->children.first != NULL) {- /* Enter to sub directories. */- np = np->children.first;- r = xmlTextWriterStartElement(writer,- BAD_CAST("file"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() "- "failed: %d", r);- goto exit_toc;- }- r = xmlTextWriterWriteFormatAttribute(- writer, BAD_CAST("id"), "%d", np->id);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterWriteAttribute() "- "failed: %d", r);- goto exit_toc;- }- continue;- }- while (np != np->parent) {- r = xmlTextWriterEndElement(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndElement() "- "failed: %d", r);- goto exit_toc;- }- if (np->chnext == NULL) {- /* Return to the parent directory. */- np = np->parent;- } else {- np = np->chnext;- r = xmlTextWriterStartElement(writer,- BAD_CAST("file"));- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterStartElement() "- "failed: %d", r);- goto exit_toc;- }- r = xmlTextWriterWriteFormatAttribute(- writer, BAD_CAST("id"), "%d", np->id);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterWriteAttribute() "- "failed: %d", r);- goto exit_toc;- }- break;- }- }- } while (np != np->parent);-- r = xmlTextWriterEndDocument(writer);- if (r < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "xmlTextWriterEndDocument() failed: %d", r);- goto exit_toc;- }-#if DEBUG_PRINT_TOC- fprintf(stderr, "\n---TOC-- %d bytes --\n%s\n",- strlen((const char *)bp->content), bp->content);-#endif-- /*- * Compress the TOC and calculate the sum of the TOC.- */- xar->toc.temp_offset = xar->temp_offset;- xar->toc.size = bp->use;- checksum_init(&(xar->a_sumwrk), xar->opt_toc_sumalg);-- r = compression_init_encoder_gzip(&(a->archive),- &(xar->stream), 6, 1);- if (r != ARCHIVE_OK)- goto exit_toc;- xar->stream.next_in = bp->content;- xar->stream.avail_in = bp->use;- xar->stream.total_in = 0;- xar->stream.next_out = xar->wbuff;- xar->stream.avail_out = sizeof(xar->wbuff);- xar->stream.total_out = 0;- for (;;) {- size_t size;-- r = compression_code(&(a->archive),- &(xar->stream), ARCHIVE_Z_FINISH);- if (r != ARCHIVE_OK && r != ARCHIVE_EOF)- goto exit_toc;- size = sizeof(xar->wbuff) - xar->stream.avail_out;- checksum_update(&(xar->a_sumwrk), xar->wbuff, size);- if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)- goto exit_toc;- if (r == ARCHIVE_EOF)- break;- xar->stream.next_out = xar->wbuff;- xar->stream.avail_out = sizeof(xar->wbuff);- }- r = compression_end(&(a->archive), &(xar->stream));- if (r != ARCHIVE_OK)- goto exit_toc;- xar->toc.length = xar->stream.total_out;- xar->toc.compression = GZIP;- checksum_final(&(xar->a_sumwrk), &(xar->toc.a_sum));-- ret = ARCHIVE_OK;-exit_toc:- if (writer)- xmlFreeTextWriter(writer);- if (bp)- xmlBufferFree(bp);-- return (ret);-}--static int-flush_wbuff(struct archive_write *a)-{- struct xar *xar;- int r;- size_t s;-- xar = (struct xar *)a->format_data;- s = sizeof(xar->wbuff) - xar->wbuff_remaining;- r = __archive_write_output(a, xar->wbuff, s);- if (r != ARCHIVE_OK)- return (r);- xar->wbuff_remaining = sizeof(xar->wbuff);- return (r);-}--static int-copy_out(struct archive_write *a, uint64_t offset, uint64_t length)-{- struct xar *xar;- int r;-- xar = (struct xar *)a->format_data;- if (lseek(xar->temp_fd, offset, SEEK_SET) < 0) {- archive_set_error(&(a->archive), errno, "lseek failed");- return (ARCHIVE_FATAL);- }- while (length) {- size_t rsize;- ssize_t rs;- unsigned char *wb;-- if (length > xar->wbuff_remaining)- rsize = xar->wbuff_remaining;- else- rsize = (size_t)length;- wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);- rs = read(xar->temp_fd, wb, rsize);- if (rs < 0) {- archive_set_error(&(a->archive), errno,- "Can't read temporary file(%jd)",- (intmax_t)rs);- return (ARCHIVE_FATAL);- }- if (rs == 0) {- archive_set_error(&(a->archive), 0,- "Truncated xar archive");- return (ARCHIVE_FATAL);- }- xar->wbuff_remaining -= rs;- length -= rs;- if (xar->wbuff_remaining == 0) {- r = flush_wbuff(a);- if (r != ARCHIVE_OK)- return (r);- }- }- return (ARCHIVE_OK);-}--static int-xar_close(struct archive_write *a)-{- struct xar *xar;- unsigned char *wb;- uint64_t length;- int r;-- xar = (struct xar *)a->format_data;-- /* Empty! */- if (xar->root->children.first == NULL)- return (ARCHIVE_OK);-- /* Save the length of all file extended attributes and contents. */- length = xar->temp_offset;-- /* Connect hardlinked files */- file_connect_hardlink_files(xar);-- /* Make the TOC */- r = make_toc(a);- if (r != ARCHIVE_OK)- return (r);- /*- * Make the xar header on wbuff(write buffer).- */- wb = xar->wbuff;- xar->wbuff_remaining = sizeof(xar->wbuff);- archive_be32enc(&wb[0], HEADER_MAGIC);- archive_be16enc(&wb[4], HEADER_SIZE);- archive_be16enc(&wb[6], HEADER_VERSION);- archive_be64enc(&wb[8], xar->toc.length);- archive_be64enc(&wb[16], xar->toc.size);- archive_be32enc(&wb[24], xar->toc.a_sum.alg);- xar->wbuff_remaining -= HEADER_SIZE;-- /*- * Write the TOC- */- r = copy_out(a, xar->toc.temp_offset, xar->toc.length);- if (r != ARCHIVE_OK)- return (r);-- /* Write the checksum value of the TOC. */- if (xar->toc.a_sum.len) {- if (xar->wbuff_remaining < xar->toc.a_sum.len) {- r = flush_wbuff(a);- if (r != ARCHIVE_OK)- return (r);- }- wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);- memcpy(wb, xar->toc.a_sum.val, xar->toc.a_sum.len);- xar->wbuff_remaining -= xar->toc.a_sum.len;- }-- /*- * Write all file extended attributes and contents.- */- r = copy_out(a, xar->toc.a_sum.len, length);- if (r != ARCHIVE_OK)- return (r);- r = flush_wbuff(a);- return (r);-}--static int-xar_free(struct archive_write *a)-{- struct xar *xar;-- xar = (struct xar *)a->format_data;-- /* Close the temporary file. */- if (xar->temp_fd >= 0)- close(xar->temp_fd);-- archive_string_free(&(xar->cur_dirstr));- archive_string_free(&(xar->tstr));- archive_string_free(&(xar->vstr));- file_free_hardlinks(xar);- file_free_register(xar);- compression_end(&(a->archive), &(xar->stream));- free(xar);-- return (ARCHIVE_OK);-}--static int-file_cmp_node(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- const struct file *f1 = (const struct file *)n1;- const struct file *f2 = (const struct file *)n2;-- return (strcmp(f1->basename.s, f2->basename.s));-}--static int-file_cmp_key(const struct archive_rb_node *n, const void *key)-{- const struct file *f = (const struct file *)n;-- return (strcmp(f->basename.s, (const char *)key));-}--static struct file *-file_new(struct archive_write *a, struct archive_entry *entry)-{- struct file *file;- static const struct archive_rb_tree_ops rb_ops = {- file_cmp_node, file_cmp_key- };-- file = calloc(1, sizeof(*file));- if (file == NULL)- return (NULL);-- if (entry != NULL)- file->entry = archive_entry_clone(entry);- else- file->entry = archive_entry_new2(&a->archive);- if (file->entry == NULL) {- free(file);- return (NULL);- }- __archive_rb_tree_init(&(file->rbtree), &rb_ops);- file->children.first = NULL;- file->children.last = &(file->children.first);- file->xattr.first = NULL;- file->xattr.last = &(file->xattr.first);- archive_string_init(&(file->parentdir));- archive_string_init(&(file->basename));- archive_string_init(&(file->symlink));- archive_string_init(&(file->script));- if (entry != NULL && archive_entry_filetype(entry) == AE_IFDIR)- file->dir = 1;-- return (file);-}--static void-file_free(struct file *file)-{- struct heap_data *heap, *next_heap;-- heap = file->xattr.first;- while (heap != NULL) {- next_heap = heap->next;- free(heap);- heap = next_heap;- }- archive_string_free(&(file->parentdir));- archive_string_free(&(file->basename));- archive_string_free(&(file->symlink));- archive_string_free(&(file->script));- archive_entry_free(file->entry);- free(file);-}--static struct file *-file_create_virtual_dir(struct archive_write *a, struct xar *xar,- const char *pathname)-{- struct file *file;-- (void)xar; /* UNUSED */-- file = file_new(a, NULL);- if (file == NULL)- return (NULL);- archive_entry_set_pathname(file->entry, pathname);- archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);-- file->dir = 1;- file->virtual = 1;-- return (file);-}--static int-file_add_child_tail(struct file *parent, struct file *child)-{- if (!__archive_rb_tree_insert_node(- &(parent->rbtree), (struct archive_rb_node *)child))- return (0);- child->chnext = NULL;- *parent->children.last = child;- parent->children.last = &(child->chnext);- child->parent = parent;- return (1);-}--/*- * Find a entry from `parent'- */-static struct file *-file_find_child(struct file *parent, const char *child_name)-{- struct file *np;-- np = (struct file *)__archive_rb_tree_find_node(- &(parent->rbtree), child_name);- return (np);-}--#if defined(_WIN32) || defined(__CYGWIN__)-static void-cleanup_backslash(char *utf8, size_t len)-{-- /* Convert a path-separator from '\' to '/' */- while (*utf8 != '\0' && len) {- if (*utf8 == '\\')- *utf8 = '/';- ++utf8;- --len;- }-}-#else-#define cleanup_backslash(p, len) /* nop */-#endif--/*- * Generate a parent directory name and a base name from a pathname.- */-static int-file_gen_utility_names(struct archive_write *a, struct file *file)-{- struct xar *xar;- const char *pp;- char *p, *dirname, *slash;- size_t len;- int r = ARCHIVE_OK;-- xar = (struct xar *)a->format_data;- archive_string_empty(&(file->parentdir));- archive_string_empty(&(file->basename));- archive_string_empty(&(file->symlink));-- if (file->parent == file)/* virtual root */- return (ARCHIVE_OK);-- if (archive_entry_pathname_l(file->entry, &pp, &len, xar->sconv)- != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate pathname '%s' to UTF-8",- archive_entry_pathname(file->entry));- r = ARCHIVE_WARN;- }- archive_strncpy(&(file->parentdir), pp, len);- len = file->parentdir.length;- p = dirname = file->parentdir.s;- /*- * Convert a path-separator from '\' to '/'- */- cleanup_backslash(p, len);-- /*- * Remove leading '/', '../' and './' elements- */- while (*p) {- if (p[0] == '/') {- p++;- len--;- } else if (p[0] != '.')- break;- else if (p[1] == '.' && p[2] == '/') {- p += 3;- len -= 3;- } else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {- p += 2;- len -= 2;- } else if (p[1] == '\0') {- p++;- len--;- } else- break;- }- if (p != dirname) {- memmove(dirname, p, len+1);- p = dirname;- }- /*- * Remove "/","/." and "/.." elements from tail.- */- while (len > 0) {- size_t ll = len;-- if (p[len-1] == '/') {- p[len-1] = '\0';- len--;- }- if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {- p[len-2] = '\0';- len -= 2;- }- if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&- p[len-1] == '.') {- p[len-3] = '\0';- len -= 3;- }- if (ll == len)- break;- }- while (*p) {- if (p[0] == '/') {- if (p[1] == '/')- /* Convert '//' --> '/' */- memmove(p, p+1, strlen(p+1) + 1);- else if (p[1] == '.' && p[2] == '/')- /* Convert '/./' --> '/' */- memmove(p, p+2, strlen(p+2) + 1);- else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {- /* Convert 'dir/dir1/../dir2/'- * --> 'dir/dir2/'- */- char *rp = p -1;- while (rp >= dirname) {- if (*rp == '/')- break;- --rp;- }- if (rp > dirname) {- strcpy(rp, p+3);- p = rp;- } else {- strcpy(dirname, p+4);- p = dirname;- }- } else- p++;- } else- p++;- }- p = dirname;- len = strlen(p);-- if (archive_entry_filetype(file->entry) == AE_IFLNK) {- size_t len2;- /* Convert symlink name too. */- if (archive_entry_symlink_l(file->entry, &pp, &len2,- xar->sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Linkname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate symlink '%s' to UTF-8",- archive_entry_symlink(file->entry));- r = ARCHIVE_WARN;- }- archive_strncpy(&(file->symlink), pp, len2);- cleanup_backslash(file->symlink.s, file->symlink.length);- }- /*- * - Count up directory elements.- * - Find out the position which points the last position of- * path separator('/').- */- slash = NULL;- for (; *p != '\0'; p++)- if (*p == '/')- slash = p;- if (slash == NULL) {- /* The pathname doesn't have a parent directory. */- file->parentdir.length = len;- archive_string_copy(&(file->basename), &(file->parentdir));- archive_string_empty(&(file->parentdir));- *file->parentdir.s = '\0';- return (r);- }-- /* Make a basename from dirname and slash */- *slash = '\0';- file->parentdir.length = slash - dirname;- archive_strcpy(&(file->basename), slash + 1);- return (r);-}--static int-get_path_component(char *name, int n, const char *fn)-{- char *p;- int l;-- p = strchr(fn, '/');- if (p == NULL) {- if ((l = strlen(fn)) == 0)- return (0);- } else- l = p - fn;- if (l > n -1)- return (-1);- memcpy(name, fn, l);- name[l] = '\0';-- return (l);-}--/*- * Add a new entry into the tree.- */-static int-file_tree(struct archive_write *a, struct file **filepp)-{-#if defined(_WIN32) && !defined(__CYGWIN__)- char name[_MAX_FNAME];/* Included null terminator size. */-#elif defined(NAME_MAX) && NAME_MAX >= 255- char name[NAME_MAX+1];-#else- char name[256];-#endif- struct xar *xar = (struct xar *)a->format_data;- struct file *dent, *file, *np;- struct archive_entry *ent;- const char *fn, *p;- int l;-- file = *filepp;- dent = xar->root;- if (file->parentdir.length > 0)- fn = p = file->parentdir.s;- else- fn = p = "";-- /*- * If the path of the parent directory of `file' entry is- * the same as the path of `cur_dirent', add isoent to- * `cur_dirent'.- */- if (archive_strlen(&(xar->cur_dirstr))- == archive_strlen(&(file->parentdir)) &&- strcmp(xar->cur_dirstr.s, fn) == 0) {- if (!file_add_child_tail(xar->cur_dirent, file)) {- np = (struct file *)__archive_rb_tree_find_node(- &(xar->cur_dirent->rbtree),- file->basename.s);- goto same_entry;- }- return (ARCHIVE_OK);- }-- for (;;) {- l = get_path_component(name, sizeof(name), fn);- if (l == 0) {- np = NULL;- break;- }- if (l < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "A name buffer is too small");- file_free(file);- *filepp = NULL;- return (ARCHIVE_FATAL);- }-- np = file_find_child(dent, name);- if (np == NULL || fn[0] == '\0')- break;-- /* Find next subdirectory. */- if (!np->dir) {- /* NOT Directory! */- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "`%s' is not directory, we cannot insert `%s' ",- archive_entry_pathname(np->entry),- archive_entry_pathname(file->entry));- file_free(file);- *filepp = NULL;- return (ARCHIVE_FAILED);- }- fn += l;- if (fn[0] == '/')- fn++;- dent = np;- }- if (np == NULL) {- /*- * Create virtual parent directories.- */- while (fn[0] != '\0') {- struct file *vp;- struct archive_string as;-- archive_string_init(&as);- archive_strncat(&as, p, fn - p + l);- if (as.s[as.length-1] == '/') {- as.s[as.length-1] = '\0';- as.length--;- }- vp = file_create_virtual_dir(a, xar, as.s);- if (vp == NULL) {- archive_string_free(&as);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- file_free(file);- *filepp = NULL;- return (ARCHIVE_FATAL);- }- archive_string_free(&as);- if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED)- return (ARCHIVE_FATAL);- file_add_child_tail(dent, vp);- file_register(xar, vp);- np = vp;-- fn += l;- if (fn[0] == '/')- fn++;- l = get_path_component(name, sizeof(name), fn);- if (l < 0) {- archive_string_free(&as);- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "A name buffer is too small");- file_free(file);- *filepp = NULL;- return (ARCHIVE_FATAL);- }- dent = np;- }-- /* Found out the parent directory where isoent can be- * inserted. */- xar->cur_dirent = dent;- archive_string_empty(&(xar->cur_dirstr));- archive_string_ensure(&(xar->cur_dirstr),- archive_strlen(&(dent->parentdir)) +- archive_strlen(&(dent->basename)) + 2);- if (archive_strlen(&(dent->parentdir)) +- archive_strlen(&(dent->basename)) == 0)- xar->cur_dirstr.s[0] = 0;- else {- if (archive_strlen(&(dent->parentdir)) > 0) {- archive_string_copy(&(xar->cur_dirstr),- &(dent->parentdir));- archive_strappend_char(&(xar->cur_dirstr), '/');- }- archive_string_concat(&(xar->cur_dirstr),- &(dent->basename));- }-- if (!file_add_child_tail(dent, file)) {- np = (struct file *)__archive_rb_tree_find_node(- &(dent->rbtree), file->basename.s);- goto same_entry;- }- return (ARCHIVE_OK);- }--same_entry:- /*- * We have already has the entry the filename of which is- * the same.- */- if (archive_entry_filetype(np->entry) !=- archive_entry_filetype(file->entry)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Found duplicate entries `%s' and its file type is "- "different",- archive_entry_pathname(np->entry));- file_free(file);- *filepp = NULL;- return (ARCHIVE_FAILED);- }-- /* Swap files. */- ent = np->entry;- np->entry = file->entry;- file->entry = ent;- np->virtual = 0;-- file_free(file);- *filepp = np;- return (ARCHIVE_OK);-}--static void-file_register(struct xar *xar, struct file *file)-{- file->id = xar->file_idx++;- file->next = NULL;- *xar->file_list.last = file;- xar->file_list.last = &(file->next);-}--static void-file_init_register(struct xar *xar)-{- xar->file_list.first = NULL;- xar->file_list.last = &(xar->file_list.first);-}--static void-file_free_register(struct xar *xar)-{- struct file *file, *file_next;-- file = xar->file_list.first;- while (file != NULL) {- file_next = file->next;- file_free(file);- file = file_next;- }-}--/*- * Register entry to get a hardlink target.- */-static int-file_register_hardlink(struct archive_write *a, struct file *file)-{- struct xar *xar = (struct xar *)a->format_data;- struct hardlink *hl;- const char *pathname;-- archive_entry_set_nlink(file->entry, 1);- pathname = archive_entry_hardlink(file->entry);- if (pathname == NULL) {- /* This `file` is a hardlink target. */- hl = malloc(sizeof(*hl));- if (hl == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory");- return (ARCHIVE_FATAL);- }- hl->nlink = 1;- /* A hardlink target must be the first position. */- file->hlnext = NULL;- hl->file_list.first = file;- hl->file_list.last = &(file->hlnext);- __archive_rb_tree_insert_node(&(xar->hardlink_rbtree),- (struct archive_rb_node *)hl);- } else {- hl = (struct hardlink *)__archive_rb_tree_find_node(- &(xar->hardlink_rbtree), pathname);- if (hl != NULL) {- /* Insert `file` entry into the tail. */- file->hlnext = NULL;- *hl->file_list.last = file;- hl->file_list.last = &(file->hlnext);- hl->nlink++;- }- archive_entry_unset_size(file->entry);- }-- return (ARCHIVE_OK);-}--/*- * Hardlinked files have to have the same location of extent.- * We have to find out hardlink target entries for entries which- * have a hardlink target name.- */-static void-file_connect_hardlink_files(struct xar *xar)-{- struct archive_rb_node *n;- struct hardlink *hl;- struct file *target, *nf;-- ARCHIVE_RB_TREE_FOREACH(n, &(xar->hardlink_rbtree)) {- hl = (struct hardlink *)n;-- /* The first entry must be a hardlink target. */- target = hl->file_list.first;- archive_entry_set_nlink(target->entry, hl->nlink);- if (hl->nlink > 1)- /* It means this file is a hardlink- * target itself. */- target->hardlink_target = target;- for (nf = target->hlnext;- nf != NULL; nf = nf->hlnext) {- nf->hardlink_target = target;- archive_entry_set_nlink(nf->entry, hl->nlink);- }- }-}--static int-file_hd_cmp_node(const struct archive_rb_node *n1,- const struct archive_rb_node *n2)-{- const struct hardlink *h1 = (const struct hardlink *)n1;- const struct hardlink *h2 = (const struct hardlink *)n2;-- return (strcmp(archive_entry_pathname(h1->file_list.first->entry),- archive_entry_pathname(h2->file_list.first->entry)));-}--static int-file_hd_cmp_key(const struct archive_rb_node *n, const void *key)-{- const struct hardlink *h = (const struct hardlink *)n;-- return (strcmp(archive_entry_pathname(h->file_list.first->entry),- (const char *)key));-}---static void-file_init_hardlinks(struct xar *xar)-{- static const struct archive_rb_tree_ops rb_ops = {- file_hd_cmp_node, file_hd_cmp_key,- };-- __archive_rb_tree_init(&(xar->hardlink_rbtree), &rb_ops);-}--static void-file_free_hardlinks(struct xar *xar)-{- struct archive_rb_node *n, *tmp;-- ARCHIVE_RB_TREE_FOREACH_SAFE(n, &(xar->hardlink_rbtree), tmp) {- __archive_rb_tree_remove_node(&(xar->hardlink_rbtree), n);- free(n);- }-}--static void-checksum_init(struct chksumwork *sumwrk, enum sumalg sum_alg)-{- sumwrk->alg = sum_alg;- switch (sum_alg) {- case CKSUM_NONE:- break;- case CKSUM_SHA1:- archive_sha1_init(&(sumwrk->sha1ctx));- break;- case CKSUM_MD5:- archive_md5_init(&(sumwrk->md5ctx));- break;- }-}--static void-checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)-{-- switch (sumwrk->alg) {- case CKSUM_NONE:- break;- case CKSUM_SHA1:- archive_sha1_update(&(sumwrk->sha1ctx), buff, size);- break;- case CKSUM_MD5:- archive_md5_update(&(sumwrk->md5ctx), buff, size);- break;- }-}--static void-checksum_final(struct chksumwork *sumwrk, struct chksumval *sumval)-{-- switch (sumwrk->alg) {- case CKSUM_NONE:- sumval->len = 0;- break;- case CKSUM_SHA1:- archive_sha1_final(&(sumwrk->sha1ctx), sumval->val);- sumval->len = SHA1_SIZE;- break;- case CKSUM_MD5:- archive_md5_final(&(sumwrk->md5ctx), sumval->val);- sumval->len = MD5_SIZE;- break;- }- sumval->alg = sumwrk->alg;-}--#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)-static int-compression_unsupported_encoder(struct archive *a,- struct la_zstream *lastrm, const char *name)-{-- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "%s compression not supported on this platform", name);- lastrm->valid = 0;- lastrm->real_stream = NULL;- return (ARCHIVE_FAILED);-}-#endif--static int-compression_init_encoder_gzip(struct archive *a,- struct la_zstream *lastrm, int level, int withheader)-{- z_stream *strm;-- if (lastrm->valid)- compression_end(a, lastrm);- strm = calloc(1, sizeof(*strm));- if (strm == NULL) {- archive_set_error(a, ENOMEM,- "Can't allocate memory for gzip stream");- return (ARCHIVE_FATAL);- }- /* zlib.h is not const-correct, so we need this one bit- * of ugly hackery to convert a const * pointer to- * a non-const pointer. */- strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;- strm->avail_in = lastrm->avail_in;- strm->total_in = (uLong)lastrm->total_in;- strm->next_out = lastrm->next_out;- strm->avail_out = lastrm->avail_out;- strm->total_out = (uLong)lastrm->total_out;- if (deflateInit2(strm, level, Z_DEFLATED,- (withheader)?15:-15,- 8, Z_DEFAULT_STRATEGY) != Z_OK) {- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Internal error initializing compression library");- return (ARCHIVE_FATAL);- }- lastrm->real_stream = strm;- lastrm->valid = 1;- lastrm->code = compression_code_gzip;- lastrm->end = compression_end_gzip;- return (ARCHIVE_OK);-}--static int-compression_code_gzip(struct archive *a,- struct la_zstream *lastrm, enum la_zaction action)-{- z_stream *strm;- int r;-- strm = (z_stream *)lastrm->real_stream;- /* zlib.h is not const-correct, so we need this one bit- * of ugly hackery to convert a const * pointer to- * a non-const pointer. */- strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;- strm->avail_in = lastrm->avail_in;- strm->total_in = (uLong)lastrm->total_in;- strm->next_out = lastrm->next_out;- strm->avail_out = lastrm->avail_out;- strm->total_out = (uLong)lastrm->total_out;- r = deflate(strm,- (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);- lastrm->next_in = strm->next_in;- lastrm->avail_in = strm->avail_in;- lastrm->total_in = strm->total_in;- lastrm->next_out = strm->next_out;- lastrm->avail_out = strm->avail_out;- lastrm->total_out = strm->total_out;- switch (r) {- case Z_OK:- return (ARCHIVE_OK);- case Z_STREAM_END:- return (ARCHIVE_EOF);- default:- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "GZip compression failed:"- " deflate() call returned status %d", r);- return (ARCHIVE_FATAL);- }-}--static int-compression_end_gzip(struct archive *a, struct la_zstream *lastrm)-{- z_stream *strm;- int r;-- strm = (z_stream *)lastrm->real_stream;- r = deflateEnd(strm);- free(strm);- lastrm->real_stream = NULL;- lastrm->valid = 0;- if (r != Z_OK) {- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Failed to clean up compressor");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}--#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)-static int-compression_init_encoder_bzip2(struct archive *a,- struct la_zstream *lastrm, int level)-{- bz_stream *strm;-- if (lastrm->valid)- compression_end(a, lastrm);- strm = calloc(1, sizeof(*strm));- if (strm == NULL) {- archive_set_error(a, ENOMEM,- "Can't allocate memory for bzip2 stream");- return (ARCHIVE_FATAL);- }- /* bzlib.h is not const-correct, so we need this one bit- * of ugly hackery to convert a const * pointer to- * a non-const pointer. */- strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;- strm->avail_in = lastrm->avail_in;- strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);- strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);- strm->next_out = (char *)lastrm->next_out;- strm->avail_out = lastrm->avail_out;- strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);- strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);- if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Internal error initializing compression library");- return (ARCHIVE_FATAL);- }- lastrm->real_stream = strm;- lastrm->valid = 1;- lastrm->code = compression_code_bzip2;- lastrm->end = compression_end_bzip2;- return (ARCHIVE_OK);-}--static int-compression_code_bzip2(struct archive *a,- struct la_zstream *lastrm, enum la_zaction action)-{- bz_stream *strm;- int r;-- strm = (bz_stream *)lastrm->real_stream;- /* bzlib.h is not const-correct, so we need this one bit- * of ugly hackery to convert a const * pointer to- * a non-const pointer. */- strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;- strm->avail_in = lastrm->avail_in;- strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);- strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);- strm->next_out = (char *)lastrm->next_out;- strm->avail_out = lastrm->avail_out;- strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);- strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);- r = BZ2_bzCompress(strm,- (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);- lastrm->next_in = (const unsigned char *)strm->next_in;- lastrm->avail_in = strm->avail_in;- lastrm->total_in =- (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)- + (uint64_t)(uint32_t)strm->total_in_lo32;- lastrm->next_out = (unsigned char *)strm->next_out;- lastrm->avail_out = strm->avail_out;- lastrm->total_out =- (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)- + (uint64_t)(uint32_t)strm->total_out_lo32;- switch (r) {- case BZ_RUN_OK: /* Non-finishing */- case BZ_FINISH_OK: /* Finishing: There's more work to do */- return (ARCHIVE_OK);- case BZ_STREAM_END: /* Finishing: all done */- /* Only occurs in finishing case */- return (ARCHIVE_EOF);- default:- /* Any other return value indicates an error */- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Bzip2 compression failed:"- " BZ2_bzCompress() call returned status %d", r);- return (ARCHIVE_FATAL);- }-}--static int-compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)-{- bz_stream *strm;- int r;-- strm = (bz_stream *)lastrm->real_stream;- r = BZ2_bzCompressEnd(strm);- free(strm);- lastrm->real_stream = NULL;- lastrm->valid = 0;- if (r != BZ_OK) {- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Failed to clean up compressor");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}--#else-static int-compression_init_encoder_bzip2(struct archive *a,- struct la_zstream *lastrm, int level)-{-- (void) level; /* UNUSED */- if (lastrm->valid)- compression_end(a, lastrm);- return (compression_unsupported_encoder(a, lastrm, "bzip2"));-}-#endif--#if defined(HAVE_LZMA_H)-static int-compression_init_encoder_lzma(struct archive *a,- struct la_zstream *lastrm, int level)-{- static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;- lzma_stream *strm;- lzma_options_lzma lzma_opt;- int r;-- if (lastrm->valid)- compression_end(a, lastrm);- if (lzma_lzma_preset(&lzma_opt, level)) {- lastrm->real_stream = NULL;- archive_set_error(a, ENOMEM,- "Internal error initializing compression library");- return (ARCHIVE_FATAL);- }- strm = calloc(1, sizeof(*strm));- if (strm == NULL) {- archive_set_error(a, ENOMEM,- "Can't allocate memory for lzma stream");- return (ARCHIVE_FATAL);- }- *strm = lzma_init_data;- r = lzma_alone_encoder(strm, &lzma_opt);- switch (r) {- case LZMA_OK:- lastrm->real_stream = strm;- lastrm->valid = 1;- lastrm->code = compression_code_lzma;- lastrm->end = compression_end_lzma;- r = ARCHIVE_OK;- break;- case LZMA_MEM_ERROR:- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ENOMEM,- "Internal error initializing compression library: "- "Cannot allocate memory");- r = ARCHIVE_FATAL;- break;- default:- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Internal error initializing compression library: "- "It's a bug in liblzma");- r = ARCHIVE_FATAL;- break;- }- return (r);-}--static int-compression_init_encoder_xz(struct archive *a,- struct la_zstream *lastrm, int level, int threads)-{- static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;- lzma_stream *strm;- lzma_filter *lzmafilters;- lzma_options_lzma lzma_opt;- int r;-#ifdef HAVE_LZMA_STREAM_ENCODER_MT- lzma_mt mt_options;-#endif-- (void)threads; /* UNUSED (if multi-threaded LZMA library not avail) */-- if (lastrm->valid)- compression_end(a, lastrm);- strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);- if (strm == NULL) {- archive_set_error(a, ENOMEM,- "Can't allocate memory for xz stream");- return (ARCHIVE_FATAL);- }- lzmafilters = (lzma_filter *)(strm+1);- if (level > 9)- level = 9;- if (lzma_lzma_preset(&lzma_opt, level)) {- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ENOMEM,- "Internal error initializing compression library");- return (ARCHIVE_FATAL);- }- lzmafilters[0].id = LZMA_FILTER_LZMA2;- lzmafilters[0].options = &lzma_opt;- lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */-- *strm = lzma_init_data;-#ifdef HAVE_LZMA_STREAM_ENCODER_MT- if (threads > 1) {- memset(&mt_options, 0, sizeof(mt_options));- mt_options.threads = threads;- mt_options.timeout = 300;- mt_options.filters = lzmafilters;- mt_options.check = LZMA_CHECK_CRC64;- r = lzma_stream_encoder_mt(strm, &mt_options);- } else-#endif- r = lzma_stream_encoder(strm, lzmafilters, LZMA_CHECK_CRC64);- switch (r) {- case LZMA_OK:- lastrm->real_stream = strm;- lastrm->valid = 1;- lastrm->code = compression_code_lzma;- lastrm->end = compression_end_lzma;- r = ARCHIVE_OK;- break;- case LZMA_MEM_ERROR:- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ENOMEM,- "Internal error initializing compression library: "- "Cannot allocate memory");- r = ARCHIVE_FATAL;- break;- default:- free(strm);- lastrm->real_stream = NULL;- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "Internal error initializing compression library: "- "It's a bug in liblzma");- r = ARCHIVE_FATAL;- break;- }- return (r);-}--static int-compression_code_lzma(struct archive *a,- struct la_zstream *lastrm, enum la_zaction action)-{- lzma_stream *strm;- int r;-- strm = (lzma_stream *)lastrm->real_stream;- strm->next_in = lastrm->next_in;- strm->avail_in = lastrm->avail_in;- strm->total_in = lastrm->total_in;- strm->next_out = lastrm->next_out;- strm->avail_out = lastrm->avail_out;- strm->total_out = lastrm->total_out;- r = lzma_code(strm,- (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);- lastrm->next_in = strm->next_in;- lastrm->avail_in = strm->avail_in;- lastrm->total_in = strm->total_in;- lastrm->next_out = strm->next_out;- lastrm->avail_out = strm->avail_out;- lastrm->total_out = strm->total_out;- switch (r) {- case LZMA_OK:- /* Non-finishing case */- return (ARCHIVE_OK);- case LZMA_STREAM_END:- /* This return can only occur in finishing case. */- return (ARCHIVE_EOF);- case LZMA_MEMLIMIT_ERROR:- archive_set_error(a, ENOMEM,- "lzma compression error:"- " %ju MiB would have been needed",- (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)- / (1024 * 1024)));- return (ARCHIVE_FATAL);- default:- /* Any other return value indicates an error */- archive_set_error(a, ARCHIVE_ERRNO_MISC,- "lzma compression failed:"- " lzma_code() call returned status %d", r);- return (ARCHIVE_FATAL);- }-}--static int-compression_end_lzma(struct archive *a, struct la_zstream *lastrm)-{- lzma_stream *strm;-- (void)a; /* UNUSED */- strm = (lzma_stream *)lastrm->real_stream;- lzma_end(strm);- free(strm);- lastrm->valid = 0;- lastrm->real_stream = NULL;- return (ARCHIVE_OK);-}-#else-static int-compression_init_encoder_lzma(struct archive *a,- struct la_zstream *lastrm, int level)-{-- (void) level; /* UNUSED */- if (lastrm->valid)- compression_end(a, lastrm);- return (compression_unsupported_encoder(a, lastrm, "lzma"));-}-static int-compression_init_encoder_xz(struct archive *a,- struct la_zstream *lastrm, int level, int threads)-{-- (void) level; /* UNUSED */- (void) threads; /* UNUSED */- if (lastrm->valid)- compression_end(a, lastrm);- return (compression_unsupported_encoder(a, lastrm, "xz"));-}-#endif--static int-xar_compression_init_encoder(struct archive_write *a)-{- struct xar *xar;- int r;-- xar = (struct xar *)a->format_data;- switch (xar->opt_compression) {- case GZIP:- r = compression_init_encoder_gzip(- &(a->archive), &(xar->stream),- xar->opt_compression_level, 1);- break;- case BZIP2:- r = compression_init_encoder_bzip2(- &(a->archive), &(xar->stream),- xar->opt_compression_level);- break;- case LZMA:- r = compression_init_encoder_lzma(- &(a->archive), &(xar->stream),- xar->opt_compression_level);- break;- case XZ:- r = compression_init_encoder_xz(- &(a->archive), &(xar->stream),- xar->opt_compression_level, xar->opt_threads);- break;- default:- r = ARCHIVE_OK;- break;- }- if (r == ARCHIVE_OK) {- xar->stream.total_in = 0;- xar->stream.next_out = xar->wbuff;- xar->stream.avail_out = sizeof(xar->wbuff);- xar->stream.total_out = 0;- }-- return (r);-}--static int-compression_code(struct archive *a, struct la_zstream *lastrm,- enum la_zaction action)-{- if (lastrm->valid)- return (lastrm->code(a, lastrm, action));- return (ARCHIVE_OK);-}--static int-compression_end(struct archive *a, struct la_zstream *lastrm)-{- if (lastrm->valid)- return (lastrm->end(a, lastrm));- return (ARCHIVE_OK);-}---static int-save_xattrs(struct archive_write *a, struct file *file)-{- struct xar *xar;- const char *name;- const void *value;- struct heap_data *heap;- size_t size;- int count, r;-- xar = (struct xar *)a->format_data;- count = archive_entry_xattr_reset(file->entry);- if (count == 0)- return (ARCHIVE_OK);- while (count--) {- archive_entry_xattr_next(file->entry,- &name, &value, &size);- checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);- checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);-- heap = calloc(1, sizeof(*heap));- if (heap == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for xattr");- return (ARCHIVE_FATAL);- }- heap->id = file->ea_idx++;- heap->temp_offset = xar->temp_offset;- heap->size = size;/* save a extracted size */- heap->compression = xar->opt_compression;- /* Get a extracted sumcheck value. */- checksum_update(&(xar->e_sumwrk), value, size);- checksum_final(&(xar->e_sumwrk), &(heap->e_sum));-- /*- * Not compression to xattr is simple way.- */- if (heap->compression == NONE) {- checksum_update(&(xar->a_sumwrk), value, size);- checksum_final(&(xar->a_sumwrk), &(heap->a_sum));- if (write_to_temp(a, value, size)- != ARCHIVE_OK) {- free(heap);- return (ARCHIVE_FATAL);- }- heap->length = size;- /* Add heap to the tail of file->xattr. */- heap->next = NULL;- *file->xattr.last = heap;- file->xattr.last = &(heap->next);- /* Next xattr */- continue;- }-- /*- * Init compression library.- */- r = xar_compression_init_encoder(a);- if (r != ARCHIVE_OK) {- free(heap);- return (ARCHIVE_FATAL);- }-- xar->stream.next_in = (const unsigned char *)value;- xar->stream.avail_in = size;- for (;;) {- r = compression_code(&(a->archive),- &(xar->stream), ARCHIVE_Z_FINISH);- if (r != ARCHIVE_OK && r != ARCHIVE_EOF) {- free(heap);- return (ARCHIVE_FATAL);- }- size = sizeof(xar->wbuff) - xar->stream.avail_out;- checksum_update(&(xar->a_sumwrk),- xar->wbuff, size);- if (write_to_temp(a, xar->wbuff, size)- != ARCHIVE_OK) {- free(heap);- return (ARCHIVE_FATAL);- }- if (r == ARCHIVE_OK) {- xar->stream.next_out = xar->wbuff;- xar->stream.avail_out = sizeof(xar->wbuff);- } else {- checksum_final(&(xar->a_sumwrk),- &(heap->a_sum));- heap->length = xar->stream.total_out;- /* Add heap to the tail of file->xattr. */- heap->next = NULL;- *file->xattr.last = heap;- file->xattr.last = &(heap->next);- break;- }- }- /* Clean up compression library. */- r = compression_end(&(a->archive), &(xar->stream));- if (r != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}--static int-getalgsize(enum sumalg sumalg)-{- switch (sumalg) {- default:- case CKSUM_NONE:- return (0);- case CKSUM_SHA1:- return (SHA1_SIZE);- case CKSUM_MD5:- return (MD5_SIZE);- }-}--static const char *-getalgname(enum sumalg sumalg)-{- switch (sumalg) {- default:- case CKSUM_NONE:- return (NULL);- case CKSUM_SHA1:- return (SHA1_NAME);- case CKSUM_MD5:- return (MD5_NAME);- }-}--#endif /* Support xar format */
− c/archive_write_set_format_zip.c
@@ -1,1693 +0,0 @@-/*-- * Copyright (c) 2008 Anselm Strauss- * Copyright (c) 2009 Joerg Sonnenberger- * Copyright (c) 2011-2012,2014 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--/*- * Development supported by Google Summer of Code 2008.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_zip.c 201168 2009-12-29 06:15:32Z kientzle $");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#ifdef HAVE_LANGINFO_H-#include <langinfo.h>-#endif-#ifdef HAVE_STDLIB_H-#include <stdlib.h>-#endif-#ifdef HAVE_STRING_H-#include <string.h>-#endif-#ifdef HAVE_ZLIB_H-#include <zlib.h>-#endif--#include "archive.h"-#include "archive_cryptor_private.h"-#include "archive_endian.h"-#include "archive_entry.h"-#include "archive_entry_locale.h"-#include "archive_hmac_private.h"-#include "archive_private.h"-#include "archive_random_private.h"-#include "archive_write_private.h"-#include "archive_write_set_format_private.h"--#ifndef HAVE_ZLIB_H-#include "archive_crc32.h"-#endif--#define ZIP_ENTRY_FLAG_ENCRYPTED (1<<0)-#define ZIP_ENTRY_FLAG_LENGTH_AT_END (1<<3)-#define ZIP_ENTRY_FLAG_UTF8_NAME (1 << 11)--#define ZIP_4GB_MAX ARCHIVE_LITERAL_LL(0xffffffff)-#define ZIP_4GB_MAX_UNCOMPRESSED ARCHIVE_LITERAL_LL(0xff000000)--enum compression {- COMPRESSION_UNSPECIFIED = -1,- COMPRESSION_STORE = 0,- COMPRESSION_DEFLATE = 8-};--#ifdef HAVE_ZLIB_H-#define COMPRESSION_DEFAULT COMPRESSION_DEFLATE-#else-#define COMPRESSION_DEFAULT COMPRESSION_STORE-#endif--enum encryption {- ENCRYPTION_NONE = 0,- ENCRYPTION_TRADITIONAL, /* Traditional PKWARE encryption. */- ENCRYPTION_WINZIP_AES128, /* WinZIP AES-128 encryption. */- ENCRYPTION_WINZIP_AES256, /* WinZIP AES-256 encryption. */-};--#define TRAD_HEADER_SIZE 12-/*- * See "WinZip - AES Encryption Information"- * http://www.winzip.com/aes_info.htm- */-/* Value used in compression method. */-#define WINZIP_AES_ENCRYPTION 99-/* A WinZip AES header size which is stored at the beginning of- * file contents. */-#define WINZIP_AES128_HEADER_SIZE (8 + 2)-#define WINZIP_AES256_HEADER_SIZE (16 + 2)-/* AES vendor version. */-#define AES_VENDOR_AE_1 0x0001-#define AES_VENDOR_AE_2 0x0002-/* Authentication code size. */-#define AUTH_CODE_SIZE 10-/**/-#define MAX_DERIVED_KEY_BUF_SIZE (AES_MAX_KEY_SIZE * 2 + 2)--struct cd_segment {- struct cd_segment *next;- size_t buff_size;- unsigned char *buff;- unsigned char *p;-};--struct trad_enc_ctx {- uint32_t keys[3];-};--struct zip {-- int64_t entry_offset;- int64_t entry_compressed_size;- int64_t entry_uncompressed_size;- int64_t entry_compressed_written;- int64_t entry_uncompressed_written;- int64_t entry_uncompressed_limit;- struct archive_entry *entry;- uint32_t entry_crc32;- enum compression entry_compression;- enum encryption entry_encryption;- int entry_flags;- int entry_uses_zip64;- int experiments;- struct trad_enc_ctx tctx;- char tctx_valid;- unsigned char trad_chkdat;- unsigned aes_vendor;- archive_crypto_ctx cctx;- char cctx_valid;- archive_hmac_sha1_ctx hctx;- char hctx_valid;-- unsigned char *file_header;- size_t file_header_extra_offset;- unsigned long (*crc32func)(unsigned long crc, const void *buff, size_t len);-- struct cd_segment *central_directory;- struct cd_segment *central_directory_last;- size_t central_directory_bytes;- size_t central_directory_entries;-- int64_t written_bytes; /* Overall position in file. */-- struct archive_string_conv *opt_sconv;- struct archive_string_conv *sconv_default;- enum compression requested_compression;- int deflate_compression_level;- int init_default_conversion;- enum encryption encryption_type;--#define ZIP_FLAG_AVOID_ZIP64 1-#define ZIP_FLAG_FORCE_ZIP64 2-#define ZIP_FLAG_EXPERIMENT_xl 4- int flags;--#ifdef HAVE_ZLIB_H- z_stream stream;-#endif- size_t len_buf;- unsigned char *buf;-};--/* Don't call this min or MIN, since those are already defined- on lots of platforms (but not all). */-#define zipmin(a, b) ((a) > (b) ? (b) : (a))--static ssize_t archive_write_zip_data(struct archive_write *,- const void *buff, size_t s);-static int archive_write_zip_close(struct archive_write *);-static int archive_write_zip_free(struct archive_write *);-static int archive_write_zip_finish_entry(struct archive_write *);-static int archive_write_zip_header(struct archive_write *,- struct archive_entry *);-static int archive_write_zip_options(struct archive_write *,- const char *, const char *);-static unsigned int dos_time(const time_t);-static size_t path_length(struct archive_entry *);-static int write_path(struct archive_entry *, struct archive_write *);-static void copy_path(struct archive_entry *, unsigned char *);-static struct archive_string_conv *get_sconv(struct archive_write *, struct zip *);-static int trad_enc_init(struct trad_enc_ctx *, const char *, size_t);-static unsigned trad_enc_encrypt_update(struct trad_enc_ctx *, const uint8_t *,- size_t, uint8_t *, size_t);-static int init_traditional_pkware_encryption(struct archive_write *);-static int is_traditional_pkware_encryption_supported(void);-static int init_winzip_aes_encryption(struct archive_write *);-static int is_winzip_aes_encryption_supported(int encryption);--static unsigned char *-cd_alloc(struct zip *zip, size_t length)-{- unsigned char *p;-- if (zip->central_directory == NULL- || (zip->central_directory_last->p + length- > zip->central_directory_last->buff + zip->central_directory_last->buff_size)) {- struct cd_segment *segment = calloc(1, sizeof(*segment));- if (segment == NULL)- return NULL;- segment->buff_size = 64 * 1024;- segment->buff = malloc(segment->buff_size);- if (segment->buff == NULL) {- free(segment);- return NULL;- }- segment->p = segment->buff;-- if (zip->central_directory == NULL) {- zip->central_directory- = zip->central_directory_last- = segment;- } else {- zip->central_directory_last->next = segment;- zip->central_directory_last = segment;- }- }-- p = zip->central_directory_last->p;- zip->central_directory_last->p += length;- zip->central_directory_bytes += length;- return (p);-}--static unsigned long-real_crc32(unsigned long crc, const void *buff, size_t len)-{- return crc32(crc, buff, (unsigned int)len);-}--static unsigned long-fake_crc32(unsigned long crc, const void *buff, size_t len)-{- (void)crc; /* UNUSED */- (void)buff; /* UNUSED */- (void)len; /* UNUSED */- return 0;-}--static int-archive_write_zip_options(struct archive_write *a, const char *key,- const char *val)-{- struct zip *zip = a->format_data;- int ret = ARCHIVE_FAILED;-- if (strcmp(key, "compression") == 0) {- /*- * Set compression to use on all future entries.- * This only affects regular files.- */- if (val == NULL || val[0] == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: compression option needs a compression name",- a->format_name);- } else if (strcmp(val, "deflate") == 0) {-#ifdef HAVE_ZLIB_H- zip->requested_compression = COMPRESSION_DEFLATE;- ret = ARCHIVE_OK;-#else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "deflate compression not supported");-#endif- } else if (strcmp(val, "store") == 0) {- zip->requested_compression = COMPRESSION_STORE;- ret = ARCHIVE_OK;- }- return (ret);- } else if (strcmp(key, "compression-level") == 0) {- if (val == NULL || !(val[0] >= '0' && val[0] <= '9') || val[1] != '\0') {- return ARCHIVE_WARN;- }-- if (val[0] == '0') {- zip->requested_compression = COMPRESSION_STORE;- return ARCHIVE_OK;- } else {-#ifdef HAVE_ZLIB_H- zip->requested_compression = COMPRESSION_DEFLATE;- zip->deflate_compression_level = val[0] - '0';- return ARCHIVE_OK;-#else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "deflate compression not supported");-#endif- }- } else if (strcmp(key, "encryption") == 0) {- if (val == NULL) {- zip->encryption_type = ENCRYPTION_NONE;- ret = ARCHIVE_OK;- } else if (val[0] == '1' || strcmp(val, "traditional") == 0- || strcmp(val, "zipcrypt") == 0- || strcmp(val, "ZipCrypt") == 0) {- if (is_traditional_pkware_encryption_supported()) {- zip->encryption_type = ENCRYPTION_TRADITIONAL;- ret = ARCHIVE_OK;- } else {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "encryption not supported");- }- } else if (strcmp(val, "aes128") == 0) {- if (is_winzip_aes_encryption_supported(- ENCRYPTION_WINZIP_AES128)) {- zip->encryption_type = ENCRYPTION_WINZIP_AES128;- ret = ARCHIVE_OK;- } else {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "encryption not supported");- }- } else if (strcmp(val, "aes256") == 0) {- if (is_winzip_aes_encryption_supported(- ENCRYPTION_WINZIP_AES256)) {- zip->encryption_type = ENCRYPTION_WINZIP_AES256;- ret = ARCHIVE_OK;- } else {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "encryption not supported");- }- } else {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: unknown encryption '%s'",- a->format_name, val);- }- return (ret);- } else if (strcmp(key, "experimental") == 0) {- if (val == NULL || val[0] == 0) {- zip->flags &= ~ ZIP_FLAG_EXPERIMENT_xl;- } else {- zip->flags |= ZIP_FLAG_EXPERIMENT_xl;- }- return (ARCHIVE_OK);- } else if (strcmp(key, "fakecrc32") == 0) {- /*- * FOR TESTING ONLY: disable CRC calculation to speed up- * certain complex tests.- */- if (val == NULL || val[0] == 0) {- zip->crc32func = real_crc32;- } else {- zip->crc32func = fake_crc32;- }- return (ARCHIVE_OK);- } else if (strcmp(key, "hdrcharset") == 0) {- /*- * Set the character set used in translating filenames.- */- if (val == NULL || val[0] == 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "%s: hdrcharset option needs a character-set name",- a->format_name);- } else {- zip->opt_sconv = archive_string_conversion_to_charset(- &a->archive, val, 0);- if (zip->opt_sconv != NULL)- ret = ARCHIVE_OK;- else- ret = ARCHIVE_FATAL;- }- return (ret);- } else if (strcmp(key, "zip64") == 0) {- /*- * Bias decisions about Zip64: force them to be- * generated in certain cases where they are not- * forbidden or avoid them in certain cases where they- * are not strictly required.- */- if (val != NULL && *val != '\0') {- zip->flags |= ZIP_FLAG_FORCE_ZIP64;- zip->flags &= ~ZIP_FLAG_AVOID_ZIP64;- } else {- zip->flags &= ~ZIP_FLAG_FORCE_ZIP64;- zip->flags |= ZIP_FLAG_AVOID_ZIP64;- }- return (ARCHIVE_OK);- }-- /* Note: The "warn" return is just to inform the options- * supervisor that we didn't handle it. It will generate- * a suitable error if no one used this option. */- return (ARCHIVE_WARN);-}--int-archive_write_zip_set_compression_deflate(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- int ret = ARCHIVE_FAILED;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_write_zip_set_compression_deflate");- if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can only use archive_write_zip_set_compression_deflate"- " with zip format");- ret = ARCHIVE_FATAL;- } else {-#ifdef HAVE_ZLIB_H- struct zip *zip = a->format_data;- zip->requested_compression = COMPRESSION_DEFLATE;- ret = ARCHIVE_OK;-#else- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "deflate compression not supported");- ret = ARCHIVE_FAILED;-#endif- }- return (ret);-}--int-archive_write_zip_set_compression_store(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct zip *zip = a->format_data;- int ret = ARCHIVE_FAILED;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,- "archive_write_zip_set_compression_deflate");- if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can only use archive_write_zip_set_compression_store"- " with zip format");- ret = ARCHIVE_FATAL;- } else {- zip->requested_compression = COMPRESSION_STORE;- ret = ARCHIVE_OK;- }- return (ret);-}--int-archive_write_set_format_zip(struct archive *_a)-{- struct archive_write *a = (struct archive_write *)_a;- struct zip *zip;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,- ARCHIVE_STATE_NEW, "archive_write_set_format_zip");-- /* If another format was already registered, unregister it. */- if (a->format_free != NULL)- (a->format_free)(a);-- zip = (struct zip *) calloc(1, sizeof(*zip));- if (zip == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate zip data");- return (ARCHIVE_FATAL);- }-- /* "Unspecified" lets us choose the appropriate compression. */- zip->requested_compression = COMPRESSION_UNSPECIFIED;-#ifdef HAVE_ZLIB_H- zip->deflate_compression_level = Z_DEFAULT_COMPRESSION;-#endif- zip->crc32func = real_crc32;-- /* A buffer used for both compression and encryption. */- zip->len_buf = 65536;- zip->buf = malloc(zip->len_buf);- if (zip->buf == NULL) {- free(zip);- archive_set_error(&a->archive, ENOMEM,- "Can't allocate compression buffer");- return (ARCHIVE_FATAL);- }-- a->format_data = zip;- a->format_name = "zip";- a->format_options = archive_write_zip_options;- a->format_write_header = archive_write_zip_header;- a->format_write_data = archive_write_zip_data;- a->format_finish_entry = archive_write_zip_finish_entry;- a->format_close = archive_write_zip_close;- a->format_free = archive_write_zip_free;- a->archive.archive_format = ARCHIVE_FORMAT_ZIP;- a->archive.archive_format_name = "ZIP";-- return (ARCHIVE_OK);-}--static int-is_all_ascii(const char *p)-{- const unsigned char *pp = (const unsigned char *)p;-- while (*pp) {- if (*pp++ > 127)- return (0);- }- return (1);-}--static int-archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)-{- unsigned char local_header[32];- unsigned char local_extra[144];- struct zip *zip = a->format_data;- unsigned char *e;- unsigned char *cd_extra;- size_t filename_length;- const char *slink = NULL;- size_t slink_size = 0;- struct archive_string_conv *sconv = get_sconv(a, zip);- int ret, ret2 = ARCHIVE_OK;- mode_t type;- int version_needed = 10;-- /* Ignore types of entries that we don't support. */- type = archive_entry_filetype(entry);- if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) {- __archive_write_entry_filetype_unsupported(- &a->archive, entry, "zip");- return ARCHIVE_FAILED;- };-- /* If we're not using Zip64, reject large files. */- if (zip->flags & ZIP_FLAG_AVOID_ZIP64) {- /* Reject entries over 4GB. */- if (archive_entry_size_is_set(entry)- && (archive_entry_size(entry) > ZIP_4GB_MAX)) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Files > 4GB require Zip64 extensions");- return ARCHIVE_FAILED;- }- /* Reject entries if archive is > 4GB. */- if (zip->written_bytes > ZIP_4GB_MAX) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Archives > 4GB require Zip64 extensions");- return ARCHIVE_FAILED;- }- }-- /* Only regular files can have size > 0. */- if (type != AE_IFREG)- archive_entry_set_size(entry, 0);--- /* Reset information from last entry. */- zip->entry_offset = zip->written_bytes;- zip->entry_uncompressed_limit = INT64_MAX;- zip->entry_compressed_size = 0;- zip->entry_uncompressed_size = 0;- zip->entry_compressed_written = 0;- zip->entry_uncompressed_written = 0;- zip->entry_flags = 0;- zip->entry_uses_zip64 = 0;- zip->entry_crc32 = zip->crc32func(0, NULL, 0);- zip->entry_encryption = 0;- archive_entry_free(zip->entry);- zip->entry = NULL;-- if (zip->cctx_valid)- archive_encrypto_aes_ctr_release(&zip->cctx);- if (zip->hctx_valid)- archive_hmac_sha1_cleanup(&zip->hctx);- zip->tctx_valid = zip->cctx_valid = zip->hctx_valid = 0;-- if (type == AE_IFREG- &&(!archive_entry_size_is_set(entry)- || archive_entry_size(entry) > 0)) {- switch (zip->encryption_type) {- case ENCRYPTION_TRADITIONAL:- case ENCRYPTION_WINZIP_AES128:- case ENCRYPTION_WINZIP_AES256:- zip->entry_flags |= ZIP_ENTRY_FLAG_ENCRYPTED;- zip->entry_encryption = zip->encryption_type;- break;- case ENCRYPTION_NONE:- default:- break;- }- }---#if defined(_WIN32) && !defined(__CYGWIN__)- /* Make sure the path separators in pathname, hardlink and symlink- * are all slash '/', not the Windows path separator '\'. */- zip->entry = __la_win_entry_in_posix_pathseparator(entry);- if (zip->entry == entry)- zip->entry = archive_entry_clone(entry);-#else- zip->entry = archive_entry_clone(entry);-#endif- if (zip->entry == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate zip header data");- return (ARCHIVE_FATAL);- }-- if (sconv != NULL) {- const char *p;- size_t len;-- if (archive_entry_pathname_l(entry, &p, &len, sconv) != 0) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory for Pathname");- return (ARCHIVE_FATAL);- }- archive_set_error(&a->archive,- ARCHIVE_ERRNO_FILE_FORMAT,- "Can't translate Pathname '%s' to %s",- archive_entry_pathname(entry),- archive_string_conversion_charset_name(sconv));- ret2 = ARCHIVE_WARN;- }- if (len > 0)- archive_entry_set_pathname(zip->entry, p);-- /*- * There is no standard for symlink handling; we convert- * it using the same character-set translation that we use- * for filename.- */- if (type == AE_IFLNK) {- if (archive_entry_symlink_l(entry, &p, &len, sconv)) {- if (errno == ENOMEM) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate memory "- " for Symlink");- return (ARCHIVE_FATAL);- }- /* No error if we can't convert. */- } else if (len > 0)- archive_entry_set_symlink(zip->entry, p);- }- }-- /* If filename isn't ASCII and we can use UTF-8, set the UTF-8 flag. */- if (!is_all_ascii(archive_entry_pathname(zip->entry))) {- if (zip->opt_sconv != NULL) {- if (strcmp(archive_string_conversion_charset_name(- zip->opt_sconv), "UTF-8") == 0)- zip->entry_flags |= ZIP_ENTRY_FLAG_UTF8_NAME;-#if HAVE_NL_LANGINFO- } else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {- zip->entry_flags |= ZIP_ENTRY_FLAG_UTF8_NAME;-#endif- }- }- filename_length = path_length(zip->entry);-- /* Determine appropriate compression and size for this entry. */- if (type == AE_IFLNK) {- slink = archive_entry_symlink(zip->entry);- if (slink != NULL)- slink_size = strlen(slink);- else- slink_size = 0;- zip->entry_uncompressed_limit = slink_size;- zip->entry_compressed_size = slink_size;- zip->entry_uncompressed_size = slink_size;- zip->entry_crc32 = zip->crc32func(zip->entry_crc32,- (const unsigned char *)slink, slink_size);- zip->entry_compression = COMPRESSION_STORE;- version_needed = 20;- } else if (type != AE_IFREG) {- zip->entry_compression = COMPRESSION_STORE;- zip->entry_uncompressed_limit = 0;- version_needed = 20;- } else if (archive_entry_size_is_set(zip->entry)) {- int64_t size = archive_entry_size(zip->entry);- int64_t additional_size = 0;-- zip->entry_uncompressed_limit = size;- zip->entry_compression = zip->requested_compression;- if (zip->entry_compression == COMPRESSION_UNSPECIFIED) {- zip->entry_compression = COMPRESSION_DEFAULT;- }- if (zip->entry_compression == COMPRESSION_STORE) {- zip->entry_compressed_size = size;- zip->entry_uncompressed_size = size;- version_needed = 10;- } else {- zip->entry_uncompressed_size = size;- version_needed = 20;- }-- if (zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED) {- switch (zip->entry_encryption) {- case ENCRYPTION_TRADITIONAL:- additional_size = TRAD_HEADER_SIZE;- version_needed = 20;- break;- case ENCRYPTION_WINZIP_AES128:- additional_size = WINZIP_AES128_HEADER_SIZE- + AUTH_CODE_SIZE;- version_needed = 20;- break;- case ENCRYPTION_WINZIP_AES256:- additional_size = WINZIP_AES256_HEADER_SIZE- + AUTH_CODE_SIZE;- version_needed = 20;- break;- case ENCRYPTION_NONE:- default:- break;- }- if (zip->entry_compression == COMPRESSION_STORE)- zip->entry_compressed_size += additional_size;- }-- /*- * Set Zip64 extension in any of the following cases- * (this was suggested by discussion on info-zip-dev- * mailing list):- * = Zip64 is being forced by user- * = File is over 4GiB uncompressed- * (including encryption header, if any)- * = File is close to 4GiB and is being compressed- * (compression might make file larger)- */- if ((zip->flags & ZIP_FLAG_FORCE_ZIP64)- || (zip->entry_uncompressed_size + additional_size > ZIP_4GB_MAX)- || (zip->entry_uncompressed_size > ZIP_4GB_MAX_UNCOMPRESSED- && zip->entry_compression != COMPRESSION_STORE)) {- zip->entry_uses_zip64 = 1;- version_needed = 45;- }-- /* We may know the size, but never the CRC. */- zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END;- } else {- /* We don't know the size. Use the default- * compression unless specified otherwise.- * We enable Zip64 extensions unless we're told not to.- */-- zip->entry_compression = zip->requested_compression;- if(zip->entry_compression == COMPRESSION_UNSPECIFIED){- zip->entry_compression = COMPRESSION_DEFAULT;- }-- zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END;- if ((zip->flags & ZIP_FLAG_AVOID_ZIP64) == 0) {- zip->entry_uses_zip64 = 1;- version_needed = 45;- } else if (zip->entry_compression == COMPRESSION_STORE) {- version_needed = 10;- } else {- version_needed = 20;- }-- if (zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED) {- switch (zip->entry_encryption) {- case ENCRYPTION_TRADITIONAL:- case ENCRYPTION_WINZIP_AES128:- case ENCRYPTION_WINZIP_AES256:- if (version_needed < 20)- version_needed = 20;- break;- case ENCRYPTION_NONE:- default:- break;- }- }- }-- /* Format the local header. */- memset(local_header, 0, sizeof(local_header));- memcpy(local_header, "PK\003\004", 4);- archive_le16enc(local_header + 4, version_needed);- archive_le16enc(local_header + 6, zip->entry_flags);- if (zip->entry_encryption == ENCRYPTION_WINZIP_AES128- || zip->entry_encryption == ENCRYPTION_WINZIP_AES256)- archive_le16enc(local_header + 8, WINZIP_AES_ENCRYPTION);- else- archive_le16enc(local_header + 8, zip->entry_compression);- archive_le32enc(local_header + 10,- dos_time(archive_entry_mtime(zip->entry)));- archive_le32enc(local_header + 14, zip->entry_crc32);- if (zip->entry_uses_zip64) {- /* Zip64 data in the local header "must" include both- * compressed and uncompressed sizes AND those fields- * are included only if these are 0xffffffff;- * THEREFORE these must be set this way, even if we- * know one of them is smaller. */- archive_le32enc(local_header + 18, ZIP_4GB_MAX);- archive_le32enc(local_header + 22, ZIP_4GB_MAX);- } else {- archive_le32enc(local_header + 18, (uint32_t)zip->entry_compressed_size);- archive_le32enc(local_header + 22, (uint32_t)zip->entry_uncompressed_size);- }- archive_le16enc(local_header + 26, (uint16_t)filename_length);-- if (zip->entry_encryption == ENCRYPTION_TRADITIONAL) {- if (zip->entry_flags & ZIP_ENTRY_FLAG_LENGTH_AT_END)- zip->trad_chkdat = local_header[11];- else- zip->trad_chkdat = local_header[17];- }-- /* Format as much of central directory file header as we can: */- zip->file_header = cd_alloc(zip, 46);- /* If (zip->file_header == NULL) XXXX */- ++zip->central_directory_entries;- memset(zip->file_header, 0, 46);- memcpy(zip->file_header, "PK\001\002", 4);- /* "Made by PKZip 2.0 on Unix." */- archive_le16enc(zip->file_header + 4, 3 * 256 + version_needed);- archive_le16enc(zip->file_header + 6, version_needed);- archive_le16enc(zip->file_header + 8, zip->entry_flags);- if (zip->entry_encryption == ENCRYPTION_WINZIP_AES128- || zip->entry_encryption == ENCRYPTION_WINZIP_AES256)- archive_le16enc(zip->file_header + 10, WINZIP_AES_ENCRYPTION);- else- archive_le16enc(zip->file_header + 10, zip->entry_compression);- archive_le32enc(zip->file_header + 12,- dos_time(archive_entry_mtime(zip->entry)));- archive_le16enc(zip->file_header + 28, (uint16_t)filename_length);- /* Following Info-Zip, store mode in the "external attributes" field. */- archive_le32enc(zip->file_header + 38,- ((uint32_t)archive_entry_mode(zip->entry)) << 16);- e = cd_alloc(zip, filename_length);- /* If (e == NULL) XXXX */- copy_path(zip->entry, e);-- /* Format extra data. */- memset(local_extra, 0, sizeof(local_extra));- e = local_extra;-- /* First, extra blocks that are the same between- * the local file header and the central directory.- * We format them once and then duplicate them. */-- /* UT timestamp, length depends on what timestamps are set. */- memcpy(e, "UT", 2);- archive_le16enc(e + 2,- 1- + (archive_entry_mtime_is_set(entry) ? 4 : 0)- + (archive_entry_atime_is_set(entry) ? 4 : 0)- + (archive_entry_ctime_is_set(entry) ? 4 : 0));- e += 4;- *e++ =- (archive_entry_mtime_is_set(entry) ? 1 : 0)- | (archive_entry_atime_is_set(entry) ? 2 : 0)- | (archive_entry_ctime_is_set(entry) ? 4 : 0);- if (archive_entry_mtime_is_set(entry)) {- archive_le32enc(e, (uint32_t)archive_entry_mtime(entry));- e += 4;- }- if (archive_entry_atime_is_set(entry)) {- archive_le32enc(e, (uint32_t)archive_entry_atime(entry));- e += 4;- }- if (archive_entry_ctime_is_set(entry)) {- archive_le32enc(e, (uint32_t)archive_entry_ctime(entry));- e += 4;- }-- /* ux Unix extra data, length 11, version 1 */- /* TODO: If uid < 64k, use 2 bytes, ditto for gid. */- memcpy(e, "ux\013\000\001", 5);- e += 5;- *e++ = 4; /* Length of following UID */- archive_le32enc(e, (uint32_t)archive_entry_uid(entry));- e += 4;- *e++ = 4; /* Length of following GID */- archive_le32enc(e, (uint32_t)archive_entry_gid(entry));- e += 4;-- /* AES extra data field: WinZIP AES information, ID=0x9901 */- if ((zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED)- && (zip->entry_encryption == ENCRYPTION_WINZIP_AES128- || zip->entry_encryption == ENCRYPTION_WINZIP_AES256)) {-- memcpy(e, "\001\231\007\000\001\000AE", 8);- /* AES vendor version AE-2 does not store a CRC.- * WinZip 11 uses AE-1, which does store the CRC,- * but it does not store the CRC when the file size- * is less than 20 bytes. So we simulate what- * WinZip 11 does.- * NOTE: WinZip 9.0 and 10.0 uses AE-2 by default. */- if (archive_entry_size_is_set(zip->entry)- && archive_entry_size(zip->entry) < 20) {- archive_le16enc(e+4, AES_VENDOR_AE_2);- zip->aes_vendor = AES_VENDOR_AE_2;/* no CRC. */- } else- zip->aes_vendor = AES_VENDOR_AE_1;- e += 8;- /* AES encryption strength. */- *e++ = (zip->entry_encryption == ENCRYPTION_WINZIP_AES128)?1:3;- /* Actual compression method. */- archive_le16enc(e, zip->entry_compression);- e += 2;- }-- /* Copy UT ,ux, and AES-extra into central directory as well. */- zip->file_header_extra_offset = zip->central_directory_bytes;- cd_extra = cd_alloc(zip, e - local_extra);- memcpy(cd_extra, local_extra, e - local_extra);-- /*- * Following extra blocks vary between local header and- * central directory. These are the local header versions.- * Central directory versions get formatted in- * archive_write_zip_finish_entry() below.- */-- /* "[Zip64 entry] in the local header MUST include BOTH- * original [uncompressed] and compressed size fields." */- if (zip->entry_uses_zip64) {- unsigned char *zip64_start = e;- memcpy(e, "\001\000\020\000", 4);- e += 4;- archive_le64enc(e, zip->entry_uncompressed_size);- e += 8;- archive_le64enc(e, zip->entry_compressed_size);- e += 8;- archive_le16enc(zip64_start + 2, (uint16_t)(e - (zip64_start + 4)));- }-- if (zip->flags & ZIP_FLAG_EXPERIMENT_xl) {- /* Experimental 'xl' extension to improve streaming. */- unsigned char *external_info = e;- int included = 7;- memcpy(e, "xl\000\000", 4); // 0x6c65 + 2-byte length- e += 4;- e[0] = included; /* bitmap of included fields */- e += 1;- if (included & 1) {- archive_le16enc(e, /* "Version created by" */- 3 * 256 + version_needed);- e += 2;- }- if (included & 2) {- archive_le16enc(e, 0); /* internal file attributes */- e += 2;- }- if (included & 4) {- archive_le32enc(e, /* external file attributes */- ((uint32_t)archive_entry_mode(zip->entry)) << 16);- e += 4;- }- if (included & 8) {- // Libarchive does not currently support file comments.- }- archive_le16enc(external_info + 2, (uint16_t)(e - (external_info + 4)));- }-- /* Update local header with size of extra data and write it all out: */- archive_le16enc(local_header + 28, (uint16_t)(e - local_extra));-- ret = __archive_write_output(a, local_header, 30);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- zip->written_bytes += 30;-- ret = write_path(zip->entry, a);- if (ret <= ARCHIVE_OK)- return (ARCHIVE_FATAL);- zip->written_bytes += ret;-- ret = __archive_write_output(a, local_extra, e - local_extra);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- zip->written_bytes += e - local_extra;-- /* For symlinks, write the body now. */- if (slink != NULL) {- ret = __archive_write_output(a, slink, slink_size);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- zip->entry_compressed_written += slink_size;- zip->entry_uncompressed_written += slink_size;- zip->written_bytes += slink_size;- }--#ifdef HAVE_ZLIB_H- if (zip->entry_compression == COMPRESSION_DEFLATE) {- zip->stream.zalloc = Z_NULL;- zip->stream.zfree = Z_NULL;- zip->stream.opaque = Z_NULL;- zip->stream.next_out = zip->buf;- zip->stream.avail_out = (uInt)zip->len_buf;- if (deflateInit2(&zip->stream, zip->deflate_compression_level,- Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {- archive_set_error(&a->archive, ENOMEM,- "Can't init deflate compressor");- return (ARCHIVE_FATAL);- }- }-#endif-- return (ret2);-}--static ssize_t-archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)-{- int ret;- struct zip *zip = a->format_data;-- if ((int64_t)s > zip->entry_uncompressed_limit)- s = (size_t)zip->entry_uncompressed_limit;- zip->entry_uncompressed_written += s;-- if (s == 0) return 0;-- if (zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED) {- switch (zip->entry_encryption) {- case ENCRYPTION_TRADITIONAL:- /* Initialize traditional PKWARE encryption context. */- if (!zip->tctx_valid) {- ret = init_traditional_pkware_encryption(a);- if (ret != ARCHIVE_OK)- return (ret);- zip->tctx_valid = 1;- }- break;- case ENCRYPTION_WINZIP_AES128:- case ENCRYPTION_WINZIP_AES256:- if (!zip->cctx_valid) {- ret = init_winzip_aes_encryption(a);- if (ret != ARCHIVE_OK)- return (ret);- zip->cctx_valid = zip->hctx_valid = 1;- }- break;- case ENCRYPTION_NONE:- default:- break;- }- }-- switch (zip->entry_compression) {- case COMPRESSION_STORE:- if (zip->tctx_valid || zip->cctx_valid) {- const uint8_t *rb = (const uint8_t *)buff;- const uint8_t * const re = rb + s;-- while (rb < re) {- size_t l;-- if (zip->tctx_valid) {- l = trad_enc_encrypt_update(&zip->tctx,- rb, re - rb,- zip->buf, zip->len_buf);- } else {- l = zip->len_buf;- ret = archive_encrypto_aes_ctr_update(- &zip->cctx,- rb, re - rb, zip->buf, &l);- if (ret < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to encrypt file");- return (ARCHIVE_FAILED);- }- archive_hmac_sha1_update(&zip->hctx,- zip->buf, l);- }- ret = __archive_write_output(a, zip->buf, l);- if (ret != ARCHIVE_OK)- return (ret);- zip->entry_compressed_written += l;- zip->written_bytes += l;- rb += l;- }- } else {- ret = __archive_write_output(a, buff, s);- if (ret != ARCHIVE_OK)- return (ret);- zip->written_bytes += s;- zip->entry_compressed_written += s;- }- break;-#if HAVE_ZLIB_H- case COMPRESSION_DEFLATE:- zip->stream.next_in = (unsigned char*)(uintptr_t)buff;- zip->stream.avail_in = (uInt)s;- do {- ret = deflate(&zip->stream, Z_NO_FLUSH);- if (ret == Z_STREAM_ERROR)- return (ARCHIVE_FATAL);- if (zip->stream.avail_out == 0) {- if (zip->tctx_valid) {- trad_enc_encrypt_update(&zip->tctx,- zip->buf, zip->len_buf,- zip->buf, zip->len_buf);- } else if (zip->cctx_valid) {- size_t outl = zip->len_buf;- ret = archive_encrypto_aes_ctr_update(- &zip->cctx,- zip->buf, zip->len_buf,- zip->buf, &outl);- if (ret < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to encrypt file");- return (ARCHIVE_FAILED);- }- archive_hmac_sha1_update(&zip->hctx,- zip->buf, zip->len_buf);- }- ret = __archive_write_output(a, zip->buf,- zip->len_buf);- if (ret != ARCHIVE_OK)- return (ret);- zip->entry_compressed_written += zip->len_buf;- zip->written_bytes += zip->len_buf;- zip->stream.next_out = zip->buf;- zip->stream.avail_out = (uInt)zip->len_buf;- }- } while (zip->stream.avail_in != 0);- break;-#endif-- case COMPRESSION_UNSPECIFIED:- default:- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Invalid ZIP compression type");- return ARCHIVE_FATAL;- }-- zip->entry_uncompressed_limit -= s;- if (!zip->cctx_valid || zip->aes_vendor != AES_VENDOR_AE_2)- zip->entry_crc32 =- zip->crc32func(zip->entry_crc32, buff, (unsigned)s);- return (s);--}--static int-archive_write_zip_finish_entry(struct archive_write *a)-{- struct zip *zip = a->format_data;- int ret;--#if HAVE_ZLIB_H- if (zip->entry_compression == COMPRESSION_DEFLATE) {- for (;;) {- size_t remainder;-- ret = deflate(&zip->stream, Z_FINISH);- if (ret == Z_STREAM_ERROR)- return (ARCHIVE_FATAL);- remainder = zip->len_buf - zip->stream.avail_out;- if (zip->tctx_valid) {- trad_enc_encrypt_update(&zip->tctx,- zip->buf, remainder, zip->buf, remainder);- } else if (zip->cctx_valid) {- size_t outl = remainder;- ret = archive_encrypto_aes_ctr_update(- &zip->cctx, zip->buf, remainder,- zip->buf, &outl);- if (ret < 0) {- archive_set_error(&a->archive,- ARCHIVE_ERRNO_MISC,- "Failed to encrypt file");- return (ARCHIVE_FAILED);- }- archive_hmac_sha1_update(&zip->hctx,- zip->buf, remainder);- }- ret = __archive_write_output(a, zip->buf, remainder);- if (ret != ARCHIVE_OK)- return (ret);- zip->entry_compressed_written += remainder;- zip->written_bytes += remainder;- zip->stream.next_out = zip->buf;- if (zip->stream.avail_out != 0)- break;- zip->stream.avail_out = (uInt)zip->len_buf;- }- deflateEnd(&zip->stream);- }-#endif- if (zip->hctx_valid) {- uint8_t hmac[20];- size_t hmac_len = 20;-- archive_hmac_sha1_final(&zip->hctx, hmac, &hmac_len);- ret = __archive_write_output(a, hmac, AUTH_CODE_SIZE);- if (ret != ARCHIVE_OK)- return (ret);- zip->entry_compressed_written += AUTH_CODE_SIZE;- zip->written_bytes += AUTH_CODE_SIZE;- }-- /* Write trailing data descriptor. */- if ((zip->entry_flags & ZIP_ENTRY_FLAG_LENGTH_AT_END) != 0) {- char d[24];- memcpy(d, "PK\007\010", 4);- if (zip->cctx_valid && zip->aes_vendor == AES_VENDOR_AE_2)- archive_le32enc(d + 4, 0);/* no CRC.*/- else- archive_le32enc(d + 4, zip->entry_crc32);- if (zip->entry_uses_zip64) {- archive_le64enc(d + 8,- (uint64_t)zip->entry_compressed_written);- archive_le64enc(d + 16,- (uint64_t)zip->entry_uncompressed_written);- ret = __archive_write_output(a, d, 24);- zip->written_bytes += 24;- } else {- archive_le32enc(d + 8,- (uint32_t)zip->entry_compressed_written);- archive_le32enc(d + 12,- (uint32_t)zip->entry_uncompressed_written);- ret = __archive_write_output(a, d, 16);- zip->written_bytes += 16;- }- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- }-- /* Append Zip64 extra data to central directory information. */- if (zip->entry_compressed_written > ZIP_4GB_MAX- || zip->entry_uncompressed_written > ZIP_4GB_MAX- || zip->entry_offset > ZIP_4GB_MAX) {- unsigned char zip64[32];- unsigned char *z = zip64, *zd;- memcpy(z, "\001\000\000\000", 4);- z += 4;- if (zip->entry_uncompressed_written >= ZIP_4GB_MAX) {- archive_le64enc(z, zip->entry_uncompressed_written);- z += 8;- }- if (zip->entry_compressed_written >= ZIP_4GB_MAX) {- archive_le64enc(z, zip->entry_compressed_written);- z += 8;- }- if (zip->entry_offset >= ZIP_4GB_MAX) {- archive_le64enc(z, zip->entry_offset);- z += 8;- }- archive_le16enc(zip64 + 2, (uint16_t)(z - (zip64 + 4)));- zd = cd_alloc(zip, z - zip64);- if (zd == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate zip data");- return (ARCHIVE_FATAL);- }- memcpy(zd, zip64, z - zip64);- /* Zip64 means version needs to be set to at least 4.5 */- if (archive_le16dec(zip->file_header + 6) < 45)- archive_le16enc(zip->file_header + 6, 45);- }-- /* Fix up central directory file header. */- if (zip->cctx_valid && zip->aes_vendor == AES_VENDOR_AE_2)- archive_le32enc(zip->file_header + 16, 0);/* no CRC.*/- else- archive_le32enc(zip->file_header + 16, zip->entry_crc32);- archive_le32enc(zip->file_header + 20,- (uint32_t)zipmin(zip->entry_compressed_written,- ZIP_4GB_MAX));- archive_le32enc(zip->file_header + 24,- (uint32_t)zipmin(zip->entry_uncompressed_written,- ZIP_4GB_MAX));- archive_le16enc(zip->file_header + 30,- (uint16_t)(zip->central_directory_bytes - zip->file_header_extra_offset));- archive_le32enc(zip->file_header + 42,- (uint32_t)zipmin(zip->entry_offset,- ZIP_4GB_MAX));-- return (ARCHIVE_OK);-}--static int-archive_write_zip_close(struct archive_write *a)-{- uint8_t buff[64];- int64_t offset_start, offset_end;- struct zip *zip = a->format_data;- struct cd_segment *segment;- int ret;-- offset_start = zip->written_bytes;- segment = zip->central_directory;- while (segment != NULL) {- ret = __archive_write_output(a,- segment->buff, segment->p - segment->buff);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- zip->written_bytes += segment->p - segment->buff;- segment = segment->next;- }- offset_end = zip->written_bytes;-- /* If central dir info is too large, write Zip64 end-of-cd */- if (offset_end - offset_start > ZIP_4GB_MAX- || offset_start > ZIP_4GB_MAX- || zip->central_directory_entries > 0xffffUL- || (zip->flags & ZIP_FLAG_FORCE_ZIP64)) {- /* Zip64 end-of-cd record */- memset(buff, 0, 56);- memcpy(buff, "PK\006\006", 4);- archive_le64enc(buff + 4, 44);- archive_le16enc(buff + 12, 45);- archive_le16enc(buff + 14, 45);- /* This is disk 0 of 0. */- archive_le64enc(buff + 24, zip->central_directory_entries);- archive_le64enc(buff + 32, zip->central_directory_entries);- archive_le64enc(buff + 40, offset_end - offset_start);- archive_le64enc(buff + 48, offset_start);- ret = __archive_write_output(a, buff, 56);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- zip->written_bytes += 56;-- /* Zip64 end-of-cd locator record. */- memset(buff, 0, 20);- memcpy(buff, "PK\006\007", 4);- archive_le32enc(buff + 4, 0);- archive_le64enc(buff + 8, offset_end);- archive_le32enc(buff + 16, 1);- ret = __archive_write_output(a, buff, 20);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- zip->written_bytes += 20;-- }-- /* Format and write end of central directory. */- memset(buff, 0, sizeof(buff));- memcpy(buff, "PK\005\006", 4);- archive_le16enc(buff + 8, (uint16_t)zipmin(0xffffU,- zip->central_directory_entries));- archive_le16enc(buff + 10, (uint16_t)zipmin(0xffffU,- zip->central_directory_entries));- archive_le32enc(buff + 12,- (uint32_t)zipmin(ZIP_4GB_MAX, (offset_end - offset_start)));- archive_le32enc(buff + 16,- (uint32_t)zipmin(ZIP_4GB_MAX, offset_start));- ret = __archive_write_output(a, buff, 22);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- zip->written_bytes += 22;- return (ARCHIVE_OK);-}--static int-archive_write_zip_free(struct archive_write *a)-{- struct zip *zip;- struct cd_segment *segment;-- zip = a->format_data;- while (zip->central_directory != NULL) {- segment = zip->central_directory;- zip->central_directory = segment->next;- free(segment->buff);- free(segment);- }- free(zip->buf);- archive_entry_free(zip->entry);- if (zip->cctx_valid)- archive_encrypto_aes_ctr_release(&zip->cctx);- if (zip->hctx_valid)- archive_hmac_sha1_cleanup(&zip->hctx);- /* TODO: Free opt_sconv, sconv_default */-- free(zip);- a->format_data = NULL;- return (ARCHIVE_OK);-}--/* Convert into MSDOS-style date/time. */-static unsigned int-dos_time(const time_t unix_time)-{- struct tm *t;- unsigned int dt;-#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)- struct tm tmbuf;-#endif--#if defined(HAVE_LOCALTIME_S)- t = localtime_s(&tmbuf, &unix_time) ? NULL : &tmbuf;-#elif defined(HAVE_LOCALTIME_R)- t = localtime_r(&unix_time, &tmbuf);-#else- t = localtime(&unix_time);-#endif-- /* MSDOS-style date/time is only between 1980-01-01 and 2107-12-31 */- if (t->tm_year < 1980 - 1900)- /* Set minimum date/time '1980-01-01 00:00:00'. */- dt = 0x00210000U;- else if (t->tm_year > 2107 - 1900)- /* Set maximum date/time '2107-12-31 23:59:58'. */- dt = 0xff9fbf7dU;- else {- dt = 0;- dt += ((t->tm_year - 80) & 0x7f) << 9;- dt += ((t->tm_mon + 1) & 0x0f) << 5;- dt += (t->tm_mday & 0x1f);- dt <<= 16;- dt += (t->tm_hour & 0x1f) << 11;- dt += (t->tm_min & 0x3f) << 5;- dt += (t->tm_sec & 0x3e) >> 1; /* Only counting every 2 seconds. */- }- return dt;-}--static size_t-path_length(struct archive_entry *entry)-{- mode_t type;- const char *path;- size_t len;-- type = archive_entry_filetype(entry);- path = archive_entry_pathname(entry);-- if (path == NULL)- return (0);- len = strlen(path);- if (type == AE_IFDIR && (path[0] == '\0' || path[len - 1] != '/'))- ++len; /* Space for the trailing / */- return len;-}--static int-write_path(struct archive_entry *entry, struct archive_write *archive)-{- int ret;- const char *path;- mode_t type;- size_t written_bytes;-- path = archive_entry_pathname(entry);- type = archive_entry_filetype(entry);- written_bytes = 0;-- if (path == NULL)- return (ARCHIVE_FATAL);-- ret = __archive_write_output(archive, path, strlen(path));- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- written_bytes += strlen(path);-- /* Folders are recognized by a trailing slash. */- if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {- ret = __archive_write_output(archive, "/", 1);- if (ret != ARCHIVE_OK)- return (ARCHIVE_FATAL);- written_bytes += 1;- }-- return ((int)written_bytes);-}--static void-copy_path(struct archive_entry *entry, unsigned char *p)-{- const char *path;- size_t pathlen;- mode_t type;-- path = archive_entry_pathname(entry);- pathlen = strlen(path);- type = archive_entry_filetype(entry);-- memcpy(p, path, pathlen);-- /* Folders are recognized by a trailing slash. */- if ((type == AE_IFDIR) && (path[pathlen - 1] != '/'))- p[pathlen] = '/';-}---static struct archive_string_conv *-get_sconv(struct archive_write *a, struct zip *zip)-{- if (zip->opt_sconv != NULL)- return (zip->opt_sconv);-- if (!zip->init_default_conversion) {- zip->sconv_default =- archive_string_default_conversion_for_write(&(a->archive));- zip->init_default_conversion = 1;- }- return (zip->sconv_default);-}--/*- Traditional PKWARE Decryption functions.- */--static void-trad_enc_update_keys(struct trad_enc_ctx *ctx, uint8_t c)-{- uint8_t t;-#define CRC32(c, b) (crc32(c ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL)-- ctx->keys[0] = CRC32(ctx->keys[0], c);- ctx->keys[1] = (ctx->keys[1] + (ctx->keys[0] & 0xff)) * 134775813L + 1;- t = (ctx->keys[1] >> 24) & 0xff;- ctx->keys[2] = CRC32(ctx->keys[2], t);-#undef CRC32-}--static uint8_t-trad_enc_decrypt_byte(struct trad_enc_ctx *ctx)-{- unsigned temp = ctx->keys[2] | 2;- return (uint8_t)((temp * (temp ^ 1)) >> 8) & 0xff;-}--static unsigned-trad_enc_encrypt_update(struct trad_enc_ctx *ctx, const uint8_t *in,- size_t in_len, uint8_t *out, size_t out_len)-{- unsigned i, max;-- max = (unsigned)((in_len < out_len)? in_len: out_len);-- for (i = 0; i < max; i++) {- uint8_t t = in[i];- out[i] = t ^ trad_enc_decrypt_byte(ctx);- trad_enc_update_keys(ctx, t);- }- return i;-}--static int-trad_enc_init(struct trad_enc_ctx *ctx, const char *pw, size_t pw_len)-{-- ctx->keys[0] = 305419896L;- ctx->keys[1] = 591751049L;- ctx->keys[2] = 878082192L;-- for (;pw_len; --pw_len)- trad_enc_update_keys(ctx, *pw++);- return 0;-}--static int-is_traditional_pkware_encryption_supported(void)-{- uint8_t key[TRAD_HEADER_SIZE];-- if (archive_random(key, sizeof(key)-1) != ARCHIVE_OK)- return (0);- return (1);-}--static int-init_traditional_pkware_encryption(struct archive_write *a)-{- struct zip *zip = a->format_data;- const char *passphrase;- uint8_t key[TRAD_HEADER_SIZE];- uint8_t key_encrypted[TRAD_HEADER_SIZE];- int ret;-- passphrase = __archive_write_get_passphrase(a);- if (passphrase == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Encryption needs passphrase");- return ARCHIVE_FAILED;- }- if (archive_random(key, sizeof(key)-1) != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't generate random number for encryption");- return ARCHIVE_FATAL;- }- trad_enc_init(&zip->tctx, passphrase, strlen(passphrase));- /* Set the last key code which will be used as a check code- * for verifying passphrase in decryption. */- key[TRAD_HEADER_SIZE-1] = zip->trad_chkdat;- trad_enc_encrypt_update(&zip->tctx, key, TRAD_HEADER_SIZE,- key_encrypted, TRAD_HEADER_SIZE);- /* Write encrypted keys in the top of the file content. */- ret = __archive_write_output(a, key_encrypted, TRAD_HEADER_SIZE);- if (ret != ARCHIVE_OK)- return (ret);- zip->written_bytes += TRAD_HEADER_SIZE;- zip->entry_compressed_written += TRAD_HEADER_SIZE;- return (ret);-}--static int-init_winzip_aes_encryption(struct archive_write *a)-{- struct zip *zip = a->format_data;- const char *passphrase;- size_t key_len, salt_len;- uint8_t salt[16 + 2];- uint8_t derived_key[MAX_DERIVED_KEY_BUF_SIZE];- int ret;-- passphrase = __archive_write_get_passphrase(a);- if (passphrase == NULL) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Encryption needs passphrase");- return (ARCHIVE_FAILED);- }- if (zip->entry_encryption == ENCRYPTION_WINZIP_AES128) {- salt_len = 8;- key_len = 16;- } else {- /* AES 256 */- salt_len = 16;- key_len = 32;- }- if (archive_random(salt, salt_len) != ARCHIVE_OK) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Can't generate random number for encryption");- return (ARCHIVE_FATAL);- }- archive_pbkdf2_sha1(passphrase, strlen(passphrase),- salt, salt_len, 1000, derived_key, key_len * 2 + 2);-- ret = archive_encrypto_aes_ctr_init(&zip->cctx, derived_key, key_len);- if (ret != 0) {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Decryption is unsupported due to lack of crypto library");- return (ARCHIVE_FAILED);- }- ret = archive_hmac_sha1_init(&zip->hctx, derived_key + key_len,- key_len);- if (ret != 0) {- archive_encrypto_aes_ctr_release(&zip->cctx);- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Failed to initialize HMAC-SHA1");- return (ARCHIVE_FAILED);- }-- /* Set a password verification value after the 'salt'. */- salt[salt_len] = derived_key[key_len * 2];- salt[salt_len + 1] = derived_key[key_len * 2 + 1];-- /* Write encrypted keys in the top of the file content. */- ret = __archive_write_output(a, salt, salt_len + 2);- if (ret != ARCHIVE_OK)- return (ret);- zip->written_bytes += salt_len + 2;- zip->entry_compressed_written += salt_len + 2;-- return (ARCHIVE_OK);-}--static int-is_winzip_aes_encryption_supported(int encryption)-{- size_t key_len, salt_len;- uint8_t salt[16 + 2];- uint8_t derived_key[MAX_DERIVED_KEY_BUF_SIZE];- archive_crypto_ctx cctx;- archive_hmac_sha1_ctx hctx;- int ret;-- if (encryption == ENCRYPTION_WINZIP_AES128) {- salt_len = 8;- key_len = 16;- } else {- /* AES 256 */- salt_len = 16;- key_len = 32;- }- if (archive_random(salt, salt_len) != ARCHIVE_OK)- return (0);- ret = archive_pbkdf2_sha1("p", 1, salt, salt_len, 1000,- derived_key, key_len * 2 + 2);- if (ret != 0)- return (0);-- ret = archive_encrypto_aes_ctr_init(&cctx, derived_key, key_len);- if (ret != 0)- return (0);- ret = archive_hmac_sha1_init(&hctx, derived_key + key_len,- key_len);- archive_encrypto_aes_ctr_release(&cctx);- if (ret != 0)- return (0);- archive_hmac_sha1_cleanup(&hctx);- return (1);-}
− c/archive_write_set_options.c
@@ -1,130 +0,0 @@-/*-- * 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$");--#include "archive_write_private.h"-#include "archive_options_private.h"--static int archive_set_format_option(struct archive *a,- const char *m, const char *o, const char *v);-static int archive_set_filter_option(struct archive *a,- const char *m, const char *o, const char *v);-static int archive_set_option(struct archive *a,- const char *m, const char *o, const char *v);--int-archive_write_set_format_option(struct archive *a, const char *m, const char *o,- const char *v)-{- return _archive_set_option(a, m, o, v,- ARCHIVE_WRITE_MAGIC, "archive_write_set_format_option",- archive_set_format_option);-}--int-archive_write_set_filter_option(struct archive *a, const char *m, const char *o,- const char *v)-{- return _archive_set_option(a, m, o, v,- ARCHIVE_WRITE_MAGIC, "archive_write_set_filter_option",- archive_set_filter_option);-}--int-archive_write_set_option(struct archive *a, const char *m, const char *o,- const char *v)-{- return _archive_set_option(a, m, o, v,- ARCHIVE_WRITE_MAGIC, "archive_write_set_option",- archive_set_option);-}--int-archive_write_set_options(struct archive *a, const char *options)-{- return _archive_set_options(a, options,- ARCHIVE_WRITE_MAGIC, "archive_write_set_options",- archive_set_option);-}--static int-archive_set_format_option(struct archive *_a, const char *m, const char *o,- const char *v)-{- struct archive_write *a = (struct archive_write *)_a;-- if (a->format_name == NULL)- return (m == NULL)?ARCHIVE_FAILED:ARCHIVE_WARN - 1;- /* If the format name didn't match, return a special code for- * _archive_set_option[s]. */- if (m != NULL && strcmp(m, a->format_name) != 0)- return (ARCHIVE_WARN - 1);- if (a->format_options == NULL)- return (ARCHIVE_WARN);- return a->format_options(a, o, v);-}--static int-archive_set_filter_option(struct archive *_a, const char *m, const char *o,- const char *v)-{- struct archive_write *a = (struct archive_write *)_a;- struct archive_write_filter *filter;- int r, rv = ARCHIVE_WARN;-- for (filter = a->filter_first; filter != NULL; filter = filter->next_filter) {- if (filter->options == NULL)- continue;- if (m != NULL && strcmp(filter->name, m) != 0)- continue;-- r = filter->options(filter, o, v);-- if (r == ARCHIVE_FATAL)- return (ARCHIVE_FATAL);-- if (m != NULL)- return (r);-- if (r == ARCHIVE_OK)- rv = ARCHIVE_OK;- }- /* If the filter name didn't match, return a special code for- * _archive_set_option[s]. */- if (rv == ARCHIVE_WARN && m != NULL)- rv = ARCHIVE_WARN - 1;- return (rv);-}--static int-archive_set_option(struct archive *a, const char *m, const char *o,- const char *v)-{- return _archive_set_either_option(a, m, o, v,- archive_set_format_option,- archive_set_filter_option);-}
− c/archive_write_set_passphrase.c
@@ -1,95 +0,0 @@-/*-- * Copyright (c) 2014 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"-__FBSDID("$FreeBSD$");--#ifdef HAVE_ERRNO_H-#include <errno.h>-#endif-#include "archive_write_private.h"--int-archive_write_set_passphrase(struct archive *_a, const char *p)-{- struct archive_write *a = (struct archive_write *)_a;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW,- "archive_write_set_passphrase");-- if (p == NULL || p[0] == '\0') {- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,- "Empty passphrase is unacceptable");- return (ARCHIVE_FAILED);- }- free(a->passphrase);- a->passphrase = strdup(p);- if (a->passphrase == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate data for passphrase");- return (ARCHIVE_FATAL);- }- return (ARCHIVE_OK);-}---int-archive_write_set_passphrase_callback(struct archive *_a, void *client_data,- archive_passphrase_callback *cb)-{- struct archive_write *a = (struct archive_write *)_a;-- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW,- "archive_write_set_passphrase_callback");-- a->passphrase_callback = cb;- a->passphrase_client_data = client_data;- return (ARCHIVE_OK);-}---const char *-__archive_write_get_passphrase(struct archive_write *a)-{-- if (a->passphrase != NULL)- return (a->passphrase);-- if (a->passphrase_callback != NULL) {- const char *p;- p = a->passphrase_callback(&a->archive,- a->passphrase_client_data);- if (p != NULL) {- a->passphrase = strdup(p);- if (a->passphrase == NULL) {- archive_set_error(&a->archive, ENOMEM,- "Can't allocate data for passphrase");- return (NULL);- }- return (a->passphrase);- }- }- return (NULL);-}
− c/archive_xxhash.h
@@ -1,48 +0,0 @@-/*-- * Copyright (c) 2014 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- */--#ifndef ARCHIVE_XXHASH_H_INCLUDED-#define ARCHIVE_XXHASH_H_INCLUDED--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif---typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;--struct archive_xxhash {- unsigned int (*XXH32)(const void* input, unsigned int len,- unsigned int seed);- void* (*XXH32_init)(unsigned int seed);- XXH_errorcode (*XXH32_update)(void* state, const void* input,- unsigned int len);- unsigned int (*XXH32_digest)(void* state);-};--extern const struct archive_xxhash __archive_xxhash;--#endif
− c/autoconf-darwin/config.h
@@ -1,1520 +0,0 @@-/* config.h. Generated from config.h.in by configure. */-/* config.h.in. Generated from configure.ac by autoheader. */--/* Darwin ACL support */-/* #undef ARCHIVE_ACL_DARWIN */--/* FreeBSD ACL support */-/* #undef ARCHIVE_ACL_FREEBSD */--/* FreeBSD NFSv4 ACL support */-/* #undef ARCHIVE_ACL_FREEBSD_NFS4 */--/* Linux POSIX.1e ACL support via libacl */-/* #undef ARCHIVE_ACL_LIBACL */--/* Linux NFSv4 ACL support via librichacl */-/* #undef ARCHIVE_ACL_LIBRICHACL */--/* Solaris ACL support */-/* #undef ARCHIVE_ACL_SUNOS */--/* Solaris NFSv4 ACL support */-/* #undef ARCHIVE_ACL_SUNOS_NFS4 */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_MD5_LIBC */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_MD5_LIBMD */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */-#define ARCHIVE_CRYPTO_MD5_LIBSYSTEM 1--/* MD5 via ARCHIVE_CRYPTO_MD5_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_MD5_MBEDTLS */--/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */--/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */--/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */-/* #undef ARCHIVE_CRYPTO_MD5_WIN */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_LIBMD */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_MBEDTLS */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_LIBMD */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */-#define ARCHIVE_CRYPTO_SHA1_LIBSYSTEM 1--/* SHA1 via ARCHIVE_CRYPTO_SHA1_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_MBEDTLS */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_WIN */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBMD */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */-#define ARCHIVE_CRYPTO_SHA256_LIBSYSTEM 1--/* SHA256 via ARCHIVE_CRYPTO_SHA256_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_MBEDTLS */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_WIN */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */-#define ARCHIVE_CRYPTO_SHA384_LIBSYSTEM 1--/* SHA384 via ARCHIVE_CRYPTO_SHA384_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_MBEDTLS */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_WIN */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBMD */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */-#define ARCHIVE_CRYPTO_SHA512_LIBSYSTEM 1--/* SHA512 via ARCHIVE_CRYPTO_SHA512_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_MBEDTLS */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_WIN */--/* AIX xattr support */-/* #undef ARCHIVE_XATTR_AIX */--/* Darwin xattr support */-/* #undef ARCHIVE_XATTR_DARWIN */--/* FreeBSD xattr support */-/* #undef ARCHIVE_XATTR_FREEBSD */--/* Linux xattr support */-/* #undef ARCHIVE_XATTR_LINUX */--/* Version number of bsdcat */-#define BSDCAT_VERSION_STRING "3.7.1"--/* Version number of bsdcpio */-#define BSDCPIO_VERSION_STRING "3.7.1"--/* Version number of bsdtar */-#define BSDTAR_VERSION_STRING "3.7.1"--/* Define to 1 if the system has the type `ace_t'. */-/* #undef HAVE_ACE_T */--/* Define to 1 if you have the `acl' function. */-/* #undef HAVE_ACL */--/* Define to 1 if the system has the type `aclent_t'. */-/* #undef HAVE_ACLENT_T */--/* Define to 1 if you have the `acl_add_flag_np' function. */-/* #undef HAVE_ACL_ADD_FLAG_NP */--/* Define to 1 if you have the `acl_add_perm' function. */-/* #undef HAVE_ACL_ADD_PERM */--/* Define to 1 if you have the `acl_clear_flags_np' function. */-/* #undef HAVE_ACL_CLEAR_FLAGS_NP */--/* Define to 1 if you have the `acl_clear_perms' function. */-/* #undef HAVE_ACL_CLEAR_PERMS */--/* Define to 1 if you have the `acl_create_entry' function. */-/* #undef HAVE_ACL_CREATE_ENTRY */--/* Define to 1 if you have the `acl_delete_def_file' function. */-/* #undef HAVE_ACL_DELETE_DEF_FILE */--/* Define to 1 if the system has the type `acl_entry_t'. */-/* #undef HAVE_ACL_ENTRY_T */--/* Define to 1 if you have the `acl_free' function. */-/* #undef HAVE_ACL_FREE */--/* Define to 1 if you have the `acl_get_brand_np' function. */-/* #undef HAVE_ACL_GET_BRAND_NP */--/* Define to 1 if you have the `acl_get_entry' function. */-/* #undef HAVE_ACL_GET_ENTRY */--/* Define to 1 if you have the `acl_get_entry_type_np' function. */-/* #undef HAVE_ACL_GET_ENTRY_TYPE_NP */--/* Define to 1 if you have the `acl_get_fd' function. */-/* #undef HAVE_ACL_GET_FD */--/* Define to 1 if you have the `acl_get_fd_np' function. */-/* #undef HAVE_ACL_GET_FD_NP */--/* Define to 1 if you have the `acl_get_file' function. */-/* #undef HAVE_ACL_GET_FILE */--/* Define to 1 if you have the `acl_get_flagset_np' function. */-/* #undef HAVE_ACL_GET_FLAGSET_NP */--/* Define to 1 if you have the `acl_get_flag_np' function. */-/* #undef HAVE_ACL_GET_FLAG_NP */--/* Define to 1 if you have the `acl_get_link_np' function. */-/* #undef HAVE_ACL_GET_LINK_NP */--/* Define to 1 if you have the `acl_get_perm' function. */-/* #undef HAVE_ACL_GET_PERM */--/* Define to 1 if you have the `acl_get_permset' function. */-/* #undef HAVE_ACL_GET_PERMSET */--/* Define to 1 if you have the `acl_get_perm_np' function. */-/* #undef HAVE_ACL_GET_PERM_NP */--/* Define to 1 if you have the `acl_get_qualifier' function. */-/* #undef HAVE_ACL_GET_QUALIFIER */--/* Define to 1 if you have the `acl_get_tag_type' function. */-/* #undef HAVE_ACL_GET_TAG_TYPE */--/* Define to 1 if you have the `acl_init' function. */-/* #undef HAVE_ACL_INIT */--/* Define to 1 if you have the `acl_is_trivial_np' function. */-/* #undef HAVE_ACL_IS_TRIVIAL_NP */--/* Define to 1 if you have the <acl/libacl.h> header file. */-/* #undef HAVE_ACL_LIBACL_H */--/* Define to 1 if the system has the type `acl_permset_t'. */-/* #undef HAVE_ACL_PERMSET_T */--/* Define to 1 if you have the `acl_set_entry_type_np' function. */-/* #undef HAVE_ACL_SET_ENTRY_TYPE_NP */--/* Define to 1 if you have the `acl_set_fd' function. */-/* #undef HAVE_ACL_SET_FD */--/* Define to 1 if you have the `acl_set_fd_np' function. */-/* #undef HAVE_ACL_SET_FD_NP */--/* Define to 1 if you have the `acl_set_file' function. */-/* #undef HAVE_ACL_SET_FILE */--/* Define to 1 if you have the `acl_set_link_np' function. */-/* #undef HAVE_ACL_SET_LINK_NP */--/* Define to 1 if you have the `acl_set_qualifier' function. */-/* #undef HAVE_ACL_SET_QUALIFIER */--/* Define to 1 if you have the `acl_set_tag_type' function. */-/* #undef HAVE_ACL_SET_TAG_TYPE */--/* Define to 1 if the system has the type `acl_t'. */-/* #undef HAVE_ACL_T */--/* Define to 1 if the system has the type `acl_tag_t'. */-/* #undef HAVE_ACL_TAG_T */--/* Define to 1 if you have the `arc4random_buf' function. */-#define HAVE_ARC4RANDOM_BUF 1--/* Define to 1 if you have the <attr/xattr.h> header file. */-/* #undef HAVE_ATTR_XATTR_H */--/* Define to 1 if you have the <bcrypt.h> header file. */-/* #undef HAVE_BCRYPT_H */--/* Define to 1 if you have the <blake2.h> header file. */-/* #undef HAVE_BLAKE2_H */--/* Define to 1 if you have the <bzlib.h> header file. */-/* #undef HAVE_BZLIB_H */--/* Define to 1 if you have the `chflags' function. */-#define HAVE_CHFLAGS 1--/* Define to 1 if you have the `chown' function. */-#define HAVE_CHOWN 1--/* Define to 1 if you have the `chroot' function. */-#define HAVE_CHROOT 1--/* cmtime_s function */-/* #undef HAVE_CMTIME_S */--/* Define to 1 if you have the <copyfile.h> header file. */-#define HAVE_COPYFILE_H 1--/* Define to 1 if you have the `ctime_r' function. */-#define HAVE_CTIME_R 1--/* Define to 1 if you have the <ctype.h> header file. */-#define HAVE_CTYPE_H 1--/* Define to 1 if you have the `cygwin_conv_path' function. */-/* #undef HAVE_CYGWIN_CONV_PATH */--/* Define to 1 if you have the declaration of `ACE_GETACL', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_GETACL */--/* Define to 1 if you have the declaration of `ACE_GETACLCNT', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_GETACLCNT */--/* Define to 1 if you have the declaration of `ACE_SETACL', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_SETACL */--/* Define to 1 if you have the declaration of `ACL_SYNCHRONIZE', and to 0 if- you don't. */-/* #undef HAVE_DECL_ACL_SYNCHRONIZE */--/* Define to 1 if you have the declaration of `ACL_TYPE_EXTENDED', and to 0 if- you don't. */-/* #undef HAVE_DECL_ACL_TYPE_EXTENDED */--/* Define to 1 if you have the declaration of `ACL_TYPE_NFS4', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACL_TYPE_NFS4 */--/* Define to 1 if you have the declaration of `ACL_USER', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACL_USER */--/* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to- 0 if you don't. */-/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */--/* Define to 1 if you have the declaration of `GETACL', and to 0 if you don't.- */-/* #undef HAVE_DECL_GETACL */--/* Define to 1 if you have the declaration of `GETACLCNT', and to 0 if you- don't. */-/* #undef HAVE_DECL_GETACLCNT */--/* Define to 1 if you have the declaration of `INT32_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INT32_MAX 1--/* Define to 1 if you have the declaration of `INT32_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INT32_MIN 1--/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INT64_MAX 1--/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INT64_MIN 1--/* Define to 1 if you have the declaration of `INTMAX_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INTMAX_MAX 1--/* Define to 1 if you have the declaration of `INTMAX_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INTMAX_MIN 1--/* Define to 1 if you have the declaration of `SETACL', and to 0 if you don't.- */-/* #undef HAVE_DECL_SETACL */--/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you- don't. */-#define HAVE_DECL_SIZE_MAX 1--/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you- don't. */-#define HAVE_DECL_SSIZE_MAX 1--/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you- don't. */-#define HAVE_DECL_STRERROR_R 1--/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINT32_MAX 1--/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINT64_MAX 1--/* Define to 1 if you have the declaration of `UINTMAX_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINTMAX_MAX 1--/* Define to 1 if you have the declaration of `XATTR_NOFOLLOW', and to 0 if- you don't. */-/* #undef HAVE_DECL_XATTR_NOFOLLOW */--/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.- */-#define HAVE_DIRENT_H 1--/* Define to 1 if you have a dirfd function or macro */-#define HAVE_DIRFD 1--/* Define to 1 if you have the <dlfcn.h> header file. */-#define HAVE_DLFCN_H 1--/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */-/* #undef HAVE_DOPRNT */--/* Define to 1 if nl_langinfo supports D_MD_ORDER */-#define HAVE_D_MD_ORDER 1--/* A possible errno value for invalid file format errors */-#define HAVE_EFTYPE 1--/* A possible errno value for invalid file format errors */-#define HAVE_EILSEQ 1--/* Define to 1 if you have the <errno.h> header file. */-#define HAVE_ERRNO_H 1--/* Define to 1 if you have the <expat.h> header file. */-/* #undef HAVE_EXPAT_H */--/* Define to 1 if you have the <ext2fs/ext2_fs.h> header file. */-/* #undef HAVE_EXT2FS_EXT2_FS_H */--/* Define to 1 if you have the `extattr_get_fd' function. */-/* #undef HAVE_EXTATTR_GET_FD */--/* Define to 1 if you have the `extattr_get_file' function. */-/* #undef HAVE_EXTATTR_GET_FILE */--/* Define to 1 if you have the `extattr_get_link' function. */-/* #undef HAVE_EXTATTR_GET_LINK */--/* Define to 1 if you have the `extattr_list_fd' function. */-/* #undef HAVE_EXTATTR_LIST_FD */--/* Define to 1 if you have the `extattr_list_file' function. */-/* #undef HAVE_EXTATTR_LIST_FILE */--/* Define to 1 if you have the `extattr_list_link' function. */-/* #undef HAVE_EXTATTR_LIST_LINK */--/* Define to 1 if you have the `extattr_set_fd' function. */-/* #undef HAVE_EXTATTR_SET_FD */--/* Define to 1 if you have the `extattr_set_link' function. */-/* #undef HAVE_EXTATTR_SET_LINK */--/* Define to 1 if you have the `facl' function. */-/* #undef HAVE_FACL */--/* Define to 1 if you have the `fchdir' function. */-#define HAVE_FCHDIR 1--/* Define to 1 if you have the `fchflags' function. */-#define HAVE_FCHFLAGS 1--/* Define to 1 if you have the `fchmod' function. */-#define HAVE_FCHMOD 1--/* Define to 1 if you have the `fchown' function. */-#define HAVE_FCHOWN 1--/* Define to 1 if you have the `fcntl' function. */-#define HAVE_FCNTL 1--/* Define to 1 if you have the <fcntl.h> header file. */-#define HAVE_FCNTL_H 1--/* Define to 1 if you have the `fdopendir' function. */-#define HAVE_FDOPENDIR 1--/* Define to 1 if you have the `fgetea' function. */-/* #undef HAVE_FGETEA */--/* Define to 1 if you have the `fgetxattr' function. */-/* #undef HAVE_FGETXATTR */--/* Define to 1 if you have the `flistea' function. */-/* #undef HAVE_FLISTEA */--/* Define to 1 if you have the `flistxattr' function. */-/* #undef HAVE_FLISTXATTR */--/* Define to 1 if you have the `fnmatch' function. */-#define HAVE_FNMATCH 1--/* Define to 1 if you have the <fnmatch.h> header file. */-#define HAVE_FNMATCH_H 1--/* Define to 1 if you have the `fork' function. */-#define HAVE_FORK 1--/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */-#define HAVE_FSEEKO 1--/* Define to 1 if you have the `fsetea' function. */-/* #undef HAVE_FSETEA */--/* Define to 1 if you have the `fsetxattr' function. */-/* #undef HAVE_FSETXATTR */--/* Define to 1 if you have the `fstat' function. */-#define HAVE_FSTAT 1--/* Define to 1 if you have the `fstatat' function. */-#define HAVE_FSTATAT 1--/* Define to 1 if you have the `fstatfs' function. */-#define HAVE_FSTATFS 1--/* Define to 1 if you have the `fstatvfs' function. */-#define HAVE_FSTATVFS 1--/* Define to 1 if you have the `ftruncate' function. */-#define HAVE_FTRUNCATE 1--/* Define to 1 if you have the `futimens' function. */-#define HAVE_FUTIMENS 1--/* Define to 1 if you have the `futimes' function. */-#define HAVE_FUTIMES 1--/* Define to 1 if you have the `futimesat' function. */-/* #undef HAVE_FUTIMESAT */--/* Define to 1 if you have the `getea' function. */-/* #undef HAVE_GETEA */--/* Define to 1 if you have the `geteuid' function. */-#define HAVE_GETEUID 1--/* Define to 1 if you have the `getgrgid_r' function. */-#define HAVE_GETGRGID_R 1--/* Define to 1 if you have the `getgrnam_r' function. */-#define HAVE_GETGRNAM_R 1--/* Define to 1 if you have the `getline' function. */-#define HAVE_GETLINE 1--/* Platform uses optreset to reset getopt */-#define HAVE_GETOPT_OPTRESET 1--/* Define to 1 if you have the `getpid' function. */-#define HAVE_GETPID 1--/* Define to 1 if you have the `getpwnam_r' function. */-#define HAVE_GETPWNAM_R 1--/* Define to 1 if you have the `getpwuid_r' function. */-#define HAVE_GETPWUID_R 1--/* Define to 1 if you have the `getvfsbyname' function. */-#define HAVE_GETVFSBYNAME 1--/* Define to 1 if you have the `getxattr' function. */-/* #undef HAVE_GETXATTR */--/* Define to 1 if you have the `gmtime_r' function. */-#define HAVE_GMTIME_R 1--/* gmtime_s function */-/* #undef HAVE_GMTIME_S */--/* Define to 1 if you have the <grp.h> header file. */-#define HAVE_GRP_H 1--/* Define if you have the iconv() function and it works. */-/* #undef HAVE_ICONV */--/* Define to 1 if you have the <iconv.h> header file. */-/* #undef HAVE_ICONV_H */--/* Define to 1 if the system has the type `intmax_t'. */-#define HAVE_INTMAX_T 1--/* Define to 1 if you have the <inttypes.h> header file. */-#define HAVE_INTTYPES_H 1--/* Define to 1 if you have the <io.h> header file. */-/* #undef HAVE_IO_H */--/* Define to 1 if you have the <langinfo.h> header file. */-#define HAVE_LANGINFO_H 1--/* Define to 1 if you have the `lchflags' function. */-#define HAVE_LCHFLAGS 1--/* Define to 1 if you have the `lchmod' function. */-#define HAVE_LCHMOD 1--/* Define to 1 if you have the `lchown' function. */-#define HAVE_LCHOWN 1--/* Define to 1 if you have the `lgetea' function. */-/* #undef HAVE_LGETEA */--/* Define to 1 if you have the `lgetxattr' function. */-/* #undef HAVE_LGETXATTR */--/* Define to 1 if you have the `acl' library (-lacl). */-/* #undef HAVE_LIBACL */--/* Define to 1 if you have the `b2' library (-lb2). */-/* #undef HAVE_LIBB2 */--/* Define to 1 if you have the `bz2' library (-lbz2). */-/* #undef HAVE_LIBBZ2 */--/* Define to 1 if you have the `charset' library (-lcharset). */-/* #undef HAVE_LIBCHARSET */--/* Define to 1 if you have the `crypto' library (-lcrypto). */-/* #undef HAVE_LIBCRYPTO */--/* Define to 1 if you have the `expat' library (-lexpat). */-/* #undef HAVE_LIBEXPAT */--/* Define to 1 if you have the `lz4' library (-llz4). */-/* #undef HAVE_LIBLZ4 */--/* Define to 1 if you have the `lzma' library (-llzma). */-/* #undef HAVE_LIBLZMA */--/* Define to 1 if you have the `lzo2' library (-llzo2). */-/* #undef HAVE_LIBLZO2 */--/* Define to 1 if you have the `mbedcrypto' library (-lmbedcrypto). */-/* #undef HAVE_LIBMBEDCRYPTO */--/* Define to 1 if you have the `md' library (-lmd). */-/* #undef HAVE_LIBMD */--/* Define to 1 if you have the `nettle' library (-lnettle). */-/* #undef HAVE_LIBNETTLE */--/* Define to 1 if you have the `pcre' library (-lpcre). */-/* #undef HAVE_LIBPCRE */--/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */-/* #undef HAVE_LIBPCREPOSIX */--/* Define to 1 if you have the `regex' library (-lregex). */-/* #undef HAVE_LIBREGEX */--/* Define to 1 if you have the `richacl' library (-lrichacl). */-/* #undef HAVE_LIBRICHACL */--/* Define to 1 if you have the `xml2' library (-lxml2). */-/* #undef HAVE_LIBXML2 */--/* Define to 1 if you have the <libxml/xmlreader.h> header file. */-/* #undef HAVE_LIBXML_XMLREADER_H */--/* Define to 1 if you have the <libxml/xmlwriter.h> header file. */-/* #undef HAVE_LIBXML_XMLWRITER_H */--/* Define to 1 if you have the `z' library (-lz). */-/* #undef HAVE_LIBZ */--/* Define to 1 if you have the `zstd' library (-lzstd). */-/* #undef HAVE_LIBZSTD */--/* Define to 1 if you have the `zstd' library (-lzstd) with compression- support. */-/* #undef HAVE_LIBZSTD_COMPRESSOR */--/* Define to 1 if you have the <limits.h> header file. */-#define HAVE_LIMITS_H 1--/* Define to 1 if you have the `link' function. */-#define HAVE_LINK 1--/* Define to 1 if you have the `linkat' function. */-#define HAVE_LINKAT 1--/* Define to 1 if you have the <linux/fiemap.h> header file. */-/* #undef HAVE_LINUX_FIEMAP_H */--/* Define to 1 if you have the <linux/fs.h> header file. */-/* #undef HAVE_LINUX_FS_H */--/* Define to 1 if you have the <linux/magic.h> header file. */-/* #undef HAVE_LINUX_MAGIC_H */--/* Define to 1 if you have the <linux/types.h> header file. */-/* #undef HAVE_LINUX_TYPES_H */--/* Define to 1 if you have the `listea' function. */-/* #undef HAVE_LISTEA */--/* Define to 1 if you have the `listxattr' function. */-/* #undef HAVE_LISTXATTR */--/* Define to 1 if you have the `llistea' function. */-/* #undef HAVE_LLISTEA */--/* Define to 1 if you have the `llistxattr' function. */-/* #undef HAVE_LLISTXATTR */--/* Define to 1 if you have the <localcharset.h> header file. */-/* #undef HAVE_LOCALCHARSET_H */--/* Define to 1 if you have the `locale_charset' function. */-/* #undef HAVE_LOCALE_CHARSET */--/* Define to 1 if you have the <locale.h> header file. */-#define HAVE_LOCALE_H 1--/* Define to 1 if you have the `localtime_r' function. */-#define HAVE_LOCALTIME_R 1--/* localtime_s function */-/* #undef HAVE_LOCALTIME_S */--/* Define to 1 if the system has the type `long long int'. */-#define HAVE_LONG_LONG_INT 1--/* Define to 1 if you have the `lsetea' function. */-/* #undef HAVE_LSETEA */--/* Define to 1 if you have the `lsetxattr' function. */-/* #undef HAVE_LSETXATTR */--/* Define to 1 if you have the `lstat' function. */-#define HAVE_LSTAT 1--/* Define to 1 if `lstat' has the bug that it succeeds when given the- zero-length file name argument. */-/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */--/* Define to 1 if you have the `lutimes' function. */-#define HAVE_LUTIMES 1--/* Define to 1 if you have the <lz4hc.h> header file. */-/* #undef HAVE_LZ4HC_H */--/* Define to 1 if you have the <lz4.h> header file. */-/* #undef HAVE_LZ4_H */--/* Define to 1 if you have the `LZMA_FILTER_ARM64' macro. */-/* #undef HAVE_LZMA_FILTER_ARM64 */--/* Define to 1 if you have the <lzma.h> header file. */-/* #undef HAVE_LZMA_H */--/* Define to 1 if you have the `lzma_stream_encoder_mt' function. */-/* #undef HAVE_LZMA_STREAM_ENCODER_MT */--/* Define to 1 if you have the <lzo/lzo1x.h> header file. */-/* #undef HAVE_LZO_LZO1X_H */--/* Define to 1 if you have the <lzo/lzoconf.h> header file. */-/* #undef HAVE_LZO_LZOCONF_H */--/* Define to 1 if you have the <mbedtls/aes.h> header file. */-/* #undef HAVE_MBEDTLS_AES_H */--/* Define to 1 if you have the <mbedtls/md.h> header file. */-/* #undef HAVE_MBEDTLS_MD_H */--/* Define to 1 if you have the <mbedtls/pkcs5.h> header file. */-/* #undef HAVE_MBEDTLS_PKCS5_H */--/* Define to 1 if you have the `mbrtowc' function. */-#define HAVE_MBRTOWC 1--/* Define to 1 if you have the `mbr_gid_to_uuid' function. */-/* #undef HAVE_MBR_GID_TO_UUID */--/* Define to 1 if you have the `mbr_uid_to_uuid' function. */-/* #undef HAVE_MBR_UID_TO_UUID */--/* Define to 1 if you have the `mbr_uuid_to_id' function. */-/* #undef HAVE_MBR_UUID_TO_ID */--/* Define to 1 if you have the <md5.h> header file. */-/* #undef HAVE_MD5_H */--/* Define to 1 if you have the <membership.h> header file. */-#define HAVE_MEMBERSHIP_H 1--/* Define to 1 if you have the `memmove' function. */-#define HAVE_MEMMOVE 1--/* Define to 1 if you have the `memset' function. */-#define HAVE_MEMSET 1--/* Define to 1 if you have the <minix/config.h> header file. */-/* #undef HAVE_MINIX_CONFIG_H */--/* Define to 1 if you have the `mkdir' function. */-#define HAVE_MKDIR 1--/* Define to 1 if you have the `mkfifo' function. */-#define HAVE_MKFIFO 1--/* Define to 1 if you have the `mknod' function. */-#define HAVE_MKNOD 1--/* Define to 1 if you have the `mkstemp' function. */-#define HAVE_MKSTEMP 1--/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */-/* #undef HAVE_NDIR_H */--/* Define to 1 if you have the <nettle/aes.h> header file. */-/* #undef HAVE_NETTLE_AES_H */--/* Define to 1 if you have the <nettle/hmac.h> header file. */-/* #undef HAVE_NETTLE_HMAC_H */--/* Define to 1 if you have the <nettle/md5.h> header file. */-/* #undef HAVE_NETTLE_MD5_H */--/* Define to 1 if you have the <nettle/pbkdf2.h> header file. */-/* #undef HAVE_NETTLE_PBKDF2_H */--/* Define to 1 if you have the <nettle/ripemd160.h> header file. */-/* #undef HAVE_NETTLE_RIPEMD160_H */--/* Define to 1 if you have the <nettle/sha.h> header file. */-/* #undef HAVE_NETTLE_SHA_H */--/* Define to 1 if you have the `nl_langinfo' function. */-#define HAVE_NL_LANGINFO 1--/* Define to 1 if you have the `openat' function. */-#define HAVE_OPENAT 1--/* Define to 1 if you have the <openssl/evp.h> header file. */-/* #undef HAVE_OPENSSL_EVP_H */--/* Define to 1 if you have the <paths.h> header file. */-#define HAVE_PATHS_H 1--/* Define to 1 if you have the <pcreposix.h> header file. */-/* #undef HAVE_PCREPOSIX_H */--/* Define to 1 if you have the `pipe' function. */-#define HAVE_PIPE 1--/* Define to 1 if you have the `PKCS5_PBKDF2_HMAC_SHA1' function. */-/* #undef HAVE_PKCS5_PBKDF2_HMAC_SHA1 */--/* Define to 1 if you have the `poll' function. */-#define HAVE_POLL 1--/* Define to 1 if you have the <poll.h> header file. */-#define HAVE_POLL_H 1--/* Define to 1 if you have the `posix_spawnp' function. */-#define HAVE_POSIX_SPAWNP 1--/* Define to 1 if you have the <pthread.h> header file. */-#define HAVE_PTHREAD_H 1--/* Define to 1 if you have the <pwd.h> header file. */-#define HAVE_PWD_H 1--/* Define to 1 if you have a POSIX compatible readdir_r */-#define HAVE_READDIR_R 1--/* Define to 1 if you have the `readlink' function. */-#define HAVE_READLINK 1--/* Define to 1 if you have the `readlinkat' function. */-#define HAVE_READLINKAT 1--/* Define to 1 if you have the `readpassphrase' function. */-#define HAVE_READPASSPHRASE 1--/* Define to 1 if you have the <readpassphrase.h> header file. */-#define HAVE_READPASSPHRASE_H 1--/* Define to 1 if you have the <regex.h> header file. */-/* #undef HAVE_REGEX_H */--/* Define to 1 if you have the `richacl_alloc' function. */-/* #undef HAVE_RICHACL_ALLOC */--/* Define to 1 if you have the `richacl_equiv_mode' function. */-/* #undef HAVE_RICHACL_EQUIV_MODE */--/* Define to 1 if you have the `richacl_free' function. */-/* #undef HAVE_RICHACL_FREE */--/* Define to 1 if you have the `richacl_get_fd' function. */-/* #undef HAVE_RICHACL_GET_FD */--/* Define to 1 if you have the `richacl_get_file' function. */-/* #undef HAVE_RICHACL_GET_FILE */--/* Define to 1 if you have the `richacl_set_fd' function. */-/* #undef HAVE_RICHACL_SET_FD */--/* Define to 1 if you have the `richacl_set_file' function. */-/* #undef HAVE_RICHACL_SET_FILE */--/* Define to 1 if you have the <ripemd.h> header file. */-/* #undef HAVE_RIPEMD_H */--/* Define to 1 if you have the `select' function. */-#define HAVE_SELECT 1--/* Define to 1 if you have the `setenv' function. */-#define HAVE_SETENV 1--/* Define to 1 if you have the `setlocale' function. */-#define HAVE_SETLOCALE 1--/* Define to 1 if you have the `setxattr' function. */-/* #undef HAVE_SETXATTR */--/* Define to 1 if you have the <sha256.h> header file. */-/* #undef HAVE_SHA256_H */--/* Define to 1 if you have the <sha512.h> header file. */-/* #undef HAVE_SHA512_H */--/* Define to 1 if you have the <sha.h> header file. */-/* #undef HAVE_SHA_H */--/* Define to 1 if you have the `sigaction' function. */-#define HAVE_SIGACTION 1--/* Define to 1 if you have the <signal.h> header file. */-#define HAVE_SIGNAL_H 1--/* Define to 1 if you have the <spawn.h> header file. */-#define HAVE_SPAWN_H 1--/* Define to 1 if you have the `statfs' function. */-#define HAVE_STATFS 1--/* Define to 1 if you have the `statvfs' function. */-#define HAVE_STATVFS 1--/* Define to 1 if `stat' has the bug that it succeeds when given the- zero-length file name argument. */-/* #undef HAVE_STAT_EMPTY_STRING_BUG */--/* Define to 1 if you have the <stdarg.h> header file. */-#define HAVE_STDARG_H 1--/* Define to 1 if you have the <stdint.h> header file. */-#define HAVE_STDINT_H 1--/* Define to 1 if you have the <stdio.h> header file. */-#define HAVE_STDIO_H 1--/* Define to 1 if you have the <stdlib.h> header file. */-#define HAVE_STDLIB_H 1--/* Define to 1 if you have the `strchr' function. */-#define HAVE_STRCHR 1--/* Define to 1 if you have the `strdup' function. */-#define HAVE_STRDUP 1--/* Define to 1 if you have the `strerror' function. */-#define HAVE_STRERROR 1--/* Define if you have `strerror_r'. */-#define HAVE_STRERROR_R 1--/* Define to 1 if you have the `strftime' function. */-#define HAVE_STRFTIME 1--/* Define to 1 if you have the <strings.h> header file. */-#define HAVE_STRINGS_H 1--/* Define to 1 if you have the <string.h> header file. */-#define HAVE_STRING_H 1--/* Define to 1 if you have the `strncpy_s' function. */-/* #undef HAVE_STRNCPY_S */--/* Define to 1 if you have the `strnlen' function. */-#define HAVE_STRNLEN 1--/* Define to 1 if you have the `strrchr' function. */-#define HAVE_STRRCHR 1--/* Define to 1 if the system has the type `struct richace'. */-/* #undef HAVE_STRUCT_RICHACE */--/* Define to 1 if the system has the type `struct richacl'. */-/* #undef HAVE_STRUCT_RICHACL */--/* Define to 1 if the system has the type `struct statfs'. */-#define HAVE_STRUCT_STATFS 1--/* Define to 1 if `f_iosize' is a member of `struct statfs'. */-#define HAVE_STRUCT_STATFS_F_IOSIZE 1--/* Define to 1 if `f_namemax' is a member of `struct statfs'. */-/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */--/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */-/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */--/* Define to 1 if `st_birthtime' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1--/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1--/* Define to 1 if `st_blksize' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_BLKSIZE 1--/* Define to 1 if `st_flags' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_FLAGS 1--/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1--/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */--/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */--/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */--/* Define to 1 if `st_umtime' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_UMTIME */--/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */-#define HAVE_STRUCT_TM_TM_GMTOFF 1--/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */-/* #undef HAVE_STRUCT_TM___TM_GMTOFF */--/* Define to 1 if the system has the type `struct vfsconf'. */-#define HAVE_STRUCT_VFSCONF 1--/* Define to 1 if the system has the type `struct xvfsconf'. */-/* #undef HAVE_STRUCT_XVFSCONF */--/* Define to 1 if you have the `symlink' function. */-#define HAVE_SYMLINK 1--/* Define to 1 if you have the <sys/acl.h> header file. */--/* Define to 1 if you have the <sys/cdefs.h> header file. */-#define HAVE_SYS_CDEFS_H 1--/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.- */-/* #undef HAVE_SYS_DIR_H */--/* Define to 1 if you have the <sys/ea.h> header file. */-/* #undef HAVE_SYS_EA_H */--/* Define to 1 if you have the <sys/extattr.h> header file. */-/* #undef HAVE_SYS_EXTATTR_H */--/* Define to 1 if you have the <sys/ioctl.h> header file. */-#define HAVE_SYS_IOCTL_H 1--/* Define to 1 if you have the <sys/mkdev.h> header file. */-/* #undef HAVE_SYS_MKDEV_H */--/* Define to 1 if you have the <sys/mount.h> header file. */-#define HAVE_SYS_MOUNT_H 1--/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.- */-/* #undef HAVE_SYS_NDIR_H */--/* Define to 1 if you have the <sys/param.h> header file. */-#define HAVE_SYS_PARAM_H 1--/* Define to 1 if you have the <sys/poll.h> header file. */-#define HAVE_SYS_POLL_H 1--/* Define to 1 if you have the <sys/queue.h> header file. */-#define HAVE_SYS_QUEUE_H 1--/* Define to 1 if you have the <sys/richacl.h> header file. */-/* #undef HAVE_SYS_RICHACL_H */--/* Define to 1 if you have the <sys/select.h> header file. */-#define HAVE_SYS_SELECT_H 1--/* Define to 1 if you have the <sys/statfs.h> header file. */-/* #undef HAVE_SYS_STATFS_H */--/* Define to 1 if you have the <sys/statvfs.h> header file. */-#define HAVE_SYS_STATVFS_H 1--/* Define to 1 if you have the <sys/stat.h> header file. */-#define HAVE_SYS_STAT_H 1--/* Define to 1 if you have the <sys/sysmacros.h> header file. */-/* #undef HAVE_SYS_SYSMACROS_H */--/* Define to 1 if you have the <sys/time.h> header file. */-#define HAVE_SYS_TIME_H 1--/* Define to 1 if you have the <sys/types.h> header file. */-#define HAVE_SYS_TYPES_H 1--/* Define to 1 if you have the <sys/utime.h> header file. */-/* #undef HAVE_SYS_UTIME_H */--/* Define to 1 if you have the <sys/utsname.h> header file. */-#define HAVE_SYS_UTSNAME_H 1--/* Define to 1 if you have the <sys/vfs.h> header file. */-/* #undef HAVE_SYS_VFS_H */--/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */-#define HAVE_SYS_WAIT_H 1--/* Define to 1 if you have the <sys/xattr.h> header file. */-#define HAVE_SYS_XATTR_H 1--/* Define to 1 if you have the `timegm' function. */-#define HAVE_TIMEGM 1--/* Define to 1 if you have the <time.h> header file. */-#define HAVE_TIME_H 1--/* Define to 1 if you have the `tzset' function. */-#define HAVE_TZSET 1--/* Define to 1 if the system has the type `uintmax_t'. */-#define HAVE_UINTMAX_T 1--/* Define to 1 if you have the <unistd.h> header file. */-#define HAVE_UNISTD_H 1--/* Define to 1 if you have the `unlinkat' function. */-#define HAVE_UNLINKAT 1--/* Define to 1 if you have the `unsetenv' function. */-#define HAVE_UNSETENV 1--/* Define to 1 if the system has the type `unsigned long long'. */-#define HAVE_UNSIGNED_LONG_LONG 1--/* Define to 1 if the system has the type `unsigned long long int'. */-#define HAVE_UNSIGNED_LONG_LONG_INT 1--/* Define to 1 if you have the `utime' function. */-#define HAVE_UTIME 1--/* Define to 1 if you have the `utimensat' function. */-#define HAVE_UTIMENSAT 1--/* Define to 1 if you have the `utimes' function. */-#define HAVE_UTIMES 1--/* Define to 1 if you have the <utime.h> header file. */-#define HAVE_UTIME_H 1--/* Define to 1 if you have the `vfork' function. */-#define HAVE_VFORK 1--/* Define to 1 if you have the `vprintf' function. */-#define HAVE_VPRINTF 1--/* Define to 1 if you have the <wchar.h> header file. */-#define HAVE_WCHAR_H 1--/* Define to 1 if the system has the type `wchar_t'. */-#define HAVE_WCHAR_T 1--/* Define to 1 if you have the `wcrtomb' function. */-#define HAVE_WCRTOMB 1--/* Define to 1 if you have the `wcscmp' function. */-#define HAVE_WCSCMP 1--/* Define to 1 if you have the `wcscpy' function. */-#define HAVE_WCSCPY 1--/* Define to 1 if you have the `wcslen' function. */-#define HAVE_WCSLEN 1--/* Define to 1 if you have the `wctomb' function. */-#define HAVE_WCTOMB 1--/* Define to 1 if you have the <wctype.h> header file. */-#define HAVE_WCTYPE_H 1--/* Define to 1 if you have the <wincrypt.h> header file. */-/* #undef HAVE_WINCRYPT_H */--/* Define to 1 if you have the <windows.h> header file. */-/* #undef HAVE_WINDOWS_H */--/* Define to 1 if you have the <winioctl.h> header file. */-/* #undef HAVE_WINIOCTL_H */--/* Define to 1 if you have the `wmemcmp' function. */-#define HAVE_WMEMCMP 1--/* Define to 1 if you have the `wmemcpy' function. */-#define HAVE_WMEMCPY 1--/* Define to 1 if you have the `wmemmove' function. */-#define HAVE_WMEMMOVE 1--/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */-/* #undef HAVE_WORKING_EXT2_IOC_GETFLAGS */--/* Define to 1 if you have a working FS_IOC_GETFLAGS */-/* #undef HAVE_WORKING_FS_IOC_GETFLAGS */--/* Define to 1 if you have the <zlib.h> header file. */-/* #undef HAVE_ZLIB_H */--/* Define to 1 if you have the <zstd.h> header file. */-/* #undef HAVE_ZSTD_H */--/* Define to 1 if you have the `_fseeki64' function. */-/* #undef HAVE__FSEEKI64 */--/* Define to 1 if you have the `_get_timezone' function. */-/* #undef HAVE__GET_TIMEZONE */--/* _mkgmtime function */-/* #undef HAVE__MKGMTIME */--/* Define as const if the declaration of iconv() needs const. */-/* #undef ICONV_CONST */--/* Version number of libarchive as a single integer */-#define LIBARCHIVE_VERSION_NUMBER "3007001"--/* Version number of libarchive */-#define LIBARCHIVE_VERSION_STRING "3.7.1"--/* Define to 1 if `lstat' dereferences a symlink specified with a trailing- slash. */-/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */--/* Define to the sub-directory where libtool stores uninstalled libraries. */-#define LT_OBJDIR ".libs/"--/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.- */-/* #undef MAJOR_IN_MKDEV */--/* Define to 1 if `major', `minor', and `makedev' are declared in- <sysmacros.h>. */-/* #undef MAJOR_IN_SYSMACROS */--/* Define to '0x05020000' for Windows Server 2003 APIs. */-/* #undef NTDDI_VERSION */--/* Name of package */-#define PACKAGE "libarchive"--/* Define to the address where bug reports for this package should be sent. */-#define PACKAGE_BUGREPORT "libarchive-discuss@googlegroups.com"--/* Define to the full name of this package. */-#define PACKAGE_NAME "libarchive"--/* Define to the full name and version of this package. */-#define PACKAGE_STRING "libarchive 3.7.1"--/* Define to the one symbol short name of this package. */-#define PACKAGE_TARNAME "libarchive"--/* Define to the home page for this package. */-#define PACKAGE_URL ""--/* Define to the version of this package. */-#define PACKAGE_VERSION "3.7.1"--/* Define to 1 if PCRE_STATIC needs to be defined. */-/* #undef PCRE_STATIC */--/* The number of bytes in type int */-#define SIZEOF_INT 4--/* The number of bytes in type long */-#define SIZEOF_LONG 8--/* The size of `wchar_t', as computed by sizeof. */-#define SIZEOF_WCHAR_T 4--/* Define to 1 if all of the C90 standard headers exist (not just the ones- required in a freestanding environment). This macro is provided for- backward compatibility; new code need not use it. */-#define STDC_HEADERS 1--/* Define to 1 if strerror_r returns char *. */-/* #undef STRERROR_R_CHAR_P */--/* Enable extensions on AIX 3, Interix. */-#ifndef _ALL_SOURCE-# define _ALL_SOURCE 1-#endif-/* Enable general extensions on macOS. */-#ifndef _DARWIN_C_SOURCE-# define _DARWIN_C_SOURCE 1-#endif-/* Enable general extensions on Solaris. */-#ifndef __EXTENSIONS__-# define __EXTENSIONS__ 1-#endif-/* Enable GNU extensions on systems that have them. */-#ifndef _GNU_SOURCE-# define _GNU_SOURCE 1-#endif-/* Enable X/Open compliant socket functions that do not require linking- with -lxnet on HP-UX 11.11. */-#ifndef _HPUX_ALT_XOPEN_SOCKET_API-# define _HPUX_ALT_XOPEN_SOCKET_API 1-#endif-/* Identify the host operating system as Minix.- This macro does not affect the system headers' behavior.- A future release of Autoconf may stop defining this macro. */-#ifndef _MINIX-/* # undef _MINIX */-#endif-/* Enable general extensions on NetBSD.- Enable NetBSD compatibility extensions on Minix. */-#ifndef _NETBSD_SOURCE-# define _NETBSD_SOURCE 1-#endif-/* Enable OpenBSD compatibility extensions on NetBSD.- Oddly enough, this does nothing on OpenBSD. */-#ifndef _OPENBSD_SOURCE-# define _OPENBSD_SOURCE 1-#endif-/* Define to 1 if needed for POSIX-compatible behavior. */-#ifndef _POSIX_SOURCE-/* # undef _POSIX_SOURCE */-#endif-/* Define to 2 if needed for POSIX-compatible behavior. */-#ifndef _POSIX_1_SOURCE-/* # undef _POSIX_1_SOURCE */-#endif-/* Enable POSIX-compatible threading on Solaris. */-#ifndef _POSIX_PTHREAD_SEMANTICS-# define _POSIX_PTHREAD_SEMANTICS 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */-#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__-# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */-#ifndef __STDC_WANT_IEC_60559_BFP_EXT__-# define __STDC_WANT_IEC_60559_BFP_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */-#ifndef __STDC_WANT_IEC_60559_DFP_EXT__-# define __STDC_WANT_IEC_60559_DFP_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */-#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__-# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */-#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__-# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */-#ifndef __STDC_WANT_LIB_EXT2__-# define __STDC_WANT_LIB_EXT2__ 1-#endif-/* Enable extensions specified by ISO/IEC 24747:2009. */-#ifndef __STDC_WANT_MATH_SPEC_FUNCS__-# define __STDC_WANT_MATH_SPEC_FUNCS__ 1-#endif-/* Enable extensions on HP NonStop. */-#ifndef _TANDEM_SOURCE-# define _TANDEM_SOURCE 1-#endif-/* Enable X/Open extensions. Define to 500 only if necessary- to make mbstate_t available. */-#ifndef _XOPEN_SOURCE-/* # undef _XOPEN_SOURCE */-#endif---/* Version number of package */-#define VERSION "3.7.1"--/* Define to '0x0502' for Windows Server 2003 APIs. */-/* #undef WINVER */--/* Number of bits in a file offset, on hosts where this is settable. */-/* #undef _FILE_OFFSET_BITS */--/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */-/* #undef _LARGEFILE_SOURCE */--/* Define for large files, on AIX-style hosts. */-/* #undef _LARGE_FILES */--/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT32_T */--/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT64_T */--/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT8_T */--/* Define to '0x0502' for Windows Server 2003 APIs. */-/* #undef _WIN32_WINNT */--/* Internal macro for sanity checks */-#define __LIBARCHIVE_CONFIG_H_INCLUDED 1--/* Define to empty if `const' does not conform to ANSI C. */-/* #undef const */--/* Define to match typeof st_gid field of struct stat if <sys/types.h> doesn't- define. */-/* #undef gid_t */--/* Define to `unsigned long' if <sys/types.h> does not define. */-/* #undef id_t */--/* Define to the type of a signed integer type of width exactly 16 bits if- such a type exists and the standard includes do not define it. */-/* #undef int16_t */--/* Define to the type of a signed integer type of width exactly 32 bits if- such a type exists and the standard includes do not define it. */-/* #undef int32_t */--/* Define to the type of a signed integer type of width exactly 64 bits if- such a type exists and the standard includes do not define it. */-/* #undef int64_t */--/* Define to the widest signed integer type if <stdint.h> and <inttypes.h> do- not define. */-/* #undef intmax_t */--/* Define to `int' if <sys/types.h> does not define. */-/* #undef mode_t */--/* Define to `long long' if <sys/types.h> does not define. */-/* #undef off_t */--/* Define to `unsigned int' if <sys/types.h> does not define. */-/* #undef size_t */--/* Define to match typeof st_uid field of struct stat if <sys/types.h> doesn't- define. */-/* #undef uid_t */--/* Define to the type of an unsigned integer type of width exactly 16 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint16_t */--/* Define to the type of an unsigned integer type of width exactly 32 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint32_t */--/* Define to the type of an unsigned integer type of width exactly 64 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint64_t */--/* Define to the type of an unsigned integer type of width exactly 8 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint8_t */--/* Define to the widest unsigned integer type if <stdint.h> and <inttypes.h>- do not define. */-/* #undef uintmax_t */--/* Define to `unsigned int' if <sys/types.h> does not define. */-/* #undef uintptr_t */-#define HAVE_LIBZ 1-#define HAVE_ZLIB_H 1
− c/autoconf-freebsd/config.h
@@ -1,1509 +0,0 @@-/* config.h. Generated from config.h.in by configure. */-/* config.h.in. Generated from configure.ac by autoheader. */--/* Darwin ACL support */-/* #undef ARCHIVE_ACL_DARWIN */--/* FreeBSD ACL support */-/* #undef ARCHIVE_ACL_FREEBSD */--/* FreeBSD NFSv4 ACL support */-/* #undef ARCHIVE_ACL_FREEBSD_NFS4 */--/* Linux POSIX.1e ACL support via libacl */-/* #undef ARCHIVE_ACL_LIBACL */--/* Linux NFSv4 ACL support via librichacl */-/* #undef ARCHIVE_ACL_LIBRICHACL */--/* Solaris ACL support */-/* #undef ARCHIVE_ACL_SUNOS */--/* Solaris NFSv4 ACL support */-/* #undef ARCHIVE_ACL_SUNOS_NFS4 */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_MD5_LIBC */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBMD supported. */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_MD5_LIBSYSTEM */--/* MD5 via ARCHIVE_CRYPTO_MD5_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_MD5_MBEDTLS */--/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */--/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */--/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */-/* #undef ARCHIVE_CRYPTO_MD5_WIN */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBMD supported. */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_MBEDTLS */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBMD supported. */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_LIBSYSTEM */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_MBEDTLS */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_WIN */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBMD supported. */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBSYSTEM */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_MBEDTLS */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_WIN */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBSYSTEM */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_MBEDTLS */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_WIN */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBMD supported. */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBSYSTEM */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_MBEDTLS */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_WIN */--/* AIX xattr support */-/* #undef ARCHIVE_XATTR_AIX */--/* Darwin xattr support */-/* #undef ARCHIVE_XATTR_DARWIN */--/* FreeBSD xattr support */-/* #undef ARCHIVE_XATTR_FREEBSD */--/* Linux xattr support */-/* #undef ARCHIVE_XATTR_LINUX */--/* Version number of bsdcat */-#define BSDCAT_VERSION_STRING "3.7.1"--/* Version number of bsdcpio */-#define BSDCPIO_VERSION_STRING "3.7.1"--/* Version number of bsdtar */-#define BSDTAR_VERSION_STRING "3.7.1"--/* Define to 1 if the system has the type `ace_t'. */-/* #undef HAVE_ACE_T */--/* Define to 1 if you have the `acl' function. */-/* #undef HAVE_ACL */--/* Define to 1 if the system has the type `aclent_t'. */-/* #undef HAVE_ACLENT_T */--/* Define to 1 if you have the `acl_add_flag_np' function. */-/* #undef HAVE_ACL_ADD_FLAG_NP */--/* Define to 1 if you have the `acl_add_perm' function. */-/* #undef HAVE_ACL_ADD_PERM */--/* Define to 1 if you have the `acl_clear_flags_np' function. */-/* #undef HAVE_ACL_CLEAR_FLAGS_NP */--/* Define to 1 if you have the `acl_clear_perms' function. */-/* #undef HAVE_ACL_CLEAR_PERMS */--/* Define to 1 if you have the `acl_create_entry' function. */-/* #undef HAVE_ACL_CREATE_ENTRY */--/* Define to 1 if you have the `acl_delete_def_file' function. */-/* #undef HAVE_ACL_DELETE_DEF_FILE */--/* Define to 1 if the system has the type `acl_entry_t'. */-/* #undef HAVE_ACL_ENTRY_T */--/* Define to 1 if you have the `acl_free' function. */-/* #undef HAVE_ACL_FREE */--/* Define to 1 if you have the `acl_get_brand_np' function. */-/* #undef HAVE_ACL_GET_BRAND_NP */--/* Define to 1 if you have the `acl_get_entry' function. */-/* #undef HAVE_ACL_GET_ENTRY */--/* Define to 1 if you have the `acl_get_entry_type_np' function. */-/* #undef HAVE_ACL_GET_ENTRY_TYPE_NP */--/* Define to 1 if you have the `acl_get_fd' function. */-/* #undef HAVE_ACL_GET_FD */--/* Define to 1 if you have the `acl_get_fd_np' function. */-/* #undef HAVE_ACL_GET_FD_NP */--/* Define to 1 if you have the `acl_get_file' function. */-/* #undef HAVE_ACL_GET_FILE */--/* Define to 1 if you have the `acl_get_flagset_np' function. */-/* #undef HAVE_ACL_GET_FLAGSET_NP */--/* Define to 1 if you have the `acl_get_flag_np' function. */-/* #undef HAVE_ACL_GET_FLAG_NP */--/* Define to 1 if you have the `acl_get_link_np' function. */-/* #undef HAVE_ACL_GET_LINK_NP */--/* Define to 1 if you have the `acl_get_perm' function. */-/* #undef HAVE_ACL_GET_PERM */--/* Define to 1 if you have the `acl_get_permset' function. */-/* #undef HAVE_ACL_GET_PERMSET */--/* Define to 1 if you have the `acl_get_perm_np' function. */-/* #undef HAVE_ACL_GET_PERM_NP */--/* Define to 1 if you have the `acl_get_qualifier' function. */-/* #undef HAVE_ACL_GET_QUALIFIER */--/* Define to 1 if you have the `acl_get_tag_type' function. */-/* #undef HAVE_ACL_GET_TAG_TYPE */--/* Define to 1 if you have the `acl_init' function. */-/* #undef HAVE_ACL_INIT */--/* Define to 1 if you have the `acl_is_trivial_np' function. */-/* #undef HAVE_ACL_IS_TRIVIAL_NP */--/* Define to 1 if you have the <acl/libacl.h> header file. */-/* #undef HAVE_ACL_LIBACL_H */--/* Define to 1 if the system has the type `acl_permset_t'. */-/* #undef HAVE_ACL_PERMSET_T */--/* Define to 1 if you have the `acl_set_entry_type_np' function. */-/* #undef HAVE_ACL_SET_ENTRY_TYPE_NP */--/* Define to 1 if you have the `acl_set_fd' function. */-/* #undef HAVE_ACL_SET_FD */--/* Define to 1 if you have the `acl_set_fd_np' function. */-/* #undef HAVE_ACL_SET_FD_NP */--/* Define to 1 if you have the `acl_set_file' function. */-/* #undef HAVE_ACL_SET_FILE */--/* Define to 1 if you have the `acl_set_link_np' function. */-/* #undef HAVE_ACL_SET_LINK_NP */--/* Define to 1 if you have the `acl_set_qualifier' function. */-/* #undef HAVE_ACL_SET_QUALIFIER */--/* Define to 1 if you have the `acl_set_tag_type' function. */-/* #undef HAVE_ACL_SET_TAG_TYPE */--/* Define to 1 if the system has the type `acl_t'. */-/* #undef HAVE_ACL_T */--/* Define to 1 if the system has the type `acl_tag_t'. */-/* #undef HAVE_ACL_TAG_T */--/* Define to 1 if you have the `arc4random_buf' function. */-#define HAVE_ARC4RANDOM_BUF 1--/* Define to 1 if you have the <attr/xattr.h> header file. */-/* #undef HAVE_ATTR_XATTR_H */--/* Define to 1 if you have the <bcrypt.h> header file. */-/* #undef HAVE_BCRYPT_H */--/* Define to 1 if you have the <blake2.h> header file. */-/* #undef HAVE_BLAKE2_H */--/* Define to 1 if you have the <bzlib.h> header file. */-/* #undef HAVE_BZLIB_H */--/* Define to 1 if you have the `chflags' function. */-#define HAVE_CHFLAGS 1--/* Define to 1 if you have the `chown' function. */-#define HAVE_CHOWN 1--/* Define to 1 if you have the `chroot' function. */-#define HAVE_CHROOT 1--/* cmtime_s function */-/* #undef HAVE_CMTIME_S */--/* Define to 1 if you have the <copyfile.h> header file. */-/* #undef HAVE_COPYFILE_H */--/* Define to 1 if you have the `ctime_r' function. */-#define HAVE_CTIME_R 1--/* Define to 1 if you have the <ctype.h> header file. */-#define HAVE_CTYPE_H 1--/* Define to 1 if you have the `cygwin_conv_path' function. */-/* #undef HAVE_CYGWIN_CONV_PATH */--/* Define to 1 if you have the declaration of `ACE_GETACL', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_GETACL */--/* Define to 1 if you have the declaration of `ACE_GETACLCNT', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_GETACLCNT */--/* Define to 1 if you have the declaration of `ACE_SETACL', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_SETACL */--/* Define to 1 if you have the declaration of `ACL_SYNCHRONIZE', and to 0 if- you don't. */-/* #undef HAVE_DECL_ACL_SYNCHRONIZE */--/* Define to 1 if you have the declaration of `ACL_TYPE_EXTENDED', and to 0 if- you don't. */-/* #undef HAVE_DECL_ACL_TYPE_EXTENDED */--/* Define to 1 if you have the declaration of `ACL_TYPE_NFS4', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACL_TYPE_NFS4 */--/* Define to 1 if you have the declaration of `ACL_USER', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACL_USER */--/* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to- 0 if you don't. */-/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */--/* Define to 1 if you have the declaration of `GETACL', and to 0 if you don't.- */-/* #undef HAVE_DECL_GETACL */--/* Define to 1 if you have the declaration of `GETACLCNT', and to 0 if you- don't. */-/* #undef HAVE_DECL_GETACLCNT */--/* Define to 1 if you have the declaration of `INT32_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INT32_MAX 1--/* Define to 1 if you have the declaration of `INT32_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INT32_MIN 1--/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INT64_MAX 1--/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INT64_MIN 1--/* Define to 1 if you have the declaration of `INTMAX_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INTMAX_MAX 1--/* Define to 1 if you have the declaration of `INTMAX_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INTMAX_MIN 1--/* Define to 1 if you have the declaration of `SETACL', and to 0 if you don't.- */-/* #undef HAVE_DECL_SETACL */--/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you- don't. */-#define HAVE_DECL_SIZE_MAX 1--/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you- don't. */-#define HAVE_DECL_SSIZE_MAX 1--/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you- don't. */-#define HAVE_DECL_STRERROR_R 1--/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINT32_MAX 1--/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINT64_MAX 1--/* Define to 1 if you have the declaration of `UINTMAX_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINTMAX_MAX 1--/* Define to 1 if you have the declaration of `XATTR_NOFOLLOW', and to 0 if- you don't. */-/* #undef HAVE_DECL_XATTR_NOFOLLOW */--/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.- */-#define HAVE_DIRENT_H 1--/* Define to 1 if you have a dirfd function or macro */-#define HAVE_DIRFD 1--/* Define to 1 if you have the <dlfcn.h> header file. */-#define HAVE_DLFCN_H 1--/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */-/* #undef HAVE_DOPRNT */--/* Define to 1 if nl_langinfo supports D_MD_ORDER */-#define HAVE_D_MD_ORDER 1--/* A possible errno value for invalid file format errors */-#define HAVE_EFTYPE 1--/* A possible errno value for invalid file format errors */-#define HAVE_EILSEQ 1--/* Define to 1 if you have the <errno.h> header file. */-#define HAVE_ERRNO_H 1--/* Define to 1 if you have the <expat.h> header file. */-/* #undef HAVE_EXPAT_H */--/* Define to 1 if you have the <ext2fs/ext2_fs.h> header file. */-/* #undef HAVE_EXT2FS_EXT2_FS_H */--/* Define to 1 if you have the `extattr_get_fd' function. */-/* #undef HAVE_EXTATTR_GET_FD */--/* Define to 1 if you have the `extattr_get_file' function. */-/* #undef HAVE_EXTATTR_GET_FILE */--/* Define to 1 if you have the `extattr_get_link' function. */-/* #undef HAVE_EXTATTR_GET_LINK */--/* Define to 1 if you have the `extattr_list_fd' function. */-/* #undef HAVE_EXTATTR_LIST_FD */--/* Define to 1 if you have the `extattr_list_file' function. */-/* #undef HAVE_EXTATTR_LIST_FILE */--/* Define to 1 if you have the `extattr_list_link' function. */-/* #undef HAVE_EXTATTR_LIST_LINK */--/* Define to 1 if you have the `extattr_set_fd' function. */-/* #undef HAVE_EXTATTR_SET_FD */--/* Define to 1 if you have the `extattr_set_link' function. */-/* #undef HAVE_EXTATTR_SET_LINK */--/* Define to 1 if you have the `facl' function. */-/* #undef HAVE_FACL */--/* Define to 1 if you have the `fchdir' function. */-#define HAVE_FCHDIR 1--/* Define to 1 if you have the `fchflags' function. */-#define HAVE_FCHFLAGS 1--/* Define to 1 if you have the `fchmod' function. */-#define HAVE_FCHMOD 1--/* Define to 1 if you have the `fchown' function. */-#define HAVE_FCHOWN 1--/* Define to 1 if you have the `fcntl' function. */-#define HAVE_FCNTL 1--/* Define to 1 if you have the <fcntl.h> header file. */-#define HAVE_FCNTL_H 1--/* Define to 1 if you have the `fdopendir' function. */-#define HAVE_FDOPENDIR 1--/* Define to 1 if you have the `fgetea' function. */-/* #undef HAVE_FGETEA */--/* Define to 1 if you have the `fgetxattr' function. */-/* #undef HAVE_FGETXATTR */--/* Define to 1 if you have the `flistea' function. */-/* #undef HAVE_FLISTEA */--/* Define to 1 if you have the `flistxattr' function. */-/* #undef HAVE_FLISTXATTR */--/* Define to 1 if you have the `fnmatch' function. */-#define HAVE_FNMATCH 1--/* Define to 1 if you have the <fnmatch.h> header file. */-#define HAVE_FNMATCH_H 1--/* Define to 1 if you have the `fork' function. */-#define HAVE_FORK 1--/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */-#define HAVE_FSEEKO 1--/* Define to 1 if you have the `fsetea' function. */-/* #undef HAVE_FSETEA */--/* Define to 1 if you have the `fsetxattr' function. */-/* #undef HAVE_FSETXATTR */--/* Define to 1 if you have the `fstat' function. */-#define HAVE_FSTAT 1--/* Define to 1 if you have the `fstatat' function. */-#define HAVE_FSTATAT 1--/* Define to 1 if you have the `fstatfs' function. */-#define HAVE_FSTATFS 1--/* Define to 1 if you have the `fstatvfs' function. */-#define HAVE_FSTATVFS 1--/* Define to 1 if you have the `ftruncate' function. */-#define HAVE_FTRUNCATE 1--/* Define to 1 if you have the `futimens' function. */-#define HAVE_FUTIMENS 1--/* Define to 1 if you have the `futimes' function. */-#define HAVE_FUTIMES 1--/* Define to 1 if you have the `futimesat' function. */-#define HAVE_FUTIMESAT 1--/* Define to 1 if you have the `getea' function. */-/* #undef HAVE_GETEA */--/* Define to 1 if you have the `geteuid' function. */-#define HAVE_GETEUID 1--/* Define to 1 if you have the `getgrgid_r' function. */-#define HAVE_GETGRGID_R 1--/* Define to 1 if you have the `getgrnam_r' function. */-#define HAVE_GETGRNAM_R 1--/* Define to 1 if you have the `getline' function. */-#define HAVE_GETLINE 1--/* Platform uses optreset to reset getopt */-#define HAVE_GETOPT_OPTRESET 1--/* Define to 1 if you have the `getpid' function. */-#define HAVE_GETPID 1--/* Define to 1 if you have the `getpwnam_r' function. */-#define HAVE_GETPWNAM_R 1--/* Define to 1 if you have the `getpwuid_r' function. */-#define HAVE_GETPWUID_R 1--/* Define to 1 if you have the `getvfsbyname' function. */-#define HAVE_GETVFSBYNAME 1--/* Define to 1 if you have the `getxattr' function. */-/* #undef HAVE_GETXATTR */--/* Define to 1 if you have the `gmtime_r' function. */-#define HAVE_GMTIME_R 1--/* gmtime_s function */-/* #undef HAVE_GMTIME_S */--/* Define to 1 if you have the <grp.h> header file. */-#define HAVE_GRP_H 1--/* Define if you have the iconv() function and it works. */-/* #undef HAVE_ICONV */--/* Define to 1 if you have the <iconv.h> header file. */-/* #undef HAVE_ICONV_H */--/* Define to 1 if the system has the type `intmax_t'. */-#define HAVE_INTMAX_T 1--/* Define to 1 if you have the <inttypes.h> header file. */-#define HAVE_INTTYPES_H 1--/* Define to 1 if you have the <io.h> header file. */-/* #undef HAVE_IO_H */--/* Define to 1 if you have the <langinfo.h> header file. */-#define HAVE_LANGINFO_H 1--/* Define to 1 if you have the `lchflags' function. */-#define HAVE_LCHFLAGS 1--/* Define to 1 if you have the `lchmod' function. */-#define HAVE_LCHMOD 1--/* Define to 1 if you have the `lchown' function. */-#define HAVE_LCHOWN 1--/* Define to 1 if you have the `lgetea' function. */-/* #undef HAVE_LGETEA */--/* Define to 1 if you have the `lgetxattr' function. */-/* #undef HAVE_LGETXATTR */--/* Define to 1 if you have the `acl' library (-lacl). */-/* #undef HAVE_LIBACL */--/* Define to 1 if you have the `b2' library (-lb2). */-/* #undef HAVE_LIBB2 */--/* Define to 1 if you have the `bz2' library (-lbz2). */-/* #undef HAVE_LIBBZ2 */--/* Define to 1 if you have the `charset' library (-lcharset). */-/* #undef HAVE_LIBCHARSET */--/* Define to 1 if you have the `crypto' library (-lcrypto). */-/* #undef HAVE_LIBCRYPTO */--/* Define to 1 if you have the `expat' library (-lexpat). */-/* #undef HAVE_LIBEXPAT */--/* Define to 1 if you have the `lz4' library (-llz4). */-/* #undef HAVE_LIBLZ4 */--/* Define to 1 if you have the `lzma' library (-llzma). */-/* #undef HAVE_LIBLZMA */--/* Define to 1 if you have the `lzo2' library (-llzo2). */-/* #undef HAVE_LIBLZO2 */--/* Define to 1 if you have the `mbedcrypto' library (-lmbedcrypto). */-/* #undef HAVE_LIBMBEDCRYPTO */--/* Define to 1 if you have the `md' library (-lmd). */--/* Define to 1 if you have the `nettle' library (-lnettle). */-/* #undef HAVE_LIBNETTLE */--/* Define to 1 if you have the `pcre' library (-lpcre). */-/* #undef HAVE_LIBPCRE */--/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */-/* #undef HAVE_LIBPCREPOSIX */--/* Define to 1 if you have the `regex' library (-lregex). */-/* #undef HAVE_LIBREGEX */--/* Define to 1 if you have the `richacl' library (-lrichacl). */-/* #undef HAVE_LIBRICHACL */--/* Define to 1 if you have the `xml2' library (-lxml2). */-/* #undef HAVE_LIBXML2 */--/* Define to 1 if you have the <libxml/xmlreader.h> header file. */-/* #undef HAVE_LIBXML_XMLREADER_H */--/* Define to 1 if you have the <libxml/xmlwriter.h> header file. */-/* #undef HAVE_LIBXML_XMLWRITER_H */--/* Define to 1 if you have the `z' library (-lz). */-/* #undef HAVE_LIBZ */--/* Define to 1 if you have the `zstd' library (-lzstd). */-/* #undef HAVE_LIBZSTD */--/* Define to 1 if you have the `zstd' library (-lzstd) with compression- support. */-/* #undef HAVE_LIBZSTD_COMPRESSOR */--/* Define to 1 if you have the <limits.h> header file. */-#define HAVE_LIMITS_H 1--/* Define to 1 if you have the `link' function. */-#define HAVE_LINK 1--/* Define to 1 if you have the `linkat' function. */-#define HAVE_LINKAT 1--/* Define to 1 if you have the <linux/fiemap.h> header file. */-/* #undef HAVE_LINUX_FIEMAP_H */--/* Define to 1 if you have the <linux/fs.h> header file. */-/* #undef HAVE_LINUX_FS_H */--/* Define to 1 if you have the <linux/magic.h> header file. */-/* #undef HAVE_LINUX_MAGIC_H */--/* Define to 1 if you have the <linux/types.h> header file. */-/* #undef HAVE_LINUX_TYPES_H */--/* Define to 1 if you have the `listea' function. */-/* #undef HAVE_LISTEA */--/* Define to 1 if you have the `listxattr' function. */-/* #undef HAVE_LISTXATTR */--/* Define to 1 if you have the `llistea' function. */-/* #undef HAVE_LLISTEA */--/* Define to 1 if you have the `llistxattr' function. */-/* #undef HAVE_LLISTXATTR */--/* Define to 1 if you have the <localcharset.h> header file. */-/* #undef HAVE_LOCALCHARSET_H */--/* Define to 1 if you have the `locale_charset' function. */-/* #undef HAVE_LOCALE_CHARSET */--/* Define to 1 if you have the <locale.h> header file. */-#define HAVE_LOCALE_H 1--/* Define to 1 if you have the `localtime_r' function. */-#define HAVE_LOCALTIME_R 1--/* localtime_s function */-/* #undef HAVE_LOCALTIME_S */--/* Define to 1 if the system has the type `long long int'. */-#define HAVE_LONG_LONG_INT 1--/* Define to 1 if you have the `lsetea' function. */-/* #undef HAVE_LSETEA */--/* Define to 1 if you have the `lsetxattr' function. */-/* #undef HAVE_LSETXATTR */--/* Define to 1 if you have the `lstat' function. */-#define HAVE_LSTAT 1--/* Define to 1 if `lstat' has the bug that it succeeds when given the- zero-length file name argument. */-/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */--/* Define to 1 if you have the `lutimes' function. */-#define HAVE_LUTIMES 1--/* Define to 1 if you have the <lz4hc.h> header file. */-/* #undef HAVE_LZ4HC_H */--/* Define to 1 if you have the <lz4.h> header file. */-/* #undef HAVE_LZ4_H */--/* Define to 1 if you have the `LZMA_FILTER_ARM64' macro. */-/* #undef HAVE_LZMA_FILTER_ARM64 */--/* Define to 1 if you have the <lzma.h> header file. */-/* #undef HAVE_LZMA_H */--/* Define to 1 if you have the `lzma_stream_encoder_mt' function. */-/* #undef HAVE_LZMA_STREAM_ENCODER_MT */--/* Define to 1 if you have the <lzo/lzo1x.h> header file. */-/* #undef HAVE_LZO_LZO1X_H */--/* Define to 1 if you have the <lzo/lzoconf.h> header file. */-/* #undef HAVE_LZO_LZOCONF_H */--/* Define to 1 if you have the <mbedtls/aes.h> header file. */-/* #undef HAVE_MBEDTLS_AES_H */--/* Define to 1 if you have the <mbedtls/md.h> header file. */-/* #undef HAVE_MBEDTLS_MD_H */--/* Define to 1 if you have the <mbedtls/pkcs5.h> header file. */-/* #undef HAVE_MBEDTLS_PKCS5_H */--/* Define to 1 if you have the `mbrtowc' function. */-#define HAVE_MBRTOWC 1--/* Define to 1 if you have the `mbr_gid_to_uuid' function. */-/* #undef HAVE_MBR_GID_TO_UUID */--/* Define to 1 if you have the `mbr_uid_to_uuid' function. */-/* #undef HAVE_MBR_UID_TO_UUID */--/* Define to 1 if you have the `mbr_uuid_to_id' function. */-/* #undef HAVE_MBR_UUID_TO_ID */--/* Define to 1 if you have the <md5.h> header file. */--/* Define to 1 if you have the <membership.h> header file. */-/* #undef HAVE_MEMBERSHIP_H */--/* Define to 1 if you have the `memmove' function. */-#define HAVE_MEMMOVE 1--/* Define to 1 if you have the `memset' function. */-#define HAVE_MEMSET 1--/* Define to 1 if you have the <minix/config.h> header file. */-/* #undef HAVE_MINIX_CONFIG_H */--/* Define to 1 if you have the `mkdir' function. */-#define HAVE_MKDIR 1--/* Define to 1 if you have the `mkfifo' function. */-#define HAVE_MKFIFO 1--/* Define to 1 if you have the `mknod' function. */-#define HAVE_MKNOD 1--/* Define to 1 if you have the `mkstemp' function. */-#define HAVE_MKSTEMP 1--/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */-/* #undef HAVE_NDIR_H */--/* Define to 1 if you have the <nettle/aes.h> header file. */-/* #undef HAVE_NETTLE_AES_H */--/* Define to 1 if you have the <nettle/hmac.h> header file. */-/* #undef HAVE_NETTLE_HMAC_H */--/* Define to 1 if you have the <nettle/md5.h> header file. */-/* #undef HAVE_NETTLE_MD5_H */--/* Define to 1 if you have the <nettle/pbkdf2.h> header file. */-/* #undef HAVE_NETTLE_PBKDF2_H */--/* Define to 1 if you have the <nettle/ripemd160.h> header file. */-/* #undef HAVE_NETTLE_RIPEMD160_H */--/* Define to 1 if you have the <nettle/sha.h> header file. */-/* #undef HAVE_NETTLE_SHA_H */--/* Define to 1 if you have the `nl_langinfo' function. */-#define HAVE_NL_LANGINFO 1--/* Define to 1 if you have the `openat' function. */-#define HAVE_OPENAT 1--/* Define to 1 if you have the <openssl/evp.h> header file. */-/* #undef HAVE_OPENSSL_EVP_H */--/* Define to 1 if you have the <paths.h> header file. */-#define HAVE_PATHS_H 1--/* Define to 1 if you have the <pcreposix.h> header file. */-/* #undef HAVE_PCREPOSIX_H */--/* Define to 1 if you have the `pipe' function. */-#define HAVE_PIPE 1--/* Define to 1 if you have the `PKCS5_PBKDF2_HMAC_SHA1' function. */-/* #undef HAVE_PKCS5_PBKDF2_HMAC_SHA1 */--/* Define to 1 if you have the `poll' function. */-#define HAVE_POLL 1--/* Define to 1 if you have the <poll.h> header file. */-#define HAVE_POLL_H 1--/* Define to 1 if you have the `posix_spawnp' function. */-#define HAVE_POSIX_SPAWNP 1--/* Define to 1 if you have the <pthread.h> header file. */-#define HAVE_PTHREAD_H 1--/* Define to 1 if you have the <pwd.h> header file. */-#define HAVE_PWD_H 1--/* Define to 1 if you have a POSIX compatible readdir_r */-#define HAVE_READDIR_R 1--/* Define to 1 if you have the `readlink' function. */-#define HAVE_READLINK 1--/* Define to 1 if you have the `readlinkat' function. */-#define HAVE_READLINKAT 1--/* Define to 1 if you have the `readpassphrase' function. */-#define HAVE_READPASSPHRASE 1--/* Define to 1 if you have the <readpassphrase.h> header file. */-#define HAVE_READPASSPHRASE_H 1--/* Define to 1 if you have the <regex.h> header file. */-/* #undef HAVE_REGEX_H */--/* Define to 1 if you have the `richacl_alloc' function. */-/* #undef HAVE_RICHACL_ALLOC */--/* Define to 1 if you have the `richacl_equiv_mode' function. */-/* #undef HAVE_RICHACL_EQUIV_MODE */--/* Define to 1 if you have the `richacl_free' function. */-/* #undef HAVE_RICHACL_FREE */--/* Define to 1 if you have the `richacl_get_fd' function. */-/* #undef HAVE_RICHACL_GET_FD */--/* Define to 1 if you have the `richacl_get_file' function. */-/* #undef HAVE_RICHACL_GET_FILE */--/* Define to 1 if you have the `richacl_set_fd' function. */-/* #undef HAVE_RICHACL_SET_FD */--/* Define to 1 if you have the `richacl_set_file' function. */-/* #undef HAVE_RICHACL_SET_FILE */--/* Define to 1 if you have the <ripemd.h> header file. */--/* Define to 1 if you have the `select' function. */-#define HAVE_SELECT 1--/* Define to 1 if you have the `setenv' function. */-#define HAVE_SETENV 1--/* Define to 1 if you have the `setlocale' function. */-#define HAVE_SETLOCALE 1--/* Define to 1 if you have the `setxattr' function. */-/* #undef HAVE_SETXATTR */--/* Define to 1 if you have the <sha256.h> header file. */--/* Define to 1 if you have the <sha512.h> header file. */--/* Define to 1 if you have the <sha.h> header file. */--/* Define to 1 if you have the `sigaction' function. */-#define HAVE_SIGACTION 1--/* Define to 1 if you have the <signal.h> header file. */-#define HAVE_SIGNAL_H 1--/* Define to 1 if you have the <spawn.h> header file. */-#define HAVE_SPAWN_H 1--/* Define to 1 if you have the `statfs' function. */-#define HAVE_STATFS 1--/* Define to 1 if you have the `statvfs' function. */-#define HAVE_STATVFS 1--/* Define to 1 if `stat' has the bug that it succeeds when given the- zero-length file name argument. */-/* #undef HAVE_STAT_EMPTY_STRING_BUG */--/* Define to 1 if you have the <stdarg.h> header file. */-#define HAVE_STDARG_H 1--/* Define to 1 if you have the <stdint.h> header file. */-#define HAVE_STDINT_H 1--/* Define to 1 if you have the <stdio.h> header file. */-#define HAVE_STDIO_H 1--/* Define to 1 if you have the <stdlib.h> header file. */-#define HAVE_STDLIB_H 1--/* Define to 1 if you have the `strchr' function. */-#define HAVE_STRCHR 1--/* Define to 1 if you have the `strdup' function. */-#define HAVE_STRDUP 1--/* Define to 1 if you have the `strerror' function. */-#define HAVE_STRERROR 1--/* Define if you have `strerror_r'. */-#define HAVE_STRERROR_R 1--/* Define to 1 if you have the `strftime' function. */-#define HAVE_STRFTIME 1--/* Define to 1 if you have the <strings.h> header file. */-#define HAVE_STRINGS_H 1--/* Define to 1 if you have the <string.h> header file. */-#define HAVE_STRING_H 1--/* Define to 1 if you have the `strncpy_s' function. */-/* #undef HAVE_STRNCPY_S */--/* Define to 1 if you have the `strnlen' function. */-#define HAVE_STRNLEN 1--/* Define to 1 if you have the `strrchr' function. */-#define HAVE_STRRCHR 1--/* Define to 1 if the system has the type `struct richace'. */-/* #undef HAVE_STRUCT_RICHACE */--/* Define to 1 if the system has the type `struct richacl'. */-/* #undef HAVE_STRUCT_RICHACL */--/* Define to 1 if the system has the type `struct statfs'. */-#define HAVE_STRUCT_STATFS 1--/* Define to 1 if `f_iosize' is a member of `struct statfs'. */-#define HAVE_STRUCT_STATFS_F_IOSIZE 1--/* Define to 1 if `f_namemax' is a member of `struct statfs'. */-#define HAVE_STRUCT_STATFS_F_NAMEMAX 1--/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */-/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */--/* Define to 1 if `st_birthtime' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1--/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1--/* Define to 1 if `st_blksize' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_BLKSIZE 1--/* Define to 1 if `st_flags' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_FLAGS 1--/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1--/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */--/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */--/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1--/* Define to 1 if `st_umtime' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_UMTIME */--/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */-#define HAVE_STRUCT_TM_TM_GMTOFF 1--/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */-/* #undef HAVE_STRUCT_TM___TM_GMTOFF */--/* Define to 1 if the system has the type `struct vfsconf'. */-#define HAVE_STRUCT_VFSCONF 1--/* Define to 1 if the system has the type `struct xvfsconf'. */-#define HAVE_STRUCT_XVFSCONF 1--/* Define to 1 if you have the `symlink' function. */-#define HAVE_SYMLINK 1--/* Define to 1 if you have the <sys/acl.h> header file. */--/* Define to 1 if you have the <sys/cdefs.h> header file. */-#define HAVE_SYS_CDEFS_H 1--/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.- */-/* #undef HAVE_SYS_DIR_H */--/* Define to 1 if you have the <sys/ea.h> header file. */-/* #undef HAVE_SYS_EA_H */--/* Define to 1 if you have the <sys/extattr.h> header file. */-#define HAVE_SYS_EXTATTR_H 1--/* Define to 1 if you have the <sys/ioctl.h> header file. */-#define HAVE_SYS_IOCTL_H 1--/* Define to 1 if you have the <sys/mkdev.h> header file. */-/* #undef HAVE_SYS_MKDEV_H */--/* Define to 1 if you have the <sys/mount.h> header file. */-#define HAVE_SYS_MOUNT_H 1--/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.- */-/* #undef HAVE_SYS_NDIR_H */--/* Define to 1 if you have the <sys/param.h> header file. */-#define HAVE_SYS_PARAM_H 1--/* Define to 1 if you have the <sys/poll.h> header file. */-#define HAVE_SYS_POLL_H 1--/* Define to 1 if you have the <sys/queue.h> header file. */-#define HAVE_SYS_QUEUE_H 1--/* Define to 1 if you have the <sys/richacl.h> header file. */-/* #undef HAVE_SYS_RICHACL_H */--/* Define to 1 if you have the <sys/select.h> header file. */-#define HAVE_SYS_SELECT_H 1--/* Define to 1 if you have the <sys/statfs.h> header file. */-/* #undef HAVE_SYS_STATFS_H */--/* Define to 1 if you have the <sys/statvfs.h> header file. */-#define HAVE_SYS_STATVFS_H 1--/* Define to 1 if you have the <sys/stat.h> header file. */-#define HAVE_SYS_STAT_H 1--/* Define to 1 if you have the <sys/sysmacros.h> header file. */-/* #undef HAVE_SYS_SYSMACROS_H */--/* Define to 1 if you have the <sys/time.h> header file. */-#define HAVE_SYS_TIME_H 1--/* Define to 1 if you have the <sys/types.h> header file. */-#define HAVE_SYS_TYPES_H 1--/* Define to 1 if you have the <sys/utime.h> header file. */-/* #undef HAVE_SYS_UTIME_H */--/* Define to 1 if you have the <sys/utsname.h> header file. */-#define HAVE_SYS_UTSNAME_H 1--/* Define to 1 if you have the <sys/vfs.h> header file. */-/* #undef HAVE_SYS_VFS_H */--/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */-#define HAVE_SYS_WAIT_H 1--/* Define to 1 if you have the <sys/xattr.h> header file. */-/* #undef HAVE_SYS_XATTR_H */--/* Define to 1 if you have the `timegm' function. */-#define HAVE_TIMEGM 1--/* Define to 1 if you have the <time.h> header file. */-#define HAVE_TIME_H 1--/* Define to 1 if you have the `tzset' function. */-#define HAVE_TZSET 1--/* Define to 1 if the system has the type `uintmax_t'. */-#define HAVE_UINTMAX_T 1--/* Define to 1 if you have the <unistd.h> header file. */-#define HAVE_UNISTD_H 1--/* Define to 1 if you have the `unlinkat' function. */-#define HAVE_UNLINKAT 1--/* Define to 1 if you have the `unsetenv' function. */-#define HAVE_UNSETENV 1--/* Define to 1 if the system has the type `unsigned long long'. */-#define HAVE_UNSIGNED_LONG_LONG 1--/* Define to 1 if the system has the type `unsigned long long int'. */-#define HAVE_UNSIGNED_LONG_LONG_INT 1--/* Define to 1 if you have the `utime' function. */-#define HAVE_UTIME 1--/* Define to 1 if you have the `utimensat' function. */-#define HAVE_UTIMENSAT 1--/* Define to 1 if you have the `utimes' function. */-#define HAVE_UTIMES 1--/* Define to 1 if you have the <utime.h> header file. */-#define HAVE_UTIME_H 1--/* Define to 1 if you have the `vfork' function. */-#define HAVE_VFORK 1--/* Define to 1 if you have the `vprintf' function. */-#define HAVE_VPRINTF 1--/* Define to 1 if you have the <wchar.h> header file. */-#define HAVE_WCHAR_H 1--/* Define to 1 if the system has the type `wchar_t'. */-#define HAVE_WCHAR_T 1--/* Define to 1 if you have the `wcrtomb' function. */-#define HAVE_WCRTOMB 1--/* Define to 1 if you have the `wcscmp' function. */-#define HAVE_WCSCMP 1--/* Define to 1 if you have the `wcscpy' function. */-#define HAVE_WCSCPY 1--/* Define to 1 if you have the `wcslen' function. */-#define HAVE_WCSLEN 1--/* Define to 1 if you have the `wctomb' function. */-#define HAVE_WCTOMB 1--/* Define to 1 if you have the <wctype.h> header file. */-#define HAVE_WCTYPE_H 1--/* Define to 1 if you have the <wincrypt.h> header file. */-/* #undef HAVE_WINCRYPT_H */--/* Define to 1 if you have the <windows.h> header file. */-/* #undef HAVE_WINDOWS_H */--/* Define to 1 if you have the <winioctl.h> header file. */-/* #undef HAVE_WINIOCTL_H */--/* Define to 1 if you have the `wmemcmp' function. */-#define HAVE_WMEMCMP 1--/* Define to 1 if you have the `wmemcpy' function. */-#define HAVE_WMEMCPY 1--/* Define to 1 if you have the `wmemmove' function. */-#define HAVE_WMEMMOVE 1--/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */-/* #undef HAVE_WORKING_EXT2_IOC_GETFLAGS */--/* Define to 1 if you have a working FS_IOC_GETFLAGS */-/* #undef HAVE_WORKING_FS_IOC_GETFLAGS */--/* Define to 1 if you have the <zlib.h> header file. */-/* #undef HAVE_ZLIB_H */--/* Define to 1 if you have the <zstd.h> header file. */-/* #undef HAVE_ZSTD_H */--/* Define to 1 if you have the `_fseeki64' function. */-/* #undef HAVE__FSEEKI64 */--/* Define to 1 if you have the `_get_timezone' function. */-/* #undef HAVE__GET_TIMEZONE */--/* _mkgmtime function */-/* #undef HAVE__MKGMTIME */--/* Define as const if the declaration of iconv() needs const. */-/* #undef ICONV_CONST */--/* Version number of libarchive as a single integer */-#define LIBARCHIVE_VERSION_NUMBER "3007001"--/* Version number of libarchive */-#define LIBARCHIVE_VERSION_STRING "3.7.1"--/* Define to 1 if `lstat' dereferences a symlink specified with a trailing- slash. */-#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1--/* Define to the sub-directory where libtool stores uninstalled libraries. */-#define LT_OBJDIR ".libs/"--/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.- */-/* #undef MAJOR_IN_MKDEV */--/* Define to 1 if `major', `minor', and `makedev' are declared in- <sysmacros.h>. */-/* #undef MAJOR_IN_SYSMACROS */--/* Define to '0x05020000' for Windows Server 2003 APIs. */-/* #undef NTDDI_VERSION */--/* Name of package */-#define PACKAGE "libarchive"--/* Define to the address where bug reports for this package should be sent. */-#define PACKAGE_BUGREPORT "libarchive-discuss@googlegroups.com"--/* Define to the full name of this package. */-#define PACKAGE_NAME "libarchive"--/* Define to the full name and version of this package. */-#define PACKAGE_STRING "libarchive 3.7.1"--/* Define to the one symbol short name of this package. */-#define PACKAGE_TARNAME "libarchive"--/* Define to the home page for this package. */-#define PACKAGE_URL ""--/* Define to the version of this package. */-#define PACKAGE_VERSION "3.7.1"--/* Define to 1 if PCRE_STATIC needs to be defined. */-/* #undef PCRE_STATIC */--/* The number of bytes in type int */-#define SIZEOF_INT 4--/* The number of bytes in type long */-#define SIZEOF_LONG 8--/* The size of `wchar_t', as computed by sizeof. */-#define SIZEOF_WCHAR_T 4--/* Define to 1 if all of the C90 standard headers exist (not just the ones- required in a freestanding environment). This macro is provided for- backward compatibility; new code need not use it. */-#define STDC_HEADERS 1--/* Define to 1 if strerror_r returns char *. */-/* #undef STRERROR_R_CHAR_P */--/* Enable extensions on AIX 3, Interix. */-#ifndef _ALL_SOURCE-# define _ALL_SOURCE 1-#endif-/* Enable general extensions on macOS. */-#ifndef _DARWIN_C_SOURCE-# define _DARWIN_C_SOURCE 1-#endif-/* Enable general extensions on Solaris. */-#ifndef __EXTENSIONS__-# define __EXTENSIONS__ 1-#endif-/* Enable GNU extensions on systems that have them. */-#ifndef _GNU_SOURCE-# define _GNU_SOURCE 1-#endif-/* Enable X/Open compliant socket functions that do not require linking- with -lxnet on HP-UX 11.11. */-#ifndef _HPUX_ALT_XOPEN_SOCKET_API-# define _HPUX_ALT_XOPEN_SOCKET_API 1-#endif-/* Identify the host operating system as Minix.- This macro does not affect the system headers' behavior.- A future release of Autoconf may stop defining this macro. */-#ifndef _MINIX-/* # undef _MINIX */-#endif-/* Enable general extensions on NetBSD.- Enable NetBSD compatibility extensions on Minix. */-#ifndef _NETBSD_SOURCE-# define _NETBSD_SOURCE 1-#endif-/* Enable OpenBSD compatibility extensions on NetBSD.- Oddly enough, this does nothing on OpenBSD. */-#ifndef _OPENBSD_SOURCE-# define _OPENBSD_SOURCE 1-#endif-/* Define to 1 if needed for POSIX-compatible behavior. */-#ifndef _POSIX_SOURCE-/* # undef _POSIX_SOURCE */-#endif-/* Define to 2 if needed for POSIX-compatible behavior. */-#ifndef _POSIX_1_SOURCE-/* # undef _POSIX_1_SOURCE */-#endif-/* Enable POSIX-compatible threading on Solaris. */-#ifndef _POSIX_PTHREAD_SEMANTICS-# define _POSIX_PTHREAD_SEMANTICS 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */-#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__-# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */-#ifndef __STDC_WANT_IEC_60559_BFP_EXT__-# define __STDC_WANT_IEC_60559_BFP_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */-#ifndef __STDC_WANT_IEC_60559_DFP_EXT__-# define __STDC_WANT_IEC_60559_DFP_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */-#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__-# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */-#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__-# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */-#ifndef __STDC_WANT_LIB_EXT2__-# define __STDC_WANT_LIB_EXT2__ 1-#endif-/* Enable extensions specified by ISO/IEC 24747:2009. */-#ifndef __STDC_WANT_MATH_SPEC_FUNCS__-# define __STDC_WANT_MATH_SPEC_FUNCS__ 1-#endif-/* Enable extensions on HP NonStop. */-#ifndef _TANDEM_SOURCE-# define _TANDEM_SOURCE 1-#endif-/* Enable X/Open extensions. Define to 500 only if necessary- to make mbstate_t available. */-#ifndef _XOPEN_SOURCE-/* # undef _XOPEN_SOURCE */-#endif---/* Version number of package */-#define VERSION "3.7.1"--/* Define to '0x0502' for Windows Server 2003 APIs. */-/* #undef WINVER */--/* Number of bits in a file offset, on hosts where this is settable. */-/* #undef _FILE_OFFSET_BITS */--/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */-/* #undef _LARGEFILE_SOURCE */--/* Define for large files, on AIX-style hosts. */-/* #undef _LARGE_FILES */--/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT32_T */--/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT64_T */--/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT8_T */--/* Define to '0x0502' for Windows Server 2003 APIs. */-/* #undef _WIN32_WINNT */--/* Internal macro for sanity checks */-#define __LIBARCHIVE_CONFIG_H_INCLUDED 1--/* Define to empty if `const' does not conform to ANSI C. */-/* #undef const */--/* Define to match typeof st_gid field of struct stat if <sys/types.h> doesn't- define. */-/* #undef gid_t */--/* Define to `unsigned long' if <sys/types.h> does not define. */-/* #undef id_t */--/* Define to the type of a signed integer type of width exactly 16 bits if- such a type exists and the standard includes do not define it. */-/* #undef int16_t */--/* Define to the type of a signed integer type of width exactly 32 bits if- such a type exists and the standard includes do not define it. */-/* #undef int32_t */--/* Define to the type of a signed integer type of width exactly 64 bits if- such a type exists and the standard includes do not define it. */-/* #undef int64_t */--/* Define to the widest signed integer type if <stdint.h> and <inttypes.h> do- not define. */-/* #undef intmax_t */--/* Define to `int' if <sys/types.h> does not define. */-/* #undef mode_t */--/* Define to `long long' if <sys/types.h> does not define. */-/* #undef off_t */--/* Define to `unsigned int' if <sys/types.h> does not define. */-/* #undef size_t */--/* Define to match typeof st_uid field of struct stat if <sys/types.h> doesn't- define. */-/* #undef uid_t */--/* Define to the type of an unsigned integer type of width exactly 16 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint16_t */--/* Define to the type of an unsigned integer type of width exactly 32 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint32_t */--/* Define to the type of an unsigned integer type of width exactly 64 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint64_t */--/* Define to the type of an unsigned integer type of width exactly 8 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint8_t */--/* Define to the widest unsigned integer type if <stdint.h> and <inttypes.h>- do not define. */-/* #undef uintmax_t */--/* Define to `unsigned int' if <sys/types.h> does not define. */-/* #undef uintptr_t */-#define HAVE_LIBZ 1-#define HAVE_ZLIB_H 1
− c/autoconf-linux/config.h
@@ -1,1520 +0,0 @@-/* config.h. Generated from config.h.in by configure. */-/* config.h.in. Generated from configure.ac by autoheader. */--/* Darwin ACL support */-/* #undef ARCHIVE_ACL_DARWIN */--/* FreeBSD ACL support */-/* #undef ARCHIVE_ACL_FREEBSD */--/* FreeBSD NFSv4 ACL support */-/* #undef ARCHIVE_ACL_FREEBSD_NFS4 */--/* Linux POSIX.1e ACL support via libacl */-/* #undef ARCHIVE_ACL_LIBACL */--/* Linux NFSv4 ACL support via librichacl */-/* #undef ARCHIVE_ACL_LIBRICHACL */--/* Solaris ACL support */-/* #undef ARCHIVE_ACL_SUNOS */--/* Solaris NFSv4 ACL support */-/* #undef ARCHIVE_ACL_SUNOS_NFS4 */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_MD5_LIBC */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_MD5_LIBMD */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_MD5_LIBSYSTEM */--/* MD5 via ARCHIVE_CRYPTO_MD5_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_MD5_MBEDTLS */--/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */--/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */--/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */-/* #undef ARCHIVE_CRYPTO_MD5_WIN */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_LIBMD */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_MBEDTLS */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_LIBMD */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_LIBSYSTEM */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_MBEDTLS */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_WIN */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBMD */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBSYSTEM */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_MBEDTLS */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_WIN */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBSYSTEM */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_MBEDTLS */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_WIN */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBMD */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBSYSTEM */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_MBEDTLS */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_WIN */--/* AIX xattr support */-/* #undef ARCHIVE_XATTR_AIX */--/* Darwin xattr support */-/* #undef ARCHIVE_XATTR_DARWIN */--/* FreeBSD xattr support */-/* #undef ARCHIVE_XATTR_FREEBSD */--/* Linux xattr support */-/* #undef ARCHIVE_XATTR_LINUX */--/* Version number of bsdcat */-#define BSDCAT_VERSION_STRING "3.7.1"--/* Version number of bsdcpio */-#define BSDCPIO_VERSION_STRING "3.7.1"--/* Version number of bsdtar */-#define BSDTAR_VERSION_STRING "3.7.1"--/* Define to 1 if the system has the type `ace_t'. */-/* #undef HAVE_ACE_T */--/* Define to 1 if you have the `acl' function. */-/* #undef HAVE_ACL */--/* Define to 1 if the system has the type `aclent_t'. */-/* #undef HAVE_ACLENT_T */--/* Define to 1 if you have the `acl_add_flag_np' function. */-/* #undef HAVE_ACL_ADD_FLAG_NP */--/* Define to 1 if you have the `acl_add_perm' function. */-/* #undef HAVE_ACL_ADD_PERM */--/* Define to 1 if you have the `acl_clear_flags_np' function. */-/* #undef HAVE_ACL_CLEAR_FLAGS_NP */--/* Define to 1 if you have the `acl_clear_perms' function. */-/* #undef HAVE_ACL_CLEAR_PERMS */--/* Define to 1 if you have the `acl_create_entry' function. */-/* #undef HAVE_ACL_CREATE_ENTRY */--/* Define to 1 if you have the `acl_delete_def_file' function. */-/* #undef HAVE_ACL_DELETE_DEF_FILE */--/* Define to 1 if the system has the type `acl_entry_t'. */-/* #undef HAVE_ACL_ENTRY_T */--/* Define to 1 if you have the `acl_free' function. */-/* #undef HAVE_ACL_FREE */--/* Define to 1 if you have the `acl_get_brand_np' function. */-/* #undef HAVE_ACL_GET_BRAND_NP */--/* Define to 1 if you have the `acl_get_entry' function. */-/* #undef HAVE_ACL_GET_ENTRY */--/* Define to 1 if you have the `acl_get_entry_type_np' function. */-/* #undef HAVE_ACL_GET_ENTRY_TYPE_NP */--/* Define to 1 if you have the `acl_get_fd' function. */-/* #undef HAVE_ACL_GET_FD */--/* Define to 1 if you have the `acl_get_fd_np' function. */-/* #undef HAVE_ACL_GET_FD_NP */--/* Define to 1 if you have the `acl_get_file' function. */-/* #undef HAVE_ACL_GET_FILE */--/* Define to 1 if you have the `acl_get_flagset_np' function. */-/* #undef HAVE_ACL_GET_FLAGSET_NP */--/* Define to 1 if you have the `acl_get_flag_np' function. */-/* #undef HAVE_ACL_GET_FLAG_NP */--/* Define to 1 if you have the `acl_get_link_np' function. */-/* #undef HAVE_ACL_GET_LINK_NP */--/* Define to 1 if you have the `acl_get_perm' function. */-/* #undef HAVE_ACL_GET_PERM */--/* Define to 1 if you have the `acl_get_permset' function. */-/* #undef HAVE_ACL_GET_PERMSET */--/* Define to 1 if you have the `acl_get_perm_np' function. */-/* #undef HAVE_ACL_GET_PERM_NP */--/* Define to 1 if you have the `acl_get_qualifier' function. */-/* #undef HAVE_ACL_GET_QUALIFIER */--/* Define to 1 if you have the `acl_get_tag_type' function. */-/* #undef HAVE_ACL_GET_TAG_TYPE */--/* Define to 1 if you have the `acl_init' function. */-/* #undef HAVE_ACL_INIT */--/* Define to 1 if you have the `acl_is_trivial_np' function. */-/* #undef HAVE_ACL_IS_TRIVIAL_NP */--/* Define to 1 if you have the <acl/libacl.h> header file. */-/* #undef HAVE_ACL_LIBACL_H */--/* Define to 1 if the system has the type `acl_permset_t'. */-/* #undef HAVE_ACL_PERMSET_T */--/* Define to 1 if you have the `acl_set_entry_type_np' function. */-/* #undef HAVE_ACL_SET_ENTRY_TYPE_NP */--/* Define to 1 if you have the `acl_set_fd' function. */-/* #undef HAVE_ACL_SET_FD */--/* Define to 1 if you have the `acl_set_fd_np' function. */-/* #undef HAVE_ACL_SET_FD_NP */--/* Define to 1 if you have the `acl_set_file' function. */-/* #undef HAVE_ACL_SET_FILE */--/* Define to 1 if you have the `acl_set_link_np' function. */-/* #undef HAVE_ACL_SET_LINK_NP */--/* Define to 1 if you have the `acl_set_qualifier' function. */-/* #undef HAVE_ACL_SET_QUALIFIER */--/* Define to 1 if you have the `acl_set_tag_type' function. */-/* #undef HAVE_ACL_SET_TAG_TYPE */--/* Define to 1 if the system has the type `acl_t'. */-/* #undef HAVE_ACL_T */--/* Define to 1 if the system has the type `acl_tag_t'. */-/* #undef HAVE_ACL_TAG_T */--/* Define to 1 if you have the `arc4random_buf' function. */-/* #undef HAVE_ARC4RANDOM_BUF */--/* Define to 1 if you have the <attr/xattr.h> header file. */-/* #undef HAVE_ATTR_XATTR_H */--/* Define to 1 if you have the <bcrypt.h> header file. */-/* #undef HAVE_BCRYPT_H */--/* Define to 1 if you have the <blake2.h> header file. */-/* #undef HAVE_BLAKE2_H */--/* Define to 1 if you have the <bzlib.h> header file. */-/* #undef HAVE_BZLIB_H */--/* Define to 1 if you have the `chflags' function. */-/* #undef HAVE_CHFLAGS */--/* Define to 1 if you have the `chown' function. */-#define HAVE_CHOWN 1--/* Define to 1 if you have the `chroot' function. */-#define HAVE_CHROOT 1--/* cmtime_s function */-/* #undef HAVE_CMTIME_S */--/* Define to 1 if you have the <copyfile.h> header file. */-/* #undef HAVE_COPYFILE_H */--/* Define to 1 if you have the `ctime_r' function. */-#define HAVE_CTIME_R 1--/* Define to 1 if you have the <ctype.h> header file. */-#define HAVE_CTYPE_H 1--/* Define to 1 if you have the `cygwin_conv_path' function. */-/* #undef HAVE_CYGWIN_CONV_PATH */--/* Define to 1 if you have the declaration of `ACE_GETACL', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_GETACL */--/* Define to 1 if you have the declaration of `ACE_GETACLCNT', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_GETACLCNT */--/* Define to 1 if you have the declaration of `ACE_SETACL', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_SETACL */--/* Define to 1 if you have the declaration of `ACL_SYNCHRONIZE', and to 0 if- you don't. */-/* #undef HAVE_DECL_ACL_SYNCHRONIZE */--/* Define to 1 if you have the declaration of `ACL_TYPE_EXTENDED', and to 0 if- you don't. */-/* #undef HAVE_DECL_ACL_TYPE_EXTENDED */--/* Define to 1 if you have the declaration of `ACL_TYPE_NFS4', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACL_TYPE_NFS4 */--/* Define to 1 if you have the declaration of `ACL_USER', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACL_USER */--/* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to- 0 if you don't. */-/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */--/* Define to 1 if you have the declaration of `GETACL', and to 0 if you don't.- */-/* #undef HAVE_DECL_GETACL */--/* Define to 1 if you have the declaration of `GETACLCNT', and to 0 if you- don't. */-/* #undef HAVE_DECL_GETACLCNT */--/* Define to 1 if you have the declaration of `INT32_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INT32_MAX 1--/* Define to 1 if you have the declaration of `INT32_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INT32_MIN 1--/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INT64_MAX 1--/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INT64_MIN 1--/* Define to 1 if you have the declaration of `INTMAX_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INTMAX_MAX 1--/* Define to 1 if you have the declaration of `INTMAX_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INTMAX_MIN 1--/* Define to 1 if you have the declaration of `SETACL', and to 0 if you don't.- */-/* #undef HAVE_DECL_SETACL */--/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you- don't. */-#define HAVE_DECL_SIZE_MAX 1--/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you- don't. */-#define HAVE_DECL_SSIZE_MAX 1--/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you- don't. */-#define HAVE_DECL_STRERROR_R 1--/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINT32_MAX 1--/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINT64_MAX 1--/* Define to 1 if you have the declaration of `UINTMAX_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINTMAX_MAX 1--/* Define to 1 if you have the declaration of `XATTR_NOFOLLOW', and to 0 if- you don't. */-/* #undef HAVE_DECL_XATTR_NOFOLLOW */--/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.- */-#define HAVE_DIRENT_H 1--/* Define to 1 if you have a dirfd function or macro */-#define HAVE_DIRFD 1--/* Define to 1 if you have the <dlfcn.h> header file. */-#define HAVE_DLFCN_H 1--/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */-/* #undef HAVE_DOPRNT */--/* Define to 1 if nl_langinfo supports D_MD_ORDER */-/* #undef HAVE_D_MD_ORDER */--/* A possible errno value for invalid file format errors */-/* #undef HAVE_EFTYPE */--/* A possible errno value for invalid file format errors */-#define HAVE_EILSEQ 1--/* Define to 1 if you have the <errno.h> header file. */-#define HAVE_ERRNO_H 1--/* Define to 1 if you have the <expat.h> header file. */-/* #undef HAVE_EXPAT_H */--/* Define to 1 if you have the <ext2fs/ext2_fs.h> header file. */--/* Define to 1 if you have the `extattr_get_fd' function. */-/* #undef HAVE_EXTATTR_GET_FD */--/* Define to 1 if you have the `extattr_get_file' function. */-/* #undef HAVE_EXTATTR_GET_FILE */--/* Define to 1 if you have the `extattr_get_link' function. */-/* #undef HAVE_EXTATTR_GET_LINK */--/* Define to 1 if you have the `extattr_list_fd' function. */-/* #undef HAVE_EXTATTR_LIST_FD */--/* Define to 1 if you have the `extattr_list_file' function. */-/* #undef HAVE_EXTATTR_LIST_FILE */--/* Define to 1 if you have the `extattr_list_link' function. */-/* #undef HAVE_EXTATTR_LIST_LINK */--/* Define to 1 if you have the `extattr_set_fd' function. */-/* #undef HAVE_EXTATTR_SET_FD */--/* Define to 1 if you have the `extattr_set_link' function. */-/* #undef HAVE_EXTATTR_SET_LINK */--/* Define to 1 if you have the `facl' function. */-/* #undef HAVE_FACL */--/* Define to 1 if you have the `fchdir' function. */-#define HAVE_FCHDIR 1--/* Define to 1 if you have the `fchflags' function. */-/* #undef HAVE_FCHFLAGS */--/* Define to 1 if you have the `fchmod' function. */-#define HAVE_FCHMOD 1--/* Define to 1 if you have the `fchown' function. */-#define HAVE_FCHOWN 1--/* Define to 1 if you have the `fcntl' function. */-#define HAVE_FCNTL 1--/* Define to 1 if you have the <fcntl.h> header file. */-#define HAVE_FCNTL_H 1--/* Define to 1 if you have the `fdopendir' function. */-#define HAVE_FDOPENDIR 1--/* Define to 1 if you have the `fgetea' function. */-/* #undef HAVE_FGETEA */--/* Define to 1 if you have the `fgetxattr' function. */-/* #undef HAVE_FGETXATTR */--/* Define to 1 if you have the `flistea' function. */-/* #undef HAVE_FLISTEA */--/* Define to 1 if you have the `flistxattr' function. */-/* #undef HAVE_FLISTXATTR */--/* Define to 1 if you have the `fnmatch' function. */-#define HAVE_FNMATCH 1--/* Define to 1 if you have the <fnmatch.h> header file. */-#define HAVE_FNMATCH_H 1--/* Define to 1 if you have the `fork' function. */-#define HAVE_FORK 1--/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */-#define HAVE_FSEEKO 1--/* Define to 1 if you have the `fsetea' function. */-/* #undef HAVE_FSETEA */--/* Define to 1 if you have the `fsetxattr' function. */-/* #undef HAVE_FSETXATTR */--/* Define to 1 if you have the `fstat' function. */-#define HAVE_FSTAT 1--/* Define to 1 if you have the `fstatat' function. */-#define HAVE_FSTATAT 1--/* Define to 1 if you have the `fstatfs' function. */-#define HAVE_FSTATFS 1--/* Define to 1 if you have the `fstatvfs' function. */-#define HAVE_FSTATVFS 1--/* Define to 1 if you have the `ftruncate' function. */-#define HAVE_FTRUNCATE 1--/* Define to 1 if you have the `futimens' function. */-#define HAVE_FUTIMENS 1--/* Define to 1 if you have the `futimes' function. */-#define HAVE_FUTIMES 1--/* Define to 1 if you have the `futimesat' function. */-#define HAVE_FUTIMESAT 1--/* Define to 1 if you have the `getea' function. */-/* #undef HAVE_GETEA */--/* Define to 1 if you have the `geteuid' function. */-#define HAVE_GETEUID 1--/* Define to 1 if you have the `getgrgid_r' function. */-#define HAVE_GETGRGID_R 1--/* Define to 1 if you have the `getgrnam_r' function. */-#define HAVE_GETGRNAM_R 1--/* Define to 1 if you have the `getline' function. */-#define HAVE_GETLINE 1--/* Platform uses optreset to reset getopt */-/* #undef HAVE_GETOPT_OPTRESET */--/* Define to 1 if you have the `getpid' function. */-#define HAVE_GETPID 1--/* Define to 1 if you have the `getpwnam_r' function. */-#define HAVE_GETPWNAM_R 1--/* Define to 1 if you have the `getpwuid_r' function. */-#define HAVE_GETPWUID_R 1--/* Define to 1 if you have the `getvfsbyname' function. */-/* #undef HAVE_GETVFSBYNAME */--/* Define to 1 if you have the `getxattr' function. */-/* #undef HAVE_GETXATTR */--/* Define to 1 if you have the `gmtime_r' function. */-#define HAVE_GMTIME_R 1--/* gmtime_s function */-/* #undef HAVE_GMTIME_S */--/* Define to 1 if you have the <grp.h> header file. */-#define HAVE_GRP_H 1--/* Define if you have the iconv() function and it works. */-/* #undef HAVE_ICONV */--/* Define to 1 if you have the <iconv.h> header file. */-/* #undef HAVE_ICONV_H */--/* Define to 1 if the system has the type `intmax_t'. */-#define HAVE_INTMAX_T 1--/* Define to 1 if you have the <inttypes.h> header file. */-#define HAVE_INTTYPES_H 1--/* Define to 1 if you have the <io.h> header file. */-/* #undef HAVE_IO_H */--/* Define to 1 if you have the <langinfo.h> header file. */-#define HAVE_LANGINFO_H 1--/* Define to 1 if you have the `lchflags' function. */-/* #undef HAVE_LCHFLAGS */--/* Define to 1 if you have the `lchmod' function. */-#define HAVE_LCHMOD 1--/* Define to 1 if you have the `lchown' function. */-#define HAVE_LCHOWN 1--/* Define to 1 if you have the `lgetea' function. */-/* #undef HAVE_LGETEA */--/* Define to 1 if you have the `lgetxattr' function. */-/* #undef HAVE_LGETXATTR */--/* Define to 1 if you have the `acl' library (-lacl). */-/* #undef HAVE_LIBACL */--/* Define to 1 if you have the `b2' library (-lb2). */-/* #undef HAVE_LIBB2 */--/* Define to 1 if you have the `bz2' library (-lbz2). */-/* #undef HAVE_LIBBZ2 */--/* Define to 1 if you have the `charset' library (-lcharset). */-/* #undef HAVE_LIBCHARSET */--/* Define to 1 if you have the `crypto' library (-lcrypto). */-/* #undef HAVE_LIBCRYPTO */--/* Define to 1 if you have the `expat' library (-lexpat). */-/* #undef HAVE_LIBEXPAT */--/* Define to 1 if you have the `lz4' library (-llz4). */-/* #undef HAVE_LIBLZ4 */--/* Define to 1 if you have the `lzma' library (-llzma). */-/* #undef HAVE_LIBLZMA */--/* Define to 1 if you have the `lzo2' library (-llzo2). */-/* #undef HAVE_LIBLZO2 */--/* Define to 1 if you have the `mbedcrypto' library (-lmbedcrypto). */-/* #undef HAVE_LIBMBEDCRYPTO */--/* Define to 1 if you have the `md' library (-lmd). */-/* #undef HAVE_LIBMD */--/* Define to 1 if you have the `nettle' library (-lnettle). */-/* #undef HAVE_LIBNETTLE */--/* Define to 1 if you have the `pcre' library (-lpcre). */-/* #undef HAVE_LIBPCRE */--/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */-/* #undef HAVE_LIBPCREPOSIX */--/* Define to 1 if you have the `regex' library (-lregex). */-/* #undef HAVE_LIBREGEX */--/* Define to 1 if you have the `richacl' library (-lrichacl). */-/* #undef HAVE_LIBRICHACL */--/* Define to 1 if you have the `xml2' library (-lxml2). */-/* #undef HAVE_LIBXML2 */--/* Define to 1 if you have the <libxml/xmlreader.h> header file. */-/* #undef HAVE_LIBXML_XMLREADER_H */--/* Define to 1 if you have the <libxml/xmlwriter.h> header file. */-/* #undef HAVE_LIBXML_XMLWRITER_H */--/* Define to 1 if you have the `z' library (-lz). */-/* #undef HAVE_LIBZ */--/* Define to 1 if you have the `zstd' library (-lzstd). */-/* #undef HAVE_LIBZSTD */--/* Define to 1 if you have the `zstd' library (-lzstd) with compression- support. */-/* #undef HAVE_LIBZSTD_COMPRESSOR */--/* Define to 1 if you have the <limits.h> header file. */-#define HAVE_LIMITS_H 1--/* Define to 1 if you have the `link' function. */-#define HAVE_LINK 1--/* Define to 1 if you have the `linkat' function. */-#define HAVE_LINKAT 1--/* Define to 1 if you have the <linux/fiemap.h> header file. */-#define HAVE_LINUX_FIEMAP_H 1--/* Define to 1 if you have the <linux/fs.h> header file. */-#define HAVE_LINUX_FS_H 1--/* Define to 1 if you have the <linux/magic.h> header file. */-#define HAVE_LINUX_MAGIC_H 1--/* Define to 1 if you have the <linux/types.h> header file. */-#define HAVE_LINUX_TYPES_H 1--/* Define to 1 if you have the `listea' function. */-/* #undef HAVE_LISTEA */--/* Define to 1 if you have the `listxattr' function. */-/* #undef HAVE_LISTXATTR */--/* Define to 1 if you have the `llistea' function. */-/* #undef HAVE_LLISTEA */--/* Define to 1 if you have the `llistxattr' function. */-/* #undef HAVE_LLISTXATTR */--/* Define to 1 if you have the <localcharset.h> header file. */-/* #undef HAVE_LOCALCHARSET_H */--/* Define to 1 if you have the `locale_charset' function. */-/* #undef HAVE_LOCALE_CHARSET */--/* Define to 1 if you have the <locale.h> header file. */-#define HAVE_LOCALE_H 1--/* Define to 1 if you have the `localtime_r' function. */-#define HAVE_LOCALTIME_R 1--/* localtime_s function */-/* #undef HAVE_LOCALTIME_S */--/* Define to 1 if the system has the type `long long int'. */-#define HAVE_LONG_LONG_INT 1--/* Define to 1 if you have the `lsetea' function. */-/* #undef HAVE_LSETEA */--/* Define to 1 if you have the `lsetxattr' function. */-/* #undef HAVE_LSETXATTR */--/* Define to 1 if you have the `lstat' function. */-#define HAVE_LSTAT 1--/* Define to 1 if `lstat' has the bug that it succeeds when given the- zero-length file name argument. */-/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */--/* Define to 1 if you have the `lutimes' function. */-#define HAVE_LUTIMES 1--/* Define to 1 if you have the <lz4hc.h> header file. */-/* #undef HAVE_LZ4HC_H */--/* Define to 1 if you have the <lz4.h> header file. */-/* #undef HAVE_LZ4_H */--/* Define to 1 if you have the `LZMA_FILTER_ARM64' macro. */-/* #undef HAVE_LZMA_FILTER_ARM64 */--/* Define to 1 if you have the <lzma.h> header file. */-/* #undef HAVE_LZMA_H */--/* Define to 1 if you have the `lzma_stream_encoder_mt' function. */-/* #undef HAVE_LZMA_STREAM_ENCODER_MT */--/* Define to 1 if you have the <lzo/lzo1x.h> header file. */-/* #undef HAVE_LZO_LZO1X_H */--/* Define to 1 if you have the <lzo/lzoconf.h> header file. */-/* #undef HAVE_LZO_LZOCONF_H */--/* Define to 1 if you have the <mbedtls/aes.h> header file. */-/* #undef HAVE_MBEDTLS_AES_H */--/* Define to 1 if you have the <mbedtls/md.h> header file. */-/* #undef HAVE_MBEDTLS_MD_H */--/* Define to 1 if you have the <mbedtls/pkcs5.h> header file. */-/* #undef HAVE_MBEDTLS_PKCS5_H */--/* Define to 1 if you have the `mbrtowc' function. */-#define HAVE_MBRTOWC 1--/* Define to 1 if you have the `mbr_gid_to_uuid' function. */-/* #undef HAVE_MBR_GID_TO_UUID */--/* Define to 1 if you have the `mbr_uid_to_uuid' function. */-/* #undef HAVE_MBR_UID_TO_UUID */--/* Define to 1 if you have the `mbr_uuid_to_id' function. */-/* #undef HAVE_MBR_UUID_TO_ID */--/* Define to 1 if you have the <md5.h> header file. */-/* #undef HAVE_MD5_H */--/* Define to 1 if you have the <membership.h> header file. */-/* #undef HAVE_MEMBERSHIP_H */--/* Define to 1 if you have the `memmove' function. */-#define HAVE_MEMMOVE 1--/* Define to 1 if you have the `memset' function. */-#define HAVE_MEMSET 1--/* Define to 1 if you have the <minix/config.h> header file. */-/* #undef HAVE_MINIX_CONFIG_H */--/* Define to 1 if you have the `mkdir' function. */-#define HAVE_MKDIR 1--/* Define to 1 if you have the `mkfifo' function. */-#define HAVE_MKFIFO 1--/* Define to 1 if you have the `mknod' function. */-#define HAVE_MKNOD 1--/* Define to 1 if you have the `mkstemp' function. */-#define HAVE_MKSTEMP 1--/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */-/* #undef HAVE_NDIR_H */--/* Define to 1 if you have the <nettle/aes.h> header file. */-/* #undef HAVE_NETTLE_AES_H */--/* Define to 1 if you have the <nettle/hmac.h> header file. */-/* #undef HAVE_NETTLE_HMAC_H */--/* Define to 1 if you have the <nettle/md5.h> header file. */-/* #undef HAVE_NETTLE_MD5_H */--/* Define to 1 if you have the <nettle/pbkdf2.h> header file. */-/* #undef HAVE_NETTLE_PBKDF2_H */--/* Define to 1 if you have the <nettle/ripemd160.h> header file. */-/* #undef HAVE_NETTLE_RIPEMD160_H */--/* Define to 1 if you have the <nettle/sha.h> header file. */-/* #undef HAVE_NETTLE_SHA_H */--/* Define to 1 if you have the `nl_langinfo' function. */-#define HAVE_NL_LANGINFO 1--/* Define to 1 if you have the `openat' function. */-#define HAVE_OPENAT 1--/* Define to 1 if you have the <openssl/evp.h> header file. */-/* #undef HAVE_OPENSSL_EVP_H */--/* Define to 1 if you have the <paths.h> header file. */-#define HAVE_PATHS_H 1--/* Define to 1 if you have the <pcreposix.h> header file. */-/* #undef HAVE_PCREPOSIX_H */--/* Define to 1 if you have the `pipe' function. */-#define HAVE_PIPE 1--/* Define to 1 if you have the `PKCS5_PBKDF2_HMAC_SHA1' function. */-/* #undef HAVE_PKCS5_PBKDF2_HMAC_SHA1 */--/* Define to 1 if you have the `poll' function. */-#define HAVE_POLL 1--/* Define to 1 if you have the <poll.h> header file. */-#define HAVE_POLL_H 1--/* Define to 1 if you have the `posix_spawnp' function. */-#define HAVE_POSIX_SPAWNP 1--/* Define to 1 if you have the <pthread.h> header file. */-#define HAVE_PTHREAD_H 1--/* Define to 1 if you have the <pwd.h> header file. */-#define HAVE_PWD_H 1--/* Define to 1 if you have a POSIX compatible readdir_r */-#define HAVE_READDIR_R 1--/* Define to 1 if you have the `readlink' function. */-#define HAVE_READLINK 1--/* Define to 1 if you have the `readlinkat' function. */-#define HAVE_READLINKAT 1--/* Define to 1 if you have the `readpassphrase' function. */-/* #undef HAVE_READPASSPHRASE */--/* Define to 1 if you have the <readpassphrase.h> header file. */-/* #undef HAVE_READPASSPHRASE_H */--/* Define to 1 if you have the <regex.h> header file. */-/* #undef HAVE_REGEX_H */--/* Define to 1 if you have the `richacl_alloc' function. */-/* #undef HAVE_RICHACL_ALLOC */--/* Define to 1 if you have the `richacl_equiv_mode' function. */-/* #undef HAVE_RICHACL_EQUIV_MODE */--/* Define to 1 if you have the `richacl_free' function. */-/* #undef HAVE_RICHACL_FREE */--/* Define to 1 if you have the `richacl_get_fd' function. */-/* #undef HAVE_RICHACL_GET_FD */--/* Define to 1 if you have the `richacl_get_file' function. */-/* #undef HAVE_RICHACL_GET_FILE */--/* Define to 1 if you have the `richacl_set_fd' function. */-/* #undef HAVE_RICHACL_SET_FD */--/* Define to 1 if you have the `richacl_set_file' function. */-/* #undef HAVE_RICHACL_SET_FILE */--/* Define to 1 if you have the <ripemd.h> header file. */-/* #undef HAVE_RIPEMD_H */--/* Define to 1 if you have the `select' function. */-#define HAVE_SELECT 1--/* Define to 1 if you have the `setenv' function. */-#define HAVE_SETENV 1--/* Define to 1 if you have the `setlocale' function. */-#define HAVE_SETLOCALE 1--/* Define to 1 if you have the `setxattr' function. */-/* #undef HAVE_SETXATTR */--/* Define to 1 if you have the <sha256.h> header file. */-/* #undef HAVE_SHA256_H */--/* Define to 1 if you have the <sha512.h> header file. */-/* #undef HAVE_SHA512_H */--/* Define to 1 if you have the <sha.h> header file. */-/* #undef HAVE_SHA_H */--/* Define to 1 if you have the `sigaction' function. */-#define HAVE_SIGACTION 1--/* Define to 1 if you have the <signal.h> header file. */-#define HAVE_SIGNAL_H 1--/* Define to 1 if you have the <spawn.h> header file. */-#define HAVE_SPAWN_H 1--/* Define to 1 if you have the `statfs' function. */-#define HAVE_STATFS 1--/* Define to 1 if you have the `statvfs' function. */-#define HAVE_STATVFS 1--/* Define to 1 if `stat' has the bug that it succeeds when given the- zero-length file name argument. */-/* #undef HAVE_STAT_EMPTY_STRING_BUG */--/* Define to 1 if you have the <stdarg.h> header file. */-#define HAVE_STDARG_H 1--/* Define to 1 if you have the <stdint.h> header file. */-#define HAVE_STDINT_H 1--/* Define to 1 if you have the <stdio.h> header file. */-#define HAVE_STDIO_H 1--/* Define to 1 if you have the <stdlib.h> header file. */-#define HAVE_STDLIB_H 1--/* Define to 1 if you have the `strchr' function. */-#define HAVE_STRCHR 1--/* Define to 1 if you have the `strdup' function. */-#define HAVE_STRDUP 1--/* Define to 1 if you have the `strerror' function. */-#define HAVE_STRERROR 1--/* Define if you have `strerror_r'. */-#define HAVE_STRERROR_R 1--/* Define to 1 if you have the `strftime' function. */-#define HAVE_STRFTIME 1--/* Define to 1 if you have the <strings.h> header file. */-#define HAVE_STRINGS_H 1--/* Define to 1 if you have the <string.h> header file. */-#define HAVE_STRING_H 1--/* Define to 1 if you have the `strncpy_s' function. */-/* #undef HAVE_STRNCPY_S */--/* Define to 1 if you have the `strnlen' function. */-#define HAVE_STRNLEN 1--/* Define to 1 if you have the `strrchr' function. */-#define HAVE_STRRCHR 1--/* Define to 1 if the system has the type `struct richace'. */-/* #undef HAVE_STRUCT_RICHACE */--/* Define to 1 if the system has the type `struct richacl'. */-/* #undef HAVE_STRUCT_RICHACL */--/* Define to 1 if the system has the type `struct statfs'. */-/* #undef HAVE_STRUCT_STATFS */--/* Define to 1 if `f_iosize' is a member of `struct statfs'. */-/* #undef HAVE_STRUCT_STATFS_F_IOSIZE */--/* Define to 1 if `f_namemax' is a member of `struct statfs'. */-/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */--/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */-/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */--/* Define to 1 if `st_birthtime' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIME */--/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC */--/* Define to 1 if `st_blksize' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_BLKSIZE 1--/* Define to 1 if `st_flags' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_FLAGS */--/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC */--/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */--/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */--/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */-#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1--/* Define to 1 if `st_umtime' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_UMTIME */--/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */-#define HAVE_STRUCT_TM_TM_GMTOFF 1--/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */-/* #undef HAVE_STRUCT_TM___TM_GMTOFF */--/* Define to 1 if the system has the type `struct vfsconf'. */-/* #undef HAVE_STRUCT_VFSCONF */--/* Define to 1 if the system has the type `struct xvfsconf'. */-/* #undef HAVE_STRUCT_XVFSCONF */--/* Define to 1 if you have the `symlink' function. */-#define HAVE_SYMLINK 1--/* Define to 1 if you have the <sys/acl.h> header file. */-/* #undef HAVE_SYS_ACL_H */--/* Define to 1 if you have the <sys/cdefs.h> header file. */-#define HAVE_SYS_CDEFS_H 1--/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.- */-/* #undef HAVE_SYS_DIR_H */--/* Define to 1 if you have the <sys/ea.h> header file. */-/* #undef HAVE_SYS_EA_H */--/* Define to 1 if you have the <sys/extattr.h> header file. */-/* #undef HAVE_SYS_EXTATTR_H */--/* Define to 1 if you have the <sys/ioctl.h> header file. */-#define HAVE_SYS_IOCTL_H 1--/* Define to 1 if you have the <sys/mkdev.h> header file. */-/* #undef HAVE_SYS_MKDEV_H */--/* Define to 1 if you have the <sys/mount.h> header file. */-#define HAVE_SYS_MOUNT_H 1--/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.- */-/* #undef HAVE_SYS_NDIR_H */--/* Define to 1 if you have the <sys/param.h> header file. */-#define HAVE_SYS_PARAM_H 1--/* Define to 1 if you have the <sys/poll.h> header file. */-#define HAVE_SYS_POLL_H 1--/* Define to 1 if you have the <sys/queue.h> header file. */-#define HAVE_SYS_QUEUE_H 1--/* Define to 1 if you have the <sys/richacl.h> header file. */-/* #undef HAVE_SYS_RICHACL_H */--/* Define to 1 if you have the <sys/select.h> header file. */-#define HAVE_SYS_SELECT_H 1--/* Define to 1 if you have the <sys/statfs.h> header file. */-#define HAVE_SYS_STATFS_H 1--/* Define to 1 if you have the <sys/statvfs.h> header file. */-#define HAVE_SYS_STATVFS_H 1--/* Define to 1 if you have the <sys/stat.h> header file. */-#define HAVE_SYS_STAT_H 1--/* Define to 1 if you have the <sys/sysmacros.h> header file. */-#define HAVE_SYS_SYSMACROS_H 1--/* Define to 1 if you have the <sys/time.h> header file. */-#define HAVE_SYS_TIME_H 1--/* Define to 1 if you have the <sys/types.h> header file. */-#define HAVE_SYS_TYPES_H 1--/* Define to 1 if you have the <sys/utime.h> header file. */-/* #undef HAVE_SYS_UTIME_H */--/* Define to 1 if you have the <sys/utsname.h> header file. */-#define HAVE_SYS_UTSNAME_H 1--/* Define to 1 if you have the <sys/vfs.h> header file. */-#define HAVE_SYS_VFS_H 1--/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */-#define HAVE_SYS_WAIT_H 1--/* Define to 1 if you have the <sys/xattr.h> header file. */-#define HAVE_SYS_XATTR_H 1--/* Define to 1 if you have the `timegm' function. */-#define HAVE_TIMEGM 1--/* Define to 1 if you have the <time.h> header file. */-#define HAVE_TIME_H 1--/* Define to 1 if you have the `tzset' function. */-#define HAVE_TZSET 1--/* Define to 1 if the system has the type `uintmax_t'. */-#define HAVE_UINTMAX_T 1--/* Define to 1 if you have the <unistd.h> header file. */-#define HAVE_UNISTD_H 1--/* Define to 1 if you have the `unlinkat' function. */-#define HAVE_UNLINKAT 1--/* Define to 1 if you have the `unsetenv' function. */-#define HAVE_UNSETENV 1--/* Define to 1 if the system has the type `unsigned long long'. */-#define HAVE_UNSIGNED_LONG_LONG 1--/* Define to 1 if the system has the type `unsigned long long int'. */-#define HAVE_UNSIGNED_LONG_LONG_INT 1--/* Define to 1 if you have the `utime' function. */-#define HAVE_UTIME 1--/* Define to 1 if you have the `utimensat' function. */-#define HAVE_UTIMENSAT 1--/* Define to 1 if you have the `utimes' function. */-#define HAVE_UTIMES 1--/* Define to 1 if you have the <utime.h> header file. */-#define HAVE_UTIME_H 1--/* Define to 1 if you have the `vfork' function. */-#define HAVE_VFORK 1--/* Define to 1 if you have the `vprintf' function. */-#define HAVE_VPRINTF 1--/* Define to 1 if you have the <wchar.h> header file. */-#define HAVE_WCHAR_H 1--/* Define to 1 if the system has the type `wchar_t'. */-#define HAVE_WCHAR_T 1--/* Define to 1 if you have the `wcrtomb' function. */-#define HAVE_WCRTOMB 1--/* Define to 1 if you have the `wcscmp' function. */-#define HAVE_WCSCMP 1--/* Define to 1 if you have the `wcscpy' function. */-#define HAVE_WCSCPY 1--/* Define to 1 if you have the `wcslen' function. */-#define HAVE_WCSLEN 1--/* Define to 1 if you have the `wctomb' function. */-#define HAVE_WCTOMB 1--/* Define to 1 if you have the <wctype.h> header file. */-#define HAVE_WCTYPE_H 1--/* Define to 1 if you have the <wincrypt.h> header file. */-/* #undef HAVE_WINCRYPT_H */--/* Define to 1 if you have the <windows.h> header file. */-/* #undef HAVE_WINDOWS_H */--/* Define to 1 if you have the <winioctl.h> header file. */-/* #undef HAVE_WINIOCTL_H */--/* Define to 1 if you have the `wmemcmp' function. */-#define HAVE_WMEMCMP 1--/* Define to 1 if you have the `wmemcpy' function. */-#define HAVE_WMEMCPY 1--/* Define to 1 if you have the `wmemmove' function. */-#define HAVE_WMEMMOVE 1--/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */-#define HAVE_WORKING_EXT2_IOC_GETFLAGS 1--/* Define to 1 if you have a working FS_IOC_GETFLAGS */-#define HAVE_WORKING_FS_IOC_GETFLAGS 1--/* Define to 1 if you have the <zlib.h> header file. */-/* #undef HAVE_ZLIB_H */--/* Define to 1 if you have the <zstd.h> header file. */-/* #undef HAVE_ZSTD_H */--/* Define to 1 if you have the `_fseeki64' function. */-/* #undef HAVE__FSEEKI64 */--/* Define to 1 if you have the `_get_timezone' function. */-/* #undef HAVE__GET_TIMEZONE */--/* _mkgmtime function */-/* #undef HAVE__MKGMTIME */--/* Define as const if the declaration of iconv() needs const. */-/* #undef ICONV_CONST */--/* Version number of libarchive as a single integer */-#define LIBARCHIVE_VERSION_NUMBER "3007001"--/* Version number of libarchive */-#define LIBARCHIVE_VERSION_STRING "3.7.1"--/* Define to 1 if `lstat' dereferences a symlink specified with a trailing- slash. */-#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1--/* Define to the sub-directory where libtool stores uninstalled libraries. */-#define LT_OBJDIR ".libs/"--/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.- */-/* #undef MAJOR_IN_MKDEV */--/* Define to 1 if `major', `minor', and `makedev' are declared in- <sysmacros.h>. */-#define MAJOR_IN_SYSMACROS 1--/* Define to '0x05020000' for Windows Server 2003 APIs. */-/* #undef NTDDI_VERSION */--/* Name of package */-#define PACKAGE "libarchive"--/* Define to the address where bug reports for this package should be sent. */-#define PACKAGE_BUGREPORT "libarchive-discuss@googlegroups.com"--/* Define to the full name of this package. */-#define PACKAGE_NAME "libarchive"--/* Define to the full name and version of this package. */-#define PACKAGE_STRING "libarchive 3.7.1"--/* Define to the one symbol short name of this package. */-#define PACKAGE_TARNAME "libarchive"--/* Define to the home page for this package. */-#define PACKAGE_URL ""--/* Define to the version of this package. */-#define PACKAGE_VERSION "3.7.1"--/* Define to 1 if PCRE_STATIC needs to be defined. */-/* #undef PCRE_STATIC */--/* The number of bytes in type int */-#define SIZEOF_INT 4--/* The number of bytes in type long */-#define SIZEOF_LONG 8--/* The size of `wchar_t', as computed by sizeof. */-#define SIZEOF_WCHAR_T 4--/* Define to 1 if all of the C90 standard headers exist (not just the ones- required in a freestanding environment). This macro is provided for- backward compatibility; new code need not use it. */-#define STDC_HEADERS 1--/* Define to 1 if strerror_r returns char *. */-#define STRERROR_R_CHAR_P 1--/* Enable extensions on AIX 3, Interix. */-#ifndef _ALL_SOURCE-# define _ALL_SOURCE 1-#endif-/* Enable general extensions on macOS. */-#ifndef _DARWIN_C_SOURCE-# define _DARWIN_C_SOURCE 1-#endif-/* Enable general extensions on Solaris. */-#ifndef __EXTENSIONS__-# define __EXTENSIONS__ 1-#endif-/* Enable GNU extensions on systems that have them. */-#ifndef _GNU_SOURCE-# define _GNU_SOURCE 1-#endif-/* Enable X/Open compliant socket functions that do not require linking- with -lxnet on HP-UX 11.11. */-#ifndef _HPUX_ALT_XOPEN_SOCKET_API-# define _HPUX_ALT_XOPEN_SOCKET_API 1-#endif-/* Identify the host operating system as Minix.- This macro does not affect the system headers' behavior.- A future release of Autoconf may stop defining this macro. */-#ifndef _MINIX-/* # undef _MINIX */-#endif-/* Enable general extensions on NetBSD.- Enable NetBSD compatibility extensions on Minix. */-#ifndef _NETBSD_SOURCE-# define _NETBSD_SOURCE 1-#endif-/* Enable OpenBSD compatibility extensions on NetBSD.- Oddly enough, this does nothing on OpenBSD. */-#ifndef _OPENBSD_SOURCE-# define _OPENBSD_SOURCE 1-#endif-/* Define to 1 if needed for POSIX-compatible behavior. */-#ifndef _POSIX_SOURCE-/* # undef _POSIX_SOURCE */-#endif-/* Define to 2 if needed for POSIX-compatible behavior. */-#ifndef _POSIX_1_SOURCE-/* # undef _POSIX_1_SOURCE */-#endif-/* Enable POSIX-compatible threading on Solaris. */-#ifndef _POSIX_PTHREAD_SEMANTICS-# define _POSIX_PTHREAD_SEMANTICS 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */-#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__-# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */-#ifndef __STDC_WANT_IEC_60559_BFP_EXT__-# define __STDC_WANT_IEC_60559_BFP_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */-#ifndef __STDC_WANT_IEC_60559_DFP_EXT__-# define __STDC_WANT_IEC_60559_DFP_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */-#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__-# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */-#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__-# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */-#ifndef __STDC_WANT_LIB_EXT2__-# define __STDC_WANT_LIB_EXT2__ 1-#endif-/* Enable extensions specified by ISO/IEC 24747:2009. */-#ifndef __STDC_WANT_MATH_SPEC_FUNCS__-# define __STDC_WANT_MATH_SPEC_FUNCS__ 1-#endif-/* Enable extensions on HP NonStop. */-#ifndef _TANDEM_SOURCE-# define _TANDEM_SOURCE 1-#endif-/* Enable X/Open extensions. Define to 500 only if necessary- to make mbstate_t available. */-#ifndef _XOPEN_SOURCE-/* # undef _XOPEN_SOURCE */-#endif---/* Version number of package */-#define VERSION "3.7.1"--/* Define to '0x0502' for Windows Server 2003 APIs. */-/* #undef WINVER */--/* Number of bits in a file offset, on hosts where this is settable. */-/* #undef _FILE_OFFSET_BITS */--/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */-/* #undef _LARGEFILE_SOURCE */--/* Define for large files, on AIX-style hosts. */-/* #undef _LARGE_FILES */--/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT32_T */--/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT64_T */--/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT8_T */--/* Define to '0x0502' for Windows Server 2003 APIs. */-/* #undef _WIN32_WINNT */--/* Internal macro for sanity checks */-#define __LIBARCHIVE_CONFIG_H_INCLUDED 1--/* Define to empty if `const' does not conform to ANSI C. */-/* #undef const */--/* Define to match typeof st_gid field of struct stat if <sys/types.h> doesn't- define. */-/* #undef gid_t */--/* Define to `unsigned long' if <sys/types.h> does not define. */-/* #undef id_t */--/* Define to the type of a signed integer type of width exactly 16 bits if- such a type exists and the standard includes do not define it. */-/* #undef int16_t */--/* Define to the type of a signed integer type of width exactly 32 bits if- such a type exists and the standard includes do not define it. */-/* #undef int32_t */--/* Define to the type of a signed integer type of width exactly 64 bits if- such a type exists and the standard includes do not define it. */-/* #undef int64_t */--/* Define to the widest signed integer type if <stdint.h> and <inttypes.h> do- not define. */-/* #undef intmax_t */--/* Define to `int' if <sys/types.h> does not define. */-/* #undef mode_t */--/* Define to `long long' if <sys/types.h> does not define. */-/* #undef off_t */--/* Define to `unsigned int' if <sys/types.h> does not define. */-/* #undef size_t */--/* Define to match typeof st_uid field of struct stat if <sys/types.h> doesn't- define. */-/* #undef uid_t */--/* Define to the type of an unsigned integer type of width exactly 16 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint16_t */--/* Define to the type of an unsigned integer type of width exactly 32 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint32_t */--/* Define to the type of an unsigned integer type of width exactly 64 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint64_t */--/* Define to the type of an unsigned integer type of width exactly 8 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint8_t */--/* Define to the widest unsigned integer type if <stdint.h> and <inttypes.h>- do not define. */-/* #undef uintmax_t */--/* Define to `unsigned int' if <sys/types.h> does not define. */-/* #undef uintptr_t */-#define HAVE_LIBZ 1-#define HAVE_ZLIB_H 1
− c/autoconf-windows/config.h
@@ -1,1521 +0,0 @@-/* config.h. Generated from config.h.in by configure. */-/* config.h.in. Generated from configure.ac by autoheader. */--/* Darwin ACL support */-/* #undef ARCHIVE_ACL_DARWIN */--/* FreeBSD ACL support */-/* #undef ARCHIVE_ACL_FREEBSD */--/* FreeBSD NFSv4 ACL support */-/* #undef ARCHIVE_ACL_FREEBSD_NFS4 */--/* Linux POSIX.1e ACL support via libacl */-/* #undef ARCHIVE_ACL_LIBACL */--/* Linux NFSv4 ACL support via librichacl */-/* #undef ARCHIVE_ACL_LIBRICHACL */--/* Solaris ACL support */-/* #undef ARCHIVE_ACL_SUNOS */--/* Solaris NFSv4 ACL support */-/* #undef ARCHIVE_ACL_SUNOS_NFS4 */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_MD5_LIBC */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_MD5_LIBMD */--/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_MD5_LIBSYSTEM */--/* MD5 via ARCHIVE_CRYPTO_MD5_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_MD5_MBEDTLS */--/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_MD5_NETTLE */--/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_MD5_OPENSSL */--/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */-#define ARCHIVE_CRYPTO_MD5_WIN 1--/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_LIBC */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_LIBMD */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_MBEDTLS */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_NETTLE */--/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_RMD160_OPENSSL */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_LIBC */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_LIBMD */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_LIBSYSTEM */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_MBEDTLS */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_NETTLE */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA1_OPENSSL */--/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */-#define ARCHIVE_CRYPTO_SHA1_WIN 1--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC2 */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBC3 */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBMD */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_LIBSYSTEM */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_MBEDTLS */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_NETTLE */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_OPENSSL */--/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA256_WIN */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC2 */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBC3 */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_LIBSYSTEM */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_MBEDTLS */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_NETTLE */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_OPENSSL */--/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA384_WIN */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC2 */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBC3 */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBMD supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBMD */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_LIBSYSTEM */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_MBEDTLS supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_MBEDTLS */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_NETTLE */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_OPENSSL */--/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */-/* #undef ARCHIVE_CRYPTO_SHA512_WIN */--/* AIX xattr support */-/* #undef ARCHIVE_XATTR_AIX */--/* Darwin xattr support */-/* #undef ARCHIVE_XATTR_DARWIN */--/* FreeBSD xattr support */-/* #undef ARCHIVE_XATTR_FREEBSD */--/* Linux xattr support */-/* #undef ARCHIVE_XATTR_LINUX */--/* Version number of bsdcat */-#define BSDCAT_VERSION_STRING "3.7.1"--/* Version number of bsdcpio */-#define BSDCPIO_VERSION_STRING "3.7.1"--/* Version number of bsdtar */-#define BSDTAR_VERSION_STRING "3.7.1"--/* Define to 1 if the system has the type `ace_t'. */-/* #undef HAVE_ACE_T */--/* Define to 1 if you have the `acl' function. */-/* #undef HAVE_ACL */--/* Define to 1 if the system has the type `aclent_t'. */-/* #undef HAVE_ACLENT_T */--/* Define to 1 if you have the `acl_add_flag_np' function. */-/* #undef HAVE_ACL_ADD_FLAG_NP */--/* Define to 1 if you have the `acl_add_perm' function. */-/* #undef HAVE_ACL_ADD_PERM */--/* Define to 1 if you have the `acl_clear_flags_np' function. */-/* #undef HAVE_ACL_CLEAR_FLAGS_NP */--/* Define to 1 if you have the `acl_clear_perms' function. */-/* #undef HAVE_ACL_CLEAR_PERMS */--/* Define to 1 if you have the `acl_create_entry' function. */-/* #undef HAVE_ACL_CREATE_ENTRY */--/* Define to 1 if you have the `acl_delete_def_file' function. */-/* #undef HAVE_ACL_DELETE_DEF_FILE */--/* Define to 1 if the system has the type `acl_entry_t'. */-/* #undef HAVE_ACL_ENTRY_T */--/* Define to 1 if you have the `acl_free' function. */-/* #undef HAVE_ACL_FREE */--/* Define to 1 if you have the `acl_get_brand_np' function. */-/* #undef HAVE_ACL_GET_BRAND_NP */--/* Define to 1 if you have the `acl_get_entry' function. */-/* #undef HAVE_ACL_GET_ENTRY */--/* Define to 1 if you have the `acl_get_entry_type_np' function. */-/* #undef HAVE_ACL_GET_ENTRY_TYPE_NP */--/* Define to 1 if you have the `acl_get_fd' function. */-/* #undef HAVE_ACL_GET_FD */--/* Define to 1 if you have the `acl_get_fd_np' function. */-/* #undef HAVE_ACL_GET_FD_NP */--/* Define to 1 if you have the `acl_get_file' function. */-/* #undef HAVE_ACL_GET_FILE */--/* Define to 1 if you have the `acl_get_flagset_np' function. */-/* #undef HAVE_ACL_GET_FLAGSET_NP */--/* Define to 1 if you have the `acl_get_flag_np' function. */-/* #undef HAVE_ACL_GET_FLAG_NP */--/* Define to 1 if you have the `acl_get_link_np' function. */-/* #undef HAVE_ACL_GET_LINK_NP */--/* Define to 1 if you have the `acl_get_perm' function. */-/* #undef HAVE_ACL_GET_PERM */--/* Define to 1 if you have the `acl_get_permset' function. */-/* #undef HAVE_ACL_GET_PERMSET */--/* Define to 1 if you have the `acl_get_perm_np' function. */-/* #undef HAVE_ACL_GET_PERM_NP */--/* Define to 1 if you have the `acl_get_qualifier' function. */-/* #undef HAVE_ACL_GET_QUALIFIER */--/* Define to 1 if you have the `acl_get_tag_type' function. */-/* #undef HAVE_ACL_GET_TAG_TYPE */--/* Define to 1 if you have the `acl_init' function. */-/* #undef HAVE_ACL_INIT */--/* Define to 1 if you have the `acl_is_trivial_np' function. */-/* #undef HAVE_ACL_IS_TRIVIAL_NP */--/* Define to 1 if you have the <acl/libacl.h> header file. */-/* #undef HAVE_ACL_LIBACL_H */--/* Define to 1 if the system has the type `acl_permset_t'. */-/* #undef HAVE_ACL_PERMSET_T */--/* Define to 1 if you have the `acl_set_entry_type_np' function. */-/* #undef HAVE_ACL_SET_ENTRY_TYPE_NP */--/* Define to 1 if you have the `acl_set_fd' function. */-/* #undef HAVE_ACL_SET_FD */--/* Define to 1 if you have the `acl_set_fd_np' function. */-/* #undef HAVE_ACL_SET_FD_NP */--/* Define to 1 if you have the `acl_set_file' function. */-/* #undef HAVE_ACL_SET_FILE */--/* Define to 1 if you have the `acl_set_link_np' function. */-/* #undef HAVE_ACL_SET_LINK_NP */--/* Define to 1 if you have the `acl_set_qualifier' function. */-/* #undef HAVE_ACL_SET_QUALIFIER */--/* Define to 1 if you have the `acl_set_tag_type' function. */-/* #undef HAVE_ACL_SET_TAG_TYPE */--/* Define to 1 if the system has the type `acl_t'. */-/* #undef HAVE_ACL_T */--/* Define to 1 if the system has the type `acl_tag_t'. */-/* #undef HAVE_ACL_TAG_T */--/* Define to 1 if you have the `arc4random_buf' function. */-/* #undef HAVE_ARC4RANDOM_BUF */--/* Define to 1 if you have the <attr/xattr.h> header file. */-/* #undef HAVE_ATTR_XATTR_H */--/* Define to 1 if you have the <bcrypt.h> header file. */-/* #undef HAVE_BCRYPT_H */--/* Define to 1 if you have the <blake2.h> header file. */-/* #undef HAVE_BLAKE2_H */--/* Define to 1 if you have the <bzlib.h> header file. */-/* #undef HAVE_BZLIB_H */--/* Define to 1 if you have the `chflags' function. */-/* #undef HAVE_CHFLAGS */--/* Define to 1 if you have the `chown' function. */-/* #undef HAVE_CHOWN */--/* Define to 1 if you have the `chroot' function. */-/* #undef HAVE_CHROOT */--/* cmtime_s function */-/* #undef HAVE_CMTIME_S */--/* Define to 1 if you have the <copyfile.h> header file. */-/* #undef HAVE_COPYFILE_H */--/* Define to 1 if you have the `ctime_r' function. */-/* #undef HAVE_CTIME_R */--/* Define to 1 if you have the <ctype.h> header file. */-#define HAVE_CTYPE_H 1--/* Define to 1 if you have the `cygwin_conv_path' function. */-/* #undef HAVE_CYGWIN_CONV_PATH */--/* Define to 1 if you have the declaration of `ACE_GETACL', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_GETACL */--/* Define to 1 if you have the declaration of `ACE_GETACLCNT', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_GETACLCNT */--/* Define to 1 if you have the declaration of `ACE_SETACL', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACE_SETACL */--/* Define to 1 if you have the declaration of `ACL_SYNCHRONIZE', and to 0 if- you don't. */-/* #undef HAVE_DECL_ACL_SYNCHRONIZE */--/* Define to 1 if you have the declaration of `ACL_TYPE_EXTENDED', and to 0 if- you don't. */-/* #undef HAVE_DECL_ACL_TYPE_EXTENDED */--/* Define to 1 if you have the declaration of `ACL_TYPE_NFS4', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACL_TYPE_NFS4 */--/* Define to 1 if you have the declaration of `ACL_USER', and to 0 if you- don't. */-/* #undef HAVE_DECL_ACL_USER */--/* Define to 1 if you have the declaration of `EXTATTR_NAMESPACE_USER', and to- 0 if you don't. */-/* #undef HAVE_DECL_EXTATTR_NAMESPACE_USER */--/* Define to 1 if you have the declaration of `GETACL', and to 0 if you don't.- */-/* #undef HAVE_DECL_GETACL */--/* Define to 1 if you have the declaration of `GETACLCNT', and to 0 if you- don't. */-/* #undef HAVE_DECL_GETACLCNT */--/* Define to 1 if you have the declaration of `INT32_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INT32_MAX 1--/* Define to 1 if you have the declaration of `INT32_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INT32_MIN 1--/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INT64_MAX 1--/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INT64_MIN 1--/* Define to 1 if you have the declaration of `INTMAX_MAX', and to 0 if you- don't. */-#define HAVE_DECL_INTMAX_MAX 1--/* Define to 1 if you have the declaration of `INTMAX_MIN', and to 0 if you- don't. */-#define HAVE_DECL_INTMAX_MIN 1--/* Define to 1 if you have the declaration of `SETACL', and to 0 if you don't.- */-/* #undef HAVE_DECL_SETACL */--/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you- don't. */-#define HAVE_DECL_SIZE_MAX 1--/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you- don't. */-#define HAVE_DECL_SSIZE_MAX 1--/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you- don't. */-#define HAVE_DECL_STRERROR_R 1--/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINT32_MAX 1--/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINT64_MAX 1--/* Define to 1 if you have the declaration of `UINTMAX_MAX', and to 0 if you- don't. */-#define HAVE_DECL_UINTMAX_MAX 1--/* Define to 1 if you have the declaration of `XATTR_NOFOLLOW', and to 0 if- you don't. */-/* #undef HAVE_DECL_XATTR_NOFOLLOW */--/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.- */-#define HAVE_DIRENT_H 1--/* Define to 1 if you have a dirfd function or macro */-/* #undef HAVE_DIRFD */--/* Define to 1 if you have the <dlfcn.h> header file. */-#define HAVE_DLFCN_H 1--/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */-/* #undef HAVE_DOPRNT */--/* Define to 1 if nl_langinfo supports D_MD_ORDER */-/* #undef HAVE_D_MD_ORDER */--/* A possible errno value for invalid file format errors */-/* #undef HAVE_EFTYPE */--/* A possible errno value for invalid file format errors */-#define HAVE_EILSEQ 1--/* Define to 1 if you have the <errno.h> header file. */-#define HAVE_ERRNO_H 1--/* Define to 1 if you have the <expat.h> header file. */-/* #undef HAVE_EXPAT_H */--/* Define to 1 if you have the <ext2fs/ext2_fs.h> header file. */-/* #undef HAVE_EXT2FS_EXT2_FS_H */--/* Define to 1 if you have the `extattr_get_fd' function. */-/* #undef HAVE_EXTATTR_GET_FD */--/* Define to 1 if you have the `extattr_get_file' function. */-/* #undef HAVE_EXTATTR_GET_FILE */--/* Define to 1 if you have the `extattr_get_link' function. */-/* #undef HAVE_EXTATTR_GET_LINK */--/* Define to 1 if you have the `extattr_list_fd' function. */-/* #undef HAVE_EXTATTR_LIST_FD */--/* Define to 1 if you have the `extattr_list_file' function. */-/* #undef HAVE_EXTATTR_LIST_FILE */--/* Define to 1 if you have the `extattr_list_link' function. */-/* #undef HAVE_EXTATTR_LIST_LINK */--/* Define to 1 if you have the `extattr_set_fd' function. */-/* #undef HAVE_EXTATTR_SET_FD */--/* Define to 1 if you have the `extattr_set_link' function. */-/* #undef HAVE_EXTATTR_SET_LINK */--/* Define to 1 if you have the `facl' function. */-/* #undef HAVE_FACL */--/* Define to 1 if you have the `fchdir' function. */-/* #undef HAVE_FCHDIR */--/* Define to 1 if you have the `fchflags' function. */-/* #undef HAVE_FCHFLAGS */--/* Define to 1 if you have the `fchmod' function. */-/* #undef HAVE_FCHMOD */--/* Define to 1 if you have the `fchown' function. */-/* #undef HAVE_FCHOWN */--/* Define to 1 if you have the `fcntl' function. */-/* #undef HAVE_FCNTL */--/* Define to 1 if you have the <fcntl.h> header file. */-#define HAVE_FCNTL_H 1--/* Define to 1 if you have the `fdopendir' function. */-/* #undef HAVE_FDOPENDIR */--/* Define to 1 if you have the `fgetea' function. */-/* #undef HAVE_FGETEA */--/* Define to 1 if you have the `fgetxattr' function. */-/* #undef HAVE_FGETXATTR */--/* Define to 1 if you have the `flistea' function. */-/* #undef HAVE_FLISTEA */--/* Define to 1 if you have the `flistxattr' function. */-/* #undef HAVE_FLISTXATTR */--/* Define to 1 if you have the `fnmatch' function. */-/* #undef HAVE_FNMATCH */--/* Define to 1 if you have the <fnmatch.h> header file. */-/* #undef HAVE_FNMATCH_H */--/* Define to 1 if you have the `fork' function. */-/* #undef HAVE_FORK */--/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */-/* #undef HAVE_FSEEKO */--/* Define to 1 if you have the `fsetea' function. */-/* #undef HAVE_FSETEA */--/* Define to 1 if you have the `fsetxattr' function. */-/* #undef HAVE_FSETXATTR */--/* Define to 1 if you have the `fstat' function. */-#define HAVE_FSTAT 1--/* Define to 1 if you have the `fstatat' function. */-/* #undef HAVE_FSTATAT */--/* Define to 1 if you have the `fstatfs' function. */-/* #undef HAVE_FSTATFS */--/* Define to 1 if you have the `fstatvfs' function. */-/* #undef HAVE_FSTATVFS */--/* Define to 1 if you have the `ftruncate' function. */-#define HAVE_FTRUNCATE 1--/* Define to 1 if you have the `futimens' function. */-/* #undef HAVE_FUTIMENS */--/* Define to 1 if you have the `futimes' function. */-/* #undef HAVE_FUTIMES */--/* Define to 1 if you have the `futimesat' function. */-/* #undef HAVE_FUTIMESAT */--/* Define to 1 if you have the `getea' function. */-/* #undef HAVE_GETEA */--/* Define to 1 if you have the `geteuid' function. */-/* #undef HAVE_GETEUID */--/* Define to 1 if you have the `getgrgid_r' function. */-/* #undef HAVE_GETGRGID_R */--/* Define to 1 if you have the `getgrnam_r' function. */-/* #undef HAVE_GETGRNAM_R */--/* Define to 1 if you have the `getline' function. */-#define HAVE_GETLINE 1--/* Platform uses optreset to reset getopt */-/* #undef HAVE_GETOPT_OPTRESET */--/* Define to 1 if you have the `getpid' function. */-#define HAVE_GETPID 1--/* Define to 1 if you have the `getpwnam_r' function. */-/* #undef HAVE_GETPWNAM_R */--/* Define to 1 if you have the `getpwuid_r' function. */-/* #undef HAVE_GETPWUID_R */--/* Define to 1 if you have the `getvfsbyname' function. */-/* #undef HAVE_GETVFSBYNAME */--/* Define to 1 if you have the `getxattr' function. */-/* #undef HAVE_GETXATTR */--/* Define to 1 if you have the `gmtime_r' function. */-/* #undef HAVE_GMTIME_R */--/* gmtime_s function */-/* #undef HAVE_GMTIME_S */--/* Define to 1 if you have the <grp.h> header file. */-/* #undef HAVE_GRP_H */--/* Define if you have the iconv() function and it works. */-/* #undef HAVE_ICONV */--/* Define to 1 if you have the <iconv.h> header file. */-/* #undef HAVE_ICONV_H */--/* Define to 1 if the system has the type `intmax_t'. */-#define HAVE_INTMAX_T 1--/* Define to 1 if you have the <inttypes.h> header file. */-#define HAVE_INTTYPES_H 1--/* Define to 1 if you have the <io.h> header file. */-#define HAVE_IO_H 1--/* Define to 1 if you have the <langinfo.h> header file. */-/* #undef HAVE_LANGINFO_H */--/* Define to 1 if you have the `lchflags' function. */-/* #undef HAVE_LCHFLAGS */--/* Define to 1 if you have the `lchmod' function. */-/* #undef HAVE_LCHMOD */--/* Define to 1 if you have the `lchown' function. */-/* #undef HAVE_LCHOWN */--/* Define to 1 if you have the `lgetea' function. */-/* #undef HAVE_LGETEA */--/* Define to 1 if you have the `lgetxattr' function. */-/* #undef HAVE_LGETXATTR */--/* Define to 1 if you have the `acl' library (-lacl). */-/* #undef HAVE_LIBACL */--/* Define to 1 if you have the `b2' library (-lb2). */-/* #undef HAVE_LIBB2 */--/* Define to 1 if you have the `bz2' library (-lbz2). */-/* #undef HAVE_LIBBZ2 */--/* Define to 1 if you have the `charset' library (-lcharset). */-/* #undef HAVE_LIBCHARSET */--/* Define to 1 if you have the `crypto' library (-lcrypto). */-/* #undef HAVE_LIBCRYPTO */--/* Define to 1 if you have the `expat' library (-lexpat). */-/* #undef HAVE_LIBEXPAT */--/* Define to 1 if you have the `lz4' library (-llz4). */-/* #undef HAVE_LIBLZ4 */--/* Define to 1 if you have the `lzma' library (-llzma). */-/* #undef HAVE_LIBLZMA */--/* Define to 1 if you have the `lzo2' library (-llzo2). */-/* #undef HAVE_LIBLZO2 */--/* Define to 1 if you have the `mbedcrypto' library (-lmbedcrypto). */-/* #undef HAVE_LIBMBEDCRYPTO */--/* Define to 1 if you have the `md' library (-lmd). */-/* #undef HAVE_LIBMD */--/* Define to 1 if you have the `nettle' library (-lnettle). */-/* #undef HAVE_LIBNETTLE */--/* Define to 1 if you have the `pcre' library (-lpcre). */-/* #undef HAVE_LIBPCRE */--/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */-/* #undef HAVE_LIBPCREPOSIX */--/* Define to 1 if you have the `regex' library (-lregex). */-/* #undef HAVE_LIBREGEX */--/* Define to 1 if you have the `richacl' library (-lrichacl). */-/* #undef HAVE_LIBRICHACL */--/* Define to 1 if you have the `xml2' library (-lxml2). */-/* #undef HAVE_LIBXML2 */--/* Define to 1 if you have the <libxml/xmlreader.h> header file. */-/* #undef HAVE_LIBXML_XMLREADER_H */--/* Define to 1 if you have the <libxml/xmlwriter.h> header file. */-/* #undef HAVE_LIBXML_XMLWRITER_H */--/* Define to 1 if you have the `z' library (-lz). */-/* #undef HAVE_LIBZ */--/* Define to 1 if you have the `zstd' library (-lzstd). */-/* #undef HAVE_LIBZSTD */--/* Define to 1 if you have the `zstd' library (-lzstd) with compression- support. */-/* #undef HAVE_LIBZSTD_COMPRESSOR */--/* Define to 1 if you have the <limits.h> header file. */-#define HAVE_LIMITS_H 1--/* Define to 1 if you have the `link' function. */-/* #undef HAVE_LINK */--/* Define to 1 if you have the `linkat' function. */-/* #undef HAVE_LINKAT */--/* Define to 1 if you have the <linux/fiemap.h> header file. */-/* #undef HAVE_LINUX_FIEMAP_H */--/* Define to 1 if you have the <linux/fs.h> header file. */-/* #undef HAVE_LINUX_FS_H */--/* Define to 1 if you have the <linux/magic.h> header file. */-/* #undef HAVE_LINUX_MAGIC_H */--/* Define to 1 if you have the <linux/types.h> header file. */-/* #undef HAVE_LINUX_TYPES_H */--/* Define to 1 if you have the `listea' function. */-/* #undef HAVE_LISTEA */--/* Define to 1 if you have the `listxattr' function. */-/* #undef HAVE_LISTXATTR */--/* Define to 1 if you have the `llistea' function. */-/* #undef HAVE_LLISTEA */--/* Define to 1 if you have the `llistxattr' function. */-/* #undef HAVE_LLISTXATTR */--/* Define to 1 if you have the <localcharset.h> header file. */-/* #undef HAVE_LOCALCHARSET_H */--/* Define to 1 if you have the `locale_charset' function. */-/* #undef HAVE_LOCALE_CHARSET */--/* Define to 1 if you have the <locale.h> header file. */-#define HAVE_LOCALE_H 1--/* Define to 1 if you have the `localtime_r' function. */-/* #undef HAVE_LOCALTIME_R */--/* localtime_s function */-/* #undef HAVE_LOCALTIME_S */--/* Define to 1 if the system has the type `long long int'. */-#define HAVE_LONG_LONG_INT 1--/* Define to 1 if you have the `lsetea' function. */-/* #undef HAVE_LSETEA */--/* Define to 1 if you have the `lsetxattr' function. */-/* #undef HAVE_LSETXATTR */--/* Define to 1 if you have the `lstat' function. */-/* #undef HAVE_LSTAT */--/* Define to 1 if `lstat' has the bug that it succeeds when given the- zero-length file name argument. */-#define HAVE_LSTAT_EMPTY_STRING_BUG 1--/* Define to 1 if you have the `lutimes' function. */-/* #undef HAVE_LUTIMES */--/* Define to 1 if you have the <lz4hc.h> header file. */-/* #undef HAVE_LZ4HC_H */--/* Define to 1 if you have the <lz4.h> header file. */-/* #undef HAVE_LZ4_H */--/* Define to 1 if you have the `LZMA_FILTER_ARM64' macro. */-/* #undef HAVE_LZMA_FILTER_ARM64 */--/* Define to 1 if you have the <lzma.h> header file. */-/* #undef HAVE_LZMA_H */--/* Define to 1 if you have the `lzma_stream_encoder_mt' function. */-/* #undef HAVE_LZMA_STREAM_ENCODER_MT */--/* Define to 1 if you have the <lzo/lzo1x.h> header file. */-/* #undef HAVE_LZO_LZO1X_H */--/* Define to 1 if you have the <lzo/lzoconf.h> header file. */-/* #undef HAVE_LZO_LZOCONF_H */--/* Define to 1 if you have the <mbedtls/aes.h> header file. */-/* #undef HAVE_MBEDTLS_AES_H */--/* Define to 1 if you have the <mbedtls/md.h> header file. */-/* #undef HAVE_MBEDTLS_MD_H */--/* Define to 1 if you have the <mbedtls/pkcs5.h> header file. */-/* #undef HAVE_MBEDTLS_PKCS5_H */--/* Define to 1 if you have the `mbrtowc' function. */-#define HAVE_MBRTOWC 1--/* Define to 1 if you have the `mbr_gid_to_uuid' function. */-/* #undef HAVE_MBR_GID_TO_UUID */--/* Define to 1 if you have the `mbr_uid_to_uuid' function. */-/* #undef HAVE_MBR_UID_TO_UUID */--/* Define to 1 if you have the `mbr_uuid_to_id' function. */-/* #undef HAVE_MBR_UUID_TO_ID */--/* Define to 1 if you have the <md5.h> header file. */-/* #undef HAVE_MD5_H */--/* Define to 1 if you have the <membership.h> header file. */-/* #undef HAVE_MEMBERSHIP_H */--/* Define to 1 if you have the `memmove' function. */-#define HAVE_MEMMOVE 1--/* Define to 1 if you have the `memset' function. */-#define HAVE_MEMSET 1--/* Define to 1 if you have the <minix/config.h> header file. */-/* #undef HAVE_MINIX_CONFIG_H */--/* Define to 1 if you have the `mkdir' function. */-#define HAVE_MKDIR 1--/* Define to 1 if you have the `mkfifo' function. */-/* #undef HAVE_MKFIFO */--/* Define to 1 if you have the `mknod' function. */-/* #undef HAVE_MKNOD */--/* Define to 1 if you have the `mkstemp' function. */-#define HAVE_MKSTEMP 1--/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */-/* #undef HAVE_NDIR_H */--/* Define to 1 if you have the <nettle/aes.h> header file. */-/* #undef HAVE_NETTLE_AES_H */--/* Define to 1 if you have the <nettle/hmac.h> header file. */-/* #undef HAVE_NETTLE_HMAC_H */--/* Define to 1 if you have the <nettle/md5.h> header file. */-/* #undef HAVE_NETTLE_MD5_H */--/* Define to 1 if you have the <nettle/pbkdf2.h> header file. */-/* #undef HAVE_NETTLE_PBKDF2_H */--/* Define to 1 if you have the <nettle/ripemd160.h> header file. */-/* #undef HAVE_NETTLE_RIPEMD160_H */--/* Define to 1 if you have the <nettle/sha.h> header file. */-/* #undef HAVE_NETTLE_SHA_H */--/* Define to 1 if you have the `nl_langinfo' function. */-/* #undef HAVE_NL_LANGINFO */--/* Define to 1 if you have the `openat' function. */-/* #undef HAVE_OPENAT */--/* Define to 1 if you have the <openssl/evp.h> header file. */-/* #undef HAVE_OPENSSL_EVP_H */--/* Define to 1 if you have the <paths.h> header file. */-/* #undef HAVE_PATHS_H */--/* Define to 1 if you have the <pcreposix.h> header file. */-/* #undef HAVE_PCREPOSIX_H */--/* Define to 1 if you have the `pipe' function. */-/* #undef HAVE_PIPE */--/* Define to 1 if you have the `PKCS5_PBKDF2_HMAC_SHA1' function. */-/* #undef HAVE_PKCS5_PBKDF2_HMAC_SHA1 */--/* Define to 1 if you have the `poll' function. */-/* #undef HAVE_POLL */--/* Define to 1 if you have the <poll.h> header file. */-/* #undef HAVE_POLL_H */--/* Define to 1 if you have the `posix_spawnp' function. */-/* #undef HAVE_POSIX_SPAWNP */--/* Define to 1 if you have the <pthread.h> header file. */-/* #undef HAVE_PTHREAD_H */--/* Define to 1 if you have the <pwd.h> header file. */-/* #undef HAVE_PWD_H */--/* Define to 1 if you have a POSIX compatible readdir_r */-/* #undef HAVE_READDIR_R */--/* Define to 1 if you have the `readlink' function. */-/* #undef HAVE_READLINK */--/* Define to 1 if you have the `readlinkat' function. */-/* #undef HAVE_READLINKAT */--/* Define to 1 if you have the `readpassphrase' function. */-/* #undef HAVE_READPASSPHRASE */--/* Define to 1 if you have the <readpassphrase.h> header file. */-/* #undef HAVE_READPASSPHRASE_H */--/* Define to 1 if you have the <regex.h> header file. */-/* #undef HAVE_REGEX_H */--/* Define to 1 if you have the `richacl_alloc' function. */-/* #undef HAVE_RICHACL_ALLOC */--/* Define to 1 if you have the `richacl_equiv_mode' function. */-/* #undef HAVE_RICHACL_EQUIV_MODE */--/* Define to 1 if you have the `richacl_free' function. */-/* #undef HAVE_RICHACL_FREE */--/* Define to 1 if you have the `richacl_get_fd' function. */-/* #undef HAVE_RICHACL_GET_FD */--/* Define to 1 if you have the `richacl_get_file' function. */-/* #undef HAVE_RICHACL_GET_FILE */--/* Define to 1 if you have the `richacl_set_fd' function. */-/* #undef HAVE_RICHACL_SET_FD */--/* Define to 1 if you have the `richacl_set_file' function. */-/* #undef HAVE_RICHACL_SET_FILE */--/* Define to 1 if you have the <ripemd.h> header file. */-/* #undef HAVE_RIPEMD_H */--/* Define to 1 if you have the `select' function. */-/* #undef HAVE_SELECT */--/* Define to 1 if you have the `setenv' function. */-#define HAVE_SETENV 1--/* Define to 1 if you have the `setlocale' function. */-#define HAVE_SETLOCALE 1--/* Define to 1 if you have the `setxattr' function. */-/* #undef HAVE_SETXATTR */--/* Define to 1 if you have the <sha256.h> header file. */-/* #undef HAVE_SHA256_H */--/* Define to 1 if you have the <sha512.h> header file. */-/* #undef HAVE_SHA512_H */--/* Define to 1 if you have the <sha.h> header file. */-/* #undef HAVE_SHA_H */--/* Define to 1 if you have the `sigaction' function. */-/* #undef HAVE_SIGACTION */--/* Define to 1 if you have the <signal.h> header file. */-#define HAVE_SIGNAL_H 1--/* Define to 1 if you have the <spawn.h> header file. */-/* #undef HAVE_SPAWN_H */--/* Define to 1 if you have the `statfs' function. */-/* #undef HAVE_STATFS */--/* Define to 1 if you have the `statvfs' function. */-/* #undef HAVE_STATVFS */--/* Define to 1 if `stat' has the bug that it succeeds when given the- zero-length file name argument. */-/* #undef HAVE_STAT_EMPTY_STRING_BUG */--/* Define to 1 if you have the <stdarg.h> header file. */-#define HAVE_STDARG_H 1--/* Define to 1 if you have the <stdint.h> header file. */-#define HAVE_STDINT_H 1--/* Define to 1 if you have the <stdio.h> header file. */-#define HAVE_STDIO_H 1--/* Define to 1 if you have the <stdlib.h> header file. */-#define HAVE_STDLIB_H 1--/* Define to 1 if you have the `strchr' function. */-#define HAVE_STRCHR 1--/* Define to 1 if you have the `strdup' function. */-#define HAVE_STRDUP 1--/* Define to 1 if you have the `strerror' function. */-#define HAVE_STRERROR 1--/* Define if you have `strerror_r'. */-#define HAVE_STRERROR_R 1--/* Define to 1 if you have the `strftime' function. */-#define HAVE_STRFTIME 1--/* Define to 1 if you have the <strings.h> header file. */-#define HAVE_STRINGS_H 1--/* Define to 1 if you have the <string.h> header file. */-#define HAVE_STRING_H 1--/* Define to 1 if you have the `strncpy_s' function. */-#define HAVE_STRNCPY_S 1--/* Define to 1 if you have the `strnlen' function. */-#define HAVE_STRNLEN 1--/* Define to 1 if you have the `strrchr' function. */-#define HAVE_STRRCHR 1--/* Define to 1 if the system has the type `struct richace'. */-/* #undef HAVE_STRUCT_RICHACE */--/* Define to 1 if the system has the type `struct richacl'. */-/* #undef HAVE_STRUCT_RICHACL */--/* Define to 1 if the system has the type `struct statfs'. */-/* #undef HAVE_STRUCT_STATFS */--/* Define to 1 if `f_iosize' is a member of `struct statfs'. */-/* #undef HAVE_STRUCT_STATFS_F_IOSIZE */--/* Define to 1 if `f_namemax' is a member of `struct statfs'. */-/* #undef HAVE_STRUCT_STATFS_F_NAMEMAX */--/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */-/* #undef HAVE_STRUCT_STATVFS_F_IOSIZE */--/* Define to 1 if `st_birthtime' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIME */--/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC */--/* Define to 1 if `st_blksize' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_BLKSIZE */--/* Define to 1 if `st_flags' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_FLAGS */--/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC */--/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIME_N */--/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIME_USEC */--/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */--/* Define to 1 if `st_umtime' is a member of `struct stat'. */-/* #undef HAVE_STRUCT_STAT_ST_UMTIME */--/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */-/* #undef HAVE_STRUCT_TM_TM_GMTOFF */--/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */-/* #undef HAVE_STRUCT_TM___TM_GMTOFF */--/* Define to 1 if the system has the type `struct vfsconf'. */-/* #undef HAVE_STRUCT_VFSCONF */--/* Define to 1 if the system has the type `struct xvfsconf'. */-/* #undef HAVE_STRUCT_XVFSCONF */--/* Define to 1 if you have the `symlink' function. */-/* #undef HAVE_SYMLINK */--/* Define to 1 if you have the <sys/acl.h> header file. */-/* #undef HAVE_SYS_ACL_H */--/* Define to 1 if you have the <sys/cdefs.h> header file. */-/* #undef HAVE_SYS_CDEFS_H */--/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.- */-/* #undef HAVE_SYS_DIR_H */--/* Define to 1 if you have the <sys/ea.h> header file. */-/* #undef HAVE_SYS_EA_H */--/* Define to 1 if you have the <sys/extattr.h> header file. */-/* #undef HAVE_SYS_EXTATTR_H */--/* Define to 1 if you have the <sys/ioctl.h> header file. */-/* #undef HAVE_SYS_IOCTL_H */--/* Define to 1 if you have the <sys/mkdev.h> header file. */-/* #undef HAVE_SYS_MKDEV_H */--/* Define to 1 if you have the <sys/mount.h> header file. */-/* #undef HAVE_SYS_MOUNT_H */--/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.- */-/* #undef HAVE_SYS_NDIR_H */--/* Define to 1 if you have the <sys/param.h> header file. */-#define HAVE_SYS_PARAM_H 1--/* Define to 1 if you have the <sys/poll.h> header file. */-/* #undef HAVE_SYS_POLL_H */--/* Define to 1 if you have the <sys/queue.h> header file. */-/* #undef HAVE_SYS_QUEUE_H */--/* Define to 1 if you have the <sys/richacl.h> header file. */-/* #undef HAVE_SYS_RICHACL_H */--/* Define to 1 if you have the <sys/select.h> header file. */-/* #undef HAVE_SYS_SELECT_H */--/* Define to 1 if you have the <sys/statfs.h> header file. */-/* #undef HAVE_SYS_STATFS_H */--/* Define to 1 if you have the <sys/statvfs.h> header file. */-/* #undef HAVE_SYS_STATVFS_H */--/* Define to 1 if you have the <sys/stat.h> header file. */-#define HAVE_SYS_STAT_H 1--/* Define to 1 if you have the <sys/sysmacros.h> header file. */-/* #undef HAVE_SYS_SYSMACROS_H */--/* Define to 1 if you have the <sys/time.h> header file. */-#define HAVE_SYS_TIME_H 1--/* Define to 1 if you have the <sys/types.h> header file. */-#define HAVE_SYS_TYPES_H 1--/* Define to 1 if you have the <sys/utime.h> header file. */-#define HAVE_SYS_UTIME_H 1--/* Define to 1 if you have the <sys/utsname.h> header file. */-/* #undef HAVE_SYS_UTSNAME_H */--/* Define to 1 if you have the <sys/vfs.h> header file. */-/* #undef HAVE_SYS_VFS_H */--/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */-/* #undef HAVE_SYS_WAIT_H */--/* Define to 1 if you have the <sys/xattr.h> header file. */-/* #undef HAVE_SYS_XATTR_H */--/* Define to 1 if you have the `timegm' function. */-/* #undef HAVE_TIMEGM */--/* Define to 1 if you have the <time.h> header file. */-#define HAVE_TIME_H 1--/* Define to 1 if you have the `tzset' function. */-#define HAVE_TZSET 1--/* Define to 1 if the system has the type `uintmax_t'. */-#define HAVE_UINTMAX_T 1--/* Define to 1 if you have the <unistd.h> header file. */-#define HAVE_UNISTD_H 1--/* Define to 1 if you have the `unlinkat' function. */-/* #undef HAVE_UNLINKAT */--/* Define to 1 if you have the `unsetenv' function. */-#define HAVE_UNSETENV 1--/* Define to 1 if the system has the type `unsigned long long'. */-#define HAVE_UNSIGNED_LONG_LONG 1--/* Define to 1 if the system has the type `unsigned long long int'. */-#define HAVE_UNSIGNED_LONG_LONG_INT 1--/* Define to 1 if you have the `utime' function. */-#define HAVE_UTIME 1--/* Define to 1 if you have the `utimensat' function. */-/* #undef HAVE_UTIMENSAT */--/* Define to 1 if you have the `utimes' function. */-/* #undef HAVE_UTIMES */--/* Define to 1 if you have the <utime.h> header file. */-#define HAVE_UTIME_H 1--/* Define to 1 if you have the `vfork' function. */-/* #undef HAVE_VFORK */--/* Define to 1 if you have the `vprintf' function. */-#define HAVE_VPRINTF 1--/* Define to 1 if you have the <wchar.h> header file. */-#define HAVE_WCHAR_H 1--/* Define to 1 if the system has the type `wchar_t'. */-#define HAVE_WCHAR_T 1--/* Define to 1 if you have the `wcrtomb' function. */-#define HAVE_WCRTOMB 1--/* Define to 1 if you have the `wcscmp' function. */-#define HAVE_WCSCMP 1--/* Define to 1 if you have the `wcscpy' function. */-#define HAVE_WCSCPY 1--/* Define to 1 if you have the `wcslen' function. */-#define HAVE_WCSLEN 1--/* Define to 1 if you have the `wctomb' function. */-#define HAVE_WCTOMB 1--/* Define to 1 if you have the <wctype.h> header file. */-#define HAVE_WCTYPE_H 1--/* Define to 1 if you have the <wincrypt.h> header file. */-#define HAVE_WINCRYPT_H 1--/* Define to 1 if you have the <windows.h> header file. */-#define HAVE_WINDOWS_H 1--/* Define to 1 if you have the <winioctl.h> header file. */-#define HAVE_WINIOCTL_H 1--/* Define to 1 if you have the `wmemcmp' function. */-#define HAVE_WMEMCMP 1--/* Define to 1 if you have the `wmemcpy' function. */-#define HAVE_WMEMCPY 1--/* Define to 1 if you have the `wmemmove' function. */-#define HAVE_WMEMMOVE 1--/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */-/* #undef HAVE_WORKING_EXT2_IOC_GETFLAGS */--/* Define to 1 if you have a working FS_IOC_GETFLAGS */-/* #undef HAVE_WORKING_FS_IOC_GETFLAGS */--/* Define to 1 if you have the <zlib.h> header file. */-/* #undef HAVE_ZLIB_H */--/* Define to 1 if you have the <zstd.h> header file. */-/* #undef HAVE_ZSTD_H */--/* Define to 1 if you have the `_fseeki64' function. */-#define HAVE__FSEEKI64 1--/* Define to 1 if you have the `_get_timezone' function. */-/* #undef HAVE__GET_TIMEZONE */--/* _mkgmtime function */-/* #undef HAVE__MKGMTIME */--/* Define as const if the declaration of iconv() needs const. */-/* #undef ICONV_CONST */--/* Version number of libarchive as a single integer */-#define LIBARCHIVE_VERSION_NUMBER "3007001"--/* Version number of libarchive */-#define LIBARCHIVE_VERSION_STRING "3.7.1"--/* Define to 1 if `lstat' dereferences a symlink specified with a trailing- slash. */-/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */--/* Define to the sub-directory where libtool stores uninstalled libraries. */-#define LT_OBJDIR ".libs/"--/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.- */-/* #undef MAJOR_IN_MKDEV */--/* Define to 1 if `major', `minor', and `makedev' are declared in- <sysmacros.h>. */-/* #undef MAJOR_IN_SYSMACROS */--/* Define to '0x05020000' for Windows Server 2003 APIs. */-#define NTDDI_VERSION 0x05020000--/* Name of package */-#define PACKAGE "libarchive"--/* Define to the address where bug reports for this package should be sent. */-#define PACKAGE_BUGREPORT "libarchive-discuss@googlegroups.com"--/* Define to the full name of this package. */-#define PACKAGE_NAME "libarchive"--/* Define to the full name and version of this package. */-#define PACKAGE_STRING "libarchive 3.7.1"--/* Define to the one symbol short name of this package. */-#define PACKAGE_TARNAME "libarchive"--/* Define to the home page for this package. */-#define PACKAGE_URL ""--/* Define to the version of this package. */-#define PACKAGE_VERSION "3.7.1"--/* Define to 1 if PCRE_STATIC needs to be defined. */-/* #undef PCRE_STATIC */--/* The number of bytes in type int */-#define SIZEOF_INT 4--/* The number of bytes in type long */-#define SIZEOF_LONG 4--/* The size of `wchar_t', as computed by sizeof. */-#define SIZEOF_WCHAR_T 2--/* Define to 1 if all of the C90 standard headers exist (not just the ones- required in a freestanding environment). This macro is provided for- backward compatibility; new code need not use it. */-#define STDC_HEADERS 1--/* Define to 1 if strerror_r returns char *. */-/* #undef STRERROR_R_CHAR_P */--/* Enable extensions on AIX 3, Interix. */-#ifndef _ALL_SOURCE-# define _ALL_SOURCE 1-#endif-/* Enable general extensions on macOS. */-#ifndef _DARWIN_C_SOURCE-# define _DARWIN_C_SOURCE 1-#endif-/* Enable general extensions on Solaris. */-#ifndef __EXTENSIONS__-# define __EXTENSIONS__ 1-#endif-/* Enable GNU extensions on systems that have them. */-#ifndef _GNU_SOURCE-# define _GNU_SOURCE 1-#endif-/* Enable X/Open compliant socket functions that do not require linking- with -lxnet on HP-UX 11.11. */-#ifndef _HPUX_ALT_XOPEN_SOCKET_API-# define _HPUX_ALT_XOPEN_SOCKET_API 1-#endif-/* Identify the host operating system as Minix.- This macro does not affect the system headers' behavior.- A future release of Autoconf may stop defining this macro. */-#ifndef _MINIX-/* # undef _MINIX */-#endif-/* Enable general extensions on NetBSD.- Enable NetBSD compatibility extensions on Minix. */-#ifndef _NETBSD_SOURCE-# define _NETBSD_SOURCE 1-#endif-/* Enable OpenBSD compatibility extensions on NetBSD.- Oddly enough, this does nothing on OpenBSD. */-#ifndef _OPENBSD_SOURCE-# define _OPENBSD_SOURCE 1-#endif-/* Define to 1 if needed for POSIX-compatible behavior. */-#ifndef _POSIX_SOURCE-/* # undef _POSIX_SOURCE */-#endif-/* Define to 2 if needed for POSIX-compatible behavior. */-#ifndef _POSIX_1_SOURCE-/* # undef _POSIX_1_SOURCE */-#endif-/* Enable POSIX-compatible threading on Solaris. */-#ifndef _POSIX_PTHREAD_SEMANTICS-# define _POSIX_PTHREAD_SEMANTICS 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */-#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__-# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */-#ifndef __STDC_WANT_IEC_60559_BFP_EXT__-# define __STDC_WANT_IEC_60559_BFP_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */-#ifndef __STDC_WANT_IEC_60559_DFP_EXT__-# define __STDC_WANT_IEC_60559_DFP_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */-#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__-# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */-#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__-# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1-#endif-/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */-#ifndef __STDC_WANT_LIB_EXT2__-# define __STDC_WANT_LIB_EXT2__ 1-#endif-/* Enable extensions specified by ISO/IEC 24747:2009. */-#ifndef __STDC_WANT_MATH_SPEC_FUNCS__-# define __STDC_WANT_MATH_SPEC_FUNCS__ 1-#endif-/* Enable extensions on HP NonStop. */-#ifndef _TANDEM_SOURCE-# define _TANDEM_SOURCE 1-#endif-/* Enable X/Open extensions. Define to 500 only if necessary- to make mbstate_t available. */-#ifndef _XOPEN_SOURCE-/* # undef _XOPEN_SOURCE */-#endif---/* Version number of package */-#define VERSION "3.7.1"--/* Define to '0x0502' for Windows Server 2003 APIs. */-#define WINVER 0x0502--/* Number of bits in a file offset, on hosts where this is settable. */-/* #undef _FILE_OFFSET_BITS */--/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */-/* #undef _LARGEFILE_SOURCE */--/* Define for large files, on AIX-style hosts. */-/* #undef _LARGE_FILES */--/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT32_T */--/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT64_T */--/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,- <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the- #define below would cause a syntax error. */-/* #undef _UINT8_T */--/* Define to '0x0502' for Windows Server 2003 APIs. */-#define _WIN32_WINNT 0x0502--/* Internal macro for sanity checks */-#define __LIBARCHIVE_CONFIG_H_INCLUDED 1--/* Define to empty if `const' does not conform to ANSI C. */-/* #undef const */--/* Define to match typeof st_gid field of struct stat if <sys/types.h> doesn't- define. */-#define gid_t short--/* Define to `unsigned long' if <sys/types.h> does not define. */-#define id_t unsigned long--/* Define to the type of a signed integer type of width exactly 16 bits if- such a type exists and the standard includes do not define it. */-/* #undef int16_t */--/* Define to the type of a signed integer type of width exactly 32 bits if- such a type exists and the standard includes do not define it. */-/* #undef int32_t */--/* Define to the type of a signed integer type of width exactly 64 bits if- such a type exists and the standard includes do not define it. */-/* #undef int64_t */--/* Define to the widest signed integer type if <stdint.h> and <inttypes.h> do- not define. */-/* #undef intmax_t */--/* Define to `int' if <sys/types.h> does not define. */-/* #undef mode_t */--/* Define to `long long' if <sys/types.h> does not define. */-/* #undef off_t */--/* Define to `unsigned int' if <sys/types.h> does not define. */-/* #undef size_t */--/* Define to match typeof st_uid field of struct stat if <sys/types.h> doesn't- define. */-#define uid_t short--/* Define to the type of an unsigned integer type of width exactly 16 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint16_t */--/* Define to the type of an unsigned integer type of width exactly 32 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint32_t */--/* Define to the type of an unsigned integer type of width exactly 64 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint64_t */--/* Define to the type of an unsigned integer type of width exactly 8 bits if- such a type exists and the standard includes do not define it. */-/* #undef uint8_t */--/* Define to the widest unsigned integer type if <stdint.h> and <inttypes.h>- do not define. */-/* #undef uintmax_t */--/* Define to `unsigned int' if <sys/types.h> does not define. */-/* #undef uintptr_t */-#define HAVE_LIBZ 1-#define HAVE_ZLIB_H 1
− c/config_freebsd.h
@@ -1,276 +0,0 @@-/*-- * Copyright (c) 2003-2007 Tim Kientzle- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- *- * $FreeBSD$- */-#define __LIBARCHIVE_CONFIG_H_INCLUDED 1--#include <osreldate.h>--/* FreeBSD 5.0 and later has ACL and extattr support. */-#if __FreeBSD__ > 4-#define ARCHIVE_ACL_FREEBSD 1-#define HAVE_ACL_GET_PERM_NP 1-#define HAVE_ARC4RANDOM_BUF 1-#define HAVE_EXTATTR_GET_FILE 1-#define HAVE_EXTATTR_LIST_FILE 1-#define HAVE_EXTATTR_SET_FD 1-#define HAVE_EXTATTR_SET_FILE 1-#define HAVE_STRUCT_XVFSCONF 1-#define HAVE_SYS_ACL_H 1-#define HAVE_SYS_EXTATTR_H 1-#if __FreeBSD__ > 7-/* FreeBSD 8.0 and later has NFSv4 ACL support */-#define ARCHIVE_ACL_FREEBSD_NFS4 1-#define HAVE_ACL_GET_LINK_NP 1-#define HAVE_ACL_IS_TRIVIAL_NP 1-#define HAVE_ACL_SET_LINK_NP 1-#endif /* __FreeBSD__ > 7 */-#endif /* __FreeBSD__ > 4 */--#ifdef WITH_OPENSSL-#define HAVE_LIBCRYPTO 1-#define HAVE_OPENSSL_EVP_H 1-#define HAVE_OPENSSL_MD5_H 1-#define HAVE_OPENSSL_RIPEMD_H 1-#define HAVE_OPENSSL_SHA_H 1-#define HAVE_OPENSSL_SHA256_INIT 1-#define HAVE_OPENSSL_SHA384_INIT 1-#define HAVE_OPENSSL_SHA512_INIT 1-#define HAVE_PKCS5_PBKDF2_HMAC_SHA1 1-#define HAVE_SHA256 1-#define HAVE_SHA384 1-#define HAVE_SHA512 1-#else-#define HAVE_LIBMD 1-#define HAVE_MD5_H 1-#define HAVE_MD5INIT 1-#define HAVE_RIPEMD_H 1-#define HAVE_SHA_H 1-#define HAVE_SHA1 1-#define HAVE_SHA1_INIT 1-#define HAVE_SHA256 1-#define HAVE_SHA256_H 1-#define HAVE_SHA256_INIT 1-#define HAVE_SHA512 1-#define HAVE_SHA512_H 1-#define HAVE_SHA512_INIT 1-#endif--#define HAVE_BSDXML_H 1-#define HAVE_BZLIB_H 1-#define HAVE_CHFLAGS 1-#define HAVE_CHOWN 1-#define HAVE_CHROOT 1-#define HAVE_CTIME_R 1-#define HAVE_CTYPE_H 1-#define HAVE_DECL_EXTATTR_NAMESPACE_USER 1-#define HAVE_DECL_INT32_MAX 1-#define HAVE_DECL_INT32_MIN 1-#define HAVE_DECL_INT64_MAX 1-#define HAVE_DECL_INT64_MIN 1-#define HAVE_DECL_INTMAX_MAX 1-#define HAVE_DECL_INTMAX_MIN 1-#define HAVE_DECL_SIZE_MAX 1-#define HAVE_DECL_SSIZE_MAX 1-#define HAVE_DECL_STRERROR_R 1-#define HAVE_DECL_UINT32_MAX 1-#define HAVE_DECL_UINT64_MAX 1-#define HAVE_DECL_UINTMAX_MAX 1-#define HAVE_DIRENT_H 1-#define HAVE_DLFCN_H 1-#define HAVE_D_MD_ORDER 1-#define HAVE_EFTYPE 1-#define HAVE_EILSEQ 1-#define HAVE_ERRNO_H 1-#define HAVE_FCHDIR 1-#define HAVE_FCHFLAGS 1-#define HAVE_FCHMOD 1-#define HAVE_FCHOWN 1-#define HAVE_FCNTL 1-#define HAVE_FCNTL_H 1-#define HAVE_FDOPENDIR 1-#define HAVE_FNMATCH 1-#define HAVE_FNMATCH_H 1-#define HAVE_FORK 1-#define HAVE_FSEEKO 1-#define HAVE_FSTAT 1-#define HAVE_FSTATAT 1-#define HAVE_FSTATFS 1-#define HAVE_FSTATVFS 1-#define HAVE_FTRUNCATE 1-#define HAVE_FUTIMES 1-#define HAVE_FUTIMESAT 1-#define HAVE_GETEUID 1-#define HAVE_GETGRGID_R 1-#define HAVE_GETGRNAM_R 1-#define HAVE_GETLINE 1-#define HAVE_GETOPT_OPTRESET 1-#define HAVE_GETPID 1-#define HAVE_GETPWNAM_R 1-#define HAVE_GETPWUID_R 1-#define HAVE_GETVFSBYNAME 1-#define HAVE_GMTIME_R 1-#define HAVE_GRP_H 1-#define HAVE_INTMAX_T 1-#define HAVE_INTTYPES_H 1-#define HAVE_LANGINFO_H 1-#define HAVE_LCHFLAGS 1-#define HAVE_LCHMOD 1-#define HAVE_LCHOWN 1-#define HAVE_LIBZ 1-#define HAVE_LIMITS_H 1-#define HAVE_LINK 1-#define HAVE_LINKAT 1-#define HAVE_LOCALE_H 1-#define HAVE_LOCALTIME_R 1-#define HAVE_LONG_LONG_INT 1-#define HAVE_LSTAT 1-#define HAVE_LUTIMES 1-#define HAVE_MBRTOWC 1-#define HAVE_MEMMOVE 1-#define HAVE_MEMORY_H 1-#define HAVE_MEMSET 1-#define HAVE_MKDIR 1-#define HAVE_MKFIFO 1-#define HAVE_MKNOD 1-#define HAVE_MKSTEMP 1-#define HAVE_NL_LANGINFO 1-#define HAVE_OPENAT 1-#define HAVE_PATHS_H 1-#define HAVE_PIPE 1-#define HAVE_POLL 1-#define HAVE_POLL_H 1-#define HAVE_POSIX_SPAWNP 1-#define HAVE_PTHREAD_H 1-#define HAVE_PWD_H 1-#define HAVE_READDIR_R 1-#define HAVE_READLINK 1-#define HAVE_READLINKAT 1-#define HAVE_READPASSPHRASE 1-#define HAVE_READPASSPHRASE_H 1-#define HAVE_REGEX_H 1-#define HAVE_SELECT 1-#define HAVE_SETENV 1-#define HAVE_SETLOCALE 1-#define HAVE_SIGACTION 1-#define HAVE_SIGNAL_H 1-#define HAVE_SPAWN_H 1-#define HAVE_STATFS 1-#define HAVE_STATVFS 1-#define HAVE_STDARG_H 1-#define HAVE_STDINT_H 1-#define HAVE_STDLIB_H 1-#define HAVE_STRCHR 1-#define HAVE_STRDUP 1-#define HAVE_STRERROR 1-#define HAVE_STRERROR_R 1-#define HAVE_STRFTIME 1-#define HAVE_STRINGS_H 1-#define HAVE_STRING_H 1-#define HAVE_STRNLEN 1-#define HAVE_STRRCHR 1-#define HAVE_STRUCT_STATFS_F_NAMEMAX 1-#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1-#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1-#define HAVE_STRUCT_STAT_ST_BLKSIZE 1-#define HAVE_STRUCT_STAT_ST_FLAGS 1-#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1-#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1-#define HAVE_STRUCT_TM_TM_GMTOFF 1-#define HAVE_SYMLINK 1-#define HAVE_SYS_CDEFS_H 1-#define HAVE_SYS_IOCTL_H 1-#define HAVE_SYS_MOUNT_H 1-#define HAVE_SYS_PARAM_H 1-#define HAVE_SYS_POLL_H 1-#define HAVE_SYS_QUEUE_H 1-#define HAVE_SYS_SELECT_H 1-#define HAVE_SYS_STATVFS_H 1-#define HAVE_SYS_STAT_H 1-#define HAVE_SYS_TIME_H 1-#define HAVE_SYS_TYPES_H 1-#define HAVE_SYS_UTSNAME_H 1-#define HAVE_SYS_WAIT_H 1-#define HAVE_TIMEGM 1-#define HAVE_TIME_H 1-#define HAVE_TZSET 1-#define HAVE_UINTMAX_T 1-#define HAVE_UNISTD_H 1-#define HAVE_UNLINKAT 1-#define HAVE_UNSETENV 1-#define HAVE_UNSIGNED_LONG_LONG 1-#define HAVE_UNSIGNED_LONG_LONG_INT 1-#define HAVE_UTIME 1-#define HAVE_UTIMES 1-#define HAVE_UTIME_H 1-#define HAVE_VFORK 1-#define HAVE_VPRINTF 1-#define HAVE_WCHAR_H 1-#define HAVE_WCHAR_T 1-#define HAVE_WCRTOMB 1-#define HAVE_WCSCMP 1-#define HAVE_WCSCPY 1-#define HAVE_WCSLEN 1-#define HAVE_WCTOMB 1-#define HAVE_WCTYPE_H 1-#define HAVE_WMEMCMP 1-#define HAVE_WMEMCPY 1-#define HAVE_WMEMMOVE 1-#define HAVE_ZLIB_H 1-#define HAVE_SYS_TIME_H 1--#if __FreeBSD_version >= 800505-#define HAVE_LIBLZMA 1-#define HAVE_LZMA_H 1-#if __FreeBSD_version >= 1002504-#define HAVE_LZMA_STREAM_ENCODER_MT 1-#endif-#endif--#if __FreeBSD_version >= 1100056-#define HAVE_FUTIMENS 1-#define HAVE_UTIMENSAT 1-#endif--/* FreeBSD 4 and earlier lack intmax_t/uintmax_t */-#if __FreeBSD__ < 5-#define intmax_t int64_t-#define uintmax_t uint64_t-#endif--/* FreeBSD defines for archive_hash.h */-#ifdef WITH_OPENSSL-#define ARCHIVE_CRYPTO_MD5_OPENSSL 1-#define ARCHIVE_CRYPTO_RMD160_OPENSSL 1-#define ARCHIVE_CRYPTO_SHA1_OPENSSL-#define ARCHIVE_CRYPTO_SHA256_OPENSSL 1-#define ARCHIVE_CRYPTO_SHA384_OPENSSL 1-#define ARCHIVE_CRYPTO_SHA512_OPENSSL 1-#else-#define ARCHIVE_CRYPTO_MD5_LIBMD 1-#define ARCHIVE_CRYPTO_SHA1_LIBMD 1-#define ARCHIVE_CRYPTO_SHA256_LIBMD 1-#define ARCHIVE_CRYPTO_SHA512_LIBMD 1-#endif
− c/filter_fork.h
@@ -1,46 +0,0 @@-/*-- * 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.- *- * $FreeBSD: head/lib/libarchive/filter_fork.h 201087 2009-12-28 02:18:26Z kientzle $- */--#ifndef FILTER_FORK_H-#define FILTER_FORK_H--#ifndef __LIBARCHIVE_BUILD-#error This header is only to be used internally to libarchive.-#endif--int-__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,-#if defined(_WIN32) && !defined(__CYGWIN__)- HANDLE *out_child);-#else- pid_t *out_child);-#endif--void-__archive_check_child(int in, int out);--#endif
− c/filter_fork_posix.c
@@ -1,240 +0,0 @@-/*-- * Copyright (c) 2007 Joerg Sonnenberger- * Copyright (c) 2012 Michihiro NAKAJIMA - * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--/* This capability is only available on POSIX systems. */-#if defined(HAVE_PIPE) && defined(HAVE_FCNTL) && \- (defined(HAVE_FORK) || defined(HAVE_VFORK) || defined(HAVE_POSIX_SPAWNP))--__FBSDID("$FreeBSD: head/lib/libarchive/filter_fork.c 182958 2008-09-12 05:33:00Z kientzle $");--#if defined(HAVE_SYS_TYPES_H)-# include <sys/types.h>-#endif-#ifdef HAVE_ERRNO_H-# include <errno.h>-#endif-#ifdef HAVE_STRING_H-# include <string.h>-#endif-#if defined(HAVE_POLL) && (defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H))-# if defined(HAVE_POLL_H)-# include <poll.h>-# elif defined(HAVE_SYS_POLL_H)-# include <sys/poll.h>-# endif-#elif defined(HAVE_SELECT)-# if defined(HAVE_SYS_SELECT_H)-# include <sys/select.h>-# elif defined(HAVE_UNISTD_H)-# include <unistd.h>-# endif-#endif-#ifdef HAVE_FCNTL_H-# include <fcntl.h>-#endif-#ifdef HAVE_SPAWN_H-# include <spawn.h>-#endif-#ifdef HAVE_STDLIB_H-# include <stdlib.h>-#endif-#ifdef HAVE_UNISTD_H-# include <unistd.h>-#endif--#include "archive.h"-#include "archive_cmdline_private.h"--#include "filter_fork.h"--int-__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,- pid_t *out_child)-{- pid_t child = -1;- int stdin_pipe[2], stdout_pipe[2], tmp;-#if HAVE_POSIX_SPAWNP- posix_spawn_file_actions_t actions;- int r;-#endif- struct archive_cmdline *cmdline;-- cmdline = __archive_cmdline_allocate();- if (cmdline == NULL)- goto state_allocated;- if (__archive_cmdline_parse(cmdline, cmd) != ARCHIVE_OK)- goto state_allocated;-- if (pipe(stdin_pipe) == -1)- goto state_allocated;- if (stdin_pipe[0] == 1 /* stdout */) {- if ((tmp = dup(stdin_pipe[0])) == -1)- goto stdin_opened;- close(stdin_pipe[0]);- stdin_pipe[0] = tmp;- }- if (pipe(stdout_pipe) == -1)- goto stdin_opened;- if (stdout_pipe[1] == 0 /* stdin */) {- if ((tmp = dup(stdout_pipe[1])) == -1)- goto stdout_opened;- close(stdout_pipe[1]);- stdout_pipe[1] = tmp;- }--#if HAVE_POSIX_SPAWNP-- r = posix_spawn_file_actions_init(&actions);- if (r != 0) {- errno = r;- goto stdout_opened;- }- r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[1]);- if (r != 0)- goto actions_inited;- r = posix_spawn_file_actions_addclose(&actions, stdout_pipe[0]);- if (r != 0)- goto actions_inited;- /* Setup for stdin. */- r = posix_spawn_file_actions_adddup2(&actions, stdin_pipe[0], 0);- if (r != 0)- goto actions_inited;- if (stdin_pipe[0] != 0 /* stdin */) {- r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[0]);- if (r != 0)- goto actions_inited;- }- /* Setup for stdout. */- r = posix_spawn_file_actions_adddup2(&actions, stdout_pipe[1], 1);- if (r != 0)- goto actions_inited;- if (stdout_pipe[1] != 1 /* stdout */) {- r = posix_spawn_file_actions_addclose(&actions, stdout_pipe[1]);- if (r != 0)- goto actions_inited;- }- r = posix_spawnp(&child, cmdline->path, &actions, NULL,- cmdline->argv, NULL);- if (r != 0)- goto actions_inited;- posix_spawn_file_actions_destroy(&actions);--#else /* HAVE_POSIX_SPAWNP */--#if HAVE_VFORK- child = vfork();-#else- child = fork();-#endif- if (child == -1)- goto stdout_opened;- if (child == 0) {- close(stdin_pipe[1]);- close(stdout_pipe[0]);- if (dup2(stdin_pipe[0], 0 /* stdin */) == -1)- _exit(254);- if (stdin_pipe[0] != 0 /* stdin */)- close(stdin_pipe[0]);- if (dup2(stdout_pipe[1], 1 /* stdout */) == -1)- _exit(254);- if (stdout_pipe[1] != 1 /* stdout */)- close(stdout_pipe[1]);- execvp(cmdline->path, cmdline->argv);- _exit(254);- }-#endif /* HAVE_POSIX_SPAWNP */-- close(stdin_pipe[0]);- close(stdout_pipe[1]);-- *child_stdin = stdin_pipe[1];- fcntl(*child_stdin, F_SETFL, O_NONBLOCK);- *child_stdout = stdout_pipe[0];- fcntl(*child_stdout, F_SETFL, O_NONBLOCK);- __archive_cmdline_free(cmdline);-- *out_child = child;- return ARCHIVE_OK;--#if HAVE_POSIX_SPAWNP-actions_inited:- errno = r;- posix_spawn_file_actions_destroy(&actions);-#endif-stdout_opened:- close(stdout_pipe[0]);- close(stdout_pipe[1]);-stdin_opened:- close(stdin_pipe[0]);- close(stdin_pipe[1]);-state_allocated:- __archive_cmdline_free(cmdline);- return ARCHIVE_FAILED;-}--void-__archive_check_child(int in, int out)-{-#if defined(HAVE_POLL) && (defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H))- struct pollfd fds[2];- int idx;-- idx = 0;- if (in != -1) {- fds[idx].fd = in;- fds[idx].events = POLLOUT;- ++idx;- }- if (out != -1) {- fds[idx].fd = out;- fds[idx].events = POLLIN;- ++idx;- }-- poll(fds, idx, -1); /* -1 == INFTIM, wait forever */-#elif defined(HAVE_SELECT)- fd_set fds_in, fds_out, fds_error;-- FD_ZERO(&fds_in);- FD_ZERO(&fds_out);- FD_ZERO(&fds_error);- if (out != -1) {- FD_SET(out, &fds_in);- FD_SET(out, &fds_error);- }- if (in != -1) {- FD_SET(in, &fds_out);- FD_SET(in, &fds_error);- }- select(in < out ? out + 1 : in + 1, &fds_in, &fds_out, &fds_error, NULL);-#else- sleep(1);-#endif-}--#endif /* defined(HAVE_PIPE) && defined(HAVE_VFORK) && defined(HAVE_FCNTL) */
− c/filter_fork_windows.c
@@ -1,245 +0,0 @@-/*-- * Copyright (c) 2009-2012 Michihiro NAKAJIMA- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or without- * modification, are permitted provided that the following conditions- * are met:- * 1. Redistributions of source code must retain the above copyright- * notice, this list of conditions and the following disclaimer.- * 2. Redistributions in binary form must reproduce the above copyright- * notice, this list of conditions and the following disclaimer in the- * documentation and/or other materials provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.- */--#include "archive_platform.h"--#if defined(_WIN32) && !defined(__CYGWIN__)-#include "archive_cmdline_private.h"-#include "archive_string.h"--#include "filter_fork.h"--#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)-/* There are some editions of Windows ("nano server," for example) that- * do not host user32.dll. If we want to keep running on those editions,- * we need to delay-load WaitForInputIdle. */-static void *-la_GetFunctionUser32(const char *name)-{- static HINSTANCE lib;- static int set;- if (!set) {- set = 1;- lib = LoadLibrary(TEXT("user32.dll"));- }- if (lib == NULL) {- return NULL;- }- return (void *)GetProcAddress(lib, name);-}--static int-la_WaitForInputIdle(HANDLE hProcess, DWORD dwMilliseconds)-{- static DWORD (WINAPI *f)(HANDLE, DWORD);- static int set;-- if (!set) {- set = 1;- f = la_GetFunctionUser32("WaitForInputIdle");- }-- if (!f) {- /* An inability to wait for input idle is- * not _good_, but it is not catastrophic. */- return WAIT_FAILED;- }- return (*f)(hProcess, dwMilliseconds);-}--int-__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,- HANDLE *out_child)-{- HANDLE childStdout[2], childStdin[2],childStderr;- SECURITY_ATTRIBUTES secAtts;- STARTUPINFOA staInfo;- PROCESS_INFORMATION childInfo;- struct archive_string cmdline;- struct archive_string fullpath;- struct archive_cmdline *acmd;- char *arg0, *ext;- int i, l;- DWORD fl, fl_old;- HANDLE child;-- childStdout[0] = childStdout[1] = INVALID_HANDLE_VALUE;- childStdin[0] = childStdin[1] = INVALID_HANDLE_VALUE;- childStderr = INVALID_HANDLE_VALUE;- archive_string_init(&cmdline);- archive_string_init(&fullpath);-- acmd = __archive_cmdline_allocate();- if (acmd == NULL)- goto fail;- if (__archive_cmdline_parse(acmd, cmd) != ARCHIVE_OK)- goto fail;-- /*- * Search the full path of 'path'.- * NOTE: This does not need if we give CreateProcessA 'path' as- * a part of the cmdline and give CreateProcessA NULL as first- * parameter, but I do not like that way.- */- ext = strrchr(acmd->path, '.');- if (ext == NULL || strlen(ext) > 4)- /* 'path' does not have a proper extension, so we have to- * give SearchPath() ".exe" as the extension. */- ext = ".exe";- else- ext = NULL;/* 'path' has an extension. */-- fl = MAX_PATH;- do {- if (archive_string_ensure(&fullpath, fl) == NULL)- goto fail;- fl_old = fl;- fl = SearchPathA(NULL, acmd->path, ext, fl, fullpath.s,- &arg0);- } while (fl != 0 && fl > fl_old);- if (fl == 0)- goto fail;-- /*- * Make a command line.- */- for (l = 0, i = 0; acmd->argv[i] != NULL; i++) {- if (i == 0)- continue;- l += (int)strlen(acmd->argv[i]) + 1;- }- if (archive_string_ensure(&cmdline, l + 1) == NULL)- goto fail;- for (i = 0; acmd->argv[i] != NULL; i++) {- if (i == 0) {- const char *p, *sp;-- if ((p = strchr(acmd->argv[i], '/')) != NULL ||- (p = strchr(acmd->argv[i], '\\')) != NULL)- p++;- else- p = acmd->argv[i];- if ((sp = strchr(p, ' ')) != NULL)- archive_strappend_char(&cmdline, '"');- archive_strcat(&cmdline, p);- if (sp != NULL)- archive_strappend_char(&cmdline, '"');- } else {- archive_strappend_char(&cmdline, ' ');- archive_strcat(&cmdline, acmd->argv[i]);- }- }- if (i <= 1) {- const char *sp;-- if ((sp = strchr(arg0, ' ')) != NULL)- archive_strappend_char(&cmdline, '"');- archive_strcat(&cmdline, arg0);- if (sp != NULL)- archive_strappend_char(&cmdline, '"');- }-- secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);- secAtts.bInheritHandle = TRUE;- secAtts.lpSecurityDescriptor = NULL;- if (CreatePipe(&childStdout[0], &childStdout[1], &secAtts, 0) == 0)- goto fail;- if (!SetHandleInformation(childStdout[0], HANDLE_FLAG_INHERIT, 0))- goto fail;- if (CreatePipe(&childStdin[0], &childStdin[1], &secAtts, 0) == 0)- goto fail;- if (!SetHandleInformation(childStdin[1], HANDLE_FLAG_INHERIT, 0))- goto fail;- if (DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE),- GetCurrentProcess(), &childStderr, 0, TRUE,- DUPLICATE_SAME_ACCESS) == 0)- goto fail;-- memset(&staInfo, 0, sizeof(staInfo));- staInfo.cb = sizeof(staInfo);- staInfo.hStdError = childStderr;- staInfo.hStdOutput = childStdout[1];- staInfo.hStdInput = childStdin[0];- staInfo.wShowWindow = SW_HIDE;- staInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;- if (CreateProcessA(fullpath.s, cmdline.s, NULL, NULL, TRUE, 0,- NULL, NULL, &staInfo, &childInfo) == 0)- goto fail;- la_WaitForInputIdle(childInfo.hProcess, INFINITE);- CloseHandle(childInfo.hProcess);- CloseHandle(childInfo.hThread);-- *child_stdout = _open_osfhandle((intptr_t)childStdout[0], _O_RDONLY);- *child_stdin = _open_osfhandle((intptr_t)childStdin[1], _O_WRONLY);- - child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,- childInfo.dwProcessId);- if (child == NULL) // INVALID_HANDLE_VALUE ?- goto fail;-- *out_child = child;-- CloseHandle(childStdout[1]);- CloseHandle(childStdin[0]);-- archive_string_free(&cmdline);- archive_string_free(&fullpath);- __archive_cmdline_free(acmd);- return ARCHIVE_OK;--fail:- if (childStdout[0] != INVALID_HANDLE_VALUE)- CloseHandle(childStdout[0]);- if (childStdout[1] != INVALID_HANDLE_VALUE)- CloseHandle(childStdout[1]);- if (childStdin[0] != INVALID_HANDLE_VALUE)- CloseHandle(childStdin[0]);- if (childStdin[1] != INVALID_HANDLE_VALUE)- CloseHandle(childStdin[1]);- if (childStderr != INVALID_HANDLE_VALUE)- CloseHandle(childStderr);- archive_string_free(&cmdline);- archive_string_free(&fullpath);- __archive_cmdline_free(acmd);- return ARCHIVE_FAILED;-}-#else /* !WINAPI_PARTITION_DESKTOP */-int-__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, HANDLE *out_child)-{- (void)cmd; (void)child_stdin; (void) child_stdout; (void) out_child;- return ARCHIVE_FAILED;-}-#endif /* !WINAPI_PARTITION_DESKTOP */--void-__archive_check_child(int in, int out)-{- (void)in; /* UNUSED */- (void)out; /* UNUSED */- Sleep(100);-}--#endif /* _WIN32 && !__CYGWIN__ */
− c/xxhash.c
@@ -1,529 +0,0 @@-/*-xxHash - Fast Hash algorithm-Copyright (C) 2012-2014, Yann Collet.-BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are-met:--* Redistributions of source code must retain the above copyright-notice, this list of conditions and the following disclaimer.-* 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 COPYRIGHT HOLDERS AND CONTRIBUTORS-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.--You can contact the author at :-- xxHash source repository : http://code.google.com/p/xxhash/-*/-#include "archive_platform.h"--#include <stdlib.h>-#include <string.h>--#include "archive_xxhash.h"--#ifdef HAVE_LIBLZ4--/***************************************-** Tuning parameters-****************************************/-/* Unaligned memory access is automatically enabled for "common" CPU, such as x86.-** For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected.-** If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance.-** You can also enable this parameter if you know your input data will always be aligned (boundaries of 4, for U32).-*/-#if defined(__ARM_FEATURE_UNALIGNED) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)-# define XXH_USE_UNALIGNED_ACCESS 1-#endif--/* XXH_ACCEPT_NULL_INPUT_POINTER :-** If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.-** When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.-** This option has a very small performance cost (only measurable on small inputs).-** By default, this option is disabled. To enable it, uncomment below define :-** #define XXH_ACCEPT_NULL_INPUT_POINTER 1--** XXH_FORCE_NATIVE_FORMAT :-** By default, xxHash library provides endian-independent Hash values, based on little-endian convention.-** Results are therefore identical for little-endian and big-endian CPU.-** This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.-** Should endian-independence be of no importance for your application, you may set the #define below to 1.-** It will improve speed for Big-endian CPU.-** This option has no impact on Little_Endian CPU.-*/-#define XXH_FORCE_NATIVE_FORMAT 0--/***************************************-** Compiler Specific Options-****************************************/-/* Disable some Visual warning messages */-#ifdef _MSC_VER /* Visual Studio */-# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */-#endif--#ifdef _MSC_VER /* Visual Studio */-# define FORCE_INLINE __forceinline-#else-# ifdef __GNUC__-# define FORCE_INLINE inline __attribute__((always_inline))-# else-# define FORCE_INLINE inline-# endif-#endif--/***************************************-** Includes & Memory related functions-****************************************/-#define XXH_malloc malloc-#define XXH_free free-#define XXH_memcpy memcpy---static unsigned int XXH32 (const void*, unsigned int, unsigned int);-static void* XXH32_init (unsigned int);-static XXH_errorcode XXH32_update (void*, const void*, unsigned int);-static unsigned int XXH32_digest (void*);-/*static int XXH32_sizeofState(void);*/-static XXH_errorcode XXH32_resetState(void*, unsigned int);-#define XXH32_SIZEOFSTATE 48-typedef struct { long long ll[(XXH32_SIZEOFSTATE+(sizeof(long long)-1))/sizeof(long long)]; } XXH32_stateSpace_t;-static unsigned int XXH32_intermediateDigest (void*);--/***************************************-** Basic Types-****************************************/-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */-# include <stdint.h>- typedef uint8_t BYTE;- typedef uint16_t U16;- typedef uint32_t U32;- typedef int32_t S32;- typedef uint64_t U64;-#else- typedef unsigned char BYTE;- typedef unsigned short U16;- typedef unsigned int U32;- typedef signed int S32;- typedef unsigned long long U64;-#endif--#if defined(__GNUC__) && !defined(XXH_USE_UNALIGNED_ACCESS)-# define _PACKED __attribute__ ((packed))-#else-# define _PACKED-#endif--#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__)-# ifdef __IBMC__-# pragma pack(1)-# else-# pragma pack(push, 1)-# endif-#endif--typedef struct _U32_S { U32 v; } _PACKED U32_S;--#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__)-# pragma pack(pop)-#endif---/****************************************-** Compiler-specific Functions and Macros-*****************************************/-#define GCC_VERSION ((__GNUC__-0) * 100 + (__GNUC_MINOR__ - 0))--#if GCC_VERSION >= 409-__attribute__((__no_sanitize_undefined__))-#else-# if defined(__clang__)-__attribute__((no_sanitize("undefined")))-# endif-#endif-#if defined(_MSC_VER)-static __inline U32 A32(const void * x)-#else-static inline U32 A32(const void* x)-#endif-{- return (((const U32_S *)(x))->v);-}--/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */-#if defined(_MSC_VER)-# define XXH_rotl32(x,r) _rotl(x,r)-#else-# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))-#endif--#if defined(_MSC_VER) /* Visual Studio */-# define XXH_swap32 _byteswap_ulong-#elif GCC_VERSION >= 403-# define XXH_swap32 __builtin_bswap32-#else-static inline U32 XXH_swap32 (U32 x) {- return ((x << 24) & 0xff000000 ) |- ((x << 8) & 0x00ff0000 ) |- ((x >> 8) & 0x0000ff00 ) |- ((x >> 24) & 0x000000ff );}-#endif---/***************************************-** Constants-****************************************/-#define PRIME32_1 2654435761U-#define PRIME32_2 2246822519U-#define PRIME32_3 3266489917U-#define PRIME32_4 668265263U-#define PRIME32_5 374761393U---/***************************************-** Architecture Macros-****************************************/-typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;-#ifndef XXH_CPU_LITTLE_ENDIAN /* It is possible to define XXH_CPU_LITTLE_ENDIAN externally, for example using a compiler switch */- static const int one = 1;-# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&one))-#endif---/***************************************-** Macros-****************************************/-#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(!!(c)) }; } /* use only *after* variable declarations */---/*****************************-** Memory reads-******************************/-typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;--static-FORCE_INLINE U32 XXH_readLE32_align(const U32* ptr, XXH_endianess endian, XXH_alignment align)-{- if (align==XXH_unaligned)- return endian==XXH_littleEndian ? A32(ptr) : XXH_swap32(A32(ptr));- else- return endian==XXH_littleEndian ? *ptr : XXH_swap32(*ptr);-}--static-FORCE_INLINE U32 XXH_readLE32(const U32* ptr, XXH_endianess endian) { return XXH_readLE32_align(ptr, endian, XXH_unaligned); }---/*****************************-** Simple Hash Functions-******************************/-static-FORCE_INLINE U32 XXH32_endian_align(const void* input, unsigned int len, U32 seed, XXH_endianess endian, XXH_alignment align)-{- const BYTE* p = (const BYTE*)input;- const BYTE* bEnd = p + len;- U32 h32;-#define XXH_get32bits(p) XXH_readLE32_align((const U32*)p, endian, align)--#ifdef XXH_ACCEPT_NULL_INPUT_POINTER- if (p==NULL) { len=0; bEnd=p=(const BYTE*)(size_t)16; }-#endif-- if (len>=16)- {- const BYTE* const limit = bEnd - 16;- U32 v1 = seed + PRIME32_1 + PRIME32_2;- U32 v2 = seed + PRIME32_2;- U32 v3 = seed + 0;- U32 v4 = seed - PRIME32_1;-- do- {- v1 += XXH_get32bits(p) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4;- v2 += XXH_get32bits(p) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4;- v3 += XXH_get32bits(p) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4;- v4 += XXH_get32bits(p) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4;- } while (p<=limit);-- h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);- }- else- {- h32 = seed + PRIME32_5;- }-- h32 += (U32) len;-- while (p<=bEnd-4)- {- h32 += XXH_get32bits(p) * PRIME32_3;- h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;- p+=4;- }-- while (p<bEnd)- {- h32 += (*p) * PRIME32_5;- h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;- p++;- }-- h32 ^= h32 >> 15;- h32 *= PRIME32_2;- h32 ^= h32 >> 13;- h32 *= PRIME32_3;- h32 ^= h32 >> 16;-- return h32;-}---U32 XXH32(const void* input, unsigned int len, U32 seed)-{-#if 0- // Simple version, good for code maintenance, but unfortunately slow for small inputs- void* state = XXH32_init(seed);- XXH32_update(state, input, len);- return XXH32_digest(state);-#else- XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;--# if !defined(XXH_USE_UNALIGNED_ACCESS)- if ((((size_t)input) & 3) == 0) /* Input is aligned, let's leverage the speed advantage */- {- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)- return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);- else- return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);- }-# endif-- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)- return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);- else- return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);-#endif-}--/*****************************-** Advanced Hash Functions-******************************/--struct XXH_state32_t-{- U64 total_len;- U32 seed;- U32 v1;- U32 v2;- U32 v3;- U32 v4;- int memsize;- char memory[16];-};--#if 0-static-int XXH32_sizeofState(void)-{- XXH_STATIC_ASSERT(XXH32_SIZEOFSTATE >= sizeof(struct XXH_state32_t)); /* A compilation error here means XXH32_SIZEOFSTATE is not large enough */- return sizeof(struct XXH_state32_t);-}-#endif--static-XXH_errorcode XXH32_resetState(void* state_in, U32 seed)-{- struct XXH_state32_t * state = (struct XXH_state32_t *) state_in;- state->seed = seed;- state->v1 = seed + PRIME32_1 + PRIME32_2;- state->v2 = seed + PRIME32_2;- state->v3 = seed + 0;- state->v4 = seed - PRIME32_1;- state->total_len = 0;- state->memsize = 0;- return XXH_OK;-}--static-void* XXH32_init (U32 seed)-{- void* state = XXH_malloc (sizeof(struct XXH_state32_t));- XXH32_resetState(state, seed);- return state;-}--static-FORCE_INLINE XXH_errorcode XXH32_update_endian (void* state_in, const void* input, int len, XXH_endianess endian)-{- struct XXH_state32_t * state = (struct XXH_state32_t *) state_in;- const BYTE* p = (const BYTE*)input;- const BYTE* const bEnd = p + len;--#ifdef XXH_ACCEPT_NULL_INPUT_POINTER- if (input==NULL) return XXH_ERROR;-#endif-- state->total_len += len;-- if (state->memsize + len < 16) /* fill in tmp buffer */- {- XXH_memcpy(state->memory + state->memsize, input, len);- state->memsize += len;- return XXH_OK;- }-- if (state->memsize) /* some data left from previous update */- {- XXH_memcpy(state->memory + state->memsize, input, 16-state->memsize);- {- const U32* p32 = (const U32*)state->memory;- state->v1 += XXH_readLE32(p32, endian) * PRIME32_2; state->v1 = XXH_rotl32(state->v1, 13); state->v1 *= PRIME32_1; p32++;- state->v2 += XXH_readLE32(p32, endian) * PRIME32_2; state->v2 = XXH_rotl32(state->v2, 13); state->v2 *= PRIME32_1; p32++;- state->v3 += XXH_readLE32(p32, endian) * PRIME32_2; state->v3 = XXH_rotl32(state->v3, 13); state->v3 *= PRIME32_1; p32++;- state->v4 += XXH_readLE32(p32, endian) * PRIME32_2; state->v4 = XXH_rotl32(state->v4, 13); state->v4 *= PRIME32_1; p32++;- }- p += 16-state->memsize;- state->memsize = 0;- }-- if (p <= bEnd-16)- {- const BYTE* const limit = bEnd - 16;- U32 v1 = state->v1;- U32 v2 = state->v2;- U32 v3 = state->v3;- U32 v4 = state->v4;-- do- {- v1 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4;- v2 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4;- v3 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4;- v4 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4;- } while (p<=limit);-- state->v1 = v1;- state->v2 = v2;- state->v3 = v3;- state->v4 = v4;- }-- if (p < bEnd)- {- XXH_memcpy(state->memory, p, bEnd-p);- state->memsize = (int)(bEnd-p);- }-- return XXH_OK;-}--static-XXH_errorcode XXH32_update (void* state_in, const void* input, unsigned int len)-{- XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;-- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)- return XXH32_update_endian(state_in, input, len, XXH_littleEndian);- else- return XXH32_update_endian(state_in, input, len, XXH_bigEndian);-}----static-FORCE_INLINE U32 XXH32_intermediateDigest_endian (void* state_in, XXH_endianess endian)-{- struct XXH_state32_t * state = (struct XXH_state32_t *) state_in;- const BYTE * p = (const BYTE*)state->memory;- BYTE* bEnd = (BYTE*)state->memory + state->memsize;- U32 h32;-- if (state->total_len >= 16)- {- h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);- }- else- {- h32 = state->seed + PRIME32_5;- }-- h32 += (U32) state->total_len;-- while (p<=bEnd-4)- {- h32 += XXH_readLE32((const U32*)p, endian) * PRIME32_3;- h32 = XXH_rotl32(h32, 17) * PRIME32_4;- p+=4;- }-- while (p<bEnd)- {- h32 += (*p) * PRIME32_5;- h32 = XXH_rotl32(h32, 11) * PRIME32_1;- p++;- }-- h32 ^= h32 >> 15;- h32 *= PRIME32_2;- h32 ^= h32 >> 13;- h32 *= PRIME32_3;- h32 ^= h32 >> 16;-- return h32;-}--static-U32 XXH32_intermediateDigest (void* state_in)-{- XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;-- if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)- return XXH32_intermediateDigest_endian(state_in, XXH_littleEndian);- else- return XXH32_intermediateDigest_endian(state_in, XXH_bigEndian);-}--static-U32 XXH32_digest (void* state_in)-{- U32 h32 = XXH32_intermediateDigest(state_in);-- XXH_free(state_in);-- return h32;-}--const-struct archive_xxhash __archive_xxhash = {- XXH32,- XXH32_init,- XXH32_update,- XXH32_digest-};-#else--/*- * Define an empty version of the struct if we aren't using the LZ4 library.- */-const-struct archive_xxhash __archive_xxhash = {- NULL,- NULL,- NULL,- NULL-};--#endif /* HAVE_LIBLZ4 */
− c/zlib/adler32.c
@@ -1,186 +0,0 @@-/* adler32.c -- compute the Adler-32 checksum of a data stream- * Copyright (C) 1995-2011, 2016 Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/* @(#) $Id$ */--#include "zutil.h"--local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));--#define BASE 65521U /* largest prime smaller than 65536 */-#define NMAX 5552-/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */--#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}-#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);-#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);-#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);-#define DO16(buf) DO8(buf,0); DO8(buf,8);--/* use NO_DIVIDE if your processor does not do division in hardware --- try it both ways to see which is faster */-#ifdef NO_DIVIDE-/* note that this assumes BASE is 65521, where 65536 % 65521 == 15- (thank you to John Reiser for pointing this out) */-# define CHOP(a) \- do { \- unsigned long tmp = a >> 16; \- a &= 0xffffUL; \- a += (tmp << 4) - tmp; \- } while (0)-# define MOD28(a) \- do { \- CHOP(a); \- if (a >= BASE) a -= BASE; \- } while (0)-# define MOD(a) \- do { \- CHOP(a); \- MOD28(a); \- } while (0)-# define MOD63(a) \- do { /* this assumes a is not negative */ \- z_off64_t tmp = a >> 32; \- a &= 0xffffffffL; \- a += (tmp << 8) - (tmp << 5) + tmp; \- tmp = a >> 16; \- a &= 0xffffL; \- a += (tmp << 4) - tmp; \- tmp = a >> 16; \- a &= 0xffffL; \- a += (tmp << 4) - tmp; \- if (a >= BASE) a -= BASE; \- } while (0)-#else-# define MOD(a) a %= BASE-# define MOD28(a) a %= BASE-# define MOD63(a) a %= BASE-#endif--/* ========================================================================= */-uLong ZEXPORT adler32_z(adler, buf, len)- uLong adler;- const Bytef *buf;- z_size_t len;-{- unsigned long sum2;- unsigned n;-- /* split Adler-32 into component sums */- sum2 = (adler >> 16) & 0xffff;- adler &= 0xffff;-- /* in case user likes doing a byte at a time, keep it fast */- if (len == 1) {- adler += buf[0];- if (adler >= BASE)- adler -= BASE;- sum2 += adler;- if (sum2 >= BASE)- sum2 -= BASE;- return adler | (sum2 << 16);- }-- /* initial Adler-32 value (deferred check for len == 1 speed) */- if (buf == Z_NULL)- return 1L;-- /* in case short lengths are provided, keep it somewhat fast */- if (len < 16) {- while (len--) {- adler += *buf++;- sum2 += adler;- }- if (adler >= BASE)- adler -= BASE;- MOD28(sum2); /* only added so many BASE's */- return adler | (sum2 << 16);- }-- /* do length NMAX blocks -- requires just one modulo operation */- while (len >= NMAX) {- len -= NMAX;- n = NMAX / 16; /* NMAX is divisible by 16 */- do {- DO16(buf); /* 16 sums unrolled */- buf += 16;- } while (--n);- MOD(adler);- MOD(sum2);- }-- /* do remaining bytes (less than NMAX, still just one modulo) */- if (len) { /* avoid modulos if none remaining */- while (len >= 16) {- len -= 16;- DO16(buf);- buf += 16;- }- while (len--) {- adler += *buf++;- sum2 += adler;- }- MOD(adler);- MOD(sum2);- }-- /* return recombined sums */- return adler | (sum2 << 16);-}--/* ========================================================================= */-uLong ZEXPORT adler32(adler, buf, len)- uLong adler;- const Bytef *buf;- uInt len;-{- return adler32_z(adler, buf, len);-}--/* ========================================================================= */-local uLong adler32_combine_(adler1, adler2, len2)- uLong adler1;- uLong adler2;- z_off64_t len2;-{- unsigned long sum1;- unsigned long sum2;- unsigned rem;-- /* for negative len, return invalid adler32 as a clue for debugging */- if (len2 < 0)- return 0xffffffffUL;-- /* the derivation of this formula is left as an exercise for the reader */- MOD63(len2); /* assumes len2 >= 0 */- rem = (unsigned)len2;- sum1 = adler1 & 0xffff;- sum2 = rem * sum1;- MOD(sum2);- sum1 += (adler2 & 0xffff) + BASE - 1;- sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;- if (sum1 >= BASE) sum1 -= BASE;- if (sum1 >= BASE) sum1 -= BASE;- if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);- if (sum2 >= BASE) sum2 -= BASE;- return sum1 | (sum2 << 16);-}--/* ========================================================================= */-uLong ZEXPORT adler32_combine(adler1, adler2, len2)- uLong adler1;- uLong adler2;- z_off_t len2;-{- return adler32_combine_(adler1, adler2, len2);-}--uLong ZEXPORT adler32_combine64(adler1, adler2, len2)- uLong adler1;- uLong adler2;- z_off64_t len2;-{- return adler32_combine_(adler1, adler2, len2);-}
− c/zlib/compress.c
@@ -1,86 +0,0 @@-/* compress.c -- compress a memory buffer- * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/* @(#) $Id$ */--#define ZLIB_INTERNAL-#include "zlib.h"--/* ===========================================================================- Compresses the source buffer into the destination buffer. The level- parameter has the same meaning as in deflateInit. sourceLen is the byte- length of the source buffer. Upon entry, destLen is the total size of the- destination buffer, which must be at least 0.1% larger than sourceLen plus- 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.-- compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough- memory, Z_BUF_ERROR if there was not enough room in the output buffer,- Z_STREAM_ERROR if the level parameter is invalid.-*/-int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)- Bytef *dest;- uLongf *destLen;- const Bytef *source;- uLong sourceLen;- int level;-{- z_stream stream;- int err;- const uInt max = (uInt)-1;- uLong left;-- left = *destLen;- *destLen = 0;-- stream.zalloc = (alloc_func)0;- stream.zfree = (free_func)0;- stream.opaque = (voidpf)0;-- err = deflateInit(&stream, level);- if (err != Z_OK) return err;-- stream.next_out = dest;- stream.avail_out = 0;- stream.next_in = (z_const Bytef *)source;- stream.avail_in = 0;-- do {- if (stream.avail_out == 0) {- stream.avail_out = left > (uLong)max ? max : (uInt)left;- left -= stream.avail_out;- }- if (stream.avail_in == 0) {- stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen;- sourceLen -= stream.avail_in;- }- err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);- } while (err == Z_OK);-- *destLen = stream.total_out;- deflateEnd(&stream);- return err == Z_STREAM_END ? Z_OK : err;-}--/* ===========================================================================- */-int ZEXPORT compress (dest, destLen, source, sourceLen)- Bytef *dest;- uLongf *destLen;- const Bytef *source;- uLong sourceLen;-{- return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);-}--/* ===========================================================================- If the default memLevel or windowBits for deflateInit() is changed, then- this function needs to be updated.- */-uLong ZEXPORT compressBound (sourceLen)- uLong sourceLen;-{- return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +- (sourceLen >> 25) + 13;-}
− c/zlib/crc32.c
@@ -1,442 +0,0 @@-/* crc32.c -- compute the CRC-32 of a data stream- * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- *- * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster- * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing- * tables for updating the shift register in one step with three exclusive-ors- * instead of four steps with four exclusive-ors. This results in about a- * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.- */--/* @(#) $Id$ */--/*- Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore- protection on the static variables used to control the first-use generation- of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should- first call get_crc_table() to initialize the tables before allowing more than- one thread to use crc32().-- DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.- */--#ifdef MAKECRCH-# include <stdio.h>-# ifndef DYNAMIC_CRC_TABLE-# define DYNAMIC_CRC_TABLE-# endif /* !DYNAMIC_CRC_TABLE */-#endif /* MAKECRCH */--#include "zutil.h" /* for STDC and FAR definitions */--/* Definitions for doing the crc four data bytes at a time. */-#if !defined(NOBYFOUR) && defined(Z_U4)-# define BYFOUR-#endif-#ifdef BYFOUR- local unsigned long crc32_little OF((unsigned long,- const unsigned char FAR *, z_size_t));- local unsigned long crc32_big OF((unsigned long,- const unsigned char FAR *, z_size_t));-# define TBLS 8-#else-# define TBLS 1-#endif /* BYFOUR */--/* Local functions for crc concatenation */-local unsigned long gf2_matrix_times OF((unsigned long *mat,- unsigned long vec));-local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));-local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));---#ifdef DYNAMIC_CRC_TABLE--local volatile int crc_table_empty = 1;-local z_crc_t FAR crc_table[TBLS][256];-local void make_crc_table OF((void));-#ifdef MAKECRCH- local void write_table OF((FILE *, const z_crc_t FAR *));-#endif /* MAKECRCH */-/*- Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:- x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.-- Polynomials over GF(2) are represented in binary, one bit per coefficient,- with the lowest powers in the most significant bit. Then adding polynomials- is just exclusive-or, and multiplying a polynomial by x is a right shift by- one. If we call the above polynomial p, and represent a byte as the- polynomial q, also with the lowest power in the most significant bit (so the- byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,- where a mod b means the remainder after dividing a by b.-- This calculation is done using the shift-register method of multiplying and- taking the remainder. The register is initialized to zero, and for each- incoming bit, x^32 is added mod p to the register if the bit is a one (where- x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by- x (which is shifting right by one and adding x^32 mod p if the bit shifted- out is a one). We start with the highest power (least significant bit) of- q and repeat for all eight bits of q.-- The first table is simply the CRC of all possible eight bit values. This is- all the information needed to generate CRCs on data a byte at a time for all- combinations of CRC register values and incoming bytes. The remaining tables- allow for word-at-a-time CRC calculation for both big-endian and little-- endian machines, where a word is four bytes.-*/-local void make_crc_table()-{- z_crc_t c;- int n, k;- z_crc_t poly; /* polynomial exclusive-or pattern */- /* terms of polynomial defining this crc (except x^32): */- static volatile int first = 1; /* flag to limit concurrent making */- static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};-- /* See if another task is already doing this (not thread-safe, but better- than nothing -- significantly reduces duration of vulnerability in- case the advice about DYNAMIC_CRC_TABLE is ignored) */- if (first) {- first = 0;-- /* make exclusive-or pattern from polynomial (0xedb88320UL) */- poly = 0;- for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)- poly |= (z_crc_t)1 << (31 - p[n]);-- /* generate a crc for every 8-bit value */- for (n = 0; n < 256; n++) {- c = (z_crc_t)n;- for (k = 0; k < 8; k++)- c = c & 1 ? poly ^ (c >> 1) : c >> 1;- crc_table[0][n] = c;- }--#ifdef BYFOUR- /* generate crc for each value followed by one, two, and three zeros,- and then the byte reversal of those as well as the first table */- for (n = 0; n < 256; n++) {- c = crc_table[0][n];- crc_table[4][n] = ZSWAP32(c);- for (k = 1; k < 4; k++) {- c = crc_table[0][c & 0xff] ^ (c >> 8);- crc_table[k][n] = c;- crc_table[k + 4][n] = ZSWAP32(c);- }- }-#endif /* BYFOUR */-- crc_table_empty = 0;- }- else { /* not first */- /* wait for the other guy to finish (not efficient, but rare) */- while (crc_table_empty)- ;- }--#ifdef MAKECRCH- /* write out CRC tables to crc32.h */- {- FILE *out;-- out = fopen("crc32.h", "w");- if (out == NULL) return;- fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");- fprintf(out, " * Generated automatically by crc32.c\n */\n\n");- fprintf(out, "local const z_crc_t FAR ");- fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");- write_table(out, crc_table[0]);-# ifdef BYFOUR- fprintf(out, "#ifdef BYFOUR\n");- for (k = 1; k < 8; k++) {- fprintf(out, " },\n {\n");- write_table(out, crc_table[k]);- }- fprintf(out, "#endif\n");-# endif /* BYFOUR */- fprintf(out, " }\n};\n");- fclose(out);- }-#endif /* MAKECRCH */-}--#ifdef MAKECRCH-local void write_table(out, table)- FILE *out;- const z_crc_t FAR *table;-{- int n;-- for (n = 0; n < 256; n++)- fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ",- (unsigned long)(table[n]),- n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));-}-#endif /* MAKECRCH */--#else /* !DYNAMIC_CRC_TABLE */-/* ========================================================================- * Tables of CRC-32s of all single-byte values, made by make_crc_table().- */-#include "crc32.h"-#endif /* DYNAMIC_CRC_TABLE */--/* =========================================================================- * This function can be used by asm versions of crc32()- */-const z_crc_t FAR * ZEXPORT get_crc_table()-{-#ifdef DYNAMIC_CRC_TABLE- if (crc_table_empty)- make_crc_table();-#endif /* DYNAMIC_CRC_TABLE */- return (const z_crc_t FAR *)crc_table;-}--/* ========================================================================= */-#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)-#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1--/* ========================================================================= */-unsigned long ZEXPORT crc32_z(crc, buf, len)- unsigned long crc;- const unsigned char FAR *buf;- z_size_t len;-{- if (buf == Z_NULL) return 0UL;--#ifdef DYNAMIC_CRC_TABLE- if (crc_table_empty)- make_crc_table();-#endif /* DYNAMIC_CRC_TABLE */--#ifdef BYFOUR- if (sizeof(void *) == sizeof(ptrdiff_t)) {- z_crc_t endian;-- endian = 1;- if (*((unsigned char *)(&endian)))- return crc32_little(crc, buf, len);- else- return crc32_big(crc, buf, len);- }-#endif /* BYFOUR */- crc = crc ^ 0xffffffffUL;- while (len >= 8) {- DO8;- len -= 8;- }- if (len) do {- DO1;- } while (--len);- return crc ^ 0xffffffffUL;-}--/* ========================================================================= */-unsigned long ZEXPORT crc32(crc, buf, len)- unsigned long crc;- const unsigned char FAR *buf;- uInt len;-{- return crc32_z(crc, buf, len);-}--#ifdef BYFOUR--/*- This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit- integer pointer type. This violates the strict aliasing rule, where a- compiler can assume, for optimization purposes, that two pointers to- fundamentally different types won't ever point to the same memory. This can- manifest as a problem only if one of the pointers is written to. This code- only reads from those pointers. So long as this code remains isolated in- this compilation unit, there won't be a problem. For this reason, this code- should not be copied and pasted into a compilation unit in which other code- writes to the buffer that is passed to these routines.- */--/* ========================================================================= */-#define DOLIT4 c ^= *buf4++; \- c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \- crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]-#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4--/* ========================================================================= */-local unsigned long crc32_little(crc, buf, len)- unsigned long crc;- const unsigned char FAR *buf;- z_size_t len;-{- register z_crc_t c;- register const z_crc_t FAR *buf4;-- c = (z_crc_t)crc;- c = ~c;- while (len && ((ptrdiff_t)buf & 3)) {- c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);- len--;- }-- buf4 = (const z_crc_t FAR *)(const void FAR *)buf;- while (len >= 32) {- DOLIT32;- len -= 32;- }- while (len >= 4) {- DOLIT4;- len -= 4;- }- buf = (const unsigned char FAR *)buf4;-- if (len) do {- c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);- } while (--len);- c = ~c;- return (unsigned long)c;-}--/* ========================================================================= */-#define DOBIG4 c ^= *buf4++; \- c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \- crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]-#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4--/* ========================================================================= */-local unsigned long crc32_big(crc, buf, len)- unsigned long crc;- const unsigned char FAR *buf;- z_size_t len;-{- register z_crc_t c;- register const z_crc_t FAR *buf4;-- c = ZSWAP32((z_crc_t)crc);- c = ~c;- while (len && ((ptrdiff_t)buf & 3)) {- c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);- len--;- }-- buf4 = (const z_crc_t FAR *)(const void FAR *)buf;- while (len >= 32) {- DOBIG32;- len -= 32;- }- while (len >= 4) {- DOBIG4;- len -= 4;- }- buf = (const unsigned char FAR *)buf4;-- if (len) do {- c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);- } while (--len);- c = ~c;- return (unsigned long)(ZSWAP32(c));-}--#endif /* BYFOUR */--#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */--/* ========================================================================= */-local unsigned long gf2_matrix_times(mat, vec)- unsigned long *mat;- unsigned long vec;-{- unsigned long sum;-- sum = 0;- while (vec) {- if (vec & 1)- sum ^= *mat;- vec >>= 1;- mat++;- }- return sum;-}--/* ========================================================================= */-local void gf2_matrix_square(square, mat)- unsigned long *square;- unsigned long *mat;-{- int n;-- for (n = 0; n < GF2_DIM; n++)- square[n] = gf2_matrix_times(mat, mat[n]);-}--/* ========================================================================= */-local uLong crc32_combine_(crc1, crc2, len2)- uLong crc1;- uLong crc2;- z_off64_t len2;-{- int n;- unsigned long row;- unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */- unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */-- /* degenerate case (also disallow negative lengths) */- if (len2 <= 0)- return crc1;-- /* put operator for one zero bit in odd */- odd[0] = 0xedb88320UL; /* CRC-32 polynomial */- row = 1;- for (n = 1; n < GF2_DIM; n++) {- odd[n] = row;- row <<= 1;- }-- /* put operator for two zero bits in even */- gf2_matrix_square(even, odd);-- /* put operator for four zero bits in odd */- gf2_matrix_square(odd, even);-- /* apply len2 zeros to crc1 (first square will put the operator for one- zero byte, eight zero bits, in even) */- do {- /* apply zeros operator for this bit of len2 */- gf2_matrix_square(even, odd);- if (len2 & 1)- crc1 = gf2_matrix_times(even, crc1);- len2 >>= 1;-- /* if no more bits set, then done */- if (len2 == 0)- break;-- /* another iteration of the loop with odd and even swapped */- gf2_matrix_square(odd, even);- if (len2 & 1)- crc1 = gf2_matrix_times(odd, crc1);- len2 >>= 1;-- /* if no more bits set, then done */- } while (len2 != 0);-- /* return combined crc */- crc1 ^= crc2;- return crc1;-}--/* ========================================================================= */-uLong ZEXPORT crc32_combine(crc1, crc2, len2)- uLong crc1;- uLong crc2;- z_off_t len2;-{- return crc32_combine_(crc1, crc2, len2);-}--uLong ZEXPORT crc32_combine64(crc1, crc2, len2)- uLong crc1;- uLong crc2;- z_off64_t len2;-{- return crc32_combine_(crc1, crc2, len2);-}
− c/zlib/crc32.h
@@ -1,441 +0,0 @@-/* crc32.h -- tables for rapid CRC calculation- * Generated automatically by crc32.c- */--local const z_crc_t FAR crc_table[TBLS][256] =-{- {- 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,- 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,- 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,- 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,- 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,- 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,- 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,- 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,- 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,- 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,- 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,- 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,- 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,- 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,- 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,- 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,- 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,- 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,- 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,- 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,- 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,- 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,- 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,- 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,- 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,- 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,- 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,- 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,- 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,- 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,- 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,- 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,- 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,- 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,- 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,- 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,- 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,- 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,- 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,- 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,- 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,- 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,- 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,- 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,- 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,- 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,- 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,- 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,- 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,- 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,- 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,- 0x2d02ef8dUL-#ifdef BYFOUR- },- {- 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,- 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,- 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,- 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,- 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,- 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,- 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,- 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,- 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,- 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,- 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,- 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,- 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,- 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,- 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,- 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,- 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,- 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,- 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,- 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,- 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,- 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,- 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,- 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,- 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,- 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,- 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,- 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,- 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,- 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,- 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,- 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,- 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,- 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,- 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,- 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,- 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,- 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,- 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,- 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,- 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,- 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,- 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,- 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,- 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,- 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,- 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,- 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,- 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,- 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,- 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,- 0x9324fd72UL- },- {- 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,- 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,- 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,- 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,- 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,- 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,- 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,- 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,- 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,- 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,- 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,- 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,- 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,- 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,- 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,- 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,- 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,- 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,- 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,- 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,- 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,- 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,- 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,- 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,- 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,- 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,- 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,- 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,- 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,- 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,- 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,- 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,- 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,- 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,- 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,- 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,- 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,- 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,- 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,- 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,- 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,- 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,- 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,- 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,- 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,- 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,- 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,- 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,- 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,- 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,- 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,- 0xbe9834edUL- },- {- 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,- 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,- 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,- 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,- 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,- 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,- 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,- 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,- 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,- 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,- 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,- 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,- 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,- 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,- 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,- 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,- 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,- 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,- 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,- 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,- 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,- 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,- 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,- 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,- 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,- 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,- 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,- 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,- 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,- 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,- 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,- 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,- 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,- 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,- 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,- 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,- 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,- 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,- 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,- 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,- 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,- 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,- 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,- 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,- 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,- 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,- 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,- 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,- 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,- 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,- 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,- 0xde0506f1UL- },- {- 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,- 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,- 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,- 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,- 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,- 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,- 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,- 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,- 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,- 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,- 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,- 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,- 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,- 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,- 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,- 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,- 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,- 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,- 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,- 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,- 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,- 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,- 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,- 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,- 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,- 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,- 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,- 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,- 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,- 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,- 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,- 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,- 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,- 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,- 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,- 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,- 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,- 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,- 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,- 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,- 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,- 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,- 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,- 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,- 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,- 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,- 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,- 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,- 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,- 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,- 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,- 0x8def022dUL- },- {- 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,- 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,- 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,- 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,- 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,- 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,- 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,- 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,- 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,- 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,- 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,- 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,- 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,- 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,- 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,- 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,- 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,- 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,- 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,- 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,- 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,- 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,- 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,- 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,- 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,- 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,- 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,- 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,- 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,- 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,- 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,- 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,- 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,- 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,- 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,- 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,- 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,- 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,- 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,- 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,- 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,- 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,- 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,- 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,- 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,- 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,- 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,- 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,- 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,- 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,- 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,- 0x72fd2493UL- },- {- 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,- 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,- 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,- 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,- 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,- 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,- 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,- 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,- 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,- 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,- 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,- 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,- 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,- 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,- 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,- 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,- 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,- 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,- 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,- 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,- 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,- 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,- 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,- 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,- 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,- 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,- 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,- 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,- 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,- 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,- 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,- 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,- 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,- 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,- 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,- 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,- 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,- 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,- 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,- 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,- 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,- 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,- 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,- 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,- 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,- 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,- 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,- 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,- 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,- 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,- 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,- 0xed3498beUL- },- {- 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,- 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,- 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,- 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,- 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,- 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,- 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,- 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,- 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,- 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,- 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,- 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,- 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,- 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,- 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,- 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,- 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,- 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,- 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,- 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,- 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,- 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,- 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,- 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,- 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,- 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,- 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,- 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,- 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,- 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,- 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,- 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,- 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,- 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,- 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,- 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,- 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,- 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,- 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,- 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,- 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,- 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,- 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,- 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,- 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,- 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,- 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,- 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,- 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,- 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,- 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,- 0xf10605deUL-#endif- }-};
− c/zlib/deflate.c
@@ -1,2163 +0,0 @@-/* deflate.c -- compress data using the deflation algorithm- * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/*- * ALGORITHM- *- * The "deflation" process depends on being able to identify portions- * of the input text which are identical to earlier input (within a- * sliding window trailing behind the input currently being processed).- *- * The most straightforward technique turns out to be the fastest for- * most input files: try all possible matches and select the longest.- * The key feature of this algorithm is that insertions into the string- * dictionary are very simple and thus fast, and deletions are avoided- * completely. Insertions are performed at each input character, whereas- * string matches are performed only when the previous match ends. So it- * is preferable to spend more time in matches to allow very fast string- * insertions and avoid deletions. The matching algorithm for small- * strings is inspired from that of Rabin & Karp. A brute force approach- * is used to find longer strings when a small match has been found.- * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze- * (by Leonid Broukhis).- * A previous version of this file used a more sophisticated algorithm- * (by Fiala and Greene) which is guaranteed to run in linear amortized- * time, but has a larger average cost, uses more memory and is patented.- * However the F&G algorithm may be faster for some highly redundant- * files if the parameter max_chain_length (described below) is too large.- *- * ACKNOWLEDGEMENTS- *- * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and- * I found it in 'freeze' written by Leonid Broukhis.- * Thanks to many people for bug reports and testing.- *- * REFERENCES- *- * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".- * Available in http://tools.ietf.org/html/rfc1951- *- * A description of the Rabin and Karp algorithm is given in the book- * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.- *- * Fiala,E.R., and Greene,D.H.- * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595- *- */--/* @(#) $Id$ */--#include "deflate.h"--const char deflate_copyright[] =- " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler ";-/*- If you use the zlib library in a product, an acknowledgment is welcome- in the documentation of your product. If for some reason you cannot- include such an acknowledgment, I would appreciate that you keep this- copyright string in the executable of your product.- */--/* ===========================================================================- * Function prototypes.- */-typedef enum {- need_more, /* block not completed, need more input or more output */- block_done, /* block flush performed */- finish_started, /* finish started, need only more output at next deflate */- finish_done /* finish done, accept no more input or output */-} block_state;--typedef block_state (*compress_func) OF((deflate_state *s, int flush));-/* Compression function. Returns the block state after the call. */--local int deflateStateCheck OF((z_streamp strm));-local void slide_hash OF((deflate_state *s));-local void fill_window OF((deflate_state *s));-local block_state deflate_stored OF((deflate_state *s, int flush));-local block_state deflate_fast OF((deflate_state *s, int flush));-#ifndef FASTEST-local block_state deflate_slow OF((deflate_state *s, int flush));-#endif-local block_state deflate_rle OF((deflate_state *s, int flush));-local block_state deflate_huff OF((deflate_state *s, int flush));-local void lm_init OF((deflate_state *s));-local void putShortMSB OF((deflate_state *s, uInt b));-local void flush_pending OF((z_streamp strm));-local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size));-#ifdef ASMV-# pragma message("Assembler code may have bugs -- use at your own risk")- void match_init OF((void)); /* asm code initialization */- uInt longest_match OF((deflate_state *s, IPos cur_match));-#else-local uInt longest_match OF((deflate_state *s, IPos cur_match));-#endif--#ifdef ZLIB_DEBUG-local void check_match OF((deflate_state *s, IPos start, IPos match,- int length));-#endif--/* ===========================================================================- * Local data- */--#define NIL 0-/* Tail of hash chains */--#ifndef TOO_FAR-# define TOO_FAR 4096-#endif-/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */--/* Values for max_lazy_match, good_match and max_chain_length, depending on- * the desired pack level (0..9). The values given below have been tuned to- * exclude worst case performance for pathological files. Better values may be- * found for specific files.- */-typedef struct config_s {- ush good_length; /* reduce lazy search above this match length */- ush max_lazy; /* do not perform lazy search above this match length */- ush nice_length; /* quit search above this match length */- ush max_chain;- compress_func func;-} config;--#ifdef FASTEST-local const config configuration_table[2] = {-/* good lazy nice chain */-/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */-/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */-#else-local const config configuration_table[10] = {-/* good lazy nice chain */-/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */-/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */-/* 2 */ {4, 5, 16, 8, deflate_fast},-/* 3 */ {4, 6, 32, 32, deflate_fast},--/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */-/* 5 */ {8, 16, 32, 32, deflate_slow},-/* 6 */ {8, 16, 128, 128, deflate_slow},-/* 7 */ {8, 32, 128, 256, deflate_slow},-/* 8 */ {32, 128, 258, 1024, deflate_slow},-/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */-#endif--/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4- * For deflate_fast() (levels <= 3) good is ignored and lazy has a different- * meaning.- */--/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */-#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0))--/* ===========================================================================- * Update a hash value with the given input byte- * IN assertion: all calls to UPDATE_HASH are made with consecutive input- * characters, so that a running hash key can be computed from the previous- * key instead of complete recalculation each time.- */-#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)---/* ===========================================================================- * Insert string str in the dictionary and set match_head to the previous head- * of the hash chain (the most recent string with same hash key). Return- * the previous length of the hash chain.- * If this file is compiled with -DFASTEST, the compression level is forced- * to 1, and no hash chains are maintained.- * IN assertion: all calls to INSERT_STRING are made with consecutive input- * characters and the first MIN_MATCH bytes of str are valid (except for- * the last MIN_MATCH-1 bytes of the input file).- */-#ifdef FASTEST-#define INSERT_STRING(s, str, match_head) \- (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \- match_head = s->head[s->ins_h], \- s->head[s->ins_h] = (Pos)(str))-#else-#define INSERT_STRING(s, str, match_head) \- (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \- match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \- s->head[s->ins_h] = (Pos)(str))-#endif--/* ===========================================================================- * Initialize the hash table (avoiding 64K overflow for 16 bit systems).- * prev[] will be initialized on the fly.- */-#define CLEAR_HASH(s) \- s->head[s->hash_size-1] = NIL; \- zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));--/* ===========================================================================- * Slide the hash table when sliding the window down (could be avoided with 32- * bit values at the expense of memory usage). We slide even when level == 0 to- * keep the hash table consistent if we switch back to level > 0 later.- */-local void slide_hash(s)- deflate_state *s;-{- unsigned n, m;- Posf *p;- uInt wsize = s->w_size;-- n = s->hash_size;- p = &s->head[n];- do {- m = *--p;- *p = (Pos)(m >= wsize ? m - wsize : NIL);- } while (--n);- n = wsize;-#ifndef FASTEST- p = &s->prev[n];- do {- m = *--p;- *p = (Pos)(m >= wsize ? m - wsize : NIL);- /* If n is not on any hash chain, prev[n] is garbage but- * its value will never be used.- */- } while (--n);-#endif-}--/* ========================================================================= */-int ZEXPORT deflateInit_(strm, level, version, stream_size)- z_streamp strm;- int level;- const char *version;- int stream_size;-{- return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,- Z_DEFAULT_STRATEGY, version, stream_size);- /* To do: ignore strm->next_in if we use it as window */-}--/* ========================================================================= */-int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,- version, stream_size)- z_streamp strm;- int level;- int method;- int windowBits;- int memLevel;- int strategy;- const char *version;- int stream_size;-{- deflate_state *s;- int wrap = 1;- static const char my_version[] = ZLIB_VERSION;-- ushf *overlay;- /* We overlay pending_buf and d_buf+l_buf. This works since the average- * output size for (length,distance) codes is <= 24 bits.- */-- if (version == Z_NULL || version[0] != my_version[0] ||- stream_size != sizeof(z_stream)) {- return Z_VERSION_ERROR;- }- if (strm == Z_NULL) return Z_STREAM_ERROR;-- strm->msg = Z_NULL;- if (strm->zalloc == (alloc_func)0) {-#ifdef Z_SOLO- return Z_STREAM_ERROR;-#else- strm->zalloc = zcalloc;- strm->opaque = (voidpf)0;-#endif- }- if (strm->zfree == (free_func)0)-#ifdef Z_SOLO- return Z_STREAM_ERROR;-#else- strm->zfree = zcfree;-#endif--#ifdef FASTEST- if (level != 0) level = 1;-#else- if (level == Z_DEFAULT_COMPRESSION) level = 6;-#endif-- if (windowBits < 0) { /* suppress zlib wrapper */- wrap = 0;- windowBits = -windowBits;- }-#ifdef GZIP- else if (windowBits > 15) {- wrap = 2; /* write gzip wrapper instead */- windowBits -= 16;- }-#endif- if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||- windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||- strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) {- return Z_STREAM_ERROR;- }- if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */- s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));- if (s == Z_NULL) return Z_MEM_ERROR;- strm->state = (struct internal_state FAR *)s;- s->strm = strm;- s->status = INIT_STATE; /* to pass state test in deflateReset() */-- s->wrap = wrap;- s->gzhead = Z_NULL;- s->w_bits = (uInt)windowBits;- s->w_size = 1 << s->w_bits;- s->w_mask = s->w_size - 1;-- s->hash_bits = (uInt)memLevel + 7;- s->hash_size = 1 << s->hash_bits;- s->hash_mask = s->hash_size - 1;- s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);-- s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));- s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));- s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));-- s->high_water = 0; /* nothing written to s->window yet */-- s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */-- overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);- s->pending_buf = (uchf *) overlay;- s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);-- if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||- s->pending_buf == Z_NULL) {- s->status = FINISH_STATE;- strm->msg = ERR_MSG(Z_MEM_ERROR);- deflateEnd (strm);- return Z_MEM_ERROR;- }- s->d_buf = overlay + s->lit_bufsize/sizeof(ush);- s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;-- s->level = level;- s->strategy = strategy;- s->method = (Byte)method;-- return deflateReset(strm);-}--/* =========================================================================- * Check for a valid deflate stream state. Return 0 if ok, 1 if not.- */-local int deflateStateCheck (strm)- z_streamp strm;-{- deflate_state *s;- if (strm == Z_NULL ||- strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)- return 1;- s = strm->state;- if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE &&-#ifdef GZIP- s->status != GZIP_STATE &&-#endif- s->status != EXTRA_STATE &&- s->status != NAME_STATE &&- s->status != COMMENT_STATE &&- s->status != HCRC_STATE &&- s->status != BUSY_STATE &&- s->status != FINISH_STATE))- return 1;- return 0;-}--/* ========================================================================= */-int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)- z_streamp strm;- const Bytef *dictionary;- uInt dictLength;-{- deflate_state *s;- uInt str, n;- int wrap;- unsigned avail;- z_const unsigned char *next;-- if (deflateStateCheck(strm) || dictionary == Z_NULL)- return Z_STREAM_ERROR;- s = strm->state;- wrap = s->wrap;- if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)- return Z_STREAM_ERROR;-- /* when using zlib wrappers, compute Adler-32 for provided dictionary */- if (wrap == 1)- strm->adler = adler32(strm->adler, dictionary, dictLength);- s->wrap = 0; /* avoid computing Adler-32 in read_buf */-- /* if dictionary would fill window, just replace the history */- if (dictLength >= s->w_size) {- if (wrap == 0) { /* already empty otherwise */- CLEAR_HASH(s);- s->strstart = 0;- s->block_start = 0L;- s->insert = 0;- }- dictionary += dictLength - s->w_size; /* use the tail */- dictLength = s->w_size;- }-- /* insert dictionary into window and hash */- avail = strm->avail_in;- next = strm->next_in;- strm->avail_in = dictLength;- strm->next_in = (z_const Bytef *)dictionary;- fill_window(s);- while (s->lookahead >= MIN_MATCH) {- str = s->strstart;- n = s->lookahead - (MIN_MATCH-1);- do {- UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);-#ifndef FASTEST- s->prev[str & s->w_mask] = s->head[s->ins_h];-#endif- s->head[s->ins_h] = (Pos)str;- str++;- } while (--n);- s->strstart = str;- s->lookahead = MIN_MATCH-1;- fill_window(s);- }- s->strstart += s->lookahead;- s->block_start = (long)s->strstart;- s->insert = s->lookahead;- s->lookahead = 0;- s->match_length = s->prev_length = MIN_MATCH-1;- s->match_available = 0;- strm->next_in = next;- strm->avail_in = avail;- s->wrap = wrap;- return Z_OK;-}--/* ========================================================================= */-int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength)- z_streamp strm;- Bytef *dictionary;- uInt *dictLength;-{- deflate_state *s;- uInt len;-- if (deflateStateCheck(strm))- return Z_STREAM_ERROR;- s = strm->state;- len = s->strstart + s->lookahead;- if (len > s->w_size)- len = s->w_size;- if (dictionary != Z_NULL && len)- zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len);- if (dictLength != Z_NULL)- *dictLength = len;- return Z_OK;-}--/* ========================================================================= */-int ZEXPORT deflateResetKeep (strm)- z_streamp strm;-{- deflate_state *s;-- if (deflateStateCheck(strm)) {- return Z_STREAM_ERROR;- }-- strm->total_in = strm->total_out = 0;- strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */- strm->data_type = Z_UNKNOWN;-- s = (deflate_state *)strm->state;- s->pending = 0;- s->pending_out = s->pending_buf;-- if (s->wrap < 0) {- s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */- }- s->status =-#ifdef GZIP- s->wrap == 2 ? GZIP_STATE :-#endif- s->wrap ? INIT_STATE : BUSY_STATE;- strm->adler =-#ifdef GZIP- s->wrap == 2 ? crc32(0L, Z_NULL, 0) :-#endif- adler32(0L, Z_NULL, 0);- s->last_flush = Z_NO_FLUSH;-- _tr_init(s);-- return Z_OK;-}--/* ========================================================================= */-int ZEXPORT deflateReset (strm)- z_streamp strm;-{- int ret;-- ret = deflateResetKeep(strm);- if (ret == Z_OK)- lm_init(strm->state);- return ret;-}--/* ========================================================================= */-int ZEXPORT deflateSetHeader (strm, head)- z_streamp strm;- gz_headerp head;-{- if (deflateStateCheck(strm) || strm->state->wrap != 2)- return Z_STREAM_ERROR;- strm->state->gzhead = head;- return Z_OK;-}--/* ========================================================================= */-int ZEXPORT deflatePending (strm, pending, bits)- unsigned *pending;- int *bits;- z_streamp strm;-{- if (deflateStateCheck(strm)) return Z_STREAM_ERROR;- if (pending != Z_NULL)- *pending = strm->state->pending;- if (bits != Z_NULL)- *bits = strm->state->bi_valid;- return Z_OK;-}--/* ========================================================================= */-int ZEXPORT deflatePrime (strm, bits, value)- z_streamp strm;- int bits;- int value;-{- deflate_state *s;- int put;-- if (deflateStateCheck(strm)) return Z_STREAM_ERROR;- s = strm->state;- if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))- return Z_BUF_ERROR;- do {- put = Buf_size - s->bi_valid;- if (put > bits)- put = bits;- s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);- s->bi_valid += put;- _tr_flush_bits(s);- value >>= put;- bits -= put;- } while (bits);- return Z_OK;-}--/* ========================================================================= */-int ZEXPORT deflateParams(strm, level, strategy)- z_streamp strm;- int level;- int strategy;-{- deflate_state *s;- compress_func func;-- if (deflateStateCheck(strm)) return Z_STREAM_ERROR;- s = strm->state;--#ifdef FASTEST- if (level != 0) level = 1;-#else- if (level == Z_DEFAULT_COMPRESSION) level = 6;-#endif- if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {- return Z_STREAM_ERROR;- }- func = configuration_table[s->level].func;-- if ((strategy != s->strategy || func != configuration_table[level].func) &&- s->high_water) {- /* Flush the last buffer: */- int err = deflate(strm, Z_BLOCK);- if (err == Z_STREAM_ERROR)- return err;- if (strm->avail_out == 0)- return Z_BUF_ERROR;- }- if (s->level != level) {- if (s->level == 0 && s->matches != 0) {- if (s->matches == 1)- slide_hash(s);- else- CLEAR_HASH(s);- s->matches = 0;- }- s->level = level;- s->max_lazy_match = configuration_table[level].max_lazy;- s->good_match = configuration_table[level].good_length;- s->nice_match = configuration_table[level].nice_length;- s->max_chain_length = configuration_table[level].max_chain;- }- s->strategy = strategy;- return Z_OK;-}--/* ========================================================================= */-int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)- z_streamp strm;- int good_length;- int max_lazy;- int nice_length;- int max_chain;-{- deflate_state *s;-- if (deflateStateCheck(strm)) return Z_STREAM_ERROR;- s = strm->state;- s->good_match = (uInt)good_length;- s->max_lazy_match = (uInt)max_lazy;- s->nice_match = nice_length;- s->max_chain_length = (uInt)max_chain;- return Z_OK;-}--/* =========================================================================- * For the default windowBits of 15 and memLevel of 8, this function returns- * a close to exact, as well as small, upper bound on the compressed size.- * They are coded as constants here for a reason--if the #define's are- * changed, then this function needs to be changed as well. The return- * value for 15 and 8 only works for those exact settings.- *- * For any setting other than those defaults for windowBits and memLevel,- * the value returned is a conservative worst case for the maximum expansion- * resulting from using fixed blocks instead of stored blocks, which deflate- * can emit on compressed data for some combinations of the parameters.- *- * This function could be more sophisticated to provide closer upper bounds for- * every combination of windowBits and memLevel. But even the conservative- * upper bound of about 14% expansion does not seem onerous for output buffer- * allocation.- */-uLong ZEXPORT deflateBound(strm, sourceLen)- z_streamp strm;- uLong sourceLen;-{- deflate_state *s;- uLong complen, wraplen;-- /* conservative upper bound for compressed data */- complen = sourceLen +- ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;-- /* if can't get parameters, return conservative bound plus zlib wrapper */- if (deflateStateCheck(strm))- return complen + 6;-- /* compute wrapper length */- s = strm->state;- switch (s->wrap) {- case 0: /* raw deflate */- wraplen = 0;- break;- case 1: /* zlib wrapper */- wraplen = 6 + (s->strstart ? 4 : 0);- break;-#ifdef GZIP- case 2: /* gzip wrapper */- wraplen = 18;- if (s->gzhead != Z_NULL) { /* user-supplied gzip header */- Bytef *str;- if (s->gzhead->extra != Z_NULL)- wraplen += 2 + s->gzhead->extra_len;- str = s->gzhead->name;- if (str != Z_NULL)- do {- wraplen++;- } while (*str++);- str = s->gzhead->comment;- if (str != Z_NULL)- do {- wraplen++;- } while (*str++);- if (s->gzhead->hcrc)- wraplen += 2;- }- break;-#endif- default: /* for compiler happiness */- wraplen = 6;- }-- /* if not default parameters, return conservative bound */- if (s->w_bits != 15 || s->hash_bits != 8 + 7)- return complen + wraplen;-- /* default settings: return tight bound for that case */- return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +- (sourceLen >> 25) + 13 - 6 + wraplen;-}--/* =========================================================================- * Put a short in the pending buffer. The 16-bit value is put in MSB order.- * IN assertion: the stream state is correct and there is enough room in- * pending_buf.- */-local void putShortMSB (s, b)- deflate_state *s;- uInt b;-{- put_byte(s, (Byte)(b >> 8));- put_byte(s, (Byte)(b & 0xff));-}--/* =========================================================================- * Flush as much pending output as possible. All deflate() output, except for- * some deflate_stored() output, goes through this function so some- * applications may wish to modify it to avoid allocating a large- * strm->next_out buffer and copying into it. (See also read_buf()).- */-local void flush_pending(strm)- z_streamp strm;-{- unsigned len;- deflate_state *s = strm->state;-- _tr_flush_bits(s);- len = s->pending;- if (len > strm->avail_out) len = strm->avail_out;- if (len == 0) return;-- zmemcpy(strm->next_out, s->pending_out, len);- strm->next_out += len;- s->pending_out += len;- strm->total_out += len;- strm->avail_out -= len;- s->pending -= len;- if (s->pending == 0) {- s->pending_out = s->pending_buf;- }-}--/* ===========================================================================- * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1].- */-#define HCRC_UPDATE(beg) \- do { \- if (s->gzhead->hcrc && s->pending > (beg)) \- strm->adler = crc32(strm->adler, s->pending_buf + (beg), \- s->pending - (beg)); \- } while (0)--/* ========================================================================= */-int ZEXPORT deflate (strm, flush)- z_streamp strm;- int flush;-{- int old_flush; /* value of flush param for previous deflate call */- deflate_state *s;-- if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) {- return Z_STREAM_ERROR;- }- s = strm->state;-- if (strm->next_out == Z_NULL ||- (strm->avail_in != 0 && strm->next_in == Z_NULL) ||- (s->status == FINISH_STATE && flush != Z_FINISH)) {- ERR_RETURN(strm, Z_STREAM_ERROR);- }- if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);-- old_flush = s->last_flush;- s->last_flush = flush;-- /* Flush as much pending output as possible */- if (s->pending != 0) {- flush_pending(strm);- if (strm->avail_out == 0) {- /* Since avail_out is 0, deflate will be called again with- * more output space, but possibly with both pending and- * avail_in equal to zero. There won't be anything to do,- * but this is not an error situation so make sure we- * return OK instead of BUF_ERROR at next call of deflate:- */- s->last_flush = -1;- return Z_OK;- }-- /* Make sure there is something to do and avoid duplicate consecutive- * flushes. For repeated and useless calls with Z_FINISH, we keep- * returning Z_STREAM_END instead of Z_BUF_ERROR.- */- } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&- flush != Z_FINISH) {- ERR_RETURN(strm, Z_BUF_ERROR);- }-- /* User must not provide more input after the first FINISH: */- if (s->status == FINISH_STATE && strm->avail_in != 0) {- ERR_RETURN(strm, Z_BUF_ERROR);- }-- /* Write the header */- if (s->status == INIT_STATE) {- /* zlib header */- uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;- uInt level_flags;-- if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)- level_flags = 0;- else if (s->level < 6)- level_flags = 1;- else if (s->level == 6)- level_flags = 2;- else- level_flags = 3;- header |= (level_flags << 6);- if (s->strstart != 0) header |= PRESET_DICT;- header += 31 - (header % 31);-- putShortMSB(s, header);-- /* Save the adler32 of the preset dictionary: */- if (s->strstart != 0) {- putShortMSB(s, (uInt)(strm->adler >> 16));- putShortMSB(s, (uInt)(strm->adler & 0xffff));- }- strm->adler = adler32(0L, Z_NULL, 0);- s->status = BUSY_STATE;-- /* Compression must start with an empty pending buffer */- flush_pending(strm);- if (s->pending != 0) {- s->last_flush = -1;- return Z_OK;- }- }-#ifdef GZIP- if (s->status == GZIP_STATE) {- /* gzip header */- strm->adler = crc32(0L, Z_NULL, 0);- put_byte(s, 31);- put_byte(s, 139);- put_byte(s, 8);- if (s->gzhead == Z_NULL) {- put_byte(s, 0);- put_byte(s, 0);- put_byte(s, 0);- put_byte(s, 0);- put_byte(s, 0);- put_byte(s, s->level == 9 ? 2 :- (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?- 4 : 0));- put_byte(s, OS_CODE);- s->status = BUSY_STATE;-- /* Compression must start with an empty pending buffer */- flush_pending(strm);- if (s->pending != 0) {- s->last_flush = -1;- return Z_OK;- }- }- else {- put_byte(s, (s->gzhead->text ? 1 : 0) +- (s->gzhead->hcrc ? 2 : 0) +- (s->gzhead->extra == Z_NULL ? 0 : 4) +- (s->gzhead->name == Z_NULL ? 0 : 8) +- (s->gzhead->comment == Z_NULL ? 0 : 16)- );- put_byte(s, (Byte)(s->gzhead->time & 0xff));- put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));- put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));- put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));- put_byte(s, s->level == 9 ? 2 :- (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?- 4 : 0));- put_byte(s, s->gzhead->os & 0xff);- if (s->gzhead->extra != Z_NULL) {- put_byte(s, s->gzhead->extra_len & 0xff);- put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);- }- if (s->gzhead->hcrc)- strm->adler = crc32(strm->adler, s->pending_buf,- s->pending);- s->gzindex = 0;- s->status = EXTRA_STATE;- }- }- if (s->status == EXTRA_STATE) {- if (s->gzhead->extra != Z_NULL) {- ulg beg = s->pending; /* start of bytes to update crc */- uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex;- while (s->pending + left > s->pending_buf_size) {- uInt copy = s->pending_buf_size - s->pending;- zmemcpy(s->pending_buf + s->pending,- s->gzhead->extra + s->gzindex, copy);- s->pending = s->pending_buf_size;- HCRC_UPDATE(beg);- s->gzindex += copy;- flush_pending(strm);- if (s->pending != 0) {- s->last_flush = -1;- return Z_OK;- }- beg = 0;- left -= copy;- }- zmemcpy(s->pending_buf + s->pending,- s->gzhead->extra + s->gzindex, left);- s->pending += left;- HCRC_UPDATE(beg);- s->gzindex = 0;- }- s->status = NAME_STATE;- }- if (s->status == NAME_STATE) {- if (s->gzhead->name != Z_NULL) {- ulg beg = s->pending; /* start of bytes to update crc */- int val;- do {- if (s->pending == s->pending_buf_size) {- HCRC_UPDATE(beg);- flush_pending(strm);- if (s->pending != 0) {- s->last_flush = -1;- return Z_OK;- }- beg = 0;- }- val = s->gzhead->name[s->gzindex++];- put_byte(s, val);- } while (val != 0);- HCRC_UPDATE(beg);- s->gzindex = 0;- }- s->status = COMMENT_STATE;- }- if (s->status == COMMENT_STATE) {- if (s->gzhead->comment != Z_NULL) {- ulg beg = s->pending; /* start of bytes to update crc */- int val;- do {- if (s->pending == s->pending_buf_size) {- HCRC_UPDATE(beg);- flush_pending(strm);- if (s->pending != 0) {- s->last_flush = -1;- return Z_OK;- }- beg = 0;- }- val = s->gzhead->comment[s->gzindex++];- put_byte(s, val);- } while (val != 0);- HCRC_UPDATE(beg);- }- s->status = HCRC_STATE;- }- if (s->status == HCRC_STATE) {- if (s->gzhead->hcrc) {- if (s->pending + 2 > s->pending_buf_size) {- flush_pending(strm);- if (s->pending != 0) {- s->last_flush = -1;- return Z_OK;- }- }- put_byte(s, (Byte)(strm->adler & 0xff));- put_byte(s, (Byte)((strm->adler >> 8) & 0xff));- strm->adler = crc32(0L, Z_NULL, 0);- }- s->status = BUSY_STATE;-- /* Compression must start with an empty pending buffer */- flush_pending(strm);- if (s->pending != 0) {- s->last_flush = -1;- return Z_OK;- }- }-#endif-- /* Start a new block or continue the current one.- */- if (strm->avail_in != 0 || s->lookahead != 0 ||- (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {- block_state bstate;-- bstate = s->level == 0 ? deflate_stored(s, flush) :- s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :- s->strategy == Z_RLE ? deflate_rle(s, flush) :- (*(configuration_table[s->level].func))(s, flush);-- if (bstate == finish_started || bstate == finish_done) {- s->status = FINISH_STATE;- }- if (bstate == need_more || bstate == finish_started) {- if (strm->avail_out == 0) {- s->last_flush = -1; /* avoid BUF_ERROR next call, see above */- }- return Z_OK;- /* If flush != Z_NO_FLUSH && avail_out == 0, the next call- * of deflate should use the same flush parameter to make sure- * that the flush is complete. So we don't have to output an- * empty block here, this will be done at next call. This also- * ensures that for a very small output buffer, we emit at most- * one empty block.- */- }- if (bstate == block_done) {- if (flush == Z_PARTIAL_FLUSH) {- _tr_align(s);- } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */- _tr_stored_block(s, (char*)0, 0L, 0);- /* For a full flush, this empty block will be recognized- * as a special marker by inflate_sync().- */- if (flush == Z_FULL_FLUSH) {- CLEAR_HASH(s); /* forget history */- if (s->lookahead == 0) {- s->strstart = 0;- s->block_start = 0L;- s->insert = 0;- }- }- }- flush_pending(strm);- if (strm->avail_out == 0) {- s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */- return Z_OK;- }- }- }-- if (flush != Z_FINISH) return Z_OK;- if (s->wrap <= 0) return Z_STREAM_END;-- /* Write the trailer */-#ifdef GZIP- if (s->wrap == 2) {- put_byte(s, (Byte)(strm->adler & 0xff));- put_byte(s, (Byte)((strm->adler >> 8) & 0xff));- put_byte(s, (Byte)((strm->adler >> 16) & 0xff));- put_byte(s, (Byte)((strm->adler >> 24) & 0xff));- put_byte(s, (Byte)(strm->total_in & 0xff));- put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));- put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));- put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));- }- else-#endif- {- putShortMSB(s, (uInt)(strm->adler >> 16));- putShortMSB(s, (uInt)(strm->adler & 0xffff));- }- flush_pending(strm);- /* If avail_out is zero, the application will call deflate again- * to flush the rest.- */- if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */- return s->pending != 0 ? Z_OK : Z_STREAM_END;-}--/* ========================================================================= */-int ZEXPORT deflateEnd (strm)- z_streamp strm;-{- int status;-- if (deflateStateCheck(strm)) return Z_STREAM_ERROR;-- status = strm->state->status;-- /* Deallocate in reverse order of allocations: */- TRY_FREE(strm, strm->state->pending_buf);- TRY_FREE(strm, strm->state->head);- TRY_FREE(strm, strm->state->prev);- TRY_FREE(strm, strm->state->window);-- ZFREE(strm, strm->state);- strm->state = Z_NULL;-- return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;-}--/* =========================================================================- * Copy the source state to the destination state.- * To simplify the source, this is not supported for 16-bit MSDOS (which- * doesn't have enough memory anyway to duplicate compression states).- */-int ZEXPORT deflateCopy (dest, source)- z_streamp dest;- z_streamp source;-{-#ifdef MAXSEG_64K- return Z_STREAM_ERROR;-#else- deflate_state *ds;- deflate_state *ss;- ushf *overlay;--- if (deflateStateCheck(source) || dest == Z_NULL) {- return Z_STREAM_ERROR;- }-- ss = source->state;-- zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));-- ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));- if (ds == Z_NULL) return Z_MEM_ERROR;- dest->state = (struct internal_state FAR *) ds;- zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));- ds->strm = dest;-- ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));- ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));- ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));- overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);- ds->pending_buf = (uchf *) overlay;-- if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||- ds->pending_buf == Z_NULL) {- deflateEnd (dest);- return Z_MEM_ERROR;- }- /* following zmemcpy do not work for 16-bit MSDOS */- zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));- zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));- zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));- zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);-- ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);- ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);- ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;-- ds->l_desc.dyn_tree = ds->dyn_ltree;- ds->d_desc.dyn_tree = ds->dyn_dtree;- ds->bl_desc.dyn_tree = ds->bl_tree;-- return Z_OK;-#endif /* MAXSEG_64K */-}--/* ===========================================================================- * Read a new buffer from the current input stream, update the adler32- * and total number of bytes read. All deflate() input goes through- * this function so some applications may wish to modify it to avoid- * allocating a large strm->next_in buffer and copying from it.- * (See also flush_pending()).- */-local unsigned read_buf(strm, buf, size)- z_streamp strm;- Bytef *buf;- unsigned size;-{- unsigned len = strm->avail_in;-- if (len > size) len = size;- if (len == 0) return 0;-- strm->avail_in -= len;-- zmemcpy(buf, strm->next_in, len);- if (strm->state->wrap == 1) {- strm->adler = adler32(strm->adler, buf, len);- }-#ifdef GZIP- else if (strm->state->wrap == 2) {- strm->adler = crc32(strm->adler, buf, len);- }-#endif- strm->next_in += len;- strm->total_in += len;-- return len;-}--/* ===========================================================================- * Initialize the "longest match" routines for a new zlib stream- */-local void lm_init (s)- deflate_state *s;-{- s->window_size = (ulg)2L*s->w_size;-- CLEAR_HASH(s);-- /* Set the default configuration parameters:- */- s->max_lazy_match = configuration_table[s->level].max_lazy;- s->good_match = configuration_table[s->level].good_length;- s->nice_match = configuration_table[s->level].nice_length;- s->max_chain_length = configuration_table[s->level].max_chain;-- s->strstart = 0;- s->block_start = 0L;- s->lookahead = 0;- s->insert = 0;- s->match_length = s->prev_length = MIN_MATCH-1;- s->match_available = 0;- s->ins_h = 0;-#ifndef FASTEST-#ifdef ASMV- match_init(); /* initialize the asm code */-#endif-#endif-}--#ifndef FASTEST-/* ===========================================================================- * Set match_start to the longest match starting at the given string and- * return its length. Matches shorter or equal to prev_length are discarded,- * in which case the result is equal to prev_length and match_start is- * garbage.- * IN assertions: cur_match is the head of the hash chain for the current- * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1- * OUT assertion: the match length is not greater than s->lookahead.- */-#ifndef ASMV-/* For 80x86 and 680x0, an optimized version will be provided in match.asm or- * match.S. The code will be functionally equivalent.- */-local uInt longest_match(s, cur_match)- deflate_state *s;- IPos cur_match; /* current match */-{- unsigned chain_length = s->max_chain_length;/* max hash chain length */- register Bytef *scan = s->window + s->strstart; /* current string */- register Bytef *match; /* matched string */- register int len; /* length of current match */- int best_len = (int)s->prev_length; /* best match length so far */- int nice_match = s->nice_match; /* stop if match long enough */- IPos limit = s->strstart > (IPos)MAX_DIST(s) ?- s->strstart - (IPos)MAX_DIST(s) : NIL;- /* Stop when cur_match becomes <= limit. To simplify the code,- * we prevent matches with the string of window index 0.- */- Posf *prev = s->prev;- uInt wmask = s->w_mask;--#ifdef UNALIGNED_OK- /* Compare two bytes at a time. Note: this is not always beneficial.- * Try with and without -DUNALIGNED_OK to check.- */- register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;- register ush scan_start = *(ushf*)scan;- register ush scan_end = *(ushf*)(scan+best_len-1);-#else- register Bytef *strend = s->window + s->strstart + MAX_MATCH;- register Byte scan_end1 = scan[best_len-1];- register Byte scan_end = scan[best_len];-#endif-- /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.- * It is easy to get rid of this optimization if necessary.- */- Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");-- /* Do not waste too much time if we already have a good match: */- if (s->prev_length >= s->good_match) {- chain_length >>= 2;- }- /* Do not look for matches beyond the end of the input. This is necessary- * to make deflate deterministic.- */- if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead;-- Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");-- do {- Assert(cur_match < s->strstart, "no future");- match = s->window + cur_match;-- /* Skip to next match if the match length cannot increase- * or if the match length is less than 2. Note that the checks below- * for insufficient lookahead only occur occasionally for performance- * reasons. Therefore uninitialized memory will be accessed, and- * conditional jumps will be made that depend on those values.- * However the length of the match is limited to the lookahead, so- * the output of deflate is not affected by the uninitialized values.- */-#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)- /* This code assumes sizeof(unsigned short) == 2. Do not use- * UNALIGNED_OK if your compiler uses a different size.- */- if (*(ushf*)(match+best_len-1) != scan_end ||- *(ushf*)match != scan_start) continue;-- /* It is not necessary to compare scan[2] and match[2] since they are- * always equal when the other bytes match, given that the hash keys- * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at- * strstart+3, +5, ... up to strstart+257. We check for insufficient- * lookahead only every 4th comparison; the 128th check will be made- * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is- * necessary to put more guard bytes at the end of the window, or- * to check more often for insufficient lookahead.- */- Assert(scan[2] == match[2], "scan[2]?");- scan++, match++;- do {- } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&- *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&- *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&- *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&- scan < strend);- /* The funny "do {}" generates better code on most compilers */-- /* Here, scan <= window+strstart+257 */- Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");- if (*scan == *match) scan++;-- len = (MAX_MATCH - 1) - (int)(strend-scan);- scan = strend - (MAX_MATCH-1);--#else /* UNALIGNED_OK */-- if (match[best_len] != scan_end ||- match[best_len-1] != scan_end1 ||- *match != *scan ||- *++match != scan[1]) continue;-- /* The check at best_len-1 can be removed because it will be made- * again later. (This heuristic is not always a win.)- * It is not necessary to compare scan[2] and match[2] since they- * are always equal when the other bytes match, given that- * the hash keys are equal and that HASH_BITS >= 8.- */- scan += 2, match++;- Assert(*scan == *match, "match[2]?");-- /* We check for insufficient lookahead only every 8th comparison;- * the 256th check will be made at strstart+258.- */- do {- } while (*++scan == *++match && *++scan == *++match &&- *++scan == *++match && *++scan == *++match &&- *++scan == *++match && *++scan == *++match &&- *++scan == *++match && *++scan == *++match &&- scan < strend);-- Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");-- len = MAX_MATCH - (int)(strend - scan);- scan = strend - MAX_MATCH;--#endif /* UNALIGNED_OK */-- if (len > best_len) {- s->match_start = cur_match;- best_len = len;- if (len >= nice_match) break;-#ifdef UNALIGNED_OK- scan_end = *(ushf*)(scan+best_len-1);-#else- scan_end1 = scan[best_len-1];- scan_end = scan[best_len];-#endif- }- } while ((cur_match = prev[cur_match & wmask]) > limit- && --chain_length != 0);-- if ((uInt)best_len <= s->lookahead) return (uInt)best_len;- return s->lookahead;-}-#endif /* ASMV */--#else /* FASTEST */--/* ---------------------------------------------------------------------------- * Optimized version for FASTEST only- */-local uInt longest_match(s, cur_match)- deflate_state *s;- IPos cur_match; /* current match */-{- register Bytef *scan = s->window + s->strstart; /* current string */- register Bytef *match; /* matched string */- register int len; /* length of current match */- register Bytef *strend = s->window + s->strstart + MAX_MATCH;-- /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.- * It is easy to get rid of this optimization if necessary.- */- Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");-- Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");-- Assert(cur_match < s->strstart, "no future");-- match = s->window + cur_match;-- /* Return failure if the match length is less than 2:- */- if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;-- /* The check at best_len-1 can be removed because it will be made- * again later. (This heuristic is not always a win.)- * It is not necessary to compare scan[2] and match[2] since they- * are always equal when the other bytes match, given that- * the hash keys are equal and that HASH_BITS >= 8.- */- scan += 2, match += 2;- Assert(*scan == *match, "match[2]?");-- /* We check for insufficient lookahead only every 8th comparison;- * the 256th check will be made at strstart+258.- */- do {- } while (*++scan == *++match && *++scan == *++match &&- *++scan == *++match && *++scan == *++match &&- *++scan == *++match && *++scan == *++match &&- *++scan == *++match && *++scan == *++match &&- scan < strend);-- Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");-- len = MAX_MATCH - (int)(strend - scan);-- if (len < MIN_MATCH) return MIN_MATCH - 1;-- s->match_start = cur_match;- return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;-}--#endif /* FASTEST */--#ifdef ZLIB_DEBUG--#define EQUAL 0-/* result of memcmp for equal strings */--/* ===========================================================================- * Check that the match at match_start is indeed a match.- */-local void check_match(s, start, match, length)- deflate_state *s;- IPos start, match;- int length;-{- /* check that the match is indeed a match */- if (zmemcmp(s->window + match,- s->window + start, length) != EQUAL) {- fprintf(stderr, " start %u, match %u, length %d\n",- start, match, length);- do {- fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);- } while (--length != 0);- z_error("invalid match");- }- if (z_verbose > 1) {- fprintf(stderr,"\\[%d,%d]", start-match, length);- do { putc(s->window[start++], stderr); } while (--length != 0);- }-}-#else-# define check_match(s, start, match, length)-#endif /* ZLIB_DEBUG */--/* ===========================================================================- * Fill the window when the lookahead becomes insufficient.- * Updates strstart and lookahead.- *- * IN assertion: lookahead < MIN_LOOKAHEAD- * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD- * At least one byte has been read, or avail_in == 0; reads are- * performed for at least two bytes (required for the zip translate_eol- * option -- not supported here).- */-local void fill_window(s)- deflate_state *s;-{- unsigned n;- unsigned more; /* Amount of free space at the end of the window. */- uInt wsize = s->w_size;-- Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");-- do {- more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);-- /* Deal with !@#$% 64K limit: */- if (sizeof(int) <= 2) {- if (more == 0 && s->strstart == 0 && s->lookahead == 0) {- more = wsize;-- } else if (more == (unsigned)(-1)) {- /* Very unlikely, but possible on 16 bit machine if- * strstart == 0 && lookahead == 1 (input done a byte at time)- */- more--;- }- }-- /* If the window is almost full and there is insufficient lookahead,- * move the upper half to the lower one to make room in the upper half.- */- if (s->strstart >= wsize+MAX_DIST(s)) {-- zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more);- s->match_start -= wsize;- s->strstart -= wsize; /* we now have strstart >= MAX_DIST */- s->block_start -= (long) wsize;- slide_hash(s);- more += wsize;- }- if (s->strm->avail_in == 0) break;-- /* If there was no sliding:- * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&- * more == window_size - lookahead - strstart- * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)- * => more >= window_size - 2*WSIZE + 2- * In the BIG_MEM or MMAP case (not yet supported),- * window_size == input_size + MIN_LOOKAHEAD &&- * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.- * Otherwise, window_size == 2*WSIZE so more >= 2.- * If there was sliding, more >= WSIZE. So in all cases, more >= 2.- */- Assert(more >= 2, "more < 2");-- n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);- s->lookahead += n;-- /* Initialize the hash value now that we have some input: */- if (s->lookahead + s->insert >= MIN_MATCH) {- uInt str = s->strstart - s->insert;- s->ins_h = s->window[str];- UPDATE_HASH(s, s->ins_h, s->window[str + 1]);-#if MIN_MATCH != 3- Call UPDATE_HASH() MIN_MATCH-3 more times-#endif- while (s->insert) {- UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);-#ifndef FASTEST- s->prev[str & s->w_mask] = s->head[s->ins_h];-#endif- s->head[s->ins_h] = (Pos)str;- str++;- s->insert--;- if (s->lookahead + s->insert < MIN_MATCH)- break;- }- }- /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,- * but this is not important since only literal bytes will be emitted.- */-- } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);-- /* If the WIN_INIT bytes after the end of the current data have never been- * written, then zero those bytes in order to avoid memory check reports of- * the use of uninitialized (or uninitialised as Julian writes) bytes by- * the longest match routines. Update the high water mark for the next- * time through here. WIN_INIT is set to MAX_MATCH since the longest match- * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.- */- if (s->high_water < s->window_size) {- ulg curr = s->strstart + (ulg)(s->lookahead);- ulg init;-- if (s->high_water < curr) {- /* Previous high water mark below current data -- zero WIN_INIT- * bytes or up to end of window, whichever is less.- */- init = s->window_size - curr;- if (init > WIN_INIT)- init = WIN_INIT;- zmemzero(s->window + curr, (unsigned)init);- s->high_water = curr + init;- }- else if (s->high_water < (ulg)curr + WIN_INIT) {- /* High water mark at or above current data, but below current data- * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up- * to end of window, whichever is less.- */- init = (ulg)curr + WIN_INIT - s->high_water;- if (init > s->window_size - s->high_water)- init = s->window_size - s->high_water;- zmemzero(s->window + s->high_water, (unsigned)init);- s->high_water += init;- }- }-- Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,- "not enough room for search");-}--/* ===========================================================================- * Flush the current block, with given end-of-file flag.- * IN assertion: strstart is set to the end of the current match.- */-#define FLUSH_BLOCK_ONLY(s, last) { \- _tr_flush_block(s, (s->block_start >= 0L ? \- (charf *)&s->window[(unsigned)s->block_start] : \- (charf *)Z_NULL), \- (ulg)((long)s->strstart - s->block_start), \- (last)); \- s->block_start = s->strstart; \- flush_pending(s->strm); \- Tracev((stderr,"[FLUSH]")); \-}--/* Same but force premature exit if necessary. */-#define FLUSH_BLOCK(s, last) { \- FLUSH_BLOCK_ONLY(s, last); \- if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \-}--/* Maximum stored block length in deflate format (not including header). */-#define MAX_STORED 65535--/* Minimum of a and b. */-#define MIN(a, b) ((a) > (b) ? (b) : (a))--/* ===========================================================================- * Copy without compression as much as possible from the input stream, return- * the current block state.- *- * In case deflateParams() is used to later switch to a non-zero compression- * level, s->matches (otherwise unused when storing) keeps track of the number- * of hash table slides to perform. If s->matches is 1, then one hash table- * slide will be done when switching. If s->matches is 2, the maximum value- * allowed here, then the hash table will be cleared, since two or more slides- * is the same as a clear.- *- * deflate_stored() is written to minimize the number of times an input byte is- * copied. It is most efficient with large input and output buffers, which- * maximizes the opportunites to have a single copy from next_in to next_out.- */-local block_state deflate_stored(s, flush)- deflate_state *s;- int flush;-{- /* Smallest worthy block size when not flushing or finishing. By default- * this is 32K. This can be as small as 507 bytes for memLevel == 1. For- * large input and output buffers, the stored block size will be larger.- */- unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size);-- /* Copy as many min_block or larger stored blocks directly to next_out as- * possible. If flushing, copy the remaining available input to next_out as- * stored blocks, if there is enough space.- */- unsigned len, left, have, last = 0;- unsigned used = s->strm->avail_in;- do {- /* Set len to the maximum size block that we can copy directly with the- * available input data and output space. Set left to how much of that- * would be copied from what's left in the window.- */- len = MAX_STORED; /* maximum deflate stored block length */- have = (s->bi_valid + 42) >> 3; /* number of header bytes */- if (s->strm->avail_out < have) /* need room for header */- break;- /* maximum stored block length that will fit in avail_out: */- have = s->strm->avail_out - have;- left = s->strstart - s->block_start; /* bytes left in window */- if (len > (ulg)left + s->strm->avail_in)- len = left + s->strm->avail_in; /* limit len to the input */- if (len > have)- len = have; /* limit len to the output */-- /* If the stored block would be less than min_block in length, or if- * unable to copy all of the available input when flushing, then try- * copying to the window and the pending buffer instead. Also don't- * write an empty block when flushing -- deflate() does that.- */- if (len < min_block && ((len == 0 && flush != Z_FINISH) ||- flush == Z_NO_FLUSH ||- len != left + s->strm->avail_in))- break;-- /* Make a dummy stored block in pending to get the header bytes,- * including any pending bits. This also updates the debugging counts.- */- last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0;- _tr_stored_block(s, (char *)0, 0L, last);-- /* Replace the lengths in the dummy stored block with len. */- s->pending_buf[s->pending - 4] = len;- s->pending_buf[s->pending - 3] = len >> 8;- s->pending_buf[s->pending - 2] = ~len;- s->pending_buf[s->pending - 1] = ~len >> 8;-- /* Write the stored block header bytes. */- flush_pending(s->strm);--#ifdef ZLIB_DEBUG- /* Update debugging counts for the data about to be copied. */- s->compressed_len += len << 3;- s->bits_sent += len << 3;-#endif-- /* Copy uncompressed bytes from the window to next_out. */- if (left) {- if (left > len)- left = len;- zmemcpy(s->strm->next_out, s->window + s->block_start, left);- s->strm->next_out += left;- s->strm->avail_out -= left;- s->strm->total_out += left;- s->block_start += left;- len -= left;- }-- /* Copy uncompressed bytes directly from next_in to next_out, updating- * the check value.- */- if (len) {- read_buf(s->strm, s->strm->next_out, len);- s->strm->next_out += len;- s->strm->avail_out -= len;- s->strm->total_out += len;- }- } while (last == 0);-- /* Update the sliding window with the last s->w_size bytes of the copied- * data, or append all of the copied data to the existing window if less- * than s->w_size bytes were copied. Also update the number of bytes to- * insert in the hash tables, in the event that deflateParams() switches to- * a non-zero compression level.- */- used -= s->strm->avail_in; /* number of input bytes directly copied */- if (used) {- /* If any input was used, then no unused input remains in the window,- * therefore s->block_start == s->strstart.- */- if (used >= s->w_size) { /* supplant the previous history */- s->matches = 2; /* clear hash */- zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size);- s->strstart = s->w_size;- }- else {- if (s->window_size - s->strstart <= used) {- /* Slide the window down. */- s->strstart -= s->w_size;- zmemcpy(s->window, s->window + s->w_size, s->strstart);- if (s->matches < 2)- s->matches++; /* add a pending slide_hash() */- }- zmemcpy(s->window + s->strstart, s->strm->next_in - used, used);- s->strstart += used;- }- s->block_start = s->strstart;- s->insert += MIN(used, s->w_size - s->insert);- }- if (s->high_water < s->strstart)- s->high_water = s->strstart;-- /* If the last block was written to next_out, then done. */- if (last)- return finish_done;-- /* If flushing and all input has been consumed, then done. */- if (flush != Z_NO_FLUSH && flush != Z_FINISH &&- s->strm->avail_in == 0 && (long)s->strstart == s->block_start)- return block_done;-- /* Fill the window with any remaining input. */- have = s->window_size - s->strstart - 1;- if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) {- /* Slide the window down. */- s->block_start -= s->w_size;- s->strstart -= s->w_size;- zmemcpy(s->window, s->window + s->w_size, s->strstart);- if (s->matches < 2)- s->matches++; /* add a pending slide_hash() */- have += s->w_size; /* more space now */- }- if (have > s->strm->avail_in)- have = s->strm->avail_in;- if (have) {- read_buf(s->strm, s->window + s->strstart, have);- s->strstart += have;- }- if (s->high_water < s->strstart)- s->high_water = s->strstart;-- /* There was not enough avail_out to write a complete worthy or flushed- * stored block to next_out. Write a stored block to pending instead, if we- * have enough input for a worthy block, or if flushing and there is enough- * room for the remaining input as a stored block in the pending buffer.- */- have = (s->bi_valid + 42) >> 3; /* number of header bytes */- /* maximum stored block length that will fit in pending: */- have = MIN(s->pending_buf_size - have, MAX_STORED);- min_block = MIN(have, s->w_size);- left = s->strstart - s->block_start;- if (left >= min_block ||- ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH &&- s->strm->avail_in == 0 && left <= have)) {- len = MIN(left, have);- last = flush == Z_FINISH && s->strm->avail_in == 0 &&- len == left ? 1 : 0;- _tr_stored_block(s, (charf *)s->window + s->block_start, len, last);- s->block_start += len;- flush_pending(s->strm);- }-- /* We've done all we can with the available input and output. */- return last ? finish_started : need_more;-}--/* ===========================================================================- * Compress as much as possible from the input stream, return the current- * block state.- * This function does not perform lazy evaluation of matches and inserts- * new strings in the dictionary only for unmatched strings or for short- * matches. It is used only for the fast compression options.- */-local block_state deflate_fast(s, flush)- deflate_state *s;- int flush;-{- IPos hash_head; /* head of the hash chain */- int bflush; /* set if current block must be flushed */-- for (;;) {- /* Make sure that we always have enough lookahead, except- * at the end of the input file. We need MAX_MATCH bytes- * for the next match, plus MIN_MATCH bytes to insert the- * string following the next match.- */- if (s->lookahead < MIN_LOOKAHEAD) {- fill_window(s);- if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {- return need_more;- }- if (s->lookahead == 0) break; /* flush the current block */- }-- /* Insert the string window[strstart .. strstart+2] in the- * dictionary, and set hash_head to the head of the hash chain:- */- hash_head = NIL;- if (s->lookahead >= MIN_MATCH) {- INSERT_STRING(s, s->strstart, hash_head);- }-- /* Find the longest match, discarding those <= prev_length.- * At this point we have always match_length < MIN_MATCH- */- if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {- /* To simplify the code, we prevent matches with the string- * of window index 0 (in particular we have to avoid a match- * of the string with itself at the start of the input file).- */- s->match_length = longest_match (s, hash_head);- /* longest_match() sets match_start */- }- if (s->match_length >= MIN_MATCH) {- check_match(s, s->strstart, s->match_start, s->match_length);-- _tr_tally_dist(s, s->strstart - s->match_start,- s->match_length - MIN_MATCH, bflush);-- s->lookahead -= s->match_length;-- /* Insert new strings in the hash table only if the match length- * is not too large. This saves time but degrades compression.- */-#ifndef FASTEST- if (s->match_length <= s->max_insert_length &&- s->lookahead >= MIN_MATCH) {- s->match_length--; /* string at strstart already in table */- do {- s->strstart++;- INSERT_STRING(s, s->strstart, hash_head);- /* strstart never exceeds WSIZE-MAX_MATCH, so there are- * always MIN_MATCH bytes ahead.- */- } while (--s->match_length != 0);- s->strstart++;- } else-#endif- {- s->strstart += s->match_length;- s->match_length = 0;- s->ins_h = s->window[s->strstart];- UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);-#if MIN_MATCH != 3- Call UPDATE_HASH() MIN_MATCH-3 more times-#endif- /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not- * matter since it will be recomputed at next deflate call.- */- }- } else {- /* No match, output a literal byte */- Tracevv((stderr,"%c", s->window[s->strstart]));- _tr_tally_lit (s, s->window[s->strstart], bflush);- s->lookahead--;- s->strstart++;- }- if (bflush) FLUSH_BLOCK(s, 0);- }- s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;- if (flush == Z_FINISH) {- FLUSH_BLOCK(s, 1);- return finish_done;- }- if (s->last_lit)- FLUSH_BLOCK(s, 0);- return block_done;-}--#ifndef FASTEST-/* ===========================================================================- * Same as above, but achieves better compression. We use a lazy- * evaluation for matches: a match is finally adopted only if there is- * no better match at the next window position.- */-local block_state deflate_slow(s, flush)- deflate_state *s;- int flush;-{- IPos hash_head; /* head of hash chain */- int bflush; /* set if current block must be flushed */-- /* Process the input block. */- for (;;) {- /* Make sure that we always have enough lookahead, except- * at the end of the input file. We need MAX_MATCH bytes- * for the next match, plus MIN_MATCH bytes to insert the- * string following the next match.- */- if (s->lookahead < MIN_LOOKAHEAD) {- fill_window(s);- if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {- return need_more;- }- if (s->lookahead == 0) break; /* flush the current block */- }-- /* Insert the string window[strstart .. strstart+2] in the- * dictionary, and set hash_head to the head of the hash chain:- */- hash_head = NIL;- if (s->lookahead >= MIN_MATCH) {- INSERT_STRING(s, s->strstart, hash_head);- }-- /* Find the longest match, discarding those <= prev_length.- */- s->prev_length = s->match_length, s->prev_match = s->match_start;- s->match_length = MIN_MATCH-1;-- if (hash_head != NIL && s->prev_length < s->max_lazy_match &&- s->strstart - hash_head <= MAX_DIST(s)) {- /* To simplify the code, we prevent matches with the string- * of window index 0 (in particular we have to avoid a match- * of the string with itself at the start of the input file).- */- s->match_length = longest_match (s, hash_head);- /* longest_match() sets match_start */-- if (s->match_length <= 5 && (s->strategy == Z_FILTERED-#if TOO_FAR <= 32767- || (s->match_length == MIN_MATCH &&- s->strstart - s->match_start > TOO_FAR)-#endif- )) {-- /* If prev_match is also MIN_MATCH, match_start is garbage- * but we will ignore the current match anyway.- */- s->match_length = MIN_MATCH-1;- }- }- /* If there was a match at the previous step and the current- * match is not better, output the previous match:- */- if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {- uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;- /* Do not insert strings in hash table beyond this. */-- check_match(s, s->strstart-1, s->prev_match, s->prev_length);-- _tr_tally_dist(s, s->strstart -1 - s->prev_match,- s->prev_length - MIN_MATCH, bflush);-- /* Insert in hash table all strings up to the end of the match.- * strstart-1 and strstart are already inserted. If there is not- * enough lookahead, the last two strings are not inserted in- * the hash table.- */- s->lookahead -= s->prev_length-1;- s->prev_length -= 2;- do {- if (++s->strstart <= max_insert) {- INSERT_STRING(s, s->strstart, hash_head);- }- } while (--s->prev_length != 0);- s->match_available = 0;- s->match_length = MIN_MATCH-1;- s->strstart++;-- if (bflush) FLUSH_BLOCK(s, 0);-- } else if (s->match_available) {- /* If there was no match at the previous position, output a- * single literal. If there was a match but the current match- * is longer, truncate the previous match to a single literal.- */- Tracevv((stderr,"%c", s->window[s->strstart-1]));- _tr_tally_lit(s, s->window[s->strstart-1], bflush);- if (bflush) {- FLUSH_BLOCK_ONLY(s, 0);- }- s->strstart++;- s->lookahead--;- if (s->strm->avail_out == 0) return need_more;- } else {- /* There is no previous match to compare with, wait for- * the next step to decide.- */- s->match_available = 1;- s->strstart++;- s->lookahead--;- }- }- Assert (flush != Z_NO_FLUSH, "no flush?");- if (s->match_available) {- Tracevv((stderr,"%c", s->window[s->strstart-1]));- _tr_tally_lit(s, s->window[s->strstart-1], bflush);- s->match_available = 0;- }- s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;- if (flush == Z_FINISH) {- FLUSH_BLOCK(s, 1);- return finish_done;- }- if (s->last_lit)- FLUSH_BLOCK(s, 0);- return block_done;-}-#endif /* FASTEST */--/* ===========================================================================- * For Z_RLE, simply look for runs of bytes, generate matches only of distance- * one. Do not maintain a hash table. (It will be regenerated if this run of- * deflate switches away from Z_RLE.)- */-local block_state deflate_rle(s, flush)- deflate_state *s;- int flush;-{- int bflush; /* set if current block must be flushed */- uInt prev; /* byte at distance one to match */- Bytef *scan, *strend; /* scan goes up to strend for length of run */-- for (;;) {- /* Make sure that we always have enough lookahead, except- * at the end of the input file. We need MAX_MATCH bytes- * for the longest run, plus one for the unrolled loop.- */- if (s->lookahead <= MAX_MATCH) {- fill_window(s);- if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) {- return need_more;- }- if (s->lookahead == 0) break; /* flush the current block */- }-- /* See how many times the previous byte repeats */- s->match_length = 0;- if (s->lookahead >= MIN_MATCH && s->strstart > 0) {- scan = s->window + s->strstart - 1;- prev = *scan;- if (prev == *++scan && prev == *++scan && prev == *++scan) {- strend = s->window + s->strstart + MAX_MATCH;- do {- } while (prev == *++scan && prev == *++scan &&- prev == *++scan && prev == *++scan &&- prev == *++scan && prev == *++scan &&- prev == *++scan && prev == *++scan &&- scan < strend);- s->match_length = MAX_MATCH - (uInt)(strend - scan);- if (s->match_length > s->lookahead)- s->match_length = s->lookahead;- }- Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");- }-- /* Emit match if have run of MIN_MATCH or longer, else emit literal */- if (s->match_length >= MIN_MATCH) {- check_match(s, s->strstart, s->strstart - 1, s->match_length);-- _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);-- s->lookahead -= s->match_length;- s->strstart += s->match_length;- s->match_length = 0;- } else {- /* No match, output a literal byte */- Tracevv((stderr,"%c", s->window[s->strstart]));- _tr_tally_lit (s, s->window[s->strstart], bflush);- s->lookahead--;- s->strstart++;- }- if (bflush) FLUSH_BLOCK(s, 0);- }- s->insert = 0;- if (flush == Z_FINISH) {- FLUSH_BLOCK(s, 1);- return finish_done;- }- if (s->last_lit)- FLUSH_BLOCK(s, 0);- return block_done;-}--/* ===========================================================================- * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.- * (It will be regenerated if this run of deflate switches away from Huffman.)- */-local block_state deflate_huff(s, flush)- deflate_state *s;- int flush;-{- int bflush; /* set if current block must be flushed */-- for (;;) {- /* Make sure that we have a literal to write. */- if (s->lookahead == 0) {- fill_window(s);- if (s->lookahead == 0) {- if (flush == Z_NO_FLUSH)- return need_more;- break; /* flush the current block */- }- }-- /* Output a literal byte */- s->match_length = 0;- Tracevv((stderr,"%c", s->window[s->strstart]));- _tr_tally_lit (s, s->window[s->strstart], bflush);- s->lookahead--;- s->strstart++;- if (bflush) FLUSH_BLOCK(s, 0);- }- s->insert = 0;- if (flush == Z_FINISH) {- FLUSH_BLOCK(s, 1);- return finish_done;- }- if (s->last_lit)- FLUSH_BLOCK(s, 0);- return block_done;-}
− c/zlib/deflate.h
@@ -1,349 +0,0 @@-/* deflate.h -- internal compression state- * Copyright (C) 1995-2016 Jean-loup Gailly- * For conditions of distribution and use, see copyright notice in zlib.h- */--/* WARNING: this file should *not* be used by applications. It is- part of the implementation of the compression library and is- subject to change. Applications should only use zlib.h.- */--/* @(#) $Id$ */--#ifndef DEFLATE_H-#define DEFLATE_H--#include "zutil.h"--/* define NO_GZIP when compiling if you want to disable gzip header and- trailer creation by deflate(). NO_GZIP would be used to avoid linking in- the crc code when it is not needed. For shared libraries, gzip encoding- should be left enabled. */-#ifndef NO_GZIP-# define GZIP-#endif--/* ===========================================================================- * Internal compression state.- */--#define LENGTH_CODES 29-/* number of length codes, not counting the special END_BLOCK code */--#define LITERALS 256-/* number of literal bytes 0..255 */--#define L_CODES (LITERALS+1+LENGTH_CODES)-/* number of Literal or Length codes, including the END_BLOCK code */--#define D_CODES 30-/* number of distance codes */--#define BL_CODES 19-/* number of codes used to transfer the bit lengths */--#define HEAP_SIZE (2*L_CODES+1)-/* maximum heap size */--#define MAX_BITS 15-/* All codes must not exceed MAX_BITS bits */--#define Buf_size 16-/* size of bit buffer in bi_buf */--#define INIT_STATE 42 /* zlib header -> BUSY_STATE */-#ifdef GZIP-# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */-#endif-#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */-#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */-#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */-#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */-#define BUSY_STATE 113 /* deflate -> FINISH_STATE */-#define FINISH_STATE 666 /* stream complete */-/* Stream status */---/* Data structure describing a single value and its code string. */-typedef struct ct_data_s {- union {- ush freq; /* frequency count */- ush code; /* bit string */- } fc;- union {- ush dad; /* father node in Huffman tree */- ush len; /* length of bit string */- } dl;-} FAR ct_data;--#define Freq fc.freq-#define Code fc.code-#define Dad dl.dad-#define Len dl.len--typedef struct static_tree_desc_s static_tree_desc;--typedef struct tree_desc_s {- ct_data *dyn_tree; /* the dynamic tree */- int max_code; /* largest code with non zero frequency */- const static_tree_desc *stat_desc; /* the corresponding static tree */-} FAR tree_desc;--typedef ush Pos;-typedef Pos FAR Posf;-typedef unsigned IPos;--/* A Pos is an index in the character window. We use short instead of int to- * save space in the various tables. IPos is used only for parameter passing.- */--typedef struct internal_state {- z_streamp strm; /* pointer back to this zlib stream */- int status; /* as the name implies */- Bytef *pending_buf; /* output still pending */- ulg pending_buf_size; /* size of pending_buf */- Bytef *pending_out; /* next pending byte to output to the stream */- ulg pending; /* nb of bytes in the pending buffer */- int wrap; /* bit 0 true for zlib, bit 1 true for gzip */- gz_headerp gzhead; /* gzip header information to write */- ulg gzindex; /* where in extra, name, or comment */- Byte method; /* can only be DEFLATED */- int last_flush; /* value of flush param for previous deflate call */-- /* used by deflate.c: */-- uInt w_size; /* LZ77 window size (32K by default) */- uInt w_bits; /* log2(w_size) (8..16) */- uInt w_mask; /* w_size - 1 */-- Bytef *window;- /* Sliding window. Input bytes are read into the second half of the window,- * and move to the first half later to keep a dictionary of at least wSize- * bytes. With this organization, matches are limited to a distance of- * wSize-MAX_MATCH bytes, but this ensures that IO is always- * performed with a length multiple of the block size. Also, it limits- * the window size to 64K, which is quite useful on MSDOS.- * To do: use the user input buffer as sliding window.- */-- ulg window_size;- /* Actual size of window: 2*wSize, except when the user input buffer- * is directly used as sliding window.- */-- Posf *prev;- /* Link to older string with same hash index. To limit the size of this- * array to 64K, this link is maintained only for the last 32K strings.- * An index in this array is thus a window index modulo 32K.- */-- Posf *head; /* Heads of the hash chains or NIL. */-- uInt ins_h; /* hash index of string to be inserted */- uInt hash_size; /* number of elements in hash table */- uInt hash_bits; /* log2(hash_size) */- uInt hash_mask; /* hash_size-1 */-- uInt hash_shift;- /* Number of bits by which ins_h must be shifted at each input- * step. It must be such that after MIN_MATCH steps, the oldest- * byte no longer takes part in the hash key, that is:- * hash_shift * MIN_MATCH >= hash_bits- */-- long block_start;- /* Window position at the beginning of the current output block. Gets- * negative when the window is moved backwards.- */-- uInt match_length; /* length of best match */- IPos prev_match; /* previous match */- int match_available; /* set if previous match exists */- uInt strstart; /* start of string to insert */- uInt match_start; /* start of matching string */- uInt lookahead; /* number of valid bytes ahead in window */-- uInt prev_length;- /* Length of the best match at previous step. Matches not greater than this- * are discarded. This is used in the lazy match evaluation.- */-- uInt max_chain_length;- /* To speed up deflation, hash chains are never searched beyond this- * length. A higher limit improves compression ratio but degrades the- * speed.- */-- uInt max_lazy_match;- /* Attempt to find a better match only when the current match is strictly- * smaller than this value. This mechanism is used only for compression- * levels >= 4.- */-# define max_insert_length max_lazy_match- /* Insert new strings in the hash table only if the match length is not- * greater than this length. This saves time but degrades compression.- * max_insert_length is used only for compression levels <= 3.- */-- int level; /* compression level (1..9) */- int strategy; /* favor or force Huffman coding*/-- uInt good_match;- /* Use a faster search when the previous match is longer than this */-- int nice_match; /* Stop searching when current match exceeds this */-- /* used by trees.c: */- /* Didn't use ct_data typedef below to suppress compiler warning */- struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */- struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */- struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */-- struct tree_desc_s l_desc; /* desc. for literal tree */- struct tree_desc_s d_desc; /* desc. for distance tree */- struct tree_desc_s bl_desc; /* desc. for bit length tree */-- ush bl_count[MAX_BITS+1];- /* number of codes at each bit length for an optimal tree */-- int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */- int heap_len; /* number of elements in the heap */- int heap_max; /* element of largest frequency */- /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.- * The same heap array is used to build all trees.- */-- uch depth[2*L_CODES+1];- /* Depth of each subtree used as tie breaker for trees of equal frequency- */-- uchf *l_buf; /* buffer for literals or lengths */-- uInt lit_bufsize;- /* Size of match buffer for literals/lengths. There are 4 reasons for- * limiting lit_bufsize to 64K:- * - frequencies can be kept in 16 bit counters- * - if compression is not successful for the first block, all input- * data is still in the window so we can still emit a stored block even- * when input comes from standard input. (This can also be done for- * all blocks if lit_bufsize is not greater than 32K.)- * - if compression is not successful for a file smaller than 64K, we can- * even emit a stored file instead of a stored block (saving 5 bytes).- * This is applicable only for zip (not gzip or zlib).- * - creating new Huffman trees less frequently may not provide fast- * adaptation to changes in the input data statistics. (Take for- * example a binary file with poorly compressible code followed by- * a highly compressible string table.) Smaller buffer sizes give- * fast adaptation but have of course the overhead of transmitting- * trees more frequently.- * - I can't count above 4- */-- uInt last_lit; /* running index in l_buf */-- ushf *d_buf;- /* Buffer for distances. To simplify the code, d_buf and l_buf have- * the same number of elements. To use different lengths, an extra flag- * array would be necessary.- */-- ulg opt_len; /* bit length of current block with optimal trees */- ulg static_len; /* bit length of current block with static trees */- uInt matches; /* number of string matches in current block */- uInt insert; /* bytes at end of window left to insert */--#ifdef ZLIB_DEBUG- ulg compressed_len; /* total bit length of compressed file mod 2^32 */- ulg bits_sent; /* bit length of compressed data sent mod 2^32 */-#endif-- ush bi_buf;- /* Output buffer. bits are inserted starting at the bottom (least- * significant bits).- */- int bi_valid;- /* Number of valid bits in bi_buf. All bits above the last valid bit- * are always zero.- */-- ulg high_water;- /* High water mark offset in window for initialized bytes -- bytes above- * this are set to zero in order to avoid memory check warnings when- * longest match routines access bytes past the input. This is then- * updated to the new high water mark.- */--} FAR deflate_state;--/* Output a byte on the stream.- * IN assertion: there is enough room in pending_buf.- */-#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);}---#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)-/* Minimum amount of lookahead, except at the end of the input file.- * See deflate.c for comments about the MIN_MATCH+1.- */--#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)-/* In order to simplify the code, particularly on 16 bit machines, match- * distances are limited to MAX_DIST instead of WSIZE.- */--#define WIN_INIT MAX_MATCH-/* Number of bytes after end of data in window to initialize in order to avoid- memory checker errors from longest match routines */-- /* in trees.c */-void ZLIB_INTERNAL _tr_init OF((deflate_state *s));-int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));-void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,- ulg stored_len, int last));-void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));-void ZLIB_INTERNAL _tr_align OF((deflate_state *s));-void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,- ulg stored_len, int last));--#define d_code(dist) \- ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])-/* Mapping from a distance to a distance code. dist is the distance - 1 and- * must not have side effects. _dist_code[256] and _dist_code[257] are never- * used.- */--#ifndef ZLIB_DEBUG-/* Inline versions of _tr_tally for speed: */--#if defined(GEN_TREES_H) || !defined(STDC)- extern uch ZLIB_INTERNAL _length_code[];- extern uch ZLIB_INTERNAL _dist_code[];-#else- extern const uch ZLIB_INTERNAL _length_code[];- extern const uch ZLIB_INTERNAL _dist_code[];-#endif--# define _tr_tally_lit(s, c, flush) \- { uch cc = (c); \- s->d_buf[s->last_lit] = 0; \- s->l_buf[s->last_lit++] = cc; \- s->dyn_ltree[cc].Freq++; \- flush = (s->last_lit == s->lit_bufsize-1); \- }-# define _tr_tally_dist(s, distance, length, flush) \- { uch len = (uch)(length); \- ush dist = (ush)(distance); \- s->d_buf[s->last_lit] = dist; \- s->l_buf[s->last_lit++] = len; \- dist--; \- s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \- s->dyn_dtree[d_code(dist)].Freq++; \- flush = (s->last_lit == s->lit_bufsize-1); \- }-#else-# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)-# define _tr_tally_dist(s, distance, length, flush) \- flush = _tr_tally(s, distance, length)-#endif--#endif /* DEFLATE_H */
− c/zlib/gzguts.h
@@ -1,218 +0,0 @@-/* gzguts.h -- zlib internal header definitions for gz* operations- * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--#ifdef _LARGEFILE64_SOURCE-# ifndef _LARGEFILE_SOURCE-# define _LARGEFILE_SOURCE 1-# endif-# ifdef _FILE_OFFSET_BITS-# undef _FILE_OFFSET_BITS-# endif-#endif--#ifdef HAVE_HIDDEN-# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))-#else-# define ZLIB_INTERNAL-#endif--#include <stdio.h>-#include "zlib.h"-#ifdef STDC-# include <string.h>-# include <stdlib.h>-# include <limits.h>-#endif--#ifndef _POSIX_SOURCE-# define _POSIX_SOURCE-#endif-#include <fcntl.h>--#ifdef _WIN32-# include <stddef.h>-#endif--#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)-# include <io.h>-#endif--#if defined(_WIN32) || defined(__CYGWIN__)-# define WIDECHAR-#endif--#ifdef WINAPI_FAMILY-# define open _open-# define read _read-# define write _write-# define close _close-#endif--#ifdef NO_DEFLATE /* for compatibility with old definition */-# define NO_GZCOMPRESS-#endif--#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)-# ifndef HAVE_VSNPRINTF-# define HAVE_VSNPRINTF-# endif-#endif--#if defined(__CYGWIN__)-# ifndef HAVE_VSNPRINTF-# define HAVE_VSNPRINTF-# endif-#endif--#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)-# ifndef HAVE_VSNPRINTF-# define HAVE_VSNPRINTF-# endif-#endif--#ifndef HAVE_VSNPRINTF-# ifdef MSDOS-/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),- but for now we just assume it doesn't. */-# define NO_vsnprintf-# endif-# ifdef __TURBOC__-# define NO_vsnprintf-# endif-# ifdef WIN32-/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */-# if !defined(vsnprintf) && !defined(NO_vsnprintf)-# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )-# define vsnprintf _vsnprintf-# endif-# endif-# endif-# ifdef __SASC-# define NO_vsnprintf-# endif-# ifdef VMS-# define NO_vsnprintf-# endif-# ifdef __OS400__-# define NO_vsnprintf-# endif-# ifdef __MVS__-# define NO_vsnprintf-# endif-#endif--/* unlike snprintf (which is required in C99), _snprintf does not guarantee- null termination of the result -- however this is only used in gzlib.c where- the result is assured to fit in the space provided */-#if defined(_MSC_VER) && _MSC_VER < 1900-# define snprintf _snprintf-#endif--#ifndef local-# define local static-#endif-/* since "static" is used to mean two completely different things in C, we- define "local" for the non-static meaning of "static", for readability- (compile with -Dlocal if your debugger can't find static symbols) */--/* gz* functions always use library allocation functions */-#ifndef STDC- extern voidp malloc OF((uInt size));- extern void free OF((voidpf ptr));-#endif--/* get errno and strerror definition */-#if defined UNDER_CE-# include <windows.h>-# define zstrerror() gz_strwinerror((DWORD)GetLastError())-#else-# ifndef NO_STRERROR-# include <errno.h>-# define zstrerror() strerror(errno)-# else-# define zstrerror() "stdio error (consult errno)"-# endif-#endif--/* provide prototypes for these when building zlib without LFS */-#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0- ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));- ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));- ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));- ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));-#endif--/* default memLevel */-#if MAX_MEM_LEVEL >= 8-# define DEF_MEM_LEVEL 8-#else-# define DEF_MEM_LEVEL MAX_MEM_LEVEL-#endif--/* default i/o buffer size -- double this for output when reading (this and- twice this must be able to fit in an unsigned type) */-#define GZBUFSIZE 8192--/* gzip modes, also provide a little integrity check on the passed structure */-#define GZ_NONE 0-#define GZ_READ 7247-#define GZ_WRITE 31153-#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */--/* values for gz_state how */-#define LOOK 0 /* look for a gzip header */-#define COPY 1 /* copy input directly */-#define GZIP 2 /* decompress a gzip stream */--/* internal gzip file state data structure */-typedef struct {- /* exposed contents for gzgetc() macro */- struct gzFile_s x; /* "x" for exposed */- /* x.have: number of bytes available at x.next */- /* x.next: next output data to deliver or write */- /* x.pos: current position in uncompressed data */- /* used for both reading and writing */- int mode; /* see gzip modes above */- int fd; /* file descriptor */- char *path; /* path or fd for error messages */- unsigned size; /* buffer size, zero if not allocated yet */- unsigned want; /* requested buffer size, default is GZBUFSIZE */- unsigned char *in; /* input buffer (double-sized when writing) */- unsigned char *out; /* output buffer (double-sized when reading) */- int direct; /* 0 if processing gzip, 1 if transparent */- /* just for reading */- int how; /* 0: get header, 1: copy, 2: decompress */- z_off64_t start; /* where the gzip data started, for rewinding */- int eof; /* true if end of input file reached */- int past; /* true if read requested past end */- /* just for writing */- int level; /* compression level */- int strategy; /* compression strategy */- /* seek request */- z_off64_t skip; /* amount to skip (already rewound if backwards) */- int seek; /* true if seek request pending */- /* error information */- int err; /* error code */- char *msg; /* error message */- /* zlib inflate or deflate stream */- z_stream strm; /* stream structure in-place (not a pointer) */-} gz_state;-typedef gz_state FAR *gz_statep;--/* shared functions */-void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));-#if defined UNDER_CE-char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));-#endif--/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t- value -- needed when comparing unsigned to z_off64_t, which is signed- (possible z_off64_t types off_t, off64_t, and long are all signed) */-#ifdef INT_MAX-# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)-#else-unsigned ZLIB_INTERNAL gz_intmax OF((void));-# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())-#endif
− c/zlib/infback.c
@@ -1,640 +0,0 @@-/* infback.c -- inflate using a call-back interface- * Copyright (C) 1995-2016 Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/*- This code is largely copied from inflate.c. Normally either infback.o or- inflate.o would be linked into an application--not both. The interface- with inffast.c is retained so that optimized assembler-coded versions of- inflate_fast() can be used with either inflate.c or infback.c.- */--#include "zutil.h"-#include "inftrees.h"-#include "inflate.h"-#include "inffast.h"--/* function prototypes */-local void fixedtables OF((struct inflate_state FAR *state));--/*- strm provides memory allocation functions in zalloc and zfree, or- Z_NULL to use the library memory allocation functions.-- windowBits is in the range 8..15, and window is a user-supplied- window and output buffer that is 2**windowBits bytes.- */-int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)-z_streamp strm;-int windowBits;-unsigned char FAR *window;-const char *version;-int stream_size;-{- struct inflate_state FAR *state;-- if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||- stream_size != (int)(sizeof(z_stream)))- return Z_VERSION_ERROR;- if (strm == Z_NULL || window == Z_NULL ||- windowBits < 8 || windowBits > 15)- return Z_STREAM_ERROR;- strm->msg = Z_NULL; /* in case we return an error */- if (strm->zalloc == (alloc_func)0) {-#ifdef Z_SOLO- return Z_STREAM_ERROR;-#else- strm->zalloc = zcalloc;- strm->opaque = (voidpf)0;-#endif- }- if (strm->zfree == (free_func)0)-#ifdef Z_SOLO- return Z_STREAM_ERROR;-#else- strm->zfree = zcfree;-#endif- state = (struct inflate_state FAR *)ZALLOC(strm, 1,- sizeof(struct inflate_state));- if (state == Z_NULL) return Z_MEM_ERROR;- Tracev((stderr, "inflate: allocated\n"));- strm->state = (struct internal_state FAR *)state;- state->dmax = 32768U;- state->wbits = (uInt)windowBits;- state->wsize = 1U << windowBits;- state->window = window;- state->wnext = 0;- state->whave = 0;- return Z_OK;-}--/*- Return state with length and distance decoding tables and index sizes set to- fixed code decoding. Normally this returns fixed tables from inffixed.h.- If BUILDFIXED is defined, then instead this routine builds the tables the- first time it's called, and returns those tables the first time and- thereafter. This reduces the size of the code by about 2K bytes, in- exchange for a little execution time. However, BUILDFIXED should not be- used for threaded applications, since the rewriting of the tables and virgin- may not be thread-safe.- */-local void fixedtables(state)-struct inflate_state FAR *state;-{-#ifdef BUILDFIXED- static int virgin = 1;- static code *lenfix, *distfix;- static code fixed[544];-- /* build fixed huffman tables if first call (may not be thread safe) */- if (virgin) {- unsigned sym, bits;- static code *next;-- /* literal/length table */- sym = 0;- while (sym < 144) state->lens[sym++] = 8;- while (sym < 256) state->lens[sym++] = 9;- while (sym < 280) state->lens[sym++] = 7;- while (sym < 288) state->lens[sym++] = 8;- next = fixed;- lenfix = next;- bits = 9;- inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);-- /* distance table */- sym = 0;- while (sym < 32) state->lens[sym++] = 5;- distfix = next;- bits = 5;- inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);-- /* do this just once */- virgin = 0;- }-#else /* !BUILDFIXED */-# include "inffixed.h"-#endif /* BUILDFIXED */- state->lencode = lenfix;- state->lenbits = 9;- state->distcode = distfix;- state->distbits = 5;-}--/* Macros for inflateBack(): */--/* Load returned state from inflate_fast() */-#define LOAD() \- do { \- put = strm->next_out; \- left = strm->avail_out; \- next = strm->next_in; \- have = strm->avail_in; \- hold = state->hold; \- bits = state->bits; \- } while (0)--/* Set state from registers for inflate_fast() */-#define RESTORE() \- do { \- strm->next_out = put; \- strm->avail_out = left; \- strm->next_in = next; \- strm->avail_in = have; \- state->hold = hold; \- state->bits = bits; \- } while (0)--/* Clear the input bit accumulator */-#define INITBITS() \- do { \- hold = 0; \- bits = 0; \- } while (0)--/* Assure that some input is available. If input is requested, but denied,- then return a Z_BUF_ERROR from inflateBack(). */-#define PULL() \- do { \- if (have == 0) { \- have = in(in_desc, &next); \- if (have == 0) { \- next = Z_NULL; \- ret = Z_BUF_ERROR; \- goto inf_leave; \- } \- } \- } while (0)--/* Get a byte of input into the bit accumulator, or return from inflateBack()- with an error if there is no input available. */-#define PULLBYTE() \- do { \- PULL(); \- have--; \- hold += (unsigned long)(*next++) << bits; \- bits += 8; \- } while (0)--/* Assure that there are at least n bits in the bit accumulator. If there is- not enough available input to do that, then return from inflateBack() with- an error. */-#define NEEDBITS(n) \- do { \- while (bits < (unsigned)(n)) \- PULLBYTE(); \- } while (0)--/* Return the low n bits of the bit accumulator (n < 16) */-#define BITS(n) \- ((unsigned)hold & ((1U << (n)) - 1))--/* Remove n bits from the bit accumulator */-#define DROPBITS(n) \- do { \- hold >>= (n); \- bits -= (unsigned)(n); \- } while (0)--/* Remove zero to seven bits as needed to go to a byte boundary */-#define BYTEBITS() \- do { \- hold >>= bits & 7; \- bits -= bits & 7; \- } while (0)--/* Assure that some output space is available, by writing out the window- if it's full. If the write fails, return from inflateBack() with a- Z_BUF_ERROR. */-#define ROOM() \- do { \- if (left == 0) { \- put = state->window; \- left = state->wsize; \- state->whave = left; \- if (out(out_desc, put, left)) { \- ret = Z_BUF_ERROR; \- goto inf_leave; \- } \- } \- } while (0)--/*- strm provides the memory allocation functions and window buffer on input,- and provides information on the unused input on return. For Z_DATA_ERROR- returns, strm will also provide an error message.-- in() and out() are the call-back input and output functions. When- inflateBack() needs more input, it calls in(). When inflateBack() has- filled the window with output, or when it completes with data in the- window, it calls out() to write out the data. The application must not- change the provided input until in() is called again or inflateBack()- returns. The application must not change the window/output buffer until- inflateBack() returns.-- in() and out() are called with a descriptor parameter provided in the- inflateBack() call. This parameter can be a structure that provides the- information required to do the read or write, as well as accumulated- information on the input and output such as totals and check values.-- in() should return zero on failure. out() should return non-zero on- failure. If either in() or out() fails, than inflateBack() returns a- Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it- was in() or out() that caused in the error. Otherwise, inflateBack()- returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format- error, or Z_MEM_ERROR if it could not allocate memory for the state.- inflateBack() can also return Z_STREAM_ERROR if the input parameters- are not correct, i.e. strm is Z_NULL or the state was not initialized.- */-int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)-z_streamp strm;-in_func in;-void FAR *in_desc;-out_func out;-void FAR *out_desc;-{- struct inflate_state FAR *state;- z_const unsigned char FAR *next; /* next input */- unsigned char FAR *put; /* next output */- unsigned have, left; /* available input and output */- unsigned long hold; /* bit buffer */- unsigned bits; /* bits in bit buffer */- unsigned copy; /* number of stored or match bytes to copy */- unsigned char FAR *from; /* where to copy match bytes from */- code here; /* current decoding table entry */- code last; /* parent table entry */- unsigned len; /* length to copy for repeats, bits to drop */- int ret; /* return code */- static const unsigned short order[19] = /* permutation of code lengths */- {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};-- /* Check that the strm exists and that the state was initialized */- if (strm == Z_NULL || strm->state == Z_NULL)- return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;-- /* Reset the state */- strm->msg = Z_NULL;- state->mode = TYPE;- state->last = 0;- state->whave = 0;- next = strm->next_in;- have = next != Z_NULL ? strm->avail_in : 0;- hold = 0;- bits = 0;- put = state->window;- left = state->wsize;-- /* Inflate until end of block marked as last */- for (;;)- switch (state->mode) {- case TYPE:- /* determine and dispatch block type */- if (state->last) {- BYTEBITS();- state->mode = DONE;- break;- }- NEEDBITS(3);- state->last = BITS(1);- DROPBITS(1);- switch (BITS(2)) {- case 0: /* stored block */- Tracev((stderr, "inflate: stored block%s\n",- state->last ? " (last)" : ""));- state->mode = STORED;- break;- case 1: /* fixed block */- fixedtables(state);- Tracev((stderr, "inflate: fixed codes block%s\n",- state->last ? " (last)" : ""));- state->mode = LEN; /* decode codes */- break;- case 2: /* dynamic block */- Tracev((stderr, "inflate: dynamic codes block%s\n",- state->last ? " (last)" : ""));- state->mode = TABLE;- break;- case 3:- strm->msg = (char *)"invalid block type";- state->mode = BAD;- }- DROPBITS(2);- break;-- case STORED:- /* get and verify stored block length */- BYTEBITS(); /* go to byte boundary */- NEEDBITS(32);- if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {- strm->msg = (char *)"invalid stored block lengths";- state->mode = BAD;- break;- }- state->length = (unsigned)hold & 0xffff;- Tracev((stderr, "inflate: stored length %u\n",- state->length));- INITBITS();-- /* copy stored block from input to output */- while (state->length != 0) {- copy = state->length;- PULL();- ROOM();- if (copy > have) copy = have;- if (copy > left) copy = left;- zmemcpy(put, next, copy);- have -= copy;- next += copy;- left -= copy;- put += copy;- state->length -= copy;- }- Tracev((stderr, "inflate: stored end\n"));- state->mode = TYPE;- break;-- case TABLE:- /* get dynamic table entries descriptor */- NEEDBITS(14);- state->nlen = BITS(5) + 257;- DROPBITS(5);- state->ndist = BITS(5) + 1;- DROPBITS(5);- state->ncode = BITS(4) + 4;- DROPBITS(4);-#ifndef PKZIP_BUG_WORKAROUND- if (state->nlen > 286 || state->ndist > 30) {- strm->msg = (char *)"too many length or distance symbols";- state->mode = BAD;- break;- }-#endif- Tracev((stderr, "inflate: table sizes ok\n"));-- /* get code length code lengths (not a typo) */- state->have = 0;- while (state->have < state->ncode) {- NEEDBITS(3);- state->lens[order[state->have++]] = (unsigned short)BITS(3);- DROPBITS(3);- }- while (state->have < 19)- state->lens[order[state->have++]] = 0;- state->next = state->codes;- state->lencode = (code const FAR *)(state->next);- state->lenbits = 7;- ret = inflate_table(CODES, state->lens, 19, &(state->next),- &(state->lenbits), state->work);- if (ret) {- strm->msg = (char *)"invalid code lengths set";- state->mode = BAD;- break;- }- Tracev((stderr, "inflate: code lengths ok\n"));-- /* get length and distance code code lengths */- state->have = 0;- while (state->have < state->nlen + state->ndist) {- for (;;) {- here = state->lencode[BITS(state->lenbits)];- if ((unsigned)(here.bits) <= bits) break;- PULLBYTE();- }- if (here.val < 16) {- DROPBITS(here.bits);- state->lens[state->have++] = here.val;- }- else {- if (here.val == 16) {- NEEDBITS(here.bits + 2);- DROPBITS(here.bits);- if (state->have == 0) {- strm->msg = (char *)"invalid bit length repeat";- state->mode = BAD;- break;- }- len = (unsigned)(state->lens[state->have - 1]);- copy = 3 + BITS(2);- DROPBITS(2);- }- else if (here.val == 17) {- NEEDBITS(here.bits + 3);- DROPBITS(here.bits);- len = 0;- copy = 3 + BITS(3);- DROPBITS(3);- }- else {- NEEDBITS(here.bits + 7);- DROPBITS(here.bits);- len = 0;- copy = 11 + BITS(7);- DROPBITS(7);- }- if (state->have + copy > state->nlen + state->ndist) {- strm->msg = (char *)"invalid bit length repeat";- state->mode = BAD;- break;- }- while (copy--)- state->lens[state->have++] = (unsigned short)len;- }- }-- /* handle error breaks in while */- if (state->mode == BAD) break;-- /* check for end-of-block code (better have one) */- if (state->lens[256] == 0) {- strm->msg = (char *)"invalid code -- missing end-of-block";- state->mode = BAD;- break;- }-- /* build code tables -- note: do not change the lenbits or distbits- values here (9 and 6) without reading the comments in inftrees.h- concerning the ENOUGH constants, which depend on those values */- state->next = state->codes;- state->lencode = (code const FAR *)(state->next);- state->lenbits = 9;- ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),- &(state->lenbits), state->work);- if (ret) {- strm->msg = (char *)"invalid literal/lengths set";- state->mode = BAD;- break;- }- state->distcode = (code const FAR *)(state->next);- state->distbits = 6;- ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,- &(state->next), &(state->distbits), state->work);- if (ret) {- strm->msg = (char *)"invalid distances set";- state->mode = BAD;- break;- }- Tracev((stderr, "inflate: codes ok\n"));- state->mode = LEN;-- case LEN:- /* use inflate_fast() if we have enough input and output */- if (have >= 6 && left >= 258) {- RESTORE();- if (state->whave < state->wsize)- state->whave = state->wsize - left;- inflate_fast(strm, state->wsize);- LOAD();- break;- }-- /* get a literal, length, or end-of-block code */- for (;;) {- here = state->lencode[BITS(state->lenbits)];- if ((unsigned)(here.bits) <= bits) break;- PULLBYTE();- }- if (here.op && (here.op & 0xf0) == 0) {- last = here;- for (;;) {- here = state->lencode[last.val +- (BITS(last.bits + last.op) >> last.bits)];- if ((unsigned)(last.bits + here.bits) <= bits) break;- PULLBYTE();- }- DROPBITS(last.bits);- }- DROPBITS(here.bits);- state->length = (unsigned)here.val;-- /* process literal */- if (here.op == 0) {- Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?- "inflate: literal '%c'\n" :- "inflate: literal 0x%02x\n", here.val));- ROOM();- *put++ = (unsigned char)(state->length);- left--;- state->mode = LEN;- break;- }-- /* process end of block */- if (here.op & 32) {- Tracevv((stderr, "inflate: end of block\n"));- state->mode = TYPE;- break;- }-- /* invalid code */- if (here.op & 64) {- strm->msg = (char *)"invalid literal/length code";- state->mode = BAD;- break;- }-- /* length code -- get extra bits, if any */- state->extra = (unsigned)(here.op) & 15;- if (state->extra != 0) {- NEEDBITS(state->extra);- state->length += BITS(state->extra);- DROPBITS(state->extra);- }- Tracevv((stderr, "inflate: length %u\n", state->length));-- /* get distance code */- for (;;) {- here = state->distcode[BITS(state->distbits)];- if ((unsigned)(here.bits) <= bits) break;- PULLBYTE();- }- if ((here.op & 0xf0) == 0) {- last = here;- for (;;) {- here = state->distcode[last.val +- (BITS(last.bits + last.op) >> last.bits)];- if ((unsigned)(last.bits + here.bits) <= bits) break;- PULLBYTE();- }- DROPBITS(last.bits);- }- DROPBITS(here.bits);- if (here.op & 64) {- strm->msg = (char *)"invalid distance code";- state->mode = BAD;- break;- }- state->offset = (unsigned)here.val;-- /* get distance extra bits, if any */- state->extra = (unsigned)(here.op) & 15;- if (state->extra != 0) {- NEEDBITS(state->extra);- state->offset += BITS(state->extra);- DROPBITS(state->extra);- }- if (state->offset > state->wsize - (state->whave < state->wsize ?- left : 0)) {- strm->msg = (char *)"invalid distance too far back";- state->mode = BAD;- break;- }- Tracevv((stderr, "inflate: distance %u\n", state->offset));-- /* copy match from window to output */- do {- ROOM();- copy = state->wsize - state->offset;- if (copy < left) {- from = put + copy;- copy = left - copy;- }- else {- from = put - state->offset;- copy = left;- }- if (copy > state->length) copy = state->length;- state->length -= copy;- left -= copy;- do {- *put++ = *from++;- } while (--copy);- } while (state->length != 0);- break;-- case DONE:- /* inflate stream terminated properly -- write leftover output */- ret = Z_STREAM_END;- if (left < state->wsize) {- if (out(out_desc, state->window, state->wsize - left))- ret = Z_BUF_ERROR;- }- goto inf_leave;-- case BAD:- ret = Z_DATA_ERROR;- goto inf_leave;-- default: /* can't happen, but makes compilers happy */- ret = Z_STREAM_ERROR;- goto inf_leave;- }-- /* Return unused input */- inf_leave:- strm->next_in = next;- strm->avail_in = have;- return ret;-}--int ZEXPORT inflateBackEnd(strm)-z_streamp strm;-{- if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)- return Z_STREAM_ERROR;- ZFREE(strm, strm->state);- strm->state = Z_NULL;- Tracev((stderr, "inflate: end\n"));- return Z_OK;-}
− c/zlib/inffast.c
@@ -1,323 +0,0 @@-/* inffast.c -- fast decoding- * Copyright (C) 1995-2017 Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--#include "zutil.h"-#include "inftrees.h"-#include "inflate.h"-#include "inffast.h"--#ifdef ASMINF-# pragma message("Assembler code may have bugs -- use at your own risk")-#else--/*- Decode literal, length, and distance codes and write out the resulting- literal and match bytes until either not enough input or output is- available, an end-of-block is encountered, or a data error is encountered.- When large enough input and output buffers are supplied to inflate(), for- example, a 16K input buffer and a 64K output buffer, more than 95% of the- inflate execution time is spent in this routine.-- Entry assumptions:-- state->mode == LEN- strm->avail_in >= 6- strm->avail_out >= 258- start >= strm->avail_out- state->bits < 8-- On return, state->mode is one of:-- LEN -- ran out of enough output space or enough available input- TYPE -- reached end of block code, inflate() to interpret next block- BAD -- error in block data-- Notes:-- - The maximum input bits used by a length/distance pair is 15 bits for the- length code, 5 bits for the length extra, 15 bits for the distance code,- and 13 bits for the distance extra. This totals 48 bits, or six bytes.- Therefore if strm->avail_in >= 6, then there is enough input to avoid- checking for available input while decoding.-- - The maximum bytes that a single length/distance pair can output is 258- bytes, which is the maximum length that can be coded. inflate_fast()- requires strm->avail_out >= 258 for each loop to avoid checking for- output space.- */-void ZLIB_INTERNAL inflate_fast(strm, start)-z_streamp strm;-unsigned start; /* inflate()'s starting value for strm->avail_out */-{- struct inflate_state FAR *state;- z_const unsigned char FAR *in; /* local strm->next_in */- z_const unsigned char FAR *last; /* have enough input while in < last */- unsigned char FAR *out; /* local strm->next_out */- unsigned char FAR *beg; /* inflate()'s initial strm->next_out */- unsigned char FAR *end; /* while out < end, enough space available */-#ifdef INFLATE_STRICT- unsigned dmax; /* maximum distance from zlib header */-#endif- unsigned wsize; /* window size or zero if not using window */- unsigned whave; /* valid bytes in the window */- unsigned wnext; /* window write index */- unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */- unsigned long hold; /* local strm->hold */- unsigned bits; /* local strm->bits */- code const FAR *lcode; /* local strm->lencode */- code const FAR *dcode; /* local strm->distcode */- unsigned lmask; /* mask for first level of length codes */- unsigned dmask; /* mask for first level of distance codes */- code here; /* retrieved table entry */- unsigned op; /* code bits, operation, extra bits, or */- /* window position, window bytes to copy */- unsigned len; /* match length, unused bytes */- unsigned dist; /* match distance */- unsigned char FAR *from; /* where to copy match from */-- /* copy state to local variables */- state = (struct inflate_state FAR *)strm->state;- in = strm->next_in;- last = in + (strm->avail_in - 5);- out = strm->next_out;- beg = out - (start - strm->avail_out);- end = out + (strm->avail_out - 257);-#ifdef INFLATE_STRICT- dmax = state->dmax;-#endif- wsize = state->wsize;- whave = state->whave;- wnext = state->wnext;- window = state->window;- hold = state->hold;- bits = state->bits;- lcode = state->lencode;- dcode = state->distcode;- lmask = (1U << state->lenbits) - 1;- dmask = (1U << state->distbits) - 1;-- /* decode literals and length/distances until end-of-block or not enough- input data or output space */- do {- if (bits < 15) {- hold += (unsigned long)(*in++) << bits;- bits += 8;- hold += (unsigned long)(*in++) << bits;- bits += 8;- }- here = lcode[hold & lmask];- dolen:- op = (unsigned)(here.bits);- hold >>= op;- bits -= op;- op = (unsigned)(here.op);- if (op == 0) { /* literal */- Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?- "inflate: literal '%c'\n" :- "inflate: literal 0x%02x\n", here.val));- *out++ = (unsigned char)(here.val);- }- else if (op & 16) { /* length base */- len = (unsigned)(here.val);- op &= 15; /* number of extra bits */- if (op) {- if (bits < op) {- hold += (unsigned long)(*in++) << bits;- bits += 8;- }- len += (unsigned)hold & ((1U << op) - 1);- hold >>= op;- bits -= op;- }- Tracevv((stderr, "inflate: length %u\n", len));- if (bits < 15) {- hold += (unsigned long)(*in++) << bits;- bits += 8;- hold += (unsigned long)(*in++) << bits;- bits += 8;- }- here = dcode[hold & dmask];- dodist:- op = (unsigned)(here.bits);- hold >>= op;- bits -= op;- op = (unsigned)(here.op);- if (op & 16) { /* distance base */- dist = (unsigned)(here.val);- op &= 15; /* number of extra bits */- if (bits < op) {- hold += (unsigned long)(*in++) << bits;- bits += 8;- if (bits < op) {- hold += (unsigned long)(*in++) << bits;- bits += 8;- }- }- dist += (unsigned)hold & ((1U << op) - 1);-#ifdef INFLATE_STRICT- if (dist > dmax) {- strm->msg = (char *)"invalid distance too far back";- state->mode = BAD;- break;- }-#endif- hold >>= op;- bits -= op;- Tracevv((stderr, "inflate: distance %u\n", dist));- op = (unsigned)(out - beg); /* max distance in output */- if (dist > op) { /* see if copy from window */- op = dist - op; /* distance back in window */- if (op > whave) {- if (state->sane) {- strm->msg =- (char *)"invalid distance too far back";- state->mode = BAD;- break;- }-#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR- if (len <= op - whave) {- do {- *out++ = 0;- } while (--len);- continue;- }- len -= op - whave;- do {- *out++ = 0;- } while (--op > whave);- if (op == 0) {- from = out - dist;- do {- *out++ = *from++;- } while (--len);- continue;- }-#endif- }- from = window;- if (wnext == 0) { /* very common case */- from += wsize - op;- if (op < len) { /* some from window */- len -= op;- do {- *out++ = *from++;- } while (--op);- from = out - dist; /* rest from output */- }- }- else if (wnext < op) { /* wrap around window */- from += wsize + wnext - op;- op -= wnext;- if (op < len) { /* some from end of window */- len -= op;- do {- *out++ = *from++;- } while (--op);- from = window;- if (wnext < len) { /* some from start of window */- op = wnext;- len -= op;- do {- *out++ = *from++;- } while (--op);- from = out - dist; /* rest from output */- }- }- }- else { /* contiguous in window */- from += wnext - op;- if (op < len) { /* some from window */- len -= op;- do {- *out++ = *from++;- } while (--op);- from = out - dist; /* rest from output */- }- }- while (len > 2) {- *out++ = *from++;- *out++ = *from++;- *out++ = *from++;- len -= 3;- }- if (len) {- *out++ = *from++;- if (len > 1)- *out++ = *from++;- }- }- else {- from = out - dist; /* copy direct from output */- do { /* minimum length is three */- *out++ = *from++;- *out++ = *from++;- *out++ = *from++;- len -= 3;- } while (len > 2);- if (len) {- *out++ = *from++;- if (len > 1)- *out++ = *from++;- }- }- }- else if ((op & 64) == 0) { /* 2nd level distance code */- here = dcode[here.val + (hold & ((1U << op) - 1))];- goto dodist;- }- else {- strm->msg = (char *)"invalid distance code";- state->mode = BAD;- break;- }- }- else if ((op & 64) == 0) { /* 2nd level length code */- here = lcode[here.val + (hold & ((1U << op) - 1))];- goto dolen;- }- else if (op & 32) { /* end-of-block */- Tracevv((stderr, "inflate: end of block\n"));- state->mode = TYPE;- break;- }- else {- strm->msg = (char *)"invalid literal/length code";- state->mode = BAD;- break;- }- } while (in < last && out < end);-- /* return unused bytes (on entry, bits < 8, so in won't go too far back) */- len = bits >> 3;- in -= len;- bits -= len << 3;- hold &= (1U << bits) - 1;-- /* update state and return */- strm->next_in = in;- strm->next_out = out;- strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));- strm->avail_out = (unsigned)(out < end ?- 257 + (end - out) : 257 - (out - end));- state->hold = hold;- state->bits = bits;- return;-}--/*- inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):- - Using bit fields for code structure- - Different op definition to avoid & for extra bits (do & for table bits)- - Three separate decoding do-loops for direct, window, and wnext == 0- - Special case for distance > 1 copies to do overlapped load and store copy- - Explicit branch predictions (based on measured branch probabilities)- - Deferring match copy and interspersed it with decoding subsequent codes- - Swapping literal/length else- - Swapping window/direct else- - Larger unrolled copy loops (three is about right)- - Moving len -= 3 statement into middle of loop- */--#endif /* !ASMINF */
− c/zlib/inffast.h
@@ -1,11 +0,0 @@-/* inffast.h -- header to use inffast.c- * Copyright (C) 1995-2003, 2010 Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/* WARNING: this file should *not* be used by applications. It is- part of the implementation of the compression library and is- subject to change. Applications should only use zlib.h.- */--void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
− c/zlib/inffixed.h
@@ -1,94 +0,0 @@- /* inffixed.h -- table for decoding fixed codes- * Generated automatically by makefixed().- */-- /* WARNING: this file should *not* be used by applications.- It is part of the implementation of this library and is- subject to change. Applications should only use zlib.h.- */-- static const code lenfix[512] = {- {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},- {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},- {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},- {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},- {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},- {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},- {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},- {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},- {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},- {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},- {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},- {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},- {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},- {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},- {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},- {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},- {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},- {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},- {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},- {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},- {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},- {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},- {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},- {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},- {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},- {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},- {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},- {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},- {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},- {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},- {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},- {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},- {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},- {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},- {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},- {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},- {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},- {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},- {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},- {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},- {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},- {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},- {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},- {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},- {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},- {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},- {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},- {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},- {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},- {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},- {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},- {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},- {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},- {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},- {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},- {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},- {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},- {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},- {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},- {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},- {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},- {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},- {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},- {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},- {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},- {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},- {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},- {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},- {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},- {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},- {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},- {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},- {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},- {0,9,255}- };-- static const code distfix[32] = {- {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},- {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},- {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},- {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},- {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},- {22,5,193},{64,5,0}- };
− c/zlib/inflate.c
@@ -1,1561 +0,0 @@-/* inflate.c -- zlib decompression- * Copyright (C) 1995-2016 Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/*- * Change history:- *- * 1.2.beta0 24 Nov 2002- * - First version -- complete rewrite of inflate to simplify code, avoid- * creation of window when not needed, minimize use of window when it is- * needed, make inffast.c even faster, implement gzip decoding, and to- * improve code readability and style over the previous zlib inflate code- *- * 1.2.beta1 25 Nov 2002- * - Use pointers for available input and output checking in inffast.c- * - Remove input and output counters in inffast.c- * - Change inffast.c entry and loop from avail_in >= 7 to >= 6- * - Remove unnecessary second byte pull from length extra in inffast.c- * - Unroll direct copy to three copies per loop in inffast.c- *- * 1.2.beta2 4 Dec 2002- * - Change external routine names to reduce potential conflicts- * - Correct filename to inffixed.h for fixed tables in inflate.c- * - Make hbuf[] unsigned char to match parameter type in inflate.c- * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)- * to avoid negation problem on Alphas (64 bit) in inflate.c- *- * 1.2.beta3 22 Dec 2002- * - Add comments on state->bits assertion in inffast.c- * - Add comments on op field in inftrees.h- * - Fix bug in reuse of allocated window after inflateReset()- * - Remove bit fields--back to byte structure for speed- * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths- * - Change post-increments to pre-increments in inflate_fast(), PPC biased?- * - Add compile time option, POSTINC, to use post-increments instead (Intel?)- * - Make MATCH copy in inflate() much faster for when inflate_fast() not used- * - Use local copies of stream next and avail values, as well as local bit- * buffer and bit count in inflate()--for speed when inflate_fast() not used- *- * 1.2.beta4 1 Jan 2003- * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings- * - Move a comment on output buffer sizes from inffast.c to inflate.c- * - Add comments in inffast.c to introduce the inflate_fast() routine- * - Rearrange window copies in inflate_fast() for speed and simplification- * - Unroll last copy for window match in inflate_fast()- * - Use local copies of window variables in inflate_fast() for speed- * - Pull out common wnext == 0 case for speed in inflate_fast()- * - Make op and len in inflate_fast() unsigned for consistency- * - Add FAR to lcode and dcode declarations in inflate_fast()- * - Simplified bad distance check in inflate_fast()- * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new- * source file infback.c to provide a call-back interface to inflate for- * programs like gzip and unzip -- uses window as output buffer to avoid- * window copying- *- * 1.2.beta5 1 Jan 2003- * - Improved inflateBack() interface to allow the caller to provide initial- * input in strm.- * - Fixed stored blocks bug in inflateBack()- *- * 1.2.beta6 4 Jan 2003- * - Added comments in inffast.c on effectiveness of POSTINC- * - Typecasting all around to reduce compiler warnings- * - Changed loops from while (1) or do {} while (1) to for (;;), again to- * make compilers happy- * - Changed type of window in inflateBackInit() to unsigned char *- *- * 1.2.beta7 27 Jan 2003- * - Changed many types to unsigned or unsigned short to avoid warnings- * - Added inflateCopy() function- *- * 1.2.0 9 Mar 2003- * - Changed inflateBack() interface to provide separate opaque descriptors- * for the in() and out() functions- * - Changed inflateBack() argument and in_func typedef to swap the length- * and buffer address return values for the input function- * - Check next_in and next_out for Z_NULL on entry to inflate()- *- * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.- */--#include "zutil.h"-#include "inftrees.h"-#include "inflate.h"-#include "inffast.h"--#ifdef MAKEFIXED-# ifndef BUILDFIXED-# define BUILDFIXED-# endif-#endif--/* function prototypes */-local int inflateStateCheck OF((z_streamp strm));-local void fixedtables OF((struct inflate_state FAR *state));-local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,- unsigned copy));-#ifdef BUILDFIXED- void makefixed OF((void));-#endif-local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,- unsigned len));--local int inflateStateCheck(strm)-z_streamp strm;-{- struct inflate_state FAR *state;- if (strm == Z_NULL ||- strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)- return 1;- state = (struct inflate_state FAR *)strm->state;- if (state == Z_NULL || state->strm != strm ||- state->mode < HEAD || state->mode > SYNC)- return 1;- return 0;-}--int ZEXPORT inflateResetKeep(strm)-z_streamp strm;-{- struct inflate_state FAR *state;-- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;- strm->total_in = strm->total_out = state->total = 0;- strm->msg = Z_NULL;- if (state->wrap) /* to support ill-conceived Java test suite */- strm->adler = state->wrap & 1;- state->mode = HEAD;- state->last = 0;- state->havedict = 0;- state->dmax = 32768U;- state->head = Z_NULL;- state->hold = 0;- state->bits = 0;- state->lencode = state->distcode = state->next = state->codes;- state->sane = 1;- state->back = -1;- Tracev((stderr, "inflate: reset\n"));- return Z_OK;-}--int ZEXPORT inflateReset(strm)-z_streamp strm;-{- struct inflate_state FAR *state;-- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;- state->wsize = 0;- state->whave = 0;- state->wnext = 0;- return inflateResetKeep(strm);-}--int ZEXPORT inflateReset2(strm, windowBits)-z_streamp strm;-int windowBits;-{- int wrap;- struct inflate_state FAR *state;-- /* get the state */- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;-- /* extract wrap request from windowBits parameter */- if (windowBits < 0) {- wrap = 0;- windowBits = -windowBits;- }- else {- wrap = (windowBits >> 4) + 5;-#ifdef GUNZIP- if (windowBits < 48)- windowBits &= 15;-#endif- }-- /* set number of window bits, free window if different */- if (windowBits && (windowBits < 8 || windowBits > 15))- return Z_STREAM_ERROR;- if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {- ZFREE(strm, state->window);- state->window = Z_NULL;- }-- /* update state and reset the rest of it */- state->wrap = wrap;- state->wbits = (unsigned)windowBits;- return inflateReset(strm);-}--int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)-z_streamp strm;-int windowBits;-const char *version;-int stream_size;-{- int ret;- struct inflate_state FAR *state;-- if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||- stream_size != (int)(sizeof(z_stream)))- return Z_VERSION_ERROR;- if (strm == Z_NULL) return Z_STREAM_ERROR;- strm->msg = Z_NULL; /* in case we return an error */- if (strm->zalloc == (alloc_func)0) {-#ifdef Z_SOLO- return Z_STREAM_ERROR;-#else- strm->zalloc = zcalloc;- strm->opaque = (voidpf)0;-#endif- }- if (strm->zfree == (free_func)0)-#ifdef Z_SOLO- return Z_STREAM_ERROR;-#else- strm->zfree = zcfree;-#endif- state = (struct inflate_state FAR *)- ZALLOC(strm, 1, sizeof(struct inflate_state));- if (state == Z_NULL) return Z_MEM_ERROR;- Tracev((stderr, "inflate: allocated\n"));- strm->state = (struct internal_state FAR *)state;- state->strm = strm;- state->window = Z_NULL;- state->mode = HEAD; /* to pass state test in inflateReset2() */- ret = inflateReset2(strm, windowBits);- if (ret != Z_OK) {- ZFREE(strm, state);- strm->state = Z_NULL;- }- return ret;-}--int ZEXPORT inflateInit_(strm, version, stream_size)-z_streamp strm;-const char *version;-int stream_size;-{- return inflateInit2_(strm, DEF_WBITS, version, stream_size);-}--int ZEXPORT inflatePrime(strm, bits, value)-z_streamp strm;-int bits;-int value;-{- struct inflate_state FAR *state;-- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;- if (bits < 0) {- state->hold = 0;- state->bits = 0;- return Z_OK;- }- if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;- value &= (1L << bits) - 1;- state->hold += (unsigned)value << state->bits;- state->bits += (uInt)bits;- return Z_OK;-}--/*- Return state with length and distance decoding tables and index sizes set to- fixed code decoding. Normally this returns fixed tables from inffixed.h.- If BUILDFIXED is defined, then instead this routine builds the tables the- first time it's called, and returns those tables the first time and- thereafter. This reduces the size of the code by about 2K bytes, in- exchange for a little execution time. However, BUILDFIXED should not be- used for threaded applications, since the rewriting of the tables and virgin- may not be thread-safe.- */-local void fixedtables(state)-struct inflate_state FAR *state;-{-#ifdef BUILDFIXED- static int virgin = 1;- static code *lenfix, *distfix;- static code fixed[544];-- /* build fixed huffman tables if first call (may not be thread safe) */- if (virgin) {- unsigned sym, bits;- static code *next;-- /* literal/length table */- sym = 0;- while (sym < 144) state->lens[sym++] = 8;- while (sym < 256) state->lens[sym++] = 9;- while (sym < 280) state->lens[sym++] = 7;- while (sym < 288) state->lens[sym++] = 8;- next = fixed;- lenfix = next;- bits = 9;- inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);-- /* distance table */- sym = 0;- while (sym < 32) state->lens[sym++] = 5;- distfix = next;- bits = 5;- inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);-- /* do this just once */- virgin = 0;- }-#else /* !BUILDFIXED */-# include "inffixed.h"-#endif /* BUILDFIXED */- state->lencode = lenfix;- state->lenbits = 9;- state->distcode = distfix;- state->distbits = 5;-}--#ifdef MAKEFIXED-#include <stdio.h>--/*- Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also- defines BUILDFIXED, so the tables are built on the fly. makefixed() writes- those tables to stdout, which would be piped to inffixed.h. A small program- can simply call makefixed to do this:-- void makefixed(void);-- int main(void)- {- makefixed();- return 0;- }-- Then that can be linked with zlib built with MAKEFIXED defined and run:-- a.out > inffixed.h- */-void makefixed()-{- unsigned low, size;- struct inflate_state state;-- fixedtables(&state);- puts(" /* inffixed.h -- table for decoding fixed codes");- puts(" * Generated automatically by makefixed().");- puts(" */");- puts("");- puts(" /* WARNING: this file should *not* be used by applications.");- puts(" It is part of the implementation of this library and is");- puts(" subject to change. Applications should only use zlib.h.");- puts(" */");- puts("");- size = 1U << 9;- printf(" static const code lenfix[%u] = {", size);- low = 0;- for (;;) {- if ((low % 7) == 0) printf("\n ");- printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,- state.lencode[low].bits, state.lencode[low].val);- if (++low == size) break;- putchar(',');- }- puts("\n };");- size = 1U << 5;- printf("\n static const code distfix[%u] = {", size);- low = 0;- for (;;) {- if ((low % 6) == 0) printf("\n ");- printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,- state.distcode[low].val);- if (++low == size) break;- putchar(',');- }- puts("\n };");-}-#endif /* MAKEFIXED */--/*- Update the window with the last wsize (normally 32K) bytes written before- returning. If window does not exist yet, create it. This is only called- when a window is already in use, or when output has been written during this- inflate call, but the end of the deflate stream has not been reached yet.- It is also called to create a window for dictionary data when a dictionary- is loaded.-- Providing output buffers larger than 32K to inflate() should provide a speed- advantage, since only the last 32K of output is copied to the sliding window- upon return from inflate(), and since all distances after the first 32K of- output will fall in the output data, making match copies simpler and faster.- The advantage may be dependent on the size of the processor's data caches.- */-local int updatewindow(strm, end, copy)-z_streamp strm;-const Bytef *end;-unsigned copy;-{- struct inflate_state FAR *state;- unsigned dist;-- state = (struct inflate_state FAR *)strm->state;-- /* if it hasn't been done already, allocate space for the window */- if (state->window == Z_NULL) {- state->window = (unsigned char FAR *)- ZALLOC(strm, 1U << state->wbits,- sizeof(unsigned char));- if (state->window == Z_NULL) return 1;- }-- /* if window not in use yet, initialize */- if (state->wsize == 0) {- state->wsize = 1U << state->wbits;- state->wnext = 0;- state->whave = 0;- }-- /* copy state->wsize or less output bytes into the circular window */- if (copy >= state->wsize) {- zmemcpy(state->window, end - state->wsize, state->wsize);- state->wnext = 0;- state->whave = state->wsize;- }- else {- dist = state->wsize - state->wnext;- if (dist > copy) dist = copy;- zmemcpy(state->window + state->wnext, end - copy, dist);- copy -= dist;- if (copy) {- zmemcpy(state->window, end - copy, copy);- state->wnext = copy;- state->whave = state->wsize;- }- else {- state->wnext += dist;- if (state->wnext == state->wsize) state->wnext = 0;- if (state->whave < state->wsize) state->whave += dist;- }- }- return 0;-}--/* Macros for inflate(): */--/* check function to use adler32() for zlib or crc32() for gzip */-#ifdef GUNZIP-# define UPDATE(check, buf, len) \- (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))-#else-# define UPDATE(check, buf, len) adler32(check, buf, len)-#endif--/* check macros for header crc */-#ifdef GUNZIP-# define CRC2(check, word) \- do { \- hbuf[0] = (unsigned char)(word); \- hbuf[1] = (unsigned char)((word) >> 8); \- check = crc32(check, hbuf, 2); \- } while (0)--# define CRC4(check, word) \- do { \- hbuf[0] = (unsigned char)(word); \- hbuf[1] = (unsigned char)((word) >> 8); \- hbuf[2] = (unsigned char)((word) >> 16); \- hbuf[3] = (unsigned char)((word) >> 24); \- check = crc32(check, hbuf, 4); \- } while (0)-#endif--/* Load registers with state in inflate() for speed */-#define LOAD() \- do { \- put = strm->next_out; \- left = strm->avail_out; \- next = strm->next_in; \- have = strm->avail_in; \- hold = state->hold; \- bits = state->bits; \- } while (0)--/* Restore state from registers in inflate() */-#define RESTORE() \- do { \- strm->next_out = put; \- strm->avail_out = left; \- strm->next_in = next; \- strm->avail_in = have; \- state->hold = hold; \- state->bits = bits; \- } while (0)--/* Clear the input bit accumulator */-#define INITBITS() \- do { \- hold = 0; \- bits = 0; \- } while (0)--/* Get a byte of input into the bit accumulator, or return from inflate()- if there is no input available. */-#define PULLBYTE() \- do { \- if (have == 0) goto inf_leave; \- have--; \- hold += (unsigned long)(*next++) << bits; \- bits += 8; \- } while (0)--/* Assure that there are at least n bits in the bit accumulator. If there is- not enough available input to do that, then return from inflate(). */-#define NEEDBITS(n) \- do { \- while (bits < (unsigned)(n)) \- PULLBYTE(); \- } while (0)--/* Return the low n bits of the bit accumulator (n < 16) */-#define BITS(n) \- ((unsigned)hold & ((1U << (n)) - 1))--/* Remove n bits from the bit accumulator */-#define DROPBITS(n) \- do { \- hold >>= (n); \- bits -= (unsigned)(n); \- } while (0)--/* Remove zero to seven bits as needed to go to a byte boundary */-#define BYTEBITS() \- do { \- hold >>= bits & 7; \- bits -= bits & 7; \- } while (0)--/*- inflate() uses a state machine to process as much input data and generate as- much output data as possible before returning. The state machine is- structured roughly as follows:-- for (;;) switch (state) {- ...- case STATEn:- if (not enough input data or output space to make progress)- return;- ... make progress ...- state = STATEm;- break;- ...- }-- so when inflate() is called again, the same case is attempted again, and- if the appropriate resources are provided, the machine proceeds to the- next state. The NEEDBITS() macro is usually the way the state evaluates- whether it can proceed or should return. NEEDBITS() does the return if- the requested bits are not available. The typical use of the BITS macros- is:-- NEEDBITS(n);- ... do something with BITS(n) ...- DROPBITS(n);-- where NEEDBITS(n) either returns from inflate() if there isn't enough- input left to load n bits into the accumulator, or it continues. BITS(n)- gives the low n bits in the accumulator. When done, DROPBITS(n) drops- the low n bits off the accumulator. INITBITS() clears the accumulator- and sets the number of available bits to zero. BYTEBITS() discards just- enough bits to put the accumulator on a byte boundary. After BYTEBITS()- and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.-- NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return- if there is no input available. The decoding of variable length codes uses- PULLBYTE() directly in order to pull just enough bytes to decode the next- code, and no more.-- Some states loop until they get enough input, making sure that enough- state information is maintained to continue the loop where it left off- if NEEDBITS() returns in the loop. For example, want, need, and keep- would all have to actually be part of the saved state in case NEEDBITS()- returns:-- case STATEw:- while (want < need) {- NEEDBITS(n);- keep[want++] = BITS(n);- DROPBITS(n);- }- state = STATEx;- case STATEx:-- As shown above, if the next state is also the next case, then the break- is omitted.-- A state may also return if there is not enough output space available to- complete that state. Those states are copying stored data, writing a- literal byte, and copying a matching string.-- When returning, a "goto inf_leave" is used to update the total counters,- update the check value, and determine whether any progress has been made- during that inflate() call in order to return the proper return code.- Progress is defined as a change in either strm->avail_in or strm->avail_out.- When there is a window, goto inf_leave will update the window with the last- output written. If a goto inf_leave occurs in the middle of decompression- and there is no window currently, goto inf_leave will create one and copy- output to the window for the next call of inflate().-- In this implementation, the flush parameter of inflate() only affects the- return code (per zlib.h). inflate() always writes as much as possible to- strm->next_out, given the space available and the provided input--the effect- documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers- the allocation of and copying into a sliding window until necessary, which- provides the effect documented in zlib.h for Z_FINISH when the entire input- stream available. So the only thing the flush parameter actually does is:- when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it- will return Z_BUF_ERROR if it has not reached the end of the stream.- */--int ZEXPORT inflate(strm, flush)-z_streamp strm;-int flush;-{- struct inflate_state FAR *state;- z_const unsigned char FAR *next; /* next input */- unsigned char FAR *put; /* next output */- unsigned have, left; /* available input and output */- unsigned long hold; /* bit buffer */- unsigned bits; /* bits in bit buffer */- unsigned in, out; /* save starting available input and output */- unsigned copy; /* number of stored or match bytes to copy */- unsigned char FAR *from; /* where to copy match bytes from */- code here; /* current decoding table entry */- code last; /* parent table entry */- unsigned len; /* length to copy for repeats, bits to drop */- int ret; /* return code */-#ifdef GUNZIP- unsigned char hbuf[4]; /* buffer for gzip header crc calculation */-#endif- static const unsigned short order[19] = /* permutation of code lengths */- {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};-- if (inflateStateCheck(strm) || strm->next_out == Z_NULL ||- (strm->next_in == Z_NULL && strm->avail_in != 0))- return Z_STREAM_ERROR;-- state = (struct inflate_state FAR *)strm->state;- if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */- LOAD();- in = have;- out = left;- ret = Z_OK;- for (;;)- switch (state->mode) {- case HEAD:- if (state->wrap == 0) {- state->mode = TYPEDO;- break;- }- NEEDBITS(16);-#ifdef GUNZIP- if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */- if (state->wbits == 0)- state->wbits = 15;- state->check = crc32(0L, Z_NULL, 0);- CRC2(state->check, hold);- INITBITS();- state->mode = FLAGS;- break;- }- state->flags = 0; /* expect zlib header */- if (state->head != Z_NULL)- state->head->done = -1;- if (!(state->wrap & 1) || /* check if zlib header allowed */-#else- if (-#endif- ((BITS(8) << 8) + (hold >> 8)) % 31) {- strm->msg = (char *)"incorrect header check";- state->mode = BAD;- break;- }- if (BITS(4) != Z_DEFLATED) {- strm->msg = (char *)"unknown compression method";- state->mode = BAD;- break;- }- DROPBITS(4);- len = BITS(4) + 8;- if (state->wbits == 0)- state->wbits = len;- if (len > 15 || len > state->wbits) {- strm->msg = (char *)"invalid window size";- state->mode = BAD;- break;- }- state->dmax = 1U << len;- Tracev((stderr, "inflate: zlib header ok\n"));- strm->adler = state->check = adler32(0L, Z_NULL, 0);- state->mode = hold & 0x200 ? DICTID : TYPE;- INITBITS();- break;-#ifdef GUNZIP- case FLAGS:- NEEDBITS(16);- state->flags = (int)(hold);- if ((state->flags & 0xff) != Z_DEFLATED) {- strm->msg = (char *)"unknown compression method";- state->mode = BAD;- break;- }- if (state->flags & 0xe000) {- strm->msg = (char *)"unknown header flags set";- state->mode = BAD;- break;- }- if (state->head != Z_NULL)- state->head->text = (int)((hold >> 8) & 1);- if ((state->flags & 0x0200) && (state->wrap & 4))- CRC2(state->check, hold);- INITBITS();- state->mode = TIME;- case TIME:- NEEDBITS(32);- if (state->head != Z_NULL)- state->head->time = hold;- if ((state->flags & 0x0200) && (state->wrap & 4))- CRC4(state->check, hold);- INITBITS();- state->mode = OS;- case OS:- NEEDBITS(16);- if (state->head != Z_NULL) {- state->head->xflags = (int)(hold & 0xff);- state->head->os = (int)(hold >> 8);- }- if ((state->flags & 0x0200) && (state->wrap & 4))- CRC2(state->check, hold);- INITBITS();- state->mode = EXLEN;- case EXLEN:- if (state->flags & 0x0400) {- NEEDBITS(16);- state->length = (unsigned)(hold);- if (state->head != Z_NULL)- state->head->extra_len = (unsigned)hold;- if ((state->flags & 0x0200) && (state->wrap & 4))- CRC2(state->check, hold);- INITBITS();- }- else if (state->head != Z_NULL)- state->head->extra = Z_NULL;- state->mode = EXTRA;- case EXTRA:- if (state->flags & 0x0400) {- copy = state->length;- if (copy > have) copy = have;- if (copy) {- if (state->head != Z_NULL &&- state->head->extra != Z_NULL) {- len = state->head->extra_len - state->length;- zmemcpy(state->head->extra + len, next,- len + copy > state->head->extra_max ?- state->head->extra_max - len : copy);- }- if ((state->flags & 0x0200) && (state->wrap & 4))- state->check = crc32(state->check, next, copy);- have -= copy;- next += copy;- state->length -= copy;- }- if (state->length) goto inf_leave;- }- state->length = 0;- state->mode = NAME;- case NAME:- if (state->flags & 0x0800) {- if (have == 0) goto inf_leave;- copy = 0;- do {- len = (unsigned)(next[copy++]);- if (state->head != Z_NULL &&- state->head->name != Z_NULL &&- state->length < state->head->name_max)- state->head->name[state->length++] = (Bytef)len;- } while (len && copy < have);- if ((state->flags & 0x0200) && (state->wrap & 4))- state->check = crc32(state->check, next, copy);- have -= copy;- next += copy;- if (len) goto inf_leave;- }- else if (state->head != Z_NULL)- state->head->name = Z_NULL;- state->length = 0;- state->mode = COMMENT;- case COMMENT:- if (state->flags & 0x1000) {- if (have == 0) goto inf_leave;- copy = 0;- do {- len = (unsigned)(next[copy++]);- if (state->head != Z_NULL &&- state->head->comment != Z_NULL &&- state->length < state->head->comm_max)- state->head->comment[state->length++] = (Bytef)len;- } while (len && copy < have);- if ((state->flags & 0x0200) && (state->wrap & 4))- state->check = crc32(state->check, next, copy);- have -= copy;- next += copy;- if (len) goto inf_leave;- }- else if (state->head != Z_NULL)- state->head->comment = Z_NULL;- state->mode = HCRC;- case HCRC:- if (state->flags & 0x0200) {- NEEDBITS(16);- if ((state->wrap & 4) && hold != (state->check & 0xffff)) {- strm->msg = (char *)"header crc mismatch";- state->mode = BAD;- break;- }- INITBITS();- }- if (state->head != Z_NULL) {- state->head->hcrc = (int)((state->flags >> 9) & 1);- state->head->done = 1;- }- strm->adler = state->check = crc32(0L, Z_NULL, 0);- state->mode = TYPE;- break;-#endif- case DICTID:- NEEDBITS(32);- strm->adler = state->check = ZSWAP32(hold);- INITBITS();- state->mode = DICT;- case DICT:- if (state->havedict == 0) {- RESTORE();- return Z_NEED_DICT;- }- strm->adler = state->check = adler32(0L, Z_NULL, 0);- state->mode = TYPE;- case TYPE:- if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;- case TYPEDO:- if (state->last) {- BYTEBITS();- state->mode = CHECK;- break;- }- NEEDBITS(3);- state->last = BITS(1);- DROPBITS(1);- switch (BITS(2)) {- case 0: /* stored block */- Tracev((stderr, "inflate: stored block%s\n",- state->last ? " (last)" : ""));- state->mode = STORED;- break;- case 1: /* fixed block */- fixedtables(state);- Tracev((stderr, "inflate: fixed codes block%s\n",- state->last ? " (last)" : ""));- state->mode = LEN_; /* decode codes */- if (flush == Z_TREES) {- DROPBITS(2);- goto inf_leave;- }- break;- case 2: /* dynamic block */- Tracev((stderr, "inflate: dynamic codes block%s\n",- state->last ? " (last)" : ""));- state->mode = TABLE;- break;- case 3:- strm->msg = (char *)"invalid block type";- state->mode = BAD;- }- DROPBITS(2);- break;- case STORED:- BYTEBITS(); /* go to byte boundary */- NEEDBITS(32);- if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {- strm->msg = (char *)"invalid stored block lengths";- state->mode = BAD;- break;- }- state->length = (unsigned)hold & 0xffff;- Tracev((stderr, "inflate: stored length %u\n",- state->length));- INITBITS();- state->mode = COPY_;- if (flush == Z_TREES) goto inf_leave;- case COPY_:- state->mode = COPY;- case COPY:- copy = state->length;- if (copy) {- if (copy > have) copy = have;- if (copy > left) copy = left;- if (copy == 0) goto inf_leave;- zmemcpy(put, next, copy);- have -= copy;- next += copy;- left -= copy;- put += copy;- state->length -= copy;- break;- }- Tracev((stderr, "inflate: stored end\n"));- state->mode = TYPE;- break;- case TABLE:- NEEDBITS(14);- state->nlen = BITS(5) + 257;- DROPBITS(5);- state->ndist = BITS(5) + 1;- DROPBITS(5);- state->ncode = BITS(4) + 4;- DROPBITS(4);-#ifndef PKZIP_BUG_WORKAROUND- if (state->nlen > 286 || state->ndist > 30) {- strm->msg = (char *)"too many length or distance symbols";- state->mode = BAD;- break;- }-#endif- Tracev((stderr, "inflate: table sizes ok\n"));- state->have = 0;- state->mode = LENLENS;- case LENLENS:- while (state->have < state->ncode) {- NEEDBITS(3);- state->lens[order[state->have++]] = (unsigned short)BITS(3);- DROPBITS(3);- }- while (state->have < 19)- state->lens[order[state->have++]] = 0;- state->next = state->codes;- state->lencode = (const code FAR *)(state->next);- state->lenbits = 7;- ret = inflate_table(CODES, state->lens, 19, &(state->next),- &(state->lenbits), state->work);- if (ret) {- strm->msg = (char *)"invalid code lengths set";- state->mode = BAD;- break;- }- Tracev((stderr, "inflate: code lengths ok\n"));- state->have = 0;- state->mode = CODELENS;- case CODELENS:- while (state->have < state->nlen + state->ndist) {- for (;;) {- here = state->lencode[BITS(state->lenbits)];- if ((unsigned)(here.bits) <= bits) break;- PULLBYTE();- }- if (here.val < 16) {- DROPBITS(here.bits);- state->lens[state->have++] = here.val;- }- else {- if (here.val == 16) {- NEEDBITS(here.bits + 2);- DROPBITS(here.bits);- if (state->have == 0) {- strm->msg = (char *)"invalid bit length repeat";- state->mode = BAD;- break;- }- len = state->lens[state->have - 1];- copy = 3 + BITS(2);- DROPBITS(2);- }- else if (here.val == 17) {- NEEDBITS(here.bits + 3);- DROPBITS(here.bits);- len = 0;- copy = 3 + BITS(3);- DROPBITS(3);- }- else {- NEEDBITS(here.bits + 7);- DROPBITS(here.bits);- len = 0;- copy = 11 + BITS(7);- DROPBITS(7);- }- if (state->have + copy > state->nlen + state->ndist) {- strm->msg = (char *)"invalid bit length repeat";- state->mode = BAD;- break;- }- while (copy--)- state->lens[state->have++] = (unsigned short)len;- }- }-- /* handle error breaks in while */- if (state->mode == BAD) break;-- /* check for end-of-block code (better have one) */- if (state->lens[256] == 0) {- strm->msg = (char *)"invalid code -- missing end-of-block";- state->mode = BAD;- break;- }-- /* build code tables -- note: do not change the lenbits or distbits- values here (9 and 6) without reading the comments in inftrees.h- concerning the ENOUGH constants, which depend on those values */- state->next = state->codes;- state->lencode = (const code FAR *)(state->next);- state->lenbits = 9;- ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),- &(state->lenbits), state->work);- if (ret) {- strm->msg = (char *)"invalid literal/lengths set";- state->mode = BAD;- break;- }- state->distcode = (const code FAR *)(state->next);- state->distbits = 6;- ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,- &(state->next), &(state->distbits), state->work);- if (ret) {- strm->msg = (char *)"invalid distances set";- state->mode = BAD;- break;- }- Tracev((stderr, "inflate: codes ok\n"));- state->mode = LEN_;- if (flush == Z_TREES) goto inf_leave;- case LEN_:- state->mode = LEN;- case LEN:- if (have >= 6 && left >= 258) {- RESTORE();- inflate_fast(strm, out);- LOAD();- if (state->mode == TYPE)- state->back = -1;- break;- }- state->back = 0;- for (;;) {- here = state->lencode[BITS(state->lenbits)];- if ((unsigned)(here.bits) <= bits) break;- PULLBYTE();- }- if (here.op && (here.op & 0xf0) == 0) {- last = here;- for (;;) {- here = state->lencode[last.val +- (BITS(last.bits + last.op) >> last.bits)];- if ((unsigned)(last.bits + here.bits) <= bits) break;- PULLBYTE();- }- DROPBITS(last.bits);- state->back += last.bits;- }- DROPBITS(here.bits);- state->back += here.bits;- state->length = (unsigned)here.val;- if ((int)(here.op) == 0) {- Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?- "inflate: literal '%c'\n" :- "inflate: literal 0x%02x\n", here.val));- state->mode = LIT;- break;- }- if (here.op & 32) {- Tracevv((stderr, "inflate: end of block\n"));- state->back = -1;- state->mode = TYPE;- break;- }- if (here.op & 64) {- strm->msg = (char *)"invalid literal/length code";- state->mode = BAD;- break;- }- state->extra = (unsigned)(here.op) & 15;- state->mode = LENEXT;- case LENEXT:- if (state->extra) {- NEEDBITS(state->extra);- state->length += BITS(state->extra);- DROPBITS(state->extra);- state->back += state->extra;- }- Tracevv((stderr, "inflate: length %u\n", state->length));- state->was = state->length;- state->mode = DIST;- case DIST:- for (;;) {- here = state->distcode[BITS(state->distbits)];- if ((unsigned)(here.bits) <= bits) break;- PULLBYTE();- }- if ((here.op & 0xf0) == 0) {- last = here;- for (;;) {- here = state->distcode[last.val +- (BITS(last.bits + last.op) >> last.bits)];- if ((unsigned)(last.bits + here.bits) <= bits) break;- PULLBYTE();- }- DROPBITS(last.bits);- state->back += last.bits;- }- DROPBITS(here.bits);- state->back += here.bits;- if (here.op & 64) {- strm->msg = (char *)"invalid distance code";- state->mode = BAD;- break;- }- state->offset = (unsigned)here.val;- state->extra = (unsigned)(here.op) & 15;- state->mode = DISTEXT;- case DISTEXT:- if (state->extra) {- NEEDBITS(state->extra);- state->offset += BITS(state->extra);- DROPBITS(state->extra);- state->back += state->extra;- }-#ifdef INFLATE_STRICT- if (state->offset > state->dmax) {- strm->msg = (char *)"invalid distance too far back";- state->mode = BAD;- break;- }-#endif- Tracevv((stderr, "inflate: distance %u\n", state->offset));- state->mode = MATCH;- case MATCH:- if (left == 0) goto inf_leave;- copy = out - left;- if (state->offset > copy) { /* copy from window */- copy = state->offset - copy;- if (copy > state->whave) {- if (state->sane) {- strm->msg = (char *)"invalid distance too far back";- state->mode = BAD;- break;- }-#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR- Trace((stderr, "inflate.c too far\n"));- copy -= state->whave;- if (copy > state->length) copy = state->length;- if (copy > left) copy = left;- left -= copy;- state->length -= copy;- do {- *put++ = 0;- } while (--copy);- if (state->length == 0) state->mode = LEN;- break;-#endif- }- if (copy > state->wnext) {- copy -= state->wnext;- from = state->window + (state->wsize - copy);- }- else- from = state->window + (state->wnext - copy);- if (copy > state->length) copy = state->length;- }- else { /* copy from output */- from = put - state->offset;- copy = state->length;- }- if (copy > left) copy = left;- left -= copy;- state->length -= copy;- do {- *put++ = *from++;- } while (--copy);- if (state->length == 0) state->mode = LEN;- break;- case LIT:- if (left == 0) goto inf_leave;- *put++ = (unsigned char)(state->length);- left--;- state->mode = LEN;- break;- case CHECK:- if (state->wrap) {- NEEDBITS(32);- out -= left;- strm->total_out += out;- state->total += out;- if ((state->wrap & 4) && out)- strm->adler = state->check =- UPDATE(state->check, put - out, out);- out = left;- if ((state->wrap & 4) && (-#ifdef GUNZIP- state->flags ? hold :-#endif- ZSWAP32(hold)) != state->check) {- strm->msg = (char *)"incorrect data check";- state->mode = BAD;- break;- }- INITBITS();- Tracev((stderr, "inflate: check matches trailer\n"));- }-#ifdef GUNZIP- state->mode = LENGTH;- case LENGTH:- if (state->wrap && state->flags) {- NEEDBITS(32);- if (hold != (state->total & 0xffffffffUL)) {- strm->msg = (char *)"incorrect length check";- state->mode = BAD;- break;- }- INITBITS();- Tracev((stderr, "inflate: length matches trailer\n"));- }-#endif- state->mode = DONE;- case DONE:- ret = Z_STREAM_END;- goto inf_leave;- case BAD:- ret = Z_DATA_ERROR;- goto inf_leave;- case MEM:- return Z_MEM_ERROR;- case SYNC:- default:- return Z_STREAM_ERROR;- }-- /*- Return from inflate(), updating the total counts and the check value.- If there was no progress during the inflate() call, return a buffer- error. Call updatewindow() to create and/or update the window state.- Note: a memory error from inflate() is non-recoverable.- */- inf_leave:- RESTORE();- if (state->wsize || (out != strm->avail_out && state->mode < BAD &&- (state->mode < CHECK || flush != Z_FINISH)))- if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {- state->mode = MEM;- return Z_MEM_ERROR;- }- in -= strm->avail_in;- out -= strm->avail_out;- strm->total_in += in;- strm->total_out += out;- state->total += out;- if ((state->wrap & 4) && out)- strm->adler = state->check =- UPDATE(state->check, strm->next_out - out, out);- strm->data_type = (int)state->bits + (state->last ? 64 : 0) +- (state->mode == TYPE ? 128 : 0) +- (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);- if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)- ret = Z_BUF_ERROR;- return ret;-}--int ZEXPORT inflateEnd(strm)-z_streamp strm;-{- struct inflate_state FAR *state;- if (inflateStateCheck(strm))- return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;- if (state->window != Z_NULL) ZFREE(strm, state->window);- ZFREE(strm, strm->state);- strm->state = Z_NULL;- Tracev((stderr, "inflate: end\n"));- return Z_OK;-}--int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)-z_streamp strm;-Bytef *dictionary;-uInt *dictLength;-{- struct inflate_state FAR *state;-- /* check state */- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;-- /* copy dictionary */- if (state->whave && dictionary != Z_NULL) {- zmemcpy(dictionary, state->window + state->wnext,- state->whave - state->wnext);- zmemcpy(dictionary + state->whave - state->wnext,- state->window, state->wnext);- }- if (dictLength != Z_NULL)- *dictLength = state->whave;- return Z_OK;-}--int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)-z_streamp strm;-const Bytef *dictionary;-uInt dictLength;-{- struct inflate_state FAR *state;- unsigned long dictid;- int ret;-- /* check state */- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;- if (state->wrap != 0 && state->mode != DICT)- return Z_STREAM_ERROR;-- /* check for correct dictionary identifier */- if (state->mode == DICT) {- dictid = adler32(0L, Z_NULL, 0);- dictid = adler32(dictid, dictionary, dictLength);- if (dictid != state->check)- return Z_DATA_ERROR;- }-- /* copy dictionary to window using updatewindow(), which will amend the- existing dictionary if appropriate */- ret = updatewindow(strm, dictionary + dictLength, dictLength);- if (ret) {- state->mode = MEM;- return Z_MEM_ERROR;- }- state->havedict = 1;- Tracev((stderr, "inflate: dictionary set\n"));- return Z_OK;-}--int ZEXPORT inflateGetHeader(strm, head)-z_streamp strm;-gz_headerp head;-{- struct inflate_state FAR *state;-- /* check state */- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;- if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;-- /* save header structure */- state->head = head;- head->done = 0;- return Z_OK;-}--/*- Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found- or when out of input. When called, *have is the number of pattern bytes- found in order so far, in 0..3. On return *have is updated to the new- state. If on return *have equals four, then the pattern was found and the- return value is how many bytes were read including the last byte of the- pattern. If *have is less than four, then the pattern has not been found- yet and the return value is len. In the latter case, syncsearch() can be- called again with more data and the *have state. *have is initialized to- zero for the first call.- */-local unsigned syncsearch(have, buf, len)-unsigned FAR *have;-const unsigned char FAR *buf;-unsigned len;-{- unsigned got;- unsigned next;-- got = *have;- next = 0;- while (next < len && got < 4) {- if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))- got++;- else if (buf[next])- got = 0;- else- got = 4 - got;- next++;- }- *have = got;- return next;-}--int ZEXPORT inflateSync(strm)-z_streamp strm;-{- unsigned len; /* number of bytes to look at or looked at */- unsigned long in, out; /* temporary to save total_in and total_out */- unsigned char buf[4]; /* to restore bit buffer to byte string */- struct inflate_state FAR *state;-- /* check parameters */- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;- if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;-- /* if first time, start search in bit buffer */- if (state->mode != SYNC) {- state->mode = SYNC;- state->hold <<= state->bits & 7;- state->bits -= state->bits & 7;- len = 0;- while (state->bits >= 8) {- buf[len++] = (unsigned char)(state->hold);- state->hold >>= 8;- state->bits -= 8;- }- state->have = 0;- syncsearch(&(state->have), buf, len);- }-- /* search available input */- len = syncsearch(&(state->have), strm->next_in, strm->avail_in);- strm->avail_in -= len;- strm->next_in += len;- strm->total_in += len;-- /* return no joy or set up to restart inflate() on a new block */- if (state->have != 4) return Z_DATA_ERROR;- in = strm->total_in; out = strm->total_out;- inflateReset(strm);- strm->total_in = in; strm->total_out = out;- state->mode = TYPE;- return Z_OK;-}--/*- Returns true if inflate is currently at the end of a block generated by- Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP- implementation to provide an additional safety check. PPP uses- Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored- block. When decompressing, PPP checks that at the end of input packet,- inflate is waiting for these length bytes.- */-int ZEXPORT inflateSyncPoint(strm)-z_streamp strm;-{- struct inflate_state FAR *state;-- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;- return state->mode == STORED && state->bits == 0;-}--int ZEXPORT inflateCopy(dest, source)-z_streamp dest;-z_streamp source;-{- struct inflate_state FAR *state;- struct inflate_state FAR *copy;- unsigned char FAR *window;- unsigned wsize;-- /* check input */- if (inflateStateCheck(source) || dest == Z_NULL)- return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)source->state;-- /* allocate space */- copy = (struct inflate_state FAR *)- ZALLOC(source, 1, sizeof(struct inflate_state));- if (copy == Z_NULL) return Z_MEM_ERROR;- window = Z_NULL;- if (state->window != Z_NULL) {- window = (unsigned char FAR *)- ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));- if (window == Z_NULL) {- ZFREE(source, copy);- return Z_MEM_ERROR;- }- }-- /* copy state */- zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));- zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));- copy->strm = dest;- if (state->lencode >= state->codes &&- state->lencode <= state->codes + ENOUGH - 1) {- copy->lencode = copy->codes + (state->lencode - state->codes);- copy->distcode = copy->codes + (state->distcode - state->codes);- }- copy->next = copy->codes + (state->next - state->codes);- if (window != Z_NULL) {- wsize = 1U << state->wbits;- zmemcpy(window, state->window, wsize);- }- copy->window = window;- dest->state = (struct internal_state FAR *)copy;- return Z_OK;-}--int ZEXPORT inflateUndermine(strm, subvert)-z_streamp strm;-int subvert;-{- struct inflate_state FAR *state;-- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;-#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR- state->sane = !subvert;- return Z_OK;-#else- (void)subvert;- state->sane = 1;- return Z_DATA_ERROR;-#endif-}--int ZEXPORT inflateValidate(strm, check)-z_streamp strm;-int check;-{- struct inflate_state FAR *state;-- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;- state = (struct inflate_state FAR *)strm->state;- if (check)- state->wrap |= 4;- else- state->wrap &= ~4;- return Z_OK;-}--long ZEXPORT inflateMark(strm)-z_streamp strm;-{- struct inflate_state FAR *state;-- if (inflateStateCheck(strm))- return -(1L << 16);- state = (struct inflate_state FAR *)strm->state;- return (long)(((unsigned long)((long)state->back)) << 16) +- (state->mode == COPY ? state->length :- (state->mode == MATCH ? state->was - state->length : 0));-}--unsigned long ZEXPORT inflateCodesUsed(strm)-z_streamp strm;-{- struct inflate_state FAR *state;- if (inflateStateCheck(strm)) return (unsigned long)-1;- state = (struct inflate_state FAR *)strm->state;- return (unsigned long)(state->next - state->codes);-}
− c/zlib/inflate.h
@@ -1,125 +0,0 @@-/* inflate.h -- internal inflate state definition- * Copyright (C) 1995-2016 Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/* WARNING: this file should *not* be used by applications. It is- part of the implementation of the compression library and is- subject to change. Applications should only use zlib.h.- */--/* define NO_GZIP when compiling if you want to disable gzip header and- trailer decoding by inflate(). NO_GZIP would be used to avoid linking in- the crc code when it is not needed. For shared libraries, gzip decoding- should be left enabled. */-#ifndef NO_GZIP-# define GUNZIP-#endif--/* Possible inflate modes between inflate() calls */-typedef enum {- HEAD = 16180, /* i: waiting for magic header */- FLAGS, /* i: waiting for method and flags (gzip) */- TIME, /* i: waiting for modification time (gzip) */- OS, /* i: waiting for extra flags and operating system (gzip) */- EXLEN, /* i: waiting for extra length (gzip) */- EXTRA, /* i: waiting for extra bytes (gzip) */- NAME, /* i: waiting for end of file name (gzip) */- COMMENT, /* i: waiting for end of comment (gzip) */- HCRC, /* i: waiting for header crc (gzip) */- DICTID, /* i: waiting for dictionary check value */- DICT, /* waiting for inflateSetDictionary() call */- TYPE, /* i: waiting for type bits, including last-flag bit */- TYPEDO, /* i: same, but skip check to exit inflate on new block */- STORED, /* i: waiting for stored size (length and complement) */- COPY_, /* i/o: same as COPY below, but only first time in */- COPY, /* i/o: waiting for input or output to copy stored block */- TABLE, /* i: waiting for dynamic block table lengths */- LENLENS, /* i: waiting for code length code lengths */- CODELENS, /* i: waiting for length/lit and distance code lengths */- LEN_, /* i: same as LEN below, but only first time in */- LEN, /* i: waiting for length/lit/eob code */- LENEXT, /* i: waiting for length extra bits */- DIST, /* i: waiting for distance code */- DISTEXT, /* i: waiting for distance extra bits */- MATCH, /* o: waiting for output space to copy string */- LIT, /* o: waiting for output space to write literal */- CHECK, /* i: waiting for 32-bit check value */- LENGTH, /* i: waiting for 32-bit length (gzip) */- DONE, /* finished check, done -- remain here until reset */- BAD, /* got a data error -- remain here until reset */- MEM, /* got an inflate() memory error -- remain here until reset */- SYNC /* looking for synchronization bytes to restart inflate() */-} inflate_mode;--/*- State transitions between above modes --- (most modes can go to BAD or MEM on error -- not shown for clarity)-- Process header:- HEAD -> (gzip) or (zlib) or (raw)- (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->- HCRC -> TYPE- (zlib) -> DICTID or TYPE- DICTID -> DICT -> TYPE- (raw) -> TYPEDO- Read deflate blocks:- TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK- STORED -> COPY_ -> COPY -> TYPE- TABLE -> LENLENS -> CODELENS -> LEN_- LEN_ -> LEN- Read deflate codes in fixed or dynamic block:- LEN -> LENEXT or LIT or TYPE- LENEXT -> DIST -> DISTEXT -> MATCH -> LEN- LIT -> LEN- Process trailer:- CHECK -> LENGTH -> DONE- */--/* State maintained between inflate() calls -- approximately 7K bytes, not- including the allocated sliding window, which is up to 32K bytes. */-struct inflate_state {- z_streamp strm; /* pointer back to this zlib stream */- inflate_mode mode; /* current inflate mode */- int last; /* true if processing last block */- int wrap; /* bit 0 true for zlib, bit 1 true for gzip,- bit 2 true to validate check value */- int havedict; /* true if dictionary provided */- int flags; /* gzip header method and flags (0 if zlib) */- unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */- unsigned long check; /* protected copy of check value */- unsigned long total; /* protected copy of output count */- gz_headerp head; /* where to save gzip header information */- /* sliding window */- unsigned wbits; /* log base 2 of requested window size */- unsigned wsize; /* window size or zero if not using window */- unsigned whave; /* valid bytes in the window */- unsigned wnext; /* window write index */- unsigned char FAR *window; /* allocated sliding window, if needed */- /* bit accumulator */- unsigned long hold; /* input bit accumulator */- unsigned bits; /* number of bits in "in" */- /* for string and stored block copying */- unsigned length; /* literal or length of data to copy */- unsigned offset; /* distance back to copy string from */- /* for table and code decoding */- unsigned extra; /* extra bits needed */- /* fixed and dynamic code tables */- code const FAR *lencode; /* starting table for length/literal codes */- code const FAR *distcode; /* starting table for distance codes */- unsigned lenbits; /* index bits for lencode */- unsigned distbits; /* index bits for distcode */- /* dynamic table building */- unsigned ncode; /* number of code length code lengths */- unsigned nlen; /* number of length code lengths */- unsigned ndist; /* number of distance code lengths */- unsigned have; /* number of code lengths in lens[] */- code FAR *next; /* next available space in codes[] */- unsigned short lens[320]; /* temporary storage for code lengths */- unsigned short work[288]; /* work area for code table building */- code codes[ENOUGH]; /* space for code tables */- int sane; /* if false, allow invalid distance too far */- int back; /* bits back of last unprocessed length/lit */- unsigned was; /* initial length of match */-};
− c/zlib/inftrees.c
@@ -1,304 +0,0 @@-/* inftrees.c -- generate Huffman trees for efficient decoding- * Copyright (C) 1995-2017 Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--#include "zutil.h"-#include "inftrees.h"--#define MAXBITS 15--const char inflate_copyright[] =- " inflate 1.2.11 Copyright 1995-2017 Mark Adler ";-/*- If you use the zlib library in a product, an acknowledgment is welcome- in the documentation of your product. If for some reason you cannot- include such an acknowledgment, I would appreciate that you keep this- copyright string in the executable of your product.- */--/*- Build a set of tables to decode the provided canonical Huffman code.- The code lengths are lens[0..codes-1]. The result starts at *table,- whose indices are 0..2^bits-1. work is a writable array of at least- lens shorts, which is used as a work area. type is the type of code- to be generated, CODES, LENS, or DISTS. On return, zero is success,- -1 is an invalid code, and +1 means that ENOUGH isn't enough. table- on return points to the next available entry's address. bits is the- requested root table index bits, and on return it is the actual root- table index bits. It will differ if the request is greater than the- longest code or if it is less than the shortest code.- */-int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)-codetype type;-unsigned short FAR *lens;-unsigned codes;-code FAR * FAR *table;-unsigned FAR *bits;-unsigned short FAR *work;-{- unsigned len; /* a code's length in bits */- unsigned sym; /* index of code symbols */- unsigned min, max; /* minimum and maximum code lengths */- unsigned root; /* number of index bits for root table */- unsigned curr; /* number of index bits for current table */- unsigned drop; /* code bits to drop for sub-table */- int left; /* number of prefix codes available */- unsigned used; /* code entries in table used */- unsigned huff; /* Huffman code */- unsigned incr; /* for incrementing code, index */- unsigned fill; /* index for replicating entries */- unsigned low; /* low bits for current root entry */- unsigned mask; /* mask for low root bits */- code here; /* table entry for duplication */- code FAR *next; /* next available space in table */- const unsigned short FAR *base; /* base value table to use */- const unsigned short FAR *extra; /* extra bits table to use */- unsigned match; /* use base and extra for symbol >= match */- unsigned short count[MAXBITS+1]; /* number of codes of each length */- unsigned short offs[MAXBITS+1]; /* offsets in table for each length */- static const unsigned short lbase[31] = { /* Length codes 257..285 base */- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};- static const unsigned short lext[31] = { /* Length codes 257..285 extra */- 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,- 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202};- static const unsigned short dbase[32] = { /* Distance codes 0..29 base */- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,- 8193, 12289, 16385, 24577, 0, 0};- static const unsigned short dext[32] = { /* Distance codes 0..29 extra */- 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,- 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,- 28, 28, 29, 29, 64, 64};-- /*- Process a set of code lengths to create a canonical Huffman code. The- code lengths are lens[0..codes-1]. Each length corresponds to the- symbols 0..codes-1. The Huffman code is generated by first sorting the- symbols by length from short to long, and retaining the symbol order- for codes with equal lengths. Then the code starts with all zero bits- for the first code of the shortest length, and the codes are integer- increments for the same length, and zeros are appended as the length- increases. For the deflate format, these bits are stored backwards- from their more natural integer increment ordering, and so when the- decoding tables are built in the large loop below, the integer codes- are incremented backwards.-- This routine assumes, but does not check, that all of the entries in- lens[] are in the range 0..MAXBITS. The caller must assure this.- 1..MAXBITS is interpreted as that code length. zero means that that- symbol does not occur in this code.-- The codes are sorted by computing a count of codes for each length,- creating from that a table of starting indices for each length in the- sorted table, and then entering the symbols in order in the sorted- table. The sorted table is work[], with that space being provided by- the caller.-- The length counts are used for other purposes as well, i.e. finding- the minimum and maximum length codes, determining if there are any- codes at all, checking for a valid set of lengths, and looking ahead- at length counts to determine sub-table sizes when building the- decoding tables.- */-- /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */- for (len = 0; len <= MAXBITS; len++)- count[len] = 0;- for (sym = 0; sym < codes; sym++)- count[lens[sym]]++;-- /* bound code lengths, force root to be within code lengths */- root = *bits;- for (max = MAXBITS; max >= 1; max--)- if (count[max] != 0) break;- if (root > max) root = max;- if (max == 0) { /* no symbols to code at all */- here.op = (unsigned char)64; /* invalid code marker */- here.bits = (unsigned char)1;- here.val = (unsigned short)0;- *(*table)++ = here; /* make a table to force an error */- *(*table)++ = here;- *bits = 1;- return 0; /* no symbols, but wait for decoding to report error */- }- for (min = 1; min < max; min++)- if (count[min] != 0) break;- if (root < min) root = min;-- /* check for an over-subscribed or incomplete set of lengths */- left = 1;- for (len = 1; len <= MAXBITS; len++) {- left <<= 1;- left -= count[len];- if (left < 0) return -1; /* over-subscribed */- }- if (left > 0 && (type == CODES || max != 1))- return -1; /* incomplete set */-- /* generate offsets into symbol table for each length for sorting */- offs[1] = 0;- for (len = 1; len < MAXBITS; len++)- offs[len + 1] = offs[len] + count[len];-- /* sort symbols by length, by symbol order within each length */- for (sym = 0; sym < codes; sym++)- if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;-- /*- Create and fill in decoding tables. In this loop, the table being- filled is at next and has curr index bits. The code being used is huff- with length len. That code is converted to an index by dropping drop- bits off of the bottom. For codes where len is less than drop + curr,- those top drop + curr - len bits are incremented through all values to- fill the table with replicated entries.-- root is the number of index bits for the root table. When len exceeds- root, sub-tables are created pointed to by the root entry with an index- of the low root bits of huff. This is saved in low to check for when a- new sub-table should be started. drop is zero when the root table is- being filled, and drop is root when sub-tables are being filled.-- When a new sub-table is needed, it is necessary to look ahead in the- code lengths to determine what size sub-table is needed. The length- counts are used for this, and so count[] is decremented as codes are- entered in the tables.-- used keeps track of how many table entries have been allocated from the- provided *table space. It is checked for LENS and DIST tables against- the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in- the initial root table size constants. See the comments in inftrees.h- for more information.-- sym increments through all symbols, and the loop terminates when- all codes of length max, i.e. all codes, have been processed. This- routine permits incomplete codes, so another loop after this one fills- in the rest of the decoding tables with invalid code markers.- */-- /* set up for code type */- switch (type) {- case CODES:- base = extra = work; /* dummy value--not used */- match = 20;- break;- case LENS:- base = lbase;- extra = lext;- match = 257;- break;- default: /* DISTS */- base = dbase;- extra = dext;- match = 0;- }-- /* initialize state for loop */- huff = 0; /* starting code */- sym = 0; /* starting code symbol */- len = min; /* starting code length */- next = *table; /* current table to fill in */- curr = root; /* current table index bits */- drop = 0; /* current bits to drop from code for index */- low = (unsigned)(-1); /* trigger new sub-table when len > root */- used = 1U << root; /* use root table entries */- mask = used - 1; /* mask for comparing low */-- /* check available table space */- if ((type == LENS && used > ENOUGH_LENS) ||- (type == DISTS && used > ENOUGH_DISTS))- return 1;-- /* process all codes and make table entries */- for (;;) {- /* create table entry */- here.bits = (unsigned char)(len - drop);- if (work[sym] + 1U < match) {- here.op = (unsigned char)0;- here.val = work[sym];- }- else if (work[sym] >= match) {- here.op = (unsigned char)(extra[work[sym] - match]);- here.val = base[work[sym] - match];- }- else {- here.op = (unsigned char)(32 + 64); /* end of block */- here.val = 0;- }-- /* replicate for those indices with low len bits equal to huff */- incr = 1U << (len - drop);- fill = 1U << curr;- min = fill; /* save offset to next table */- do {- fill -= incr;- next[(huff >> drop) + fill] = here;- } while (fill != 0);-- /* backwards increment the len-bit code huff */- incr = 1U << (len - 1);- while (huff & incr)- incr >>= 1;- if (incr != 0) {- huff &= incr - 1;- huff += incr;- }- else- huff = 0;-- /* go to next symbol, update count, len */- sym++;- if (--(count[len]) == 0) {- if (len == max) break;- len = lens[work[sym]];- }-- /* create new sub-table if needed */- if (len > root && (huff & mask) != low) {- /* if first time, transition to sub-tables */- if (drop == 0)- drop = root;-- /* increment past last table */- next += min; /* here min is 1 << curr */-- /* determine length of next table */- curr = len - drop;- left = (int)(1 << curr);- while (curr + drop < max) {- left -= count[curr + drop];- if (left <= 0) break;- curr++;- left <<= 1;- }-- /* check for enough space */- used += 1U << curr;- if ((type == LENS && used > ENOUGH_LENS) ||- (type == DISTS && used > ENOUGH_DISTS))- return 1;-- /* point entry in root table to sub-table */- low = huff & mask;- (*table)[low].op = (unsigned char)curr;- (*table)[low].bits = (unsigned char)root;- (*table)[low].val = (unsigned short)(next - *table);- }- }-- /* fill in remaining table entry if code is incomplete (guaranteed to have- at most one remaining entry, since if the code is incomplete, the- maximum code length that was allowed to get this far is one bit) */- if (huff != 0) {- here.op = (unsigned char)64; /* invalid code marker */- here.bits = (unsigned char)(len - drop);- here.val = (unsigned short)0;- next[huff] = here;- }-- /* set return parameters */- *table += used;- *bits = root;- return 0;-}
− c/zlib/inftrees.h
@@ -1,62 +0,0 @@-/* inftrees.h -- header to use inftrees.c- * Copyright (C) 1995-2005, 2010 Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/* WARNING: this file should *not* be used by applications. It is- part of the implementation of the compression library and is- subject to change. Applications should only use zlib.h.- */--/* Structure for decoding tables. Each entry provides either the- information needed to do the operation requested by the code that- indexed that table entry, or it provides a pointer to another- table that indexes more bits of the code. op indicates whether- the entry is a pointer to another table, a literal, a length or- distance, an end-of-block, or an invalid code. For a table- pointer, the low four bits of op is the number of index bits of- that table. For a length or distance, the low four bits of op- is the number of extra bits to get after the code. bits is- the number of bits in this code or part of the code to drop off- of the bit buffer. val is the actual byte to output in the case- of a literal, the base length or distance, or the offset from- the current table to the next table. Each entry is four bytes. */-typedef struct {- unsigned char op; /* operation, extra bits, table bits */- unsigned char bits; /* bits in this part of the code */- unsigned short val; /* offset in table or code value */-} code;--/* op values as set by inflate_table():- 00000000 - literal- 0000tttt - table link, tttt != 0 is the number of table index bits- 0001eeee - length or distance, eeee is the number of extra bits- 01100000 - end of block- 01000000 - invalid code- */--/* Maximum size of the dynamic table. The maximum number of code structures is- 1444, which is the sum of 852 for literal/length codes and 592 for distance- codes. These values were found by exhaustive searches using the program- examples/enough.c found in the zlib distribtution. The arguments to that- program are the number of symbols, the initial root table size, and the- maximum bit length of a code. "enough 286 9 15" for literal/length codes- returns returns 852, and "enough 30 6 15" for distance codes returns 592.- The initial root table size (9 or 6) is found in the fifth argument of the- inflate_table() calls in inflate.c and infback.c. If the root table size is- changed, then these maximum sizes would be need to be recalculated and- updated. */-#define ENOUGH_LENS 852-#define ENOUGH_DISTS 592-#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)--/* Type of code to build for inflate_table() */-typedef enum {- CODES,- LENS,- DISTS-} codetype;--int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,- unsigned codes, code FAR * FAR *table,- unsigned FAR *bits, unsigned short FAR *work));
− c/zlib/trees.c
@@ -1,1203 +0,0 @@-/* trees.c -- output deflated data using Huffman coding- * Copyright (C) 1995-2017 Jean-loup Gailly- * detect_data_type() function provided freely by Cosmin Truta, 2006- * For conditions of distribution and use, see copyright notice in zlib.h- */--/*- * ALGORITHM- *- * The "deflation" process uses several Huffman trees. The more- * common source values are represented by shorter bit sequences.- *- * Each code tree is stored in a compressed form which is itself- * a Huffman encoding of the lengths of all the code strings (in- * ascending order by source values). The actual code strings are- * reconstructed from the lengths in the inflate process, as described- * in the deflate specification.- *- * REFERENCES- *- * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".- * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc- *- * Storer, James A.- * Data Compression: Methods and Theory, pp. 49-50.- * Computer Science Press, 1988. ISBN 0-7167-8156-5.- *- * Sedgewick, R.- * Algorithms, p290.- * Addison-Wesley, 1983. ISBN 0-201-06672-6.- */--/* @(#) $Id$ */--/* #define GEN_TREES_H */--#include "deflate.h"--#ifdef ZLIB_DEBUG-# include <ctype.h>-#endif--/* ===========================================================================- * Constants- */--#define MAX_BL_BITS 7-/* Bit length codes must not exceed MAX_BL_BITS bits */--#define END_BLOCK 256-/* end of block literal code */--#define REP_3_6 16-/* repeat previous bit length 3-6 times (2 bits of repeat count) */--#define REPZ_3_10 17-/* repeat a zero length 3-10 times (3 bits of repeat count) */--#define REPZ_11_138 18-/* repeat a zero length 11-138 times (7 bits of repeat count) */--local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */- = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};--local const int extra_dbits[D_CODES] /* extra bits for each distance code */- = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};--local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */- = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};--local const uch bl_order[BL_CODES]- = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};-/* The lengths of the bit length codes are sent in order of decreasing- * probability, to avoid transmitting the lengths for unused bit length codes.- */--/* ===========================================================================- * Local data. These are initialized only once.- */--#define DIST_CODE_LEN 512 /* see definition of array dist_code below */--#if defined(GEN_TREES_H) || !defined(STDC)-/* non ANSI compilers may not accept trees.h */--local ct_data static_ltree[L_CODES+2];-/* The static literal tree. Since the bit lengths are imposed, there is no- * need for the L_CODES extra codes used during heap construction. However- * The codes 286 and 287 are needed to build a canonical tree (see _tr_init- * below).- */--local ct_data static_dtree[D_CODES];-/* The static distance tree. (Actually a trivial tree since all codes use- * 5 bits.)- */--uch _dist_code[DIST_CODE_LEN];-/* Distance codes. The first 256 values correspond to the distances- * 3 .. 258, the last 256 values correspond to the top 8 bits of- * the 15 bit distances.- */--uch _length_code[MAX_MATCH-MIN_MATCH+1];-/* length code for each normalized match length (0 == MIN_MATCH) */--local int base_length[LENGTH_CODES];-/* First normalized length for each code (0 = MIN_MATCH) */--local int base_dist[D_CODES];-/* First normalized distance for each code (0 = distance of 1) */--#else-# include "trees.h"-#endif /* GEN_TREES_H */--struct static_tree_desc_s {- const ct_data *static_tree; /* static tree or NULL */- const intf *extra_bits; /* extra bits for each code or NULL */- int extra_base; /* base index for extra_bits */- int elems; /* max number of elements in the tree */- int max_length; /* max bit length for the codes */-};--local const static_tree_desc static_l_desc =-{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};--local const static_tree_desc static_d_desc =-{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};--local const static_tree_desc static_bl_desc =-{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};--/* ===========================================================================- * Local (static) routines in this file.- */--local void tr_static_init OF((void));-local void init_block OF((deflate_state *s));-local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));-local void gen_bitlen OF((deflate_state *s, tree_desc *desc));-local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));-local void build_tree OF((deflate_state *s, tree_desc *desc));-local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));-local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));-local int build_bl_tree OF((deflate_state *s));-local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,- int blcodes));-local void compress_block OF((deflate_state *s, const ct_data *ltree,- const ct_data *dtree));-local int detect_data_type OF((deflate_state *s));-local unsigned bi_reverse OF((unsigned value, int length));-local void bi_windup OF((deflate_state *s));-local void bi_flush OF((deflate_state *s));--#ifdef GEN_TREES_H-local void gen_trees_header OF((void));-#endif--#ifndef ZLIB_DEBUG-# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)- /* Send a code of the given tree. c and tree must not have side effects */--#else /* !ZLIB_DEBUG */-# define send_code(s, c, tree) \- { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \- send_bits(s, tree[c].Code, tree[c].Len); }-#endif--/* ===========================================================================- * Output a short LSB first on the stream.- * IN assertion: there is enough room in pendingBuf.- */-#define put_short(s, w) { \- put_byte(s, (uch)((w) & 0xff)); \- put_byte(s, (uch)((ush)(w) >> 8)); \-}--/* ===========================================================================- * Send a value on a given number of bits.- * IN assertion: length <= 16 and value fits in length bits.- */-#ifdef ZLIB_DEBUG-local void send_bits OF((deflate_state *s, int value, int length));--local void send_bits(s, value, length)- deflate_state *s;- int value; /* value to send */- int length; /* number of bits */-{- Tracevv((stderr," l %2d v %4x ", length, value));- Assert(length > 0 && length <= 15, "invalid length");- s->bits_sent += (ulg)length;-- /* If not enough room in bi_buf, use (valid) bits from bi_buf and- * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))- * unused bits in value.- */- if (s->bi_valid > (int)Buf_size - length) {- s->bi_buf |= (ush)value << s->bi_valid;- put_short(s, s->bi_buf);- s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);- s->bi_valid += length - Buf_size;- } else {- s->bi_buf |= (ush)value << s->bi_valid;- s->bi_valid += length;- }-}-#else /* !ZLIB_DEBUG */--#define send_bits(s, value, length) \-{ int len = length;\- if (s->bi_valid > (int)Buf_size - len) {\- int val = (int)value;\- s->bi_buf |= (ush)val << s->bi_valid;\- put_short(s, s->bi_buf);\- s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\- s->bi_valid += len - Buf_size;\- } else {\- s->bi_buf |= (ush)(value) << s->bi_valid;\- s->bi_valid += len;\- }\-}-#endif /* ZLIB_DEBUG */---/* the arguments must not have side effects */--/* ===========================================================================- * Initialize the various 'constant' tables.- */-local void tr_static_init()-{-#if defined(GEN_TREES_H) || !defined(STDC)- static int static_init_done = 0;- int n; /* iterates over tree elements */- int bits; /* bit counter */- int length; /* length value */- int code; /* code value */- int dist; /* distance index */- ush bl_count[MAX_BITS+1];- /* number of codes at each bit length for an optimal tree */-- if (static_init_done) return;-- /* For some embedded targets, global variables are not initialized: */-#ifdef NO_INIT_GLOBAL_POINTERS- static_l_desc.static_tree = static_ltree;- static_l_desc.extra_bits = extra_lbits;- static_d_desc.static_tree = static_dtree;- static_d_desc.extra_bits = extra_dbits;- static_bl_desc.extra_bits = extra_blbits;-#endif-- /* Initialize the mapping length (0..255) -> length code (0..28) */- length = 0;- for (code = 0; code < LENGTH_CODES-1; code++) {- base_length[code] = length;- for (n = 0; n < (1<<extra_lbits[code]); n++) {- _length_code[length++] = (uch)code;- }- }- Assert (length == 256, "tr_static_init: length != 256");- /* Note that the length 255 (match length 258) can be represented- * in two different ways: code 284 + 5 bits or code 285, so we- * overwrite length_code[255] to use the best encoding:- */- _length_code[length-1] = (uch)code;-- /* Initialize the mapping dist (0..32K) -> dist code (0..29) */- dist = 0;- for (code = 0 ; code < 16; code++) {- base_dist[code] = dist;- for (n = 0; n < (1<<extra_dbits[code]); n++) {- _dist_code[dist++] = (uch)code;- }- }- Assert (dist == 256, "tr_static_init: dist != 256");- dist >>= 7; /* from now on, all distances are divided by 128 */- for ( ; code < D_CODES; code++) {- base_dist[code] = dist << 7;- for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {- _dist_code[256 + dist++] = (uch)code;- }- }- Assert (dist == 256, "tr_static_init: 256+dist != 512");-- /* Construct the codes of the static literal tree */- for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;- n = 0;- while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;- while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;- while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;- while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;- /* Codes 286 and 287 do not exist, but we must include them in the- * tree construction to get a canonical Huffman tree (longest code- * all ones)- */- gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);-- /* The static distance tree is trivial: */- for (n = 0; n < D_CODES; n++) {- static_dtree[n].Len = 5;- static_dtree[n].Code = bi_reverse((unsigned)n, 5);- }- static_init_done = 1;--# ifdef GEN_TREES_H- gen_trees_header();-# endif-#endif /* defined(GEN_TREES_H) || !defined(STDC) */-}--/* ===========================================================================- * Genererate the file trees.h describing the static trees.- */-#ifdef GEN_TREES_H-# ifndef ZLIB_DEBUG-# include <stdio.h>-# endif--# define SEPARATOR(i, last, width) \- ((i) == (last)? "\n};\n\n" : \- ((i) % (width) == (width)-1 ? ",\n" : ", "))--void gen_trees_header()-{- FILE *header = fopen("trees.h", "w");- int i;-- Assert (header != NULL, "Can't open trees.h");- fprintf(header,- "/* header created automatically with -DGEN_TREES_H */\n\n");-- fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");- for (i = 0; i < L_CODES+2; i++) {- fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,- static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));- }-- fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");- for (i = 0; i < D_CODES; i++) {- fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,- static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));- }-- fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");- for (i = 0; i < DIST_CODE_LEN; i++) {- fprintf(header, "%2u%s", _dist_code[i],- SEPARATOR(i, DIST_CODE_LEN-1, 20));- }-- fprintf(header,- "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");- for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {- fprintf(header, "%2u%s", _length_code[i],- SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));- }-- fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");- for (i = 0; i < LENGTH_CODES; i++) {- fprintf(header, "%1u%s", base_length[i],- SEPARATOR(i, LENGTH_CODES-1, 20));- }-- fprintf(header, "local const int base_dist[D_CODES] = {\n");- for (i = 0; i < D_CODES; i++) {- fprintf(header, "%5u%s", base_dist[i],- SEPARATOR(i, D_CODES-1, 10));- }-- fclose(header);-}-#endif /* GEN_TREES_H */--/* ===========================================================================- * Initialize the tree data structures for a new zlib stream.- */-void ZLIB_INTERNAL _tr_init(s)- deflate_state *s;-{- tr_static_init();-- s->l_desc.dyn_tree = s->dyn_ltree;- s->l_desc.stat_desc = &static_l_desc;-- s->d_desc.dyn_tree = s->dyn_dtree;- s->d_desc.stat_desc = &static_d_desc;-- s->bl_desc.dyn_tree = s->bl_tree;- s->bl_desc.stat_desc = &static_bl_desc;-- s->bi_buf = 0;- s->bi_valid = 0;-#ifdef ZLIB_DEBUG- s->compressed_len = 0L;- s->bits_sent = 0L;-#endif-- /* Initialize the first block of the first file: */- init_block(s);-}--/* ===========================================================================- * Initialize a new block.- */-local void init_block(s)- deflate_state *s;-{- int n; /* iterates over tree elements */-- /* Initialize the trees. */- for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;- for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;- for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;-- s->dyn_ltree[END_BLOCK].Freq = 1;- s->opt_len = s->static_len = 0L;- s->last_lit = s->matches = 0;-}--#define SMALLEST 1-/* Index within the heap array of least frequent node in the Huffman tree */---/* ===========================================================================- * Remove the smallest element from the heap and recreate the heap with- * one less element. Updates heap and heap_len.- */-#define pqremove(s, tree, top) \-{\- top = s->heap[SMALLEST]; \- s->heap[SMALLEST] = s->heap[s->heap_len--]; \- pqdownheap(s, tree, SMALLEST); \-}--/* ===========================================================================- * Compares to subtrees, using the tree depth as tie breaker when- * the subtrees have equal frequency. This minimizes the worst case length.- */-#define smaller(tree, n, m, depth) \- (tree[n].Freq < tree[m].Freq || \- (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))--/* ===========================================================================- * Restore the heap property by moving down the tree starting at node k,- * exchanging a node with the smallest of its two sons if necessary, stopping- * when the heap property is re-established (each father smaller than its- * two sons).- */-local void pqdownheap(s, tree, k)- deflate_state *s;- ct_data *tree; /* the tree to restore */- int k; /* node to move down */-{- int v = s->heap[k];- int j = k << 1; /* left son of k */- while (j <= s->heap_len) {- /* Set j to the smallest of the two sons: */- if (j < s->heap_len &&- smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {- j++;- }- /* Exit if v is smaller than both sons */- if (smaller(tree, v, s->heap[j], s->depth)) break;-- /* Exchange v with the smallest son */- s->heap[k] = s->heap[j]; k = j;-- /* And continue down the tree, setting j to the left son of k */- j <<= 1;- }- s->heap[k] = v;-}--/* ===========================================================================- * Compute the optimal bit lengths for a tree and update the total bit length- * for the current block.- * IN assertion: the fields freq and dad are set, heap[heap_max] and- * above are the tree nodes sorted by increasing frequency.- * OUT assertions: the field len is set to the optimal bit length, the- * array bl_count contains the frequencies for each bit length.- * The length opt_len is updated; static_len is also updated if stree is- * not null.- */-local void gen_bitlen(s, desc)- deflate_state *s;- tree_desc *desc; /* the tree descriptor */-{- ct_data *tree = desc->dyn_tree;- int max_code = desc->max_code;- const ct_data *stree = desc->stat_desc->static_tree;- const intf *extra = desc->stat_desc->extra_bits;- int base = desc->stat_desc->extra_base;- int max_length = desc->stat_desc->max_length;- int h; /* heap index */- int n, m; /* iterate over the tree elements */- int bits; /* bit length */- int xbits; /* extra bits */- ush f; /* frequency */- int overflow = 0; /* number of elements with bit length too large */-- for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;-- /* In a first pass, compute the optimal bit lengths (which may- * overflow in the case of the bit length tree).- */- tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */-- for (h = s->heap_max+1; h < HEAP_SIZE; h++) {- n = s->heap[h];- bits = tree[tree[n].Dad].Len + 1;- if (bits > max_length) bits = max_length, overflow++;- tree[n].Len = (ush)bits;- /* We overwrite tree[n].Dad which is no longer needed */-- if (n > max_code) continue; /* not a leaf node */-- s->bl_count[bits]++;- xbits = 0;- if (n >= base) xbits = extra[n-base];- f = tree[n].Freq;- s->opt_len += (ulg)f * (unsigned)(bits + xbits);- if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits);- }- if (overflow == 0) return;-- Tracev((stderr,"\nbit length overflow\n"));- /* This happens for example on obj2 and pic of the Calgary corpus */-- /* Find the first bit length which could increase: */- do {- bits = max_length-1;- while (s->bl_count[bits] == 0) bits--;- s->bl_count[bits]--; /* move one leaf down the tree */- s->bl_count[bits+1] += 2; /* move one overflow item as its brother */- s->bl_count[max_length]--;- /* The brother of the overflow item also moves one step up,- * but this does not affect bl_count[max_length]- */- overflow -= 2;- } while (overflow > 0);-- /* Now recompute all bit lengths, scanning in increasing frequency.- * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all- * lengths instead of fixing only the wrong ones. This idea is taken- * from 'ar' written by Haruhiko Okumura.)- */- for (bits = max_length; bits != 0; bits--) {- n = s->bl_count[bits];- while (n != 0) {- m = s->heap[--h];- if (m > max_code) continue;- if ((unsigned) tree[m].Len != (unsigned) bits) {- Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));- s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq;- tree[m].Len = (ush)bits;- }- n--;- }- }-}--/* ===========================================================================- * Generate the codes for a given tree and bit counts (which need not be- * optimal).- * IN assertion: the array bl_count contains the bit length statistics for- * the given tree and the field len is set for all tree elements.- * OUT assertion: the field code is set for all tree elements of non- * zero code length.- */-local void gen_codes (tree, max_code, bl_count)- ct_data *tree; /* the tree to decorate */- int max_code; /* largest code with non zero frequency */- ushf *bl_count; /* number of codes at each bit length */-{- ush next_code[MAX_BITS+1]; /* next code value for each bit length */- unsigned code = 0; /* running code value */- int bits; /* bit index */- int n; /* code index */-- /* The distribution counts are first used to generate the code values- * without bit reversal.- */- for (bits = 1; bits <= MAX_BITS; bits++) {- code = (code + bl_count[bits-1]) << 1;- next_code[bits] = (ush)code;- }- /* Check that the bit counts in bl_count are consistent. The last code- * must be all ones.- */- Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,- "inconsistent bit counts");- Tracev((stderr,"\ngen_codes: max_code %d ", max_code));-- for (n = 0; n <= max_code; n++) {- int len = tree[n].Len;- if (len == 0) continue;- /* Now reverse the bits */- tree[n].Code = (ush)bi_reverse(next_code[len]++, len);-- Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",- n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));- }-}--/* ===========================================================================- * Construct one Huffman tree and assigns the code bit strings and lengths.- * Update the total bit length for the current block.- * IN assertion: the field freq is set for all tree elements.- * OUT assertions: the fields len and code are set to the optimal bit length- * and corresponding code. The length opt_len is updated; static_len is- * also updated if stree is not null. The field max_code is set.- */-local void build_tree(s, desc)- deflate_state *s;- tree_desc *desc; /* the tree descriptor */-{- ct_data *tree = desc->dyn_tree;- const ct_data *stree = desc->stat_desc->static_tree;- int elems = desc->stat_desc->elems;- int n, m; /* iterate over heap elements */- int max_code = -1; /* largest code with non zero frequency */- int node; /* new node being created */-- /* Construct the initial heap, with least frequent element in- * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].- * heap[0] is not used.- */- s->heap_len = 0, s->heap_max = HEAP_SIZE;-- for (n = 0; n < elems; n++) {- if (tree[n].Freq != 0) {- s->heap[++(s->heap_len)] = max_code = n;- s->depth[n] = 0;- } else {- tree[n].Len = 0;- }- }-- /* The pkzip format requires that at least one distance code exists,- * and that at least one bit should be sent even if there is only one- * possible code. So to avoid special checks later on we force at least- * two codes of non zero frequency.- */- while (s->heap_len < 2) {- node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);- tree[node].Freq = 1;- s->depth[node] = 0;- s->opt_len--; if (stree) s->static_len -= stree[node].Len;- /* node is 0 or 1 so it does not have extra bits */- }- desc->max_code = max_code;-- /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,- * establish sub-heaps of increasing lengths:- */- for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);-- /* Construct the Huffman tree by repeatedly combining the least two- * frequent nodes.- */- node = elems; /* next internal node of the tree */- do {- pqremove(s, tree, n); /* n = node of least frequency */- m = s->heap[SMALLEST]; /* m = node of next least frequency */-- s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */- s->heap[--(s->heap_max)] = m;-- /* Create a new node father of n and m */- tree[node].Freq = tree[n].Freq + tree[m].Freq;- s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?- s->depth[n] : s->depth[m]) + 1);- tree[n].Dad = tree[m].Dad = (ush)node;-#ifdef DUMP_BL_TREE- if (tree == s->bl_tree) {- fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",- node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);- }-#endif- /* and insert the new node in the heap */- s->heap[SMALLEST] = node++;- pqdownheap(s, tree, SMALLEST);-- } while (s->heap_len >= 2);-- s->heap[--(s->heap_max)] = s->heap[SMALLEST];-- /* At this point, the fields freq and dad are set. We can now- * generate the bit lengths.- */- gen_bitlen(s, (tree_desc *)desc);-- /* The field len is now set, we can generate the bit codes */- gen_codes ((ct_data *)tree, max_code, s->bl_count);-}--/* ===========================================================================- * Scan a literal or distance tree to determine the frequencies of the codes- * in the bit length tree.- */-local void scan_tree (s, tree, max_code)- deflate_state *s;- ct_data *tree; /* the tree to be scanned */- int max_code; /* and its largest code of non zero frequency */-{- int n; /* iterates over all tree elements */- int prevlen = -1; /* last emitted length */- int curlen; /* length of current code */- int nextlen = tree[0].Len; /* length of next code */- int count = 0; /* repeat count of the current code */- int max_count = 7; /* max repeat count */- int min_count = 4; /* min repeat count */-- if (nextlen == 0) max_count = 138, min_count = 3;- tree[max_code+1].Len = (ush)0xffff; /* guard */-- for (n = 0; n <= max_code; n++) {- curlen = nextlen; nextlen = tree[n+1].Len;- if (++count < max_count && curlen == nextlen) {- continue;- } else if (count < min_count) {- s->bl_tree[curlen].Freq += count;- } else if (curlen != 0) {- if (curlen != prevlen) s->bl_tree[curlen].Freq++;- s->bl_tree[REP_3_6].Freq++;- } else if (count <= 10) {- s->bl_tree[REPZ_3_10].Freq++;- } else {- s->bl_tree[REPZ_11_138].Freq++;- }- count = 0; prevlen = curlen;- if (nextlen == 0) {- max_count = 138, min_count = 3;- } else if (curlen == nextlen) {- max_count = 6, min_count = 3;- } else {- max_count = 7, min_count = 4;- }- }-}--/* ===========================================================================- * Send a literal or distance tree in compressed form, using the codes in- * bl_tree.- */-local void send_tree (s, tree, max_code)- deflate_state *s;- ct_data *tree; /* the tree to be scanned */- int max_code; /* and its largest code of non zero frequency */-{- int n; /* iterates over all tree elements */- int prevlen = -1; /* last emitted length */- int curlen; /* length of current code */- int nextlen = tree[0].Len; /* length of next code */- int count = 0; /* repeat count of the current code */- int max_count = 7; /* max repeat count */- int min_count = 4; /* min repeat count */-- /* tree[max_code+1].Len = -1; */ /* guard already set */- if (nextlen == 0) max_count = 138, min_count = 3;-- for (n = 0; n <= max_code; n++) {- curlen = nextlen; nextlen = tree[n+1].Len;- if (++count < max_count && curlen == nextlen) {- continue;- } else if (count < min_count) {- do { send_code(s, curlen, s->bl_tree); } while (--count != 0);-- } else if (curlen != 0) {- if (curlen != prevlen) {- send_code(s, curlen, s->bl_tree); count--;- }- Assert(count >= 3 && count <= 6, " 3_6?");- send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);-- } else if (count <= 10) {- send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);-- } else {- send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);- }- count = 0; prevlen = curlen;- if (nextlen == 0) {- max_count = 138, min_count = 3;- } else if (curlen == nextlen) {- max_count = 6, min_count = 3;- } else {- max_count = 7, min_count = 4;- }- }-}--/* ===========================================================================- * Construct the Huffman tree for the bit lengths and return the index in- * bl_order of the last bit length code to send.- */-local int build_bl_tree(s)- deflate_state *s;-{- int max_blindex; /* index of last bit length code of non zero freq */-- /* Determine the bit length frequencies for literal and distance trees */- scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);- scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);-- /* Build the bit length tree: */- build_tree(s, (tree_desc *)(&(s->bl_desc)));- /* opt_len now includes the length of the tree representations, except- * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.- */-- /* Determine the number of bit length codes to send. The pkzip format- * requires that at least 4 bit length codes be sent. (appnote.txt says- * 3 but the actual value used is 4.)- */- for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {- if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;- }- /* Update opt_len to include the bit length tree and counts */- s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4;- Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",- s->opt_len, s->static_len));-- return max_blindex;-}--/* ===========================================================================- * Send the header for a block using dynamic Huffman trees: the counts, the- * lengths of the bit length codes, the literal tree and the distance tree.- * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.- */-local void send_all_trees(s, lcodes, dcodes, blcodes)- deflate_state *s;- int lcodes, dcodes, blcodes; /* number of codes for each tree */-{- int rank; /* index in bl_order */-- Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");- Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,- "too many codes");- Tracev((stderr, "\nbl counts: "));- send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */- send_bits(s, dcodes-1, 5);- send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */- for (rank = 0; rank < blcodes; rank++) {- Tracev((stderr, "\nbl code %2d ", bl_order[rank]));- send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);- }- Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));-- send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */- Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));-- send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */- Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));-}--/* ===========================================================================- * Send a stored block- */-void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)- deflate_state *s;- charf *buf; /* input block */- ulg stored_len; /* length of input block */- int last; /* one if this is the last block for a file */-{- send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */- bi_windup(s); /* align on byte boundary */- put_short(s, (ush)stored_len);- put_short(s, (ush)~stored_len);- zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len);- s->pending += stored_len;-#ifdef ZLIB_DEBUG- s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;- s->compressed_len += (stored_len + 4) << 3;- s->bits_sent += 2*16;- s->bits_sent += stored_len<<3;-#endif-}--/* ===========================================================================- * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)- */-void ZLIB_INTERNAL _tr_flush_bits(s)- deflate_state *s;-{- bi_flush(s);-}--/* ===========================================================================- * Send one empty static block to give enough lookahead for inflate.- * This takes 10 bits, of which 7 may remain in the bit buffer.- */-void ZLIB_INTERNAL _tr_align(s)- deflate_state *s;-{- send_bits(s, STATIC_TREES<<1, 3);- send_code(s, END_BLOCK, static_ltree);-#ifdef ZLIB_DEBUG- s->compressed_len += 10L; /* 3 for block type, 7 for EOB */-#endif- bi_flush(s);-}--/* ===========================================================================- * Determine the best encoding for the current block: dynamic trees, static- * trees or store, and write out the encoded block.- */-void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)- deflate_state *s;- charf *buf; /* input block, or NULL if too old */- ulg stored_len; /* length of input block */- int last; /* one if this is the last block for a file */-{- ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */- int max_blindex = 0; /* index of last bit length code of non zero freq */-- /* Build the Huffman trees unless a stored block is forced */- if (s->level > 0) {-- /* Check if the file is binary or text */- if (s->strm->data_type == Z_UNKNOWN)- s->strm->data_type = detect_data_type(s);-- /* Construct the literal and distance trees */- build_tree(s, (tree_desc *)(&(s->l_desc)));- Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,- s->static_len));-- build_tree(s, (tree_desc *)(&(s->d_desc)));- Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,- s->static_len));- /* At this point, opt_len and static_len are the total bit lengths of- * the compressed block data, excluding the tree representations.- */-- /* Build the bit length tree for the above two trees, and get the index- * in bl_order of the last bit length code to send.- */- max_blindex = build_bl_tree(s);-- /* Determine the best encoding. Compute the block lengths in bytes. */- opt_lenb = (s->opt_len+3+7)>>3;- static_lenb = (s->static_len+3+7)>>3;-- Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",- opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,- s->last_lit));-- if (static_lenb <= opt_lenb) opt_lenb = static_lenb;-- } else {- Assert(buf != (char*)0, "lost buf");- opt_lenb = static_lenb = stored_len + 5; /* force a stored block */- }--#ifdef FORCE_STORED- if (buf != (char*)0) { /* force stored block */-#else- if (stored_len+4 <= opt_lenb && buf != (char*)0) {- /* 4: two words for the lengths */-#endif- /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.- * Otherwise we can't have processed more than WSIZE input bytes since- * the last block flush, because compression would have been- * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to- * transform a block into a stored block.- */- _tr_stored_block(s, buf, stored_len, last);--#ifdef FORCE_STATIC- } else if (static_lenb >= 0) { /* force static trees */-#else- } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {-#endif- send_bits(s, (STATIC_TREES<<1)+last, 3);- compress_block(s, (const ct_data *)static_ltree,- (const ct_data *)static_dtree);-#ifdef ZLIB_DEBUG- s->compressed_len += 3 + s->static_len;-#endif- } else {- send_bits(s, (DYN_TREES<<1)+last, 3);- send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,- max_blindex+1);- compress_block(s, (const ct_data *)s->dyn_ltree,- (const ct_data *)s->dyn_dtree);-#ifdef ZLIB_DEBUG- s->compressed_len += 3 + s->opt_len;-#endif- }- Assert (s->compressed_len == s->bits_sent, "bad compressed size");- /* The above check is made mod 2^32, for files larger than 512 MB- * and uLong implemented on 32 bits.- */- init_block(s);-- if (last) {- bi_windup(s);-#ifdef ZLIB_DEBUG- s->compressed_len += 7; /* align on byte boundary */-#endif- }- Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,- s->compressed_len-7*last));-}--/* ===========================================================================- * Save the match info and tally the frequency counts. Return true if- * the current block must be flushed.- */-int ZLIB_INTERNAL _tr_tally (s, dist, lc)- deflate_state *s;- unsigned dist; /* distance of matched string */- unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */-{- s->d_buf[s->last_lit] = (ush)dist;- s->l_buf[s->last_lit++] = (uch)lc;- if (dist == 0) {- /* lc is the unmatched char */- s->dyn_ltree[lc].Freq++;- } else {- s->matches++;- /* Here, lc is the match length - MIN_MATCH */- dist--; /* dist = match distance - 1 */- Assert((ush)dist < (ush)MAX_DIST(s) &&- (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&- (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");-- s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;- s->dyn_dtree[d_code(dist)].Freq++;- }--#ifdef TRUNCATE_BLOCK- /* Try to guess if it is profitable to stop the current block here */- if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {- /* Compute an upper bound for the compressed length */- ulg out_length = (ulg)s->last_lit*8L;- ulg in_length = (ulg)((long)s->strstart - s->block_start);- int dcode;- for (dcode = 0; dcode < D_CODES; dcode++) {- out_length += (ulg)s->dyn_dtree[dcode].Freq *- (5L+extra_dbits[dcode]);- }- out_length >>= 3;- Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",- s->last_lit, in_length, out_length,- 100L - out_length*100L/in_length));- if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;- }-#endif- return (s->last_lit == s->lit_bufsize-1);- /* We avoid equality with lit_bufsize because of wraparound at 64K- * on 16 bit machines and because stored blocks are restricted to- * 64K-1 bytes.- */-}--/* ===========================================================================- * Send the block data compressed using the given Huffman trees- */-local void compress_block(s, ltree, dtree)- deflate_state *s;- const ct_data *ltree; /* literal tree */- const ct_data *dtree; /* distance tree */-{- unsigned dist; /* distance of matched string */- int lc; /* match length or unmatched char (if dist == 0) */- unsigned lx = 0; /* running index in l_buf */- unsigned code; /* the code to send */- int extra; /* number of extra bits to send */-- if (s->last_lit != 0) do {- dist = s->d_buf[lx];- lc = s->l_buf[lx++];- if (dist == 0) {- send_code(s, lc, ltree); /* send a literal byte */- Tracecv(isgraph(lc), (stderr," '%c' ", lc));- } else {- /* Here, lc is the match length - MIN_MATCH */- code = _length_code[lc];- send_code(s, code+LITERALS+1, ltree); /* send the length code */- extra = extra_lbits[code];- if (extra != 0) {- lc -= base_length[code];- send_bits(s, lc, extra); /* send the extra length bits */- }- dist--; /* dist is now the match distance - 1 */- code = d_code(dist);- Assert (code < D_CODES, "bad d_code");-- send_code(s, code, dtree); /* send the distance code */- extra = extra_dbits[code];- if (extra != 0) {- dist -= (unsigned)base_dist[code];- send_bits(s, dist, extra); /* send the extra distance bits */- }- } /* literal or match pair ? */-- /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */- Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,- "pendingBuf overflow");-- } while (lx < s->last_lit);-- send_code(s, END_BLOCK, ltree);-}--/* ===========================================================================- * Check if the data type is TEXT or BINARY, using the following algorithm:- * - TEXT if the two conditions below are satisfied:- * a) There are no non-portable control characters belonging to the- * "black list" (0..6, 14..25, 28..31).- * b) There is at least one printable character belonging to the- * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).- * - BINARY otherwise.- * - The following partially-portable control characters form a- * "gray list" that is ignored in this detection algorithm:- * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).- * IN assertion: the fields Freq of dyn_ltree are set.- */-local int detect_data_type(s)- deflate_state *s;-{- /* black_mask is the bit mask of black-listed bytes- * set bits 0..6, 14..25, and 28..31- * 0xf3ffc07f = binary 11110011111111111100000001111111- */- unsigned long black_mask = 0xf3ffc07fUL;- int n;-- /* Check for non-textual ("black-listed") bytes. */- for (n = 0; n <= 31; n++, black_mask >>= 1)- if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))- return Z_BINARY;-- /* Check for textual ("white-listed") bytes. */- if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0- || s->dyn_ltree[13].Freq != 0)- return Z_TEXT;- for (n = 32; n < LITERALS; n++)- if (s->dyn_ltree[n].Freq != 0)- return Z_TEXT;-- /* There are no "black-listed" or "white-listed" bytes:- * this stream either is empty or has tolerated ("gray-listed") bytes only.- */- return Z_BINARY;-}--/* ===========================================================================- * Reverse the first len bits of a code, using straightforward code (a faster- * method would use a table)- * IN assertion: 1 <= len <= 15- */-local unsigned bi_reverse(code, len)- unsigned code; /* the value to invert */- int len; /* its bit length */-{- register unsigned res = 0;- do {- res |= code & 1;- code >>= 1, res <<= 1;- } while (--len > 0);- return res >> 1;-}--/* ===========================================================================- * Flush the bit buffer, keeping at most 7 bits in it.- */-local void bi_flush(s)- deflate_state *s;-{- if (s->bi_valid == 16) {- put_short(s, s->bi_buf);- s->bi_buf = 0;- s->bi_valid = 0;- } else if (s->bi_valid >= 8) {- put_byte(s, (Byte)s->bi_buf);- s->bi_buf >>= 8;- s->bi_valid -= 8;- }-}--/* ===========================================================================- * Flush the bit buffer and align the output on a byte boundary- */-local void bi_windup(s)- deflate_state *s;-{- if (s->bi_valid > 8) {- put_short(s, s->bi_buf);- } else if (s->bi_valid > 0) {- put_byte(s, (Byte)s->bi_buf);- }- s->bi_buf = 0;- s->bi_valid = 0;-#ifdef ZLIB_DEBUG- s->bits_sent = (s->bits_sent+7) & ~7;-#endif-}
− c/zlib/trees.h
@@ -1,128 +0,0 @@-/* header created automatically with -DGEN_TREES_H */--local const ct_data static_ltree[L_CODES+2] = {-{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},-{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},-{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},-{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},-{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},-{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},-{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},-{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},-{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},-{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},-{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},-{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},-{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},-{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},-{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},-{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},-{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},-{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},-{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},-{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},-{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},-{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},-{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},-{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},-{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},-{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},-{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},-{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},-{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},-{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},-{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},-{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},-{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},-{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},-{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},-{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},-{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},-{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},-{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},-{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},-{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},-{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},-{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},-{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},-{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},-{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},-{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},-{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},-{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},-{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},-{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},-{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},-{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},-{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},-{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},-{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},-{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},-{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}-};--local const ct_data static_dtree[D_CODES] = {-{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},-{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},-{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},-{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},-{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},-{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}-};--const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {- 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,- 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,-10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,-11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,-12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,-13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,-13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,-14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,-14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,-14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,-15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,-15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,-15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,-18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,-23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,-24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,-26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,-26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,-27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,-27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,-28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,-28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,-28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,-29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,-29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,-29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29-};--const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {- 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,-13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,-17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,-19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,-21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,-22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,-23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,-24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,-25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,-25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,-26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,-26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,-27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28-};--local const int base_length[LENGTH_CODES] = {-0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,-64, 80, 96, 112, 128, 160, 192, 224, 0-};--local const int base_dist[D_CODES] = {- 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,- 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,- 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576-};-
− c/zlib/uncompr.c
@@ -1,93 +0,0 @@-/* uncompr.c -- decompress a memory buffer- * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/* @(#) $Id$ */--#define ZLIB_INTERNAL-#include "zlib.h"--/* ===========================================================================- Decompresses the source buffer into the destination buffer. *sourceLen is- the byte length of the source buffer. Upon entry, *destLen is the total size- of the destination buffer, which must be large enough to hold the entire- uncompressed data. (The size of the uncompressed data must have been saved- previously by the compressor and transmitted to the decompressor by some- mechanism outside the scope of this compression library.) Upon exit,- *destLen is the size of the decompressed data and *sourceLen is the number- of source bytes consumed. Upon return, source + *sourceLen points to the- first unused input byte.-- uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough- memory, Z_BUF_ERROR if there was not enough room in the output buffer, or- Z_DATA_ERROR if the input data was corrupted, including if the input data is- an incomplete zlib stream.-*/-int ZEXPORT uncompress2 (dest, destLen, source, sourceLen)- Bytef *dest;- uLongf *destLen;- const Bytef *source;- uLong *sourceLen;-{- z_stream stream;- int err;- const uInt max = (uInt)-1;- uLong len, left;- Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */-- len = *sourceLen;- if (*destLen) {- left = *destLen;- *destLen = 0;- }- else {- left = 1;- dest = buf;- }-- stream.next_in = (z_const Bytef *)source;- stream.avail_in = 0;- stream.zalloc = (alloc_func)0;- stream.zfree = (free_func)0;- stream.opaque = (voidpf)0;-- err = inflateInit(&stream);- if (err != Z_OK) return err;-- stream.next_out = dest;- stream.avail_out = 0;-- do {- if (stream.avail_out == 0) {- stream.avail_out = left > (uLong)max ? max : (uInt)left;- left -= stream.avail_out;- }- if (stream.avail_in == 0) {- stream.avail_in = len > (uLong)max ? max : (uInt)len;- len -= stream.avail_in;- }- err = inflate(&stream, Z_NO_FLUSH);- } while (err == Z_OK);-- *sourceLen -= len + stream.avail_in;- if (dest != buf)- *destLen = stream.total_out;- else if (stream.total_out && err == Z_BUF_ERROR)- left = 1;-- inflateEnd(&stream);- return err == Z_STREAM_END ? Z_OK :- err == Z_NEED_DICT ? Z_DATA_ERROR :- err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :- err;-}--int ZEXPORT uncompress (dest, destLen, source, sourceLen)- Bytef *dest;- uLongf *destLen;- const Bytef *source;- uLong sourceLen;-{- return uncompress2(dest, destLen, source, &sourceLen);-}
− c/zlib/zconf.h
@@ -1,534 +0,0 @@-/* zconf.h -- configuration of the zlib compression library- * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/* @(#) $Id$ */--#ifndef ZCONF_H-#define ZCONF_H--/*- * If you *really* need a unique prefix for all types and library functions,- * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.- * Even better than compiling with -DZ_PREFIX would be to use configure to set- * this permanently in zconf.h using "./configure --zprefix".- */-#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */-# define Z_PREFIX_SET--/* all linked symbols and init macros */-# define _dist_code z__dist_code-# define _length_code z__length_code-# define _tr_align z__tr_align-# define _tr_flush_bits z__tr_flush_bits-# define _tr_flush_block z__tr_flush_block-# define _tr_init z__tr_init-# define _tr_stored_block z__tr_stored_block-# define _tr_tally z__tr_tally-# define adler32 z_adler32-# define adler32_combine z_adler32_combine-# define adler32_combine64 z_adler32_combine64-# define adler32_z z_adler32_z-# ifndef Z_SOLO-# define compress z_compress-# define compress2 z_compress2-# define compressBound z_compressBound-# endif-# define crc32 z_crc32-# define crc32_combine z_crc32_combine-# define crc32_combine64 z_crc32_combine64-# define crc32_z z_crc32_z-# define deflate z_deflate-# define deflateBound z_deflateBound-# define deflateCopy z_deflateCopy-# define deflateEnd z_deflateEnd-# define deflateGetDictionary z_deflateGetDictionary-# define deflateInit z_deflateInit-# define deflateInit2 z_deflateInit2-# define deflateInit2_ z_deflateInit2_-# define deflateInit_ z_deflateInit_-# define deflateParams z_deflateParams-# define deflatePending z_deflatePending-# define deflatePrime z_deflatePrime-# define deflateReset z_deflateReset-# define deflateResetKeep z_deflateResetKeep-# define deflateSetDictionary z_deflateSetDictionary-# define deflateSetHeader z_deflateSetHeader-# define deflateTune z_deflateTune-# define deflate_copyright z_deflate_copyright-# define get_crc_table z_get_crc_table-# ifndef Z_SOLO-# define gz_error z_gz_error-# define gz_intmax z_gz_intmax-# define gz_strwinerror z_gz_strwinerror-# define gzbuffer z_gzbuffer-# define gzclearerr z_gzclearerr-# define gzclose z_gzclose-# define gzclose_r z_gzclose_r-# define gzclose_w z_gzclose_w-# define gzdirect z_gzdirect-# define gzdopen z_gzdopen-# define gzeof z_gzeof-# define gzerror z_gzerror-# define gzflush z_gzflush-# define gzfread z_gzfread-# define gzfwrite z_gzfwrite-# define gzgetc z_gzgetc-# define gzgetc_ z_gzgetc_-# define gzgets z_gzgets-# define gzoffset z_gzoffset-# define gzoffset64 z_gzoffset64-# define gzopen z_gzopen-# define gzopen64 z_gzopen64-# ifdef _WIN32-# define gzopen_w z_gzopen_w-# endif-# define gzprintf z_gzprintf-# define gzputc z_gzputc-# define gzputs z_gzputs-# define gzread z_gzread-# define gzrewind z_gzrewind-# define gzseek z_gzseek-# define gzseek64 z_gzseek64-# define gzsetparams z_gzsetparams-# define gztell z_gztell-# define gztell64 z_gztell64-# define gzungetc z_gzungetc-# define gzvprintf z_gzvprintf-# define gzwrite z_gzwrite-# endif-# define inflate z_inflate-# define inflateBack z_inflateBack-# define inflateBackEnd z_inflateBackEnd-# define inflateBackInit z_inflateBackInit-# define inflateBackInit_ z_inflateBackInit_-# define inflateCodesUsed z_inflateCodesUsed-# define inflateCopy z_inflateCopy-# define inflateEnd z_inflateEnd-# define inflateGetDictionary z_inflateGetDictionary-# define inflateGetHeader z_inflateGetHeader-# define inflateInit z_inflateInit-# define inflateInit2 z_inflateInit2-# define inflateInit2_ z_inflateInit2_-# define inflateInit_ z_inflateInit_-# define inflateMark z_inflateMark-# define inflatePrime z_inflatePrime-# define inflateReset z_inflateReset-# define inflateReset2 z_inflateReset2-# define inflateResetKeep z_inflateResetKeep-# define inflateSetDictionary z_inflateSetDictionary-# define inflateSync z_inflateSync-# define inflateSyncPoint z_inflateSyncPoint-# define inflateUndermine z_inflateUndermine-# define inflateValidate z_inflateValidate-# define inflate_copyright z_inflate_copyright-# define inflate_fast z_inflate_fast-# define inflate_table z_inflate_table-# ifndef Z_SOLO-# define uncompress z_uncompress-# define uncompress2 z_uncompress2-# endif-# define zError z_zError-# ifndef Z_SOLO-# define zcalloc z_zcalloc-# define zcfree z_zcfree-# endif-# define zlibCompileFlags z_zlibCompileFlags-# define zlibVersion z_zlibVersion--/* all zlib typedefs in zlib.h and zconf.h */-# define Byte z_Byte-# define Bytef z_Bytef-# define alloc_func z_alloc_func-# define charf z_charf-# define free_func z_free_func-# ifndef Z_SOLO-# define gzFile z_gzFile-# endif-# define gz_header z_gz_header-# define gz_headerp z_gz_headerp-# define in_func z_in_func-# define intf z_intf-# define out_func z_out_func-# define uInt z_uInt-# define uIntf z_uIntf-# define uLong z_uLong-# define uLongf z_uLongf-# define voidp z_voidp-# define voidpc z_voidpc-# define voidpf z_voidpf--/* all zlib structs in zlib.h and zconf.h */-# define gz_header_s z_gz_header_s-# define internal_state z_internal_state--#endif--#if defined(__MSDOS__) && !defined(MSDOS)-# define MSDOS-#endif-#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)-# define OS2-#endif-#if defined(_WINDOWS) && !defined(WINDOWS)-# define WINDOWS-#endif-#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)-# ifndef WIN32-# define WIN32-# endif-#endif-#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)-# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)-# ifndef SYS16BIT-# define SYS16BIT-# endif-# endif-#endif--/*- * Compile with -DMAXSEG_64K if the alloc function cannot allocate more- * than 64k bytes at a time (needed on systems with 16-bit int).- */-#ifdef SYS16BIT-# define MAXSEG_64K-#endif-#ifdef MSDOS-# define UNALIGNED_OK-#endif--#ifdef __STDC_VERSION__-# ifndef STDC-# define STDC-# endif-# if __STDC_VERSION__ >= 199901L-# ifndef STDC99-# define STDC99-# endif-# endif-#endif-#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))-# define STDC-#endif-#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))-# define STDC-#endif-#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))-# define STDC-#endif-#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))-# define STDC-#endif--#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */-# define STDC-#endif--#ifndef STDC-# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */-# define const /* note: need a more gentle solution here */-# endif-#endif--#if defined(ZLIB_CONST) && !defined(z_const)-# define z_const const-#else-# define z_const-#endif--#ifdef Z_SOLO- typedef unsigned long z_size_t;-#else-# define z_longlong long long-# if defined(NO_SIZE_T)- typedef unsigned NO_SIZE_T z_size_t;-# elif defined(STDC)-# include <stddef.h>- typedef size_t z_size_t;-# else- typedef unsigned long z_size_t;-# endif-# undef z_longlong-#endif--/* Maximum value for memLevel in deflateInit2 */-#ifndef MAX_MEM_LEVEL-# ifdef MAXSEG_64K-# define MAX_MEM_LEVEL 8-# else-# define MAX_MEM_LEVEL 9-# endif-#endif--/* Maximum value for windowBits in deflateInit2 and inflateInit2.- * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files- * created by gzip. (Files created by minigzip can still be extracted by- * gzip.)- */-#ifndef MAX_WBITS-# define MAX_WBITS 15 /* 32K LZ77 window */-#endif--/* The memory requirements for deflate are (in bytes):- (1 << (windowBits+2)) + (1 << (memLevel+9))- that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)- plus a few kilobytes for small objects. For example, if you want to reduce- the default memory requirements from 256K to 128K, compile with- make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"- Of course this will generally degrade compression (there's no free lunch).-- The memory requirements for inflate are (in bytes) 1 << windowBits- that is, 32K for windowBits=15 (default value) plus about 7 kilobytes- for small objects.-*/-- /* Type declarations */--#ifndef OF /* function prototypes */-# ifdef STDC-# define OF(args) args-# else-# define OF(args) ()-# endif-#endif--#ifndef Z_ARG /* function prototypes for stdarg */-# if defined(STDC) || defined(Z_HAVE_STDARG_H)-# define Z_ARG(args) args-# else-# define Z_ARG(args) ()-# endif-#endif--/* The following definitions for FAR are needed only for MSDOS mixed- * model programming (small or medium model with some far allocations).- * This was tested only with MSC; for other MSDOS compilers you may have- * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,- * just define FAR to be empty.- */-#ifdef SYS16BIT-# if defined(M_I86SM) || defined(M_I86MM)- /* MSC small or medium model */-# define SMALL_MEDIUM-# ifdef _MSC_VER-# define FAR _far-# else-# define FAR far-# endif-# endif-# if (defined(__SMALL__) || defined(__MEDIUM__))- /* Turbo C small or medium model */-# define SMALL_MEDIUM-# ifdef __BORLANDC__-# define FAR _far-# else-# define FAR far-# endif-# endif-#endif--#if defined(WINDOWS) || defined(WIN32)- /* If building or using zlib as a DLL, define ZLIB_DLL.- * This is not mandatory, but it offers a little performance increase.- */-# ifdef ZLIB_DLL-# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))-# ifdef ZLIB_INTERNAL-# define ZEXTERN extern __declspec(dllexport)-# else-# define ZEXTERN extern __declspec(dllimport)-# endif-# endif-# endif /* ZLIB_DLL */- /* If building or using zlib with the WINAPI/WINAPIV calling convention,- * define ZLIB_WINAPI.- * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.- */-# ifdef ZLIB_WINAPI-# ifdef FAR-# undef FAR-# endif-# include <windows.h>- /* No need for _export, use ZLIB.DEF instead. */- /* For complete Windows compatibility, use WINAPI, not __stdcall. */-# define ZEXPORT WINAPI-# ifdef WIN32-# define ZEXPORTVA WINAPIV-# else-# define ZEXPORTVA FAR CDECL-# endif-# endif-#endif--#if defined (__BEOS__)-# ifdef ZLIB_DLL-# ifdef ZLIB_INTERNAL-# define ZEXPORT __declspec(dllexport)-# define ZEXPORTVA __declspec(dllexport)-# else-# define ZEXPORT __declspec(dllimport)-# define ZEXPORTVA __declspec(dllimport)-# endif-# endif-#endif--#ifndef ZEXTERN-# define ZEXTERN extern-#endif-#ifndef ZEXPORT-# define ZEXPORT-#endif-#ifndef ZEXPORTVA-# define ZEXPORTVA-#endif--#ifndef FAR-# define FAR-#endif--#if !defined(__MACTYPES__)-typedef unsigned char Byte; /* 8 bits */-#endif-typedef unsigned int uInt; /* 16 bits or more */-typedef unsigned long uLong; /* 32 bits or more */--#ifdef SMALL_MEDIUM- /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */-# define Bytef Byte FAR-#else- typedef Byte FAR Bytef;-#endif-typedef char FAR charf;-typedef int FAR intf;-typedef uInt FAR uIntf;-typedef uLong FAR uLongf;--#ifdef STDC- typedef void const *voidpc;- typedef void FAR *voidpf;- typedef void *voidp;-#else- typedef Byte const *voidpc;- typedef Byte FAR *voidpf;- typedef Byte *voidp;-#endif--#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)-# include <limits.h>-# if (UINT_MAX == 0xffffffffUL)-# define Z_U4 unsigned-# elif (ULONG_MAX == 0xffffffffUL)-# define Z_U4 unsigned long-# elif (USHRT_MAX == 0xffffffffUL)-# define Z_U4 unsigned short-# endif-#endif--#ifdef Z_U4- typedef Z_U4 z_crc_t;-#else- typedef unsigned long z_crc_t;-#endif--#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */-# define Z_HAVE_UNISTD_H-#endif--#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */-# define Z_HAVE_STDARG_H-#endif--#ifdef STDC-# ifndef Z_SOLO-# include <sys/types.h> /* for off_t */-# endif-#endif--#if defined(STDC) || defined(Z_HAVE_STDARG_H)-# ifndef Z_SOLO-# include <stdarg.h> /* for va_list */-# endif-#endif--#ifdef _WIN32-# ifndef Z_SOLO-# include <stddef.h> /* for wchar_t */-# endif-#endif--/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and- * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even- * though the former does not conform to the LFS document), but considering- * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as- * equivalently requesting no 64-bit operations- */-#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1-# undef _LARGEFILE64_SOURCE-#endif--#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)-# define Z_HAVE_UNISTD_H-#endif-#ifndef Z_SOLO-# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)-# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */-# ifdef VMS-# include <unixio.h> /* for off_t */-# endif-# ifndef z_off_t-# define z_off_t off_t-# endif-# endif-#endif--#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0-# define Z_LFS64-#endif--#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)-# define Z_LARGE64-#endif--#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)-# define Z_WANT64-#endif--#if !defined(SEEK_SET) && !defined(Z_SOLO)-# define SEEK_SET 0 /* Seek from beginning of file. */-# define SEEK_CUR 1 /* Seek from current position. */-# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */-#endif--#ifndef z_off_t-# define z_off_t long-#endif--#if !defined(_WIN32) && defined(Z_LARGE64)-# define z_off64_t off64_t-#else-# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)-# define z_off64_t __int64-# else-# define z_off64_t z_off_t-# endif-#endif--/* MVS linker does not support external names larger than 8 bytes */-#if defined(__MVS__)- #pragma map(deflateInit_,"DEIN")- #pragma map(deflateInit2_,"DEIN2")- #pragma map(deflateEnd,"DEEND")- #pragma map(deflateBound,"DEBND")- #pragma map(inflateInit_,"ININ")- #pragma map(inflateInit2_,"ININ2")- #pragma map(inflateEnd,"INEND")- #pragma map(inflateSync,"INSY")- #pragma map(inflateSetDictionary,"INSEDI")- #pragma map(compressBound,"CMBND")- #pragma map(inflate_table,"INTABL")- #pragma map(inflate_fast,"INFA")- #pragma map(inflate_copyright,"INCOPY")-#endif--#endif /* ZCONF_H */
− c/zlib/zlib.h
@@ -1,1912 +0,0 @@-/* zlib.h -- interface of the 'zlib' general purpose compression library- version 1.2.11, January 15th, 2017-- Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler-- This software is provided 'as-is', without any express or implied- warranty. In no event will the authors be held liable for any damages- arising from the use of this software.-- Permission is granted to anyone to use this software for any purpose,- including commercial applications, and to alter it and redistribute it- freely, subject to the following restrictions:-- 1. The origin of this software must not be misrepresented; you must not- claim that you wrote the original software. If you use this software- in a product, an acknowledgment in the product documentation would be- appreciated but is not required.- 2. Altered source versions must be plainly marked as such, and must not be- misrepresented as being the original software.- 3. This notice may not be removed or altered from any source distribution.-- Jean-loup Gailly Mark Adler- jloup@gzip.org madler@alumni.caltech.edu--- The data format used by the zlib library is described by RFCs (Request for- Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950- (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).-*/--#ifndef ZLIB_H-#define ZLIB_H--#include "zconf.h"--#ifdef __cplusplus-extern "C" {-#endif--#define ZLIB_VERSION "1.2.11"-#define ZLIB_VERNUM 0x12b0-#define ZLIB_VER_MAJOR 1-#define ZLIB_VER_MINOR 2-#define ZLIB_VER_REVISION 11-#define ZLIB_VER_SUBREVISION 0--/*- The 'zlib' compression library provides in-memory compression and- decompression functions, including integrity checks of the uncompressed data.- This version of the library supports only one compression method (deflation)- but other algorithms will be added later and will have the same stream- interface.-- Compression can be done in a single step if the buffers are large enough,- or can be done by repeated calls of the compression function. In the latter- case, the application must provide more input and/or consume the output- (providing more output space) before each call.-- The compressed data format used by default by the in-memory functions is- the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped- around a deflate stream, which is itself documented in RFC 1951.-- The library also supports reading and writing files in gzip (.gz) format- with an interface similar to that of stdio using the functions that start- with "gz". The gzip format is different from the zlib format. gzip is a- gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.-- This library can optionally read and write gzip and raw deflate streams in- memory as well.-- The zlib format was designed to be compact and fast for use in memory- and on communications channels. The gzip format was designed for single-- file compression on file systems, has a larger header than zlib to maintain- directory information, and uses a different, slower check method than zlib.-- The library does not install any signal handler. The decoder checks- the consistency of the compressed data, so the library should never crash- even in the case of corrupted input.-*/--typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));-typedef void (*free_func) OF((voidpf opaque, voidpf address));--struct internal_state;--typedef struct z_stream_s {- z_const Bytef *next_in; /* next input byte */- uInt avail_in; /* number of bytes available at next_in */- uLong total_in; /* total number of input bytes read so far */-- Bytef *next_out; /* next output byte will go here */- uInt avail_out; /* remaining free space at next_out */- uLong total_out; /* total number of bytes output so far */-- z_const char *msg; /* last error message, NULL if no error */- struct internal_state FAR *state; /* not visible by applications */-- alloc_func zalloc; /* used to allocate the internal state */- free_func zfree; /* used to free the internal state */- voidpf opaque; /* private data object passed to zalloc and zfree */-- int data_type; /* best guess about the data type: binary or text- for deflate, or the decoding state for inflate */- uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */- uLong reserved; /* reserved for future use */-} z_stream;--typedef z_stream FAR *z_streamp;--/*- gzip header information passed to and from zlib routines. See RFC 1952- for more details on the meanings of these fields.-*/-typedef struct gz_header_s {- int text; /* true if compressed data believed to be text */- uLong time; /* modification time */- int xflags; /* extra flags (not used when writing a gzip file) */- int os; /* operating system */- Bytef *extra; /* pointer to extra field or Z_NULL if none */- uInt extra_len; /* extra field length (valid if extra != Z_NULL) */- uInt extra_max; /* space at extra (only when reading header) */- Bytef *name; /* pointer to zero-terminated file name or Z_NULL */- uInt name_max; /* space at name (only when reading header) */- Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */- uInt comm_max; /* space at comment (only when reading header) */- int hcrc; /* true if there was or will be a header crc */- int done; /* true when done reading gzip header (not used- when writing a gzip file) */-} gz_header;--typedef gz_header FAR *gz_headerp;--/*- The application must update next_in and avail_in when avail_in has dropped- to zero. It must update next_out and avail_out when avail_out has dropped- to zero. The application must initialize zalloc, zfree and opaque before- calling the init function. All other fields are set by the compression- library and must not be updated by the application.-- The opaque value provided by the application will be passed as the first- parameter for calls of zalloc and zfree. This can be useful for custom- memory management. The compression library attaches no meaning to the- opaque value.-- zalloc must return Z_NULL if there is not enough memory for the object.- If zlib is used in a multi-threaded application, zalloc and zfree must be- thread safe. In that case, zlib is thread-safe. When zalloc and zfree are- Z_NULL on entry to the initialization function, they are set to internal- routines that use the standard library functions malloc() and free().-- On 16-bit systems, the functions zalloc and zfree must be able to allocate- exactly 65536 bytes, but will not be required to allocate more than this if- the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers- returned by zalloc for objects of exactly 65536 bytes *must* have their- offset normalized to zero. The default allocation function provided by this- library ensures this (see zutil.c). To reduce memory requirements and avoid- any allocation of 64K objects, at the expense of compression ratio, compile- the library with -DMAX_WBITS=14 (see zconf.h).-- The fields total_in and total_out can be used for statistics or progress- reports. After compression, total_in holds the total size of the- uncompressed data and may be saved for use by the decompressor (particularly- if the decompressor wants to decompress everything in a single step).-*/-- /* constants */--#define Z_NO_FLUSH 0-#define Z_PARTIAL_FLUSH 1-#define Z_SYNC_FLUSH 2-#define Z_FULL_FLUSH 3-#define Z_FINISH 4-#define Z_BLOCK 5-#define Z_TREES 6-/* Allowed flush values; see deflate() and inflate() below for details */--#define Z_OK 0-#define Z_STREAM_END 1-#define Z_NEED_DICT 2-#define Z_ERRNO (-1)-#define Z_STREAM_ERROR (-2)-#define Z_DATA_ERROR (-3)-#define Z_MEM_ERROR (-4)-#define Z_BUF_ERROR (-5)-#define Z_VERSION_ERROR (-6)-/* Return codes for the compression/decompression functions. Negative values- * are errors, positive values are used for special but normal events.- */--#define Z_NO_COMPRESSION 0-#define Z_BEST_SPEED 1-#define Z_BEST_COMPRESSION 9-#define Z_DEFAULT_COMPRESSION (-1)-/* compression levels */--#define Z_FILTERED 1-#define Z_HUFFMAN_ONLY 2-#define Z_RLE 3-#define Z_FIXED 4-#define Z_DEFAULT_STRATEGY 0-/* compression strategy; see deflateInit2() below for details */--#define Z_BINARY 0-#define Z_TEXT 1-#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */-#define Z_UNKNOWN 2-/* Possible values of the data_type field for deflate() */--#define Z_DEFLATED 8-/* The deflate compression method (the only one supported in this version) */--#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */--#define zlib_version zlibVersion()-/* for compatibility with versions < 1.0.2 */--- /* basic functions */--ZEXTERN const char * ZEXPORT zlibVersion OF((void));-/* The application can compare zlibVersion and ZLIB_VERSION for consistency.- If the first character differs, the library code actually used is not- compatible with the zlib.h header file used by the application. This check- is automatically made by deflateInit and inflateInit.- */--/*-ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));-- Initializes the internal stream state for compression. The fields- zalloc, zfree and opaque must be initialized before by the caller. If- zalloc and zfree are set to Z_NULL, deflateInit updates them to use default- allocation functions.-- The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:- 1 gives best speed, 9 gives best compression, 0 gives no compression at all- (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION- requests a default compromise between speed and compression (currently- equivalent to level 6).-- deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough- memory, Z_STREAM_ERROR if level is not a valid compression level, or- Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible- with the version assumed by the caller (ZLIB_VERSION). msg is set to null- if there is no error message. deflateInit does not perform any compression:- this will be done by deflate().-*/---ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));-/*- deflate compresses as much data as possible, and stops when the input- buffer becomes empty or the output buffer becomes full. It may introduce- some output latency (reading input without producing any output) except when- forced to flush.-- The detailed semantics are as follows. deflate performs one or both of the- following actions:-- - Compress more input starting at next_in and update next_in and avail_in- accordingly. If not all input can be processed (because there is not- enough room in the output buffer), next_in and avail_in are updated and- processing will resume at this point for the next call of deflate().-- - Generate more output starting at next_out and update next_out and avail_out- accordingly. This action is forced if the parameter flush is non zero.- Forcing flush frequently degrades the compression ratio, so this parameter- should be set only when necessary. Some output may be provided even if- flush is zero.-- Before the call of deflate(), the application should ensure that at least- one of the actions is possible, by providing more input and/or consuming more- output, and updating avail_in or avail_out accordingly; avail_out should- never be zero before the call. The application can consume the compressed- output when it wants, for example when the output buffer is full (avail_out- == 0), or after each call of deflate(). If deflate returns Z_OK and with- zero avail_out, it must be called again after making room in the output- buffer because there might be more output pending. See deflatePending(),- which can be used if desired to determine whether or not there is more ouput- in that case.-- Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to- decide how much data to accumulate before producing output, in order to- maximize compression.-- If the parameter flush is set to Z_SYNC_FLUSH, all pending output is- flushed to the output buffer and the output is aligned on a byte boundary, so- that the decompressor can get all input data available so far. (In- particular avail_in is zero after the call if enough output space has been- provided before the call.) Flushing may degrade compression for some- compression algorithms and so it should be used only when necessary. This- completes the current deflate block and follows it with an empty stored block- that is three bits plus filler bits to the next byte, followed by four bytes- (00 00 ff ff).-- If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the- output buffer, but the output is not aligned to a byte boundary. All of the- input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.- This completes the current deflate block and follows it with an empty fixed- codes block that is 10 bits long. This assures that enough bytes are output- in order for the decompressor to finish the block before the empty fixed- codes block.-- If flush is set to Z_BLOCK, a deflate block is completed and emitted, as- for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to- seven bits of the current block are held to be written as the next byte after- the next deflate block is completed. In this case, the decompressor may not- be provided enough bits at this point in order to complete decompression of- the data provided so far to the compressor. It may need to wait for the next- block to be emitted. This is for advanced applications that need to control- the emission of deflate blocks.-- If flush is set to Z_FULL_FLUSH, all output is flushed as with- Z_SYNC_FLUSH, and the compression state is reset so that decompression can- restart from this point if previous compressed data has been damaged or if- random access is desired. Using Z_FULL_FLUSH too often can seriously degrade- compression.-- If deflate returns with avail_out == 0, this function must be called again- with the same value of the flush parameter and more output space (updated- avail_out), until the flush is complete (deflate returns with non-zero- avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that- avail_out is greater than six to avoid repeated flush markers due to- avail_out == 0 on return.-- If the parameter flush is set to Z_FINISH, pending input is processed,- pending output is flushed and deflate returns with Z_STREAM_END if there was- enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this- function must be called again with Z_FINISH and more output space (updated- avail_out) but no more input data, until it returns with Z_STREAM_END or an- error. After deflate has returned Z_STREAM_END, the only possible operations- on the stream are deflateReset or deflateEnd.-- Z_FINISH can be used in the first deflate call after deflateInit if all the- compression is to be done in a single step. In order to complete in one- call, avail_out must be at least the value returned by deflateBound (see- below). Then deflate is guaranteed to return Z_STREAM_END. If not enough- output space is provided, deflate will not return Z_STREAM_END, and it must- be called again as described above.-- deflate() sets strm->adler to the Adler-32 checksum of all input read- so far (that is, total_in bytes). If a gzip stream is being generated, then- strm->adler will be the CRC-32 checksum of the input read so far. (See- deflateInit2 below.)-- deflate() may update strm->data_type if it can make a good guess about- the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is- considered binary. This field is only for information purposes and does not- affect the compression algorithm in any manner.-- deflate() returns Z_OK if some progress has been made (more input- processed or more output produced), Z_STREAM_END if all input has been- consumed and all output has been produced (only when flush is set to- Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example- if next_in or next_out was Z_NULL or the state was inadvertently written over- by the application), or Z_BUF_ERROR if no progress is possible (for example- avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and- deflate() can be called again with more input and more output space to- continue compressing.-*/---ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));-/*- All dynamically allocated data structures for this stream are freed.- This function discards any unprocessed input and does not flush any pending- output.-- deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the- stream state was inconsistent, Z_DATA_ERROR if the stream was freed- prematurely (some input or output was discarded). In the error case, msg- may be set but then points to a static string (which must not be- deallocated).-*/---/*-ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));-- Initializes the internal stream state for decompression. The fields- next_in, avail_in, zalloc, zfree and opaque must be initialized before by- the caller. In the current version of inflate, the provided input is not- read or consumed. The allocation of a sliding window will be deferred to- the first call of inflate (if the decompression does not complete on the- first call). If zalloc and zfree are set to Z_NULL, inflateInit updates- them to use default allocation functions.-- inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough- memory, Z_VERSION_ERROR if the zlib library version is incompatible with the- version assumed by the caller, or Z_STREAM_ERROR if the parameters are- invalid, such as a null pointer to the structure. msg is set to null if- there is no error message. inflateInit does not perform any decompression.- Actual decompression will be done by inflate(). So next_in, and avail_in,- next_out, and avail_out are unused and unchanged. The current- implementation of inflateInit() does not process any header information --- that is deferred until inflate() is called.-*/---ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));-/*- inflate decompresses as much data as possible, and stops when the input- buffer becomes empty or the output buffer becomes full. It may introduce- some output latency (reading input without producing any output) except when- forced to flush.-- The detailed semantics are as follows. inflate performs one or both of the- following actions:-- - Decompress more input starting at next_in and update next_in and avail_in- accordingly. If not all input can be processed (because there is not- enough room in the output buffer), then next_in and avail_in are updated- accordingly, and processing will resume at this point for the next call of- inflate().-- - Generate more output starting at next_out and update next_out and avail_out- accordingly. inflate() provides as much output as possible, until there is- no more input data or no more space in the output buffer (see below about- the flush parameter).-- Before the call of inflate(), the application should ensure that at least- one of the actions is possible, by providing more input and/or consuming more- output, and updating the next_* and avail_* values accordingly. If the- caller of inflate() does not provide both available input and available- output space, it is possible that there will be no progress made. The- application can consume the uncompressed output when it wants, for example- when the output buffer is full (avail_out == 0), or after each call of- inflate(). If inflate returns Z_OK and with zero avail_out, it must be- called again after making room in the output buffer because there might be- more output pending.-- The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,- Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much- output as possible to the output buffer. Z_BLOCK requests that inflate()- stop if and when it gets to the next deflate block boundary. When decoding- the zlib or gzip format, this will cause inflate() to return immediately- after the header and before the first block. When doing a raw inflate,- inflate() will go ahead and process the first block, and will return when it- gets to the end of that block, or when it runs out of data.-- The Z_BLOCK option assists in appending to or combining deflate streams.- To assist in this, on return inflate() always sets strm->data_type to the- number of unused bits in the last byte taken from strm->next_in, plus 64 if- inflate() is currently decoding the last block in the deflate stream, plus- 128 if inflate() returned immediately after decoding an end-of-block code or- decoding the complete header up to just before the first byte of the deflate- stream. The end-of-block will not be indicated until all of the uncompressed- data from that block has been written to strm->next_out. The number of- unused bits may in general be greater than seven, except when bit 7 of- data_type is set, in which case the number of unused bits will be less than- eight. data_type is set as noted here every time inflate() returns for all- flush options, and so can be used to determine the amount of currently- consumed input in bits.-- The Z_TREES option behaves as Z_BLOCK does, but it also returns when the- end of each deflate block header is reached, before any actual data in that- block is decoded. This allows the caller to determine the length of the- deflate block header for later use in random access within a deflate block.- 256 is added to the value of strm->data_type when inflate() returns- immediately after reaching the end of the deflate block header.-- inflate() should normally be called until it returns Z_STREAM_END or an- error. However if all decompression is to be performed in a single step (a- single call of inflate), the parameter flush should be set to Z_FINISH. In- this case all pending input is processed and all pending output is flushed;- avail_out must be large enough to hold all of the uncompressed data for the- operation to complete. (The size of the uncompressed data may have been- saved by the compressor for this purpose.) The use of Z_FINISH is not- required to perform an inflation in one step. However it may be used to- inform inflate that a faster approach can be used for the single inflate()- call. Z_FINISH also informs inflate to not maintain a sliding window if the- stream completes, which reduces inflate's memory footprint. If the stream- does not complete, either because not all of the stream is provided or not- enough output space is provided, then a sliding window will be allocated and- inflate() can be called again to continue the operation as if Z_NO_FLUSH had- been used.-- In this implementation, inflate() always flushes as much output as- possible to the output buffer, and always uses the faster approach on the- first call. So the effects of the flush parameter in this implementation are- on the return value of inflate() as noted below, when inflate() returns early- when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of- memory for a sliding window when Z_FINISH is used.-- If a preset dictionary is needed after this call (see inflateSetDictionary- below), inflate sets strm->adler to the Adler-32 checksum of the dictionary- chosen by the compressor and returns Z_NEED_DICT; otherwise it sets- strm->adler to the Adler-32 checksum of all output produced so far (that is,- total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described- below. At the end of the stream, inflate() checks that its computed Adler-32- checksum is equal to that saved by the compressor and returns Z_STREAM_END- only if the checksum is correct.-- inflate() can decompress and check either zlib-wrapped or gzip-wrapped- deflate data. The header type is detected automatically, if requested when- initializing with inflateInit2(). Any information contained in the gzip- header is not retained unless inflateGetHeader() is used. When processing- gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output- produced so far. The CRC-32 is checked against the gzip trailer, as is the- uncompressed length, modulo 2^32.-- inflate() returns Z_OK if some progress has been made (more input processed- or more output produced), Z_STREAM_END if the end of the compressed data has- been reached and all uncompressed output has been produced, Z_NEED_DICT if a- preset dictionary is needed at this point, Z_DATA_ERROR if the input data was- corrupted (input stream not conforming to the zlib format or incorrect check- value, in which case strm->msg points to a string with a more specific- error), Z_STREAM_ERROR if the stream structure was inconsistent (for example- next_in or next_out was Z_NULL, or the state was inadvertently written over- by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR- if no progress was possible or if there was not enough room in the output- buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and- inflate() can be called again with more input and more output space to- continue decompressing. If Z_DATA_ERROR is returned, the application may- then call inflateSync() to look for a good compression block if a partial- recovery of the data is to be attempted.-*/---ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));-/*- All dynamically allocated data structures for this stream are freed.- This function discards any unprocessed input and does not flush any pending- output.-- inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state- was inconsistent.-*/--- /* Advanced functions */--/*- The following functions are needed only in some special applications.-*/--/*-ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,- int level,- int method,- int windowBits,- int memLevel,- int strategy));-- This is another version of deflateInit with more compression options. The- fields next_in, zalloc, zfree and opaque must be initialized before by the- caller.-- The method parameter is the compression method. It must be Z_DEFLATED in- this version of the library.-- The windowBits parameter is the base two logarithm of the window size- (the size of the history buffer). It should be in the range 8..15 for this- version of the library. Larger values of this parameter result in better- compression at the expense of memory usage. The default value is 15 if- deflateInit is used instead.-- For the current implementation of deflate(), a windowBits value of 8 (a- window size of 256 bytes) is not supported. As a result, a request for 8- will result in 9 (a 512-byte window). In that case, providing 8 to- inflateInit2() will result in an error when the zlib header with 9 is- checked against the initialization of inflate(). The remedy is to not use 8- with deflateInit2() with this initialization, or at least in that case use 9- with inflateInit2().-- windowBits can also be -8..-15 for raw deflate. In this case, -windowBits- determines the window size. deflate() will then generate raw deflate data- with no zlib header or trailer, and will not compute a check value.-- windowBits can also be greater than 15 for optional gzip encoding. Add- 16 to windowBits to write a simple gzip header and trailer around the- compressed data instead of a zlib wrapper. The gzip header will have no- file name, no extra data, no comment, no modification time (set to zero), no- header crc, and the operating system will be set to the appropriate value,- if the operating system was determined at compile time. If a gzip stream is- being written, strm->adler is a CRC-32 instead of an Adler-32.-- For raw deflate or gzip encoding, a request for a 256-byte window is- rejected as invalid, since only the zlib header provides a means of- transmitting the window size to the decompressor.-- The memLevel parameter specifies how much memory should be allocated- for the internal compression state. memLevel=1 uses minimum memory but is- slow and reduces compression ratio; memLevel=9 uses maximum memory for- optimal speed. The default value is 8. See zconf.h for total memory usage- as a function of windowBits and memLevel.-- The strategy parameter is used to tune the compression algorithm. Use the- value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a- filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no- string match), or Z_RLE to limit match distances to one (run-length- encoding). Filtered data consists mostly of small values with a somewhat- random distribution. In this case, the compression algorithm is tuned to- compress them better. The effect of Z_FILTERED is to force more Huffman- coding and less string matching; it is somewhat intermediate between- Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as- fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The- strategy parameter only affects the compression ratio but not the- correctness of the compressed output even if it is not set appropriately.- Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler- decoder for special applications.-- deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough- memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid- method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is- incompatible with the version assumed by the caller (ZLIB_VERSION). msg is- set to null if there is no error message. deflateInit2 does not perform any- compression: this will be done by deflate().-*/--ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,- const Bytef *dictionary,- uInt dictLength));-/*- Initializes the compression dictionary from the given byte sequence- without producing any compressed output. When using the zlib format, this- function must be called immediately after deflateInit, deflateInit2 or- deflateReset, and before any call of deflate. When doing raw deflate, this- function must be called either before any call of deflate, or immediately- after the completion of a deflate block, i.e. after all input has been- consumed and all output has been delivered when using any of the flush- options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The- compressor and decompressor must use exactly the same dictionary (see- inflateSetDictionary).-- The dictionary should consist of strings (byte sequences) that are likely- to be encountered later in the data to be compressed, with the most commonly- used strings preferably put towards the end of the dictionary. Using a- dictionary is most useful when the data to be compressed is short and can be- predicted with good accuracy; the data can then be compressed better than- with the default empty dictionary.-- Depending on the size of the compression data structures selected by- deflateInit or deflateInit2, a part of the dictionary may in effect be- discarded, for example if the dictionary is larger than the window size- provided in deflateInit or deflateInit2. Thus the strings most likely to be- useful should be put at the end of the dictionary, not at the front. In- addition, the current implementation of deflate will use at most the window- size minus 262 bytes of the provided dictionary.-- Upon return of this function, strm->adler is set to the Adler-32 value- of the dictionary; the decompressor may later use this value to determine- which dictionary has been used by the compressor. (The Adler-32 value- applies to the whole dictionary even if only a subset of the dictionary is- actually used by the compressor.) If a raw deflate was requested, then the- Adler-32 value is not computed and strm->adler is not set.-- deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a- parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is- inconsistent (for example if deflate has already been called for this stream- or if not at a block boundary for raw deflate). deflateSetDictionary does- not perform any compression: this will be done by deflate().-*/--ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm,- Bytef *dictionary,- uInt *dictLength));-/*- Returns the sliding dictionary being maintained by deflate. dictLength is- set to the number of bytes in the dictionary, and that many bytes are copied- to dictionary. dictionary must have enough space, where 32768 bytes is- always enough. If deflateGetDictionary() is called with dictionary equal to- Z_NULL, then only the dictionary length is returned, and nothing is copied.- Similary, if dictLength is Z_NULL, then it is not set.-- deflateGetDictionary() may return a length less than the window size, even- when more than the window size in input has been provided. It may return up- to 258 bytes less in that case, due to how zlib's implementation of deflate- manages the sliding window and lookahead for matches, where matches can be- up to 258 bytes long. If the application needs the last window-size bytes of- input, then that would need to be saved by the application outside of zlib.-- deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the- stream state is inconsistent.-*/--ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,- z_streamp source));-/*- Sets the destination stream as a complete copy of the source stream.-- This function can be useful when several compression strategies will be- tried, for example when there are several ways of pre-processing the input- data with a filter. The streams that will be discarded should then be freed- by calling deflateEnd. Note that deflateCopy duplicates the internal- compression state which can be quite large, so this strategy is slow and can- consume lots of memory.-- deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not- enough memory, Z_STREAM_ERROR if the source stream state was inconsistent- (such as zalloc being Z_NULL). msg is left unchanged in both source and- destination.-*/--ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));-/*- This function is equivalent to deflateEnd followed by deflateInit, but- does not free and reallocate the internal compression state. The stream- will leave the compression level and any other attributes that may have been- set unchanged.-- deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source- stream state was inconsistent (such as zalloc or state being Z_NULL).-*/--ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,- int level,- int strategy));-/*- Dynamically update the compression level and compression strategy. The- interpretation of level and strategy is as in deflateInit2(). This can be- used to switch between compression and straight copy of the input data, or- to switch to a different kind of input data requiring a different strategy.- If the compression approach (which is a function of the level) or the- strategy is changed, and if any input has been consumed in a previous- deflate() call, then the input available so far is compressed with the old- level and strategy using deflate(strm, Z_BLOCK). There are three approaches- for the compression levels 0, 1..3, and 4..9 respectively. The new level- and strategy will take effect at the next call of deflate().-- If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does- not have enough output space to complete, then the parameter change will not- take effect. In this case, deflateParams() can be called again with the- same parameters and more output space to try again.-- In order to assure a change in the parameters on the first try, the- deflate stream should be flushed using deflate() with Z_BLOCK or other flush- request until strm.avail_out is not zero, before calling deflateParams().- Then no more input data should be provided before the deflateParams() call.- If this is done, the old level and strategy will be applied to the data- compressed before deflateParams(), and the new level and strategy will be- applied to the the data compressed after deflateParams().-- deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream- state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if- there was not enough output space to complete the compression of the- available input data before a change in the strategy or approach. Note that- in the case of a Z_BUF_ERROR, the parameters are not changed. A return- value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be- retried with more output space.-*/--ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,- int good_length,- int max_lazy,- int nice_length,- int max_chain));-/*- Fine tune deflate's internal compression parameters. This should only be- used by someone who understands the algorithm used by zlib's deflate for- searching for the best matching string, and even then only by the most- fanatic optimizer trying to squeeze out the last compressed bit for their- specific input data. Read the deflate.c source code for the meaning of the- max_lazy, good_length, nice_length, and max_chain parameters.-- deflateTune() can be called after deflateInit() or deflateInit2(), and- returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.- */--ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,- uLong sourceLen));-/*- deflateBound() returns an upper bound on the compressed size after- deflation of sourceLen bytes. It must be called after deflateInit() or- deflateInit2(), and after deflateSetHeader(), if used. This would be used- to allocate an output buffer for deflation in a single pass, and so would be- called before deflate(). If that first deflate() call is provided the- sourceLen input bytes, an output buffer allocated to the size returned by- deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed- to return Z_STREAM_END. Note that it is possible for the compressed size to- be larger than the value returned by deflateBound() if flush options other- than Z_FINISH or Z_NO_FLUSH are used.-*/--ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,- unsigned *pending,- int *bits));-/*- deflatePending() returns the number of bytes and bits of output that have- been generated, but not yet provided in the available output. The bytes not- provided would be due to the available output space having being consumed.- The number of bits of output not provided are between 0 and 7, where they- await more bits to join them in order to fill out a full byte. If pending- or bits are Z_NULL, then those values are not set.-- deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source- stream state was inconsistent.- */--ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,- int bits,- int value));-/*- deflatePrime() inserts bits in the deflate output stream. The intent- is that this function is used to start off the deflate output with the bits- leftover from a previous deflate stream when appending to it. As such, this- function can only be used for raw deflate, and must be used before the first- deflate() call after a deflateInit2() or deflateReset(). bits must be less- than or equal to 16, and that many of the least significant bits of value- will be inserted in the output.-- deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough- room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the- source stream state was inconsistent.-*/--ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,- gz_headerp head));-/*- deflateSetHeader() provides gzip header information for when a gzip- stream is requested by deflateInit2(). deflateSetHeader() may be called- after deflateInit2() or deflateReset() and before the first call of- deflate(). The text, time, os, extra field, name, and comment information- in the provided gz_header structure are written to the gzip header (xflag is- ignored -- the extra flags are set according to the compression level). The- caller must assure that, if not Z_NULL, name and comment are terminated with- a zero byte, and that if extra is not Z_NULL, that extra_len bytes are- available there. If hcrc is true, a gzip header crc is included. Note that- the current versions of the command-line version of gzip (up through version- 1.3.x) do not support header crc's, and will report that it is a "multi-part- gzip file" and give up.-- If deflateSetHeader is not used, the default gzip header has text false,- the time set to zero, and os set to 255, with no extra, name, or comment- fields. The gzip header is returned to the default state by deflateReset().-- deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source- stream state was inconsistent.-*/--/*-ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,- int windowBits));-- This is another version of inflateInit with an extra parameter. The- fields next_in, avail_in, zalloc, zfree and opaque must be initialized- before by the caller.-- The windowBits parameter is the base two logarithm of the maximum window- size (the size of the history buffer). It should be in the range 8..15 for- this version of the library. The default value is 15 if inflateInit is used- instead. windowBits must be greater than or equal to the windowBits value- provided to deflateInit2() while compressing, or it must be equal to 15 if- deflateInit2() was not used. If a compressed stream with a larger window- size is given as input, inflate() will return with the error code- Z_DATA_ERROR instead of trying to allocate a larger window.-- windowBits can also be zero to request that inflate use the window size in- the zlib header of the compressed stream.-- windowBits can also be -8..-15 for raw inflate. In this case, -windowBits- determines the window size. inflate() will then process raw deflate data,- not looking for a zlib or gzip header, not generating a check value, and not- looking for any check values for comparison at the end of the stream. This- is for use with other formats that use the deflate compressed data format- such as zip. Those formats provide their own check values. If a custom- format is developed using the raw deflate format for compressed data, it is- recommended that a check value such as an Adler-32 or a CRC-32 be applied to- the uncompressed data as is done in the zlib, gzip, and zip formats. For- most applications, the zlib format should be used as is. Note that comments- above on the use in deflateInit2() applies to the magnitude of windowBits.-- windowBits can also be greater than 15 for optional gzip decoding. Add- 32 to windowBits to enable zlib and gzip decoding with automatic header- detection, or add 16 to decode only the gzip format (the zlib format will- return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a- CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see- below), inflate() will not automatically decode concatenated gzip streams.- inflate() will return Z_STREAM_END at the end of the gzip stream. The state- would need to be reset to continue decoding a subsequent gzip stream.-- inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough- memory, Z_VERSION_ERROR if the zlib library version is incompatible with the- version assumed by the caller, or Z_STREAM_ERROR if the parameters are- invalid, such as a null pointer to the structure. msg is set to null if- there is no error message. inflateInit2 does not perform any decompression- apart from possibly reading the zlib header if present: actual decompression- will be done by inflate(). (So next_in and avail_in may be modified, but- next_out and avail_out are unused and unchanged.) The current implementation- of inflateInit2() does not process any header information -- that is- deferred until inflate() is called.-*/--ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,- const Bytef *dictionary,- uInt dictLength));-/*- Initializes the decompression dictionary from the given uncompressed byte- sequence. This function must be called immediately after a call of inflate,- if that call returned Z_NEED_DICT. The dictionary chosen by the compressor- can be determined from the Adler-32 value returned by that call of inflate.- The compressor and decompressor must use exactly the same dictionary (see- deflateSetDictionary). For raw inflate, this function can be called at any- time to set the dictionary. If the provided dictionary is smaller than the- window and there is already data in the window, then the provided dictionary- will amend what's there. The application must insure that the dictionary- that was used for compression is provided.-- inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a- parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is- inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the- expected one (incorrect Adler-32 value). inflateSetDictionary does not- perform any decompression: this will be done by subsequent calls of- inflate().-*/--ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,- Bytef *dictionary,- uInt *dictLength));-/*- Returns the sliding dictionary being maintained by inflate. dictLength is- set to the number of bytes in the dictionary, and that many bytes are copied- to dictionary. dictionary must have enough space, where 32768 bytes is- always enough. If inflateGetDictionary() is called with dictionary equal to- Z_NULL, then only the dictionary length is returned, and nothing is copied.- Similary, if dictLength is Z_NULL, then it is not set.-- inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the- stream state is inconsistent.-*/--ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));-/*- Skips invalid compressed data until a possible full flush point (see above- for the description of deflate with Z_FULL_FLUSH) can be found, or until all- available input is skipped. No output is provided.-- inflateSync searches for a 00 00 FF FF pattern in the compressed data.- All full flush points have this pattern, but not all occurrences of this- pattern are full flush points.-- inflateSync returns Z_OK if a possible full flush point has been found,- Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point- has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.- In the success case, the application may save the current current value of- total_in which indicates where valid compressed data was found. In the- error case, the application may repeatedly call inflateSync, providing more- input each time, until success or end of the input data.-*/--ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,- z_streamp source));-/*- Sets the destination stream as a complete copy of the source stream.-- This function can be useful when randomly accessing a large stream. The- first pass through the stream can periodically record the inflate state,- allowing restarting inflate at those points when randomly accessing the- stream.-- inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not- enough memory, Z_STREAM_ERROR if the source stream state was inconsistent- (such as zalloc being Z_NULL). msg is left unchanged in both source and- destination.-*/--ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));-/*- This function is equivalent to inflateEnd followed by inflateInit,- but does not free and reallocate the internal decompression state. The- stream will keep attributes that may have been set by inflateInit2.-- inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source- stream state was inconsistent (such as zalloc or state being Z_NULL).-*/--ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,- int windowBits));-/*- This function is the same as inflateReset, but it also permits changing- the wrap and window size requests. The windowBits parameter is interpreted- the same as it is for inflateInit2. If the window size is changed, then the- memory allocated for the window is freed, and the window will be reallocated- by inflate() if needed.-- inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source- stream state was inconsistent (such as zalloc or state being Z_NULL), or if- the windowBits parameter is invalid.-*/--ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,- int bits,- int value));-/*- This function inserts bits in the inflate input stream. The intent is- that this function is used to start inflating at a bit position in the- middle of a byte. The provided bits will be used before any bytes are used- from next_in. This function should only be used with raw inflate, and- should be used before the first inflate() call after inflateInit2() or- inflateReset(). bits must be less than or equal to 16, and that many of the- least significant bits of value will be inserted in the input.-- If bits is negative, then the input stream bit buffer is emptied. Then- inflatePrime() can be called again to put bits in the buffer. This is used- to clear out bits leftover after feeding inflate a block description prior- to feeding inflate codes.-- inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source- stream state was inconsistent.-*/--ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));-/*- This function returns two values, one in the lower 16 bits of the return- value, and the other in the remaining upper bits, obtained by shifting the- return value down 16 bits. If the upper value is -1 and the lower value is- zero, then inflate() is currently decoding information outside of a block.- If the upper value is -1 and the lower value is non-zero, then inflate is in- the middle of a stored block, with the lower value equaling the number of- bytes from the input remaining to copy. If the upper value is not -1, then- it is the number of bits back from the current bit position in the input of- the code (literal or length/distance pair) currently being processed. In- that case the lower value is the number of bytes already emitted for that- code.-- A code is being processed if inflate is waiting for more input to complete- decoding of the code, or if it has completed decoding but is waiting for- more output space to write the literal or match data.-- inflateMark() is used to mark locations in the input data for random- access, which may be at bit positions, and to note those cases where the- output of a code may span boundaries of random access blocks. The current- location in the input stream can be determined from avail_in and data_type- as noted in the description for the Z_BLOCK flush parameter for inflate.-- inflateMark returns the value noted above, or -65536 if the provided- source stream state was inconsistent.-*/--ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,- gz_headerp head));-/*- inflateGetHeader() requests that gzip header information be stored in the- provided gz_header structure. inflateGetHeader() may be called after- inflateInit2() or inflateReset(), and before the first call of inflate().- As inflate() processes the gzip stream, head->done is zero until the header- is completed, at which time head->done is set to one. If a zlib stream is- being decoded, then head->done is set to -1 to indicate that there will be- no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be- used to force inflate() to return immediately after header processing is- complete and before any actual data is decompressed.-- The text, time, xflags, and os fields are filled in with the gzip header- contents. hcrc is set to true if there is a header CRC. (The header CRC- was valid if done is set to one.) If extra is not Z_NULL, then extra_max- contains the maximum number of bytes to write to extra. Once done is true,- extra_len contains the actual extra field length, and extra contains the- extra field, or that field truncated if extra_max is less than extra_len.- If name is not Z_NULL, then up to name_max characters are written there,- terminated with a zero unless the length is greater than name_max. If- comment is not Z_NULL, then up to comm_max characters are written there,- terminated with a zero unless the length is greater than comm_max. When any- of extra, name, or comment are not Z_NULL and the respective field is not- present in the header, then that field is set to Z_NULL to signal its- absence. This allows the use of deflateSetHeader() with the returned- structure to duplicate the header. However if those fields are set to- allocated memory, then the application will need to save those pointers- elsewhere so that they can be eventually freed.-- If inflateGetHeader is not used, then the header information is simply- discarded. The header is always checked for validity, including the header- CRC if present. inflateReset() will reset the process to discard the header- information. The application would need to call inflateGetHeader() again to- retrieve the header from the next gzip stream.-- inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source- stream state was inconsistent.-*/--/*-ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,- unsigned char FAR *window));-- Initialize the internal stream state for decompression using inflateBack()- calls. The fields zalloc, zfree and opaque in strm must be initialized- before the call. If zalloc and zfree are Z_NULL, then the default library-- derived memory allocation routines are used. windowBits is the base two- logarithm of the window size, in the range 8..15. window is a caller- supplied buffer of that size. Except for special applications where it is- assured that deflate was used with small window sizes, windowBits must be 15- and a 32K byte window must be supplied to be able to decompress general- deflate streams.-- See inflateBack() for the usage of these routines.-- inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of- the parameters are invalid, Z_MEM_ERROR if the internal state could not be- allocated, or Z_VERSION_ERROR if the version of the library does not match- the version of the header file.-*/--typedef unsigned (*in_func) OF((void FAR *,- z_const unsigned char FAR * FAR *));-typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));--ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,- in_func in, void FAR *in_desc,- out_func out, void FAR *out_desc));-/*- inflateBack() does a raw inflate with a single call using a call-back- interface for input and output. This is potentially more efficient than- inflate() for file i/o applications, in that it avoids copying between the- output and the sliding window by simply making the window itself the output- buffer. inflate() can be faster on modern CPUs when used with large- buffers. inflateBack() trusts the application to not change the output- buffer passed by the output function, at least until inflateBack() returns.-- inflateBackInit() must be called first to allocate the internal state- and to initialize the state with the user-provided window buffer.- inflateBack() may then be used multiple times to inflate a complete, raw- deflate stream with each call. inflateBackEnd() is then called to free the- allocated state.-- A raw deflate stream is one with no zlib or gzip header or trailer.- This routine would normally be used in a utility that reads zip or gzip- files and writes out uncompressed files. The utility would decode the- header and process the trailer on its own, hence this routine expects only- the raw deflate stream to decompress. This is different from the default- behavior of inflate(), which expects a zlib header and trailer around the- deflate stream.-- inflateBack() uses two subroutines supplied by the caller that are then- called by inflateBack() for input and output. inflateBack() calls those- routines until it reads a complete deflate stream and writes out all of the- uncompressed data, or until it encounters an error. The function's- parameters and return types are defined above in the in_func and out_func- typedefs. inflateBack() will call in(in_desc, &buf) which should return the- number of bytes of provided input, and a pointer to that input in buf. If- there is no input available, in() must return zero -- buf is ignored in that- case -- and inflateBack() will return a buffer error. inflateBack() will- call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].- out() should return zero on success, or non-zero on failure. If out()- returns non-zero, inflateBack() will return with an error. Neither in() nor- out() are permitted to change the contents of the window provided to- inflateBackInit(), which is also the buffer that out() uses to write from.- The length written by out() will be at most the window size. Any non-zero- amount of input may be provided by in().-- For convenience, inflateBack() can be provided input on the first call by- setting strm->next_in and strm->avail_in. If that input is exhausted, then- in() will be called. Therefore strm->next_in must be initialized before- calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called- immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in- must also be initialized, and then if strm->avail_in is not zero, input will- initially be taken from strm->next_in[0 .. strm->avail_in - 1].-- The in_desc and out_desc parameters of inflateBack() is passed as the- first parameter of in() and out() respectively when they are called. These- descriptors can be optionally used to pass any information that the caller-- supplied in() and out() functions need to do their job.-- On return, inflateBack() will set strm->next_in and strm->avail_in to- pass back any unused input that was provided by the last in() call. The- return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR- if in() or out() returned an error, Z_DATA_ERROR if there was a format error- in the deflate stream (in which case strm->msg is set to indicate the nature- of the error), or Z_STREAM_ERROR if the stream was not properly initialized.- In the case of Z_BUF_ERROR, an input or output error can be distinguished- using strm->next_in which will be Z_NULL only if in() returned an error. If- strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning- non-zero. (in() will always be called before out(), so strm->next_in is- assured to be defined if out() returns non-zero.) Note that inflateBack()- cannot return Z_OK.-*/--ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));-/*- All memory allocated by inflateBackInit() is freed.-- inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream- state was inconsistent.-*/--ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));-/* Return flags indicating compile-time options.-- Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:- 1.0: size of uInt- 3.2: size of uLong- 5.4: size of voidpf (pointer)- 7.6: size of z_off_t-- Compiler, assembler, and debug options:- 8: ZLIB_DEBUG- 9: ASMV or ASMINF -- use ASM code- 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention- 11: 0 (reserved)-- One-time table building (smaller code, but not thread-safe if true):- 12: BUILDFIXED -- build static block decoding tables when needed- 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed- 14,15: 0 (reserved)-- Library content (indicates missing functionality):- 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking- deflate code when not needed)- 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect- and decode gzip streams (to avoid linking crc code)- 18-19: 0 (reserved)-- Operation variations (changes in library functionality):- 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate- 21: FASTEST -- deflate algorithm with only one, lowest compression level- 22,23: 0 (reserved)-- The sprintf variant used by gzprintf (zero is best):- 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format- 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!- 26: 0 = returns value, 1 = void -- 1 means inferred string length returned-- Remainder:- 27-31: 0 (reserved)- */--#ifndef Z_SOLO-- /* utility functions */--/*- The following utility functions are implemented on top of the basic- stream-oriented functions. To simplify the interface, some default options- are assumed (compression level and memory usage, standard memory allocation- functions). The source code of these utility functions can be modified if- you need special options.-*/--ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,- const Bytef *source, uLong sourceLen));-/*- Compresses the source buffer into the destination buffer. sourceLen is- the byte length of the source buffer. Upon entry, destLen is the total size- of the destination buffer, which must be at least the value returned by- compressBound(sourceLen). Upon exit, destLen is the actual size of the- compressed data. compress() is equivalent to compress2() with a level- parameter of Z_DEFAULT_COMPRESSION.-- compress returns Z_OK if success, Z_MEM_ERROR if there was not- enough memory, Z_BUF_ERROR if there was not enough room in the output- buffer.-*/--ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,- const Bytef *source, uLong sourceLen,- int level));-/*- Compresses the source buffer into the destination buffer. The level- parameter has the same meaning as in deflateInit. sourceLen is the byte- length of the source buffer. Upon entry, destLen is the total size of the- destination buffer, which must be at least the value returned by- compressBound(sourceLen). Upon exit, destLen is the actual size of the- compressed data.-- compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough- memory, Z_BUF_ERROR if there was not enough room in the output buffer,- Z_STREAM_ERROR if the level parameter is invalid.-*/--ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));-/*- compressBound() returns an upper bound on the compressed size after- compress() or compress2() on sourceLen bytes. It would be used before a- compress() or compress2() call to allocate the destination buffer.-*/--ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,- const Bytef *source, uLong sourceLen));-/*- Decompresses the source buffer into the destination buffer. sourceLen is- the byte length of the source buffer. Upon entry, destLen is the total size- of the destination buffer, which must be large enough to hold the entire- uncompressed data. (The size of the uncompressed data must have been saved- previously by the compressor and transmitted to the decompressor by some- mechanism outside the scope of this compression library.) Upon exit, destLen- is the actual size of the uncompressed data.-- uncompress returns Z_OK if success, Z_MEM_ERROR if there was not- enough memory, Z_BUF_ERROR if there was not enough room in the output- buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In- the case where there is not enough room, uncompress() will fill the output- buffer with the uncompressed data up to that point.-*/--ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen,- const Bytef *source, uLong *sourceLen));-/*- Same as uncompress, except that sourceLen is a pointer, where the- length of the source is *sourceLen. On return, *sourceLen is the number of- source bytes consumed.-*/-- /* gzip file access functions */--/*- This library supports reading and writing files in gzip (.gz) format with- an interface similar to that of stdio, using the functions that start with- "gz". The gzip format is different from the zlib format. gzip is a gzip- wrapper, documented in RFC 1952, wrapped around a deflate stream.-*/--typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */--/*-ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));-- Opens a gzip (.gz) file for reading or writing. The mode parameter is as- in fopen ("rb" or "wb") but can also include a compression level ("wb9") or- a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only- compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'- for fixed code compression as in "wb9F". (See the description of- deflateInit2 for more information about the strategy parameter.) 'T' will- request transparent writing or appending with no compression and not using- the gzip format.-- "a" can be used instead of "w" to request that the gzip stream that will- be written be appended to the file. "+" will result in an error, since- reading and writing to the same gzip file is not supported. The addition of- "x" when writing will create the file exclusively, which fails if the file- already exists. On systems that support it, the addition of "e" when- reading or writing will set the flag to close the file on an execve() call.-- These functions, as well as gzip, will read and decode a sequence of gzip- streams in a file. The append function of gzopen() can be used to create- such a file. (Also see gzflush() for another way to do this.) When- appending, gzopen does not test whether the file begins with a gzip stream,- nor does it look for the end of the gzip streams to begin appending. gzopen- will simply append a gzip stream to the existing file.-- gzopen can be used to read a file which is not in gzip format; in this- case gzread will directly read from the file without decompression. When- reading, this will be detected automatically by looking for the magic two-- byte gzip header.-- gzopen returns NULL if the file could not be opened, if there was- insufficient memory to allocate the gzFile state, or if an invalid mode was- specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).- errno can be checked to determine if the reason gzopen failed was that the- file could not be opened.-*/--ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));-/*- gzdopen associates a gzFile with the file descriptor fd. File descriptors- are obtained from calls like open, dup, creat, pipe or fileno (if the file- has been previously opened with fopen). The mode parameter is as in gzopen.-- The next call of gzclose on the returned gzFile will also close the file- descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor- fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,- mode);. The duplicated descriptor should be saved to avoid a leak, since- gzdopen does not close fd if it fails. If you are using fileno() to get the- file descriptor from a FILE *, then you will have to use dup() to avoid- double-close()ing the file descriptor. Both gzclose() and fclose() will- close the associated file descriptor, so they need to have different file- descriptors.-- gzdopen returns NULL if there was insufficient memory to allocate the- gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not- provided, or '+' was provided), or if fd is -1. The file descriptor is not- used until the next gz* read, write, seek, or close operation, so gzdopen- will not detect if fd is invalid (unless fd is -1).-*/--ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));-/*- Set the internal buffer size used by this library's functions. The- default buffer size is 8192 bytes. This function must be called after- gzopen() or gzdopen(), and before any other calls that read or write the- file. The buffer memory allocation is always deferred to the first read or- write. Three times that size in buffer space is allocated. A larger buffer- size of, for example, 64K or 128K bytes will noticeably increase the speed- of decompression (reading).-- The new buffer size also affects the maximum length for gzprintf().-- gzbuffer() returns 0 on success, or -1 on failure, such as being called- too late.-*/--ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));-/*- Dynamically update the compression level or strategy. See the description- of deflateInit2 for the meaning of these parameters. Previously provided- data is flushed before the parameter change.-- gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not- opened for writing, Z_ERRNO if there is an error writing the flushed data,- or Z_MEM_ERROR if there is a memory allocation error.-*/--ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));-/*- Reads the given number of uncompressed bytes from the compressed file. If- the input file is not in gzip format, gzread copies the given number of- bytes into the buffer directly from the file.-- After reaching the end of a gzip stream in the input, gzread will continue- to read, looking for another gzip stream. Any number of gzip streams may be- concatenated in the input file, and will all be decompressed by gzread().- If something other than a gzip stream is encountered after a gzip stream,- that remaining trailing garbage is ignored (and no error is returned).-- gzread can be used to read a gzip file that is being concurrently written.- Upon reaching the end of the input, gzread will return with the available- data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then- gzclearerr can be used to clear the end of file indicator in order to permit- gzread to be tried again. Z_OK indicates that a gzip stream was completed- on the last gzread. Z_BUF_ERROR indicates that the input file ended in the- middle of a gzip stream. Note that gzread does not return -1 in the event- of an incomplete gzip stream. This error is deferred until gzclose(), which- will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip- stream. Alternatively, gzerror can be used before gzclose to detect this- case.-- gzread returns the number of uncompressed bytes actually read, less than- len for end of file, or -1 for error. If len is too large to fit in an int,- then nothing is read, -1 is returned, and the error state is set to- Z_STREAM_ERROR.-*/--ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems,- gzFile file));-/*- Read up to nitems items of size size from file to buf, otherwise operating- as gzread() does. This duplicates the interface of stdio's fread(), with- size_t request and return types. If the library defines size_t, then- z_size_t is identical to size_t. If not, then z_size_t is an unsigned- integer type that can contain a pointer.-- gzfread() returns the number of full items read of size size, or zero if- the end of the file was reached and a full item could not be read, or if- there was an error. gzerror() must be consulted if zero is returned in- order to determine if there was an error. If the multiplication of size and- nitems overflows, i.e. the product does not fit in a z_size_t, then nothing- is read, zero is returned, and the error state is set to Z_STREAM_ERROR.-- In the event that the end of file is reached and only a partial item is- available at the end, i.e. the remaining uncompressed data length is not a- multiple of size, then the final partial item is nevetheless read into buf- and the end-of-file flag is set. The length of the partial item read is not- provided, but could be inferred from the result of gztell(). This behavior- is the same as the behavior of fread() implementations in common libraries,- but it prevents the direct use of gzfread() to read a concurrently written- file, reseting and retrying on end-of-file, when size is not 1.-*/--ZEXTERN int ZEXPORT gzwrite OF((gzFile file,- voidpc buf, unsigned len));-/*- Writes the given number of uncompressed bytes into the compressed file.- gzwrite returns the number of uncompressed bytes written or 0 in case of- error.-*/--ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size,- z_size_t nitems, gzFile file));-/*- gzfwrite() writes nitems items of size size from buf to file, duplicating- the interface of stdio's fwrite(), with size_t request and return types. If- the library defines size_t, then z_size_t is identical to size_t. If not,- then z_size_t is an unsigned integer type that can contain a pointer.-- gzfwrite() returns the number of full items written of size size, or zero- if there was an error. If the multiplication of size and nitems overflows,- i.e. the product does not fit in a z_size_t, then nothing is written, zero- is returned, and the error state is set to Z_STREAM_ERROR.-*/--ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));-/*- Converts, formats, and writes the arguments to the compressed file under- control of the format string, as in fprintf. gzprintf returns the number of- uncompressed bytes actually written, or a negative zlib error code in case- of error. The number of uncompressed bytes written is limited to 8191, or- one less than the buffer size given to gzbuffer(). The caller should assure- that this limit is not exceeded. If it is exceeded, then gzprintf() will- return an error (0) with nothing written. In this case, there may also be a- buffer overflow with unpredictable consequences, which is possible only if- zlib was compiled with the insecure functions sprintf() or vsprintf()- because the secure snprintf() or vsnprintf() functions were not available.- This can be determined using zlibCompileFlags().-*/--ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));-/*- Writes the given null-terminated string to the compressed file, excluding- the terminating null character.-- gzputs returns the number of characters written, or -1 in case of error.-*/--ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));-/*- Reads bytes from the compressed file until len-1 characters are read, or a- newline character is read and transferred to buf, or an end-of-file- condition is encountered. If any characters are read or if len == 1, the- string is terminated with a null character. If no characters are read due- to an end-of-file or len < 1, then the buffer is left untouched.-- gzgets returns buf which is a null-terminated string, or it returns NULL- for end-of-file or in case of error. If there was an error, the contents at- buf are indeterminate.-*/--ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));-/*- Writes c, converted to an unsigned char, into the compressed file. gzputc- returns the value that was written, or -1 in case of error.-*/--ZEXTERN int ZEXPORT gzgetc OF((gzFile file));-/*- Reads one byte from the compressed file. gzgetc returns this byte or -1- in case of end of file or error. This is implemented as a macro for speed.- As such, it does not do all of the checking the other functions do. I.e.- it does not check to see if file is NULL, nor whether the structure file- points to has been clobbered or not.-*/--ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));-/*- Push one character back onto the stream to be read as the first character- on the next read. At least one character of push-back is allowed.- gzungetc() returns the character pushed, or -1 on failure. gzungetc() will- fail if c is -1, and may fail if a character has been pushed but not read- yet. If gzungetc is used immediately after gzopen or gzdopen, at least the- output buffer size of pushed characters is allowed. (See gzbuffer above.)- The pushed character will be discarded if the stream is repositioned with- gzseek() or gzrewind().-*/--ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));-/*- Flushes all pending output into the compressed file. The parameter flush- is as in the deflate() function. The return value is the zlib error number- (see function gzerror below). gzflush is only permitted when writing.-- If the flush parameter is Z_FINISH, the remaining data is written and the- gzip stream is completed in the output. If gzwrite() is called again, a new- gzip stream will be started in the output. gzread() is able to read such- concatenated gzip streams.-- gzflush should be called only when strictly necessary because it will- degrade compression if called too often.-*/--/*-ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,- z_off_t offset, int whence));-- Sets the starting position for the next gzread or gzwrite on the given- compressed file. The offset represents a number of bytes in the- uncompressed data stream. The whence parameter is defined as in lseek(2);- the value SEEK_END is not supported.-- If the file is opened for reading, this function is emulated but can be- extremely slow. If the file is opened for writing, only forward seeks are- supported; gzseek then compresses a sequence of zeroes up to the new- starting position.-- gzseek returns the resulting offset location as measured in bytes from- the beginning of the uncompressed stream, or -1 in case of error, in- particular if the file is opened for writing and the new starting position- would be before the current position.-*/--ZEXTERN int ZEXPORT gzrewind OF((gzFile file));-/*- Rewinds the given file. This function is supported only for reading.-- gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)-*/--/*-ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));-- Returns the starting position for the next gzread or gzwrite on the given- compressed file. This position represents a number of bytes in the- uncompressed data stream, and is zero when starting, even if appending or- reading a gzip stream from the middle of a file using gzdopen().-- gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)-*/--/*-ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));-- Returns the current offset in the file being read or written. This offset- includes the count of bytes that precede the gzip stream, for example when- appending or when using gzdopen() for reading. When reading, the offset- does not include as yet unused buffered input. This information can be used- for a progress indicator. On error, gzoffset() returns -1.-*/--ZEXTERN int ZEXPORT gzeof OF((gzFile file));-/*- Returns true (1) if the end-of-file indicator has been set while reading,- false (0) otherwise. Note that the end-of-file indicator is set only if the- read tried to go past the end of the input, but came up short. Therefore,- just like feof(), gzeof() may return false even if there is no more data to- read, in the event that the last read request was for the exact number of- bytes remaining in the input file. This will happen if the input file size- is an exact multiple of the buffer size.-- If gzeof() returns true, then the read functions will return no more data,- unless the end-of-file indicator is reset by gzclearerr() and the input file- has grown since the previous end of file was detected.-*/--ZEXTERN int ZEXPORT gzdirect OF((gzFile file));-/*- Returns true (1) if file is being copied directly while reading, or false- (0) if file is a gzip stream being decompressed.-- If the input file is empty, gzdirect() will return true, since the input- does not contain a gzip stream.-- If gzdirect() is used immediately after gzopen() or gzdopen() it will- cause buffers to be allocated to allow reading the file to determine if it- is a gzip file. Therefore if gzbuffer() is used, it should be called before- gzdirect().-- When writing, gzdirect() returns true (1) if transparent writing was- requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note:- gzdirect() is not needed when writing. Transparent writing must be- explicitly requested, so the application already knows the answer. When- linking statically, using gzdirect() will include all of the zlib code for- gzip file reading and decompression, which may not be desired.)-*/--ZEXTERN int ZEXPORT gzclose OF((gzFile file));-/*- Flushes all pending output if necessary, closes the compressed file and- deallocates the (de)compression state. Note that once file is closed, you- cannot call gzerror with file, since its structures have been deallocated.- gzclose must not be called more than once on the same file, just as free- must not be called more than once on the same allocation.-- gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a- file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the- last read ended in the middle of a gzip stream, or Z_OK on success.-*/--ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));-ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));-/*- Same as gzclose(), but gzclose_r() is only for use when reading, and- gzclose_w() is only for use when writing or appending. The advantage to- using these instead of gzclose() is that they avoid linking in zlib- compression or decompression code that is not used when only reading or only- writing respectively. If gzclose() is used, then both compression and- decompression code will be included the application when linking to a static- zlib library.-*/--ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));-/*- Returns the error message for the last error which occurred on the given- compressed file. errnum is set to zlib error number. If an error occurred- in the file system and not in the compression library, errnum is set to- Z_ERRNO and the application may consult errno to get the exact error code.-- The application must not modify the returned string. Future calls to- this function may invalidate the previously returned string. If file is- closed, then the string previously returned by gzerror will no longer be- available.-- gzerror() should be used to distinguish errors from end-of-file for those- functions above that do not distinguish those cases in their return values.-*/--ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));-/*- Clears the error and end-of-file flags for file. This is analogous to the- clearerr() function in stdio. This is useful for continuing to read a gzip- file that is being written concurrently.-*/--#endif /* !Z_SOLO */-- /* checksum functions */--/*- These functions are not related to compression but are exported- anyway because they might be useful in applications using the compression- library.-*/--ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));-/*- Update a running Adler-32 checksum with the bytes buf[0..len-1] and- return the updated checksum. If buf is Z_NULL, this function returns the- required initial value for the checksum.-- An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed- much faster.-- Usage example:-- uLong adler = adler32(0L, Z_NULL, 0);-- while (read_buffer(buffer, length) != EOF) {- adler = adler32(adler, buffer, length);- }- if (adler != original_adler) error();-*/--ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf,- z_size_t len));-/*- Same as adler32(), but with a size_t length.-*/--/*-ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,- z_off_t len2));-- Combine two Adler-32 checksums into one. For two sequences of bytes, seq1- and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for- each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of- seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note- that the z_off_t type (like off_t) is a signed integer. If len2 is- negative, the result has no meaning or utility.-*/--ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));-/*- Update a running CRC-32 with the bytes buf[0..len-1] and return the- updated CRC-32. If buf is Z_NULL, this function returns the required- initial value for the crc. Pre- and post-conditioning (one's complement) is- performed within this function so it shouldn't be done by the application.-- Usage example:-- uLong crc = crc32(0L, Z_NULL, 0);-- while (read_buffer(buffer, length) != EOF) {- crc = crc32(crc, buffer, length);- }- if (crc != original_crc) error();-*/--ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf,- z_size_t len));-/*- Same as crc32(), but with a size_t length.-*/--/*-ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));-- Combine two CRC-32 check values into one. For two sequences of bytes,- seq1 and seq2 with lengths len1 and len2, CRC-32 check values were- calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32- check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and- len2.-*/--- /* various hacks, don't look :) */--/* deflateInit and inflateInit are macros to allow checking the zlib version- * and the compiler's view of z_stream:- */-ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,- const char *version, int stream_size));-ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,- const char *version, int stream_size));-ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,- int windowBits, int memLevel,- int strategy, const char *version,- int stream_size));-ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,- const char *version, int stream_size));-ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,- unsigned char FAR *window,- const char *version,- int stream_size));-#ifdef Z_PREFIX_SET-# define z_deflateInit(strm, level) \- deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))-# define z_inflateInit(strm) \- inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))-# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \- deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\- (strategy), ZLIB_VERSION, (int)sizeof(z_stream))-# define z_inflateInit2(strm, windowBits) \- inflateInit2_((strm), (windowBits), ZLIB_VERSION, \- (int)sizeof(z_stream))-# define z_inflateBackInit(strm, windowBits, window) \- inflateBackInit_((strm), (windowBits), (window), \- ZLIB_VERSION, (int)sizeof(z_stream))-#else-# define deflateInit(strm, level) \- deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))-# define inflateInit(strm) \- inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))-# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \- deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\- (strategy), ZLIB_VERSION, (int)sizeof(z_stream))-# define inflateInit2(strm, windowBits) \- inflateInit2_((strm), (windowBits), ZLIB_VERSION, \- (int)sizeof(z_stream))-# define inflateBackInit(strm, windowBits, window) \- inflateBackInit_((strm), (windowBits), (window), \- ZLIB_VERSION, (int)sizeof(z_stream))-#endif--#ifndef Z_SOLO--/* gzgetc() macro and its supporting function and exposed data structure. Note- * that the real internal state is much larger than the exposed structure.- * This abbreviated structure exposes just enough for the gzgetc() macro. The- * user should not mess with these exposed elements, since their names or- * behavior could change in the future, perhaps even capriciously. They can- * only be used by the gzgetc() macro. You have been warned.- */-struct gzFile_s {- unsigned have;- unsigned char *next;- z_off64_t pos;-};-ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */-#ifdef Z_PREFIX_SET-# undef z_gzgetc-# define z_gzgetc(g) \- ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))-#else-# define gzgetc(g) \- ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))-#endif--/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or- * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if- * both are true, the application gets the *64 functions, and the regular- * functions are changed to 64 bits) -- in case these are set on systems- * without large file support, _LFS64_LARGEFILE must also be true- */-#ifdef Z_LARGE64- ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));- ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));- ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));- ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));- ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));- ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));-#endif--#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)-# ifdef Z_PREFIX_SET-# define z_gzopen z_gzopen64-# define z_gzseek z_gzseek64-# define z_gztell z_gztell64-# define z_gzoffset z_gzoffset64-# define z_adler32_combine z_adler32_combine64-# define z_crc32_combine z_crc32_combine64-# else-# define gzopen gzopen64-# define gzseek gzseek64-# define gztell gztell64-# define gzoffset gzoffset64-# define adler32_combine adler32_combine64-# define crc32_combine crc32_combine64-# endif-# ifndef Z_LARGE64- ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));- ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));- ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));- ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));- ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));- ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));-# endif-#else- ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));- ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));- ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));- ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));- ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));- ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));-#endif--#else /* Z_SOLO */-- ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));- ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));--#endif /* !Z_SOLO */--/* undocumented functions */-ZEXTERN const char * ZEXPORT zError OF((int));-ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));-ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void));-ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));-ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int));-ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp));-ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp));-ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp));-#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO)-ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path,- const char *mode));-#endif-#if defined(STDC) || defined(Z_HAVE_STDARG_H)-# ifndef Z_SOLO-ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file,- const char *format,- va_list va));-# endif-#endif--#ifdef __cplusplus-}-#endif--#endif /* ZLIB_H */
− c/zlib/zutil.c
@@ -1,325 +0,0 @@-/* zutil.c -- target dependent utility functions for the compression library- * Copyright (C) 1995-2017 Jean-loup Gailly- * For conditions of distribution and use, see copyright notice in zlib.h- */--/* @(#) $Id$ */--#include "zutil.h"-#ifndef Z_SOLO-# include "gzguts.h"-#endif--z_const char * const z_errmsg[10] = {- (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */- (z_const char *)"stream end", /* Z_STREAM_END 1 */- (z_const char *)"", /* Z_OK 0 */- (z_const char *)"file error", /* Z_ERRNO (-1) */- (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */- (z_const char *)"data error", /* Z_DATA_ERROR (-3) */- (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */- (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */- (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */- (z_const char *)""-};---const char * ZEXPORT zlibVersion()-{- return ZLIB_VERSION;-}--uLong ZEXPORT zlibCompileFlags()-{- uLong flags;-- flags = 0;- switch ((int)(sizeof(uInt))) {- case 2: break;- case 4: flags += 1; break;- case 8: flags += 2; break;- default: flags += 3;- }- switch ((int)(sizeof(uLong))) {- case 2: break;- case 4: flags += 1 << 2; break;- case 8: flags += 2 << 2; break;- default: flags += 3 << 2;- }- switch ((int)(sizeof(voidpf))) {- case 2: break;- case 4: flags += 1 << 4; break;- case 8: flags += 2 << 4; break;- default: flags += 3 << 4;- }- switch ((int)(sizeof(z_off_t))) {- case 2: break;- case 4: flags += 1 << 6; break;- case 8: flags += 2 << 6; break;- default: flags += 3 << 6;- }-#ifdef ZLIB_DEBUG- flags += 1 << 8;-#endif-#if defined(ASMV) || defined(ASMINF)- flags += 1 << 9;-#endif-#ifdef ZLIB_WINAPI- flags += 1 << 10;-#endif-#ifdef BUILDFIXED- flags += 1 << 12;-#endif-#ifdef DYNAMIC_CRC_TABLE- flags += 1 << 13;-#endif-#ifdef NO_GZCOMPRESS- flags += 1L << 16;-#endif-#ifdef NO_GZIP- flags += 1L << 17;-#endif-#ifdef PKZIP_BUG_WORKAROUND- flags += 1L << 20;-#endif-#ifdef FASTEST- flags += 1L << 21;-#endif-#if defined(STDC) || defined(Z_HAVE_STDARG_H)-# ifdef NO_vsnprintf- flags += 1L << 25;-# ifdef HAS_vsprintf_void- flags += 1L << 26;-# endif-# else-# ifdef HAS_vsnprintf_void- flags += 1L << 26;-# endif-# endif-#else- flags += 1L << 24;-# ifdef NO_snprintf- flags += 1L << 25;-# ifdef HAS_sprintf_void- flags += 1L << 26;-# endif-# else-# ifdef HAS_snprintf_void- flags += 1L << 26;-# endif-# endif-#endif- return flags;-}--#ifdef ZLIB_DEBUG-#include <stdlib.h>-# ifndef verbose-# define verbose 0-# endif-int ZLIB_INTERNAL z_verbose = verbose;--void ZLIB_INTERNAL z_error (m)- char *m;-{- fprintf(stderr, "%s\n", m);- exit(1);-}-#endif--/* exported to allow conversion of error code to string for compress() and- * uncompress()- */-const char * ZEXPORT zError(err)- int err;-{- return ERR_MSG(err);-}--#if defined(_WIN32_WCE)- /* The Microsoft C Run-Time Library for Windows CE doesn't have- * errno. We define it as a global variable to simplify porting.- * Its value is always 0 and should not be used.- */- int errno = 0;-#endif--#ifndef HAVE_MEMCPY--void ZLIB_INTERNAL zmemcpy(dest, source, len)- Bytef* dest;- const Bytef* source;- uInt len;-{- if (len == 0) return;- do {- *dest++ = *source++; /* ??? to be unrolled */- } while (--len != 0);-}--int ZLIB_INTERNAL zmemcmp(s1, s2, len)- const Bytef* s1;- const Bytef* s2;- uInt len;-{- uInt j;-- for (j = 0; j < len; j++) {- if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;- }- return 0;-}--void ZLIB_INTERNAL zmemzero(dest, len)- Bytef* dest;- uInt len;-{- if (len == 0) return;- do {- *dest++ = 0; /* ??? to be unrolled */- } while (--len != 0);-}-#endif--#ifndef Z_SOLO--#ifdef SYS16BIT--#ifdef __TURBOC__-/* Turbo C in 16-bit mode */--# define MY_ZCALLOC--/* Turbo C malloc() does not allow dynamic allocation of 64K bytes- * and farmalloc(64K) returns a pointer with an offset of 8, so we- * must fix the pointer. Warning: the pointer must be put back to its- * original form in order to free it, use zcfree().- */--#define MAX_PTR 10-/* 10*64K = 640K */--local int next_ptr = 0;--typedef struct ptr_table_s {- voidpf org_ptr;- voidpf new_ptr;-} ptr_table;--local ptr_table table[MAX_PTR];-/* This table is used to remember the original form of pointers- * to large buffers (64K). Such pointers are normalized with a zero offset.- * Since MSDOS is not a preemptive multitasking OS, this table is not- * protected from concurrent access. This hack doesn't work anyway on- * a protected system like OS/2. Use Microsoft C instead.- */--voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)-{- voidpf buf;- ulg bsize = (ulg)items*size;-- (void)opaque;-- /* If we allocate less than 65520 bytes, we assume that farmalloc- * will return a usable pointer which doesn't have to be normalized.- */- if (bsize < 65520L) {- buf = farmalloc(bsize);- if (*(ush*)&buf != 0) return buf;- } else {- buf = farmalloc(bsize + 16L);- }- if (buf == NULL || next_ptr >= MAX_PTR) return NULL;- table[next_ptr].org_ptr = buf;-- /* Normalize the pointer to seg:0 */- *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;- *(ush*)&buf = 0;- table[next_ptr++].new_ptr = buf;- return buf;-}--void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)-{- int n;-- (void)opaque;-- if (*(ush*)&ptr != 0) { /* object < 64K */- farfree(ptr);- return;- }- /* Find the original pointer */- for (n = 0; n < next_ptr; n++) {- if (ptr != table[n].new_ptr) continue;-- farfree(table[n].org_ptr);- while (++n < next_ptr) {- table[n-1] = table[n];- }- next_ptr--;- return;- }- Assert(0, "zcfree: ptr not found");-}--#endif /* __TURBOC__ */---#ifdef M_I86-/* Microsoft C in 16-bit mode */--# define MY_ZCALLOC--#if (!defined(_MSC_VER) || (_MSC_VER <= 600))-# define _halloc halloc-# define _hfree hfree-#endif--voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)-{- (void)opaque;- return _halloc((long)items, size);-}--void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)-{- (void)opaque;- _hfree(ptr);-}--#endif /* M_I86 */--#endif /* SYS16BIT */---#ifndef MY_ZCALLOC /* Any system without a special alloc function */--#ifndef STDC-extern voidp malloc OF((uInt size));-extern voidp calloc OF((uInt items, uInt size));-extern void free OF((voidpf ptr));-#endif--voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)- voidpf opaque;- unsigned items;- unsigned size;-{- (void)opaque;- return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :- (voidpf)calloc(items, size);-}--void ZLIB_INTERNAL zcfree (opaque, ptr)- voidpf opaque;- voidpf ptr;-{- (void)opaque;- free(ptr);-}--#endif /* MY_ZCALLOC */--#endif /* !Z_SOLO */
− c/zlib/zutil.h
@@ -1,271 +0,0 @@-/* zutil.h -- internal interface and configuration of the compression library- * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler- * For conditions of distribution and use, see copyright notice in zlib.h- */--/* WARNING: this file should *not* be used by applications. It is- part of the implementation of the compression library and is- subject to change. Applications should only use zlib.h.- */--/* @(#) $Id$ */--#ifndef ZUTIL_H-#define ZUTIL_H--#ifdef HAVE_HIDDEN-# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))-#else-# define ZLIB_INTERNAL-#endif--#include "zlib.h"--#if defined(STDC) && !defined(Z_SOLO)-# if !(defined(_WIN32_WCE) && defined(_MSC_VER))-# include <stddef.h>-# endif-# include <string.h>-# include <stdlib.h>-#endif--#ifdef Z_SOLO- typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */-#endif--#ifndef local-# define local static-#endif-/* since "static" is used to mean two completely different things in C, we- define "local" for the non-static meaning of "static", for readability- (compile with -Dlocal if your debugger can't find static symbols) */--typedef unsigned char uch;-typedef uch FAR uchf;-typedef unsigned short ush;-typedef ush FAR ushf;-typedef unsigned long ulg;--extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */-/* (size given to avoid silly warnings with Visual C++) */--#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]--#define ERR_RETURN(strm,err) \- return (strm->msg = ERR_MSG(err), (err))-/* To be used only when the state is known to be valid */-- /* common constants */--#ifndef DEF_WBITS-# define DEF_WBITS MAX_WBITS-#endif-/* default windowBits for decompression. MAX_WBITS is for compression only */--#if MAX_MEM_LEVEL >= 8-# define DEF_MEM_LEVEL 8-#else-# define DEF_MEM_LEVEL MAX_MEM_LEVEL-#endif-/* default memLevel */--#define STORED_BLOCK 0-#define STATIC_TREES 1-#define DYN_TREES 2-/* The three kinds of block type */--#define MIN_MATCH 3-#define MAX_MATCH 258-/* The minimum and maximum match lengths */--#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */-- /* target dependencies */--#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))-# define OS_CODE 0x00-# ifndef Z_SOLO-# if defined(__TURBOC__) || defined(__BORLANDC__)-# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))- /* Allow compilation with ANSI keywords only enabled */- void _Cdecl farfree( void *block );- void *_Cdecl farmalloc( unsigned long nbytes );-# else-# include <alloc.h>-# endif-# else /* MSC or DJGPP */-# include <malloc.h>-# endif-# endif-#endif--#ifdef AMIGA-# define OS_CODE 1-#endif--#if defined(VAXC) || defined(VMS)-# define OS_CODE 2-# define F_OPEN(name, mode) \- fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")-#endif--#ifdef __370__-# if __TARGET_LIB__ < 0x20000000-# define OS_CODE 4-# elif __TARGET_LIB__ < 0x40000000-# define OS_CODE 11-# else-# define OS_CODE 8-# endif-#endif--#if defined(ATARI) || defined(atarist)-# define OS_CODE 5-#endif--#ifdef OS2-# define OS_CODE 6-# if defined(M_I86) && !defined(Z_SOLO)-# include <malloc.h>-# endif-#endif--#if defined(MACOS) || defined(TARGET_OS_MAC)-# define OS_CODE 7-# ifndef Z_SOLO-# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os-# include <unix.h> /* for fdopen */-# else-# ifndef fdopen-# define fdopen(fd,mode) NULL /* No fdopen() */-# endif-# endif-# endif-#endif--#ifdef __acorn-# define OS_CODE 13-#endif--#if defined(WIN32) && !defined(__CYGWIN__)-# define OS_CODE 10-#endif--#ifdef _BEOS_-# define OS_CODE 16-#endif--#ifdef __TOS_OS400__-# define OS_CODE 18-#endif--#ifdef __APPLE__-# define OS_CODE 19-#endif--#if defined(_BEOS_) || defined(RISCOS)-# define fdopen(fd,mode) NULL /* No fdopen() */-#endif--#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX-# if defined(_WIN32_WCE)-# define fdopen(fd,mode) NULL /* No fdopen() */-# ifndef _PTRDIFF_T_DEFINED- typedef int ptrdiff_t;-# define _PTRDIFF_T_DEFINED-# endif-# else-# define fdopen(fd,type) _fdopen(fd,type)-# endif-#endif--#if defined(__BORLANDC__) && !defined(MSDOS)- #pragma warn -8004- #pragma warn -8008- #pragma warn -8066-#endif--/* provide prototypes for these when building zlib without LFS */-#if !defined(_WIN32) && \- (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)- ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));- ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));-#endif-- /* common defaults */--#ifndef OS_CODE-# define OS_CODE 3 /* assume Unix */-#endif--#ifndef F_OPEN-# define F_OPEN(name, mode) fopen((name), (mode))-#endif-- /* functions */--#if defined(pyr) || defined(Z_SOLO)-# define NO_MEMCPY-#endif-#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)- /* Use our own functions for small and medium model with MSC <= 5.0.- * You may have to use the same strategy for Borland C (untested).- * The __SC__ check is for Symantec.- */-# define NO_MEMCPY-#endif-#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)-# define HAVE_MEMCPY-#endif-#ifdef HAVE_MEMCPY-# ifdef SMALL_MEDIUM /* MSDOS small or medium model */-# define zmemcpy _fmemcpy-# define zmemcmp _fmemcmp-# define zmemzero(dest, len) _fmemset(dest, 0, len)-# else-# define zmemcpy memcpy-# define zmemcmp memcmp-# define zmemzero(dest, len) memset(dest, 0, len)-# endif-#else- void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));- int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));- void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));-#endif--/* Diagnostic functions */-#ifdef ZLIB_DEBUG-# include <stdio.h>- extern int ZLIB_INTERNAL z_verbose;- extern void ZLIB_INTERNAL z_error OF((char *m));-# define Assert(cond,msg) {if(!(cond)) z_error(msg);}-# define Trace(x) {if (z_verbose>=0) fprintf x ;}-# define Tracev(x) {if (z_verbose>0) fprintf x ;}-# define Tracevv(x) {if (z_verbose>1) fprintf x ;}-# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}-# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}-#else-# define Assert(cond,msg)-# define Trace(x)-# define Tracev(x)-# define Tracevv(x)-# define Tracec(c,x)-# define Tracecv(c,x)-#endif--#ifndef Z_SOLO- voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,- unsigned size));- void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));-#endif--#define ZALLOC(strm, items, size) \- (*((strm)->zalloc))((strm)->opaque, (items), (size))-#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))-#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}--/* Reverse the bytes in a 32-bit value */-#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \- (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))--#endif /* ZUTIL_H */
libarchive.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: libarchive-version: 3.0.4.2+version: 3.0.5.0 license: BSD-3-Clause license-file: LICENSE copyright: Copyright: (c) 2018-2020 Vanessa McHale@@ -15,14 +15,6 @@ category: Codec build-type: Custom extra-source-files:- ./c/autoconf-darwin/config.h- ./c/autoconf-linux/config.h- ./c/autoconf-freebsd/config.h- ./c/autoconf-windows/config.h- ./c/*.c- ./c/*.h- ./c/zlib/*.c- ./c/zlib/*.h test/data/aarch64-linux-dist.tar extra-doc-files:@@ -114,179 +106,15 @@ if impl(ghc >=8.10) ghc-options: -Wunused-packages - if !flag(system-libarchive)- include-dirs: c-- if !flag(system-libarchive)- cc-options: -std=c11 -DHAVE_CONFIG_H- c-sources:- ./c/archive_acl.c- ./c/archive_blake2sp_ref.c- ./c/archive_blake2s_ref.c- ./c/archive_check_magic.c- ./c/archive_cmdline.c- ./c/archive_cryptor.c- ./c/archive_digest.c- ./c/archive_disk_acl_darwin.c- ./c/archive_disk_acl_freebsd.c- ./c/archive_disk_acl_linux.c- ./c/archive_disk_acl_sunos.c- ./c/archive_entry.c- ./c/archive_entry_copy_bhfi.c- ./c/archive_entry_copy_stat.c- ./c/archive_entry_link_resolver.c- ./c/archive_entry_sparse.c- ./c/archive_entry_stat.c- ./c/archive_entry_strmode.c- ./c/archive_entry_xattr.c- ./c/archive_getdate.c- ./c/archive_hmac.c- ./c/archive_match.c- ./c/archive_options.c- ./c/archive_pack_dev.c- ./c/archive_pathmatch.c- ./c/archive_ppmd7.c- ./c/archive_ppmd8.c- ./c/archive_random.c- ./c/archive_rb.c- ./c/archive_read_add_passphrase.c- ./c/archive_read_append_filter.c- ./c/archive_read.c- ./c/archive_read_data_into_fd.c- ./c/archive_read_disk_entry_from_file.c- ./c/archive_read_disk_posix.c- ./c/archive_read_disk_set_standard_lookup.c- ./c/archive_read_disk_windows.c- ./c/archive_read_extract2.c- ./c/archive_read_extract.c- ./c/archive_read_open_fd.c- ./c/archive_read_open_file.c- ./c/archive_read_open_filename.c- ./c/archive_read_open_memory.c- ./c/archive_read_set_format.c- ./c/archive_read_set_options.c- ./c/archive_read_support_filter_all.c- ./c/archive_read_support_filter_by_code.c- ./c/archive_read_support_filter_bzip2.c- ./c/archive_read_support_filter_compress.c- ./c/archive_read_support_filter_grzip.c- ./c/archive_read_support_filter_gzip.c- ./c/archive_read_support_filter_lrzip.c- ./c/archive_read_support_filter_lz4.c- ./c/archive_read_support_filter_lzop.c- ./c/archive_read_support_filter_none.c- ./c/archive_read_support_filter_program.c- ./c/archive_read_support_filter_rpm.c- ./c/archive_read_support_filter_uu.c- ./c/archive_read_support_filter_xz.c- ./c/archive_read_support_filter_zstd.c- ./c/archive_read_support_format_7zip.c- ./c/archive_read_support_format_all.c- ./c/archive_read_support_format_ar.c- ./c/archive_read_support_format_by_code.c- ./c/archive_read_support_format_cab.c- ./c/archive_read_support_format_cpio.c- ./c/archive_read_support_format_empty.c- ./c/archive_read_support_format_iso9660.c- ./c/archive_read_support_format_lha.c- ./c/archive_read_support_format_mtree.c- ./c/archive_read_support_format_rar5.c- ./c/archive_read_support_format_rar.c- ./c/archive_read_support_format_raw.c- ./c/archive_read_support_format_tar.c- ./c/archive_read_support_format_warc.c- ./c/archive_read_support_format_xar.c- ./c/archive_read_support_format_zip.c- ./c/archive_string.c- ./c/archive_string_sprintf.c- ./c/archive_util.c- ./c/archive_version_details.c- ./c/archive_virtual.c- ./c/archive_windows.c- ./c/archive_write_add_filter_b64encode.c- ./c/archive_write_add_filter_by_name.c- ./c/archive_write_add_filter_bzip2.c- ./c/archive_write_add_filter.c- ./c/archive_write_add_filter_compress.c- ./c/archive_write_add_filter_grzip.c- ./c/archive_write_add_filter_gzip.c- ./c/archive_write_add_filter_lrzip.c- ./c/archive_write_add_filter_lz4.c- ./c/archive_write_add_filter_lzop.c- ./c/archive_write_add_filter_none.c- ./c/archive_write_add_filter_program.c- ./c/archive_write_add_filter_uuencode.c- ./c/archive_write_add_filter_xz.c- ./c/archive_write_add_filter_zstd.c- ./c/archive_write.c- ./c/archive_write_disk_posix.c- ./c/archive_write_disk_set_standard_lookup.c- ./c/archive_write_disk_windows.c- ./c/archive_write_open_fd.c- ./c/archive_write_open_file.c- ./c/archive_write_open_filename.c- ./c/archive_write_open_memory.c- ./c/archive_write_set_format_7zip.c- ./c/archive_write_set_format_ar.c- ./c/archive_write_set_format_by_name.c- ./c/archive_write_set_format.c- ./c/archive_write_set_format_cpio.c- ./c/archive_write_set_format_cpio_binary.c- ./c/archive_write_set_format_cpio_newc.c- ./c/archive_write_set_format_cpio_odc.c- ./c/archive_write_set_format_filter_by_ext.c- ./c/archive_write_set_format_gnutar.c- ./c/archive_write_set_format_iso9660.c- ./c/archive_write_set_format_mtree.c- ./c/archive_write_set_format_pax.c- ./c/archive_write_set_format_raw.c- ./c/archive_write_set_format_shar.c- ./c/archive_write_set_format_ustar.c- ./c/archive_write_set_format_v7tar.c- ./c/archive_write_set_format_warc.c- ./c/archive_write_set_format_xar.c- ./c/archive_write_set_format_zip.c- ./c/archive_write_set_options.c- ./c/archive_write_set_passphrase.c- ./c/filter_fork_posix.c- ./c/filter_fork_windows.c- ./c/xxhash.c- ./c/zlib/adler32.c- ./c/zlib/crc32.c- ./c/zlib/deflate.c- ./c/zlib/inffast.c- ./c/zlib/zutil.c- ./c/zlib/compress.c- ./c/zlib/infback.c- ./c/zlib/inflate.c- ./c/zlib/inftrees.c- ./c/zlib/trees.c- ./c/zlib/uncompr.c-- include-dirs: c/ c/zlib/-- if os(osx)- include-dirs: c/autoconf-darwin-- else- if os(linux)- include-dirs: c/autoconf-linux-- else- if os(freebsd)- include-dirs: c/autoconf-freebsd-- else- if os(windows)- include-dirs: c/autoconf-windows-- else- buildable: False- build-depends: unbuildable <0-+ if flag(system-libarchive)+ pkgconfig-depends: libarchive >=3.8.2 && <4.0 else- pkgconfig-depends: libarchive (==3.6.0 || >3.6.0) && <4.0+ build-depends: libarchive-clib >=3.8.2 && <4.0 + includes:+ archive.h+ archive_entry.h+ executable archive main-is: Main.hs hs-source-dirs: exe@@ -302,7 +130,7 @@ libarchive, lzma-static, time,- zlib ^>=0.6.2.2+ zlib ^>=0.7.1.1 if flag(no-exe) buildable: False@@ -333,6 +161,10 @@ composition-prelude >=2.0.5.0, pathological-bytestrings + if os(windows)+ build-depends:+ hspec-core+ if flag(low-memory) cpp-options: -DLOW_MEMORY @@ -361,7 +193,7 @@ libarchive, criterion, bytestring,- tar,+ tar >=0.6.0.0, temporary if impl(ghc >=8.0)
src/Codec/Archive/Foreign/Archive.chs view
@@ -12,6 +12,23 @@ , archiveBzlibVersion , archiveLiblz4Version , archiveLibzstdVersion+ , archiveLiblzo2Version+ , archiveLibexpatVersion+ , archiveLibbsdxmlVersion+ , archiveLibxml2Version+ , archiveMbedtlsVersion+ , archiveNettleVersion+ , archiveOpensslVersion+ , archiveLibmdVersion+ , archiveCommoncryptoVersion+ , archiveCngVersion+ , archiveWincryptVersion+ , archiveLibrichaclVersion+ , archiveLibaclVersion+ , archiveLibattrVersion+ , archiveLibiconvVersion+ , archiveLibpcreVersion+ , archiveLibpcre2Version -- * Miscellany , archiveErrorString , archiveFormatName@@ -162,6 +179,10 @@ , archiveWriteSetFormatFilterByExtDef , archiveWriteZipSetCompressionDeflate , archiveWriteZipSetCompressionStore+ , archiveWriteZipSetCompressionLzma+ , archiveWriteZipSetCompressionXz+ , archiveWriteZipSetCompressionBzip2+ , archiveWriteZipSetCompressionZstd , archiveWriteOpen2 , archiveWriteOpenFd , archiveWriteOpenFilenameW@@ -412,6 +433,23 @@ {# fun archive_bzlib_version as ^ {} -> `CString' #} {# fun archive_liblz4_version as ^ {} -> `CString' #} {# fun archive_libzstd_version as ^ {} -> `CString' #}+{# fun archive_liblzo2_version as ^ {} -> `CString' #}+{# fun archive_libexpat_version as ^ {} -> `CString' #}+{# fun archive_libbsdxml_version as ^ {} -> `CString' #}+{# fun archive_libxml2_version as ^ {} -> `CString' #}+{# fun archive_mbedtls_version as ^ {} -> `CString' #}+{# fun archive_nettle_version as ^ {} -> `CString' #}+{# fun archive_openssl_version as ^ {} -> `CString' #}+{# fun archive_libmd_version as ^ {} -> `CString' #}+{# fun archive_commoncrypto_version as ^ {} -> `CString' #}+{# fun archive_cng_version as ^ {} -> `CString' #}+{# fun archive_wincrypt_version as ^ {} -> `CString' #}+{# fun archive_librichacl_version as ^ {} -> `CString' #}+{# fun archive_libacl_version as ^ {} -> `CString' #}+{# fun archive_libattr_version as ^ {} -> `CString' #}+{# fun archive_libiconv_version as ^ {} -> `CString' #}+{# fun archive_libpcre_version as ^ {} -> `CString' #}+{# fun archive_libpcre2_version as ^ {} -> `CString' #} {# fun archive_error_string as ^ { `ArchivePtr' } -> `CString' #} {# fun archive_format_name as ^ { `ArchivePtr' } -> `CString' #}@@ -565,6 +603,10 @@ {# fun archive_write_set_format_filter_by_ext_def as ^ { `ArchivePtr', `CString', `CString' } -> `ArchiveResult' #} {# fun archive_write_zip_set_compression_deflate as ^ { `ArchivePtr' } -> `ArchiveResult' #} {# fun archive_write_zip_set_compression_store as ^ { `ArchivePtr' } -> `ArchiveResult' #}+{# fun archive_write_zip_set_compression_lzma as ^ { `ArchivePtr' } -> `ArchiveResult' #}+{# fun archive_write_zip_set_compression_xz as ^ { `ArchivePtr' } -> `ArchiveResult' #}+{# fun archive_write_zip_set_compression_bzip2 as ^ { `ArchivePtr' } -> `ArchiveResult' #}+{# fun archive_write_zip_set_compression_zstd as ^ { `ArchivePtr' } -> `ArchiveResult' #} {# fun archive_write_open as ^ { `ArchivePtr' , castPtr `Ptr a' , castFunPtr `FunPtr (ArchiveOpenCallbackRaw a)'