Merge branch 'libarchive-upstream' into update-libarchive

Add Utilities/cmlibarchive using upstream libarchive 3.0.0-r3950
snapshot.
This commit is contained in:
Brad King 2011-12-20 11:50:51 -05:00
commit 3e5a80f063
164 changed files with 100292 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
The libarchive distribution as a whole is Copyright by Tim Kientzle
and is subject to the copyright notice reproduced at the bottom of
this file.
Each individual file in this distribution should have a clear
copyright/licensing statement at the beginning of the file. If any do
not, please let me know and I will rectify it. The following is
intended to summarize the copyright status of the individual files;
the actual statements in the files are controlling.
* Except as listed below, all C sources (including .c and .h files)
and documentation files are subject to the copyright notice reproduced
at the bottom of this file.
* The following source files are also subject in whole or in part to
a 3-clause UC Regents copyright; please read the individual source
files for details:
libarchive/archive_entry.c
libarchive/archive_read_support_filter_compress.c
libarchive/archive_write_set_filter_compress.c
libarchive/mtree.5
tar/matching.c
* The following source files are in the public domain:
tar/getdate.c
* The build files---including Makefiles, configure scripts,
and auxiliary scripts used as part of the compile process---have
widely varying licensing terms. Please check individual files before
distributing them to see if those restrictions apply to you.
I intend for all new source code to use the license below and hope over
time to replace code with other licenses with new implementations that
do use the license below. The varying licensing of the build scripts
seems to be an unavoidable mess.
Copyright (c) 2003-2009 <author(s)>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that 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.

View File

@ -0,0 +1,11 @@
# TODO: This file should be moved into the build/cmake directory...
# The libarchive CDash page appears at
# http://my.cdash.org/index.php?project=libarchive
set(CTEST_PROJECT_NAME "libarchive")
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=libarchive")
set(CTEST_DROP_SITE_CDASH TRUE)

View File

@ -0,0 +1,107 @@
# - Macro approximating the CMake 2.8 ADD_TEST(NAME) signature.
# ADD_TEST_28(NAME <name> COMMAND <command> [arg1 [arg2 ...]])
# <name> - The name of the test
# <command> - The test executable
# [argN...] - Arguments to the test executable
# This macro approximates the ADD_TEST(NAME) signature provided in
# CMake 2.8 but works with CMake 2.6 too. See CMake 2.8 documentation
# of ADD_TEST()for details.
#
# This macro automatically replaces a <command> that names an
# executable target with the target location. A generator expression
# of the form "$<TARGET_FILE:tgt>" is supported in both the command
# and arguments of the test. Howerver, this macro only works for
# targets without per-config output name properties set.
#
# Example usage:
# add_test(NAME mytest COMMAND testDriver --exe $<TARGET_FILE:myexe>)
# This creates a test "mytest" whose command runs a testDriver tool
# passing the full path to the executable file produced by target
# "myexe".
#=============================================================================
# Copyright 2009 Kitware, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that 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.
#=============================================================================
CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3)
# CMake 2.8 supports ADD_TEST(NAME) natively.
IF(NOT "${CMAKE_VERSION}" VERSION_LESS "2.8")
MACRO(ADD_TEST_28)
ADD_TEST(${ARGV})
ENDMACRO()
RETURN()
ENDIF()
# Simulate ADD_TEST(NAME) signature from CMake 2.8.
MACRO(ADD_TEST_28 NAME name COMMAND command)
# Enforce the signature.
IF(NOT "x${NAME}" STREQUAL "xNAME")
MESSAGE(FATAL_ERROR "First ADD_TEST_28 argument must be \"NAME\"")
ENDIF()
IF(NOT "x${COMMAND}" STREQUAL "xCOMMAND")
MESSAGE(FATAL_ERROR "Third ADD_TEST_28 argument must be \"COMMAND\"")
ENDIF()
# Perform "COMMAND myexe ..." substitution.
SET(cmd "${command}")
IF(TARGET "${cmd}")
_ADD_TEST_28_GET_EXE(${cmd} cmd)
ENDIF()
# Perform "COMMAND ... $<TARGET_FILE:myexe> ..." substitution.
SET(target_file "\\$<TARGET_FILE:(.+)>")
SET(args)
FOREACH(ARG ${cmd} ${ARGN})
SET(arg "${ARG}")
IF("${arg}" MATCHES "${target_file}")
STRING(REGEX REPLACE "${target_file}" "\\1" tgt "${arg}")
IF(TARGET "${tgt}")
_ADD_TEST_28_GET_EXE(${tgt} exe)
STRING(REGEX REPLACE "${target_file}" "${exe}" arg "${arg}")
ENDIF()
ENDIF()
LIST(APPEND args "${arg}")
ENDFOREACH()
# Invoke old ADD_TEST() signature with transformed arguments.
ADD_TEST(${name} ${args})
ENDMACRO()
# Get the test-time location of an executable target.
MACRO(_ADD_TEST_28_GET_EXE tgt exe_var)
# The LOCATION property gives a build-time location.
GET_TARGET_PROPERTY(${exe_var} ${tgt} LOCATION)
# In single-configuration generatrs the build-time and test-time
# locations are the same because there is no per-config variable
# reference. In multi-configuration generators the following
# substitution converts the build-time configuration variable
# reference to a test-time configuration variable reference.
IF(CMAKE_CONFIGURATION_TYPES)
STRING(REPLACE "${CMAKE_CFG_INTDIR}" "\${CTEST_CONFIGURATION_TYPE}"
${exe_var} "${${exe_var}}")
ENDIF(CMAKE_CONFIGURATION_TYPES)
ENDMACRO()

View File

@ -0,0 +1,14 @@
#include <sys/types.h>
#define KB ((off_t)1024)
#define MB ((off_t)1024 * KB)
#define GB ((off_t)1024 * MB)
#define TB ((off_t)1024 * GB)
int t2[(((64 * GB -1) % 671088649) == 268434537)
&& (((TB - (64 * GB -1) + 255) % 1792151290) == 305159546)? 1: -1];
int main()
{
;
return 0;
}

View File

@ -0,0 +1,44 @@
# - Check if _FILE_OFFSET_BITS macro needed for large files
# CHECK_FILE_OFFSET_BITS ()
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
# Copyright (c) 2009, Michihiro NAKAJIMA
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#INCLUDE(CheckCXXSourceCompiles)
GET_FILENAME_COMPONENT(_selfdir_CheckFileOffsetBits
"${CMAKE_CURRENT_LIST_FILE}" PATH)
MACRO (CHECK_FILE_OFFSET_BITS)
IF(NOT DEFINED _FILE_OFFSET_BITS)
MESSAGE(STATUS "Cheking _FILE_OFFSET_BITS for large files")
TRY_COMPILE(__WITHOUT_FILE_OFFSET_BITS_64
${CMAKE_CURRENT_BINARY_DIR}
${_selfdir_CheckFileOffsetBits}/CheckFileOffsetBits.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS})
IF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
TRY_COMPILE(__WITH_FILE_OFFSET_BITS_64
${CMAKE_CURRENT_BINARY_DIR}
${_selfdir_CheckFileOffsetBits}/CheckFileOffsetBits.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64)
ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
IF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
SET(_FILE_OFFSET_BITS 64 CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
MESSAGE(STATUS "Cheking _FILE_OFFSET_BITS for large files - needed")
ELSE(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
SET(_FILE_OFFSET_BITS "" CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
MESSAGE(STATUS "Cheking _FILE_OFFSET_BITS for large files - not needed")
ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
ENDIF(NOT DEFINED _FILE_OFFSET_BITS)
ENDMACRO (CHECK_FILE_OFFSET_BITS)

View File

@ -0,0 +1,49 @@
# Check if the system has the specified function; treat glibc "stub"
# functions as nonexistent:
# CHECK_FUNCTION_EXISTS_GLIBC (FUNCTION FUNCVAR)
#
# FUNCTION - the function(s) where the prototype should be declared
# FUNCVAR - variable to define if the function does exist
#
# In particular, this understands the glibc convention of
# defining macros __stub_XXXX or __stub___XXXX if the function
# does appear in the library but is merely a stub that does nothing.
# By detecting this case, we can select alternate behavior on
# platforms that don't support this functionality.
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
# Copyright (c) 2009, Michihiro NAKAJIMA
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
INCLUDE(CheckFunctionExists)
GET_FILENAME_COMPONENT(_selfdir_CheckFunctionExistsGlibc
"${CMAKE_CURRENT_LIST_FILE}" PATH)
MACRO (CHECK_FUNCTION_EXISTS_GLIBC _FUNC _FUNCVAR)
IF(NOT DEFINED ${_FUNCVAR})
SET(CHECK_STUB_FUNC_1 "__stub_${_FUNC}")
SET(CHECK_STUB_FUNC_2 "__stub___${_FUNC}")
CONFIGURE_FILE( ${_selfdir_CheckFunctionExistsGlibc}/CheckFuncs_stub.c.in
${CMAKE_CURRENT_BINARY_DIR}/cmake.tmp/CheckFuncs_stub.c IMMEDIATE)
TRY_COMPILE(__stub
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/cmake.tmp/CheckFuncs_stub.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
CMAKE_FLAGS
-DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILE_FLAGS}
"${CHECK_INCLUDE_FILE_C_INCLUDE_DIRS}")
IF (__stub)
SET("${_FUNCVAR}" "" CACHE INTERNAL "Have function ${_FUNC}")
ELSE (__stub)
CHECK_FUNCTION_EXISTS("${_FUNC}" "${_FUNCVAR}")
ENDIF (__stub)
ENDIF(NOT DEFINED ${_FUNCVAR})
ENDMACRO (CHECK_FUNCTION_EXISTS_GLIBC)

View File

@ -0,0 +1,16 @@
#ifdef __STDC__
#include <limits.h>
#else
#include <assert.h>
#endif
int
main()
{
#if defined ${CHECK_STUB_FUNC_1} || defined ${CHECK_STUB_FUNC_2}
return 0;
#else
this system have stub
return 0;
#endif
}

View File

@ -0,0 +1,32 @@
# - Check if the system has the specified type
# CHECK_HEADER_DIRENT (HEADER1 HEARDER2 ...)
#
# HEADER - the header(s) where the prototype should be declared
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
# Copyright (c) 2009, Michihiro NAKAJIMA
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
INCLUDE(CheckTypeExists)
MACRO (CHECK_HEADER_DIRENT)
CHECK_TYPE_EXISTS("DIR *" dirent.h HAVE_DIRENT_H)
IF(NOT HAVE_DIRENT_H)
CHECK_TYPE_EXISTS("DIR *" sys/ndir.h HAVE_SYS_NDIR_H)
IF(NOT HAVE_SYS_NDIR_H)
CHECK_TYPE_EXISTS("DIR *" ndir.h HAVE_NDIR_H)
IF(NOT HAVE_NDIR_H)
CHECK_TYPE_EXISTS("DIR *" sys/dir.h HAVE_SYS_DIR_H)
ENDIF(NOT HAVE_NDIR_H)
ENDIF(NOT HAVE_SYS_NDIR_H)
ENDIF(NOT HAVE_DIRENT_H)
ENDMACRO (CHECK_HEADER_DIRENT)

View File

@ -0,0 +1,43 @@
# - Check if the given struct or class has the specified member variable
# CHECK_STRUCT_MEMBER (STRUCT MEMBER HEADER VARIABLE)
#
# STRUCT - the name of the struct or class you are interested in
# MEMBER - the member which existence you want to check
# HEADER - the header(s) where the prototype should be declared
# VARIABLE - variable to store the result
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
INCLUDE(CheckCSourceCompiles)
MACRO (CHECK_STRUCT_MEMBER _STRUCT _MEMBER _HEADER _RESULT)
SET(_INCLUDE_FILES)
FOREACH (it ${_HEADER})
SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
ENDFOREACH (it)
SET(_CHECK_STRUCT_MEMBER_SOURCE_CODE "
${_INCLUDE_FILES}
int main()
{
static ${_STRUCT} tmp;
if (sizeof(tmp.${_MEMBER}))
return 0;
return 0;
}
")
CHECK_C_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
ENDMACRO (CHECK_STRUCT_MEMBER)

View File

@ -0,0 +1,42 @@
# - Check if the system has the specified type
# CHECK_TYPE_EXISTS (TYPE HEADER VARIABLE)
#
# TYPE - the name of the type or struct or class you are interested in
# HEADER - the header(s) where the prototype should be declared
# VARIABLE - variable to store the result
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
# Copyright (c) 2009, Michihiro NAKAJIMA
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
INCLUDE(CheckCSourceCompiles)
MACRO (CHECK_TYPE_EXISTS _TYPE _HEADER _RESULT)
SET(_INCLUDE_FILES)
FOREACH (it ${_HEADER})
SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
ENDFOREACH (it)
SET(_CHECK_TYPE_EXISTS_SOURCE_CODE "
${_INCLUDE_FILES}
int main()
{
static ${_TYPE} tmp;
if (sizeof(tmp))
return 0;
return 0;
}
")
CHECK_C_SOURCE_COMPILES("${_CHECK_TYPE_EXISTS_SOURCE_CODE}" ${_RESULT})
ENDMACRO (CHECK_TYPE_EXISTS)

View File

@ -0,0 +1,48 @@
# - Find lzma and lzmadec
# Find the native LZMA includes and library
#
# LZMA_INCLUDE_DIR - where to find lzma.h, etc.
# LZMA_LIBRARIES - List of libraries when using liblzma.
# LZMA_FOUND - True if liblzma found.
# LZMADEC_INCLUDE_DIR - where to find lzmadec.h, etc.
# LZMADEC_LIBRARIES - List of libraries when using liblzmadec.
# LZMADEC_FOUND - True if liblzmadec found.
IF (LZMA_INCLUDE_DIR)
# Already in cache, be silent
SET(LZMA_FIND_QUIETLY TRUE)
ENDIF (LZMA_INCLUDE_DIR)
FIND_PATH(LZMA_INCLUDE_DIR lzma.h)
FIND_LIBRARY(LZMA_LIBRARY NAMES lzma liblzma)
# handle the QUIETLY and REQUIRED arguments and set LZMA_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZMA DEFAULT_MSG LZMA_LIBRARY LZMA_INCLUDE_DIR)
IF(LZMA_FOUND)
SET( LZMA_LIBRARIES ${LZMA_LIBRARY} )
ELSE(LZMA_FOUND)
SET( LZMA_LIBRARIES )
IF (LZMADEC_INCLUDE_DIR)
# Already in cache, be silent
SET(LZMADEC_FIND_QUIETLY TRUE)
ENDIF (LZMADEC_INCLUDE_DIR)
FIND_PATH(LZMADEC_INCLUDE_DIR lzmadec.h)
FIND_LIBRARY(LZMADEC_LIBRARY NAMES lzmadec )
# handle the QUIETLY and REQUIRED arguments and set LZMADEC_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZMADEC DEFAULT_MSG LZMADEC_LIBRARY
LZMADEC_INCLUDE_DIR)
IF(LZMADEC_FOUND)
SET( LZMADEC_LIBRARIES ${LZMADEC_LIBRARY} )
ELSE(LZMADEC_FOUND)
SET( LZMADEC_LIBRARIES )
ENDIF(LZMADEC_FOUND)
ENDIF(LZMA_FOUND)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libarchive
Description: library that can create and read several streaming archive formats
Version: @VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -larchive
Libs.private: @LIBS@

View File

@ -0,0 +1,418 @@
#!/bin/sh
#
# This needs http://unicode.org/Public/UNIDATA/UnicodeData.txt
#
inputfile="$1" # Expect UnicodeData.txt
outfile=archive_string_composition.h
pickout=/tmp/mk_unicode_composition_tbl$$.awk
#################################################################################
#
# Append the file header of "archive_string_composition.h"
#
#################################################################################
append_copyright()
{
cat > ${outfile} <<CR_END
/*-
* Copyright (c) 2011 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/UNIDATA/UnicodeData.txt
*
* See also http://unicode.org/report/tr15/
*/
#ifndef __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_STRING_COMPOSITION_H_INCLUDED
#define ARCHIVE_STRING_COMPOSITION_H_INCLUDED
struct unicode_composition_table {
uint32_t cp1;
uint32_t cp2;
uint32_t nfc;
};
CR_END
}
#################################################################################
#
# awk script
#
#################################################################################
cat > ${pickout} <<AWK_END
#
BEGIN {
FS = ";"
min = "";
max = "";
cmd="sort | awk -F ' ' '{printf \"\\\\t{ 0x%s , 0x%s , 0x%s },\\\\n\",\$1,\$2,\$3}'"
print "static const struct unicode_composition_table u_composition_table[] = {"
}
END {
close(cmd)
print "};"
print ""
#
# Output Canonical Combining Class tables used for translating NFD to NFC.
#
printf "#define CANONICAL_CLASS_MIN\\t0x%s\\n", min
printf "#define CANONICAL_CLASS_MAX\\t0x%s\\n", max
print ""
printf "#define IS_DECOMPOSABLE_BLOCK(uc)\\t\\\\\n"
printf "\\t(((uc)>>8) <= 0x%X && u_decomposable_blocks[(uc)>>8])\\n", highnum
printf "static const char u_decomposable_blocks[0x%X+1] = {\\n\\t", highnum
#
# Output blockmap
for (i = 0; i <= highnum; i++) {
if (i != 0 && i % 32 == 0)
printf "\\n\\t"
# Additionally Hangul[11XX(17), AC00(172) - D7FF(215)] is decomposable.
if (blockmap[i] || i == 17 || (i >= 172 && i <= 215))
printf "1,"
else
printf "0,"
}
printf "\\n};\\n\\n"
#
# Output a macro to get a canonical combining class.
#
print "/* Get Canonical Combining Class(CCC). */"
printf "#define CCC(uc)\\t\\\\\n"
printf "\\t(((uc) > 0x%s)?0:\\\\\\n", max
printf "\\tccc_val[ccc_val_index[ccc_index[(uc)>>8]][((uc)>>4)&0x0F]][(uc)&0x0F])\\n"
print ""
#
# Output a canonical combining class value table.
#
midcnt = 0
printf "/* The table of the value of Canonical Cimbining Class */\\n"
print "static const unsigned char ccc_val[][16] = {"
print " /* idx=0: XXXX0 - XXXXF */"
print " { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },"
for (h = 0; h <= highnum; h++) {
if (!blockmap[h])
continue;
for (m = 0; m < 16; m++) {
if (!xx_blockmap[h, m])
continue;
midcnt++
printf " /* idx=%d: %03X%1X0 - %03X%1XF */\\n {", midcnt, h, m, h, m
for (l = 0; l < 15; l++) {
printf "%d, ", xxx_blockmap[h, m, l]
}
printf "%d },\n", xxx_blockmap[h, m, 15]
}
}
printf "};\n"
#
# Output the index table of the canonical combining class value table.
#
cnt = 0
midcnt = 0
printf "\\n/* The index table to ccc_val[*][16] */\\n"
print "static const unsigned char ccc_val_index[][16] = {"
print " /* idx=0: XXX00 - XXXFF */"
print " { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },"
for (h = 0; h <= highnum; h++) {
if (!blockmap[h])
continue;
cnt++
printf " /* idx=%d: %03X00 - %03XFF */\\n {", cnt, h, h
for (m = 0; m < 16; m++) {
if (m != 0)
printf ","
if (xx_blockmap[h, m]) {
midcnt++
printf "%2d", midcnt
} else
printf " 0"
}
printf " },\\n"
}
printf "};\\n"
#
# Output the index table to the index table of the canonical combining
# class value table.
#
printf "\\n/* The index table to ccc_val_index[*][16] */\\n"
printf "static const unsigned char ccc_index[] = {\\n ", h
cnt = 0
for (h = 0; h <= highnum; h++) {
if (h != 0 && h % 24 == 0)
printf "\\n "
if (blockmap[h]) {
cnt++;
printf "%2d,", cnt
} else
printf " 0,"
}
print "};"
print ""
print "#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */"
}
#
#
function hextoi(hex)
{
dec = 0
for (i=0; i < length(hex); i++) {
x = substr(hex, i+1, 1)
if (x ~/[0-9]/)
dec = dec * 16 + x;
else if (x == "A")
dec = dec * 16 + 10;
else if (x == "B")
dec = dec * 16 + 11;
else if (x == "C")
dec = dec * 16 + 12;
else if (x == "D")
dec = dec * 16 + 13;
else if (x == "E")
dec = dec * 16 + 14;
else if (x == "F")
dec = dec * 16 + 15;
}
return dec
}
#
# Collect Canonical Combining Class values.
#
\$4 ~/^[0-9A-F]+$/ {
if (\$4 !~/^0$/) {
if (min == "") {
min = \$1
}
max = \$1
high = substr(\$1, 1, length(\$1) -2)
highnum = hextoi(high)
mid = substr(\$1, length(\$1) -1, 1)
midnum = hextoi(mid)
low = substr(\$1, length(\$1), 1)
lownum = hextoi(low)
blockmap[highnum] = 1
xx_blockmap[highnum, midnum] = 1
xxx_blockmap[highnum, midnum, lownum] = \$4
}
}
#
# Following code points are not decomposed in MAC OS.
# U+2000 - U+2FFF
# U+F900 - U+FAFF
# U+2F800 - U+2FAFF
#
#\$1 ~/^2[0-9A-F][0-9A-F][0-9A-F]\$/ {
# next
#}
#\$1 ~/^F[9A][0-9A-F][0-9A-F]\$/ {
# next
#}
#\$1 ~/^2F[89A][0-9A-F][0-9A-F]\$/ {
# next
#}
#
# Exclusion code points specified by
# http://unicode.org/Public/UNIDATA/CompositionExclusions.txt
##
# 1. Script Specifices
##
\$1 ~/^095[89ABCDEF]\$/ {
next
}
\$1 ~/^09D[CDF]\$/ {
next
}
\$1 ~/^0A3[36]\$/ {
next
}
\$1 ~/^0A5[9ABE]\$/ {
next
}
\$1 ~/^0B5[CD]\$/ {
next
}
\$1 ~/^0F4[3D]\$/ {
next
}
\$1 ~/^0F5[27C]\$/ {
next
}
\$1 ~/^0F69\$/ {
next
}
\$1 ~/^0F7[68]\$/ {
next
}
\$1 ~/^0F9[3D]\$/ {
next
}
\$1 ~/^0FA[27C]\$/ {
next
}
\$1 ~/^0FB9\$/ {
next
}
\$1 ~/^FB1[DF]\$/ {
next
}
\$1 ~/^FB2[ABCDEF]\$/ {
next
}
\$1 ~/^FB3[012345689ABCE]\$/ {
next
}
\$1 ~/^FB4[01346789ABCDE]\$/ {
next
}
##
# 2. Post Composition Version precomposed characters
##
\$1 ~/^2ADC\$/ {
next
}
\$1 ~/^1D15[EF]\$/ {
next
}
\$1 ~/^1D16[01234]\$/ {
next
}
\$1 ~/^1D1B[BCDEF]\$/ {
next
}
\$1 ~/^1D1C0\$/ {
next
}
##
# 3. Singleton Decompositions
##
\$1 ~/^034[01]\$/ {
next
}
\$1 ~/^037[4E]\$/ {
next
}
\$1 ~/^0387\$/ {
next
}
\$1 ~/^1F7[13579BD]\$/ {
next
}
\$1 ~/^1FB[BE]\$/ {
next
}
\$1 ~/^1FC[9B]\$/ {
next
}
\$1 ~/^1FD[3B]\$/ {
next
}
\$1 ~/^1FE[3BEF]\$/ {
next
}
\$1 ~/^1FF[9BD]\$/ {
next
}
\$1 ~/^200[01]\$/ {
next
}
\$1 ~/^212[6AB]\$/ {
next
}
\$1 ~/^232[9A]\$/ {
next
}
\$1 ~/^F9[0-9A-F][0-9A-F]\$/ {
next
}
\$1 ~/^FA0[0-9A-D]\$/ {
next
}
\$1 ~/^FA1[025-9A-E]\$/ {
next
}
\$1 ~/^FA2[0256A-D]\$/ {
next
}
\$1 ~/^FA[3-5][0-9A-F]\$/ {
next
}
\$1 ~/^FA6[0-9A-D]\$/ {
next
}
\$1 ~/^FA[7-9A-C][0-9A-F]\$/ {
next
}
\$1 ~/^FAD[0-9]\$/ {
next
}
\$1 ~/^2F[89][0-9A-F][0-9A-F]\$/ {
next
}
\$1 ~/^2FA0[0-9A-F]\$/ {
next
}
\$1 ~/^2FA1[0-9A-D]\$/ {
next
}
##
# 4. Non-Starter Decompositions
##
\$1 ~/^0344\$/ {
next
}
\$1 ~/^0F7[35]\$/ {
next
}
\$1 ~/^0F81\$/ {
next
}
#
# Output combinations for NFD ==> NFC.
#
\$6 ~/^[0-9A-F]+ [0-9A-F]+\$/ {
split(\$6, cp, " ")
if (length(\$1) == 4)
print "0"cp[1], "0"cp[2], "0"\$1 | cmd
else
print cp[1], cp[2], \$1 | cmd
}
AWK_END
#################################################################################
#
# Run awk a script.
#
#################################################################################
append_copyright
awk -f ${pickout} ${inputfile} >> ${outfile}
#
# Remove awk the script.
rm ${pickout}

View File

@ -0,0 +1 @@
3000001b

View File

@ -0,0 +1,172 @@
############################################
#
# How to build libarchive
#
############################################
# Public headers
SET(include_HEADERS
archive.h
archive_entry.h
)
# Sources and private headers
SET(libarchive_SOURCES
archive_acl.c
archive_check_magic.c
archive_crypto.c
archive_crypto_private.h
archive_endian.h
archive_entry.c
archive_entry.h
archive_entry_copy_stat.c
archive_entry_link_resolver.c
archive_entry_locale.h
archive_entry_private.h
archive_entry_sparse.c
archive_entry_stat.c
archive_entry_strmode.c
archive_entry_xattr.c
archive_options.c
archive_options_private.h
archive_platform.h
archive_ppmd_private.h
archive_ppmd7.c
archive_ppmd7_private.h
archive_private.h
archive_rb.c
archive_rb.h
archive_read.c
archive_read_data_into_fd.c
archive_read_disk_entry_from_file.c
archive_read_disk_posix.c
archive_read_disk_private.h
archive_read_disk_set_standard_lookup.c
archive_read_extract.c
archive_read_open_fd.c
archive_read_open_file.c
archive_read_open_filename.c
archive_read_open_memory.c
archive_read_private.h
archive_read_set_options.c
archive_read_support_filter_all.c
archive_read_support_filter_bzip2.c
archive_read_support_filter_compress.c
archive_read_support_filter_gzip.c
archive_read_support_filter_none.c
archive_read_support_filter_program.c
archive_read_support_filter_rpm.c
archive_read_support_filter_uu.c
archive_read_support_filter_xz.c
archive_read_support_format_7zip.c
archive_read_support_format_all.c
archive_read_support_format_ar.c
archive_read_support_format_by_code.c
archive_read_support_format_cab.c
archive_read_support_format_cpio.c
archive_read_support_format_empty.c
archive_read_support_format_iso9660.c
archive_read_support_format_lha.c
archive_read_support_format_mtree.c
archive_read_support_format_rar.c
archive_read_support_format_raw.c
archive_read_support_format_tar.c
archive_read_support_format_xar.c
archive_read_support_format_zip.c
archive_string.c
archive_string.h
archive_string_composition.h
archive_string_sprintf.c
archive_util.c
archive_virtual.c
archive_write.c
archive_write_disk_posix.c
archive_write_disk_private.h
archive_write_disk_set_standard_lookup.c
archive_write_private.h
archive_write_open_fd.c
archive_write_open_file.c
archive_write_open_filename.c
archive_write_open_memory.c
archive_write_add_filter_bzip2.c
archive_write_add_filter_compress.c
archive_write_add_filter_gzip.c
archive_write_add_filter_none.c
archive_write_add_filter_program.c
archive_write_add_filter_xz.c
archive_write_set_format.c
archive_write_set_format_7zip.c
archive_write_set_format_ar.c
archive_write_set_format_by_name.c
archive_write_set_format_cpio.c
archive_write_set_format_cpio_newc.c
archive_write_set_format_gnutar.c
archive_write_set_format_iso9660.c
archive_write_set_format_mtree.c
archive_write_set_format_pax.c
archive_write_set_format_shar.c
archive_write_set_format_ustar.c
archive_write_set_format_xar.c
archive_write_set_format_zip.c
archive_write_set_options.c
filter_fork.c
filter_fork.h
)
# Man pages
SET(libarchive_MANS
archive_entry.3
archive_entry_acl.3
archive_entry_linkify.3
archive_entry_paths.3
archive_entry_perms.3
archive_entry_stat.3
archive_entry_time.3
archive_read.3
archive_read_disk.3
archive_read_set_options.3
archive_util.3
archive_write.3
archive_write_disk.3
archive_write_set_options.3
cpio.5
libarchive.3
libarchive_internals.3
libarchive-formats.5
mtree.5
tar.5
)
IF(WIN32 AND NOT CYGWIN)
LIST(APPEND libarchive_SOURCES archive_entry_copy_bhfi.c)
LIST(APPEND libarchive_SOURCES archive_read_disk_windows.c)
LIST(APPEND libarchive_SOURCES archive_windows.c)
LIST(APPEND libarchive_SOURCES archive_windows.h)
LIST(APPEND libarchive_SOURCES archive_write_disk_windows.c)
LIST(APPEND libarchive_SOURCES filter_fork_windows.c)
ENDIF(WIN32 AND NOT CYGWIN)
# Libarchive is a shared library
ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS})
TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS})
SET_TARGET_PROPERTIES(archive PROPERTIES SOVERSION ${SOVERSION})
# archive_static is a static library
ADD_LIBRARY(archive_static STATIC ${libarchive_SOURCES} ${include_HEADERS})
SET_TARGET_PROPERTIES(archive_static PROPERTIES COMPILE_DEFINITIONS
LIBARCHIVE_STATIC)
# On Posix systems, libarchive.so and libarchive.a can co-exist.
IF(NOT WIN32 OR CYGWIN)
SET_TARGET_PROPERTIES(archive_static PROPERTIES OUTPUT_NAME archive)
ENDIF(NOT WIN32 OR CYGWIN)
# How to install the libraries
INSTALL(TARGETS archive archive_static
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
INSTALL_MAN(${libarchive_MANS})
INSTALL(FILES ${include_HEADERS} DESTINATION include)
add_subdirectory(test)

View File

@ -0,0 +1,832 @@
/*-
* 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
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
#include <stdio.h> /* For FILE * */
/*
* 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)
# include <inttypes.h>
#endif
/* Get appropriate definitions of standard POSIX-style types. */
/* These should match the types used in 'struct stat' */
#if defined(_WIN32) && !defined(__CYGWIN__)
# define __LA_INT64_T __int64
# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
# define __LA_SSIZE_T ssize_t
# elif defined(_WIN64)
# define __LA_SSIZE_T __int64
# else
# define __LA_SSIZE_T long
# endif
# if defined(__BORLANDC__)
# define __LA_UID_T uid_t
# define __LA_GID_T gid_t
# else
# define __LA_UID_T short
# define __LA_GID_T short
# endif
#else
# include <unistd.h> /* ssize_t, uid_t, and gid_t */
# if defined(_SCO_DS)
# define __LA_INT64_T long long
# else
# define __LA_INT64_T int64_t
# endif
# define __LA_SSIZE_T ssize_t
# define __LA_UID_T uid_t
# define __LA_GID_T gid_t
#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
#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
#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.
*/
/*
* 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 >= 2012108.
*
* This single-number format was introduced with libarchive 1.9.0 in
* the libarchive 1.x family and libarchive 2.2.4 in the libarchive
* 2.x family. The following may be useful if you really want to do
* feature detection for earlier libarchive versions (which defined
* ARCHIVE_API_VERSION and ARCHIVE_API_FEATURE instead):
*
* #ifndef ARCHIVE_VERSION_NUMBER
* #define ARCHIVE_VERSION_NUMBER \
* (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
* #endif
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
#define ARCHIVE_VERSION_NUMBER 3000001
__LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
#define ARCHIVE_VERSION_STRING "libarchive 3.0.1b"
__LA_DECL const char * archive_version_string(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);
/*
* 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
#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
#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_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
/*-
* 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_finish 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_DECL int archive_read_support_compression_bzip2(struct archive *);
__LA_DECL int archive_read_support_compression_compress(struct archive *);
__LA_DECL int archive_read_support_compression_gzip(struct archive *);
__LA_DECL int archive_read_support_compression_lzip(struct archive *);
__LA_DECL int archive_read_support_compression_lzma(struct archive *);
__LA_DECL int archive_read_support_compression_none(struct archive *);
__LA_DECL int archive_read_support_compression_program(struct archive *,
const char *command);
__LA_DECL int archive_read_support_compression_program_signature
(struct archive *, const char *,
const void * /* match */, size_t);
__LA_DECL int archive_read_support_compression_rpm(struct archive *);
__LA_DECL int archive_read_support_compression_uu(struct archive *);
__LA_DECL int archive_read_support_compression_xz(struct archive *);
#endif
__LA_DECL int archive_read_support_filter_all(struct archive *);
__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_lzip(struct archive *);
__LA_DECL int archive_read_support_filter_lzma(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 *,
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_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_raw(struct archive *);
__LA_DECL int archive_read_support_format_tar(struct archive *);
__LA_DECL int archive_read_support_format_xar(struct archive *);
__LA_DECL int archive_read_support_format_zip(struct archive *);
/* 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 *);
/* The callback data is provided to all of the callbacks above. */
__LA_DECL int archive_read_set_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);
__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);
/* Read an archive that's stored in memory. */
__LA_DECL int archive_read_open_memory(struct archive *,
void * buff, size_t size);
/* A more involved version that is only used for internal testing. */
__LA_DECL int archive_read_open_memory2(struct archive *a, void *buff,
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 *);
/* 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);
/*
* 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_buffer(struct archive *,
void *buffer, __LA_SSIZE_T len);
__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);
/*-
* 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)
__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 *);
#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_DECL int archive_write_set_compression_compress(struct archive *);
__LA_DECL int archive_write_set_compression_gzip(struct archive *);
__LA_DECL int archive_write_set_compression_lzip(struct archive *);
__LA_DECL int archive_write_set_compression_lzma(struct archive *);
__LA_DECL int archive_write_set_compression_none(struct archive *);
__LA_DECL int archive_write_set_compression_program(struct archive *,
const char *cmd);
__LA_DECL int archive_write_set_compression_xz(struct archive *);
#endif
__LA_DECL int archive_write_add_filter_bzip2(struct archive *);
__LA_DECL int archive_write_add_filter_compress(struct archive *);
__LA_DECL int archive_write_add_filter_gzip(struct archive *);
__LA_DECL int archive_write_add_filter_lzip(struct archive *);
__LA_DECL int archive_write_add_filter_lzma(struct archive *);
__LA_DECL int archive_write_add_filter_none(struct archive *);
__LA_DECL int archive_write_add_filter_program(struct archive *,
const char *cmd);
__LA_DECL int archive_write_add_filter_xz(struct archive *);
/* A convenience function to set the format based on the code or name. */
__LA_DECL int archive_write_set_format(struct archive *, int format_code);
__LA_DECL int archive_write_set_format_by_name(struct archive *,
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_newc(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 *);
/* TODO: int archive_write_set_format_old_tar(struct archive *); */
__LA_DECL int archive_write_set_format_pax(struct archive *);
__LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
__LA_DECL int archive_write_set_format_shar(struct archive *);
__LA_DECL int archive_write_set_format_shar_dump(struct archive *);
__LA_DECL int archive_write_set_format_ustar(struct archive *);
__LA_DECL int archive_write_set_format_xar(struct archive *);
__LA_DECL int archive_write_set_format_zip(struct archive *);
__LA_DECL int archive_write_open(struct archive *, void *,
archive_open_callback *, archive_write_callback *,
archive_close_callback *);
__LA_DECL int archive_write_open_fd(struct archive *, int _fd);
__LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
__LA_DECL int archive_write_open_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_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 *);
/* 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 *);
#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);
/*-
* 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_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 travesal be restored. */
__LA_DECL int archive_read_disk_set_atime_restored(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 *);
/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */
__LA_DECL __LA_INT64_T archive_position_uncompressed(struct archive *);
/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
__LA_DECL const char *archive_compression_name(struct archive *);
/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */
__LA_DECL int archive_compression(struct archive *);
#endif
__LA_DECL int archive_errno(struct archive *);
__LA_DECL const char *archive_error_string(struct archive *);
__LA_DECL const char *archive_format_name(struct archive *);
__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 *);
#ifdef __cplusplus
}
#endif
/* These are meaningless outside of this header. */
#undef __LA_DECL
#undef __LA_GID_T
#undef __LA_UID_T
/* These need to remain defined because they're used in the
* callback type definitions. XXX Fix this. This is ugly. XXX */
/* #undef __LA_INT64_T */
/* #undef __LA_SSIZE_T */
#endif /* !ARCHIVE_H_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
/*-
* 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 __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_ACL_PRIVATE_H_INCLUDED
#define ARCHIVE_ACL_PRIVATE_H_INCLUDED
#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_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);
const wchar_t *archive_acl_text_w(struct archive *, struct archive_acl *, int);
int archive_acl_text_l(struct archive_acl *, int, const char **, size_t *,
struct archive_string_conv *);
/*
* Private ACL parser. This is private because it handles some
* very weird formats that clients should not be messing with.
* Clients should only deal with their platform-native formats.
* Because of the need to support many formats cleanly, new arguments
* are likely to get added on a regular basis. Clients who try to use
* this interface are likely to be surprised when it changes.
*/
int archive_acl_parse_w(struct archive_acl *,
const wchar_t *, int /* type */);
int archive_acl_parse_l(struct archive_acl *,
const char *, int /* type */,
struct archive_string_conv *);
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */

View File

@ -0,0 +1,174 @@
/*-
* 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, strlen(m));
if (written <= 0)
return;
m += written;
s -= written;
}
}
static 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");
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;
}

View File

@ -0,0 +1,78 @@
/*-
* 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 __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);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,376 @@
/*-
* 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 __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
#define ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
/*
* 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
/* 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 <openssl/evp.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)
#include <wincrypt.h>
typedef struct {
int valid;
HCRYPTPROV cryptProv;
HCRYPTHASH hash;
} Digest_CTX;
#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_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_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_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_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_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_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_NETTLE) ||\
defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_MD5_WIN)
#define ARCHIVE_HAS_MD5
#endif
#define archive_md5_init(ctx)\
__archive_crypto.md5init(ctx)
#define archive_md5_final(ctx, md)\
__archive_crypto.md5final(ctx, md)
#define archive_md5_update(ctx, buf, n)\
__archive_crypto.md5update(ctx, buf, n)
#if defined(ARCHIVE_CRYPTO_RMD160_LIBC) ||\
defined(ARCHIVE_CRYPTO_RMD160_NETTLE) ||\
defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
#define ARCHIVE_HAS_RMD160
#endif
#define archive_rmd160_init(ctx)\
__archive_crypto.rmd160init(ctx)
#define archive_rmd160_final(ctx, md)\
__archive_crypto.rmd160final(ctx, md)
#define archive_rmd160_update(ctx, buf, n)\
__archive_crypto.rmd160update(ctx, buf, n)
#if defined(ARCHIVE_CRYPTO_SHA1_LIBC) ||\
defined(ARCHIVE_CRYPTO_SHA1_LIBMD) || \
defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
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_crypto.sha1init(ctx)
#define archive_sha1_final(ctx, md)\
__archive_crypto.sha1final(ctx, md)
#define archive_sha1_update(ctx, buf, n)\
__archive_crypto.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_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA256_WIN)
#define ARCHIVE_HAS_SHA256
#endif
#define archive_sha256_init(ctx)\
__archive_crypto.sha256init(ctx)
#define archive_sha256_final(ctx, md)\
__archive_crypto.sha256final(ctx, md)
#define archive_sha256_update(ctx, buf, n)\
__archive_crypto.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_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA384_WIN)
#define ARCHIVE_HAS_SHA384
#endif
#define archive_sha384_init(ctx)\
__archive_crypto.sha384init(ctx)
#define archive_sha384_final(ctx, md)\
__archive_crypto.sha384final(ctx, md)
#define archive_sha384_update(ctx, buf, n)\
__archive_crypto.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_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA512_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA512_WIN)
#define ARCHIVE_HAS_SHA512
#endif
#define archive_sha512_init(ctx)\
__archive_crypto.sha512init(ctx)
#define archive_sha512_final(ctx, md)\
__archive_crypto.sha512final(ctx, md)
#define archive_sha512_update(ctx, buf, n)\
__archive_crypto.sha512update(ctx, buf, n)
/* Minimal interface to crypto functionality for internal use in libarchive */
struct archive_crypto
{
/* 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_crypto __archive_crypto;
#endif

View File

@ -0,0 +1,162 @@
/*-
* 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 __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
/* Note: This is a purely internal header! */
/* Do not use this outside of libarchive internal code! */
#ifndef ARCHIVE_ENDIAN_H_INCLUDED
#define ARCHIVE_ENDIAN_H_INCLUDED
/*
* 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)
*/
#if defined(__WATCOMC__) || defined(__sgi) || defined(__hpux) || defined(__BORLANDC__)
#define inline
#elif defined(_MSC_VER)
#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;
return ((p[0] << 8) | p[1]);
}
static inline uint32_t
archive_be32dec(const void *pp)
{
unsigned char const *p = (unsigned char const *)pp;
return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
}
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;
return ((p[1] << 8) | p[0]);
}
static inline uint32_t
archive_le32dec(const void *pp)
{
unsigned char const *p = (unsigned char const *)pp;
return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
}
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, u >> 32);
archive_be32enc(p + 4, 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, u & 0xffffffff);
archive_le32enc(p + 4, u >> 32);
}
#endif

View File

@ -0,0 +1,148 @@
.\" Copyright (c) 2003-2007 Tim Kientzle
.\" Copyright (c) 2010 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 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: src/lib/libarchive/archive_entry.3,v 1.18 2008/05/26 17:00:22 kientzle Exp $
.\"
.Dd Feburary 22, 2010
.Dt archive_entry 3
.Os
.Sh NAME
.Nm archive_entry_clear ,
.Nm archive_entry_clone ,
.Nm archive_entry_free ,
.Nm archive_entry_new ,
.Nd functions for managing archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft "struct archive_entry *"
.Fn archive_entry_clear "struct archive_entry *"
.Ft struct archive_entry *
.Fn archive_entry_clone "struct archive_entry *"
.Ft void
.Fn archive_entry_free "struct archive_entry *"
.Ft struct archive_entry *
.Fn archive_entry_new "void"
.Sh DESCRIPTION
These functions create and manipulate data objects that
represent entries within an archive.
You can think of a
.Tn struct archive_entry
as a heavy-duty version of
.Tn struct stat :
it includes everything from
.Tn struct stat
plus associated pathname, textual group and user names, etc.
These objects are used by
.Xr libarchive 3
to represent the metadata associated with a particular
entry in an archive.
.Ss Create and Destroy
There are functions to allocate, destroy, clear, and copy
.Va archive_entry
objects:
.Bl -tag -compact -width indent
.It Fn archive_entry_clear
Erases the object, resetting all internal fields to the
same state as a newly-created object.
This is provided to allow you to quickly recycle objects
without thrashing the heap.
.It Fn archive_entry_clone
A deep copy operation; all text fields are duplicated.
.It Fn archive_entry_free
Releases the
.Tn struct archive_entry
object.
.It Fn archive_entry_new
Allocate and return a blank
.Tn struct archive_entry
object.
.El
.Ss Function groups
Due to high number of functions, the accessor functions can be found in
man pages grouped by the purpose.
.Bl -tag -width ".Xr archive_entry_perms 3"
.It Xr archive_entry_acl 3
Access Control List manipulation
.It Xr archive_entry_paths 3
Path name manipulation
.It Xr archive_entry_perms 3
User, group and mode manipulation
.It Xr archive_entry_stat 3
Functions not in the other groups and copying to/from
.Vt struct stat .
.It Xr archive_entry_time 3
Time field manipulation
.El
.Pp
Most of the functions set or read entries in an object.
Such functions have one of the following forms:
.Bl -tag -compact -width indent
.It Fn archive_entry_set_XXXX
Stores the provided data in the object.
In particular, for strings, the pointer is stored,
not the referenced string.
.It Fn archive_entry_copy_XXXX
As above, except that the referenced data is copied
into the object.
.It Fn archive_entry_XXXX
Returns the specified data.
In the case of strings, a const-qualified pointer to
the string is returned.
.El
String data can be set or accessed as wide character strings
or normal
.Va char
strings.
The functions that use wide character strings are suffixed with
.Cm _w .
Note that these are different representations of the same data:
For example, if you store a narrow string and read the corresponding
wide string, the object will transparently convert formats
using the current locale.
Similarly, if you store a wide string and then store a
narrow string for the same data, the previously-set wide string will
be discarded in favor of the new data.
.Pp
.\" .Sh EXAMPLE
.\" .Sh RETURN VALUES
.\" .Sh ERRORS
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry_acl 3 ,
.Xr archive_entry_paths 3 ,
.Xr archive_entry_perms 3 ,
.Xr archive_entry_time 3
.Sh HISTORY
The
.Nm libarchive
library first appeared in
.Fx 5.3 .
.Sh AUTHORS
.An -nosplit
The
.Nm libarchive
library was written by
.An Tim Kientzle Aq kientzle@acm.org .
.\" .Sh BUGS

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,620 @@
/*-
* Copyright (c) 2003-2008 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $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 3000001
/*
* 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 <time.h>
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <windows.h>
#endif
/* Get appropriate definitions of standard POSIX-style types. */
/* These should match the types used in 'struct stat' */
#if defined(_WIN32) && !defined(__CYGWIN__)
#define __LA_INT64_T __int64
# if defined(__BORLANDC__)
# define __LA_UID_T uid_t /* Remove in libarchive 3.2 */
# define __LA_GID_T gid_t /* Remove in libarchive 3.2 */
# define __LA_DEV_T dev_t
# define __LA_MODE_T mode_t
# else
# define __LA_UID_T short /* Remove in libarchive 3.2 */
# define __LA_GID_T short /* Remove in libarchive 3.2 */
# define __LA_DEV_T unsigned int
# define __LA_MODE_T unsigned short
# endif
#else
#include <unistd.h>
# if defined(_SCO_DS)
# define __LA_INT64_T long long
# else
# define __LA_INT64_T int64_t
# endif
# define __LA_UID_T uid_t /* Remove in libarchive 3.2 */
# define __LA_GID_T gid_t /* Remove in libarchive 3.2 */
# define __LA_DEV_T dev_t
# define __LA_MODE_T mode_t
#endif
/*
* Remove this for libarchive 3.2, since ino_t is no longer used.
*/
#define __LA_INO_T ino_t
/*
* 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
#else
/* Static libraries on all platforms and shared libraries on non-Windows. */
# define __LA_DECL
#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.
*/
#define AE_IFMT 0170000
#define AE_IFREG 0100000
#define AE_IFLNK 0120000
#define AE_IFSOCK 0140000
#define AE_IFCHR 0020000
#define AE_IFBLK 0060000
#define AE_IFDIR 0040000
#define AE_IFIFO 0010000
/*
* 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 wchar_t *archive_entry_gname_w(struct archive_entry *);
__LA_DECL const char *archive_entry_hardlink(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 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 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 wchar_t *archive_entry_uname_w(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_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_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_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_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_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_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 *);
/*
* 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, provide both stat32 and stat64 versions of these functions.
*/
__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);
/*
* 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_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)
/* We need to be able to specify combinations of these. */
#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 256 /* POSIX.1e only */
#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 512 /* POSIX.1e only */
#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 1024 /* NFS4 only */
#define ARCHIVE_ENTRY_ACL_TYPE_DENY 2048 /* NFS4 only */
#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 4096 /* NFS4 only */
#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 8192 /* 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 */);
__LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */,
int * /* type */, int * /* permset */, int * /* tag */,
int * /* qual */, const wchar_t ** /* name */);
/*
* Construct a text-format ACL. The flags argument is a bitmask that
* can include any of the following:
*
* ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries.
* ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries.
* ARCHIVE_ENTRY_ACL_TYPE_NFS4 - Include NFS4 entries.
* ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
* each ACL entry. ('star' introduced this for POSIX.1e, this flag
* also applies to NFS4.)
* ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
* default ACL entry, as used in old Solaris ACLs.
*/
#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
int /* flags */);
__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
int /* flags */);
/* 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 */

View File

@ -0,0 +1,233 @@
.\" Copyright (c) 2010 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 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.
.\"
.Dd February 21, 2010
.Dt archive_entry_acl 3
.Os
.Sh NAME
.Nm archive_entry_acl_add_entry ,
.Nm archive_entry_acl_add_entry_w ,
.Nm archive_entry_acl_clear ,
.Nm archive_entry_acl_count ,
.Nm archive_entry_acl_next ,
.Nm archive_entry_acl_next_w ,
.Nm archive_entry_acl_reset ,
.Nm archive_entry_acl_text_w
.Nd functions for manipulating Access Control Lists in archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft void
.Fo archive_entry_acl_add_entry
.Fa "struct archive_entry *a"
.Fa "int type"
.Fa "int permset"
.Fa "int tag"
.Fa "int qualifier"
.Fa "const char *name"
.Fc
.Ft void
.Fo archive_entry_acl_add_entry_w
.Fa "struct archive_entry *a"
.Fa "int type"
.Fa "int permset"
.Fa "int tag"
.Fa "int qualifier"
.Fa "const wchar_t *name"
.Fc
.Ft void
.Fn archive_entry_acl_clear "struct archive_entry *a"
.Ft int
.Fn archive_entry_acl_count "struct archive_entry *a" "int type"
.Ft int
.Fo archive_entry_acl_next
.Fa "struct archive_entry *a"
.Fa "int type"
.Fa "int *ret_type"
.Fa "int *ret_permset"
.Fa "int *ret_tag"
.Fa "int *ret_qual"
.Fa "const char **ret_name"
.Fc
.Ft int
.Fo archive_entry_acl_next_w
.Fa "struct archive_entry *a"
.Fa "int type"
.Fa "int *ret_type"
.Fa "int *ret_permset"
.Fa "int *ret_tag"
.Fa "int *ret_qual"
.Fa "const wchar_t **ret_name"
.Fc
.Ft int
.Fn archive_entry_acl_reset "struct archive_entry *a" "int type"
.Ft const wchar_t *
.Fn archive_entry_acl_text_w "struct archive_entry *a" "int flags"
.\" enum?
.Sh DESCRIPTION
An
.Dq Access Control List
is a generalisation of the classic Unix permission system.
The ACL interface of
.Nm libarchive
is derived from the POSIX.1e draft, but restricted to simplify dealing
with practical implementations in various Operating Systems and archive formats.
.Pp
An ACL consists of a number of independent entries.
Each entry specifies the permission set as bitmask of basic permissions.
Valid permissions are:
.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_EXECUTE"
.It Dv ARCHIVE_ENTRY_ACL_EXECUTE
.It Dv ARCHIVE_ENTRY_ACL_WRITE
.It Dv ARCHIVE_ENTRY_ACL_READ
.El
The permissions correspond to the normal Unix permissions.
.Pp
The tag specifies the principal to which the permission applies.
Valid values are:
.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ"
.It Dv ARCHIVE_ENTRY_ACL_USER
The user specified by the name field.
.It Dv ARCHIVE_ENTRY_ACL_USER_OBJ
The owner of the file.
.It Dv ARCHIVE_ENTRY_ACL_GROUP
The group specied by the name field.
.It Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
The group who owns the file.
.It Dv ARCHIVE_ENTRY_ACL_MASK
The maximum permissions to be obtained via group permissions.
.It Dv ARCHIVE_ENTRY_ACL_OTHER
Any principal who doesn't have a user or group entry.
.El
The principals
.Dv ARCHIVE_ENTRY_ACL_USER_OBJ ,
.Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
and
.Dv ARCHIVE_ENTRY_ACL_OTHER
are equivalent to user, group and other in the classic Unix permission
model and specify non-extended ACL entries.
.Pp
All files have an access ACL
.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS .
This specifies the permissions required for access to the file itself.
Directories have an additional ACL
.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT ,
which controlls the initial access ACL for newly created directory entries.
.Pp
.Fn archive_entry_acl_add_entry
and
.Fn archive_entry_acl_add_entry_w
add a single ACL entry.
For the access ACL and non-extended principals, the classic Unix permissions
are updated.
.Pp
.Fn archive_entry_acl_clear
removes all ACL entries and resets the enumeration pointer.
.Pp
.Fn archive_entry_acl_count
counts the ACL entries that have the given type mask.
.Fa type
can be the bitwise-or of
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
and
.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT .
If
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
is included and at least one extended ACL entry is found,
the three non-extened ACLs are added.
.Pp
.Fn archive_entry_acl_next
and
.Fn archive_entry_acl_next_w
return the next entry of the ACL list.
This functions may only be called after
.Fn archive_entry_acl_reset
has indicated the presence of extended ACL entries.
.Pp
.Fn archive_entry_acl_reset
prepare reading the list of ACL entries with
.Fn archive_entry_acl_next
or
.Fn archive_entry_acl_next_w .
The function returns either 0, if no non-extended ACLs are found.
In this case, the access permissions should be obtained by
.Xr archive_entry_mode 3
or set using
.Xr chmod 2 .
Otherwise, the function returns the same value as
.Fn archive_entry_acl_count .
.Pp
.Fn archive_entry_acl_text_w
converts the ACL entries for the given type mask into a wide string.
In addition to the normal type flags,
.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
and
.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
can be specified to further customize the result.
The returned long string is valid until the next call to
.Fn archive_entry_acl_clear ,
.Fn archive_entry_acl_add_entry ,
.Fn archive_entry_acl_add_entry_w
or
.Fn archive_entry_acl_text_w .
.Sh RETURN VALUES
.Fn archive_entry_acl_count
and
.Fn archive_entry_acl_reset
returns the number of ACL entries that match the given type mask.
If the type mask includes
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
and at least one extended ACL entry exists, the three classic Unix
permissions are counted.
.Pp
.Fn archive_entry_acl_next
and
.Fn archive_entry_acl_next_w
return
.Dv ARCHIVE_OK
on success,
.Dv ARCHIVE_EOF
if no more ACL entries exist
and
.Dv ARCHIVE_WARN
if
.Fn archive_entry_acl_reset
has not been called first.
.Pp
.Fn archive_entry_text_w
returns a wide string representation of the ACL entrise matching the
given type mask.
The returned long string is valid until the next call to
.Fn archive_entry_acl_clear ,
.Fn archive_entry_acl_add_entry ,
.Fn archive_entry_acl_add_entry_w
or
.Fn archive_entry_acl_text_w .
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry 3
.Sh BUGS
.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
and
.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
are not documented.

View File

@ -0,0 +1,75 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "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 *time, long *ns)
{
ULARGE_INTEGER utc;
utc.HighPart = filetime->dwHighDateTime;
utc.LowPart = filetime->dwLowDateTime;
if (utc.QuadPart >= EPOC_TIME) {
utc.QuadPart -= EPOC_TIME;
*time = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */
*ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
} else {
*time = 0;
*ns = 0;
}
}
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

View File

@ -0,0 +1,79 @@
/*-
* 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_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);
}

View File

@ -0,0 +1,444 @@
/*-
* 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);
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 = 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);
}

View File

@ -0,0 +1,224 @@
.\" Copyright (c) 2010 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 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.
.\"
.Dd February 20, 2010
.Dt archive_entry_linkify 3
.Os
.Sh NAME
.Nm archive_entry_linkresolver ,
.Nm archive_entry_linkresolver_new ,
.Nm archive_entry_linkresolver_set_strategy ,
.Nm archive_entry_linkresolver_free ,
.Nm archive_entry_linkify
.Nd hardlink resolver functions
.Sh LIBRARY
.Lb libarchive
.Sh SYNOPSIS
.In archive_entry.h
.Ft struct archive_entry_linkresolver *
.Fn archive_entry_linkresolver_new void
.Ft void
.Fo archive_entry_linkresolver_set_strategy
.Fa "struct archive_entry_linkresolver *resolver"
.Fa "int format"
.Fc
.Ft void
.Fo archive_entry_linkresolver_free
.Fa "struct archive_entry_linkresolver *resolver"
.Fc
.Ft void
.Fo archive_entry_linkify
.Fa "struct archive_entry_linkresolver *resolver"
.Fa "struct archive_entry **entry"
.Fa "struct archive_entry **sparse"
.Fc
.Sh DESCRIPTION
Programs that want to create archives have to deal with hardlinks.
Hardlinks are handled in different ways by the archive formats.
The basic strategies are:
.Bl -enum
.It
Ignore hardlinks and store the body for each reference (old cpio, zip).
.It
Store the body the first time an inode is seen (ustar, pax).
.It
Store the body the last time an inode is seen (new cpio).
.El
.Pp
The
.Nm
functions help by providing a unified interface and handling the complexity
behind the scene.
.Pp
The
.Nm
functions assume that
.Vt archive_entry
instances have valid nlinks, inode and device values.
The inode and device value is used to match entries.
The nlinks value is used to determined if all references have been found and
if the internal references can be recycled.
.Pp
The
.Fn archive_entry_linkresolver_new
function allocates a new link resolver.
The instance can be freed using
.Fn archive_entry_linkresolver_free .
All deferred entries are flushed and the internal storage is freed.
.Pp
The
.Fn archive_entry_linkresolver_set_strategy
function selects the optimal hardlink strategy for the given format.
The format code can be obtained from
.Xr archive_format 3 .
The function can be called more than once, but it is recommended to
flush all deferred entries first.
.Pp
The
.Fn archive_entry_linkify
function is the core of
.Nm .
The
.Fn entry
argument points to the
.Vt archive_entry
that should be written.
Depending on the strategy one of the following actions is taken:
.Bl -enum
.It
For the simple archive formats
.Va *entry
is left unmodified and
.Va *sparse
is set to
.Dv NULL .
.It
For tar like archive formats,
.Va *sparse
is set to
.Dv NULL .
If
.Va *entry
is
.Dv NULL ,
no action is taken.
If the hardlink count of
.Va *entry
is larger than 1 and the file type is a regular file or symbolic link,
the internal list is searched for a matching inode.
If such an inode is found, the link count is decremented and the file size
of
.Va *entry
is set to 0 to notify that no body should be written.
If no such inode is found, a copy of the entry is added to the internal cache
with a link count reduced by one.
.It
For new cpio like archive formats a value for
.Va *entry
of
.Dv NULL
is used to flush deferred entries.
In that case
.Va *entry
is set to an arbitrary deferred entry and the entry itself is removed from the
internal list.
If the internal list is empty,
.Va *entry
is set to
.Dv NULL .
In either case,
.Va *sparse
is set to
.Dv NULL
and the function returns.
If the hardlink count of
.Va *entry
is one or the file type is a directory or device,
.Va *sparse
is set to
.Dv NULL
and no further action is taken.
Otherwise, the internal list is searched for a matching inode.
If such an inode is not found, the entry is added to the internal list,
both
.Va *entry
and
.Va *sparse
are set to
.Dv NULL
and the function returns.
If such an inode is found, the link count is decremented.
If it remains larger than one, the existing entry on the internal list
is swapped with
.Va *entry
after retaining the link count.
The existing entry is returned in
.Va *entry .
If the link count reached one, the new entry is also removed from the
internal list and returned in
.Va *sparse .
Otherwise
.Va *sparse
is set to
.Dv NULL .
.El
.Pp
The general usage is therefore:
.Bl -enum
.It
For each new archive entry, call
.Fn archive_entry_linkify .
.It
Keep in mind that the entries returned may have a size of 0 now.
.It
If
.Va *entry
is not
.Dv NULL ,
archive it.
.It
If
.Va *sparse
is not
.Dv NULL ,
archive it.
.It
After all entries have been written to disk, call
.Fn archive_entry_linkify
with
.Va *entry
set to
.Dv NULL
and archive the returned entry as long as it is not
.Dv NULL .
.El
.Sh RETURN VALUES
.Fn archive_entry_linkresolver_new
returns
.Dv NULL
on
.Xr malloc 3
failures.
.Sh SEE ALSO
.Xr archive_entry 3

View File

@ -0,0 +1,88 @@
/*-
* 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 __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_ENTRY_LOCALE_H_INCLUDED
#define ARCHIVE_ENTRY_LOCALE_H_INCLUDED
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 *);
#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 */

View File

@ -0,0 +1,151 @@
.\" Copyright (c) 2010 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 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.
.\"
.Dd February 22, 2010
.Dt archive_entry_paths 3
.Os
.Sh NAME
.Nm archive_entry_hardlink ,
.Nm archive_entry_hardlink_w ,
.Nm archive_entry_set_hardlink ,
.Nm archive_entry_copy_hardlink ,
.Nm archive_entry_copy_hardlink_w ,
.Nm archve_entry_update_hardlink_utf8 ,
.Nm archive_entry_set_link ,
.Nm archive_entry_copy_link ,
.Nm archive_entry_copy_link_w ,
.Nm archve_entry_update_link_utf8 ,
.Nm archive_entry_pathname ,
.Nm archive_entry_pathname_w ,
.Nm archive_entry_set_pathname ,
.Nm archive_entry_copy_pathname ,
.Nm archive_entry_copy_pathname_w ,
.Nm archve_entry_update_pathname_utf8 ,
.Nm archive_entry_sourcepath ,
.Nm archive_entry_copy_sourcepath ,
.Nm archive_entry_symlink,
.Nm archive_entry_symlink_w,
.Nm archive_entry_set_symlink ,
.Nm archive_entry_copy_symlink ,
.Nm archive_entry_copy_symlink_w ,
.Nm archve_entry_update_symlink_utf8
.Nd functions for manipulating path names in archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft const char *
.Fn archive_entry_hardlink "struct archive_entry *a"
.Ft const wchar_t *
.Fn archive_entry_hardlink_w "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_hardlink "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_hardlink "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_hardlink_w "struct archive_entry *a "const wchar_t *path"
.Ft int
.Fn archive_entry_update_hardlink_utf8 "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_set_link "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_link "struct archive_entry *a" " const char *path"
.Ft void
.Fn archive_entry_copy_link_w "struct archive_entry *a" " const wchar_t *path"
.Ft int
.Fn archive_entry_update_link_utf8 "struct archive_entry *a" " const char *path"
.Ft const char *
.Fn archive_entry_pathname "struct archive_entry *a"
.Ft const wchar_t *
.Fn archive_entry_pathname_w "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_pathname "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_pathname "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_pathname_w "struct archive_entry *a" "const wchar_t *path"
.Ft int
.Fn archive_entry_update_pathname_utf8 "struct archive_entry *a" "const char *path"
.Ft const char *
.Fn archive_entry_sourcepath "struct archive_entry *a"
.Ft void
.Fn archive_entry_copy_sourcepath "struct archive_entry *a" "const char *path"
.Ft const char *
.Fn archive_entry_symlink "struct archive_entry *a"
.Ft const wchar_t *
.Fn archive_entry_symlink_w "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_symlink "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_symlink "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_symlink_w "struct archive_entry *a" "const wchar_t *path"
.Ft int
.Fn archive_entry_update_symlink_utf8 "struct archive_entry *a" "const char *path"
.Sh DESCRIPTION
Path names supported by
.Xr archive_entry 3 :
.Bl -tag -width "sourcepath" -compact
.It hardlink
Destination of the hardlink.
.It link
Update only.
For a symlink, update the destination.
Otherwise, make the entry a hardlink and alter
the destination for that.
.It pathname
Path in the archive
.It sourcepath
Path on the disk for use by
.Xr archive_read_disk 3 .
.It symlink
Destination of the symbolic link.
.El
.Pp
Path names can be provided in one of three different ways:
.Bl -tag -width "wchar_t *"
.It char *
Multibyte strings in the current locale.
.It wchar_t *
Wide character strings in the current locale.
The accessor functions are named
.Fn XXX_w .
.It UTF-8
Unicode strings encoded as UTF-8.
This are convience functions to update both the multibyte and wide
character strings at the same time.
.El
.Pp
The sourcepath is a pure filesystem concept and never stored in an
archive directly.
.Pp
For that reason, it is only available as multibyte string.
The link path is a convience function for conditionally setting
hardlink or symlink destination.
It doesn't have a corresponding get accessor function.
.Pp
.Fn archive_entry_set_XXX
is an alias for
.Fn archive_entry_copy_XXX .
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry 3

View File

@ -0,0 +1,207 @@
.\" Copyright (c) 2003-2007 Tim Kientzle
.\" Copyright (c) 2010 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 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.
.\"
.Dd February 22, 2010
.Dt archive_entry_perms 3
.Os
.Sh NAME
.Nm archive_entry_gid ,
.Nm archive_entry_set_gid ,
.Nm archive_entry_uid ,
.Nm archive_entry_set_uid ,
.Nm archive_entry_perm ,
.Nm archive_entry_set_perm ,
.Nm archive_entry_strmode ,
.Nm archive_entry_uname
.Nm archive_entry_uname_w
.Nm archive_entry_set_uname ,
.Nm archive_entry_copy_uname ,
.Nm archive_entry_copy_uname_w ,
.Nm archive_entry_update_uname_utf8 ,
.Nm archive_entry_gname ,
.Nm archive_entry_gname_w ,
.Nm archive_entry_set_gname ,
.Nm archive_entry_copy_gname ,
.Nm archive_entry_copy_gname_w ,
.Nm archive_entry_update_gname_utf8 ,
.Nm archive_entry_fflags ,
.Nm archive_entry_fflags_text ,
.Nm archive_entry_set_fflags ,
.Nm archive_entry_copy_fflags_text ,
.Nm archive_entry_copy_fflags_text_w
.Nd functions for manipulating ownership and permissions in archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft gid_t
.Fn archive_entry_gid "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_gid "struct archive_entry *a" "gid_t gid"
.Ft uid_t
.Fn archive_entry_uid "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_uid "struct archive_entry *a" "uid_t uid"
.Ft mode_t
.Fn archive_entry_perm "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_perm "struct archive_entry *a" "mode_t mode"
.Ft const char *
.Fn archive_entry_strmode "struct archive_entry *a"
.Ft const char *
.Fn archive_entry_gname "struct archive_entry *a"
.Ft const wchar_t *
.Fn archive_entry_gname_w "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_gname "struct archive_entry *a" "const char *a"
.Ft void
.Fn archive_entry_copy_gname "struct archive_entry *a" "const char *name"
.Ft void
.Fn archive_entry_copy_gname_w "struct archive_entry *a" "const wchar_t *name"
.Ft int
.Fn archive_entry_update_gname_utf8 "struct archive_entry *a" "const char *name"
.Ft const char *
.Fn archive_entry_uname "struct archive_entry *a"
.Ft const wchar_t *
.Fn archive_entry_uname_w "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_uname "struct archive_entry *a" "const char *name"
.Ft void
.Fn archive_entry_copy_uname "struct archive_entry *a" "const char *name"
.Ft void
.Fn archive_entry_copy_uname_w "struct archive_entry *a" "const wchar_t *name"
.Ft int
.Fn archive_entry_update_uname_utf8 "struct archive_entry *a" "const char *name"
.Ft void
.Fo archive_entry_fflags
.Fa "struct archive_entry *a"
.Fa "unsigned long *set_bits"
.Fa "unsigned long *clear_bits"
.Fc
.Ft const char *
.Fn archive_entry_fflags_text "struct archive_entry *a"
.Ft void
.Fo archive_entry_set_fflags
.Fa "struct archive_entry *a"
.Fa "unsigned long set_bits"
.Fa "unsigned long clear_bits"
.Fc
.Ft const char *
.Fn archive_entry_copy_fflags_text "struct archive_entry *a" "const char *text"
.Ft const wchar_t *
.Fn archive_entry_copy_fflags_text_w "struct archive_entry *a" "const wchar_t *text"
.Sh DESCRIPTION
.Ss User id, group id and mode
The functions
.Fn archive_entry_uid ,
.Fn archive_entry_gid ,
and
.Fn archive_entry_perm
can be used to extract the user id, group id and permission from the given entry.
The corresponding functions
.Fn archive_entry_set_uid ,
.Fn archive_entry_set_gid ,
and
.Fn archive_entry_set_perm
store the given user id, group id and permission in the entry.
The permission is also set as side effect of calling
.Fn archive_entry_set_mode .
.Pp
.Fn archive_entry_strmode
returns a string representation of the permission as used by the long mode of
.Xr ls 1 .
.Ss User and group name
User and group names can be provided in one of three different ways:
.Bl -tag -width "wchar_t *"
.It char *
Multibyte strings in the current locale.
.It wchar_t *
Wide character strings in the current locale.
The accessor functions are named
.Fn XXX_w .
.It UTF-8
Unicode strings encoded as UTF-8.
This are convience functions to update both the multibyte and wide
character strings at the same time.
.El
.Pp
.Fn archive_entry_set_XXX
is an alias for
.Fn archive_entry_copy_XXX .
.Ss File Flags
File flags are transparently converted between a bitmap
representation and a textual format.
For example, if you set the bitmap and ask for text, the library
will build a canonical text format.
However, if you set a text format and request a text format,
you will get back the same text, even if it is ill-formed.
If you need to canonicalize a textual flags string, you should first set the
text form, then request the bitmap form, then use that to set the bitmap form.
Setting the bitmap format will clear the internal text representation
and force it to be reconstructed when you next request the text form.
.Pp
The bitmap format consists of two integers, one containing bits
that should be set, the other specifying bits that should be
cleared.
Bits not mentioned in either bitmap will be ignored.
Usually, the bitmap of bits to be cleared will be set to zero.
In unusual circumstances, you can force a fully-specified set
of file flags by setting the bitmap of flags to clear to the complement
of the bitmap of flags to set.
(This differs from
.Xr fflagstostr 3 ,
which only includes names for set bits.)
Converting a bitmap to a textual string is a platform-specific
operation; bits that are not meaningful on the current platform
will be ignored.
.Pp
The canonical text format is a comma-separated list of flag names.
The
.Fn archive_entry_copy_fflags_text
and
.Fn archive_entry_copy_fflags_text_w
functions parse the provided text and sets the internal bitmap values.
This is a platform-specific operation; names that are not meaningful
on the current platform will be ignored.
The function returns a pointer to the start of the first name that was not
recognized, or NULL if every name was recognized.
Note that every name \(em including names that follow an unrecognized
name \(em will be evaluated, and the bitmaps will be set to reflect
every name that is recognized.
(In particular, this differs from
.Xr strtofflags 3 ,
which stops parsing at the first unrecognized name.)
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry 3 ,
.Xr archive_entry_acl 3 ,
.Xr archive_read_disk 3 ,
.Xr archive_write_disk 3
.Sh BUGS
The platform types
.Vt uid_t
and
.Vt gid_t
are often 16 or 32 bit wide.
In this case it is possible that the ids can not be correctly restored
from archives and get truncated.

View File

@ -0,0 +1,176 @@
/*-
* 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 __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED
#define ARCHIVE_ENTRY_PRIVATE_H_INCLUDED
#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;
};
/*
* 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. */
void *mac_metadata;
size_t mac_metadata_size;
/* 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];
};
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */

View File

@ -0,0 +1,156 @@
/*-
* 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,
int64_t offset, int64_t length)
{
struct ae_sparse *sp;
if (offset < 0 || length < 0)
/* Invalid value */
return;
if (offset + length < 0 ||
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,
int64_t *offset, 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
*/

View File

@ -0,0 +1,272 @@
.\" Copyright (c) 2010 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 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.
.\"
.Dd May 12, 2008
.Dt archive_entry 3
.Os
.Sh NAME
.Nm archive_entry_stat ,
.Nm archive_entry_copy_stat ,
.Nm archive_entry_filetype ,
.Nm archive_entry_set_filetype ,
.Nm archive_entry_mode ,
.Nm archive_entry_set_mode ,
.Nm archive_entry_size ,
.Nm archive_entry_size_is_set ,
.Nm archive_entry_set_size ,
.Nm archive_entry_unset_size ,
.Nm archive_entry_dev ,
.Nm archive_entry_set_dev ,
.Nm archive_entry_dev_is_set ,
.Nm archive_entry_devmajor ,
.Nm archive_entry_set_devmajor ,
.Nm archive_entry_devminor ,
.Nm archive_entry_set_devminor ,
.Nm archive_entry_ino ,
.Nm archive_entry_set_ino ,
.Nm archive_entry_ino_is_set ,
.Nm archive_entry_ino64 ,
.Nm archive_entry_set_ino64 ,
.Nm archive_entry_nlink ,
.Nm archive_entry_rdev ,
.Nm archive_entry_set_rdev ,
.Nm archive_entry_rdevmajor ,
.Nm archive_entry_set_rdevmajor ,
.Nm archive_entry_rdevminor ,
.Nm archive_entry_set_rdevminor ,
.Nd accessor functions for manipulating archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft const struct stat *
.Fn archive_entry_stat "struct archive_entry *a"
.Ft void
.Fn archive_entry_copy_stat "struct archive_entry *a" "const struct stat *sb"
.Ft mode_t
.Fn archive_entry_filetype "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_filetype "struct archive_entry *a" "unsigned int type"
.Ft mode_t
.Fn archive_entry_mode "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_mode "struct archive_entry *a" "mode_t mode"
.Ft int64_t
.Fn archive_entry_size "struct archive_entry *a"
.Ft int
.Fn archive_entry_size_is_set "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_size "struct archive_entry *a" "int64_t size"
.Ft void
.Fn archive_entry_unset_size "struct archive_entry *a"
.Ft dev_t
.Fn archive_entry_dev "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_dev "struct archive_entry *a" "dev_t dev"
.Ft int
.Fn archive_entry_dev_is_set "struct archive_entry *a"
.Ft dev_t
.Fn archive_entry_devmajor "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_devmajor "struct archive_entry *a" "dev_t major"
.Ft dev_t
.Fn archive_entry_devminor "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_devminor "struct archive_entry *a" "dev_t minor"
.Ft ino_t
.Fn archive_entry_ino "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_ino "struct archive_entry *a" "unsigned long ino"
.Ft int
.Fn archive_entry_ino_is_set "struct archive_entry *a"
.Ft int64_t
.Fn archive_entry_ino64 "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_ino64 "struct archive_entry *a" "int64_t ino"
.Ft unsigned int
.Fn archive_entry_nlink "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_nlink "struct archive_entry *a" "unsigned int count"
.Ft dev_t
.Fn archive_entry_rdev "struct archive_entry *a"
.Ft dev_t
.Fn archive_entry_rdevmajor "struct archive_entry *a"
.Ft dev_t
.Fn archive_entry_rdevminor "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_rdev "struct archive_entry *a" "dev_t dev"
.Ft void
.Fn archive_entry_set_rdevmajor "struct archive_entry *a" "dev_t major"
.Ft void
.Fn archive_entry_set_rdevminor "struct archive_entry *a" "dev_t minor"
.Sh DESCRIPTION
.Ss Copying to and from Vt struct stat
The function
.Fn archive_entry_stat
converts the various fields stored in the archive entry to the format
used by
.Xr stat 2 .
The return value remains valid until either
.Fn archive_entry_clear
or
.Fn archive_entry_free
is called.
It is not affected by calls to the set accessor functions.
It currently sets the following values in
.Vt struct stat :
.Vt st_atime ,
.Vt st_ctime ,
.Vt st_dev ,
.Vt st_gid ,
.Vt st_ino ,
.Vt st_mode ,
.Vt st_mtime ,
.Vt st_nlink ,
.Vt st_rdev ,
.Vt st_size ,
.Vt st_uid .
In addition,
.Vt st_birthtime
and high-precision information for time-related fields
will be included on platforms that support it.
.Pp
The function
.Fn archive_entry_copy_stat
copies fields from the platform's
.Vt struct stat .
Fields not provided by
.Vt struct stat
are unchanged.
.Ss General accessor functions
The functions
.Fn archive_entry_filetype
and
.Fn archive_entry_set_filetype
get respectively set the filetype.
The file type is one of the following constants:
.Bl -tag -width "AE_IFSOCK" -compact -offset indent
.It AE_IFREG
Regular file
.It AE_IFLNK
Symbolic link
.It AE_IFSOCK
Socket
.It AE_IFCHR
Character device
.It AE_IFBLK
Block device
.It AE_IFDIR
Directory
.It AE_IFIFO
Named pipe (fifo)
.El
Not all file types are supported by all platforms.
The constants used by
.Xr stat 2
may have different numeric values from the
corresponding constants above.
.Pp
The functions
.Fn archive_entry_mode
and
.Fn archive_entry_set_mode
get/set a combination of file type and permissions and provide the
equivalent of
.Va st_mode .
Use of
.Fn archive_entry_filetype
and
.Fn archive_entry_perm
for getting and
.Fn archive_entry_set_filetype
and
.Fn archive_entry_set_perm
for setting is recommended.
.Pp
The function
.Fn archive_entry_size
returns the file size, if it has been set, and 0 otherwise.
.Fn archive_entry_size
can be used to query that status.
.Fn archive_entry_set_size
and
.Fn archive_entry_unset_size
set and unset the size, respectively.
.Pp
The number of references (hardlinks) can be obtained by calling
.Fn archive_entry_nlinks
and set with
.Fn archive_entry_set_nlinks .
.Ss Identifying unique files
The functions
.Fn archive_entry_dev
and
.Fn archive_entry_ino64
are used by
.Xr archive_entry_linkify 3
to find hardlinks.
The pair of device and inode is suppossed to identify hardlinked files.
.Pp
The device major and minor number can be obtained independently using
.Fn archive_entry_devmajor
and
.Fn archive_entry_devminor .
The device can be set either via
.Fn archive_entry_set_dev
or by the combination of major and minor number using
.Fn archive_entry_set_devmajor
and
.Fn archive_entry_set_devminor .
.Pp
The inode number can be obtained using
.Fn archive_entry_ino .
This is a legacy interface that uses the platform
.Vt ino_t ,
which may be very small.
To set the inode number,
.Fn archive_entry_set_ino64
is the preferred interface.
.Ss Accessor functions for block and character devices
Block and character devices are characterised either using a device number
or a pair of major and minor number.
The combined device number can be obtained with
.Fn archive_device_rdev
and set with
.Fn archive_device_set_rdev .
The major and minor numbers are accessed by
.Fn archive_device_rdevmajor ,
.Fn archive_device_rdevminor
.Fn archive_device_set_rdevmajor
and
.Fn archive_device_set_rdevminor .
.Pp
The process of splitting the combined device number into major and
minor number and the reverse process of combing them differs between
platforms.
Some archive formats use the combined form, while other formats use
the split form.
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry_acl 3 ,
.Xr archive_entry_perms 3 ,
.Xr archive_entry_time 3 ,
.Xr stat 2

View File

@ -0,0 +1,118 @@
/*-
* 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 = archive_entry_gid(entry);
st->st_uid = archive_entry_uid(entry);
st->st_ino = archive_entry_ino64(entry);
st->st_nlink = archive_entry_nlink(entry);
st->st_rdev = archive_entry_rdev(entry);
st->st_size = 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 interchangably.
*/
entry->stat_valid = 1;
return (st);
}

View File

@ -0,0 +1,87 @@
/*-
* 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_count(entry, ARCHIVE_ENTRY_ACL_TYPE_ACCESS))
bp[10] = '+';
return (bp);
}

View File

@ -0,0 +1,127 @@
.\" Copyright (c) 2003-2007 Tim Kientzle
.\" Copyright (c) 2010 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 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: src/lib/libarchive/archive_entry.3,v 1.18 2008/05/26 17:00:22 kientzle Exp $
.\"
.Dd February 21, 2010
.Dt archive_entry_time 3
.Os
.Sh NAME
.Nm archive_entry_atime ,
.Nm archive_entry_atime_nsec ,
.Nm archive_entry_atime_is_set ,
.Nm archive_entry_set_atime ,
.Nm archive_entry_unset_atime ,
.Nm archive_entry_birthtime ,
.Nm archive_entry_birthtime_nsec ,
.Nm archive_entry_birthtime_is_set ,
.Nm archive_entry_set_birthtime ,
.Nm archive_entry_unset_birthtime ,
.Nm archive_entry_ctime ,
.Nm archive_entry_ctime_nsec ,
.Nm archive_entry_ctime_is_set ,
.Nm archive_entry_set_ctime ,
.Nm archive_entry_unset_ctime ,
.Nm archive_entry_mtime ,
.Nm archive_entry_mtime_nsec ,
.Nm archive_entry_mtime_is_set ,
.Nm archive_entry_set_mtime ,
.Nm archive_entry_unset_mtime ,
.Nd functions for manipulating times in archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft time_t
.Fn archive_entry_atime "struct archive_entry *a"
.Ft long
.Fn archive_entry_atime_nsec "struct archive_entry *a"
.Ft int
.Fn archive_entry_atime_is_set "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_atime "struct archive_entry *a" "time_t sec" "long nanosec"
.Ft void
.Fn archive_entry_unset_atime "struct archive_entry *a"
.Ft time_t
.Fn archive_entry_birthtime "struct archive_entry *a"
.Ft long
.Fn archive_entry_birthtime_nsec "struct archive_entry *a"
.Ft int
.Fn archive_entry_birthtime_is_set "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_birthtime "struct archive_entry *a" "time_t sec" "long nanosec"
.Ft void
.Fn archive_entry_unset_birthtime "struct archive_entry *a"
.Ft time_t
.Fn archive_entry_ctime "struct archive_entry *a"
.Ft long
.Fn archive_entry_ctime_nsec "struct archive_entry *a"
.Ft int
.Fn archive_entry_ctime_is_set "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_ctime "struct archive_entry *a" "time_t sec" "long nanosec"
.Ft void
.Fn archive_entry_unset_ctime "struct archive_entry *a"
.Ft time_t
.Fn archive_entry_mtime "struct archive_entry *a"
.Ft long
.Fn archive_entry_mtime_nsec "struct archive_entry *a"
.Ft int
.Fn archive_entry_mtime_is_set "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_mtime "struct archive_entry *a" "time_t sec" "long nanosec"
.Ft void
.Fn archive_entry_unset_mtime "struct archive_entry *a"
.Sh DESCRIPTION
These functions create and manipulate the time fields in an
.Vt archive_entry .
Supported time fields are atime (access time), birthtime (creation time),
ctime (last time an inode property was changed) and mtime (modification time).
.Pp
.Xr libarchive 3
provides a high-resolution interface.
The timestamps are truncated automatically depending on the archive format
(for archiving) or the filesystem capabilities (for restoring).
.Pp
All timestamp fields are optional.
The
.Fn XXX_unset
functions can be used to mark the corresponding field as missing.
The current state can be queried using
.Fn XXX_is_set .
Unset time fields have a second and nanosecond field of 0.
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry 3
.Sh HISTORY
The
.Nm libarchive
library first appeared in
.Fx 5.3 .
.Sh AUTHORS
.An -nosplit
The
.Nm libarchive
library was written by
.An Tim Kientzle Aq kientzle@acm.org .
.\" .Sh BUGS

View File

@ -0,0 +1,158 @@
/*-
* 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;
for (xp = entry->xattr_head; xp != NULL; xp = xp->next)
;
if ((xp = (struct ae_xattr *)malloc(sizeof(struct ae_xattr))) == NULL)
/* XXX Error XXX */
return;
xp->name = strdup(name);
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
*/

View File

@ -0,0 +1,164 @@
/*-
* 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_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;
archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
mp = m != NULL && m[0] == '\0' ? NULL : m;
op = o != NULL && o[0] == '\0' ? NULL : o;
vp = v != NULL && v[0] == '\0' ? NULL : v;
if (op == NULL && vp == NULL)
return (ARCHIVE_OK);
if (op == NULL)
return (ARCHIVE_FAILED);
return use_option(a, mp, op, vp);
}
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);
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, 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;
data = (char *)malloc(strlen(options) + 1);
strcpy(data, options);
s = (const char *)data;
do {
mod = opt = val = NULL;
parse_option(&s, &mod, &opt, &val);
r = use_option(a, mod, opt, val);
if (r == ARCHIVE_FATAL) {
free(data);
return (ARCHIVE_FATAL);
}
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;
}

View File

@ -0,0 +1,47 @@
/*-
* 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_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);

View File

@ -0,0 +1,165 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $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
/* 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"
#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 if we can */
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
/* If not, define it so as to avoid dangling semicolons. */
#ifndef __FBSDID
#define __FBSDID(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_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 this platform has <sys/acl.h>, acl_create(), acl_init(),
* acl_set_file(), and ACL_USER, we assume it has the rest of the
* POSIX.1e draft functions used in archive_read_extract.c.
*/
#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE && HAVE_ACL_USER
#define HAVE_POSIX_ACL 1
#endif
/*
* 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
/* 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
#endif /* !ARCHIVE_PLATFORM_H_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,119 @@
/* 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 __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_PPMD7_PRIVATE_H_INCLUDED
#define ARCHIVE_PPMD7_PRIVATE_H_INCLUDED
#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 (0xFFFFFFFF - 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, ISzAlloc *alloc);
void (*Ppmd7_Free)(CPpmd7 *p, ISzAlloc *alloc);
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

View File

@ -0,0 +1,158 @@
/* 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 __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_PPMD_PRIVATE_H_INCLUDED
#define ARCHIVE_PPMD_PRIVATE_H_INCLUDED
#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;
typedef struct
{
void *(*Alloc)(void *p, size_t size);
void (*Free)(void *p, void *address); /* address can be 0 */
} ISzAlloc;
/*** 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 i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \
p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }}
#endif

View File

@ -0,0 +1,150 @@
/*-
* 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 __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_PRIVATE_H_INCLUDED
#define ARCHIVE_PRIVATE_H_INCLUDED
#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
#define ARCHIVE_WRITE_MAGIC (0xb0c5c0deU)
#define ARCHIVE_READ_MAGIC (0xdeb0c5U)
#define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
#define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U)
#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.
*/
struct archive_vtable *vtable;
int archive_format;
const char *archive_format_name;
int compression_code; /* Currently active compression. */
const char *compression_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;
};
/* 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;
int __archive_mktemp(const char *tmpdir);
int __archive_clean(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

View File

@ -0,0 +1,701 @@
/*-
* 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;
*((const 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;
/*
* 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 greatgrandpa 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 childen would be opposite of
* our parent.
*/
standin_son = standin->rb_nodes[standin_which];
} else {
/*
* Since we aren't a child of self, any childen 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, sincef 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 evalate 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 simpliest 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 simpliest 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];
/*
* 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];
} 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.
*/
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 == 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;
}

View File

@ -0,0 +1,100 @@
/*-
* 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_
#define ARCHIVE_RB_H_
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_FOREACH(N, T) \
for ((N) = ARCHIVE_RB_TREE_MIN(T); (N); \
(N) = __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_RIGHT))
#define ARCHIVE_RB_TREE_FOREACH_REVERSE(N, T) \
for ((N) = ARCHIVE_RB_TREE_MAX(T); (N); \
(N) = __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_LEFT))
/*
* 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_*/

View File

@ -0,0 +1,250 @@
.\" Copyright (c) 2003-2007 Tim Kientzle
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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_read.3 191595 2009-04-27 20:13:13Z kientzle $
.\"
.Dd March 23, 2011
.Dt archive_read 3
.Os
.Sh NAME
.Nm archive_read
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Sh DESCRIPTION
These functions provide a complete API for reading streaming archives.
The general process is to first create the
.Tn struct archive
object, set options, initialize the reader, iterate over the archive
headers and associated data, then close the archive and release all
resources.
.\"
.Ss Create archive object
See
.Xr archive_read_new 3 .
.Pp
To read an archive, you must first obtain an initialized
.Tn struct archive
object from
.Fn archive_read_new .
.\"
.Ss Enable filters and formats
See
.Xr archive_read_filter 3
and
.Xr archive_read_format 3 .
.Pp
You can then modify this object for the desired operations with the
various
.Fn archive_read_set_XXX
and
.Fn archive_read_support_XXX
functions.
In particular, you will need to invoke appropriate
.Fn archive_read_support_XXX
functions to enable the corresponding compression and format
support.
Note that these latter functions perform two distinct operations:
they cause the corresponding support code to be linked into your
program, and they enable the corresponding auto-detect code.
Unless you have specific constraints, you will generally want
to invoke
.Fn archive_read_support_filter_all
and
.Fn archive_read_support_format_all
to enable auto-detect for all formats and compression types
currently supported by the library.
.\"
.Ss Set options
See
.Xr archive_read_set_options 3 .
.\"
.Ss Open archive
See
.Xr archive_read_open 3 .
.Pp
Once you have prepared the
.Tn struct archive
object, you call
.Fn archive_read_open
to actually open the archive and prepare it for reading.
There are several variants of this function;
the most basic expects you to provide pointers to several
functions that can provide blocks of bytes from the archive.
There are convenience forms that allow you to
specify a filename, file descriptor,
.Ft "FILE *"
object, or a block of memory from which to read the archive data.
Note that the core library makes no assumptions about the
size of the blocks read;
callback functions are free to read whatever block size is
most appropriate for the medium.
.\"
.Ss Consume archive
See
.Xr archive_read_header 3 ,
.Xr archive_read_data 3
and
.Xr archive_read_extract 3 .
.Pp
Each archive entry consists of a header followed by a certain
amount of data.
You can obtain the next header with
.Fn archive_read_next_header ,
which returns a pointer to an
.Tn struct archive_entry
structure with information about the current archive element.
If the entry is a regular file, then the header will be followed
by the file data.
You can use
.Fn archive_read_data
(which works much like the
.Xr read 2
system call)
to read this data from the archive, or
.Fn archive_read_data_block
which provides a slightly more efficient interface.
You may prefer to use the higher-level
.Fn archive_read_data_skip ,
which reads and discards the data for this entry,
.Fn archive_read_data_to_file ,
which copies the data to the provided file descriptor, or
.Fn archive_read_extract ,
which recreates the specified entry on disk and copies data
from the archive.
In particular, note that
.Fn archive_read_extract
uses the
.Tn struct archive_entry
structure that you provide it, which may differ from the
entry just read from the archive.
In particular, many applications will want to override the
pathname, file permissions, or ownership.
.\"
.Ss Release resources
See
.Xr archive_read_free 3 .
.Pp
Once you have finished reading data from the archive, you
should call
.Fn archive_read_close
to close the archive, then call
.Fn archive_read_free
to release all resources, including all memory allocated by the library.
.\"
.Sh EXAMPLE
The following illustrates basic usage of the library.
In this example,
the callback functions are simply wrappers around the standard
.Xr open 2 ,
.Xr read 2 ,
and
.Xr close 2
system calls.
.Bd -literal -offset indent
void
list_archive(const char *name)
{
struct mydata *mydata;
struct archive *a;
struct archive_entry *entry;
mydata = malloc(sizeof(struct mydata));
a = archive_read_new();
mydata->name = name;
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
archive_read_open(a, mydata, myopen, myread, myclose);
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
printf("%s\en",archive_entry_pathname(entry));
archive_read_data_skip(a);
}
archive_read_free(a);
free(mydata);
}
ssize_t
myread(struct archive *a, void *client_data, const void **buff)
{
struct mydata *mydata = client_data;
*buff = mydata->buff;
return (read(mydata->fd, mydata->buff, 10240));
}
int
myopen(struct archive *a, void *client_data)
{
struct mydata *mydata = client_data;
mydata->fd = open(mydata->name, O_RDONLY);
return (mydata->fd >= 0 ? ARCHIVE_OK : ARCHIVE_FATAL);
}
int
myclose(struct archive *a, void *client_data)
{
struct mydata *mydata = client_data;
if (mydata->fd > 0)
close(mydata->fd);
return (ARCHIVE_OK);
}
.Ed
.\" .Sh ERRORS
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read_new 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_extract 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_header 3 ,
.Xr archive_read_open 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5
.Sh HISTORY
The
.Nm libarchive
library first appeared in
.Fx 5.3 .
.Sh AUTHORS
.An -nosplit
The
.Nm libarchive
library was written by
.An Tim Kientzle Aq kientzle@acm.org .
.Sh BUGS
Many traditional archiver programs treat
empty files as valid empty archives.
For example, many implementations of
.Xr tar 1
allow you to append entries to an empty file.
Of course, it is impossible to determine the format of an empty file
by inspecting the contents, so this library treats empty files as
having a special
.Dq empty
format.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,142 @@
.\" 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 AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd March 22, 2011
.Dt archive_read_data 3
.Os
.Sh NAME
.Nm archive_read_data
.Nm archive_read_data_block ,
.Nm archive_read_data_skip ,
.\" #if ARCHIVE_API_VERSION < 3
.Nm archive_read_data_into_buffer ,
.\" #endif
.Nm archive_read_data_into_fd
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft ssize_t
.Fn archive_read_data "struct archive *" "void *buff" "size_t len"
.Ft int
.Fo archive_read_data_block
.Fa "struct archive *"
.Fa "const void **buff"
.Fa "size_t *len"
.Fa "off_t *offset"
.Fc
.Ft int
.Fn archive_read_data_skip "struct archive *"
.\" #if ARCHIVE_API_VERSION < 3
.Ft int
.Fn archive_read_data_into_buffer "struct archive *" "void *" "ssize_t len"
.\" #endif
.Ft int
.Fn archive_read_data_into_fd "struct archive *" "int fd"
.\"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Fn archive_read_data
Read data associated with the header just read.
Internally, this is a convenience function that calls
.Fn archive_read_data_block
and fills any gaps with nulls so that callers see a single
continuous stream of data.
.It Fn archive_read_data_block
Return the next available block of data for this entry.
Unlike
.Fn archive_read_data ,
the
.Fn archive_read_data_block
function avoids copying data and allows you to correctly handle
sparse files, as supported by some archive formats.
The library guarantees that offsets will increase and that blocks
will not overlap.
Note that the blocks returned from this function can be much larger
than the block size read from disk, due to compression
and internal buffer optimizations.
.It Fn archive_read_data_skip
A convenience function that repeatedly calls
.Fn archive_read_data_block
to skip all of the data for this archive entry.
Note that this function is invoked automatically by
.Fn archive_read_next_header2
if the previous entry was not completely consumed.
.\" #if ARCHIVE_API_VERSION < 3
.It Fn archive_read_data_into_buffer
This function is deprecated and will be removed.
Use
.Fn archive_read_data
instead.
.\" #endif
.It Fn archive_read_data_into_fd
A convenience function that repeatedly calls
.Fn archive_read_data_block
to copy the entire entry to the provided file descriptor.
.El
.\"
.Sh RETURN VALUES
Most functions return zero on success, non-zero on error.
The possible return codes include:
.Cm ARCHIVE_OK
(the operation succeeded),
.Cm ARCHIVE_WARN
(the operation succeeded but a non-critical error was encountered),
.Cm ARCHIVE_EOF
(end-of-archive was encountered),
.Cm ARCHIVE_RETRY
(the operation failed but can be retried),
and
.Cm ARCHIVE_FATAL
(there was a fatal error; the archive should be closed immediately).
.Pp
.Fn archive_read_data
returns a count of bytes actually read or zero at the end of the entry.
On error, a value of
.Cm ARCHIVE_FATAL ,
.Cm ARCHIVE_WARN ,
or
.Cm ARCHIVE_RETRY
is returned.
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read 3 ,
.Xr archive_read_extract 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_header 3 ,
.Xr archive_read_open 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5

View File

@ -0,0 +1,139 @@
/*-
* 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.
*/
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 + 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);
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);
}

View File

@ -0,0 +1,315 @@
.\" 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 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_read_disk.3 190957 2009-04-12 05:04:02Z kientzle $
.\"
.Dd March 10, 2009
.Dt archive_read_disk 3
.Os
.Sh NAME
.Nm archive_read_disk_new ,
.Nm archive_read_disk_set_symlink_logical ,
.Nm archive_read_disk_set_symlink_physical ,
.Nm archive_read_disk_set_symlink_hybrid ,
.Nm archive_read_disk_entry_from_file ,
.Nm archive_read_disk_gname ,
.Nm archive_read_disk_uname ,
.Nm archive_read_disk_set_uname_lookup ,
.Nm archive_read_disk_set_gname_lookup ,
.Nm archive_read_disk_set_standard_lookup ,
.Nm archive_read_close ,
.Nm archive_read_finish ,
.Nm archive_read_free
.Nd functions for reading objects from disk
.Sh SYNOPSIS
.In archive.h
.Ft struct archive *
.Fn archive_read_disk_new "void"
.Ft int
.Fn archive_read_disk_set_symlink_logical "struct archive *"
.Ft int
.Fn archive_read_disk_set_symlink_physical "struct archive *"
.Ft int
.Fn archive_read_disk_set_symlink_hybrid "struct archive *"
.Ft int
.Fn archive_read_disk_gname "struct archive *" "gid_t"
.Ft int
.Fn archive_read_disk_uname "struct archive *" "uid_t"
.Ft int
.Fo archive_read_disk_set_gname_lookup
.Fa "struct archive *"
.Fa "void *"
.Fa "const char *(*lookup)(void *, gid_t)"
.Fa "void (*cleanup)(void *)"
.Fc
.Ft int
.Fo archive_read_disk_set_uname_lookup
.Fa "struct archive *"
.Fa "void *"
.Fa "const char *(*lookup)(void *, uid_t)"
.Fa "void (*cleanup)(void *)"
.Fc
.Ft int
.Fn archive_read_disk_set_standard_lookup "struct archive *"
.Ft int
.Fo archive_read_disk_entry_from_file
.Fa "struct archive *"
.Fa "struct archive_entry *"
.Fa "int fd"
.Fa "const struct stat *"
.Fc
.Ft int
.Fn archive_read_close "struct archive *"
.Ft int
.Fn archive_read_finish "struct archive *"
.Ft int
.Fn archive_read_free "struct archive *"
.Sh DESCRIPTION
These functions provide an API for reading information about
objects on disk.
In particular, they provide an interface for populating
.Tn struct archive_entry
objects.
.Bl -tag -width indent
.It Fn archive_read_disk_new
Allocates and initializes a
.Tn struct archive
object suitable for reading object information from disk.
.It Xo
.Fn archive_read_disk_set_symlink_logical ,
.Fn archive_read_disk_set_symlink_physical ,
.Fn archive_read_disk_set_symlink_hybrid
.Xc
This sets the mode used for handling symbolic links.
The
.Dq logical
mode follows all symbolic links.
The
.Dq physical
mode does not follow any symbolic links.
The
.Dq hybrid
mode currently behaves identically to the
.Dq logical
mode.
.It Xo
.Fn archive_read_disk_gname ,
.Fn archive_read_disk_uname
.Xc
Returns a user or group name given a gid or uid value.
By default, these always return a NULL string.
.It Xo
.Fn archive_read_disk_set_gname_lookup ,
.Fn archive_read_disk_set_uname_lookup
.Xc
These allow you to override the functions used for
user and group name lookups.
You may also provide a
.Tn void *
pointer to a private data structure and a cleanup function for
that data.
The cleanup function will be invoked when the
.Tn struct archive
object is destroyed or when new lookup functions are registered.
.It Fn archive_read_disk_set_standard_lookup
This convenience function installs a standard set of user
and group name lookup functions.
These functions use
.Xr getpwuid 3
and
.Xr getgrgid 3
to convert ids to names, defaulting to NULL if the names cannot
be looked up.
These functions also implement a simple memory cache to reduce
the number of calls to
.Xr getpwuid 3
and
.Xr getgrgid 3 .
.It Fn archive_read_disk_entry_from_file
Populates a
.Tn struct archive_entry
object with information about a particular file.
The
.Tn archive_entry
object must have already been created with
.Xr archive_entry_new 3
and at least one of the source path or path fields must already be set.
(If both are set, the source path will be used.)
.Pp
Information is read from disk using the path name from the
.Tn struct archive_entry
object.
If a file descriptor is provided, some information will be obtained using
that file descriptor, on platforms that support the appropriate
system calls.
.Pp
If a pointer to a
.Tn struct stat
is provided, information from that structure will be used instead
of reading from the disk where appropriate.
This can provide performance benefits in scenarios where
.Tn struct stat
information has already been read from the disk as a side effect
of some other operation.
(For example, directory traversal libraries often provide this information.)
.Pp
Where necessary, user and group ids are converted to user and group names
using the currently registered lookup functions above.
This affects the file ownership fields and ACL values in the
.Tn struct archive_entry
object.
.It Fn archive_read_close
Does nothing for
.Tn archive_read_disk
handles.
.It Fn archive_read_finish
This is a deprecated synonym for
.Fn archive_read_free .
.It Fn archive_read_free
Invokes
.Fn archive_read_close
if it was not invoked manually, then releases all resources.
.El
More information about the
.Va struct archive
object and the overall design of the library can be found in the
.Xr libarchive 3
overview.
.Sh EXAMPLE
The following illustrates basic usage of the library by
showing how to use it to copy an item on disk into an archive.
.Bd -literal -offset indent
void
file_to_archive(struct archive *a, const char *name)
{
char buff[8192];
size_t bytes_read;
struct archive *ard;
struct archive_entry *entry;
int fd;
ard = archive_read_disk_new();
archive_read_disk_set_standard_lookup(ard);
entry = archive_entry_new();
fd = open(name, O_RDONLY);
if (fd < 0)
return;
archive_entry_copy_pathname(entry, name);
archive_read_disk_entry_from_file(ard, entry, fd, NULL);
archive_write_header(a, entry);
while ((bytes_read = read(fd, buff, sizeof(buff))) > 0)
archive_write_data(a, buff, bytes_read);
archive_write_finish_entry(a);
archive_read_free(ard);
archive_entry_free(entry);
}
.Ed
.Sh RETURN VALUES
Most functions return
.Cm ARCHIVE_OK
(zero) on success, or one of several negative
error codes for errors.
Specific error codes include:
.Cm ARCHIVE_RETRY
for operations that might succeed if retried,
.Cm ARCHIVE_WARN
for unusual conditions that do not prevent further operations, and
.Cm ARCHIVE_FATAL
for serious errors that make remaining operations impossible.
.Pp
.Fn archive_read_disk_new
returns a pointer to a newly-allocated
.Tn struct archive
object or NULL if the allocation failed for any reason.
.Pp
.Fn archive_read_disk_gname
and
.Fn archive_read_disk_uname
return
.Tn const char *
pointers to the textual name or NULL if the lookup failed for any reason.
The returned pointer points to internal storage that
may be reused on the next call to either of these functions;
callers should copy the string if they need to continue accessing it.
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr archive_read 3 ,
.Xr archive_util 3 ,
.Xr archive_write 3 ,
.Xr archive_write_disk 3 ,
.Xr tar 1 ,
.Xr libarchive 3
.Sh HISTORY
The
.Nm libarchive
library first appeared in
.Fx 5.3 .
The
.Nm archive_read_disk
interface was added to
.Nm libarchive 2.6
and first appeared in
.Fx 8.0 .
.Sh AUTHORS
.An -nosplit
The
.Nm libarchive
library was written by
.An Tim Kientzle Aq kientzle@freebsd.org .
.Sh BUGS
The
.Dq standard
user name and group name lookup functions are not the defaults because
.Xr getgrgid 3
and
.Xr getpwuid 3
are sometimes too large for particular applications.
The current design allows the application author to use a more
compact implementation when appropriate.
.Pp
The full list of metadata read from disk by
.Fn archive_read_disk_entry_from_file
is necessarily system-dependent.
.Pp
The
.Fn archive_read_disk_entry_from_file
function reads as much information as it can from disk.
Some method should be provided to limit this so that clients who
do not need ACLs, for instance, can avoid the extra work needed
to look up such information.
.Pp
This API should provide a set of methods for walking a directory tree.
That would make it a direct parallel of the
.Xr archive_read 3
API.
When such methods are implemented, the
.Dq hybrid
symbolic link mode will make sense.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,71 @@
/*-
* 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 __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
#define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
struct tree;
struct archive_read_disk {
struct archive archive;
/*
* 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;
/* Set 1 if users request to restore atime . */
int restore_time;
int entry_wd_fd;
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;
};
#endif

View File

@ -0,0 +1,311 @@
/*-
* 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 resolveers, etc). This can easily top 500kB, which makes
* it inappropriate for some space-constrained applications.
*
* Applications that are size-sensitive may want to just use the
* real default functions (defined in archive_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;
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;
result = getgrgid((gid_t)id);
if (result == NULL)
return (NULL);
return strdup(result->gr_name);
}
#endif
#endif /* ! (_WIN32 && !__CYGWIN__) */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,135 @@
.\" 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 AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd March 22, 2011
.Dt archive_read_extract 3
.Os
.Sh NAME
.Nm archive_read_extract ,
.Nm archive_read_extract2 ,
.Nm archive_read_extract_set_progress_callback
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fo archive_read_extract
.Fa "struct archive *"
.Fa "struct archive_entry *"
.Fa "int flags"
.Fc
.Ft int
.Fo archive_read_extract2
.Fa "struct archive *src"
.Fa "struct archive_entry *"
.Fa "struct archive *dest"
.Fc
.Ft void
.Fo archive_read_extract_set_progress_callback
.Fa "struct archive *"
.Fa "void (*func)(void *)"
.Fa "void *user_data"
.Fc
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Fn archive_read_extract , Fn archive_read_extract_set_skip_file
A convenience function that wraps the corresponding
.Xr archive_write_disk 3
interfaces.
The first call to
.Fn archive_read_extract
creates a restore object using
.Xr archive_write_disk_new 3
and
.Xr archive_write_disk_set_standard_lookup 3 ,
then transparently invokes
.Xr archive_write_disk_set_options 3 ,
.Xr archive_write_header 3 ,
.Xr archive_write_data 3 ,
and
.Xr archive_write_finish_entry 3
to create the entry on disk and copy data into it.
The
.Va flags
argument is passed unmodified to
.Xr archive_write_disk_set_options 3 .
.It Fn archive_read_extract2
This is another version of
.Fn archive_read_extract
that allows you to provide your own restore object.
In particular, this allows you to override the standard lookup functions
using
.Xr archive_write_disk_set_group_lookup 3 ,
and
.Xr archive_write_disk_set_user_lookup 3 .
Note that
.Fn archive_read_extract2
does not accept a
.Va flags
argument; you should use
.Fn archive_write_disk_set_options
to set the restore options yourself.
.It Fn archive_read_extract_set_progress_callback
Sets a pointer to a user-defined callback that can be used
for updating progress displays during extraction.
The progress function will be invoked during the extraction of large
regular files.
The progress function will be invoked with the pointer provided to this call.
Generally, the data pointed to should include a reference to the archive
object and the archive_entry object so that various statistics
can be retrieved for the progress display.
.El
.\"
.Sh RETURN VALUES
Most functions return zero on success, non-zero on error.
The possible return codes include:
.Cm ARCHIVE_OK
(the operation succeeded),
.Cm ARCHIVE_WARN
(the operation succeeded but a non-critical error was encountered),
.Cm ARCHIVE_EOF
(end-of-archive was encountered),
.Cm ARCHIVE_RETRY
(the operation failed but can be retried),
and
.Cm ARCHIVE_FATAL
(there was a fatal error; the archive should be closed immediately).
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_open 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5

View File

@ -0,0 +1,183 @@
/*-
* 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_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_read_private.h"
#include "archive_write_disk_private.h"
struct extract {
struct archive *ad; /* archive_write_disk object */
/* Progress function invoked during extract. */
void (*extract_progress)(void *);
void *extract_progress_user_data;
};
static int archive_read_extract_cleanup(struct archive_read *);
static int copy_data(struct archive *ar, struct archive *aw);
static struct extract *get_extract(struct archive_read *);
static struct extract *
get_extract(struct archive_read *a)
{
/* If we haven't initialized, do it now. */
/* This also sets up a lot of global state. */
if (a->extract == NULL) {
a->extract = (struct extract *)malloc(sizeof(*a->extract));
if (a->extract == NULL) {
archive_set_error(&a->archive, ENOMEM, "Can't extract");
return (NULL);
}
memset(a->extract, 0, sizeof(*a->extract));
a->extract->ad = archive_write_disk_new();
if (a->extract->ad == NULL) {
archive_set_error(&a->archive, ENOMEM, "Can't extract");
return (NULL);
}
archive_write_disk_set_standard_lookup(a->extract->ad);
a->cleanup_archive_extract = archive_read_extract_cleanup;
}
return (a->extract);
}
int
archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags)
{
struct extract *extract;
extract = get_extract((struct archive_read *)_a);
if (extract == NULL)
return (ARCHIVE_FATAL);
archive_write_disk_set_options(extract->ad, flags);
return (archive_read_extract2(_a, entry, extract->ad));
}
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 extract *extract = 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 extract *extract;
size_t size;
int r;
extract = 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 = 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);
}
}
/*
* Cleanup function for archive_extract.
*/
static int
archive_read_extract_cleanup(struct archive_read *a)
{
int ret = ARCHIVE_OK;
ret = archive_write_free(a->extract->ad);
free(a->extract);
a->extract = NULL;
return (ret);
}

View File

@ -0,0 +1,127 @@
.\" 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 AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd March 19, 2011
.Dt archive_read_filter 3
.Os
.Sh NAME
.Nm archive_read_support_filter_all ,
.Nm archive_read_support_filter_bzip2 ,
.Nm archive_read_support_filter_compress ,
.Nm archive_read_support_filter_gzip ,
.Nm archive_read_support_filter_lzma ,
.Nm archive_read_support_filter_none ,
.Nm archive_read_support_filter_xz ,
.Nm archive_read_support_filter_program ,
.Nm archive_read_support_filter_program_signature
.Nd functions for reading streaming archives
.\"
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fn archive_read_support_filter_all "struct archive *"
.Ft int
.Fn archive_read_support_filter_bzip2 "struct archive *"
.Ft int
.Fn archive_read_support_filter_compress "struct archive *"
.Ft int
.Fn archive_read_support_filter_gzip "struct archive *"
.Ft int
.Fn archive_read_support_filter_lzma "struct archive *"
.Ft int
.Fn archive_read_support_filter_none "struct archive *"
.Ft int
.Fn archive_read_support_filter_xz "struct archive *"
.Ft int
.Fo archive_read_support_filter_program
.Fa "struct archive *"
.Fa "const char *cmd"
.Fc
.Ft int
.Fo archive_read_support_filter_program_signature
.Fa "struct archive *"
.Fa "const char *cmd"
.Fa "const void *signature"
.Fa "size_t signature_length"
.Fc
.\"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Xo
.Fn archive_read_support_filter_bzip2 ,
.Fn archive_read_support_filter_compress ,
.Fn archive_read_support_filter_gzip ,
.Fn archive_read_support_filter_lzma ,
.Fn archive_read_support_filter_none ,
.Fn archive_read_support_filter_xz
.Xc
Enables auto-detection code and decompression support for the
specified compression.
These functions may fall back on external programs if an appropriate
library was not available at build time.
Decompression using an external program is usually slower than
decompression through built-in libraries.
Note that
.Dq none
is always enabled by default.
.It Fn archive_read_support_filter_all
Enables all available decompression filters.
.It Fn archive_read_support_filter_program
Data is fed through the specified external program before being dearchived.
Note that this disables automatic detection of the compression format,
so it makes no sense to specify this in conjunction with any other
decompression option.
.It Fn archive_read_support_filter_program_signature
This feeds data through the specified external program
but only if the initial bytes of the data match the specified
signature value.
.El
.\"
.\". Sh EXAMPLE
.\"
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
if the compression is fully supported,
.Cm ARCHIVE_WARN
if the compression is supported only through an external program.
.Pp
.Fn archive_read_support_filter_none
always succeeds.
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr libarchive 3 ,
.Xr archive_read 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_format 3

View File

@ -0,0 +1,175 @@
.\" 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 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_read.3 191595 2009-04-27 20:13:13Z kientzle $
.\"
.Dd March 19, 2011
.Dt archive_read_format 3
.Os
.Sh NAME
.Nm archive_read_support_format_7zip ,
.Nm archive_read_support_format_all ,
.Nm archive_read_support_format_ar ,
.Nm archive_read_support_format_by_code ,
.Nm archive_read_support_format_cab ,
.Nm archive_read_support_format_cpio ,
.Nm archive_read_support_format_empty ,
.Nm archive_read_support_format_iso9660 ,
.Nm archive_read_support_format_lha ,
.Nm archive_read_support_format_mtree,
.Nm archive_read_support_format_rar,
.Nm archive_read_support_format_raw,
.Nm archive_read_support_format_tar ,
.Nm archive_read_support_format_xar ,
.Nm archive_read_support_format_zip
.Nd functions for reading streaming archives
.\"
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fn archive_read_support_format_7zip "struct archive *"
.Ft int
.Fn archive_read_support_format_all "struct archive *"
.Ft int
.Fn archive_read_support_format_ar "struct archive *"
.Ft int
.Fn archive_read_support_format_by_code "struct archive *" "int"
.Ft int
.Fn archive_read_support_format_cab "struct archive *"
.Ft int
.Fn archive_read_support_format_cpio "struct archive *"
.Ft int
.Fn archive_read_support_format_empty "struct archive *"
.Ft int
.Fn archive_read_support_format_iso9660 "struct archive *"
.Ft int
.Fn archive_read_support_format_lha "struct archive *"
.Ft int
.Fn archive_read_support_format_mtree "struct archive *"
.Ft int
.Fn archive_read_support_format_rar "struct archive *"
.Ft int
.Fn archive_read_support_format_raw "struct archive *"
.Ft int
.Fn archive_read_support_format_tar "struct archive *"
.Ft int
.Fn archive_read_support_format_xar "struct archive *"
.Ft int
.Fn archive_read_support_format_zip "struct archive *"
.\"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Xo
.Fn archive_read_support_format_7zip ,
.Fn archive_read_support_format_ar ,
.Fn archive_read_support_format_cab ,
.Fn archive_read_support_format_cpio ,
.Fn archive_read_support_format_iso9660 ,
.Fn archive_read_support_format_lha ,
.Fn archive_read_support_format_mtree ,
.Fn archive_read_support_format_rar ,
.Fn archive_read_support_format_raw ,
.Fn archive_read_support_format_tar ,
.Fn archive_read_support_format_xar ,
.Fn archive_read_support_format_zip
.Xc
Enables support---including auto-detection code---for the
specified archive format.
For example,
.Fn archive_read_support_format_tar
enables support for a variety of standard tar formats, old-style tar,
ustar, pax interchange format, and many common variants.
.It Fn archive_read_support_format_all
Enables support for all available formats except the
.Dq raw
format (see below).
.It Fn archive_read_support_format_by_code
Enables a single format specified by the format code.
This can be useful when reading a single archive twice;
use
.Fn archive_format
after reading the first time and pass the resulting code
to this function to selectively enable only the necessary
format support.
Note: In statically-linked executables, this will cause
your program to include support for every format.
If executable size is a concern, you may wish to avoid
using this function.
.It Fn archive_read_support_format_empty
Enables support for treating empty files as empty archives.
Because empty files are valid for several different formats,
it is not possible to accurately determine a format for
an empty file based purely on contents.
So empty files are treated by libarchive as a distinct
format.
.It Fn archive_read_support_format_raw
The
.Dq raw
format handler allows libarchive to be used to read arbitrary data.
It treats any data stream as an archive with a single entry.
The pathname of this entry is
.Dq data ;
all other entry fields are unset.
This is not enabled by
.Fn archive_read_support_format_all
in order to avoid erroneous handling of damaged archives.
.El
.\" .Sh EXAMPLE
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
on success, or
.Cm ARCHIVE_FATAL .
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5
.Sh BUGS
Many traditional archiver programs treat
empty files as valid empty archives.
For example, many implementations of
.Xr tar 1
allow you to append entries to an empty file.
Of course, it is impossible to determine the format of an empty file
by inspecting the contents, so this library treats empty files as
having a special
.Dq empty
format.
.Pp
Using the
.Dq raw
handler together with any other handler will often work
but can produce surprising results.

View File

@ -0,0 +1,91 @@
.\" 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 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_read.3 191595 2009-04-27 20:13:13Z kientzle $
.\"
.Dd March 20, 2011
.Dt archive_read_free 3
.Os
.Sh NAME
.Nm archive_read_close ,
.Nm archive_read_finish ,
.Nm archive_read_free
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fn archive_read_close "struct archive *"
.Ft int
.Fn archive_read_finish "struct archive *"
.Ft int
.Fn archive_read_free "struct archive *"
.\"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Fn archive_read_close
Complete the archive and invoke the close callback.
.It Fn archive_read_finish
This is a deprecated synonym for
.Fn archive_read_free .
The new name was introduced with libarchive 3.0.
Applications that need to compile with either libarchive 2
or libarchive 3 should continue to use the
.Fn archive_read_finish
name.
Both names will be supported until libarchive 4.0 is
released, which is not expected to occur earlier
than 2013.
.It Fn archive_read_free
Invokes
.Fn archive_read_close
if it was not invoked manually, then release all resources.
Note: In libarchive 1.x, this function was declared to return
.Ft void ,
which made it impossible to detect certain errors when
.Fn archive_read_close
was invoked implicitly from this function.
The declaration is corrected beginning with libarchive 2.0.
.El
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
on success, or
.Cm ARCHIVE_FATAL .
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr libarchive 3 ,
.Xr archive_read_new 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_open 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3

View File

@ -0,0 +1,89 @@
.\" 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 AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd March 22, 2011
.Dt archive_read_header 3
.Os
.Sh NAME
.Nm archive_read_next_header ,
.Nm archive_read_next_header2
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fn archive_read_next_header "struct archive *" "struct archive_entry **"
.Ft int
.Fn archive_read_next_header2 "struct archive *" "struct archive_entry *"
.\"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Fn archive_read_next_header
Read the header for the next entry and return a pointer to
a
.Tn struct archive_entry .
This is a convenience wrapper around
.Fn archive_read_next_header2
that reuses an internal
.Tn struct archive_entry
object for each request.
.It Fn archive_read_next_header2
Read the header for the next entry and populate the provided
.Tn struct archive_entry .
.El
.\"
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
(the operation succeeded),
.Cm ARCHIVE_WARN
(the operation succeeded but a non-critical error was encountered),
.Cm ARCHIVE_EOF
(end-of-archive was encountered),
.Cm ARCHIVE_RETRY
(the operation failed but can be retried),
and
.Cm ARCHIVE_FATAL
(there was a fatal error; the archive should be closed immediately).
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_extract 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_open 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5

View File

@ -0,0 +1,57 @@
.\" 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 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_read.3 191595 2009-04-27 20:13:13Z kientzle $
.\"
.Dd March 20, 2011
.Dt archive_read_new 3
.Os
.Sh NAME
.Nm archive_read_new
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft struct archive *
.Fn archive_read_new "void"
.Sh DESCRIPTION
Allocates and initializes a
.Tn struct archive
object suitable for reading from an archive.
.Dv NULL
is returned on error.
.Pp
A complete description of the
.Tn struct archive
object can be found in the overview manual page for
.Xr libarchive 3 .
.\" .Sh ERRORS
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5

View File

@ -0,0 +1,231 @@
.\" 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 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_read.3 191595 2009-04-27 20:13:13Z kientzle $
.\"
.Dd March 19, 2011
.Dt archive_read_open 3
.Os
.Sh NAME
.Nm archive_read_open ,
.Nm archive_read_open2 ,
.Nm archive_read_open_fd ,
.Nm archive_read_open_FILE ,
.Nm archive_read_open_filename ,
.Nm archive_read_open_memory ,
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fo archive_read_open
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "archive_open_callback *"
.Fa "archive_read_callback *"
.Fa "archive_close_callback *"
.Fc
.Ft int
.Fo archive_read_open2
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "archive_open_callback *"
.Fa "archive_read_callback *"
.Fa "archive_skip_callback *"
.Fa "archive_close_callback *"
.Fc
.Ft int
.Fn archive_read_open_FILE "struct archive *" "FILE *file"
.Ft int
.Fn archive_read_open_fd "struct archive *" "int fd" "size_t block_size"
.Ft int
.Fo archive_read_open_filename
.Fa "struct archive *"
.Fa "const char *filename"
.Fa "size_t block_size"
.Fc
.Ft int
.Fn archive_read_open_memory "struct archive *" "void *buff" "size_t size"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Fn archive_read_open
The same as
.Fn archive_read_open2 ,
except that the skip callback is assumed to be
.Dv NULL .
.It Fn archive_read_open2
Freeze the settings, open the archive, and prepare for reading entries.
This is the most generic version of this call, which accepts
four callback functions.
Most clients will want to use
.Fn archive_read_open_filename ,
.Fn archive_read_open_FILE ,
.Fn archive_read_open_fd ,
or
.Fn archive_read_open_memory
instead.
The library invokes the client-provided functions to obtain
raw bytes from the archive.
.It Fn archive_read_open_FILE
Like
.Fn archive_read_open ,
except that it accepts a
.Ft "FILE *"
pointer.
This function should not be used with tape drives or other devices
that require strict I/O blocking.
.It Fn archive_read_open_fd
Like
.Fn archive_read_open ,
except that it accepts a file descriptor and block size rather than
a set of function pointers.
Note that the file descriptor will not be automatically closed at
end-of-archive.
This function is safe for use with tape drives or other blocked devices.
.It Fn archive_read_open_file
This is a deprecated synonym for
.Fn archive_read_open_filename .
.It Fn archive_read_open_filename
Like
.Fn archive_read_open ,
except that it accepts a simple filename and a block size.
A NULL filename represents standard input.
This function is safe for use with tape drives or other blocked devices.
.It Fn archive_read_open_memory
Like
.Fn archive_read_open ,
except that it accepts a pointer and size of a block of
memory containing the archive data.
.El
.Pp
A complete description of the
.Tn struct archive
and
.Tn struct archive_entry
objects can be found in the overview manual page for
.Xr libarchive 3 .
.Sh CLIENT CALLBACKS
The callback functions must match the following prototypes:
.Bl -item -offset indent
.It
.Ft typedef ssize_t
.Fo archive_read_callback
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "const void **buffer"
.Fc
.It
.Ft typedef off_t
.Fo archive_skip_callback
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "off_t request"
.Fc
.It
.Ft typedef int
.Fn archive_open_callback "struct archive *" "void *client_data"
.It
.Ft typedef int
.Fn archive_close_callback "struct archive *" "void *client_data"
.El
.Pp
The open callback is invoked by
.Fn archive_open .
It should return
.Cm ARCHIVE_OK
if the underlying file or data source is successfully
opened.
If the open fails, it should call
.Fn archive_set_error
to register an error code and message and return
.Cm ARCHIVE_FATAL .
.Pp
The read callback is invoked whenever the library
requires raw bytes from the archive.
The read callback should read data into a buffer,
set the
.Li const void **buffer
argument to point to the available data, and
return a count of the number of bytes available.
The library will invoke the read callback again
only after it has consumed this data.
The library imposes no constraints on the size
of the data blocks returned.
On end-of-file, the read callback should
return zero.
On error, the read callback should invoke
.Fn archive_set_error
to register an error code and message and
return -1.
.Pp
The skip callback is invoked when the
library wants to ignore a block of data.
The return value is the number of bytes actually
skipped, which may differ from the request.
If the callback cannot skip data, it should return
zero.
If the skip callback is not provided (the
function pointer is
.Dv NULL ),
the library will invoke the read function
instead and simply discard the result.
A skip callback can provide significant
performance gains when reading uncompressed
archives from slow disk drives or other media
that can skip quickly.
.Pp
The close callback is invoked by archive_close when
the archive processing is complete.
The callback should return
.Cm ARCHIVE_OK
on success.
On failure, the callback should invoke
.Fn archive_set_error
to register an error code and message and
return
.Cm ARCHIVE_FATAL.
.\" .Sh EXAMPLE
.\"
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
on success, or
.Cm ARCHIVE_FATAL .
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5

View File

@ -0,0 +1,181 @@
/*-
* 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_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_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;
off_t skip = (off_t)request;
off_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);
}
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);
}

View File

@ -0,0 +1,177 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "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. (FILE * objects can wrap many kinds of I/O
* streams, some of which don't support fileno()).)
*/
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;
ssize_t bytes_read;
*buff = mine->buffer;
bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f);
if (bytes_read < 0) {
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;
}
#if HAVE_FSEEKO
if (fseeko(mine->f, skip, SEEK_CUR) != 0)
#elif HAVE__FSEEKI64
if (_fseeki64(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 */
if (mine->buffer != NULL)
free(mine->buffer);
free(mine);
return (ARCHIVE_OK);
}

View File

@ -0,0 +1,509 @@
/*-
* 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_string.h"
#ifndef O_BINARY
#define O_BINARY 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_close(struct archive *, void *);
static int file_open_filename(struct archive *, enum fnt_e, const void *,
size_t);
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)
{
enum fnt_e filename_type;
if (filename == NULL || filename[0] == '\0') {
filename_type = FNT_STDIN;
} else
filename_type = FNT_MBS;
return (file_open_filename(a, filename_type, filename, block_size));
}
int
archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
size_t block_size)
{
enum fnt_e filename_type;
if (wfilename == NULL || wfilename[0] == L'\0') {
filename_type = FNT_STDIN;
} else {
#if defined(_WIN32) && !defined(__CYGWIN__)
filename_type = FNT_WCS;
#else
/*
* POSIX system does not support a wchar_t interface for
* open() system call, so we have to translate a whcar_t
* filename to multi-byte one and use it.
*/
struct archive_string fn;
int r;
archive_string_init(&fn);
if (archive_string_append_from_wcs(&fn, wfilename,
wcslen(wfilename)) != 0) {
archive_set_error(a, EINVAL,
"Failed to convert a wide-character filename to"
" a multi-byte filename");
archive_string_free(&fn);
return (ARCHIVE_FATAL);
}
r = file_open_filename(a, FNT_MBS, fn.s, block_size);
archive_string_free(&fn);
return (r);
#endif
}
return (file_open_filename(a, filename_type, wfilename, block_size));
}
static int
file_open_filename(struct archive *a, enum fnt_e filename_type,
const void *_filename, size_t block_size)
{
struct stat st;
struct read_file_data *mine;
void *buffer;
const char *filename = NULL;
const wchar_t *wfilename = NULL;
int fd;
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 (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 (filename_type == FNT_MBS) {
filename = (const char *)_filename;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0) {
archive_set_error(a, errno,
"Failed to open '%s'", filename);
return (ARCHIVE_FATAL);
}
} else {
#if defined(_WIN32) && !defined(__CYGWIN__)
wfilename = (const wchar_t *)_filename;
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");
return (ARCHIVE_FATAL);
#endif
}
if (fstat(fd, &st) != 0) {
if (filename_type == FNT_WCS)
archive_set_error(a, errno, "Can't stat '%S'",
wfilename);
else
archive_set_error(a, errno, "Can't stat '%s'",
filename);
return (ARCHIVE_FATAL);
}
/*
* 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. */
if (filename_type == FNT_WCS)
mine = (struct read_file_data *)calloc(1,
sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t));
else
mine = (struct read_file_data *)calloc(1,
sizeof(*mine) + strlen(filename));
/* 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 < block_size
&& new_block_size < 64 * 1024 * 1024)
new_block_size *= 2;
block_size = new_block_size;
}
buffer = malloc(block_size);
if (mine == NULL || buffer == NULL) {
archive_set_error(a, ENOMEM, "No memory");
free(mine);
free(buffer);
return (ARCHIVE_FATAL);
}
if (filename_type == FNT_WCS)
wcscpy(mine->filename.w, wfilename);
else
strcpy(mine->filename.m, filename);
mine->filename_type = filename_type;
mine->block_size = block_size;
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) {
archive_read_set_seek_callback(a, file_seek);
mine->use_lseek = 1;
}
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;
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. It's still an issue
* on Windows, though, so it might suffice to just use
* _lseeki64() on Windows.
*/
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;
off_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_close(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);
free(mine);
return (ARCHIVE_OK);
}

View File

@ -0,0 +1,186 @@
/*-
* 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 {
unsigned char *start;
unsigned char *p;
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, 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, void *buff,
size_t size, size_t read_size)
{
struct read_memory_data *mine;
mine = (struct read_memory_data *)malloc(sizeof(*mine));
if (mine == NULL) {
archive_set_error(a, ENOMEM, "No memory");
return (ARCHIVE_FATAL);
}
memset(mine, 0, sizeof(*mine));
mine->start = mine->p = (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;
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);
}

View File

@ -0,0 +1,210 @@
/*-
* 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 __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED
#define ARCHIVE_READ_PRIVATE_H_INCLUDED
#include "archive.h"
#include "archive_string.h"
#include "archive_private.h"
struct archive_read;
struct archive_read_filter_bidder;
struct archive_read_filter;
/*
* 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;
/* 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 *);
/* Set an option for the filter bidder. */
int (*options)(struct archive_read_filter_bidder *,
const char *key, const char *value);
/* Release the bidder's configuration data. */
int (*free)(struct archive_read_filter_bidder *);
};
/*
* 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. */
/* Return next block. */
ssize_t (*read)(struct archive_read_filter *, const void **);
/* Skip forward this many bytes. */
int64_t (*skip)(struct archive_read_filter *self, int64_t request);
/* Seek to an absolute location. */
int64_t (*seek)(struct archive_read_filter *self, int64_t offset, int whence);
/* Close (just this filter) and free(self). */
int (*close)(struct archive_read_filter *self);
/* My private data. */
void *data;
const char *name;
int code;
/* 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_client {
archive_open_callback *opener;
archive_read_callback *reader;
archive_skip_callback *skipper;
archive_seek_callback *seeker;
archive_close_callback *closer;
void *data;
};
struct archive_read {
struct archive archive;
struct archive_entry *entry;
/* Dev/ino of the archive being read/written. */
int skip_file_set;
dev_t skip_file_dev;
ino_t skip_file_ino;
/*
* 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;
/* Callbacks to open/read/write/close client archive stream. */
struct archive_read_client client;
/* Registered filter bidders. */
struct archive_read_filter_bidder bidders[9];
/* Last filter in chain */
struct archive_read_filter *filter;
/* File offset of beginning of most recently-read header. */
int64_t header_position;
/*
* 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 *);
int (*cleanup)(struct archive_read *);
} formats[16];
struct archive_format_descriptor *format; /* Active format. */
/*
* Various information needed by archive_extract.
*/
struct extract *extract;
int (*cleanup_archive_extract)(struct archive_read *);
};
int __archive_read_register_format(struct archive_read *a,
void *format_data,
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 *),
int (*cleanup)(struct archive_read *));
int __archive_read_get_bidder(struct archive_read *a,
struct archive_read_filter_bidder **bidder);
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_program(struct archive_read_filter *, const char *);
#endif

View File

@ -0,0 +1,207 @@
.\" 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 AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd April 13, 2009
.Dt archive_read_options 3
.Os
.Sh NAME
.Nm archive_read_set_filter_option ,
.Nm archive_read_set_format_option ,
.Nm archive_read_set_option ,
.Nm archive_read_set_options
.Nd functions controlling options for reading archives
.\"
.Sh SYNOPSIS
.Ft int
.Fo archive_read_set_filter_option
.Fa "struct archive *"
.Fa "const char *module"
.Fa "const char *option"
.Fa "const char *value"
.Fc
.Ft int
.Fo archive_read_set_format_option
.Fa "struct archive *"
.Fa "const char *module"
.Fa "const char *option"
.Fa "const char *value"
.Fc
.Ft int
.Fo archive_read_set_option
.Fa "struct archive *"
.Fa "const char *module"
.Fa "const char *option"
.Fa "const char *value"
.Fc
.Ft int
.Fo archive_read_set_options
.Fa "struct archive *"
.Fa "const char *options"
.Fc
.Sh DESCRIPTION
These functions provide a way for libarchive clients to configure
specific read modules.
.Bl -tag -width indent
.It Xo
.Fn archive_read_set_filter_option ,
.Fn archive_read_set_format_option
.Xc
Specifies an option that will be passed to currently-registered
filters (including decompression filters) or format readers.
.Pp
If
.Ar option
and
.Ar value
are both
.Dv NULL ,
these functions will do nothing and
.Cm ARCHIVE_OK
will be returned.
If
.Ar option
is
.Dv NULL
but
.Ar value
is not, these functions will do nothing and
.Cm ARCHIVE_FAILED
will be returned.
.Pp
If
.Ar module
is not
.Dv NULL ,
.Ar option
and
.Ar value
will be provided to the filter or reader named
.Ar module .
The return value will be that of the module.
If there is no such module,
.Cm ARCHIVE_FAILED
will be returned.
.Pp
If
.Ar module
is
.Dv NULL ,
.Ar option
and
.Ar value
will be provided to every registered module.
If any module returns
.Cm ARCHIVE_FATAL ,
this value will be returned immediately.
Otherwise,
.Cm ARCHIVE_OK
will be returned if any module accepts the option, and
.Cm ARCHIVE_FAILED
in all other cases.
.\"
.It Xo
.Fn archive_read_set_option
.Xc
Calls
.Fn archive_read_set_format_option ,
then
.Fn archive_read_set_filter_option .
If either function returns
.Cm ARCHIVE_FATAL ,
.Cm ARCHIVE_FATAL
will be returned
immediately.
Otherwise, greater of the two values will be returned.
.\"
.It Xo
.Fn archive_read_set_options
.Xc
.Ar options
is a comma-separated list of options.
If
.Ar options
is
.Dv NULL
or empty,
.Cm ARCHIVE_OK
will be returned immediately.
.Pp
Calls
.Fn archive_read_set_option
with each option in turn.
If any
.Fn archive_read_set_option
call returns
.Cm ARCHIVE_FATAL ,
.Cm ARCHIVE_FATAL
will be returned immediately.
.Pp
Individual options have one of the following forms:
.Bl -tag -compact -width indent
.It Ar option=value
The option/value pair will be provided to every module.
Modules that do not accept an option with this name will ignore it.
.It Ar option
The option will be provided to every module with a value of
.Dq 1 .
.It Ar !option
The option will be provided to every module with a NULL value.
.It Ar module:option=value , Ar module:option , Ar module:!option
As above, but the corresponding option and value will be provided
only to modules whose name matches
.Ar module .
.El
.El
.\"
.Sh OPTIONS
.Bl -tag -compact -width indent
.It Format iso9660
.Bl -tag -compact -width indent
.It Cm joliet
Support Joliet extensions.
Defaults to enabled, use
.Cm !joliet
to disable.
.It Cm rockridge
Support RockRidge extensions.
Defaults to enabled, use
.Cm !rockridge
to disable.
.El
.El
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_write_set_options 3 ,
.Xr archive_read 3

View File

@ -0,0 +1,148 @@
/*-
* 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;
struct archive_format_descriptor *format;
size_t i;
int r, rv = ARCHIVE_FAILED;
for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) {
format = &a->formats[i];
if (format == NULL || format->options == NULL ||
format->name == NULL)
/* This format does not support option. */
continue;
if (m != NULL && strcmp(format->name, m) != 0)
continue;
a->format = format;
r = format->options(a, o, v);
a->format = NULL;
if (r == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
if (m != NULL)
return (r);
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
return (rv);
}
static int
archive_set_filter_option(struct archive *_a, const char *m, const char *o,
const char *v)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter *filter;
struct archive_read_filter_bidder *bidder;
int r, rv = ARCHIVE_FAILED;
for (filter = a->filter; filter != NULL; filter = filter->upstream) {
bidder = filter->bidder;
if (bidder == NULL)
continue;
if (bidder->options == NULL)
/* This bidder does not support option */
continue;
if (m != NULL && strcmp(filter->name, m) != 0)
continue;
r = bidder->options(bidder, o, v);
if (r == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
if (m != NULL)
return (r);
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
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);
}

View File

@ -0,0 +1,75 @@
/*-
* 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 "gunzip" 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);
/* 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);
}

View File

@ -0,0 +1,370 @@
/*-
* 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 *);
static int bzip2_reader_free(struct archive_read_filter_bidder *);
#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
int
archive_read_support_filter_bzip2(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *reader;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_bzip2");
if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
reader->data = NULL;
reader->bid = bzip2_reader_bid;
reader->init = bzip2_reader_init;
reader->options = NULL;
reader->free = bzip2_reader_free;
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
return (ARCHIVE_OK);
#else
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
"Using external bunzip2 program");
return (ARCHIVE_WARN);
#endif
}
static int
bzip2_reader_free(struct archive_read_filter_bidder *self){
(void)self; /* UNUSED */
return (ARCHIVE_OK);
}
/*
* 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, "bunzip2");
/* 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_COMPRESSION_BZIP2;
self->name = "bzip2";
return (r);
}
#else
/*
* 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_COMPRESSION_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->read = bzip2_filter_read;
self->skip = NULL; /* not supported */
self->close = bzip2_filter_close;
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 = 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 = 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 */

View File

@ -0,0 +1,454 @@
/*-
* 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 int compress_bidder_free(struct archive_read_filter_bidder *);
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
int
archive_read_support_filter_compress(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_compress");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->bid = compress_bidder_bid;
bidder->init = compress_bidder_init;
bidder->options = NULL;
bidder->free = compress_bidder_free;
return (ARCHIVE_OK);
}
/*
* 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 */
buffer = __archive_read_filter_ahead(filter, 2, &avail);
if (buffer == NULL)
return (0);
bits_checked = 0;
if (buffer[0] != 0x1F || buffer[1] != 0x9D)
return (0);
bits_checked += 16;
/*
* TODO: Verify more.
*/
return (bits_checked);
}
/*
* 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_COMPRESSION_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->read = compress_filter_read;
self->skip = NULL; /* not supported */
self->close = compress_filter_close;
/* XXX MOVE THE FOLLOWING OUT OF INIT() XXX */
(void)getbits(self, 8); /* Skip first signature byte. */
(void)getbits(self, 8); /* Skip second signature byte. */
code = getbits(self, 8);
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);
}
/*
* Clean up the reader.
*/
static int
compress_bidder_free(struct archive_read_filter_bidder *self)
{
self->data = NULL;
return (ARCHIVE_OK);
}
/*
* 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) {
/* 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]);
}

View File

@ -0,0 +1,476 @@
/*-
* 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
#ifdef HAVE_ZLIB_H
#include <zlib.h>
#endif
#include "archive.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;
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
* gunzip 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
int
archive_read_support_filter_gzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_gzip");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->bid = gzip_bidder_bid;
bidder->init = gzip_bidder_init;
bidder->options = NULL;
bidder->free = NULL; /* No data, so no cleanup necessary. */
/* 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 gunzip 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 int
peek_at_header(struct archive_read_filter *filter, int *pbits)
{
const unsigned char *p;
ssize_t avail, len;
int bits = 0;
int header_flags;
/* 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. */
/* 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) {
do {
++len;
if (avail < len)
p = __archive_read_filter_ahead(filter,
len, &avail);
if (p == NULL)
return (0);
} while (p[len - 1] != 0);
}
/* 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))
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 gunzip
* in case that's available.
*/
static int
gzip_bidder_init(struct archive_read_filter *self)
{
int r;
r = __archive_read_program(self, "gunzip");
/* 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_COMPRESSION_GZIP;
self->name = "gzip";
return (r);
}
#else
/*
* 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_COMPRESSION_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->read = gzip_filter_read;
self->skip = NULL; /* not supported */
self->close = gzip_filter_close;
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);
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 = 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;
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 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);
}
state->stream.avail_in = 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->out_block);
free(state);
return (ret);
}
#endif /* HAVE_ZLIB_H */

View File

@ -0,0 +1,52 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "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);
}

View File

@ -0,0 +1,476 @@
/*-
* Copyright (c) 2007 Joerg Sonnenberger
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
#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_read_private.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));
}
/* This capability is only available on POSIX systems. */
#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
!(defined(HAVE_FORK) || defined(HAVE_VFORK))) && (!defined(_WIN32) || defined(__CYGWIN__))
/*
* On non-Posix systems, allow the program to build, but choke if
* this function is actually invoked.
*/
int
archive_read_support_filter_program_signature(struct archive *_a,
const char *cmd, const void *signature, size_t signature_len)
{
(void)_a; /* UNUSED */
(void)cmd; /* UNUSED */
(void)signature; /* UNUSED */
(void)signature_len; /* UNUSED */
archive_set_error(_a, -1,
"External compression programs not supported on this platform");
return (ARCHIVE_FATAL);
}
int
__archive_read_program(struct archive_read_filter *self, const char *cmd)
{
(void)self; /* UNUSED */
(void)cmd; /* UNUSED */
archive_set_error(&self->archive->archive, -1,
"External compression programs not supported on this platform");
return (ARCHIVE_FATAL);
}
#else
#include "filter_fork.h"
/*
* 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 *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 int program_bidder_free(struct archive_read_filter_bidder *);
/*
* The actual filter needs to track input and output data.
*/
struct program_filter {
char *description;
pid_t child;
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 *);
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 archive_read_filter_bidder *bidder;
struct program_bidder *state;
/*
* Get a bidder object from the read core.
*/
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
/*
* Allocate our private state.
*/
state = (struct program_bidder *)calloc(sizeof (*state), 1);
if (state == NULL)
return (ARCHIVE_FATAL);
state->cmd = strdup(cmd);
if (signature != NULL && signature_len > 0) {
state->signature_len = signature_len;
state->signature = malloc(signature_len);
memcpy(state->signature, signature, signature_len);
}
/*
* Fill in the bidder object.
*/
bidder->data = state;
bidder->bid = program_bidder_bid;
bidder->init = program_bidder_init;
bidder->options = NULL;
bidder->free = program_bidder_free;
return (ARCHIVE_OK);
}
static int
program_bidder_free(struct archive_read_filter_bidder *self)
{
struct program_bidder *state = (struct program_bidder *)self->data;
free(state->cmd);
free(state->signature);
free(self->data);
return (ARCHIVE_OK);
}
/*
* 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);
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;
requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
for (;;) {
do {
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);
}
}
}
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;
char *description;
const char *prefix = "Program: ";
state = (struct program_filter *)calloc(1, sizeof(*state));
out_buf = (char *)malloc(out_buf_len);
description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
if (state == NULL || out_buf == NULL || description == NULL) {
archive_set_error(&self->archive->archive, ENOMEM,
"Can't allocate input data");
free(state);
free(out_buf);
free(description);
return (ARCHIVE_FATAL);
}
self->code = ARCHIVE_COMPRESSION_PROGRAM;
state->description = description;
strcpy(state->description, prefix);
strcat(state->description, cmd);
self->name = state->description;
state->out_buf = out_buf;
state->out_buf_len = out_buf_len;
if ((state->child = __archive_create_child(cmd,
&state->child_stdin, &state->child_stdout)) == -1) {
free(state->out_buf);
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->read = program_filter_read;
self->skip = NULL;
self->close = program_filter_close;
/* 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);
free(state->description);
free(state);
return (e);
}
#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */

View File

@ -0,0 +1,288 @@
/*-
* 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
int
archive_read_support_filter_rpm(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_rpm");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->bid = rpm_bidder_bid;
bidder->init = rpm_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
return (ARCHIVE_OK);
}
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 int
rpm_bidder_init(struct archive_read_filter *self)
{
struct rpm *rpm;
self->code = ARCHIVE_COMPRESSION_RPM;
self->name = "rpm";
self->read = rpm_filter_read;
self->skip = NULL; /* not supported */
self->close = rpm_filter_close;
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;
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 = 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,
"Unrecoginized 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);
}

View File

@ -0,0 +1,680 @@
/*-
* 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
};
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
int
archive_read_support_filter_uu(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_uu");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->bid = uudecode_bidder_bid;
bidder->init = uudecode_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
return (ARCHIVE_OK);
}
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 determinated. */
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) {
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);
while (l && len-nl > 0) {
if (l > 0) {
if (!uuchar[*b++])
return (0);
if (!uuchar[*b++])
return (0);
len -= 2;
--l;
}
if (l > 0) {
if (!uuchar[*b++])
return (0);
--len;
--l;
}
if (l > 0) {
if (!uuchar[*b++])
return (0);
--len;
--l;
}
}
if (len-nl < 0)
return (0);
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);
}
if (l == 13) {
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 int
uudecode_bidder_init(struct archive_read_filter *self)
{
struct uudecode *uudecode;
void *out_buff;
void *in_buff;
self->code = ARCHIVE_COMPRESSION_UU;
self->name = "uu";
self->read = uudecode_filter_read;
self->skip = NULL; /* not supported */
self->close = uudecode_filter_close;
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;
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->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) {
int l, body;
b = d;
len = get_line(b, avail_in - used, &nl);
if (len < 0) {
/* Non-ascii character is found. */
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
llen = len;
if (nl == 0) {
/*
* 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 = 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;
}
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)
break;
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 curent 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 (l > 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)
break;
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 (l > 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;
}
}
__archive_read_filter_consume(self->upstream, ravail);
*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);
}

View File

@ -0,0 +1,985 @@
/*-
* 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>
#elif HAVE_LZMADEC_H
#include <lzmadec.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 *);
#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
struct private_data {
lzmadec_stream stream;
unsigned char *out_block;
size_t out_block_size;
int64_t total_out;
char eof; /* True = found end of compressed data. */
};
/* Lzma-only filter */
static ssize_t lzma_filter_read(struct archive_read_filter *, const void **);
static int lzma_filter_close(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
int
archive_read_support_filter_xz(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_xz");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->bid = xz_bidder_bid;
bidder->init = xz_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
#if HAVE_LZMA_H && HAVE_LIBLZMA
return (ARCHIVE_OK);
#else
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
"Using external unxz 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
int
archive_read_support_filter_lzma(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_lzma");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->bid = lzma_bidder_bid;
bidder->init = lzma_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
#if HAVE_LZMA_H && HAVE_LIBLZMA
return (ARCHIVE_OK);
#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
return (ARCHIVE_OK);
#else
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
"Using external unlzma 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
int
archive_read_support_filter_lzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_lzip");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->bid = lzip_bidder_bid;
bidder->init = lzip_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
#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 maxinam dictionary size is 1 << 27(128MiB)
* which the one uses with option -d27.
* 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 > 27)
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_COMPRESSION_XZ;
self->name = "xz";
return (xz_lzma_bidder_init(self));
}
static int
lzma_bidder_init(struct archive_read_filter *self)
{
self->code = ARCHIVE_COMPRESSION_LZMA;
self->name = "lzma";
return (xz_lzma_bidder_init(self));
}
static int
lzip_bidder_init(struct archive_read_filter *self)
{
self->code = ARCHIVE_COMPRESSION_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;
}
}
/*
* 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->read = xz_filter_read;
self->skip = NULL; /* not supported */
self->close = xz_filter_close;
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_COMPRESSION_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_COMPRESSION_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 > 27)
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);
#if LZMA_VERSION < 50000030
free(filters[0].options);
#endif
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 (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)) {
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: CRC32 error");
return (ARCHIVE_FAILED);
}
/* 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_COMPRESSION_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 HAVE_LZMADEC_H && HAVE_LIBLZMADEC
/*
* If we have the older liblzmadec library, then we can handle
* LZMA streams but not XZ streams.
*/
/*
* Setup the callbacks.
*/
static int
lzma_bidder_init(struct archive_read_filter *self)
{
static const size_t out_block_size = 64 * 1024;
void *out_block;
struct private_data *state;
ssize_t ret, avail_in;
self->code = ARCHIVE_COMPRESSION_LZMA;
self->name = "lzma";
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 lzma 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->read = lzma_filter_read;
self->skip = NULL; /* not supported */
self->close = lzma_filter_close;
/* Prime the lzma library with 18 bytes of input. */
state->stream.next_in = (unsigned char *)(uintptr_t)
__archive_read_filter_ahead(self->upstream, 18, &avail_in);
if (state->stream.next_in == NULL)
return (ARCHIVE_FATAL);
state->stream.avail_in = avail_in;
state->stream.next_out = state->out_block;
state->stream.avail_out = state->out_block_size;
/* Initialize compression library. */
ret = lzmadec_init(&(state->stream));
__archive_read_filter_consume(self->upstream,
avail_in - state->stream.avail_in);
if (ret == LZMADEC_OK)
return (ARCHIVE_OK);
/* Library setup failed: Clean up. */
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing lzma library");
/* Override the error message if we know what really went wrong. */
switch (ret) {
case LZMADEC_HEADER_ERROR:
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid header");
break;
case LZMADEC_MEM_ERROR:
archive_set_error(&self->archive->archive, ENOMEM,
"Internal error initializing compression library: "
"out of memory");
break;
}
free(state->out_block);
free(state);
self->data = NULL;
return (ARCHIVE_FATAL);
}
/*
* Return the next block of decompressed data.
*/
static ssize_t
lzma_filter_read(struct archive_read_filter *self, const void **p)
{
struct private_data *state;
size_t decompressed;
ssize_t avail_in, 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) {
state->stream.next_in = (unsigned char *)(uintptr_t)
__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 lzma input");
return (ARCHIVE_FATAL);
}
state->stream.avail_in = avail_in;
/* Decompress as much as we can in one pass. */
ret = lzmadec_decode(&(state->stream), avail_in == 0);
switch (ret) {
case LZMADEC_STREAM_END: /* Found end of stream. */
state->eof = 1;
/* FALL THROUGH */
case LZMADEC_OK: /* Decompressor made some progress. */
__archive_read_filter_consume(self->upstream,
avail_in - state->stream.avail_in);
break;
case LZMADEC_BUF_ERROR: /* Insufficient input data? */
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
default:
/* Return an error. */
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma decompression failed");
return (ARCHIVE_FATAL);
}
}
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
lzma_filter_close(struct archive_read_filter *self)
{
struct private_data *state;
int ret;
state = (struct private_data *)self->data;
ret = ARCHIVE_OK;
switch (lzmadec_end(&(state->stream))) {
case LZMADEC_OK:
break;
default:
archive_set_error(&(self->archive->archive),
ARCHIVE_ERRNO_MISC,
"Failed to clean up %s compressor",
self->archive->archive.compression_name);
ret = ARCHIVE_FATAL;
}
free(state->out_block);
free(state);
return (ret);
}
#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, "unlzma");
/* 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_COMPRESSION_LZMA;
self->name = "lzma";
return (r);
}
#endif /* HAVE_LZMADEC_H */
static int
xz_bidder_init(struct archive_read_filter *self)
{
int r;
r = __archive_read_program(self, "unxz");
/* 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_COMPRESSION_XZ;
self->name = "xz";
return (r);
}
static int
lzip_bidder_init(struct archive_read_filter *self)
{
int r;
r = __archive_read_program(self, "unlzip");
/* 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_COMPRESSION_LZIP;
self->name = "lzip";
return (r);
}
#endif /* HAVE_LZMA_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
/*-
* 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);
/*
* 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_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);
}

View File

@ -0,0 +1,625 @@
/*-
* 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 *)malloc(sizeof(*ar));
if (ar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate ar data");
return (ARCHIVE_FATAL);
}
memset(ar, 0, sizeof(*ar));
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,
archive_read_format_ar_cleanup);
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);
if (ar->strtab)
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_WARN);
}
/* 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 == '/')
*p = '\0';
/*
* '//' 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) {
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_WARN);
}
if (ar->strtab != NULL) {
archive_set_error(&a->archive, EINVAL,
"More than one string tables exist");
return (ARCHIVE_WARN);
}
/* 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 entry");
archive_entry_copy_pathname(entry, filename);
/* Parse the time, owner, mode, size fields. */
ar_parse_common_header(ar, entry, h);
return (ARCHIVE_WARN);
}
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);
bsd_name_length = (size_t)number;
/* Guard against the filename + trailing NUL
* overflowing a size_t and against the filename size
* being larger than the entire entry. */
if (number > (uint64_t)(bsd_name_length + 1)
|| (int64_t)bsd_name_length > ar->entry_bytes_remaining) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Bad input file size");
return (ARCHIVE_FATAL);
}
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.
*/
if (strcmp(filename, "/") == 0) {
archive_entry_copy_pathname(entry, "/");
/* 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_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_WARN);
}
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);
}

View File

@ -0,0 +1,74 @@
/*-
* 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"
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_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_TAR:
return archive_read_support_format_tar(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;
}
return (ARCHIVE_FATAL);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "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,
NULL,
archive_read_format_empty_bid,
NULL,
archive_read_format_empty_read_header,
archive_read_format_empty_read_data,
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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
/*-
* 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,
archive_read_format_raw_cleanup);
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. */
return (ARCHIVE_OK);
}
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 (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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More