[Cmake-commits] CMake branch, next, updated. v2.8.11.2-3515-gdeeb80a

Brad King brad.king at kitware.com
Wed Jul 31 08:28:18 EDT 2013


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, next has been updated
       via  deeb80a6cb4ded8d5ce8fe2c493d208dda975d6b (commit)
       via  26fe7e3adfc76a733ecc74794f22d53755ac194a (commit)
       via  b81a4e1568c58d733051d9f27cd070761f264a80 (commit)
       via  3218f52f11713d28bdfedbe6eceddb8cf8502731 (commit)
       via  bae3a73ceea6163eeb6eae59dfcf838a43048831 (commit)
       via  677384017a343f1ca70342951a39302a683843a2 (commit)
       via  8dc0a9f898710215bd29fa260f790a7051dbaab2 (commit)
       via  102071f80cf4ad7aa97bf8a1618cfc6ee6689ab6 (commit)
       via  35df7c8ba8854e97bd6994c4d1143f57535ed6f2 (commit)
      from  b11ce2cc030b4a59a9a4dfc75d91fb21ac068367 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=deeb80a6cb4ded8d5ce8fe2c493d208dda975d6b
commit deeb80a6cb4ded8d5ce8fe2c493d208dda975d6b
Merge: b11ce2c 26fe7e3
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Jul 31 08:28:01 2013 -0400
Commit:     CMake Topic Stage <kwrobot at kitware.com>
CommitDate: Wed Jul 31 08:28:01 2013 -0400

    Merge topic 'update-libarchive' into next
    
    26fe7e3 libarchive: Backport to CMake 2.8.2
    b81a4e1 libarchive: Remove build options not used by CMake
    3218f52 libarchive: Avoid struct init with variable
    bae3a73 libarchive: Silence API deprecation warnings
    6773840 libarchive: Include cm_zlib.h to get zlib used by CMake
    8dc0a9f libarchive: Update README-CMake.txt for new snapshot
    102071f Merge branch 'libarchive-upstream' into update-libarchive
    35df7c8 libarchive 3.1.2 (reduced)


http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=26fe7e3adfc76a733ecc74794f22d53755ac194a
commit 26fe7e3adfc76a733ecc74794f22d53755ac194a
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Jul 26 16:59:48 2013 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jul 31 08:22:15 2013 -0400

    libarchive: Backport to CMake 2.8.2
    
    Avoid requiring CMake 2.8.6 for CMakePushCheckState or CMake 2.8.8 for
    CMakeExpandImportedTargets.  Drop the custom versions of CMake modules
    CheckCSource(Compiles|Runs) because we do not use the SAFESEH option
    anyway.

diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt
index 64484fd..621888c 100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@ -1,6 +1,3 @@
-#
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8.6 FATAL_ERROR)
-#
 PROJECT(libarchive C)
 #
 SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
@@ -48,7 +45,7 @@ SET(SOVERSION "${INTERFACE_VERSION}")
 
 # Enalbe CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE() macros
 # saving and restoring the state of the variables.
-INCLUDE(CMakePushCheckState)
+INCLUDE(${CMake_SOURCE_DIR}/Modules/CMakePushCheckState.cmake)
 
 # Initialize the state of the variables. This initialization is not
 # necessary but this shows you what value the variables initially have.
@@ -90,8 +87,8 @@ IF("${CMAKE_C_PLATFORM_ID}" MATCHES "^(HP-UX)$")
 ENDIF()
 
 #
-INCLUDE(LibarchiveCheckCSourceCompiles)
-INCLUDE(LibarchiveCheckCSourceRuns)
+INCLUDE(CheckCSourceCompiles)
+INCLUDE(CheckCSourceRuns)
 INCLUDE(CheckFileOffsetBits)
 INCLUDE(CheckFuncs)
 INCLUDE(CheckHeaderDirent)
@@ -155,9 +152,9 @@ MACRO (TRY_MACRO_FOR_LIBRARY INCLUDES LIBRARIES
       ENDIF(NOT "${PREV_VAR_WITH_LIB}" STREQUAL "${LIBRARIES}")
       # Check if the library can be used with the macro.
       IF("${TRY_TYPE}" MATCHES "COMPILES")
-        LIBARCHIVE_CHECK_C_SOURCE_COMPILES("${SAMPLE_SOURCE}" ${VAR})
+        CHECK_C_SOURCE_COMPILES("${SAMPLE_SOURCE}" ${VAR})
       ELSEIF("${TRY_TYPE}" MATCHES "RUNS")
-        LIBARCHIVE_CHECK_C_SOURCE_RUNS("${SAMPLE_SOURCE}" ${VAR})
+        CHECK_C_SOURCE_RUNS("${SAMPLE_SOURCE}" ${VAR})
       ELSE("${TRY_TYPE}" MATCHES "COMPILES")
         MESSAGE(FATAL_ERROR "UNKNOWN KEYWORD \"${TRY_TYPE}\" FOR TRY_TYPE")
       ENDIF("${TRY_TYPE}" MATCHES "COMPILES")
@@ -338,7 +335,7 @@ LA_CHECK_INCLUDE_FILE("dlfcn.h" HAVE_DLFCN_H)
 LA_CHECK_INCLUDE_FILE("errno.h" HAVE_ERRNO_H)
 LA_CHECK_INCLUDE_FILE("ext2fs/ext2_fs.h" HAVE_EXT2FS_EXT2_FS_H)
 
-LIBARCHIVE_CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
+CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
 #include <ext2fs/ext2_fs.h>
 int main(void) { return EXT2_IOC_GETFLAGS; }" HAVE_WORKING_EXT2_IOC_GETFLAGS)
 
@@ -401,7 +398,7 @@ FOREACH (it ${_HEADER})
    SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
 ENDFOREACH (it)
 
-LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
+CHECK_C_SOURCE_COMPILES(
   "#define __EXTENSIONS__ 1
    ${_INCLUDE_FILES}
    int main() { return 0;}"
@@ -662,7 +659,7 @@ MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
       SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /WX")
     ENDIF (MSVC)
     #
-    LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
+    CHECK_C_SOURCE_COMPILES(
       "#include <stdlib.h>
        #include <iconv.h>
        int main() {
@@ -922,14 +919,14 @@ CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
 
 # Make sure we have the POSIX version of readdir_r, not the
 # older 2-argument version.
-LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
+CHECK_C_SOURCE_COMPILES(
   "#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}"
   HAVE_READDIR_R)
 
 
 # Only detect readlinkat() if we also have AT_FDCWD in unistd.h.
 # NOTE: linux requires fcntl.h for AT_FDCWD.
-LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
+CHECK_C_SOURCE_COMPILES(
   "#include <fcntl.h>\n#include <unistd.h>\nint main() {char buf[10]; return readlinkat(AT_FDCWD, \"\", buf, 0);}"
   HAVE_READLINKAT)
 
@@ -938,10 +935,10 @@ LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
 # of interest and verify that the result can be linked.
 # CHECK_FUNCTION_EXISTS doesn't accept a header argument,
 # CHECK_SYMBOL_EXISTS doesn't test linkage.
-LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
+CHECK_C_SOURCE_COMPILES(
   "#include <sys/mkdev.h>\nint main() { return major(256); }"
   MAJOR_IN_MKDEV)
-LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
+CHECK_C_SOURCE_COMPILES(
   "#include <sys/sysmacros.h>\nint main() { return major(256); }"
   MAJOR_IN_SYSMACROS)
 
diff --git a/Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceCompiles.cmake b/Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceCompiles.cmake
deleted file mode 100644
index 6b6f593..0000000
--- a/Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceCompiles.cmake
+++ /dev/null
@@ -1,106 +0,0 @@
-# - Check if given C source compiles and links into an executable
-# CHECK_C_SOURCE_COMPILES(<code> <var> [FAIL_REGEX <fail-regex>])
-#  <code>       - source code to try to compile, must define 'main'
-#  <var>        - variable to store whether the source code compiled
-#  <fail-regex> - fail if test output matches this regex
-# 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
-#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-
-#=============================================================================
-# Copyright 2005-2009 Kitware, Inc.
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# (To distribute this file outside of CMake, substitute the full
-#  License text for the above reference.)
-
-#
-# Extra arguments added by libarchive
-# CMAKE_REQUIRED_LINKER_FLAGS = string of linker command line flags
-#
-
-include(CMakeExpandImportedTargets)
-
-
-macro(LIBARCHIVE_CHECK_C_SOURCE_COMPILES SOURCE VAR)
-  if("${VAR}" MATCHES "^${VAR}$")
-    set(_FAIL_REGEX)
-    set(_key)
-    foreach(arg ${ARGN})
-      if("${arg}" MATCHES "^(FAIL_REGEX)$")
-        set(_key "${arg}")
-      elseif(_key)
-        list(APPEND _${_key} "${arg}")
-      else()
-        message(FATAL_ERROR "Unknown argument:\n  ${arg}\n")
-      endif()
-    endforeach()
-    set(MACRO_CHECK_FUNCTION_DEFINITIONS
-      "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
-    if(CMAKE_REQUIRED_LIBRARIES)
-      # this one translates potentially used imported library targets to their files on disk
-      CMAKE_EXPAND_IMPORTED_TARGETS(_ADJUSTED_CMAKE_REQUIRED_LIBRARIES  LIBRARIES  ${CMAKE_REQUIRED_LIBRARIES} CONFIGURATION "${CMAKE_TRY_COMPILE_CONFIGURATION}")
-      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES
-        "-DLINK_LIBRARIES:STRING=${_ADJUSTED_CMAKE_REQUIRED_LIBRARIES}")
-    else()
-      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
-    endif()
-    if(CMAKE_REQUIRED_INCLUDES)
-      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES
-        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
-    else()
-      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
-    endif()
-	if(CMAKE_REQUIRED_LINKER_FLAGS)
-	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS
-	    "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
-	else()
-	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS)
-	endif()
-    file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
-      "${SOURCE}\n")
-
-    message(STATUS "Performing Test ${VAR}")
-    try_compile(${VAR}
-      ${CMAKE_BINARY_DIR}
-      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
-      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
-      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} ${CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS}
-      "${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
-      "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
-      OUTPUT_VARIABLE OUTPUT)
-
-    foreach(_regex ${_FAIL_REGEX})
-      if("${OUTPUT}" MATCHES "${_regex}")
-        set(${VAR} 0)
-      endif()
-    endforeach()
-
-    if(${VAR})
-      set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
-      message(STATUS "Performing Test ${VAR} - Success")
-      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
-        "Performing C SOURCE FILE Test ${VAR} succeded with the following output:\n"
-        "${OUTPUT}\n"
-        "Source file was:\n${SOURCE}\n")
-    else()
-      message(STATUS "Performing Test ${VAR} - Failed")
-      set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
-      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
-        "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n"
-        "${OUTPUT}\n"
-        "Source file was:\n${SOURCE}\n")
-    endif()
-  endif()
-endmacro()
-
diff --git a/Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceRuns.cmake b/Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceRuns.cmake
deleted file mode 100644
index 498f522..0000000
--- a/Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceRuns.cmake
+++ /dev/null
@@ -1,102 +0,0 @@
-# - Check if the given C source code compiles and runs.
-# CHECK_C_SOURCE_RUNS(<code> <var>)
-#  <code>   - source code to try to compile
-#  <var>    - variable to store the result
-#             (1 for success, empty for failure)
-# 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
-#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-
-#=============================================================================
-# Copyright 2006-2009 Kitware, Inc.
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# (To distribute this file outside of CMake, substitute the full
-#  License text for the above reference.)
-
-#
-# Extra arguments added by libarchive
-# CMAKE_REQUIRED_LINKER_FLAGS = string of linker command line flags
-#
-
-include(CMakeExpandImportedTargets)
-
-
-macro(LIBARCHIVE_CHECK_C_SOURCE_RUNS SOURCE VAR)
-  if("${VAR}" MATCHES "^${VAR}$")
-    set(MACRO_CHECK_FUNCTION_DEFINITIONS
-      "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
-    if(CMAKE_REQUIRED_LIBRARIES)
-      # this one translates potentially used imported library targets to their files on disk
-      CMAKE_EXPAND_IMPORTED_TARGETS(_ADJUSTED_CMAKE_REQUIRED_LIBRARIES  LIBRARIES  ${CMAKE_REQUIRED_LIBRARIES} CONFIGURATION "${CMAKE_TRY_COMPILE_CONFIGURATION}")
-      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES
-        "-DLINK_LIBRARIES:STRING=${_ADJUSTED_CMAKE_REQUIRED_LIBRARIES}")
-    else()
-      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
-    endif()
-    if(CMAKE_REQUIRED_INCLUDES)
-      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES
-        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
-    else()
-      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
-    endif()
-	if(CMAKE_REQUIRED_LINKER_FLAGS)
-	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS
-	    "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
-	else()
-	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS)
-	endif()
-    file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
-      "${SOURCE}\n")
-
-    message(STATUS "Performing Test ${VAR}")
-    try_run(${VAR}_EXITCODE ${VAR}_COMPILED
-      ${CMAKE_BINARY_DIR}
-      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
-      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
-      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} ${CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS}
-      -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
-      "${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
-      "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
-      COMPILE_OUTPUT_VARIABLE OUTPUT)
-    # if it did not compile make the return value fail code of 1
-    if(NOT ${VAR}_COMPILED)
-      set(${VAR}_EXITCODE 1)
-    endif()
-    # if the return value was 0 then it worked
-    if("${${VAR}_EXITCODE}" EQUAL 0)
-      set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
-      message(STATUS "Performing Test ${VAR} - Success")
-      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
-        "Performing C SOURCE FILE Test ${VAR} succeded with the following output:\n"
-        "${OUTPUT}\n"
-        "Return value: ${${VAR}}\n"
-        "Source file was:\n${SOURCE}\n")
-    else()
-      if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES  "FAILED_TO_RUN")
-        set(${VAR} "${${VAR}_EXITCODE}")
-      else()
-        set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
-      endif()
-
-      message(STATUS "Performing Test ${VAR} - Failed")
-      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
-        "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n"
-        "${OUTPUT}\n"
-        "Return value: ${${VAR}_EXITCODE}\n"
-        "Source file was:\n${SOURCE}\n")
-
-    endif()
-  endif()
-endmacro()
-

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b81a4e1568c58d733051d9f27cd070761f264a80
commit b81a4e1568c58d733051d9f27cd070761f264a80
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Jul 26 16:47:31 2013 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jul 31 08:21:20 2013 -0400

    libarchive: Remove build options not used by CMake
    
    Drop options POSIX_REGEX_LIB and ENABLE_SAFESEH that we do not want for
    the CMake build of libarchive.

diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt
index d7a7682..64484fd 100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@ -75,8 +75,6 @@ OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON)
 OPTION(ENABLE_XATTR "Enable extended attribute support" ON)
 OPTION(ENABLE_ACL "Enable ACL support" ON)
 OPTION(ENABLE_ICONV "Enable iconv support" ON)
-SET(POSIX_REGEX_LIB "AUTO" CACHE STRING "Choose what library should provide POSIX regular expression support")
-SET(ENABLE_SAFESEH "AUTO" CACHE STRING "Enable use of /SAFESEH linker flag (MSVC only)")
 
 IF(WIN32)
   IF(MSVC60)
@@ -87,20 +85,6 @@ IF(WIN32)
   SET(_WIN32_WINNT ${WINVER})
 ENDIF(WIN32)
 
-IF(MSVC)
-  IF(ENABLE_SAFESEH STREQUAL "YES")
-    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH")
-    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH")
-    SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH")
-	SET(CMAKE_REQUIRED_LINKER_FLAGS "/SAFESEH")
-  ELSEIF(ENABLE_SAFESEH STREQUAL "NO")
-    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
-    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
-    SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
-	SET(CMAKE_REQUIRED_LINKER_FLAGS "/SAFESEH:NO")
-  ENDIF(ENABLE_SAFESEH STREQUAL "YES")
-ENDIF(MSVC)
-
 IF("${CMAKE_C_PLATFORM_ID}" MATCHES "^(HP-UX)$")
   ADD_DEFINITIONS(-D_XOPEN_SOURCE=500) # Ask wchar.h for mbstate_t
 ENDIF()
@@ -836,112 +820,6 @@ MARK_AS_ADVANCED(CLEAR LIBXML2_LIBRARIES)
 ENDIF()
 
 #
-# POSIX Regular Expression support
-#
-IF(POSIX_REGEX_LIB MATCHES "^(AUTO|LIBC|LIBREGEX)$")
-  #
-  # If PCREPOSIX is not found or not requested, try using regex
-  # from libc or libregex
-  #
-  FIND_PATH(REGEX_INCLUDE_DIR regex.h)
-  IF(REGEX_INCLUDE_DIR)
-    CHECK_FUNCTION_EXISTS_GLIBC(regcomp HAVE_REGCOMP_LIBC)
-    #
-    # If libc does not provide regex, find libregex.
-    #
-    IF(NOT HAVE_REGCOMP_LIBC)
-      CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
-      FIND_LIBRARY(REGEX_LIBRARY regex)
-      IF(REGEX_LIBRARY)
-        SET(CMAKE_REQUIRED_LIBRARIES ${REGEX_LIBRARY})
-        CHECK_FUNCTION_EXISTS_GLIBC(regcomp HAVE_REGCOMP_LIBREGEX)
-        IF(HAVE_REGCOMP_LIBREGEX)
-          LIST(APPEND ADDITIONAL_LIBS ${REGEX_LIBRARY})
-          #
-          # If regex.h is not found, retry looking for regex.h at
-          # REGEX_INCLUDE_DIR
-          #
-          IF(NOT HAVE_REGEX_H)
-            UNSET(HAVE_REGEX_H CACHE)
-            INCLUDE_DIRECTORIES(${REGEX_INCLUDE_DIR})
-            SET(CMAKE_REQUIRED_INCLUDES ${REGEX_INCLUDE_DIR})
-            LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
-          ENDIF(NOT HAVE_REGEX_H)
-          # Test if a macro is needed for the library.
-          TRY_MACRO_FOR_LIBRARY(
-            "${REGEX_INCLUDE_DIR}" "${REGEX_LIBRARY}"
-            COMPILES
-            "#include <stddef.h>\n#include <regex.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
-            "USE_REGEX_DLL;USE_REGEX_STATIC")
-          IF(USE_REGEX_DLL)
-            ADD_DEFINITIONS(-DUSE_REGEX_DLL)
-          ELSEIF(USE_REGEX_STATIC)
-            ADD_DEFINITIONS(-DUSE_REGEX_STATIC)
-          ENDIF(USE_REGEX_DLL)
-        ENDIF(HAVE_REGCOMP_LIBREGEX)
-      ENDIF(REGEX_LIBRARY)
-      CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
-    ENDIF(NOT HAVE_REGCOMP_LIBC)
-  ENDIF(REGEX_INCLUDE_DIR)
-  IF(HAVE_REGCOMP_LIBC OR HAVE_REGCOMP_LIBREGEX)
-    SET(FOUND_POSIX_REGEX_LIB 1)
-  ENDIF(HAVE_REGCOMP_LIBC OR HAVE_REGCOMP_LIBREGEX)
-ENDIF(POSIX_REGEX_LIB MATCHES "^(AUTO|LIBC|LIBREGEX)$")
-
-IF(NOT FOUND_POSIX_REGEX_LIB AND POSIX_REGEX_LIB MATCHES "^(AUTO|LIBPCREPOSIX)$")
-  #
-  # If requested, try finding library for PCREPOSIX
-  #
-  FIND_PACKAGE(LibGCC)
-  FIND_PACKAGE(PCREPOSIX)
-  IF(PCREPOSIX_FOUND)
-    INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIR})
-    LIST(APPEND ADDITIONAL_LIBS ${PCREPOSIX_LIBRARIES})
-    # Test if a macro is needed for the library.
-    TRY_MACRO_FOR_LIBRARY(
-      "${PCRE_INCLUDE_DIR}" "${PCREPOSIX_LIBRARIES}"
-      COMPILES
-      "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
-      "WITHOUT_PCRE_STATIC;PCRE_STATIC")
-    IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
-      ADD_DEFINITIONS(-DPCRE_STATIC)
-	ELSEIF(NOT WITHOUT_PCRE_STATIC AND NOT PCRE_STATIC AND PCRE_FOUND)
-	  # Determine if pcre static libraries are to be used.
-      LIST(APPEND ADDITIONAL_LIBS ${PCRE_LIBRARIES})
-      SET(TMP_LIBRARIES ${PCREPOSIX_LIBRARIES} ${PCRE_LIBRARIES})
-      MESSAGE(STATUS "trying again with -lpcre included")
-      TRY_MACRO_FOR_LIBRARY(
-        "${PCRE_INCLUDE_DIR}" "${TMP_LIBRARIES}"
-        COMPILES
-        "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
-        "WITHOUT_PCRE_STATIC;PCRE_STATIC")
-      IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
-        ADD_DEFINITIONS(-DPCRE_STATIC)
-      ELSEIF(NOT WITHOUT_PCRE_STATIC AND NOT PCRE_STATIC AND MSVC AND LIBGCC_FOUND)
-        # When doing a Visual Studio build using pcre static libraries
-        # built using the mingw toolchain, -lgcc is needed to resolve
-        # ___chkstk_ms.
-        MESSAGE(STATUS "Visual Studio build detected, trying again with -lgcc included")
-        LIST(APPEND ADDITIONAL_LIBS ${LIBGCC_LIBRARIES})
-        SET(TMP_LIBRARIES ${PCREPOSIX_LIBRARIES} ${PCRE_LIBRARIES} ${LIBGCC_LIBRARIES})
-          TRY_MACRO_FOR_LIBRARY(
-            "${PCRE_INCLUDE_DIR}" "${TMP_LIBRARIES}"
-            COMPILES
-            "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
-            "WITHOUT_PCRE_STATIC;PCRE_STATIC")
-          IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
-            ADD_DEFINITIONS(-DPCRE_STATIC)
-          ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
-      ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
-    ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
-  ENDIF(PCREPOSIX_FOUND)
-  MARK_AS_ADVANCED(CLEAR PCRE_INCLUDE_DIR)
-  MARK_AS_ADVANCED(CLEAR PCREPOSIX_LIBRARIES)
-  MARK_AS_ADVANCED(CLEAR PCRE_LIBRARIES)
-  MARK_AS_ADVANCED(CLEAR LIBGCC_LIBRARIES)
-ENDIF(NOT FOUND_POSIX_REGEX_LIB AND POSIX_REGEX_LIB MATCHES "^(AUTO|LIBPCREPOSIX)$")
-
-#
 # Check functions
 #
 CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3218f52f11713d28bdfedbe6eceddb8cf8502731
commit 3218f52f11713d28bdfedbe6eceddb8cf8502731
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Jul 26 16:44:27 2013 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jul 31 08:20:24 2013 -0400

    libarchive: Avoid struct init with variable
    
    Compilers such as Borland and MIPSpro do not like struct initialization
    with variables.  Initialize using assignment instead.

diff --git a/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c b/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c
index fefcd90..622c960 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c
@@ -103,7 +103,9 @@ int
 archive_read_open_filename(struct archive *a, const char *filename,
     size_t block_size)
 {
-	const char *filenames[2] = { filename, NULL };
+	const char *filenames[2];
+	filenames[0] = filename;
+	filenames[1] = NULL;
 	return archive_read_open_filenames(a, filenames, block_size);
 }
 

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bae3a73ceea6163eeb6eae59dfcf838a43048831
commit bae3a73ceea6163eeb6eae59dfcf838a43048831
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Jul 26 16:25:37 2013 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jul 31 08:20:05 2013 -0400

    libarchive: Silence API deprecation warnings
    
    CMake uses old libarchive APIs for now.

diff --git a/Utilities/cmlibarchive/libarchive/archive.h b/Utilities/cmlibarchive/libarchive/archive.h
index f866978..1a1d32a 100644
--- a/Utilities/cmlibarchive/libarchive/archive.h
+++ b/Utilities/cmlibarchive/libarchive/archive.h
@@ -104,11 +104,8 @@
 #define	__LA_PRINTF(fmtarg, firstvararg)	/* nothing */
 #endif
 
-#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
-# define __LA_DEPRECATED __attribute__((deprecated))
-#else
-# define __LA_DEPRECATED
-#endif
+/* CMake uses some deprecated APIs to build with old libarchive versions.  */
+#define __LA_DEPRECATED
 
 #ifdef __cplusplus
 extern "C" {

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=677384017a343f1ca70342951a39302a683843a2
commit 677384017a343f1ca70342951a39302a683843a2
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Jul 26 16:22:48 2013 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jul 31 08:19:58 2013 -0400

    libarchive: Include cm_zlib.h to get zlib used by CMake
    
    Follow up change from commit ffa6faa4 (libarchive: Include cm_zlib.h to
    get zlib used by CMake, 2011-12-20) for new includes of zlib.h in
    updated libarchive.

diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
index 713af31..7958fa5 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
@@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$");
 #include <lzo/lzo1x.h>
 #endif
 #ifdef HAVE_ZLIB_H
-#include <zlib.h> /* for crc32 and adler32 */
+#include <cm_zlib.h> /* for crc32 and adler32 */
 #endif
 
 #include "archive.h"
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
index bbd50a6..b69c873 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
@@ -119,7 +119,7 @@ __FBSDID("$FreeBSD$");
 #endif
 
 #ifdef HAVE_ZLIB_H
-#include <zlib.h>
+#include <cm_zlib.h>
 #endif
 
 /* TODO: Support Mac OS 'quarantine' feature.  This is really just a

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8dc0a9f898710215bd29fa260f790a7051dbaab2
commit 8dc0a9f898710215bd29fa260f790a7051dbaab2
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Jul 26 16:13:54 2013 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jul 31 08:19:48 2013 -0400

    libarchive: Update README-CMake.txt for new snapshot

diff --git a/Utilities/cmlibarchive/README-CMake.txt b/Utilities/cmlibarchive/README-CMake.txt
index 45cb093..ab105f0 100644
--- a/Utilities/cmlibarchive/README-CMake.txt
+++ b/Utilities/cmlibarchive/README-CMake.txt
@@ -11,7 +11,7 @@ branch, but it is merged into our history.
 Update libarchive from upstream as follows.  Create a local branch to
 explicitly reference the upstream snapshot branch head:
 
- git branch libarchive-upstream 4f4fe6e5
+ git branch libarchive-upstream 35df7c8b
 
 Use a temporary directory to checkout the branch:
 
@@ -24,7 +24,7 @@ Use a temporary directory to checkout the branch:
 Now place the (reduced) libarchive content in this directory.  See
 instructions shown by
 
- git log 4f4fe6e5
+ git log 35df7c8b
 
 for help extracting the content from the upstream svn repo.  Then run
 the following commands to commit the new version.  Substitute the
@@ -34,8 +34,8 @@ appropriate date and version number:
 
  GIT_AUTHOR_NAME='LibArchive Upstream' \
  GIT_AUTHOR_EMAIL='libarchive-discuss at googlegroups.com' \
- GIT_AUTHOR_DATE='2011-12-31 13:54:34 -0500' \
- git commit -m 'libarchive 3.0.2-r4051 (reduced)' &&
+ GIT_AUTHOR_DATE='2013-02-09 12:17:57 -0500' \
+ git commit -m 'libarchive 3.1.2 (reduced)' &&
  git commit --amend
 
 Edit the commit message to describe the procedure used to obtain the

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=102071f80cf4ad7aa97bf8a1618cfc6ee6689ab6
commit 102071f80cf4ad7aa97bf8a1618cfc6ee6689ab6
Merge: 87402c9 35df7c8
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Jul 26 16:08:54 2013 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jul 31 08:19:13 2013 -0400

    Merge branch 'libarchive-upstream' into update-libarchive
    
    Conflicts:
    	Utilities/cmlibarchive/CMakeLists.txt
    	Utilities/cmlibarchive/libarchive/archive.h
    	Utilities/cmlibarchive/libarchive/archive_entry.h
    	Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
    	Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
    	Utilities/cmlibarchive/libarchive/archive_windows.h
    	Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c

diff --cc Utilities/cmlibarchive/CMakeLists.txt
index ebf28ae,0000000..d7a7682
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@@ -1,1114 -1,0 +1,1439 @@@
 +#
++CMAKE_MINIMUM_REQUIRED(VERSION 2.8.6 FATAL_ERROR)
 +#
 +PROJECT(libarchive C)
 +#
- CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
 +SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
 +if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
 +  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${libarchive_BINARY_DIR}/bin)
 +endif()
 +
 +# On MacOS, prefer MacPorts libraries to system libraries.
 +# I haven't come up with a compelling argument for this to be conditional.
 +list(APPEND CMAKE_PREFIX_PATH /opt/local)
 +
 +#
 +# Version - read from 'version' file.
 +#
 +FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/build/version _version)
 +STRING(REGEX REPLACE
 + "^([0-9])[0-9][0-9][0-9][0-9][0-9][0-9][a-z]?$" "\\1" _major ${_version})
 +STRING(REGEX REPLACE
 + "^[0-9]([0-9][0-9][0-9])[0-9][0-9][0-9][a-z]?$" "\\1" _minor ${_version})
 +STRING(REGEX REPLACE
 + "^[0-9][0-9][0-9][0-9]([0-9][0-9][0-9])[a-z]?$" "\\1" _revision ${_version})
 +STRING(REGEX REPLACE
 + "^[0-9][0-9][0-9][0-9][0-9][0-9][0-9]([a-z]?)$" "\\1" _quality ${_version})
 +SET(_version_number ${_major}${_minor}${_revision})
 +STRING(REGEX REPLACE "[0]*([^0]*[0-9])$" "\\1" _trimmed_minor ${_minor})
 +STRING(REGEX REPLACE "[0]*([^0]*[0-9])$" "\\1" _trimmed_revision ${_revision})
 +#
 +SET(VERSION                    "${_major}.${_trimmed_minor}.${_trimmed_revision}${_quality}")
 +SET(BSDCPIO_VERSION_STRING     "${VERSION}")
 +SET(BSDTAR_VERSION_STRING      "${VERSION}")
 +SET(LIBARCHIVE_VERSION_NUMBER  "${_version_number}")
 +SET(LIBARCHIVE_VERSION_STRING  "${VERSION}")
 +
 +# INTERFACE_VERSION increments with every release
 +# libarchive 2.7 == interface version 9 = 2 + 7 
 +# libarchive 2.8 == interface version 10 = 2 + 8
 +# libarchive 2.9 == interface version 11 = 2 + 9
 +# libarchive 3.0 == interface version 12
- # libarchive 3.x == interface version 12 + x
- math(EXPR INTERFACE_VERSION  "12 + ${_minor}")
++# libarchive 3.1 == interface version 13
++math(EXPR INTERFACE_VERSION  "13 + ${_minor}")
 +
 +# Set SOVERSION == Interface version
 +# ?? Should there be more here ??
 +SET(SOVERSION "${INTERFACE_VERSION}")
 +
++# Enalbe CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE() macros
++# saving and restoring the state of the variables.
++INCLUDE(CMakePushCheckState)
++
++# Initialize the state of the variables. This initialization is not
++# necessary but this shows you what value the variables initially have.
++SET(CMAKE_REQUIRED_DEFINITIONS)
++SET(CMAKE_REQUIRED_INCLUDES)
++SET(CMAKE_REQUIRED_LIBRARIES)
++SET(CMAKE_REQUIRED_FLAGS)
++
 +# Disable warnings to avoid changing 3rd party code.
 +IF("${CMAKE_C_COMPILER_ID}" MATCHES
 +    "^(GNU|Clang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
 +  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 +ELSEIF("${CMAKE_C_COMPILER_ID}" MATCHES "^(PathScale)$")
 +  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
 +ELSEIF(BORLAND)
 +  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-")
 +ENDIF()
 +
 +# Enable CTest/CDash support
 +include(CTest)
 +
 +OPTION(ENABLE_NETTLE "Enable use of Nettle" ON)
 +OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON)
 +OPTION(ENABLE_XATTR "Enable extended attribute support" ON)
 +OPTION(ENABLE_ACL "Enable ACL support" ON)
 +OPTION(ENABLE_ICONV "Enable iconv support" ON)
++SET(POSIX_REGEX_LIB "AUTO" CACHE STRING "Choose what library should provide POSIX regular expression support")
++SET(ENABLE_SAFESEH "AUTO" CACHE STRING "Enable use of /SAFESEH linker flag (MSVC only)")
 +
 +IF(WIN32)
 +  IF(MSVC60)
 +    SET(WINVER 0x0400)
 +  ELSE()
 +    SET(WINVER 0x0500)
 +  ENDIF()
 +  SET(_WIN32_WINNT ${WINVER})
 +ENDIF(WIN32)
 +
++IF(MSVC)
++  IF(ENABLE_SAFESEH STREQUAL "YES")
++    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH")
++    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH")
++    SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH")
++	SET(CMAKE_REQUIRED_LINKER_FLAGS "/SAFESEH")
++  ELSEIF(ENABLE_SAFESEH STREQUAL "NO")
++    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
++    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
++    SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
++	SET(CMAKE_REQUIRED_LINKER_FLAGS "/SAFESEH:NO")
++  ENDIF(ENABLE_SAFESEH STREQUAL "YES")
++ENDIF(MSVC)
++
 +IF("${CMAKE_C_PLATFORM_ID}" MATCHES "^(HP-UX)$")
 +  ADD_DEFINITIONS(-D_XOPEN_SOURCE=500) # Ask wchar.h for mbstate_t
 +ENDIF()
 +
 +#
- INCLUDE(CheckCSourceCompiles)
- INCLUDE(CheckCSourceRuns)
++INCLUDE(LibarchiveCheckCSourceCompiles)
++INCLUDE(LibarchiveCheckCSourceRuns)
 +INCLUDE(CheckFileOffsetBits)
 +INCLUDE(CheckFuncs)
 +INCLUDE(CheckHeaderDirent)
 +INCLUDE(CheckIncludeFile)
 +INCLUDE(CheckIncludeFiles)
 +INCLUDE(CheckLibraryExists)
 +INCLUDE(CheckStructMember)
 +INCLUDE(CheckSymbolExists)
 +INCLUDE(CheckTypeExists)
 +INCLUDE(CheckTypeSize)
 +
 +#
 +# Generate list.h
 +#
 +MACRO (GENERATE_LIST_H _listfile _cmlist __list_sources)
 +  SET(_argv ${ARGV})
 +  # Remove _listfile and _cmlist from _argv
 +  LIST(REMOVE_AT _argv 0 1)
 +  IF (NOT EXISTS "${_listfile}" OR
 +     ${_cmlist} IS_NEWER_THAN "${_listfile}")
 +
 +    MESSAGE(STATUS "Generating ${_listfile}")
 +    FILE(WRITE ${_listfile} "")
 +    FOREACH (testfile ${_argv})
 +      IF (testfile MATCHES "^test_[^/]+[.]c$")
 +        FILE(STRINGS ${testfile} testvar REGEX "^DEFINE_TEST")
 +        FOREACH (deftest ${testvar})
 +          FILE(APPEND ${_listfile} "${deftest}\n")
 +        ENDFOREACH (deftest)
 +      ENDIF (testfile MATCHES "^test_[^/]+[.]c$")
 +    ENDFOREACH (testfile)
 +
 +  ENDIF (NOT EXISTS "${_listfile}" OR
 +     ${_cmlist} IS_NEWER_THAN "${_listfile}")
 +ENDMACRO (GENERATE_LIST_H)
 +#
 +# Generate installation rules for man pages.
 +#
 +MACRO (INSTALL_MAN __mans)
 +  FOREACH (_man ${ARGV})
 +    STRING(REGEX REPLACE "^.+[.]([1-9])" "\\1" _mansect ${_man})
 +    INSTALL(FILES ${_man} DESTINATION "share/man/man${_mansect}")
 +  ENDFOREACH (_man)
 +ENDMACRO (INSTALL_MAN __mans)
- 
++#
++# Find out what macro is needed to use libraries on Windows.
++#
++MACRO (TRY_MACRO_FOR_LIBRARY INCLUDES LIBRARIES
++       TRY_TYPE SAMPLE_SOURCE MACRO_LIST)
++  IF(WIN32 AND NOT CYGWIN)
++    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
++    SET(CMAKE_REQUIRED_INCLUDES ${INCLUDES})
++    SET(CMAKE_REQUIRED_LIBRARIES ${LIBRARIES})
++    FOREACH(VAR ${MACRO_LIST})
++      # Clear ${VAR} from CACHE If the libraries which ${VAR} was
++      # checked with are changed.
++      SET(VAR_WITH_LIB "${VAR}_WITH_LIB")
++      GET_PROPERTY(PREV_VAR_WITH_LIB VARIABLE PROPERTY ${VAR_WITH_LIB})
++      IF(NOT "${PREV_VAR_WITH_LIB}" STREQUAL "${LIBRARIES}")
++        UNSET(${VAR} CACHE)
++      ENDIF(NOT "${PREV_VAR_WITH_LIB}" STREQUAL "${LIBRARIES}")
++      # Check if the library can be used with the macro.
++      IF("${TRY_TYPE}" MATCHES "COMPILES")
++        LIBARCHIVE_CHECK_C_SOURCE_COMPILES("${SAMPLE_SOURCE}" ${VAR})
++      ELSEIF("${TRY_TYPE}" MATCHES "RUNS")
++        LIBARCHIVE_CHECK_C_SOURCE_RUNS("${SAMPLE_SOURCE}" ${VAR})
++      ELSE("${TRY_TYPE}" MATCHES "COMPILES")
++        MESSAGE(FATAL_ERROR "UNKNOWN KEYWORD \"${TRY_TYPE}\" FOR TRY_TYPE")
++      ENDIF("${TRY_TYPE}" MATCHES "COMPILES")
++      # Save the libraries which ${VAR} is checked with.
++      SET(${VAR_WITH_LIB} "${LIBRARIES}" CACHE INTERNAL
++          "Macro ${VAR} is checked with")
++    ENDFOREACH(VAR)
++    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
++  ENDIF(WIN32 AND NOT CYGWIN)
++ENDMACRO (TRY_MACRO_FOR_LIBRARY)
 +#
 +# Check compress/decompress libraries
 +#
 +IF(WIN32 AND NOT CMAKE_CL_64 AND NOT CYGWIN)
 +  # GnuWin32 is only for Win32, not Win64.
 +  SET(__GNUWIN32PATH "C:/Program Files/GnuWin32")
 +ENDIF(WIN32 AND NOT CMAKE_CL_64 AND NOT CYGWIN)
 +IF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}")
 +  # You have to add a path availabel DLL file into PATH environment variable.
 +  # Maybe DLL path is "C:/Program Files/GnuWin32/bin".
 +  # The zlib and the bzip2 Setup program have installed programs and DLLs into
 +  # "C:/Program Files/GnuWin32" by default.
 +  # This is convenience setting for Windows.
 +  SET(CMAKE_PREFIX_PATH ${__GNUWIN32PATH} $(CMAKE_PREFIX_PATH))
 +  #
 +  # If you didn't use Setup program or installed into nonstandard path,
 +  # cmake cannot find out your zlib or bzip2 libraries and include files,
 +  # you should execute cmake with  -DCMAKE_PREFIX_PATH option.
 +  #   e.g.
 +  #     cmake -DCMAKE_PREFIX_PATH=<your-GnuWin32-path> <path-to-source>
 +  #
 +  # If compiling error occured in zconf.h, You may need patch to zconf.h.
 +  #--- zconf.h.orig	2005-07-21 00:40:26.000000000
 +  #+++ zconf.h	2009-01-19 11:39:10.093750000
 +  #@@ -286,7 +286,7 @@
 +  # 
 +  # #if 1           /* HAVE_UNISTD_H -- this line is updated by ./configure */
 +  # #  include <sys/types.h> /* for off_t */
 +  #-#  include <unistd.h>    /* for SEEK_* and off_t */
 +  #+#  include <stdio.h>    /* for SEEK_* and off_t */
 +  # #  ifdef VMS
 +  # #    include <unixio.h>   /* for off_t */
 +  # #  endif
 +ENDIF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}")
 +
 +SET(ADDITIONAL_LIBS "")
 +#
 +# Find ZLIB
 +#
 +FIND_PACKAGE(ZLIB)
 +IF(ZLIB_FOUND)
 +  SET(HAVE_LIBZ 1)
 +  SET(HAVE_ZLIB_H 1)
 +  INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
 +  LIST(APPEND ADDITIONAL_LIBS ${ZLIB_LIBRARIES})
 +  IF(WIN32 AND NOT CYGWIN)
-     SET(CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIR})
-     SET(CMAKE_REQUIRED_LIBRARIES ${ZLIB_LIBRARIES})
-     CHECK_C_SOURCE_Runs(
-       "#ifndef ZLIB_WINAPI\n#define ZLIB_WINAPI\n#endif\n#include <zlib.h>\nint main() {uLong f = zlibCompileFlags(); return (f&(1U<<10))?0:-1; }"
++    #
++    # Test if ZLIB_WINAPI macro is needed to use.
++    #
++    TRY_MACRO_FOR_LIBRARY(
++      "${ZLIB_INCLUDE_DIR}" "${ZLIB_LIBRARIES}"
++      RUNS
++      "#include <zlib.h>\nint main() {uLong f = zlibCompileFlags(); return (f&(1U<<10))?0:-1; }"
 +      ZLIB_WINAPI)
-     SET(CMAKE_REQUIRED_INCLUDES)
-     SET(CMAKE_REQUIRED_LIBRARIES)
++    IF(ZLIB_WINAPI)
++      ADD_DEFINITIONS(-DZLIB_WINAPI)
++    ELSE(ZLIB_WINAPI)
++      # Test if a macro is needed for the library.
++      TRY_MACRO_FOR_LIBRARY(
++        "${ZLIB_INCLUDE_DIR}" "${ZLIB_LIBRARIES}"
++        COMPILES
++        "#include <zlib.h>\nint main() {return zlibVersion()?1:0; }"
++        "ZLIB_DLL;WITHOUT_ZLIB_DLL")
++      IF(ZLIB_DLL)
++        ADD_DEFINITIONS(-DZLIB_DLL)
++      ENDIF(ZLIB_DLL)
++    ENDIF(ZLIB_WINAPI)
 +  ENDIF(WIN32 AND NOT CYGWIN)
 +ELSE(ZLIB_FOUND)
 +  MESSAGE(FATAL_ERROR "CMake requires zlib to be available to libarchive")
 +ENDIF(ZLIB_FOUND)
 +#
 +# Find BZip2
 +#
 +FIND_PACKAGE(BZip2)
 +IF(BZIP2_FOUND)
 +  SET(HAVE_LIBBZ2 1)
 +  SET(HAVE_BZLIB_H 1)
 +  INCLUDE_DIRECTORIES(${BZIP2_INCLUDE_DIR})
 +  LIST(APPEND ADDITIONAL_LIBS ${BZIP2_LIBRARIES})
++  # Test if a macro is needed for the library.
++  TRY_MACRO_FOR_LIBRARY(
++    "${BZIP2_INCLUDE_DIR}" "${BZIP2_LIBRARIES}"
++    COMPILES
++    "#include <bzlib.h>\nint main() {return BZ2_bzlibVersion()?1:0; }"
++    "USE_BZIP2_DLL;USE_BZIP2_STATIC")
++  IF(USE_BZIP2_DLL)
++    ADD_DEFINITIONS(-DUSE_BZIP2_DLL)
++  ELSEIF(USE_BZIP2_STATIC)
++    ADD_DEFINITIONS(-DUSE_BZIP2_STATIC)
++  ENDIF(USE_BZIP2_DLL)
 +ENDIF(BZIP2_FOUND)
 +MARK_AS_ADVANCED(CLEAR BZIP2_INCLUDE_DIR)
- MARK_AS_ADVANCED(CLEAR BZIP2_LIBRARY)
- 
- IF(0) # CMake does not need LZMA support in libarchive
++MARK_AS_ADVANCED(CLEAR BZIP2_LIBRARIES)
++IF(0) # CMake does not need LZMA or LZO2 support in libarchive
 +#
 +# Find LZMA
 +#
 +FIND_PACKAGE(LZMA)
 +IF(LZMA_FOUND)
 +  SET(HAVE_LIBLZMA 1)
 +  SET(HAVE_LZMA_H 1)
 +  INCLUDE_DIRECTORIES(${LZMA_INCLUDE_DIR})
 +  LIST(APPEND ADDITIONAL_LIBS ${LZMA_LIBRARIES})
++  # Test if a macro is needed for the library.
++  TRY_MACRO_FOR_LIBRARY(
++    "${LZMA_INCLUDE_DIR}" "${LZMA_LIBRARIES}"
++    COMPILES
++    "#include <lzma.h>\nint main() {return (int)lzma_version_number(); }"
++    "WITHOUT_LZMA_API_STATIC;LZMA_API_STATIC")
++  IF(NOT WITHOUT_LZMA_API_STATIC AND LZMA_API_STATIC)
++    ADD_DEFINITIONS(-DLZMA_API_STATIC)
++  ENDIF(NOT WITHOUT_LZMA_API_STATIC AND LZMA_API_STATIC)
 +ELSEIF(LZMADEC_FOUND)
 +  SET(HAVE_LIBLZMADEC 1)
 +  SET(HAVE_LZMADEC_H 1)
 +  INCLUDE_DIRECTORIES(${LZMADEC_INCLUDE_DIR})
 +  LIST(APPEND ADDITIONAL_LIBS ${LZMADEC_LIBRARIES})
 +ENDIF(LZMA_FOUND)
++#
++# Find LZO2
++#
++IF (LZO2_INCLUDE_DIR)
++  # Already in cache, be silent
++  SET(LZO2_FIND_QUIETLY TRUE)
++ENDIF (LZO2_INCLUDE_DIR)
++
++FIND_PATH(LZO2_INCLUDE_DIR lzo/lzoconf.h)
++FIND_LIBRARY(LZO2_LIBRARY NAMES lzo2 liblzo2)
++INCLUDE(FindPackageHandleStandardArgs)
++FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZO2 DEFAULT_MSG LZO2_LIBRARY LZO2_INCLUDE_DIR)
++IF(LZO2_FOUND)
++  SET(HAVE_LIBLZO2 1)
++  SET(HAVE_LZO_LZOCONF_H 1)
++  SET(HAVE_LZO_LZO1X_H 1)
++  INCLUDE_DIRECTORIES(${LZO2_INCLUDE_DIR})
++  LIST(APPEND ADDITIONAL_LIBS ${LZO2_LIBRARY})
++  #
++  # TODO: test for static library.
++  #
++ENDIF(LZO2_FOUND)
++MARK_AS_ADVANCED(CLEAR LZO2_INCLUDE_DIR)
++MARK_AS_ADVANCED(CLEAR LZO2_LIBRARY)
 +ENDIF()
 +
 +#
 +# Check headers
 +#
 +CHECK_HEADER_DIRENT()
 +
 +SET(INCLUDES "")
 +MACRO (LA_CHECK_INCLUDE_FILE header var)
 +      CHECK_INCLUDE_FILES("${INCLUDES};${header}" ${var})
 +      IF (${var})
 +      	 SET(INCLUDES ${INCLUDES} ${header})
 +      ENDIF (${var})
 +ENDMACRO (LA_CHECK_INCLUDE_FILE)
 +
 +# Some FreeBSD headers assume sys/types.h was already included.
 +LA_CHECK_INCLUDE_FILE("sys/types.h" HAVE_SYS_TYPES_H)
 +
 +# Alphabetize the rest unless there's a compelling reason
 +LA_CHECK_INCLUDE_FILE("acl/libacl.h" HAVE_ACL_LIBACL_H)
 +LA_CHECK_INCLUDE_FILE("ctype.h" HAVE_CTYPE_H)
 +LA_CHECK_INCLUDE_FILE("copyfile.h" HAVE_COPYFILE_H)
 +LA_CHECK_INCLUDE_FILE("direct.h" HAVE_DIRECT_H)
 +LA_CHECK_INCLUDE_FILE("dlfcn.h" HAVE_DLFCN_H)
 +LA_CHECK_INCLUDE_FILE("errno.h" HAVE_ERRNO_H)
 +LA_CHECK_INCLUDE_FILE("ext2fs/ext2_fs.h" HAVE_EXT2FS_EXT2_FS_H)
 +
- CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
++LIBARCHIVE_CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
 +#include <ext2fs/ext2_fs.h>
 +int main(void) { return EXT2_IOC_GETFLAGS; }" HAVE_WORKING_EXT2_IOC_GETFLAGS)
 +
 +LA_CHECK_INCLUDE_FILE("fcntl.h" HAVE_FCNTL_H)
 +LA_CHECK_INCLUDE_FILE("grp.h" HAVE_GRP_H)
 +LA_CHECK_INCLUDE_FILE("inttypes.h" HAVE_INTTYPES_H)
 +LA_CHECK_INCLUDE_FILE("io.h" HAVE_IO_H)
 +LA_CHECK_INCLUDE_FILE("langinfo.h" HAVE_LANGINFO_H)
 +LA_CHECK_INCLUDE_FILE("limits.h" HAVE_LIMITS_H)
 +LA_CHECK_INCLUDE_FILE("linux/types.h" HAVE_LINUX_TYPES_H)
 +LA_CHECK_INCLUDE_FILE("linux/fiemap.h" HAVE_LINUX_FIEMAP_H)
 +LA_CHECK_INCLUDE_FILE("linux/fs.h" HAVE_LINUX_FS_H)
 +LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H)
 +LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H)
 +LA_CHECK_INCLUDE_FILE("memory.h" HAVE_MEMORY_H)
 +LA_CHECK_INCLUDE_FILE("paths.h" HAVE_PATHS_H)
 +LA_CHECK_INCLUDE_FILE("poll.h" HAVE_POLL_H)
 +LA_CHECK_INCLUDE_FILE("process.h" HAVE_PROCESS_H)
 +LA_CHECK_INCLUDE_FILE("pwd.h" HAVE_PWD_H)
 +LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
 +LA_CHECK_INCLUDE_FILE("signal.h" HAVE_SIGNAL_H)
++LA_CHECK_INCLUDE_FILE("spawn.h" HAVE_SPAWN_H)
 +LA_CHECK_INCLUDE_FILE("stdarg.h" HAVE_STDARG_H)
 +LA_CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H)
 +LA_CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H)
 +LA_CHECK_INCLUDE_FILE("string.h" HAVE_STRING_H)
 +LA_CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H)
 +LA_CHECK_INCLUDE_FILE("sys/acl.h" HAVE_SYS_ACL_H)
 +LA_CHECK_INCLUDE_FILE("sys/cdefs.h" HAVE_SYS_CDEFS_H)
 +LA_CHECK_INCLUDE_FILE("sys/ioctl.h" HAVE_SYS_IOCTL_H)
 +LA_CHECK_INCLUDE_FILE("sys/mkdev.h" HAVE_SYS_MKDEV_H)
 +LA_CHECK_INCLUDE_FILE("sys/mount.h" HAVE_SYS_MOUNT_H)
 +LA_CHECK_INCLUDE_FILE("sys/param.h" HAVE_SYS_PARAM_H)
 +LA_CHECK_INCLUDE_FILE("sys/poll.h" HAVE_SYS_POLL_H)
 +LA_CHECK_INCLUDE_FILE("sys/select.h" HAVE_SYS_SELECT_H)
 +LA_CHECK_INCLUDE_FILE("sys/stat.h" HAVE_SYS_STAT_H)
 +LA_CHECK_INCLUDE_FILE("sys/statfs.h" HAVE_SYS_STATFS_H)
 +LA_CHECK_INCLUDE_FILE("sys/statvfs.h" HAVE_SYS_STATVFS_H)
 +LA_CHECK_INCLUDE_FILE("sys/time.h" HAVE_SYS_TIME_H)
 +LA_CHECK_INCLUDE_FILE("sys/utime.h" HAVE_SYS_UTIME_H)
 +LA_CHECK_INCLUDE_FILE("sys/utsname.h" HAVE_SYS_UTSNAME_H)
 +LA_CHECK_INCLUDE_FILE("sys/vfs.h" HAVE_SYS_VFS_H)
 +LA_CHECK_INCLUDE_FILE("sys/wait.h" HAVE_SYS_WAIT_H)
 +LA_CHECK_INCLUDE_FILE("time.h" HAVE_TIME_H)
 +LA_CHECK_INCLUDE_FILE("unistd.h" HAVE_UNISTD_H)
 +LA_CHECK_INCLUDE_FILE("utime.h" HAVE_UTIME_H)
 +LA_CHECK_INCLUDE_FILE("wchar.h" HAVE_WCHAR_H)
 +LA_CHECK_INCLUDE_FILE("wctype.h" HAVE_WCTYPE_H)
 +LA_CHECK_INCLUDE_FILE("windows.h" HAVE_WINDOWS_H)
 +# Following files need windwos.h, so we should test it after windows.h test.
 +LA_CHECK_INCLUDE_FILE("wincrypt.h" HAVE_WINCRYPT_H)
 +LA_CHECK_INCLUDE_FILE("winioctl.h" HAVE_WINIOCTL_H)
 +
 +#
 +# Check whether use of __EXTENSIONS__ is safe.
 +# We need some macro such as _GNU_SOURCE to use extension functions.
 +#
 +SET(_INCLUDE_FILES)
 +FOREACH (it ${_HEADER})
 +   SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
 +ENDFOREACH (it)
 +
- CHECK_C_SOURCE_COMPILES(
++LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
 +  "#define __EXTENSIONS__ 1
 +   ${_INCLUDE_FILES}
 +   int main() { return 0;}"
 + SAFE_TO_DEFINE_EXTENSIONS)
 +
 +#
 +# Find Nettle
 +#
 +IF(ENABLE_NETTLE)
-   CHECK_LIBRARY_EXISTS(nettle "nettle_sha1_digest" "" NETTLE_FOUND)
++  FIND_PACKAGE(Nettle)
 +  IF(NETTLE_FOUND)
-     SET(CMAKE_REQUIRED_LIBRARIES "nettle")
-     FIND_LIBRARY(NETTLE_LIBRARY NAMES nettle)
-     LIST(APPEND ADDITIONAL_LIBS ${NETTLE_LIBRARY})
-   ELSE(NETTLE_FOUND)
-     SET(ENABLE_NETTLE OFF)
++    SET(HAVE_LIBNETTLE 1)
++    SET(HAVE_NETTLE_MD5_H 1)
++    SET(HAVE_NETTLE_RIPEMD160_H 1)
++    SET(HAVE_NETTLE_SHA_H 1)
++    INCLUDE_DIRECTORIES(${NETTLE_INCLUDE_DIR})
++    LIST(APPEND ADDITIONAL_LIBS ${NETTLE_LIBRARIES})
 +  ENDIF(NETTLE_FOUND)
++  MARK_AS_ADVANCED(CLEAR NETTLE_INCLUDE_DIR)
++  MARK_AS_ADVANCED(CLEAR NETTLE_LIBRARIES)
 +ENDIF(ENABLE_NETTLE)
 +
 +#
 +# Find OpenSSL
 +# (Except on Mac, where OpenSSL is deprecated.)
 +#
 +IF(ENABLE_OPENSSL AND NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
 +  FIND_PACKAGE(OpenSSL)
 +ELSE()
 +  SET(OPENSSL_FOUND FALSE) # Override cached value
 +ENDIF()
 +
 +# FreeBSD libmd
- CHECK_LIBRARY_EXISTS(md "MD5Init" "" LIBMD_FOUND)
- IF(LIBMD_FOUND)
-   SET(CMAKE_REQUIRED_LIBRARIES "md")
-   FIND_LIBRARY(LIBMD_LIBRARY NAMES md)
-   LIST(APPEND ADDITIONAL_LIBS ${LIBMD_LIBRARY})
- ENDIF(LIBMD_FOUND)
++IF(NOT OPENSSL_FOUND)
++  CHECK_LIBRARY_EXISTS(md "MD5Init" "" LIBMD_FOUND)
++  IF(LIBMD_FOUND)
++    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
++    SET(CMAKE_REQUIRED_LIBRARIES "md")
++    FIND_LIBRARY(LIBMD_LIBRARY NAMES md)
++    LIST(APPEND ADDITIONAL_LIBS ${LIBMD_LIBRARY})
++    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
++  ENDIF(LIBMD_FOUND)
++ENDIF(NOT OPENSSL_FOUND)
 +
 +#
 +# How to prove that CRYPTO functions, which have several names on various
 +# platforms, just see if archive_crypto.c can compile and link against
 +# required libraries.
 +#
 +MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
-     IF(HAVE_SYS_TYPES_H)
-         SET(CRYPTO_HEADER_CONFIG "#define HAVE_SYS_TYPES_H 1\n")
-     ELSE(HAVE_SYS_TYPES_H)
-         SET(CRYPTO_HEADER_CONFIG "")
-     ENDIF(HAVE_SYS_TYPES_H)
- 
 +    FOREACH(ALGORITHM ${ALGORITHMS})
++      IF(NOT ARCHIVE_CRYPTO_${ALGORITHM})
 +      STRING(TOLOWER "${ALGORITHM}" lower_algorithm)
 +      STRING(TOUPPER "${ALGORITHM}" algorithm)
 +      IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND NOT OPENSSL_FOUND)
 +        SET(ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} FALSE)
 +      ELSEIF("${IMPLEMENTATION}" MATCHES "^NETTLE$" AND NOT NETTLE_FOUND)
 +        SET(ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} FALSE)
 +      ENDIF("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND NOT OPENSSL_FOUND)
 +
 +      IF(NOT DEFINED ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +        # Probe the local implementation for whether this
 +	# crypto implementation is available on this platform.
 +	SET(TRY_CRYPTO_REQUIRED_INCLUDES
- 	  "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_CURRENT_SOURCE_DIR}/libarchive;${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
++	  "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive;${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
 +	SET(TRY_CRYPTO_REQUIRED_LIBS)
 +	IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 +	    SET(TRY_CRYPTO_REQUIRED_INCLUDES
 +	      "${TRY_CRYPTO_REQUIRED_INCLUDES};${OPENSSL_INCLUDE_DIR}")
 +	    SET(TRY_CRYPTO_REQUIRED_LIBS
 +	        "-DLINK_LIBRARIES:STRING=${OPENSSL_LIBRARIES}")
 +	ELSEIF("${IMPLEMENTATION}" MATCHES "^NETTLE$" AND NETTLE_FOUND)
++	    SET(TRY_CRYPTO_REQUIRED_INCLUDES
++	      "${TRY_CRYPTO_REQUIRED_INCLUDES};${NETTLE_INCLUDE_DIR}")
 +	    SET(TRY_CRYPTO_REQUIRED_LIBS
 +	        "-DLINK_LIBRARIES:STRING=${NETTLE_LIBRARY}")
 +	ELSEIF("${IMPLEMENTATION}" MATCHES "^LIBMD$" AND LIBMD_FOUND)
 +	    SET(TRY_CRYPTO_REQUIRED_LIBS
 +	        "-DLINK_LIBRARIES:STRING=${LIBMD_LIBRARY}")
 +	ENDIF("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 +
++    CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in
++      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h)
++	FILE(READ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h"
++	     CONFDEFS_H)
 +	FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/libarchive/archive_crypto.c"
 +	     ARCHIVE_CRYPTO_C)
 +
- 	SET(SOURCE "
++	SET(SOURCE "${CONFDEFS_H}
++
 +#define ARCHIVE_${algorithm}_COMPILE_TEST
 +#define ARCHIVE_CRYPTO_${algorithm}_${IMPLEMENTATION}
 +#define PLATFORM_CONFIG_H \"check_crypto_md.h\"
 +
 +${ARCHIVE_CRYPTO_C}
 +
 +int
 +main(int argc, char **argv)
 +{
-   archive_${lower_crypto}_ctx ctx;
-   archive_${lower_crypto}_init(&ctx);
-   archive_${lower_crypto}_update(&ctx, *argv, argc);
-   archive_${lower_crypto}_final(&ctx, NULL);
++  archive_${lower_algorithm}_ctx ctx;
++  archive_${lower_algorithm}_init(&ctx);
++  archive_${lower_algorithm}_update(&ctx, *argv, argc);
++  archive_${lower_algorithm}_final(&ctx, NULL);
 +  return 0;
 +}
 +")
 +
 +  FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.h" "")
 +	FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c" "${SOURCE}")
 +	MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}")
 +
++    IF(CMAKE_REQUIRED_LINKER_FLAGS)
++      SET(CHECK_CRYPTO_ADD_LINKER_FLAGS
++        "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
++    ELSE(CMAKE_REQUIRED_LINKER_FLAGS)
++      SET(CHECK_CRYPTO_ADD_LINKER_FLAGS)
++    ENDIF(CMAKE_REQUIRED_LINKER_FLAGS)
 +	TRY_COMPILE(ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}
 +	  ${CMAKE_BINARY_DIR}
 +	  ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c
- 	  CMAKE_FLAGS
++	  CMAKE_FLAGS ${CHECK_CRYPTO_ADD_LINKER_FLAGS}
 +	   "${TRY_CRYPTO_REQUIRED_LIBS}"
 +	   "${TRY_CRYPTO_REQUIRED_INCLUDES}"
 +	  OUTPUT_VARIABLE OUTPUT)
 +
 +	# Inform user whether or not we found it; if not, log why we didn't.
 +        IF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +          MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} -- found")
++		  SET(ARCHIVE_CRYPTO_${ALGORITHM} 1)
 +        ELSE (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +          MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} -- not found")
 +          FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
 +    	    "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} failed with the following output:\n"
 +    	    "${OUTPUT}\n"
 +    	    "Source file was:\n${SOURCE}\n")
 +        ENDIF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +      ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +
 +      # Add appropriate libs/includes depending on whether the implementation
 +      # was found on this platform.
 +      IF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
 +        IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 +          INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
 +	  LIST(APPEND ADDITIONAL_LIBS ${OPENSSL_LIBRARIES})
 +	   LIST(REMOVE_DUPLICATES ADDITIONAL_LIBS)
 +        ENDIF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 +      ENDIF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
++      ENDIF(NOT ARCHIVE_CRYPTO_${ALGORITHM})
 +    ENDFOREACH(ALGORITHM ${ALGORITHMS})
 +ENDMACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 +
 +#
 +# CRYPTO functions on Windows is defined at archive_windows.c, thus we do not
 +# need the test what the functions can be mapped to archive_{crypto name}_init,
 +# archive_{crypto name}_update and archive_{crypto name}_final.
 +# The functions on Windows use CALG_{crypto name} macro to create a crypt object
 +# and then we need to know what CALG_{crypto name} macros is available to show
 +# ARCHIVE_CRYPTO_{crypto name}_WIN macros because Windows 2000 and earlier version
 +# of Windows XP do not support SHA256, SHA384 and SHA512.
 +#
 +MACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 +  IF(WIN32 AND NOT CYGWIN)
 +    FOREACH(CRYPTO ${CRYPTO_LIST})
++      IF(NOT ARCHIVE_CRYPTO_${CRYPTO})
 +      IF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 +	STRING(TOUPPER "${CRYPTO}" crypto)
 +	SET(ALGID "")
 +	IF ("${CRYPTO}" MATCHES "^MD5$")
 +	    SET(ALGID "CALG_MD5")
 +	ENDIF ("${CRYPTO}" MATCHES "^MD5$")
 +	IF ("${CRYPTO}" MATCHES "^SHA1$")
 +	    SET(ALGID "CALG_SHA1")
 +	ENDIF ("${CRYPTO}" MATCHES "^SHA1$")
 +	IF ("${CRYPTO}" MATCHES "^SHA256$")
 +	    SET(ALGID "CALG_SHA_256")
 +	ENDIF ("${CRYPTO}" MATCHES "^SHA256$")
 +	IF ("${CRYPTO}" MATCHES "^SHA384$")
 +	    SET(ALGID "CALG_SHA_384")
 +	ENDIF ("${CRYPTO}" MATCHES "^SHA384$")
 +	IF ("${CRYPTO}" MATCHES "^SHA512$")
 +	    SET(ALGID "CALG_SHA_512")
 +	ENDIF ("${CRYPTO}" MATCHES "^SHA512$")
 +
- 	SET(SOURCE "#define ${crypto}_COMPILE_TEST
- #define _WIN32_WINNT ${_WIN32_WINNT}
- #define WINVER ${WINVER}
++    CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in
++      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h)
++	FILE(READ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h"
++	     CONFDEFS_H)
++
++	SET(SOURCE "${CONFDEFS_H}
++
++#define ${crypto}_COMPILE_TEST
 +#include <windows.h>
 +#include <wincrypt.h>
 +
 +int
 +main(int argc, char **argv)
 +{
 +	return ${ALGID};
 +}
 +")
 +	SET(SOURCE_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_win.c")
 +
 +	FILE(WRITE "${SOURCE_FILE}" "${SOURCE}")
 +	MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN")
 +
++    IF(CMAKE_REQUIRED_LINKER_FLAGS)
++      SET(CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS
++        "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
++    ELSE(CMAKE_REQUIRED_LINKER_FLAGS)
++      SET(CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS)
++    ENDIF(CMAKE_REQUIRED_LINKER_FLAGS)
 +	TRY_COMPILE(ARCHIVE_CRYPTO_${CRYPTO}_WIN
 +	  ${CMAKE_BINARY_DIR}
 +	  ${SOURCE_FILE}
- 	  CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_CURRENT_SOURCE_DIR}/libarchive"
++	  CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive" ${CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS}
 +	  OUTPUT_VARIABLE OUTPUT)
 +
 +	IF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 +	    MESSAGE(STATUS
 +	        "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- found")
++		SET(ARCHIVE_CRYPTO_${CRYPTO} 1)
 +	ELSE (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 +	    MESSAGE(STATUS
 +	         "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- not found")
 +    	    FILE(APPEND
 +	        ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
 +                "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN failed with the following output:\n"
 +        	"${OUTPUT}\n"
 +        	"Source file was:\n${SOURCE}\n")
 +	ENDIF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 +
 +      ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
++      ENDIF(NOT ARCHIVE_CRYPTO_${CRYPTO})
 +    ENDFOREACH(CRYPTO)
 +  ENDIF(WIN32 AND NOT CYGWIN)
 +ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 +
 +#
 +# Find iconv
 +# POSIX defines the second arg as const char **
 +# and requires it to be in libc.  But we can accept
 +# a non-const argument here and can support iconv()
 +# being in libiconv.
 +#
 +MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
 +  IF(NOT HAVE_ICONV)
-     CHECK_C_SOURCE_COMPILES(
++    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
++    IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
++      #
++      # During checking iconv proto type, we should use -Werror to avoid the
++      # success of iconv detection with a warnig which success is a miss
++      # detection. So this needs for all build mode(even it's a release mode).
++      #
++      SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
++    ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
++    IF (MSVC)
++      # NOTE: /WX option is the same as gcc's -Werror option.
++      SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /WX")
++    ENDIF (MSVC)
++    #
++    LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
 +      "#include <stdlib.h>
 +       #include <iconv.h>
 +       int main() {
 +          ${TRY_ICONV_CONST} char *ccp;
 +          iconv_t cd = iconv_open(\"\", \"\");
 +          iconv(cd, &ccp, (size_t *)0, (char **)0, (size_t *)0);
 +          iconv_close(cd);
 +          return 0;
 +       }"
 +     HAVE_ICONV_${LIB}_${TRY_ICONV_CONST})
 +    IF(HAVE_ICONV_${LIB}_${TRY_ICONV_CONST})
 +      SET(HAVE_ICONV true)
 +      SET(ICONV_CONST ${TRY_ICONV_CONST})
 +    ENDIF(HAVE_ICONV_${LIB}_${TRY_ICONV_CONST})
++    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
 +  ENDIF(NOT HAVE_ICONV)
 +ENDMACRO(CHECK_ICONV TRY_ICONV_CONST)
 +
 +IF(ENABLE_ICONV)
++  CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
 +  FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
 +  MARK_AS_ADVANCED(ICONV_INCLUDE_DIR)
 +  IF(ICONV_INCLUDE_DIR)
 +    #SET(INCLUDES ${INCLUDES} "iconv.h")
 +    SET(HAVE_ICONV_H 1)
 +    INCLUDE_DIRECTORIES(${ICONV_INCLUDE_DIR})
 +    SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
 +    CHECK_ICONV("libc" "const")
 +    CHECK_ICONV("libc" "")
 +
 +    # If iconv isn't in libc and we have a libiconv, try that.
-     FIND_LIBRARY(LIBICONV_PATH iconv)
++    FIND_LIBRARY(LIBICONV_PATH NAMES iconv libiconv)
 +    IF(NOT HAVE_ICONV AND LIBICONV_PATH)
 +      LIST(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBICONV_PATH})
++      # Test if a macro is needed for the library.
++      TRY_MACRO_FOR_LIBRARY(
++        "${ICONV_INCLUDE_DIR}" "${LIBICONV_PATH}"
++        COMPILES
++        "#include <iconv.h>\nint main() {return iconv_close((iconv_t)0);}"
++        "WITHOUT_LIBICONV_STATIC;LIBICONV_STATIC")
++      IF(NOT WITHOUT_LIBICONV_STATIC AND LIBICONV_STATIC)
++        ADD_DEFINITIONS(-DLIBICONV_STATIC)
++      ENDIF(NOT WITHOUT_LIBICONV_STATIC AND LIBICONV_STATIC)
++      #
++      # Set up CMAKE_REQUIRED_* for CHECK_ICONV
++      #
++      SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
++      SET(CMAKE_REQUIRED_LIBRARIES ${LIBICONV_PATH})
++      IF(LIBICONV_STATIC)
++        # LIBICONV_STATIC is necessary for the success of CHECK_ICONV
++        # on Windows.
++        SET(CMAKE_REQUIRED_DEFINITIONS "-DLIBICONV_STATIC")
++      ELSE(LIBICONV_STATIC)
++        SET(CMAKE_REQUIRED_DEFINITIONS)
++      ENDIF(LIBICONV_STATIC)
 +      CHECK_ICONV("libiconv" "const")
 +      CHECK_ICONV("libiconv" "")
 +      IF (HAVE_ICONV)
 +        LIST(APPEND ADDITIONAL_LIBS ${LIBICONV_PATH})
 +      ENDIF(HAVE_ICONV)
 +    ENDIF(NOT HAVE_ICONV AND LIBICONV_PATH)
 +  ENDIF(ICONV_INCLUDE_DIR)
 +  #
 +  # Find locale_charset() for libiconv.
 +  #
 +  IF(LIBICONV_PATH)
++    SET(CMAKE_REQUIRED_DEFINITIONS)
++    SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
++    SET(CMAKE_REQUIRED_LIBRARIES)
 +    CHECK_INCLUDE_FILES("localcharset.h" HAVE_LOCALCHARSET_H)
-     CHECK_FUNCTION_EXISTS_GLIBC(locale_charset HAVE_LOCALE_CHARSET)
-     IF(NOT HAVE_LOCALE_CHARSET)
-       FIND_LIBRARY(LIBCHARSET_PATH charset)
-       IF(LIBCHARSET_PATH)
-         SET(CMAKE_REQUIRED_LIBRARIES ${LIBCHARSET_PATH})
++    FIND_LIBRARY(LIBCHARSET_PATH NAMES charset libcharset)
++    IF(LIBCHARSET_PATH)
++      SET(CMAKE_REQUIRED_LIBRARIES ${LIBCHARSET_PATH})
++      IF(WIN32 AND NOT CYGWIN)
++        # Test if a macro is needed for the library.
++        TRY_MACRO_FOR_LIBRARY(
++          "${ICONV_INCLUDE_DIR}" "${LIBCHARSET_PATH}"
++          COMPILES
++          "#include <localcharset.h>\nint main() {return locale_charset()?1:0;}"
++          "WITHOUT_LIBCHARSET_STATIC;LIBCHARSET_STATIC")
++        IF(NOT WITHOUT_LIBCHARSET_STATIC AND LIBCHARSET_STATIC)
++          ADD_DEFINITIONS(-DLIBCHARSET_STATIC)
++        ENDIF(NOT WITHOUT_LIBCHARSET_STATIC AND LIBCHARSET_STATIC)
++        IF(WITHOUT_LIBCHARSET_STATIC OR LIBCHARSET_STATIC)
++          SET(HAVE_LOCALE_CHARSET ON CACHE INTERNAL
++              "Have function locale_charset")
++        ENDIF(WITHOUT_LIBCHARSET_STATIC OR LIBCHARSET_STATIC)
++      ELSE(WIN32 AND NOT CYGWIN)
 +        CHECK_FUNCTION_EXISTS_GLIBC(locale_charset HAVE_LOCALE_CHARSET)
-         IF(HAVE_LOCALE_CHARSET)
-           LIST(APPEND ADDITIONAL_LIBS ${LIBCHARSET_PATH})
-         ENDIF(HAVE_LOCALE_CHARSET)
-       ENDIF(LIBCHARSET_PATH)
-     ENDIF(NOT HAVE_LOCALE_CHARSET)
++      ENDIF(WIN32 AND NOT CYGWIN)
++      IF(HAVE_LOCALE_CHARSET)
++        LIST(APPEND ADDITIONAL_LIBS ${LIBCHARSET_PATH})
++      ENDIF(HAVE_LOCALE_CHARSET)
++    ENDIF(LIBCHARSET_PATH)
 +  ENDIF(LIBICONV_PATH)
++  CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
 +ELSE(ENABLE_ICONV)
 +  # Make sure ICONV variables are not in CACHE after ENABLE_ICONV disabled
 +  # (once enabled).
 +  UNSET(HAVE_LOCALE_CHARSET CACHE)
 +  UNSET(HAVE_ICONV CACHE)
 +  UNSET(HAVE_ICONV_libc_ CACHE)
 +  UNSET(HAVE_ICONV_libc_const CACHE)
 +  UNSET(HAVE_ICONV_libiconv_ CACHE)
 +  UNSET(HAVE_ICONV_libiconv_const CACHE)
 +  UNSET(ICONV_INCLUDE_DIR CACHE)
 +  UNSET(LIBICONV_PATH CACHE)
++  UNSET(LIBICONV_DLL CACHE)
++  UNSET(LIBICONV_STATIC CACHE)
++  UNSET(LIBCHARSET_DLL CACHE)
++  UNSET(LIBCHARSET_STATIC CACHE)
 +ENDIF(ENABLE_ICONV)
 +
 +IF(0) # CMake does not need XML support in libarchive
 +#
 +# Find Libxml2
 +#
 +FIND_PACKAGE(LibXml2)
 +IF(LIBXML2_FOUND)
++  CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
 +  INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})
 +  LIST(APPEND ADDITIONAL_LIBS ${LIBXML2_LIBRARIES})
 +  SET(HAVE_LIBXML2 1)
 +  # libxml2's include files use iconv.h
 +  SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR})
 +  CHECK_INCLUDE_FILES("libxml/xmlreader.h" HAVE_LIBXML_XMLREADER_H)
 +  CHECK_INCLUDE_FILES("libxml/xmlwriter.h" HAVE_LIBXML_XMLWRITER_H)
-   SET(CMAKE_REQUIRED_INCLUDES "")
++  # Test if a macro is needed for the library.
++  TRY_MACRO_FOR_LIBRARY(
++    "${ICONV_INCLUDE_DIR};${LIBXML2_INCLUDE_DIR}"
++    "ws2_32.lib;${ZLIB_LIBRARIES};${LIBICONV_PATH};${LIBXML2_LIBRARIES}"
++    COMPILES
++    "#include <stddef.h>\n#include <libxml/xmlreader.h>\nint main() {return xmlTextReaderRead((xmlTextReaderPtr)(void *)0);}"
++    "WITHOUT_LIBXML_STATIC;LIBXML_STATIC")
++  IF(NOT WITHOUT_LIBXML_STATIC AND LIBXML_STATIC)
++    ADD_DEFINITIONS(-DLIBXML_STATIC)
++  ENDIF(NOT WITHOUT_LIBXML_STATIC AND LIBXML_STATIC)
++  CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
 +ELSE(LIBXML2_FOUND)
 +  #
 +  # Find Expat
 +  #
 +  FIND_PACKAGE(EXPAT)
 +  IF(EXPAT_FOUND)
++    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
 +    INCLUDE_DIRECTORIES(${EXPAT_INCLUDE_DIR})
 +    LIST(APPEND ADDITIONAL_LIBS ${EXPAT_LIBRARIES})
 +    SET(HAVE_LIBEXPAT 1)
 +    LA_CHECK_INCLUDE_FILE("expat.h" HAVE_EXPAT_H)
++    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
 +  ENDIF(EXPAT_FOUND)
 +ENDIF(LIBXML2_FOUND)
++MARK_AS_ADVANCED(CLEAR LIBXML2_INCLUDE_DIR)
++MARK_AS_ADVANCED(CLEAR LIBXML2_LIBRARIES)
 +ENDIF()
 +
 +#
++# POSIX Regular Expression support
++#
++IF(POSIX_REGEX_LIB MATCHES "^(AUTO|LIBC|LIBREGEX)$")
++  #
++  # If PCREPOSIX is not found or not requested, try using regex
++  # from libc or libregex
++  #
++  FIND_PATH(REGEX_INCLUDE_DIR regex.h)
++  IF(REGEX_INCLUDE_DIR)
++    CHECK_FUNCTION_EXISTS_GLIBC(regcomp HAVE_REGCOMP_LIBC)
++    #
++    # If libc does not provide regex, find libregex.
++    #
++    IF(NOT HAVE_REGCOMP_LIBC)
++      CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
++      FIND_LIBRARY(REGEX_LIBRARY regex)
++      IF(REGEX_LIBRARY)
++        SET(CMAKE_REQUIRED_LIBRARIES ${REGEX_LIBRARY})
++        CHECK_FUNCTION_EXISTS_GLIBC(regcomp HAVE_REGCOMP_LIBREGEX)
++        IF(HAVE_REGCOMP_LIBREGEX)
++          LIST(APPEND ADDITIONAL_LIBS ${REGEX_LIBRARY})
++          #
++          # If regex.h is not found, retry looking for regex.h at
++          # REGEX_INCLUDE_DIR
++          #
++          IF(NOT HAVE_REGEX_H)
++            UNSET(HAVE_REGEX_H CACHE)
++            INCLUDE_DIRECTORIES(${REGEX_INCLUDE_DIR})
++            SET(CMAKE_REQUIRED_INCLUDES ${REGEX_INCLUDE_DIR})
++            LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
++          ENDIF(NOT HAVE_REGEX_H)
++          # Test if a macro is needed for the library.
++          TRY_MACRO_FOR_LIBRARY(
++            "${REGEX_INCLUDE_DIR}" "${REGEX_LIBRARY}"
++            COMPILES
++            "#include <stddef.h>\n#include <regex.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
++            "USE_REGEX_DLL;USE_REGEX_STATIC")
++          IF(USE_REGEX_DLL)
++            ADD_DEFINITIONS(-DUSE_REGEX_DLL)
++          ELSEIF(USE_REGEX_STATIC)
++            ADD_DEFINITIONS(-DUSE_REGEX_STATIC)
++          ENDIF(USE_REGEX_DLL)
++        ENDIF(HAVE_REGCOMP_LIBREGEX)
++      ENDIF(REGEX_LIBRARY)
++      CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
++    ENDIF(NOT HAVE_REGCOMP_LIBC)
++  ENDIF(REGEX_INCLUDE_DIR)
++  IF(HAVE_REGCOMP_LIBC OR HAVE_REGCOMP_LIBREGEX)
++    SET(FOUND_POSIX_REGEX_LIB 1)
++  ENDIF(HAVE_REGCOMP_LIBC OR HAVE_REGCOMP_LIBREGEX)
++ENDIF(POSIX_REGEX_LIB MATCHES "^(AUTO|LIBC|LIBREGEX)$")
++
++IF(NOT FOUND_POSIX_REGEX_LIB AND POSIX_REGEX_LIB MATCHES "^(AUTO|LIBPCREPOSIX)$")
++  #
++  # If requested, try finding library for PCREPOSIX
++  #
++  FIND_PACKAGE(LibGCC)
++  FIND_PACKAGE(PCREPOSIX)
++  IF(PCREPOSIX_FOUND)
++    INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIR})
++    LIST(APPEND ADDITIONAL_LIBS ${PCREPOSIX_LIBRARIES})
++    # Test if a macro is needed for the library.
++    TRY_MACRO_FOR_LIBRARY(
++      "${PCRE_INCLUDE_DIR}" "${PCREPOSIX_LIBRARIES}"
++      COMPILES
++      "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
++      "WITHOUT_PCRE_STATIC;PCRE_STATIC")
++    IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
++      ADD_DEFINITIONS(-DPCRE_STATIC)
++	ELSEIF(NOT WITHOUT_PCRE_STATIC AND NOT PCRE_STATIC AND PCRE_FOUND)
++	  # Determine if pcre static libraries are to be used.
++      LIST(APPEND ADDITIONAL_LIBS ${PCRE_LIBRARIES})
++      SET(TMP_LIBRARIES ${PCREPOSIX_LIBRARIES} ${PCRE_LIBRARIES})
++      MESSAGE(STATUS "trying again with -lpcre included")
++      TRY_MACRO_FOR_LIBRARY(
++        "${PCRE_INCLUDE_DIR}" "${TMP_LIBRARIES}"
++        COMPILES
++        "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
++        "WITHOUT_PCRE_STATIC;PCRE_STATIC")
++      IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
++        ADD_DEFINITIONS(-DPCRE_STATIC)
++      ELSEIF(NOT WITHOUT_PCRE_STATIC AND NOT PCRE_STATIC AND MSVC AND LIBGCC_FOUND)
++        # When doing a Visual Studio build using pcre static libraries
++        # built using the mingw toolchain, -lgcc is needed to resolve
++        # ___chkstk_ms.
++        MESSAGE(STATUS "Visual Studio build detected, trying again with -lgcc included")
++        LIST(APPEND ADDITIONAL_LIBS ${LIBGCC_LIBRARIES})
++        SET(TMP_LIBRARIES ${PCREPOSIX_LIBRARIES} ${PCRE_LIBRARIES} ${LIBGCC_LIBRARIES})
++          TRY_MACRO_FOR_LIBRARY(
++            "${PCRE_INCLUDE_DIR}" "${TMP_LIBRARIES}"
++            COMPILES
++            "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
++            "WITHOUT_PCRE_STATIC;PCRE_STATIC")
++          IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
++            ADD_DEFINITIONS(-DPCRE_STATIC)
++          ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
++      ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
++    ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
++  ENDIF(PCREPOSIX_FOUND)
++  MARK_AS_ADVANCED(CLEAR PCRE_INCLUDE_DIR)
++  MARK_AS_ADVANCED(CLEAR PCREPOSIX_LIBRARIES)
++  MARK_AS_ADVANCED(CLEAR PCRE_LIBRARIES)
++  MARK_AS_ADVANCED(CLEAR LIBGCC_LIBRARIES)
++ENDIF(NOT FOUND_POSIX_REGEX_LIB AND POSIX_REGEX_LIB MATCHES "^(AUTO|LIBPCREPOSIX)$")
++
++#
 +# Check functions
 +#
++CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
 +IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 +  #
 +  # During checking functions, we should use -fno-builtin to avoid the
 +  # failure of function detection which failure is an error "conflicting
 +  # types for built-in function" caused by using -Werror option.
 +  #
-   SET(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
 +  SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-builtin")
 +ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 +CHECK_SYMBOL_EXISTS(_CrtSetReportMode "crtdbg.h" HAVE__CrtSetReportMode)
 +CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS)
 +CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
 +CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
 +CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R)
++CHECK_FUNCTION_EXISTS_GLIBC(dirfd HAVE_DIRFD)
 +CHECK_FUNCTION_EXISTS_GLIBC(fchdir HAVE_FCHDIR)
 +CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS)
 +CHECK_FUNCTION_EXISTS_GLIBC(fchmod HAVE_FCHMOD)
 +CHECK_FUNCTION_EXISTS_GLIBC(fchown HAVE_FCHOWN)
 +CHECK_FUNCTION_EXISTS_GLIBC(fcntl HAVE_FCNTL)
 +CHECK_FUNCTION_EXISTS_GLIBC(fdopendir HAVE_FDOPENDIR)
 +CHECK_FUNCTION_EXISTS_GLIBC(fork HAVE_FORK)
 +CHECK_FUNCTION_EXISTS_GLIBC(fstat HAVE_FSTAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(fstatat HAVE_FSTATAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(fstatfs HAVE_FSTATFS)
 +CHECK_FUNCTION_EXISTS_GLIBC(fstatvfs HAVE_FSTATVFS)
 +CHECK_FUNCTION_EXISTS_GLIBC(ftruncate HAVE_FTRUNCATE)
 +CHECK_FUNCTION_EXISTS_GLIBC(futimens HAVE_FUTIMENS)
 +CHECK_FUNCTION_EXISTS_GLIBC(futimes HAVE_FUTIMES)
 +CHECK_FUNCTION_EXISTS_GLIBC(futimesat HAVE_FUTIMESAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(geteuid HAVE_GETEUID)
 +CHECK_FUNCTION_EXISTS_GLIBC(getgrgid_r HAVE_GETGRGID_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(getgrnam_r HAVE_GETGRNAM_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(getpwnam_r HAVE_GETPWNAM_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(getpwuid_r HAVE_GETPWUID_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(getpid HAVE_GETPID)
 +CHECK_FUNCTION_EXISTS_GLIBC(getvfsbyname HAVE_GETVFSBYNAME)
 +CHECK_FUNCTION_EXISTS_GLIBC(gmtime_r HAVE_GMTIME_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(lchflags HAVE_LCHFLAGS)
 +CHECK_FUNCTION_EXISTS_GLIBC(lchmod HAVE_LCHMOD)
 +CHECK_FUNCTION_EXISTS_GLIBC(lchown HAVE_LCHOWN)
 +CHECK_FUNCTION_EXISTS_GLIBC(link HAVE_LINK)
 +CHECK_FUNCTION_EXISTS_GLIBC(localtime_r HAVE_LOCALTIME_R)
 +CHECK_FUNCTION_EXISTS_GLIBC(lstat HAVE_LSTAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(lutimes HAVE_LUTIMES)
 +CHECK_FUNCTION_EXISTS_GLIBC(mbrtowc HAVE_MBRTOWC)
- CHECK_FUNCTION_EXISTS_GLIBC(mbsnrtowcs HAVE_MBSNRTOWCS)
 +CHECK_FUNCTION_EXISTS_GLIBC(memmove HAVE_MEMMOVE)
 +CHECK_FUNCTION_EXISTS_GLIBC(mkdir HAVE_MKDIR)
 +CHECK_FUNCTION_EXISTS_GLIBC(mkfifo HAVE_MKFIFO)
 +CHECK_FUNCTION_EXISTS_GLIBC(mknod HAVE_MKNOD)
 +CHECK_FUNCTION_EXISTS_GLIBC(mkstemp HAVE_MKSTEMP)
 +CHECK_FUNCTION_EXISTS_GLIBC(nl_langinfo HAVE_NL_LANGINFO)
 +CHECK_FUNCTION_EXISTS_GLIBC(openat HAVE_OPENAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(pipe HAVE_PIPE)
 +CHECK_FUNCTION_EXISTS_GLIBC(poll HAVE_POLL)
++CHECK_FUNCTION_EXISTS_GLIBC(posix_spawnp HAVE_POSIX_SPAWNP)
 +CHECK_FUNCTION_EXISTS_GLIBC(readlink HAVE_READLINK)
 +CHECK_FUNCTION_EXISTS_GLIBC(select HAVE_SELECT)
 +CHECK_FUNCTION_EXISTS_GLIBC(setenv HAVE_SETENV)
 +CHECK_FUNCTION_EXISTS_GLIBC(setlocale HAVE_SETLOCALE)
 +CHECK_FUNCTION_EXISTS_GLIBC(sigaction HAVE_SIGACTION)
 +CHECK_FUNCTION_EXISTS_GLIBC(statfs HAVE_STATFS)
 +CHECK_FUNCTION_EXISTS_GLIBC(statvfs HAVE_STATVFS)
 +CHECK_FUNCTION_EXISTS_GLIBC(strchr HAVE_STRCHR)
 +CHECK_FUNCTION_EXISTS_GLIBC(strdup HAVE_STRDUP)
 +CHECK_FUNCTION_EXISTS_GLIBC(strerror HAVE_STRERROR)
 +CHECK_FUNCTION_EXISTS_GLIBC(strncpy_s HAVE_STRNCPY_S)
 +CHECK_FUNCTION_EXISTS_GLIBC(strrchr HAVE_STRRCHR)
 +CHECK_FUNCTION_EXISTS_GLIBC(symlink HAVE_SYMLINK)
 +CHECK_FUNCTION_EXISTS_GLIBC(timegm HAVE_TIMEGM)
 +CHECK_FUNCTION_EXISTS_GLIBC(tzset HAVE_TZSET)
 +CHECK_FUNCTION_EXISTS_GLIBC(unsetenv HAVE_UNSETENV)
 +CHECK_FUNCTION_EXISTS_GLIBC(utime HAVE_UTIME)
 +CHECK_FUNCTION_EXISTS_GLIBC(utimes HAVE_UTIMES)
 +CHECK_FUNCTION_EXISTS_GLIBC(utimensat HAVE_UTIMENSAT)
 +CHECK_FUNCTION_EXISTS_GLIBC(vfork HAVE_VFORK)
 +CHECK_FUNCTION_EXISTS_GLIBC(wcrtomb HAVE_WCRTOMB)
 +CHECK_FUNCTION_EXISTS_GLIBC(wcscmp HAVE_WCSCMP)
 +CHECK_FUNCTION_EXISTS_GLIBC(wcscpy HAVE_WCSCPY)
 +CHECK_FUNCTION_EXISTS_GLIBC(wcslen HAVE_WCSLEN)
- CHECK_FUNCTION_EXISTS_GLIBC(wcsnrtombs HAVE_WCSNRTOMBS)
 +CHECK_FUNCTION_EXISTS_GLIBC(wctomb HAVE_WCTOMB)
 +CHECK_FUNCTION_EXISTS_GLIBC(_ctime64_s HAVE__CTIME64_S)
 +CHECK_FUNCTION_EXISTS_GLIBC(_fseeki64 HAVE__FSEEKI64)
 +CHECK_FUNCTION_EXISTS_GLIBC(_get_timezone HAVE__GET_TIMEZONE)
 +CHECK_FUNCTION_EXISTS_GLIBC(_localtime64_s HAVE__LOCALTIME64_S)
 +CHECK_FUNCTION_EXISTS_GLIBC(_mkgmtime64 HAVE__MKGMTIME64)
 +
 +SET(CMAKE_REQUIRED_LIBRARIES "")
 +CHECK_FUNCTION_EXISTS(cygwin_conv_path HAVE_CYGWIN_CONV_PATH)
 +CHECK_FUNCTION_EXISTS(fseeko HAVE_FSEEKO)
 +CHECK_FUNCTION_EXISTS(strerror_r HAVE_STRERROR_R)
 +CHECK_FUNCTION_EXISTS(strftime HAVE_STRFTIME)
 +CHECK_FUNCTION_EXISTS(vprintf HAVE_VPRINTF)
 +CHECK_FUNCTION_EXISTS(wmemcmp HAVE_WMEMCMP)
 +CHECK_FUNCTION_EXISTS(wmemcpy HAVE_WMEMCPY)
 +
- # Restore CMAKE_REQUIRED_FLAGS
- IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
-   SET(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS})
- ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
++CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
 +
 +# Make sure we have the POSIX version of readdir_r, not the
 +# older 2-argument version.
- CHECK_C_SOURCE_COMPILES(
++LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
 +  "#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}"
 +  HAVE_READDIR_R)
 +
 +
 +# Only detect readlinkat() if we also have AT_FDCWD in unistd.h.
 +# NOTE: linux requires fcntl.h for AT_FDCWD.
- CHECK_C_SOURCE_COMPILES(
++LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
 +  "#include <fcntl.h>\n#include <unistd.h>\nint main() {char buf[10]; return readlinkat(AT_FDCWD, \"\", buf, 0);}"
 +  HAVE_READLINKAT)
 +
 +
 +# To verify major(), we need to both include the header
 +# of interest and verify that the result can be linked.
 +# CHECK_FUNCTION_EXISTS doesn't accept a header argument,
 +# CHECK_SYMBOL_EXISTS doesn't test linkage.
- CHECK_C_SOURCE_COMPILES(
++LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
 +  "#include <sys/mkdev.h>\nint main() { return major(256); }"
 +  MAJOR_IN_MKDEV)
- CHECK_C_SOURCE_COMPILES(
++LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
 +  "#include <sys/sysmacros.h>\nint main() { return major(256); }"
 +  MAJOR_IN_SYSMACROS)
 +
 +IF(HAVE_STRERROR_R)
 +  SET(HAVE_DECL_STRERROR_R 1)
 +ENDIF(HAVE_STRERROR_R)
 +
 +#
 +# Check defines
 +#
 +SET(headers "limits.h")
 +IF(HAVE_STDINT_H)
 +  LIST(APPEND headers "stdint.h")
 +ENDIF(HAVE_STDINT_H)
 +IF(HAVE_INTTYPES_H)
 +  LIST(APPEND headers "inttypes.h")
 +ENDIF(HAVE_INTTYPES_H)
 +CHECK_SYMBOL_EXISTS(EFTYPE           "errno.h"    HAVE_EFTYPE)
 +CHECK_SYMBOL_EXISTS(EILSEQ           "errno.h"    HAVE_EILSEQ)
 +CHECK_SYMBOL_EXISTS(D_MD_ORDER       "langinfo.h" HAVE_D_MD_ORDER)
 +CHECK_SYMBOL_EXISTS(INT64_MAX        "${headers}" HAVE_DECL_INT64_MAX)
 +CHECK_SYMBOL_EXISTS(INT64_MIN        "${headers}" HAVE_DECL_INT64_MIN)
 +CHECK_SYMBOL_EXISTS(UINT32_MAX       "${headers}" HAVE_DECL_UINT32_MAX)
 +CHECK_SYMBOL_EXISTS(UINT64_MAX       "${headers}" HAVE_DECL_UINT64_MAX)
 +CHECK_SYMBOL_EXISTS(SIZE_MAX         "${headers}" HAVE_DECL_SIZE_MAX)
 +CHECK_SYMBOL_EXISTS(SSIZE_MAX        "limits.h"   HAVE_DECL_SSIZE_MAX)
 +
 +#
 +# Check struct members
 +#
 +# Check for tm_gmtoff in struct tm
 +CHECK_STRUCT_MEMBER("struct tm" tm_gmtoff
 +    "time.h" HAVE_STRUCT_TM_TM_GMTOFF)
 +CHECK_STRUCT_MEMBER("struct tm" __tm_gmtoff
 +    "time.h" HAVE_STRUCT_TM___TM_GMTOFF)
 +
 +# Check for f_namemax in struct statfs
 +CHECK_STRUCT_MEMBER("struct statfs" f_namemax
 +    "sys/param.h;sys/mount.h" HAVE_STRUCT_STATFS_F_NAMEMAX)
 +
 +# Check for birthtime in struct stat
 +CHECK_STRUCT_MEMBER("struct stat" st_birthtime
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_BIRTHTIME)
 +
 +# Check for high-resolution timestamps in struct stat
 +CHECK_STRUCT_MEMBER("struct stat" st_birthtimespec.tv_nsec
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
 +CHECK_STRUCT_MEMBER("struct stat" st_mtimespec.tv_nsec
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
 +CHECK_STRUCT_MEMBER("struct stat" st_mtim.tv_nsec
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
 +CHECK_STRUCT_MEMBER("struct stat" st_mtime_n
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIME_N)
 +CHECK_STRUCT_MEMBER("struct stat" st_umtime
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_UMTIME)
 +CHECK_STRUCT_MEMBER("struct stat" st_mtime_usec
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIME_USEC)
 +# Check for block size support in struct stat
 +CHECK_STRUCT_MEMBER("struct stat" st_blksize
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_BLKSIZE)
 +# Check for st_flags in struct stat (BSD fflags)
 +CHECK_STRUCT_MEMBER("struct stat" st_flags
 +    "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_FLAGS)
 +
 +IF(HAVE_SYS_STATVFS_H)
 +  CHECK_STRUCT_MEMBER("struct statvfs" f_iosize
 +    "sys/types.h;sys/statvfs.h" HAVE_STRUCT_STATVFS_F_IOSIZE)
 +ENDIF()
 +
 +#
 +#
 +CHECK_STRUCT_MEMBER("struct tm" tm_sec
 +    "sys/types.h;sys/time.h;time.h" TIME_WITH_SYS_TIME)
 +
 +#
 +# Check for integer types
 +#
 +#
 +CHECK_TYPE_SIZE("short" SIZE_OF_SHORT)
 +CHECK_TYPE_SIZE("int" SIZE_OF_INT)
 +CHECK_TYPE_SIZE("long" SIZE_OF_LONG)
 +CHECK_TYPE_SIZE("long long"     SIZE_OF_LONG_LONG)
 +
 +CHECK_TYPE_SIZE("unsigned short" SIZE_OF_UNSIGNED_SHORT)
 +CHECK_TYPE_SIZE("unsigned" SIZE_OF_UNSIGNED)
 +CHECK_TYPE_SIZE("unsigned long" SIZE_OF_UNSIGNED_LONG)
 +CHECK_TYPE_SIZE("unsigned long long" SIZE_OF_UNSIGNED_LONG_LONG)
 +
 +CHECK_TYPE_SIZE("__int64" __INT64)
 +CHECK_TYPE_SIZE("unsigned __int64" UNSIGNED___INT64)
 +
 +CHECK_TYPE_SIZE(int16_t INT16_T) 
 +CHECK_TYPE_SIZE(int32_t INT32_T)
 +CHECK_TYPE_SIZE(int64_t INT64_T)
 +CHECK_TYPE_SIZE(intmax_t INTMAX_T)
 +CHECK_TYPE_SIZE(uint8_t UINT8_T) 
 +CHECK_TYPE_SIZE(uint16_t UINT16_T) 
 +CHECK_TYPE_SIZE(uint32_t UINT32_T) 
 +CHECK_TYPE_SIZE(uint64_t UINT64_T)
 +CHECK_TYPE_SIZE(uintmax_t UINTMAX_T)
 +
 +CHECK_TYPE_SIZE(dev_t       DEV_T)
 +IF(NOT HAVE_DEV_T)
 +  IF(MSVC)
 +    SET(dev_t "unsigned int")
 +  ENDIF(MSVC)
 +ENDIF(NOT HAVE_DEV_T)
 +#
 +CHECK_TYPE_SIZE(gid_t       GID_T)
 +IF(NOT HAVE_GID_T)
 +  IF(WIN32)
 +    SET(gid_t "short")
 +  ELSE(WIN32)
 +    SET(gid_t "unsigned int")
 +  ENDIF(WIN32)
 +ENDIF(NOT HAVE_GID_T)
 +#
 +CHECK_TYPE_SIZE(id_t        ID_T)
 +IF(NOT HAVE_ID_T)
 +  IF(WIN32)
 +    SET(id_t "short")
 +  ELSE(WIN32)
 +    SET(id_t "unsigned int")
 +  ENDIF(WIN32)
 +ENDIF(NOT HAVE_ID_T)
 +#
 +CHECK_TYPE_SIZE(mode_t      MODE_T)
 +IF(NOT HAVE_MODE_T)
 +  IF(WIN32)
 +    SET(mode_t "unsigned short")
 +  ELSE(WIN32)
 +    SET(mode_t "int")
 +  ENDIF(WIN32)
 +ENDIF(NOT HAVE_MODE_T)
 +#
 +CHECK_TYPE_SIZE(off_t       OFF_T)
 +IF(NOT HAVE_OFF_T)
 +  SET(off_t "__int64")
 +ENDIF(NOT HAVE_OFF_T)
 +#
 +CHECK_TYPE_SIZE(size_t      SIZE_T)
 +IF(NOT HAVE_SIZE_T)
 +  IF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(size_t "uint64_t")
 +  ELSE("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(size_t   "uint32_t")
 +  ENDIF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +ENDIF(NOT HAVE_SIZE_T)
 +#
 +CHECK_TYPE_SIZE(ssize_t     SSIZE_T)
 +IF(NOT HAVE_SSIZE_T)
 +  IF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(ssize_t "int64_t")
 +  ELSE("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(ssize_t "long")
 +  ENDIF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +ENDIF(NOT HAVE_SSIZE_T)
 +#
 +CHECK_TYPE_SIZE(uid_t       UID_T)
 +IF(NOT HAVE_UID_T)
 +  IF(WIN32)
 +    SET(uid_t "short")
 +  ELSE(WIN32)
 +    SET(uid_t "unsigned int")
 +  ENDIF(WIN32)
 +ENDIF(NOT HAVE_UID_T)
 +#
 +CHECK_TYPE_SIZE(pid_t       PID_T)
 +IF(NOT HAVE_PID_T)
 +  IF(WIN32)
 +    SET(pid_t "int")
 +  ELSE(WIN32)
 +    MESSAGE(FATAL_ERROR "pid_t doesn't exist on this platform?")
 +  ENDIF(WIN32)
 +ENDIF(NOT HAVE_PID_T)
 +#
 +CHECK_TYPE_SIZE(intptr_t   INTPTR_T)
 +IF(NOT HAVE_INTPTR_T)
 +  IF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(intptr_t "int64_t")
 +  ELSE()
 +    SET(intptr_t "int32_t")
 +  ENDIF()
 +ENDIF(NOT HAVE_INTPTR_T)
 +#
 +CHECK_TYPE_SIZE(uintptr_t   UINTPTR_T)
 +IF(NOT HAVE_UINTPTR_T)
 +  IF("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
 +    SET(uintptr_t "uint64_t")
 +  ELSE()
 +    SET(uintptr_t "uint32_t")
 +  ENDIF()
 +ENDIF(NOT HAVE_UINTPTR_T)
 +#
 +CHECK_TYPE_SIZE(wchar_t     SIZEOF_WCHAR_T)
 +IF(HAVE_SIZEOF_WCHAR_T)
 +  SET(HAVE_WCHAR_T 1)
 +ENDIF(HAVE_SIZEOF_WCHAR_T)
 +#
 +# Check if _FILE_OFFSET_BITS macro needed for large files
 +#
 +CHECK_FILE_OFFSET_BITS()
 +
 +#
 +# Check for Extended Attribute libraries, headers, and functions
 +#
 +IF(ENABLE_XATTR)
 +  LA_CHECK_INCLUDE_FILE(attr/xattr.h     HAVE_ATTR_XATTR_H)
 +  LA_CHECK_INCLUDE_FILE(sys/xattr.h      HAVE_SYS_XATTR_H)
 +  LA_CHECK_INCLUDE_FILE(sys/extattr.h      HAVE_SYS_EXTATTR_H)
 +  CHECK_LIBRARY_EXISTS(attr "setxattr" "" HAVE_LIBATTR)
 +  IF(HAVE_LIBATTR)
 +    SET(CMAKE_REQUIRED_LIBRARIES "attr")
 +  ENDIF(HAVE_LIBATTR)
 +  CHECK_SYMBOL_EXISTS(EXTATTR_NAMESPACE_USER "sys/types.h;sys/extattr.h" HAVE_DECL_EXTATTR_NAMESPACE_USER)
 +  CHECK_FUNCTION_EXISTS_GLIBC(extattr_get_file HAVE_EXTATTR_GET_FILE)
 +  CHECK_FUNCTION_EXISTS_GLIBC(extattr_list_file HAVE_EXTATTR_LIST_FILE)
 +  CHECK_FUNCTION_EXISTS_GLIBC(extattr_set_fd HAVE_EXTATTR_SET_FD)
 +  CHECK_FUNCTION_EXISTS_GLIBC(extattr_set_file HAVE_EXTATTR_SET_FILE)
 +  CHECK_FUNCTION_EXISTS_GLIBC(fgetxattr HAVE_FGETXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(flistxattr HAVE_FLISTXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(fsetxattr HAVE_FSETXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(getxattr HAVE_GETXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(lgetxattr HAVE_LGETXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(listxattr HAVE_LISTXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(llistxattr HAVE_LLISTXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(lsetxattr HAVE_LSETXATTR)
 +  CHECK_FUNCTION_EXISTS_GLIBC(fgetea HAVE_FGETEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(flistea HAVE_FLISTEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(fsetea HAVE_FSETEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(getea HAVE_GETEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(lgetea HAVE_LGETEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(listea HAVE_LISTEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(llistea HAVE_LLISTEA)
 +  CHECK_FUNCTION_EXISTS_GLIBC(lsetea HAVE_LSETEA)
 +ELSE(ENABLE_XATTR)
 +  SET(HAVE_ATTR_LIB FALSE)
 +  SET(HAVE_ATTR_XATTR_H FALSE)
 +  SET(HAVE_DECL_EXTATTR_NAMESPACE_USER FALSE)
 +  SET(HAVE_EXTATTR_GET_FILE FALSE)
 +  SET(HAVE_EXTATTR_LIST_FILE FALSE)
 +  SET(HAVE_EXTATTR_SET_FD FALSE)
 +  SET(HAVE_EXTATTR_SET_FILE FALSE)
 +  SET(HAVE_FGETEA FALSE)
 +  SET(HAVE_FGETXATTR FALSE)
 +  SET(HAVE_FLISTEA FALSE)
 +  SET(HAVE_FLISTXATTR FALSE)
 +  SET(HAVE_FSETEA FALSE)
 +  SET(HAVE_FSETXATTR FALSE)
 +  SET(HAVE_GETEA FALSE)
 +  SET(HAVE_GETXATTR FALSE)
 +  SET(HAVE_LGETEA FALSE)
 +  SET(HAVE_LGETXATTR FALSE)
 +  SET(HAVE_LISTEA FALSE)
 +  SET(HAVE_LISTXATTR FALSE)
 +  SET(HAVE_LLISTEA FALSE)
 +  SET(HAVE_LLISTXATTR FALSE)
 +  SET(HAVE_LSETEA FALSE)
 +  SET(HAVE_LSETXATTR FALSE)
 +  SET(HAVE_SYS_EXTATTR_H FALSE)
 +  SET(HAVE_SYS_XATTR_H FALSE)
 +ENDIF(ENABLE_XATTR)
 +
 +#
 +# Check for ACL libraries, headers, and functions
 +#
 +# The ACL support in libarchive is written against the POSIX1e draft,
 +# which was never officially approved and varies quite a bit across
 +# platforms.  Worse, some systems have completely non-POSIX acl functions,
 +# which makes the following checks rather more complex than I would like.
 +#
 +IF(ENABLE_ACL)
 +  CHECK_LIBRARY_EXISTS(acl "acl_get_file" "" HAVE_LIBACL)
 +  IF(HAVE_LIBACL)
 +    SET(CMAKE_REQUIRED_LIBRARIES "acl")
 +    FIND_LIBRARY(ACL_LIBRARY NAMES acl)
 +    LIST(APPEND ADDITIONAL_LIBS ${ACL_LIBRARY})
 +  ENDIF(HAVE_LIBACL)
 +  #
 +  CHECK_FUNCTION_EXISTS_GLIBC(acl_create_entry HAVE_ACL_CREATE_ENTRY)
 +  CHECK_FUNCTION_EXISTS_GLIBC(acl_init HAVE_ACL_INIT)
 +  CHECK_FUNCTION_EXISTS_GLIBC(acl_set_fd HAVE_ACL_SET_FD)
 +  CHECK_FUNCTION_EXISTS_GLIBC(acl_set_fd_np HAVE_ACL_SET_FD_NP)
 +  CHECK_FUNCTION_EXISTS_GLIBC(acl_set_file HAVE_ACL_SET_FILE)
 +  CHECK_TYPE_EXISTS(acl_permset_t "${INCLUDES}"    HAVE_ACL_PERMSET_T)
 +
 +  # The "acl_get_perm()" function was omitted from the POSIX draft.
 +  # (It's a pretty obvious oversight; otherwise, there's no way to
 +  # test for specific permissions in a permset.)  Linux uses the obvious
 +  # name, FreeBSD adds _np to mark it as "non-Posix extension."
 +  # Test for both as a double-check that we really have POSIX-style ACL support.
 +  CHECK_FUNCTION_EXISTS(acl_get_perm HAVE_ACL_GET_PERM)
 +  CHECK_FUNCTION_EXISTS(acl_get_perm_np HAVE_ACL_GET_PERM_NP)
 +  CHECK_FUNCTION_EXISTS(acl_get_link HAVE_ACL_GET_LINK)
 +  CHECK_FUNCTION_EXISTS(acl_get_link_np HAVE_ACL_GET_LINK_NP)
++  CHECK_FUNCTION_EXISTS(acl_is_trivial_np HAVE_ACL_IS_TRIVIAL_NP)
++  CHECK_FUNCTION_EXISTS(acl_set_link_np HAVE_ACL_SET_LINK_NP)
 +
 +  # MacOS has an acl.h that isn't POSIX.  It can be detected by
 +  # checking for ACL_USER
 +  CHECK_SYMBOL_EXISTS(ACL_USER "${INCLUDES}" HAVE_ACL_USER)
 +ELSE(ENABLE_ACL)
 +  # If someone runs cmake, then disables ACL support, we need
 +  # to forcibly override the cached values for these.
 +  SET(HAVE_ACL_CREATE_ENTRY FALSE)
 +  SET(HAVE_ACL_GET_LINK FALSE)
 +  SET(HAVE_ACL_GET_LINK_NP FALSE)
 +  SET(HAVE_ACL_GET_PERM FALSE)
 +  SET(HAVE_ACL_GET_PERM_NP FALSE)
 +  SET(HAVE_ACL_INIT FALSE)
 +  SET(HAVE_ACL_LIB FALSE)
 +  SET(HAVE_ACL_PERMSET_T FALSE)
 +  SET(HAVE_ACL_SET_FD FALSE)
 +  SET(HAVE_ACL_SET_FD_NP FALSE)
 +  SET(HAVE_ACL_SET_FILE FALSE)
 +  SET(HAVE_ACL_USER FALSE)
 +ENDIF(ENABLE_ACL)
 +
 +#
 +# Check MD5/RMD160/SHA support
 +# NOTE: Crypto checks must be run last before generating config.h
 +#
 +CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" LIBC)
 +CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC2)
 +CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC3)
 +CHECK_CRYPTO("MD5;SHA1;SHA256;SHA384;SHA512" LIBSYSTEM)
 +CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" NETTLE)
 +CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" OPENSSL)
 +
 +# Libmd has to be probed after OpenSSL.
 +CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA512" LIBMD)
 +
 +CHECK_CRYPTO_WIN("MD5;SHA1;SHA256;SHA384;SHA512")
 +
 +# Generate "config.h" from "build/cmake/config.h.in"
 +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in
 +	${CMAKE_CURRENT_BINARY_DIR}/config.h)
 +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
 +ADD_DEFINITIONS(-DHAVE_CONFIG_H)
 +
 +#
 +# Register installation of PDF documents.
 +#
 +IF(WIN32 AND NOT CYGWIN)
 +  #
 +  # On Windows platform, It's better that we install PDF documents
 +  # on one's computer.
 +  # These PDF documents are available in the release package.
 +  #
 +  IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doc/pdf)
 +    INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc/pdf
 +            DESTINATION share/man
 +            FILES_MATCHING PATTERN "*.pdf"
 +    )
 +  ENDIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doc/pdf)
 +ENDIF(WIN32 AND NOT CYGWIN)
 +#
 +#
 +#
 +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/libarchive)
 +#
 +IF(MSVC)
 +  ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
 +ENDIF(MSVC)
 +
 +# We need CoreServices on Mac OS.
 +IF(APPLE)
 +  LIST(APPEND ADDITIONAL_LIBS "-framework CoreServices")
 +ENDIF(APPLE)
 +
 +add_subdirectory(libarchive)
 +
 +install(FILES COPYING DESTINATION ${CMake_DOC_DEST}/cmlibarchive)
diff --cc Utilities/cmlibarchive/build/cmake/FindLibGCC.cmake
index 0000000,7985f2b..7985f2b
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/build/cmake/FindLibGCC.cmake
+++ b/Utilities/cmlibarchive/build/cmake/FindLibGCC.cmake
diff --cc Utilities/cmlibarchive/build/cmake/FindNettle.cmake
index 0000000,1f66610..1f66610
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/build/cmake/FindNettle.cmake
+++ b/Utilities/cmlibarchive/build/cmake/FindNettle.cmake
diff --cc Utilities/cmlibarchive/build/cmake/FindPCREPOSIX.cmake
index 0000000,7cc40ec..7cc40ec
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/build/cmake/FindPCREPOSIX.cmake
+++ b/Utilities/cmlibarchive/build/cmake/FindPCREPOSIX.cmake
diff --cc Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceCompiles.cmake
index 0000000,6b6f593..6b6f593
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceCompiles.cmake
+++ b/Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceCompiles.cmake
diff --cc Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceRuns.cmake
index 0000000,498f522..498f522
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceRuns.cmake
+++ b/Utilities/cmlibarchive/build/cmake/LibarchiveCheckCSourceRuns.cmake
diff --cc Utilities/cmlibarchive/build/cmake/config.h.in
index ff97cbd,0000000..750ae66
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/build/cmake/config.h.in
+++ b/Utilities/cmlibarchive/build/cmake/config.h.in
@@@ -1,1110 -1,0 +1,1149 @@@
 +/* config.h.  Generated from build/cmake/config.h.in by cmake configure */
 +#if defined(__osf__)
 +# define _OSF_SOURCE
 +#endif
 +
 +/*
 + * Ensure we have C99-style int64_t, etc, all defined.
 + */
 +
 +/* First, we need to know if the system has already defined them. */
 +#cmakedefine HAVE_INT16_T
 +#cmakedefine HAVE_INT32_T
 +#cmakedefine HAVE_INT64_T
 +#cmakedefine HAVE_INTMAX_T
 +
 +#cmakedefine HAVE_UINT8_T
 +#cmakedefine HAVE_UINT16_T
 +#cmakedefine HAVE_UINT32_T
 +#cmakedefine HAVE_UINT64_T
 +#cmakedefine HAVE_UINTMAX_T
 +
 +/* We might have the types we want under other spellings. */
 +#cmakedefine HAVE___INT64
 +#cmakedefine HAVE_U_INT64_T
 +#cmakedefine HAVE_UNSIGNED___INT64
 +
 +/* The sizes of various standard integer types. */
 + at SIZE_OF_SHORT_CODE@
 + at SIZE_OF_INT_CODE@
 + at SIZE_OF_LONG_CODE@
 + at SIZE_OF_LONG_LONG_CODE@
 + at SIZE_OF_UNSIGNED_SHORT_CODE@
 + at SIZE_OF_UNSIGNED_CODE@
 + at SIZE_OF_UNSIGNED_LONG_CODE@
 + at SIZE_OF_UNSIGNED_LONG_LONG_CODE@
 +
 +/*
 + * If we lack int64_t, define it to the first of __int64, int, long, and long long
 + * that exists and is the right size.
 + */
 +#if !defined(HAVE_INT64_T) && defined(HAVE___INT64)
 +typedef __int64 int64_t;
 +#define HAVE_INT64_T
 +#endif
 +
 +#if !defined(HAVE_INT64_T) && SIZE_OF_INT == 8
 +typedef int int64_t;
 +#define HAVE_INT64_T
 +#endif
 +
 +#if !defined(HAVE_INT64_T) && SIZE_OF_LONG == 8
 +typedef long int64_t;
 +#define HAVE_INT64_T
 +#endif
 +
 +#if !defined(HAVE_INT64_T) && SIZE_OF_LONG_LONG == 8
 +typedef long long int64_t;
 +#define HAVE_INT64_T
 +#endif
 +
 +#if !defined(HAVE_INT64_T)
 +#error No 64-bit integer type was found.
 +#endif
 +
 +/*
 + * Similarly for int32_t
 + */
 +#if !defined(HAVE_INT32_T) && SIZE_OF_INT == 4
 +typedef long int32_t;
 +#define HAVE_INT32_T
 +#endif
 +
 +#if !defined(HAVE_INT32_T) && SIZE_OF_LONG == 4
 +typedef long int32_t;
 +#define HAVE_INT32_T
 +#endif
 +
 +#if !defined(HAVE_INT32_T)
 +#error No 32-bit integer type was found.
 +#endif
 +
 +/*
 + * Similarly for int16_t
 + */
 +#if !defined(HAVE_INT16_T) && SIZE_OF_INT == 2
 +typedef int int16_t;
 +#define HAVE_INT16_T
 +#endif
 +
 +#if !defined(HAVE_INT16_T) && SIZE_OF_SHORT == 2
 +typedef short int16_t;
 +#define HAVE_INT16_T
 +#endif
 +
 +#if !defined(HAVE_INT16_T)
 +#error No 16-bit integer type was found.
 +#endif
 +
 +/*
 + * Similarly for uint64_t
 + */
 +#if !defined(HAVE_UINT64_T) && defined(HAVE_UNSIGNED___INT64)
 +typedef unsigned __int64 uint64_t;
 +#define HAVE_UINT64_T
 +#endif
 +
 +#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED == 8
 +typedef unsigned uint64_t;
 +#define HAVE_UINT64_T
 +#endif
 +
 +#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED_LONG == 8
 +typedef unsigned long uint64_t;
 +#define HAVE_UINT64_T
 +#endif
 +
 +#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED_LONG_LONG == 8
 +typedef unsigned long long uint64_t;
 +#define HAVE_UINT64_T
 +#endif
 +
 +#if !defined(HAVE_UINT64_T)
 +#error No 64-bit unsigned integer type was found.
 +#endif
 +
 +
 +/*
 + * Similarly for uint32_t
 + */
 +#if !defined(HAVE_UINT32_T) && SIZE_OF_UNSIGNED == 4
 +typedef unsigned uint32_t;
 +#define HAVE_UINT32_T
 +#endif
 +
 +#if !defined(HAVE_UINT32_T) && SIZE_OF_UNSIGNED_LONG == 4
 +typedef unsigned long uint32_t;
 +#define HAVE_UINT32_T
 +#endif
 +
 +#if !defined(HAVE_UINT32_T)
 +#error No 32-bit unsigned integer type was found.
 +#endif
 +
 +/*
 + * Similarly for uint16_t
 + */
 +#if !defined(HAVE_UINT16_T) && SIZE_OF_UNSIGNED == 2
 +typedef unsigned uint16_t;
 +#define HAVE_UINT16_T
 +#endif
 +
 +#if !defined(HAVE_UINT16_T) && SIZE_OF_UNSIGNED_SHORT == 2
 +typedef unsigned short uint16_t;
 +#define HAVE_UINT16_T
 +#endif
 +
 +#if !defined(HAVE_UINT16_T)
 +#error No 16-bit unsigned integer type was found.
 +#endif
 +
 +/*
 + * Similarly for uint8_t
 + */
 +#if !defined(HAVE_UINT8_T)
 +typedef unsigned char uint8_t;
 +#define HAVE_UINT8_T
 +#endif
 +
 +#if !defined(HAVE_UINT16_T)
 +#error No 8-bit unsigned integer type was found.
 +#endif
 +
 +/* Define intmax_t and uintmax_t if they are not already defined. */
 +#if !defined(HAVE_INTMAX_T)
 +typedef int64_t intmax_t;
 +#define INTMAX_MIN INT64_MIN
 +#define INTMAX_MAX INT64_MAX
 +#endif
 +
 +#if !defined(HAVE_UINTMAX_T)
 +typedef uint64_t uintmax_t;
 +#endif
 +
 +/* Define ZLIB_WINAPI if zlib was built on Visual Studio. */
 +#cmakedefine ZLIB_WINAPI 1
 +
 +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */
 +#cmakedefine ARCHIVE_CRYPTO_MD5_LIBC 1
 +
 +/* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */
 +#cmakedefine ARCHIVE_CRYPTO_MD5_LIBSYSTEM 1
 +
 +/* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */
 +#cmakedefine ARCHIVE_CRYPTO_MD5_NETTLE 1
 +
 +/* MD5 via ARCHIVE_CRYPTO_MD5_OPENSSL supported. */
 +#cmakedefine ARCHIVE_CRYPTO_MD5_OPENSSL 1
 +
 +/* MD5 via ARCHIVE_CRYPTO_MD5_WIN supported. */
 +#cmakedefine ARCHIVE_CRYPTO_MD5_WIN 1
 +
 +/* RMD160 via ARCHIVE_CRYPTO_RMD160_LIBC supported. */
 +#cmakedefine ARCHIVE_CRYPTO_RMD160_LIBC 1
 +
 +/* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */
 +#cmakedefine ARCHIVE_CRYPTO_RMD160_NETTLE 1
 +
 +/* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */
 +#cmakedefine ARCHIVE_CRYPTO_RMD160_OPENSSL 1
 +
 +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBC supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA1_LIBC 1
 +
 +/* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA1_LIBSYSTEM 1
 +
 +/* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA1_NETTLE 1
 +
 +/* SHA1 via ARCHIVE_CRYPTO_SHA1_OPENSSL supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA1_OPENSSL 1
 +
 +/* SHA1 via ARCHIVE_CRYPTO_SHA1_WIN supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA1_WIN 1
 +
 +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA256_LIBC 1
 +
 +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC2 supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA256_LIBC2 1
 +
 +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBC3 supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA256_LIBC3 1
 +
 +/* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA256_LIBSYSTEM 1
 +
 +/* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA256_NETTLE 1
 +
 +/* SHA256 via ARCHIVE_CRYPTO_SHA256_OPENSSL supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA256_OPENSSL 1
 +
 +/* SHA256 via ARCHIVE_CRYPTO_SHA256_WIN supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA256_WIN 1
 +
 +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA384_LIBC 1
 +
 +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC2 supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA384_LIBC2 1
 +
 +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBC3 supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA384_LIBC3 1
 +
 +/* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA384_LIBSYSTEM 1
 +
 +/* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA384_NETTLE 1
 +
 +/* SHA384 via ARCHIVE_CRYPTO_SHA384_OPENSSL supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA384_OPENSSL 1
 +
 +/* SHA384 via ARCHIVE_CRYPTO_SHA384_WIN supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA384_WIN 1
 +
 +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA512_LIBC 1
 +
 +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC2 supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA512_LIBC2 1
 +
 +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBC3 supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA512_LIBC3 1
 +
 +/* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA512_LIBSYSTEM 1
 +
 +/* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA512_NETTLE 1
 +
 +/* SHA512 via ARCHIVE_CRYPTO_SHA512_OPENSSL supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA512_OPENSSL 1
 +
 +/* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */
 +#cmakedefine ARCHIVE_CRYPTO_SHA512_WIN 1
 +
 +/* Version number of bsdcpio */
 +#cmakedefine BSDCPIO_VERSION_STRING "${BSDCPIO_VERSION_STRING}"
 +
 +/* Version number of bsdtar */
 +#cmakedefine BSDTAR_VERSION_STRING "${BSDTAR_VERSION_STRING}"
 +
 +/* Define to 1 if you have the `acl_create_entry' function. */
 +#cmakedefine HAVE_ACL_CREATE_ENTRY 1
 +
 +/* Define to 1 if you have the `acl_get_link' function. */
 +#cmakedefine HAVE_ACL_GET_LINK 1
 +
 +/* Define to 1 if you have the `acl_get_link_np' function. */
 +#cmakedefine HAVE_ACL_GET_LINK_NP 1
 +
 +/* Define to 1 if you have the `acl_get_perm' function. */
 +#cmakedefine HAVE_ACL_GET_PERM 1
 +
 +/* Define to 1 if you have the `acl_get_perm_np' function. */
 +#cmakedefine HAVE_ACL_GET_PERM_NP 1
 +
 +/* Define to 1 if you have the `acl_init' function. */
 +#cmakedefine HAVE_ACL_INIT 1
 +
 +/* Define to 1 if you have the <acl/libacl.h> header file. */
 +#cmakedefine HAVE_ACL_LIBACL_H 1
 +
 +/* Define to 1 if the system has the type `acl_permset_t'. */
 +#cmakedefine HAVE_ACL_PERMSET_T 1
 +
 +/* Define to 1 if you have the `acl_set_fd' function. */
 +#cmakedefine HAVE_ACL_SET_FD 1
 +
 +/* Define to 1 if you have the `acl_set_fd_np' function. */
 +#cmakedefine HAVE_ACL_SET_FD_NP 1
 +
 +/* Define to 1 if you have the `acl_set_file' function. */
 +#cmakedefine HAVE_ACL_SET_FILE 1
 +
 +/* True for systems with POSIX ACL support */
 +#cmakedefine HAVE_ACL_USER 1
 +
 +/* Define to 1 if you have the <attr/xattr.h> header file. */
 +#cmakedefine HAVE_ATTR_XATTR_H 1
 +
 +/* Define to 1 if you have the <bsdxml.h> header file. */
 +#cmakedefine HAVE_BSDXML_H 1
 +
 +/* Define to 1 if you have the <bzlib.h> header file. */
 +#cmakedefine HAVE_BZLIB_H 1
 +
 +/* Define to 1 if you have the `chflags' function. */
 +#cmakedefine HAVE_CHFLAGS 1
 +
 +/* Define to 1 if you have the `chown' function. */
 +#cmakedefine HAVE_CHOWN 1
 +
 +/* Define to 1 if you have the `chroot' function. */
 +#cmakedefine HAVE_CHROOT 1
 +
 +/* Define to 1 if you have the <copyfile.h> header file. */
 +#cmakedefine HAVE_COPYFILE_H 1
 +
 +/* Define to 1 if you have the `ctime_r' function. */
 +#cmakedefine HAVE_CTIME_R 1
 +
 +/* Define to 1 if you have the <ctype.h> header file. */
 +#cmakedefine HAVE_CTYPE_H 1
 +
 +/* Define to 1 if you have the `cygwin_conv_path' function. */
 +#cmakedefine HAVE_CYGWIN_CONV_PATH 1
 +
 +/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you
 +   don't. */
 +#cmakedefine HAVE_DECL_INT64_MAX 1
 +
 +/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you
 +   don't. */
 +#cmakedefine HAVE_DECL_INT64_MIN 1
 +
 +/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you
 +   don't. */
 +#cmakedefine HAVE_DECL_SIZE_MAX 1
 +
 +/* Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you
 +   don't. */
 +#cmakedefine HAVE_DECL_SSIZE_MAX 1
 +
 +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
 +   don't. */
 +#cmakedefine HAVE_DECL_STRERROR_R 1
 +
 +/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you
 +   don't. */
 +#cmakedefine HAVE_DECL_UINT32_MAX 1
 +
 +/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you
 +   don't. */
 +#cmakedefine HAVE_DECL_UINT64_MAX 1
 +
 +/* Define to 1 if you have the <direct.h> header file. */
 +#cmakedefine HAVE_DIRECT_H 1
 +
 +/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
 +   */
 +#cmakedefine HAVE_DIRENT_H 1
 +
++/* Define to 1 if you have the `dirfd' function. */
++#cmakedefine HAVE_DIRFD 1
++
 +/* Define to 1 if you have the <dlfcn.h> header file. */
 +#cmakedefine HAVE_DLFCN_H 1
 +
 +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
 +#cmakedefine HAVE_DOPRNT 1
 +
 +/* Define to 1 if nl_langinfo supports D_MD_ORDER */
 +#cmakedefine HAVE_D_MD_ORDER 1
 +
 +/* A possible errno value for invalid file format errors */
 +#cmakedefine HAVE_EFTYPE 1
 +
 +/* A possible errno value for invalid file format errors */
 +#cmakedefine HAVE_EILSEQ 1
 +
 +/* Define to 1 if you have the <errno.h> header file. */
 +#cmakedefine HAVE_ERRNO_H 1
 +
 +/* Define to 1 if you have the <expat.h> header file. */
 +#cmakedefine HAVE_EXPAT_H 1
 +
 +/* Define to 1 if you have the <ext2fs/ext2_fs.h> header file. */
 +#cmakedefine HAVE_EXT2FS_EXT2_FS_H 1
 +
 +/* Define to 1 if you have the `extattr_get_file' function. */
 +#cmakedefine HAVE_EXTATTR_GET_FILE 1
 +
 +/* Define to 1 if you have the `extattr_list_file' function. */
 +#cmakedefine HAVE_EXTATTR_LIST_FILE 1
 +
 +/* Define to 1 if you have the `extattr_set_fd' function. */
 +#cmakedefine HAVE_EXTATTR_SET_FD 1
 +
 +/* Define to 1 if you have the `extattr_set_file' function. */
 +#cmakedefine HAVE_EXTATTR_SET_FILE 1
 +
 +/* Define to 1 if EXTATTR_NAMESPACE_USER is defined in sys/extattr.h. */
 +#cmakedefine HAVE_DECL_EXTATTR_NAMESPACE_USER 1
 +
 +/* Define to 1 if you have the `fchdir' function. */
 +#cmakedefine HAVE_FCHDIR 1
 +
 +/* Define to 1 if you have the `fchflags' function. */
 +#cmakedefine HAVE_FCHFLAGS 1
 +
 +/* Define to 1 if you have the `fchmod' function. */
 +#cmakedefine HAVE_FCHMOD 1
 +
 +/* Define to 1 if you have the `fchown' function. */
 +#cmakedefine HAVE_FCHOWN 1
 +
 +/* Define to 1 if you have the `fcntl' function. */
 +#cmakedefine HAVE_FCNTL 1
 +
 +/* Define to 1 if you have the <fcntl.h> header file. */
 +#cmakedefine HAVE_FCNTL_H 1
 +
 +/* Define to 1 if you have the `fdopendir' function. */
 +#cmakedefine HAVE_FDOPENDIR 1
 +
 +/* Define to 1 if you have the `fgetea' function. */
 +#cmakedefine HAVE_FGETEA 1
 +
 +/* Define to 1 if you have the `fgetxattr' function. */
 +#cmakedefine HAVE_FGETXATTR 1
 +
 +/* Define to 1 if you have the `flistea' function. */
 +#cmakedefine HAVE_FLISTEA 1
 +
 +/* Define to 1 if you have the `flistxattr' function. */
 +#cmakedefine HAVE_FLISTXATTR 1
 +
 +/* Define to 1 if you have the `fork' function. */
 +#cmakedefine HAVE_FORK 1
 +
 +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
 +#cmakedefine HAVE_FSEEKO 1
 +
 +/* Define to 1 if you have the `fsetea' function. */
 +#cmakedefine HAVE_FSETEA 1
 +
 +/* Define to 1 if you have the `fsetxattr' function. */
 +#cmakedefine HAVE_FSETXATTR 1
 +
 +/* Define to 1 if you have the `fstat' function. */
 +#cmakedefine HAVE_FSTAT 1
 +
 +/* Define to 1 if you have the `fstatat' function. */
 +#cmakedefine HAVE_FSTATAT 1
 +
 +/* Define to 1 if you have the `fstatfs' function. */
 +#cmakedefine HAVE_FSTATFS 1
 +
 +/* Define to 1 if you have the `fstatvfs' function. */
 +#cmakedefine HAVE_FSTATVFS 1
 +
 +/* Define to 1 if you have the `ftruncate' function. */
 +#cmakedefine HAVE_FTRUNCATE 1
 +
 +/* Define to 1 if you have the `futimens' function. */
 +#cmakedefine HAVE_FUTIMENS 1
 +
 +/* Define to 1 if you have the `futimes' function. */
 +#cmakedefine HAVE_FUTIMES 1
 +
 +/* Define to 1 if you have the `futimesat' function. */
 +#cmakedefine HAVE_FUTIMESAT 1
 +
 +/* Define to 1 if you have the `getea' function. */
 +#cmakedefine HAVE_GETEA 1
 +
 +/* Define to 1 if you have the `geteuid' function. */
 +#cmakedefine HAVE_GETEUID 1
 +
 +/* Define to 1 if you have the `getgrgid_r' function. */
 +#cmakedefine HAVE_GETGRGID_R 1
 +
 +/* Define to 1 if you have the `getgrnam_r' function. */
 +#cmakedefine HAVE_GETGRNAM_R 1
 +
 +/* Define to 1 if you have the `getpid' function. */
 +#cmakedefine HAVE_GETPID 1
 +
 +/* Define to 1 if you have the `getpwnam_r' function. */
 +#cmakedefine HAVE_GETPWNAM_R 1
 +
 +/* Define to 1 if you have the `getpwuid_r' function. */
 +#cmakedefine HAVE_GETPWUID_R 1
 +
 +/* Define to 1 if you have the `getvfsbyname' function. */
 +#cmakedefine HAVE_GETVFSBYNAME 1
 +
 +/* Define to 1 if you have the `getxattr' function. */
 +#cmakedefine HAVE_GETXATTR 1
 +
 +/* Define to 1 if you have the `gmtime_r' function. */
 +#cmakedefine HAVE_GMTIME_R 1
 +
 +/* Define to 1 if you have the <grp.h> header file. */
 +#cmakedefine HAVE_GRP_H 1
 +
 +/* Define to 1 if you have the `iconv' function. */
 +#cmakedefine HAVE_ICONV 1
 +
 +/* Define to 1 if you have the <iconv.h> header file. */
 +#cmakedefine HAVE_ICONV_H 1
 +
 +/* Define to 1 if you have the <inttypes.h> header file. */
 +#cmakedefine HAVE_INTTYPES_H 1
 +
 +/* Define to 1 if you have the <io.h> header file. */
 +#cmakedefine HAVE_IO_H 1
 +
 +/* Define to 1 if you have the <langinfo.h> header file. */
 +#cmakedefine HAVE_LANGINFO_H 1
 +
 +/* Define to 1 if you have the `lchflags' function. */
 +#cmakedefine HAVE_LCHFLAGS 1
 +
 +/* Define to 1 if you have the `lchmod' function. */
 +#cmakedefine HAVE_LCHMOD 1
 +
 +/* Define to 1 if you have the `lchown' function. */
 +#cmakedefine HAVE_LCHOWN 1
 +
 +/* Define to 1 if you have the `lgetea' function. */
 +#cmakedefine HAVE_LGETEA 1
 +
 +/* Define to 1 if you have the `lgetxattr' function. */
 +#cmakedefine HAVE_LGETXATTR 1
 +
 +/* Define to 1 if you have the `acl' library (-lacl). */
 +#cmakedefine HAVE_LIBACL 1
 +
 +/* Define to 1 if you have the `attr' library (-lattr). */
 +#cmakedefine HAVE_LIBATTR 1
 +
 +/* Define to 1 if you have the `bsdxml' library (-lbsdxml). */
 +#cmakedefine HAVE_LIBBSDXML 1
 +
 +/* Define to 1 if you have the `bz2' library (-lbz2). */
 +#cmakedefine HAVE_LIBBZ2 1
 +
 +/* Define to 1 if you have the `expat' library (-lexpat). */
 +#cmakedefine HAVE_LIBEXPAT 1
 +
++/* Define to 1 if you have the `gcc' library (-lgcc). */
++#cmakedefine HAVE_LIBGCC 1
++
 +/* Define to 1 if you have the `lzma' library (-llzma). */
 +#cmakedefine HAVE_LIBLZMA 1
 +
 +/* Define to 1 if you have the `lzmadec' library (-llzmadec). */
 +#cmakedefine HAVE_LIBLZMADEC 1
 +
++/* Define to 1 if you have the `lzo2' library (-llzo2). */
++#cmakedefine HAVE_LIBLZO2 1
++
++/* Define to 1 if you have the `nettle' library (-lnettle). */
++#cmakedefine HAVE_LIBNETTLE 1
++
++/* Define to 1 if you have the `pcre' library (-lpcre). */
++#cmakedefine HAVE_LIBPCRE 1
++
++/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */
++#cmakedefine HAVE_LIBPCREPOSIX 1
++
 +/* Define to 1 if you have the `xml2' library (-lxml2). */
 +#cmakedefine HAVE_LIBXML2 1
 +
 +/* Define to 1 if you have the <libxml/xmlreader.h> header file. */
 +#cmakedefine HAVE_LIBXML_XMLREADER_H 1
 +
 +/* Define to 1 if you have the <libxml/xmlwriter.h> header file. */
 +#cmakedefine HAVE_LIBXML_XMLWRITER_H 1
 +
 +/* Define to 1 if you have the `z' library (-lz). */
 +#cmakedefine HAVE_LIBZ 1
 +
 +/* Define to 1 if you have the <limits.h> header file. */
 +#cmakedefine HAVE_LIMITS_H 1
 +
 +/* Define to 1 if you have the `link' function. */
 +#cmakedefine HAVE_LINK 1
 +
 +/* Define to 1 if you have the <linux/types.h> header file. */
 +#cmakedefine HAVE_LINUX_TYPES_H 1
 +
 +/* Define to 1 if you have the <linux/fiemap.h> header file. */
 +#cmakedefine HAVE_LINUX_FIEMAP_H 1
 +
 +/* Define to 1 if you have the <linux/fs.h> header file. */
 +#cmakedefine HAVE_LINUX_FS_H 1
 +
 +/* Define to 1 if you have the <linux/magic.h> header file. */
 +#cmakedefine HAVE_LINUX_MAGIC_H 1
 +
++/* Define to 1 if you have the <linux/types.h> header file. */
++#cmakedefine HAVE_LINUX_TYPES_H 1
++
 +/* Define to 1 if you have the `listea' function. */
 +#cmakedefine HAVE_LISTEA 1
 +
 +/* Define to 1 if you have the `listxattr' function. */
 +#cmakedefine HAVE_LISTXATTR 1
 +
 +/* Define to 1 if you have the `llistea' function. */
 +#cmakedefine HAVE_LLISTEA 1
 +
 +/* Define to 1 if you have the `llistxattr' function. */
 +#cmakedefine HAVE_LLISTXATTR 1
 +
 +/* Define to 1 if you have the <localcharset.h> header file. */
 +#cmakedefine HAVE_LOCALCHARSET_H 1
 +
 +/* Define to 1 if you have the `locale_charset' function. */
 +#cmakedefine HAVE_LOCALE_CHARSET 1
 +
 +/* Define to 1 if you have the <locale.h> header file. */
 +#cmakedefine HAVE_LOCALE_H 1
 +
 +/* Define to 1 if you have the `localtime_r' function. */
 +#cmakedefine HAVE_LOCALTIME_R 1
 +
 +/* Define to 1 if the system has the type `long long int'. */
 +#cmakedefine HAVE_LONG_LONG_INT 1
 +
 +/* Define to 1 if you have the `lsetea' function. */
 +#cmakedefine HAVE_LSETEA 1
 +
 +/* Define to 1 if you have the `lsetxattr' function. */
 +#cmakedefine HAVE_LSETXATTR 1
 +
 +/* Define to 1 if you have the `lstat' function. */
 +#cmakedefine HAVE_LSTAT 1
 +
 +/* Define to 1 if `lstat' has the bug that it succeeds when given the
 +   zero-length file name argument. */
 +#cmakedefine HAVE_LSTAT_EMPTY_STRING_BUG 1
 +
 +/* Define to 1 if you have the `lutimes' function. */
 +#cmakedefine HAVE_LUTIMES 1
 +
 +/* Define to 1 if you have the <lzmadec.h> header file. */
 +#cmakedefine HAVE_LZMADEC_H 1
 +
 +/* Define to 1 if you have the <lzma.h> header file. */
 +#cmakedefine HAVE_LZMA_H 1
 +
++/* Define to 1 if you have the <lzo/lzo1x.h> header file. */
++#cmakedefine HAVE_LZO_LZO1X_H 1
++
++/* Define to 1 if you have the <lzo/lzoconf.h> header file. */
++#cmakedefine HAVE_LZO_LZOCONF_H 1
++
 +/* Define to 1 if you have the `mbrtowc' function. */
 +#cmakedefine HAVE_MBRTOWC 1
 +
- /* Define to 1 if you have the `mbsnrtowcs' function. */
- #cmakedefine HAVE_MBSNRTOWCS 1
- 
 +/* Define to 1 if you have the `memmove' function. */
 +#cmakedefine HAVE_MEMMOVE 1
 +
 +/* Define to 1 if you have the <memory.h> header file. */
 +#cmakedefine HAVE_MEMORY_H 1
 +
 +/* Define to 1 if you have the `mkdir' function. */
 +#cmakedefine HAVE_MKDIR 1
 +
 +/* Define to 1 if you have the `mkfifo' function. */
 +#cmakedefine HAVE_MKFIFO 1
 +
 +/* Define to 1 if you have the `mknod' function. */
 +#cmakedefine HAVE_MKNOD 1
 +
 +/* Define to 1 if you have the `mkstemp' function. */
 +#cmakedefine HAVE_MKSTEMP 1
 +
 +/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
 +#cmakedefine HAVE_NDIR_H 1
 +
++/* Define to 1 if you have the <nettle/md5.h> header file. */
++#cmakedefine HAVE_NETTLE_MD5_H 1
++
++/* Define to 1 if you have the <nettle/ripemd160.h> header file. */
++#cmakedefine HAVE_NETTLE_RIPEMD160_H 1
++
++/* Define to 1 if you have the <nettle/sha.h> header file. */
++#cmakedefine HAVE_NETTLE_SHA_H 1
++
 +/* Define to 1 if you have the `nl_langinfo' function. */
 +#cmakedefine HAVE_NL_LANGINFO 1
 +
 +/* Define to 1 if you have the `openat' function. */
 +#cmakedefine HAVE_OPENAT 1
 +
 +/* Define to 1 if you have the <paths.h> header file. */
 +#cmakedefine HAVE_PATHS_H 1
 +
++/* Define to 1 if you have the <pcreposix.h> header file. */
++#cmakedefine HAVE_PCREPOSIX_H 1
++
 +/* Define to 1 if you have the `pipe' function. */
 +#cmakedefine HAVE_PIPE 1
 +
 +/* Define to 1 if you have the `poll' function. */
 +#cmakedefine HAVE_POLL 1
 +
 +/* Define to 1 if you have the <poll.h> header file. */
 +#cmakedefine HAVE_POLL_H 1
 +
++/* Define to 1 if you have the `posix_spawnp' function. */
++#cmakedefine HAVE_POSIX_SPAWNP 1
++
 +/* Define to 1 if you have the <process.h> header file. */
 +#cmakedefine HAVE_PROCESS_H 1
 +
 +/* Define to 1 if you have the <pwd.h> header file. */
 +#cmakedefine HAVE_PWD_H 1
 +
 +/* Define to 1 if you have the `readdir_r' function. */
 +#cmakedefine HAVE_READDIR_R 1
 +
 +/* Define to 1 if you have the `readlink' function. */
 +#cmakedefine HAVE_READLINK 1
 +
 +/* Define to 1 if you have the `readlinkat' function. */
 +#cmakedefine HAVE_READLINKAT 1
 +
 +/* Define to 1 if you have the <regex.h> header file. */
 +#cmakedefine HAVE_REGEX_H 1
 +
 +/* Define to 1 if you have the `select' function. */
 +#cmakedefine HAVE_SELECT 1
 +
 +/* Define to 1 if you have the `setenv' function. */
 +#cmakedefine HAVE_SETENV 1
 +
 +/* Define to 1 if you have the `setlocale' function. */
 +#cmakedefine HAVE_SETLOCALE 1
 +
 +/* Define to 1 if you have the `sigaction' function. */
 +#cmakedefine HAVE_SIGACTION 1
 +
 +/* Define to 1 if you have the <signal.h> header file. */
 +#cmakedefine HAVE_SIGNAL_H 1
 +
++/* Define to 1 if you have the <spawn.h> header file. */
++#cmakedefine HAVE_SPAWN_H 1
++
 +/* Define to 1 if you have the `statfs' function. */
 +#cmakedefine HAVE_STATFS 1
 +
 +/* Define to 1 if you have the `statvfs' function. */
 +#cmakedefine HAVE_STATVFS 1
 +
 +/* Define to 1 if `stat' has the bug that it succeeds when given the
 +   zero-length file name argument. */
 +#cmakedefine HAVE_STAT_EMPTY_STRING_BUG 1
 +
 +/* Define to 1 if you have the <stdarg.h> header file. */
 +#cmakedefine HAVE_STDARG_H 1
 +
 +/* Define to 1 if you have the <stdint.h> header file. */
 +#cmakedefine HAVE_STDINT_H 1
 +
 +/* Define to 1 if you have the <stdlib.h> header file. */
 +#cmakedefine HAVE_STDLIB_H 1
 +
 +/* Define to 1 if you have the `strchr' function. */
 +#cmakedefine HAVE_STRCHR 1
 +
 +/* Define to 1 if you have the `strdup' function. */
 +#cmakedefine HAVE_STRDUP 1
 +
 +/* Define to 1 if you have the `strerror' function. */
 +#cmakedefine HAVE_STRERROR 1
 +
 +/* Define to 1 if you have the `strerror_r' function. */
 +#cmakedefine HAVE_STRERROR_R 1
 +
 +/* Define to 1 if you have the `strftime' function. */
 +#cmakedefine HAVE_STRFTIME 1
 +
 +/* Define to 1 if you have the <strings.h> header file. */
 +#cmakedefine HAVE_STRINGS_H 1
 +
 +/* Define to 1 if you have the <string.h> header file. */
 +#cmakedefine HAVE_STRING_H 1
 +
 +/* Define to 1 if you have the `strrchr' function. */
 +#cmakedefine HAVE_STRRCHR 1
 +
 +/* Define to 1 if `f_namemax' is a member of `struct statfs'. */
 +#cmakedefine HAVE_STRUCT_STATFS_F_NAMEMAX 1
 +
 +/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */
 +#cmakedefine HAVE_STRUCT_STATVFS_F_IOSIZE 1
 +
 +/* Define to 1 if `st_birthtime' is a member of `struct stat'. */
 +#cmakedefine HAVE_STRUCT_STAT_ST_BIRTHTIME 1
 +
 +/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */
 +#cmakedefine HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1
 +
 +/* Define to 1 if `st_blksize' is a member of `struct stat'. */
 +#cmakedefine HAVE_STRUCT_STAT_ST_BLKSIZE 1
 +
 +/* Define to 1 if `st_flags' is a member of `struct stat'. */
 +#cmakedefine HAVE_STRUCT_STAT_ST_FLAGS 1
 +
 +/* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */
 +#cmakedefine HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
 +
 +/* Define to 1 if `st_mtime_n' is a member of `struct stat'. */
 +#cmakedefine HAVE_STRUCT_STAT_ST_MTIME_N 1
 +
 +/* Define to 1 if `st_mtime_usec' is a member of `struct stat'. */
 +#cmakedefine HAVE_STRUCT_STAT_ST_MTIME_USEC 1
 +
 +/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */
 +#cmakedefine HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1
 +
 +/* Define to 1 if `st_umtime' is a member of `struct stat'. */
 +#cmakedefine HAVE_STRUCT_STAT_ST_UMTIME 1
 +
 +/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */
 +#cmakedefine HAVE_STRUCT_TM_TM_GMTOFF 1
 +
 +/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */
 +#cmakedefine HAVE_STRUCT_TM___TM_GMTOFF 1
 +
 +/* Define to 1 if you have the `symlink' function. */
 +#cmakedefine HAVE_SYMLINK 1
 +
 +/* Define to 1 if you have the <sys/acl.h> header file. */
 +#cmakedefine HAVE_SYS_ACL_H 1
 +
 +/* Define to 1 if you have the <sys/cdefs.h> header file. */
 +#cmakedefine HAVE_SYS_CDEFS_H 1
 +
 +/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
 +   */
 +#cmakedefine HAVE_SYS_DIR_H 1
 +
 +/* Define to 1 if you have the <sys/ea.h> header file. */
 +#cmakedefine HAVE_SYS_EA_H 1
 +
 +/* Define to 1 if you have the <sys/extattr.h> header file. */
 +#cmakedefine HAVE_SYS_EXTATTR_H 1
 +
 +/* Define to 1 if you have the <sys/ioctl.h> header file. */
 +#cmakedefine HAVE_SYS_IOCTL_H 1
 +
 +/* Define to 1 if you have the <sys/mkdev.h> header file. */
 +#cmakedefine HAVE_SYS_MKDEV_H 1
 +
 +/* Define to 1 if you have the <sys/mount.h> header file. */
 +#cmakedefine HAVE_SYS_MOUNT_H 1
 +
 +/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
 +   */
 +#cmakedefine HAVE_SYS_NDIR_H 1
 +
 +/* Define to 1 if you have the <sys/param.h> header file. */
 +#cmakedefine HAVE_SYS_PARAM_H 1
 +
 +/* Define to 1 if you have the <sys/poll.h> header file. */
 +#cmakedefine HAVE_SYS_POLL_H 1
 +
 +/* Define to 1 if you have the <sys/select.h> header file. */
 +#cmakedefine HAVE_SYS_SELECT_H 1
 +
 +/* Define to 1 if you have the <sys/statfs.h> header file. */
 +#cmakedefine HAVE_SYS_STATFS_H 1
 +
 +/* Define to 1 if you have the <sys/statvfs.h> header file. */
 +#cmakedefine HAVE_SYS_STATVFS_H 1
 +
 +/* Define to 1 if you have the <sys/stat.h> header file. */
 +#cmakedefine HAVE_SYS_STAT_H 1
 +
 +/* Define to 1 if you have the <sys/time.h> header file. */
 +#cmakedefine HAVE_SYS_TIME_H 1
 +
 +/* Define to 1 if you have the <sys/types.h> header file. */
 +#cmakedefine HAVE_SYS_TYPES_H 1
 +
 +/* Define to 1 if you have the <sys/utime.h> header file. */
 +#cmakedefine HAVE_SYS_UTIME_H 1
 +
 +/* Define to 1 if you have the <sys/utsname.h> header file. */
 +#cmakedefine HAVE_SYS_UTSNAME_H 1
 +
 +/* Define to 1 if you have the <sys/vfs.h> header file. */
 +#cmakedefine HAVE_SYS_VFS_H 1
 +
 +/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
 +#cmakedefine HAVE_SYS_WAIT_H 1
 +
 +/* Define to 1 if you have the <sys/xattr.h> header file. */
 +#cmakedefine HAVE_SYS_XATTR_H 1
 +
 +/* Define to 1 if you have the `timegm' function. */
 +#cmakedefine HAVE_TIMEGM 1
 +
 +/* Define to 1 if you have the <time.h> header file. */
 +#cmakedefine HAVE_TIME_H 1
 +
 +/* Define to 1 if you have the `tzset' function. */
 +#cmakedefine HAVE_TZSET 1
 +
 +/* Define to 1 if you have the <unistd.h> header file. */
 +#cmakedefine HAVE_UNISTD_H 1
 +
 +/* Define to 1 if you have the `unsetenv' function. */
 +#cmakedefine HAVE_UNSETENV 1
 +
 +/* Define to 1 if the system has the type `unsigned long long'. */
 +#cmakedefine HAVE_UNSIGNED_LONG_LONG 1
 +
 +/* Define to 1 if the system has the type `unsigned long long int'. */
 +#cmakedefine HAVE_UNSIGNED_LONG_LONG_INT 1
 +
 +/* Define to 1 if you have the `utime' function. */
 +#cmakedefine HAVE_UTIME 1
 +
 +/* Define to 1 if you have the `utimensat' function. */
 +#cmakedefine HAVE_UTIMENSAT 1
 +
 +/* Define to 1 if you have the `utimes' function. */
 +#cmakedefine HAVE_UTIMES 1
 +
 +/* Define to 1 if you have the <utime.h> header file. */
 +#cmakedefine HAVE_UTIME_H 1
 +
 +/* Define to 1 if you have the `vfork' function. */
 +#cmakedefine HAVE_VFORK 1
 +
 +/* Define to 1 if you have the `vprintf' function. */
 +#cmakedefine HAVE_VPRINTF 1
 +
 +/* Define to 1 if you have the <wchar.h> header file. */
 +#cmakedefine HAVE_WCHAR_H 1
 +
 +/* Define to 1 if the system has the type `wchar_t'. */
 +#cmakedefine HAVE_WCHAR_T 1
 +
 +/* Define to 1 if you have the `wcrtomb' function. */
 +#cmakedefine HAVE_WCRTOMB 1
 +
 +/* Define to 1 if you have the `wcscmp' function. */
 +#cmakedefine HAVE_WCSCMP 1
 +
 +/* Define to 1 if you have the `wcscpy' function. */
 +#cmakedefine HAVE_WCSCPY 1
 +
 +/* Define to 1 if you have the `wcslen' function. */
 +#cmakedefine HAVE_WCSLEN 1
 +
- /* Define to 1 if you have the `wcsnrtombs' function. */
- #cmakedefine HAVE_WCSNRTOMBS 1
- 
 +/* Define to 1 if you have the `wctomb' function. */
 +#cmakedefine HAVE_WCTOMB 1
 +
 +/* Define to 1 if you have the <wctype.h> header file. */
 +#cmakedefine HAVE_WCTYPE_H 1
 +
 +/* Define to 1 if you have the <wincrypt.h> header file. */
 +#cmakedefine HAVE_WINCRYPT_H 1
 +
 +/* Define to 1 if you have the <windows.h> header file. */
 +#cmakedefine HAVE_WINDOWS_H 1
 +
 +/* Define to 1 if you have the <winioctl.h> header file. */
 +#cmakedefine HAVE_WINIOCTL_H 1
 +
 +/* Define to 1 if you have _CrtSetReportMode in <crtdbg.h>  */
 +#cmakedefine HAVE__CrtSetReportMode 1
 +
 +/* Define to 1 if you have the `wmemcmp' function. */
 +#cmakedefine HAVE_WMEMCMP 1
 +
 +/* Define to 1 if you have the `wmemcpy' function. */
 +#cmakedefine HAVE_WMEMCPY 1
 +
 +/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */
 +#cmakedefine HAVE_WORKING_EXT2_IOC_GETFLAGS 1
 +
 +/* Define to 1 if you have the <zlib.h> header file. */
 +#cmakedefine HAVE_ZLIB_H 1
 +
 +/* Define to 1 if you have the `_ctime64_s' function. */
 +#cmakedefine HAVE__CTIME64_S 1
 +
 +/* Define to 1 if you have the `_fseeki64' function. */
 +#cmakedefine HAVE__FSEEKI64 1
 +
 +/* Define to 1 if you have the `_get_timezone' function. */
 +#cmakedefine HAVE__GET_TIMEZONE 1
 +
 +/* Define to 1 if you have the `_localtime64_s' function. */
 +#cmakedefine HAVE__LOCALTIME64_S 1
 +
 +/* Define to 1 if you have the `_mkgmtime64' function. */
 +#cmakedefine HAVE__MKGMTIME64 1
 +
 +/* Define as const if the declaration of iconv() needs const. */
 +#define ICONV_CONST ${ICONV_CONST}
 +
 +/* Version number of libarchive as a single integer */
 +#cmakedefine LIBARCHIVE_VERSION_NUMBER "${LIBARCHIVE_VERSION_NUMBER}"
 +
 +/* Version number of libarchive */
 +#cmakedefine LIBARCHIVE_VERSION_STRING "${LIBARCHIVE_VERSION_STRING}"
 +
 +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
 +   slash. */
 +#cmakedefine LSTAT_FOLLOWS_SLASHED_SYMLINK 1
 +
 +/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
 +   */
 +#cmakedefine MAJOR_IN_MKDEV 1
 +
 +/* Define to 1 if `major', `minor', and `makedev' are declared in
 +   <sysmacros.h>. */
 +#cmakedefine MAJOR_IN_SYSMACROS 1
 +
 +/* Define to 1 if your C compiler doesn't accept -c and -o together. */
 +#cmakedefine NO_MINUS_C_MINUS_O 1
 +
 +/* The size of `wchar_t', as computed by sizeof. */
 +#cmakedefine SIZEOF_WCHAR_T ${SIZEOF_WCHAR_T}
 +
 +/* Define to 1 if strerror_r returns char *. */
 +#cmakedefine STRERROR_R_CHAR_P 1
 +
 +/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
 +#cmakedefine TIME_WITH_SYS_TIME 1
 +
 +/*
 + * Some platform requires a macro to use extension functions.
 + */
 +#cmakedefine SAFE_TO_DEFINE_EXTENSIONS 1
 +#ifdef SAFE_TO_DEFINE_EXTENSIONS
 +/* Enable extensions on AIX 3, Interix.  */
 +#ifndef _ALL_SOURCE
 +# define _ALL_SOURCE 1
 +#endif
 +/* Enable GNU extensions on systems that have them.  */
 +#ifndef _GNU_SOURCE
 +# define _GNU_SOURCE 1
 +#endif
 +/* Enable threading extensions on Solaris.  */
 +#ifndef _POSIX_PTHREAD_SEMANTICS
 +# define _POSIX_PTHREAD_SEMANTICS 1
 +#endif
 +/* Enable extensions on HP NonStop.  */
 +#ifndef _TANDEM_SOURCE
 +# define _TANDEM_SOURCE 1
 +#endif
 +/* Enable general extensions on Solaris.  */
 +#ifndef __EXTENSIONS__
 +# define __EXTENSIONS__ 1
 +#endif
 +#endif /* SAFE_TO_DEFINE_EXTENSIONS */
 +
 +/* Version number of package */
 +#cmakedefine VERSION "${VERSION}"
 +
 +/* Number of bits in a file offset, on hosts where this is settable. */
 +#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
 +
 +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
 +#cmakedefine _LARGEFILE_SOURCE 1
 +
 +/* Define for large files, on AIX-style hosts. */
 +#cmakedefine _LARGE_FILES ${_LARGE_FILES}
 +
 +/* Define for Windows to use Windows 2000+ APIs. */
 +#cmakedefine _WIN32_WINNT ${_WIN32_WINNT}
 +#cmakedefine WINVER ${WINVER}
 +
 +/* Define to empty if `const' does not conform to ANSI C. */
 +#cmakedefine const ${const}
 +
 +/* Define to `int' if <sys/types.h> doesn't define. */
 +#cmakedefine gid_t ${gid_t}
 +
 +/* Define to `unsigned long' if <sys/types.h> does not define. */
 +#cmakedefine id_t ${id_t}
 +
 +/* Define to `int' if <sys/types.h> does not define. */
 +#cmakedefine mode_t ${mode_t}
 +
 +/* Define to `long long' if <sys/types.h> does not define. */
 +#cmakedefine off_t ${off_t}
 +
 +/* Define to `int' if <sys/types.h> doesn't define. */
 +#cmakedefine pid_t ${pid_t}
 +
 +/* Define to `unsigned int' if <sys/types.h> does not define. */
 +#cmakedefine size_t ${size_t}
 +
 +/* Define to `int' if <sys/types.h> does not define. */
 +#cmakedefine ssize_t ${ssize_t}
 +
 +/* Define to `int' if <sys/types.h> doesn't define. */
 +#cmakedefine uid_t ${uid_t}
 +
 +/* Define to `int' if <sys/types.h> does not define. */
 +#cmakedefine intptr_t ${intptr_t}
 +
 +/* Define to `unsigned int' if <sys/types.h> does not define. */
 +#cmakedefine uintptr_t ${uintptr_t}
diff --cc Utilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh
index 95dbe16,925de5c..925de5c
mode 100644,100755..100755
--- a/Utilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh
+++ b/Utilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh
diff --cc Utilities/cmlibarchive/libarchive/CMakeLists.txt
index 7384195,0000000..42781bc
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
@@@ -1,152 -1,0 +1,173 @@@
 +
 +############################################
 +#
 +# 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_cmdline.c
++  archive_cmdline_private.h
++  archive_crc32.h
 +  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_getdate.c
++  archive_match.c
 +  archive_options.c
 +  archive_options_private.h
++  archive_pathmatch.c
++  archive_pathmatch.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_append_filter.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_format.c
 +  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_grzip.c
++  archive_read_support_filter_lrzip.c
++  archive_read_support_filter_lzop.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_acl.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.c
++  archive_write_add_filter_b64encode.c
++  archive_write_add_filter_by_name.c
 +  archive_write_add_filter_bzip2.c
 +  archive_write_add_filter_compress.c
++  archive_write_add_filter_grzip.c
 +  archive_write_add_filter_gzip.c
++  archive_write_add_filter_lrzip.c
++  archive_write_add_filter_lzop.c
 +  archive_write_add_filter_none.c
 +  archive_write_add_filter_program.c
++  archive_write_add_filter_uuencode.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_v7tar.c
 +  archive_write_set_format_xar.c
 +  archive_write_set_format_zip.c
 +  archive_write_set_options.c
-   filter_fork.c
++  filter_fork_posix.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)
 +
 +# CMake needs just one static "cmlibarchive" library.
 +ADD_LIBRARY(cmlibarchive STATIC ${libarchive_SOURCES} ${include_HEADERS})
 +TARGET_LINK_LIBRARIES(cmlibarchive ${ADDITIONAL_LIBS})
diff --cc Utilities/cmlibarchive/libarchive/archive.h
index 9b6b1b0,0000000..f866978
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive.h
+++ b/Utilities/cmlibarchive/libarchive/archive.h
@@@ -1,826 -1,0 +1,1047 @@@
 +/*-
 + * 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) && !defined(__osf__)
 +# include <inttypes.h>
 +#endif
 +
 +/* Borland symbols are case-insensitive.  This workaround only works
 +   within CMake because we do not mix compilers.  */
 +#if defined(__BORLANDC__)
 +# define archive_read_open_FILE archive_read_open_FILE_
 +# define archive_write_open_FILE archive_write_open_FILE_
 +#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) || defined(__osf__)
 +#  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
 +
++#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
++# define __LA_DEPRECATED __attribute__((deprecated))
++#else
++# define __LA_DEPRECATED
++#endif
++
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/*
 + * The version number is provided as both a macro and a function.
 + * The macro identifies the installed header; the function identifies
 + * the library version (which may not be the same if you're using a
 + * dynamically-linked version of the library).  Of course, if the
 + * header and library are very different, you should expect some
 + * strangeness.  Don't do that.
 + */
 +
 +/*
 + * The version number is expressed as a single integer that makes it
 + * easy to compare versions at build time: for version a.b.c, the
 + * version number is printf("%d%03d%03d",a,b,c).  For example, if you
 + * know your application requires version 2.12.108 or later, you can
 + * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
 + */
 +/* Note: Compiler will complain if this does not match archive_entry.h! */
- #define	ARCHIVE_VERSION_NUMBER 3000002
++#define	ARCHIVE_VERSION_NUMBER 3001002
 +__LA_DECL int		archive_version_number(void);
 +
 +/*
 + * Textual name/version of the library, useful for version displays.
 + */
- #define	ARCHIVE_VERSION_STRING "libarchive 3.0.2"
++#define	ARCHIVE_VERSION_STRING "libarchive 3.1.2"
 +__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);
 +
++/* Switches from one client data object to the next/prev client data object.
++ * This is useful for reading from different data blocks such as a set of files
++ * that make up one large file.
++ */
++typedef int archive_switch_callback(struct archive *, void *_client_data1,
++			    void *_client_data2);
++
 +/*
 + * Codes to identify various stream filters.
 + */
 +#define	ARCHIVE_FILTER_NONE	0
 +#define	ARCHIVE_FILTER_GZIP	1
 +#define	ARCHIVE_FILTER_BZIP2	2
 +#define	ARCHIVE_FILTER_COMPRESS	3
 +#define	ARCHIVE_FILTER_PROGRAM	4
 +#define	ARCHIVE_FILTER_LZMA	5
 +#define	ARCHIVE_FILTER_XZ	6
 +#define	ARCHIVE_FILTER_UU	7
 +#define	ARCHIVE_FILTER_RPM	8
 +#define	ARCHIVE_FILTER_LZIP	9
++#define	ARCHIVE_FILTER_LRZIP	10
++#define	ARCHIVE_FILTER_LZOP	11
++#define	ARCHIVE_FILTER_GRZIP	12
 +
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +#define	ARCHIVE_COMPRESSION_NONE	ARCHIVE_FILTER_NONE
 +#define	ARCHIVE_COMPRESSION_GZIP	ARCHIVE_FILTER_GZIP
 +#define	ARCHIVE_COMPRESSION_BZIP2	ARCHIVE_FILTER_BZIP2
 +#define	ARCHIVE_COMPRESSION_COMPRESS	ARCHIVE_FILTER_COMPRESS
 +#define	ARCHIVE_COMPRESSION_PROGRAM	ARCHIVE_FILTER_PROGRAM
 +#define	ARCHIVE_COMPRESSION_LZMA	ARCHIVE_FILTER_LZMA
 +#define	ARCHIVE_COMPRESSION_XZ		ARCHIVE_FILTER_XZ
 +#define	ARCHIVE_COMPRESSION_UU		ARCHIVE_FILTER_UU
 +#define	ARCHIVE_COMPRESSION_RPM		ARCHIVE_FILTER_RPM
 +#define	ARCHIVE_COMPRESSION_LZIP	ARCHIVE_FILTER_LZIP
++#define	ARCHIVE_COMPRESSION_LRZIP	ARCHIVE_FILTER_LRZIP
 +#endif
 +
 +/*
 + * Codes returned by archive_format.
 + *
 + * Top 16 bits identifies the format family (e.g., "tar"); lower
 + * 16 bits indicate the variant.  This is updated by read_next_header.
 + * Note that the lower 16 bits will often vary from entry to entry.
 + * In some cases, this variation occurs as libarchive learns more about
 + * the archive (for example, later entries might utilize extensions that
 + * weren't necessary earlier in the archive; in this case, libarchive
 + * will change the format code to indicate the extended format that
 + * was used).  In other cases, it's because different tools have
 + * modified the archive and so different parts of the archive
 + * actually have slightly different formats.  (Both tar and cpio store
 + * format codes in each entry, so it is quite possible for each
 + * entry to be in a different format.)
 + */
 +#define	ARCHIVE_FORMAT_BASE_MASK		0xff0000
 +#define	ARCHIVE_FORMAT_CPIO			0x10000
 +#define	ARCHIVE_FORMAT_CPIO_POSIX		(ARCHIVE_FORMAT_CPIO | 1)
 +#define	ARCHIVE_FORMAT_CPIO_BIN_LE		(ARCHIVE_FORMAT_CPIO | 2)
 +#define	ARCHIVE_FORMAT_CPIO_BIN_BE		(ARCHIVE_FORMAT_CPIO | 3)
 +#define	ARCHIVE_FORMAT_CPIO_SVR4_NOCRC		(ARCHIVE_FORMAT_CPIO | 4)
 +#define	ARCHIVE_FORMAT_CPIO_SVR4_CRC		(ARCHIVE_FORMAT_CPIO | 5)
 +#define	ARCHIVE_FORMAT_CPIO_AFIO_LARGE		(ARCHIVE_FORMAT_CPIO | 6)
 +#define	ARCHIVE_FORMAT_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_all(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_read_support_compression_bzip2(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_read_support_compression_compress(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_read_support_compression_gzip(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_read_support_compression_lzip(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_read_support_compression_lzma(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_read_support_compression_none(struct archive *)
++		__LA_DEPRECATED;
 +__LA_DECL int archive_read_support_compression_program(struct archive *,
- 		     const char *command);
++		     const char *command) __LA_DEPRECATED;
 +__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 *);
++		 const void * /* match */, size_t) __LA_DEPRECATED;
++
++__LA_DECL int archive_read_support_compression_rpm(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_read_support_compression_uu(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_read_support_compression_xz(struct archive *)
++		__LA_DEPRECATED;
 +#endif
 +
 +__LA_DECL int archive_read_support_filter_all(struct archive *);
 +__LA_DECL int archive_read_support_filter_bzip2(struct archive *);
 +__LA_DECL int archive_read_support_filter_compress(struct archive *);
 +__LA_DECL int archive_read_support_filter_gzip(struct archive *);
++__LA_DECL int archive_read_support_filter_grzip(struct archive *);
++__LA_DECL int archive_read_support_filter_lrzip(struct archive *);
 +__LA_DECL int archive_read_support_filter_lzip(struct archive *);
 +__LA_DECL int archive_read_support_filter_lzma(struct archive *);
++__LA_DECL int archive_read_support_filter_lzop(struct archive *);
 +__LA_DECL int archive_read_support_filter_none(struct archive *);
 +__LA_DECL int archive_read_support_filter_program(struct archive *,
 +		     const char *command);
 +__LA_DECL int archive_read_support_filter_program_signature
- 		(struct archive *, const char *,
++		(struct archive *, const char * /* cmd */,
 +				    const void * /* match */, size_t);
- 
 +__LA_DECL int archive_read_support_filter_rpm(struct archive *);
 +__LA_DECL int archive_read_support_filter_uu(struct archive *);
 +__LA_DECL int archive_read_support_filter_xz(struct archive *);
 +
 +__LA_DECL int archive_read_support_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 *);
 +
++/* Functions to manually set the format and filters to be used. This is
++ * useful to bypass the bidding process when the format and filters to use
++ * is known in advance.
++ */
++__LA_DECL int archive_read_set_format(struct archive *, int);
++__LA_DECL int archive_read_append_filter(struct archive *, int);
++__LA_DECL int archive_read_append_filter_program(struct archive *,
++    const char *);
++__LA_DECL int archive_read_append_filter_program_signature
++    (struct archive *, const char *, const void * /* match */, size_t);
++
 +/* Set various callbacks. */
 +__LA_DECL int archive_read_set_open_callback(struct archive *,
 +    archive_open_callback *);
 +__LA_DECL int archive_read_set_read_callback(struct archive *,
 +    archive_read_callback *);
 +__LA_DECL int archive_read_set_seek_callback(struct archive *,
 +    archive_seek_callback *);
 +__LA_DECL int archive_read_set_skip_callback(struct archive *,
 +    archive_skip_callback *);
 +__LA_DECL int archive_read_set_close_callback(struct archive *,
 +    archive_close_callback *);
- /* The callback data is provided to all of the callbacks above. */
++/* Callback used to switch between one data object to the next */
++__LA_DECL int archive_read_set_switch_callback(struct archive *,
++    archive_switch_callback *);
++
++/* This sets the first data object. */
 +__LA_DECL int archive_read_set_callback_data(struct archive *, void *);
++/* This sets data object at specified index */
++__LA_DECL int archive_read_set_callback_data2(struct archive *, void *,
++    unsigned int);
++/* This adds a data object at the specified index. */
++__LA_DECL int archive_read_add_callback_data(struct archive *, void *,
++    unsigned int);
++/* This appends a data object to the end of list */
++__LA_DECL int archive_read_append_callback_data(struct archive *, void *);
++/* This prepends a data object to the beginning of list */
++__LA_DECL int archive_read_prepend_callback_data(struct archive *, void *);
++
 +/* Opening freezes the callbacks. */
 +__LA_DECL int archive_read_open1(struct archive *);
 +
 +/* Convenience wrappers around the above. */
 +__LA_DECL int archive_read_open(struct archive *, void *_client_data,
 +		     archive_open_callback *, archive_read_callback *,
 +		     archive_close_callback *);
 +__LA_DECL int archive_read_open2(struct archive *, void *_client_data,
 +		     archive_open_callback *, archive_read_callback *,
 +		     archive_skip_callback *, archive_close_callback *);
 +
 +/*
 + * A variety of shortcuts that invoke archive_read_open() with
 + * canned callbacks suitable for common situations.  The ones that
 + * accept a block size handle tape blocking correctly.
 + */
 +/* Use this if you know the filename.  Note: NULL indicates stdin. */
 +__LA_DECL int archive_read_open_filename(struct archive *,
 +		     const char *_filename, size_t _block_size);
++/* Use this for reading multivolume files by filenames.
++ * NOTE: Must be NULL terminated. Sorting is NOT done. */
++__LA_DECL int archive_read_open_filenames(struct archive *,
++		     const char **_filenames, size_t _block_size);
 +__LA_DECL int archive_read_open_filename_w(struct archive *,
 +		     const wchar_t *_filename, size_t _block_size);
 +/* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
 +__LA_DECL int archive_read_open_file(struct archive *,
- 		     const char *_filename, size_t _block_size);
++		     const char *_filename, size_t _block_size) __LA_DEPRECATED;
 +/* Read an archive that's stored in memory. */
 +__LA_DECL int archive_read_open_memory(struct archive *,
 +		     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);
 +
++/* Seek within the body of an entry.  Similar to lseek(2). */
++__LA_DECL __LA_INT64_T archive_seek_data(struct archive *, __LA_INT64_T, int);
++
 +/*
 + * A zero-copy version of archive_read_data that also exposes the file offset
 + * of each returned block.  Note that the client has no way to specify
 + * the desired size of the block.  The API does guarantee that offsets will
 + * be strictly increasing and that returned blocks will not overlap.
 + */
 +__LA_DECL int archive_read_data_block(struct archive *a,
 +		    const void **buff, size_t *size, __LA_INT64_T *offset);
 +
 +/*-
 + * Some convenience functions that are built on archive_read_data:
 + *  'skip': skips entire entry
 + *  'into_buffer': writes data into memory buffer that you provide
 + *  'into_fd': writes data to specified filedes
 + */
 +__LA_DECL int archive_read_data_skip(struct archive *);
 +__LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
 +
 +/*
 + * Set read options.
 + */
 +/* Apply option to the format only. */
 +__LA_DECL int archive_read_set_format_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option to the filter only. */
 +__LA_DECL int archive_read_set_filter_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option to both the format and the filter. */
 +__LA_DECL int archive_read_set_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option string to both the format and the filter. */
 +__LA_DECL int archive_read_set_options(struct archive *_a,
 +			    const char *opts);
 +
 +/*-
 + * Convenience function to recreate the current entry (whose header
 + * has just been read) on disk.
 + *
 + * This does quite a bit more than just copy data to disk. It also:
 + *  - Creates intermediate directories as required.
 + *  - Manages directory permissions:  non-writable directories will
 + *    be initially created with write permission enabled; when the
 + *    archive is closed, dir permissions are edited to the values specified
 + *    in the archive.
 + *  - Checks hardlinks:  hardlinks will not be extracted unless the
 + *    linked-to file was also extracted within the same session. (TODO)
 + */
 +
 +/* The "flags" argument selects optional behavior, 'OR' the flags you want. */
 +
 +/* Default: Do not try to set owner/group. */
 +#define	ARCHIVE_EXTRACT_OWNER			(0x0001)
 +/* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */
 +#define	ARCHIVE_EXTRACT_PERM			(0x0002)
 +/* Default: Do not restore mtime/atime. */
 +#define	ARCHIVE_EXTRACT_TIME			(0x0004)
 +/* Default: Replace existing files. */
 +#define	ARCHIVE_EXTRACT_NO_OVERWRITE 		(0x0008)
 +/* Default: Try create first, unlink only if create fails with EEXIST. */
 +#define	ARCHIVE_EXTRACT_UNLINK			(0x0010)
 +/* Default: Do not restore ACLs. */
 +#define	ARCHIVE_EXTRACT_ACL			(0x0020)
 +/* Default: Do not restore fflags. */
 +#define	ARCHIVE_EXTRACT_FFLAGS			(0x0040)
 +/* Default: Do not restore xattrs. */
 +#define	ARCHIVE_EXTRACT_XATTR 			(0x0080)
 +/* Default: Do not try to guard against extracts redirected by symlinks. */
 +/* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */
 +#define	ARCHIVE_EXTRACT_SECURE_SYMLINKS		(0x0100)
 +/* Default: Do not reject entries with '..' as path elements. */
 +#define	ARCHIVE_EXTRACT_SECURE_NODOTDOT		(0x0200)
 +/* Default: Create parent directories as needed. */
 +#define	ARCHIVE_EXTRACT_NO_AUTODIR		(0x0400)
 +/* Default: Overwrite files, even if one on disk is newer. */
 +#define	ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER	(0x0800)
 +/* Detect blocks of 0 and write holes instead. */
 +#define	ARCHIVE_EXTRACT_SPARSE			(0x1000)
 +/* Default: Do not restore Mac extended metadata. */
 +/* This has no effect except on Mac OS. */
 +#define	ARCHIVE_EXTRACT_MAC_METADATA		(0x2000)
++/* Default: Use HFS+ compression if it was compressed. */
++/* This has no effect except on Mac OS v10.6 or later. */
++#define	ARCHIVE_EXTRACT_NO_HFS_COMPRESSION	(0x4000)
++/* Default: Do not use HFS+ compression if it was not compressed. */
++/* This has no effect except on Mac OS v10.6 or later. */
++#define	ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED	(0x8000)
 +
 +__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
 +		     int flags);
 +__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *,
 +		     struct archive * /* dest */);
 +__LA_DECL void	 archive_read_extract_set_progress_callback(struct archive *,
 +		     void (*_progress_func)(void *), void *_user_data);
 +
 +/* Record the dev/ino of a file that will not be written.  This is
 + * generally set to the dev/ino of the archive being read. */
 +__LA_DECL void		archive_read_extract_set_skip_file(struct archive *,
 +		     __LA_INT64_T, __LA_INT64_T);
 +
 +/* Close the file and release most resources. */
 +__LA_DECL int		 archive_read_close(struct archive *);
 +/* Release all resources and destroy the object. */
 +/* Note that archive_read_free will call archive_read_close for you. */
 +__LA_DECL int		 archive_read_free(struct archive *);
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +/* Synonym for archive_read_free() for backwards compatibility. */
- __LA_DECL int		 archive_read_finish(struct archive *);
++__LA_DECL int		 archive_read_finish(struct archive *) __LA_DEPRECATED;
 +#endif
 +
 +/*-
 + * To create an archive:
 + *   1) Ask archive_write_new for an archive writer object.
 + *   2) Set any global properties.  In particular, you should set
 + *      the compression and format to use.
 + *   3) Call archive_write_open to open the file (most people
 + *       will use archive_write_open_file or archive_write_open_fd,
 + *       which provide convenient canned I/O callbacks for you).
 + *   4) For each entry:
 + *      - construct an appropriate struct archive_entry structure
 + *      - archive_write_header to write the header
 + *      - archive_write_data to write the entry data
 + *   5) archive_write_close to close the output
 + *   6) archive_write_free to cleanup the writer and release resources
 + */
 +__LA_DECL struct archive	*archive_write_new(void);
 +__LA_DECL int archive_write_set_bytes_per_block(struct archive *,
 +		     int bytes_per_block);
 +__LA_DECL int archive_write_get_bytes_per_block(struct archive *);
 +/* XXX This is badly misnamed; suggestions appreciated. XXX */
 +__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
 +		     int bytes_in_last_block);
 +__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *);
 +
 +/* The dev/ino of a file that won't be archived.  This is used
 + * to avoid recursively adding an archive to itself. */
 +__LA_DECL int archive_write_set_skip_file(struct archive *,
 +    __LA_INT64_T, __LA_INT64_T);
 +
 +#if ARCHIVE_VERSION_NUMBER < 4000000
- __LA_DECL int archive_write_set_compression_bzip2(struct archive *);
- __LA_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_bzip2(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_write_set_compression_compress(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_write_set_compression_gzip(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_write_set_compression_lzip(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_write_set_compression_lzma(struct archive *)
++		__LA_DEPRECATED;
++__LA_DECL int archive_write_set_compression_none(struct archive *)
++		__LA_DEPRECATED;
 +__LA_DECL int archive_write_set_compression_program(struct archive *,
- 		     const char *cmd);
- __LA_DECL int archive_write_set_compression_xz(struct archive *);
++		     const char *cmd) __LA_DEPRECATED;
++__LA_DECL int archive_write_set_compression_xz(struct archive *)
++		__LA_DEPRECATED;
 +#endif
 +
++/* A convenience function to set the filter based on the code. */
++__LA_DECL int archive_write_add_filter(struct archive *, int filter_code);
++__LA_DECL int archive_write_add_filter_by_name(struct archive *,
++		     const char *name);
++__LA_DECL int archive_write_add_filter_b64encode(struct archive *);
 +__LA_DECL int archive_write_add_filter_bzip2(struct archive *);
 +__LA_DECL int archive_write_add_filter_compress(struct archive *);
++__LA_DECL int archive_write_add_filter_grzip(struct archive *);
 +__LA_DECL int archive_write_add_filter_gzip(struct archive *);
++__LA_DECL int archive_write_add_filter_lrzip(struct archive *);
 +__LA_DECL int archive_write_add_filter_lzip(struct archive *);
 +__LA_DECL int archive_write_add_filter_lzma(struct archive *);
++__LA_DECL int archive_write_add_filter_lzop(struct archive *);
 +__LA_DECL int archive_write_add_filter_none(struct archive *);
 +__LA_DECL int archive_write_add_filter_program(struct archive *,
 +		     const char *cmd);
++__LA_DECL int archive_write_add_filter_uuencode(struct archive *);
 +__LA_DECL int archive_write_add_filter_xz(struct archive *);
 +
 +
 +/* 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 *);
++__LA_DECL int archive_write_set_format_mtree_classic(struct archive *);
 +/* TODO: int archive_write_set_format_old_tar(struct archive *); */
 +__LA_DECL int archive_write_set_format_pax(struct archive *);
 +__LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
 +__LA_DECL int archive_write_set_format_shar(struct archive *);
 +__LA_DECL int archive_write_set_format_shar_dump(struct archive *);
 +__LA_DECL int archive_write_set_format_ustar(struct archive *);
++__LA_DECL int archive_write_set_format_v7tar(struct archive *);
 +__LA_DECL int archive_write_set_format_xar(struct archive *);
 +__LA_DECL int archive_write_set_format_zip(struct archive *);
++__LA_DECL int archive_write_zip_set_compression_deflate(struct archive *);
++__LA_DECL int archive_write_zip_set_compression_store(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 *, const char *_file)
++		__LA_DEPRECATED;
 +__LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
 +/* _buffSize is the size of the buffer, _used refers to a variable that
 + * will be updated after each write into the buffer. */
 +__LA_DECL int archive_write_open_memory(struct archive *,
 +			void *_buffer, size_t _buffSize, size_t *_used);
 +
 +/*
 + * Note that the library will truncate writes beyond the size provided
 + * to archive_write_header or pad if the provided data is short.
 + */
 +__LA_DECL int archive_write_header(struct archive *,
 +		     struct archive_entry *);
 +__LA_DECL __LA_SSIZE_T	archive_write_data(struct archive *,
 +			    const void *, size_t);
 +
 +/* This interface is currently only available for archive_write_disk handles.  */
 +__LA_DECL __LA_SSIZE_T	 archive_write_data_block(struct archive *,
 +				    const void *, size_t, __LA_INT64_T);
 +
 +__LA_DECL int		 archive_write_finish_entry(struct archive *);
 +__LA_DECL int		 archive_write_close(struct archive *);
++/* Marks the archive as FATAL so that a subsequent free() operation
++ * won't try to close() cleanly.  Provides a fast abort capability
++ * when the client discovers that things have gone wrong. */
++__LA_DECL int            archive_write_fail(struct archive *);
 +/* This can fail if the archive wasn't already closed, in which case
 + * archive_write_free() will implicitly call archive_write_close(). */
 +__LA_DECL int		 archive_write_free(struct archive *);
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +/* Synonym for archive_write_free() for backwards compatibility. */
- __LA_DECL int		 archive_write_finish(struct archive *);
++__LA_DECL int		 archive_write_finish(struct archive *) __LA_DEPRECATED;
 +#endif
 +
 +/*
 + * Set write options.
 + */
 +/* Apply option to the format only. */
 +__LA_DECL int archive_write_set_format_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option to the filter only. */
 +__LA_DECL int archive_write_set_filter_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option to both the format and the filter. */
 +__LA_DECL int archive_write_set_option(struct archive *_a,
 +			    const char *m, const char *o,
 +			    const char *v);
 +/* Apply option string to both the format and the filter. */
 +__LA_DECL int archive_write_set_options(struct archive *_a,
 +			    const char *opts);
 +
 +/*-
 + * ARCHIVE_WRITE_DISK API
 + *
 + * To create objects on disk:
 + *   1) Ask archive_write_disk_new for a new archive_write_disk object.
 + *   2) Set any global properties.  In particular, you probably
 + *      want to set the options.
 + *   3) For each entry:
 + *      - construct an appropriate struct archive_entry structure
 + *      - archive_write_header to create the file/dir/etc on disk
 + *      - archive_write_data to write the entry data
 + *   4) archive_write_free to cleanup the writer and release resources
 + *
 + * In particular, you can use this in conjunction with archive_read()
 + * to pull entries out of an archive and create them on disk.
 + */
 +__LA_DECL struct archive	*archive_write_disk_new(void);
 +/* This file will not be overwritten. */
 +__LA_DECL int archive_write_disk_set_skip_file(struct archive *,
 +    __LA_INT64_T, __LA_INT64_T);
 +/* Set flags to control how the next item gets created.
 + * This accepts a bitmask of ARCHIVE_EXTRACT_XXX flags defined above. */
 +__LA_DECL int		 archive_write_disk_set_options(struct archive *,
 +		     int flags);
 +/*
 + * The lookup functions are given uname/uid (or gname/gid) pairs and
 + * return a uid (gid) suitable for this system.  These are used for
 + * restoring ownership and for setting ACLs.  The default functions
 + * are naive, they just return the uid/gid.  These are small, so reasonable
 + * for applications that don't need to preserve ownership; they
 + * are probably also appropriate for applications that are doing
 + * same-system backup and restore.
 + */
 +/*
 + * The "standard" lookup functions use common system calls to lookup
 + * the uname/gname, falling back to the uid/gid if the names can't be
 + * found.  They cache lookups and are reasonably fast, but can be very
 + * large, so they are not used unless you ask for them.  In
 + * particular, these match the specifications of POSIX "pax" and old
 + * POSIX "tar".
 + */
 +__LA_DECL int	 archive_write_disk_set_standard_lookup(struct archive *);
 +/*
 + * If neither the default (naive) nor the standard (big) functions suit
 + * your needs, you can write your own and register them.  Be sure to
 + * include a cleanup function if you have allocated private data.
 + */
 +__LA_DECL int archive_write_disk_set_group_lookup(struct archive *,
 +    void * /* private_data */,
 +    __LA_INT64_T (*)(void *, const char *, __LA_INT64_T),
 +    void (* /* cleanup */)(void *));
 +__LA_DECL int archive_write_disk_set_user_lookup(struct archive *,
 +    void * /* private_data */,
 +    __LA_INT64_T (*)(void *, const char *, __LA_INT64_T),
 +    void (* /* cleanup */)(void *));
 +__LA_DECL __LA_INT64_T archive_write_disk_gid(struct archive *, const char *, __LA_INT64_T);
 +__LA_DECL __LA_INT64_T archive_write_disk_uid(struct archive *, const char *, __LA_INT64_T);
 +
 +/*
 + * ARCHIVE_READ_DISK API
 + *
 + * This is still evolving and somewhat experimental.
 + */
 +__LA_DECL struct archive *archive_read_disk_new(void);
 +/* The names for symlink modes here correspond to an old BSD
 + * command-line argument convention: -L, -P, -H */
 +/* Follow all symlinks. */
 +__LA_DECL int archive_read_disk_set_symlink_logical(struct archive *);
 +/* Follow no symlinks. */
 +__LA_DECL int archive_read_disk_set_symlink_physical(struct archive *);
 +/* Follow symlink initially, then not. */
 +__LA_DECL int archive_read_disk_set_symlink_hybrid(struct archive *);
 +/* TODO: Handle Linux stat32/stat64 ugliness. <sigh> */
 +__LA_DECL int archive_read_disk_entry_from_file(struct archive *,
 +    struct archive_entry *, int /* fd */, const struct stat *);
 +/* Look up gname for gid or uname for uid. */
 +/* Default implementations are very, very stupid. */
 +__LA_DECL const char *archive_read_disk_gname(struct archive *, __LA_INT64_T);
 +__LA_DECL const char *archive_read_disk_uname(struct archive *, __LA_INT64_T);
 +/* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the
 + * results for performance. */
 +__LA_DECL int	archive_read_disk_set_standard_lookup(struct archive *);
 +/* You can install your own lookups if you like. */
 +__LA_DECL int	archive_read_disk_set_gname_lookup(struct archive *,
 +    void * /* private_data */,
 +    const char *(* /* lookup_fn */)(void *, __LA_INT64_T),
 +    void (* /* cleanup_fn */)(void *));
 +__LA_DECL int	archive_read_disk_set_uname_lookup(struct archive *,
 +    void * /* private_data */,
 +    const char *(* /* lookup_fn */)(void *, __LA_INT64_T),
 +    void (* /* cleanup_fn */)(void *));
 +/* Start traversal. */
 +__LA_DECL int	archive_read_disk_open(struct archive *, const char *);
 +__LA_DECL int	archive_read_disk_open_w(struct archive *, const wchar_t *);
 +/*
 + * Request that current entry be visited.  If you invoke it on every
 + * directory, you'll get a physical traversal.  This is ignored if the
 + * current entry isn't a directory or a link to a directory.  So, if
 + * you invoke this on every returned path, you'll get a full logical
 + * traversal.
 + */
 +__LA_DECL int	archive_read_disk_descend(struct archive *);
++__LA_DECL int	archive_read_disk_can_descend(struct archive *);
 +__LA_DECL int	archive_read_disk_current_filesystem(struct archive *);
 +__LA_DECL int	archive_read_disk_current_filesystem_is_synthetic(struct archive *);
 +__LA_DECL int	archive_read_disk_current_filesystem_is_remote(struct archive *);
 +/* Request that the access time of the entry visited by travesal be restored. */
 +__LA_DECL int  archive_read_disk_set_atime_restored(struct archive *);
++/*
++ * Set behavior. The "flags" argument selects optional behavior.
++ */
++/* Request that the access time of the entry visited by travesal be restored.
++ * This is the same as archive_read_disk_set_atime_restored. */
++#define	ARCHIVE_READDISK_RESTORE_ATIME		(0x0001)
++/* Default: Do not skip an entry which has nodump flags. */
++#define	ARCHIVE_READDISK_HONOR_NODUMP		(0x0002)
++/* Default: Skip a mac resource fork file whose prefix is "._" because of
++ * using copyfile. */
++#define	ARCHIVE_READDISK_MAC_COPYFILE		(0x0004)
++/* Default: Do not traverse mount points. */
++#define	ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS	(0x0008)
++
++__LA_DECL int  archive_read_disk_set_behavior(struct archive *,
++		    int flags);
++
++/*
++ * Set archive_match object that will be used in archive_read_disk to
++ * know whether an entry should be skipped. The callback function
++ * _excluded_func will be invoked when an entry is skipped by the result
++ * of archive_match.
++ */
++__LA_DECL int	archive_read_disk_set_matching(struct archive *,
++		    struct archive *_matching, void (*_excluded_func)
++		    (struct archive *, void *, struct archive_entry *),
++		    void *_client_data);
++__LA_DECL int	archive_read_disk_set_metadata_filter_callback(struct archive *,
++		    int (*_metadata_filter_func)(struct archive *, void *,
++		    	struct archive_entry *), void *_client_data);
 +
 +/*
 + * Accessor functions to read/set various information in
 + * the struct archive object:
 + */
 +
 +/* Number of filters in the current filter pipeline. */
 +/* Filter #0 is the one closest to the format, -1 is a synonym for the
 + * last filter, which is always the pseudo-filter that wraps the
 + * client callbacks. */
 +__LA_DECL int		 archive_filter_count(struct archive *);
 +__LA_DECL __LA_INT64_T	 archive_filter_bytes(struct archive *, int);
 +__LA_DECL int		 archive_filter_code(struct archive *, int);
 +__LA_DECL const char *	 archive_filter_name(struct archive *, int);
 +
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +/* These don't properly handle multiple filters, so are deprecated and
 + * will eventually be removed. */
 +/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */
- __LA_DECL __LA_INT64_T	 archive_position_compressed(struct archive *);
++__LA_DECL __LA_INT64_T	 archive_position_compressed(struct archive *)
++				__LA_DEPRECATED;
 +/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */
- __LA_DECL __LA_INT64_T	 archive_position_uncompressed(struct archive *);
++__LA_DECL __LA_INT64_T	 archive_position_uncompressed(struct archive *)
++				__LA_DEPRECATED;
 +/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
- __LA_DECL const char	*archive_compression_name(struct archive *);
++__LA_DECL const char	*archive_compression_name(struct archive *)
++				__LA_DEPRECATED;
 +/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */
- __LA_DECL int		 archive_compression(struct archive *);
++__LA_DECL int		 archive_compression(struct archive *)
++				__LA_DEPRECATED;
 +#endif
 +
 +__LA_DECL int		 archive_errno(struct archive *);
 +__LA_DECL const char	*archive_error_string(struct archive *);
 +__LA_DECL const char	*archive_format_name(struct archive *);
 +__LA_DECL int		 archive_format(struct archive *);
 +__LA_DECL void		 archive_clear_error(struct archive *);
 +__LA_DECL void		 archive_set_error(struct archive *, int _err,
 +			    const char *fmt, ...) __LA_PRINTF(3, 4);
 +__LA_DECL void		 archive_copy_error(struct archive *dest,
 +			    struct archive *src);
 +__LA_DECL int		 archive_file_count(struct archive *);
 +
++/*
++ * ARCHIVE_MATCH API
++ */
++__LA_DECL struct archive *archive_match_new(void);
++__LA_DECL int	archive_match_free(struct archive *);
++
++/*
++ * Test if archive_entry is excluded.
++ * This is a convenience function. This is the same as calling all
++ * archive_match_path_excluded, archive_match_time_excluded
++ * and archive_match_owner_excluded.
++ */
++__LA_DECL int	archive_match_excluded(struct archive *,
++		    struct archive_entry *);
++
++/*
++ * Test if pathname is excluded. The conditions are set by following functions.
++ */
++__LA_DECL int	archive_match_path_excluded(struct archive *,
++		    struct archive_entry *);
++/* Add exclusion pathname pattern. */
++__LA_DECL int	archive_match_exclude_pattern(struct archive *, const char *);
++__LA_DECL int	archive_match_exclude_pattern_w(struct archive *,
++		    const wchar_t *);
++/* Add exclusion pathname pattern from file. */
++__LA_DECL int	archive_match_exclude_pattern_from_file(struct archive *,
++		    const char *, int _nullSeparator);
++__LA_DECL int	archive_match_exclude_pattern_from_file_w(struct archive *,
++		    const wchar_t *, int _nullSeparator);
++/* Add inclusion pathname pattern. */
++__LA_DECL int	archive_match_include_pattern(struct archive *, const char *);
++__LA_DECL int	archive_match_include_pattern_w(struct archive *,
++		    const wchar_t *);
++/* Add inclusion pathname pattern from file. */
++__LA_DECL int	archive_match_include_pattern_from_file(struct archive *,
++		    const char *, int _nullSeparator);
++__LA_DECL int	archive_match_include_pattern_from_file_w(struct archive *,
++		    const wchar_t *, int _nullSeparator);
++/*
++ * How to get statistic information for inclusion patterns.
++ */
++/* Return the amount number of unmatched inclusion patterns. */
++__LA_DECL int	archive_match_path_unmatched_inclusions(struct archive *);
++/* Return the pattern of unmatched inclusion with ARCHIVE_OK.
++ * Return ARCHIVE_EOF if there is no inclusion pattern. */
++__LA_DECL int	archive_match_path_unmatched_inclusions_next(
++		    struct archive *, const char **);
++__LA_DECL int	archive_match_path_unmatched_inclusions_next_w(
++		    struct archive *, const wchar_t **);
++
++/*
++ * Test if a file is excluded by its time stamp.
++ * The conditions are set by following functions.
++ */
++__LA_DECL int	archive_match_time_excluded(struct archive *,
++		    struct archive_entry *);
++
++/*
++ * Flags to tell a matching type of time stamps. These are used for
++ * following functinos.
++ */
++/* Time flag: mtime to be tested. */
++#define ARCHIVE_MATCH_MTIME	(0x0100)
++/* Time flag: ctime to be tested. */
++#define ARCHIVE_MATCH_CTIME	(0x0200)
++/* Comparison flag: Match the time if it is newer than. */
++#define ARCHIVE_MATCH_NEWER	(0x0001)
++/* Comparison flag: Match the time if it is older than. */
++#define ARCHIVE_MATCH_OLDER	(0x0002)
++/* Comparison flag: Match the time if it is equal to. */
++#define ARCHIVE_MATCH_EQUAL	(0x0010)
++/* Set inclusion time. */
++__LA_DECL int	archive_match_include_time(struct archive *, int _flag,
++		    time_t _sec, long _nsec);
++/* Set inclusion time by a date string. */
++__LA_DECL int	archive_match_include_date(struct archive *, int _flag,
++		    const char *_datestr);
++__LA_DECL int	archive_match_include_date_w(struct archive *, int _flag,
++		    const wchar_t *_datestr);
++/* Set inclusion time by a particluar file. */
++__LA_DECL int	archive_match_include_file_time(struct archive *,
++		    int _flag, const char *_pathname);
++__LA_DECL int	archive_match_include_file_time_w(struct archive *,
++		    int _flag, const wchar_t *_pathname);
++/* Add exclusion entry. */
++__LA_DECL int	archive_match_exclude_entry(struct archive *,
++		    int _flag, struct archive_entry *);
++
++/*
++ * Test if a file is excluded by its uid ,gid, uname or gname.
++ * The conditions are set by following functions.
++ */
++__LA_DECL int	archive_match_owner_excluded(struct archive *,
++		    struct archive_entry *);
++/* Add inclusion uid, gid, uname and gname. */
++__LA_DECL int	archive_match_include_uid(struct archive *, __LA_INT64_T);
++__LA_DECL int	archive_match_include_gid(struct archive *, __LA_INT64_T);
++__LA_DECL int	archive_match_include_uname(struct archive *, const char *);
++__LA_DECL int	archive_match_include_uname_w(struct archive *,
++		    const wchar_t *);
++__LA_DECL int	archive_match_include_gname(struct archive *, const char *);
++__LA_DECL int	archive_match_include_gname_w(struct archive *,
++		    const wchar_t *);
++
 +#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 */
diff --cc Utilities/cmlibarchive/libarchive/archive_cmdline.c
index 0000000,7d3bac5..7d3bac5
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_cmdline.c
+++ b/Utilities/cmlibarchive/libarchive/archive_cmdline.c
diff --cc Utilities/cmlibarchive/libarchive/archive_endian.h
index 3c039f7,0000000..1c48563
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_endian.h
+++ b/Utilities/cmlibarchive/libarchive/archive_endian.h
@@@ -1,196 -1,0 +1,196 @@@
 +/*-
 + * Copyright (c) 2002 Thomas Moestl <tmm at 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)
 + * - IBM VisualAge 6 (XL v6)
 + * - Sun WorkShop C (SunPro) before 5.9
 + */
 +#if defined(__WATCOMC__) || defined(__sgi) || defined(__hpux) || defined(__BORLANDC__)
 +#define	inline
 +#elif defined(__IBMC__) && __IBMC__ < 700
 +#define	inline
 +#elif defined(__SUNPRO_C) && __SUNPRO_C < 0x590
 +#define inline
 +#elif defined(_MSC_VER) || defined(__osf__)
 +#define inline __inline
 +#endif
 +
 +/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
 +
 +static inline uint16_t
 +archive_be16dec(const void *pp)
 +{
 +	unsigned char const *p = (unsigned char const *)pp;
 +
 +	/* Store into unsigned temporaries before left shifting, to avoid
 +	promotion to signed int and then left shifting into the sign bit,
 +	which is undefined behaviour. */
 +	unsigned int p1 = p[1];
 +	unsigned int p0 = p[0];
 +
 +	return ((p0 << 8) | p1);
 +}
 +
 +static inline uint32_t
 +archive_be32dec(const void *pp)
 +{
 +	unsigned char const *p = (unsigned char const *)pp;
 +
 +	/* Store into unsigned temporaries before left shifting, to avoid
 +	promotion to signed int and then left shifting into the sign bit,
 +	which is undefined behaviour. */
 +	unsigned int p3 = p[3];
 +	unsigned int p2 = p[2];
 +	unsigned int p1 = p[1];
 +	unsigned int p0 = p[0];
 +
 +	return ((p0 << 24) | (p1 << 16) | (p2 << 8) | p3);
 +}
 +
 +static inline uint64_t
 +archive_be64dec(const void *pp)
 +{
 +	unsigned char const *p = (unsigned char const *)pp;
 +
 +	return (((uint64_t)archive_be32dec(p) << 32) | archive_be32dec(p + 4));
 +}
 +
 +static inline uint16_t
 +archive_le16dec(const void *pp)
 +{
 +	unsigned char const *p = (unsigned char const *)pp;
 +
 +	/* Store into unsigned temporaries before left shifting, to avoid
 +	promotion to signed int and then left shifting into the sign bit,
 +	which is undefined behaviour. */
 +	unsigned int p1 = p[1];
 +	unsigned int p0 = p[0];
 +
 +	return ((p1 << 8) | p0);
 +}
 +
 +static inline uint32_t
 +archive_le32dec(const void *pp)
 +{
 +	unsigned char const *p = (unsigned char const *)pp;
 +
 +	/* Store into unsigned temporaries before left shifting, to avoid
 +	promotion to signed int and then left shifting into the sign bit,
 +	which is undefined behaviour. */
 +	unsigned int p3 = p[3];
 +	unsigned int p2 = p[2];
 +	unsigned int p1 = p[1];
 +	unsigned int p0 = p[0];
 +
 +	return ((p3 << 24) | (p2 << 16) | (p1 << 8) | p0);
 +}
 +
 +static inline uint64_t
 +archive_le64dec(const void *pp)
 +{
 +	unsigned char const *p = (unsigned char const *)pp;
 +
 +	return (((uint64_t)archive_le32dec(p + 4) << 32) | archive_le32dec(p));
 +}
 +
 +static inline void
 +archive_be16enc(void *pp, uint16_t u)
 +{
 +	unsigned char *p = (unsigned char *)pp;
 +
 +	p[0] = (u >> 8) & 0xff;
 +	p[1] = u & 0xff;
 +}
 +
 +static inline void
 +archive_be32enc(void *pp, uint32_t u)
 +{
 +	unsigned char *p = (unsigned char *)pp;
 +
 +	p[0] = (u >> 24) & 0xff;
 +	p[1] = (u >> 16) & 0xff;
 +	p[2] = (u >> 8) & 0xff;
 +	p[3] = u & 0xff;
 +}
 +
 +static inline void
 +archive_be64enc(void *pp, uint64_t u)
 +{
 +	unsigned char *p = (unsigned char *)pp;
 +
- 	archive_be32enc(p, u >> 32);
- 	archive_be32enc(p + 4, u & 0xffffffff);
++	archive_be32enc(p, (uint32_t)(u >> 32));
++	archive_be32enc(p + 4, (uint32_t)(u & 0xffffffff));
 +}
 +
 +static inline void
 +archive_le16enc(void *pp, uint16_t u)
 +{
 +	unsigned char *p = (unsigned char *)pp;
 +
 +	p[0] = u & 0xff;
 +	p[1] = (u >> 8) & 0xff;
 +}
 +
 +static inline void
 +archive_le32enc(void *pp, uint32_t u)
 +{
 +	unsigned char *p = (unsigned char *)pp;
 +
 +	p[0] = u & 0xff;
 +	p[1] = (u >> 8) & 0xff;
 +	p[2] = (u >> 16) & 0xff;
 +	p[3] = (u >> 24) & 0xff;
 +}
 +
 +static inline void
 +archive_le64enc(void *pp, uint64_t u)
 +{
 +	unsigned char *p = (unsigned char *)pp;
 +
- 	archive_le32enc(p, u & 0xffffffff);
- 	archive_le32enc(p + 4, u >> 32);
++	archive_le32enc(p, (uint32_t)(u & 0xffffffff));
++	archive_le32enc(p + 4, (uint32_t)(u >> 32));
 +}
 +
 +#endif
diff --cc Utilities/cmlibarchive/libarchive/archive_entry.h
index 9c44e25,0000000..85ea885
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry.h
+++ b/Utilities/cmlibarchive/libarchive/archive_entry.h
@@@ -1,620 -1,0 +1,615 @@@
 +/*-
 + * 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 3000002
++#define	ARCHIVE_VERSION_NUMBER 3001002
 +
 +/*
 + * 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' */
++/* Get a suitable 64-bit integer type. */
 +#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
++# define	__LA_INT64_T	__int64
 +#else
 +#include <unistd.h>
 +# if defined(_SCO_DS) || defined(__osf__)
 +#  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
- 
++/* Get a suitable definition for mode_t */
++#if ARCHIVE_VERSION_NUMBER >= 3999000
++/* Switch to plain 'int' for libarchive 4.0.  It's less broken than 'mode_t' */
++# define	__LA_MODE_T	int
++#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__)
++# define	__LA_MODE_T	unsigned short
++#else
++# define	__LA_MODE_T	mode_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 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.
 + */
++/*
++ * In libarchive 4.0, we can drop the casts here.
++ * They're needed to work around Borland C's broken mode_t.
++ */
 +#define AE_IFMT		((__LA_MODE_T)0170000)
 +#define AE_IFREG	((__LA_MODE_T)0100000)
 +#define AE_IFLNK	((__LA_MODE_T)0120000)
 +#define AE_IFSOCK	((__LA_MODE_T)0140000)
 +#define AE_IFCHR	((__LA_MODE_T)0020000)
 +#define AE_IFBLK	((__LA_MODE_T)0060000)
 +#define AE_IFDIR	((__LA_MODE_T)0040000)
 +#define AE_IFIFO	((__LA_MODE_T)0010000)
 +
 +/*
 + * 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.
++ * TODO: On Linux and other LFS systems, provide both stat32 and
++ * stat64 versions of these functions and all of the macro glue so
++ * that archive_entry_stat is magically defined to
++ * archive_entry_stat32 or archive_entry_stat64 as appropriate.
 + */
 +__LA_DECL const struct stat	*archive_entry_stat(struct archive_entry *);
 +__LA_DECL void	archive_entry_copy_stat(struct archive_entry *, const struct stat *);
 +
 +/*
 + * Storage for Mac OS-specific AppleDouble metadata information.
 + * Apple-format tar files store a separate binary blob containing
 + * encoded metadata with ACL, extended attributes, etc.
 + * This provides a place to store that blob.
 + */
 +
 +__LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *);
 +__LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t);
 +
 +/*
 + * 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 */
diff --cc Utilities/cmlibarchive/libarchive/archive_getdate.c
index 0000000,f8b5a28..f8b5a28
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_getdate.c
+++ b/Utilities/cmlibarchive/libarchive/archive_getdate.c
diff --cc Utilities/cmlibarchive/libarchive/archive_match.c
index 0000000,6b6be9c..6b6be9c
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_match.c
+++ b/Utilities/cmlibarchive/libarchive/archive_match.c
diff --cc Utilities/cmlibarchive/libarchive/archive_options.c
index 79b4ffb,0000000..220ebd4
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_options.c
+++ b/Utilities/cmlibarchive/libarchive/archive_options.c
@@@ -1,164 -1,0 +1,211 @@@
 +/*-
 + * 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;
++	int r;
 +
 +	archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
 +
 +	mp = m != NULL && m[0] != '\0' ? m : NULL;
 +	op = o != NULL && o[0] != '\0' ? o : NULL;
 +	vp = v != NULL && v[0] != '\0' ? v : NULL;
 +
 +	if (op == NULL && vp == NULL)
 +		return (ARCHIVE_OK);
- 	if (op == NULL)
++	if (op == NULL) {
++		archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");
 +		return (ARCHIVE_FAILED);
++	}
 +
- 	return use_option(a, mp, op, vp);
++	r = use_option(a, mp, op, vp);
++	if (r == ARCHIVE_WARN - 1) {
++		archive_set_error(a, ARCHIVE_ERRNO_MISC,
++		    "Unknown module name: `%s'", mp);
++		return (ARCHIVE_FAILED);
++	}
++	if (r == ARCHIVE_WARN) {
++		archive_set_error(a, ARCHIVE_ERRNO_MISC,
++		    "Undefined option: `%s%s%s%s%s%s'",
++		    vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:"");
++		return (ARCHIVE_FAILED);
++	}
++	return (r);
 +}
 +
 +int
 +_archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v,
 +    option_handler use_format_option, option_handler use_filter_option)
 +{
 +	int r1, r2;
 +
 +	if (o == NULL && v == NULL)
 +		return (ARCHIVE_OK);
 +	if (o == NULL)
 +		return (ARCHIVE_FAILED);
 +
 +	r1 = use_format_option(a, m, o, v);
 +	if (r1 == ARCHIVE_FATAL)
 +		return (ARCHIVE_FATAL);
 +
 +	r2 = use_filter_option(a, m, o, v);
 +	if (r2 == ARCHIVE_FATAL)
 +		return (ARCHIVE_FATAL);
 +
++	if (r2 == ARCHIVE_WARN - 1)
++		return r1;
 +	return r1 > r2 ? r1 : r2;
 +}
 +
 +int
 +_archive_set_options(struct archive *a, const char *options,
 +    int magic, const char *fn, option_handler use_option)
 +{
- 	int allok = 1, anyok = 0, r;
++	int allok = 1, anyok = 0, ignore_mod_err = 0, r;
 +	char *data;
 +	const char *s, *mod, *opt, *val;
 +
 +	archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
 +
 +	if (options == NULL || options[0] == '\0')
 +		return ARCHIVE_OK;
 +
 +	data = (char *)malloc(strlen(options) + 1);
 +	strcpy(data, options);
 +	s = (const char *)data;
 +
 +	do {
 +		mod = opt = val = NULL;
 +
 +		parse_option(&s, &mod, &opt, &val);
++		if (mod == NULL && opt != NULL &&
++		    strcmp("__ignore_wrong_module_name__", opt) == 0) {
++			/* Ignore module name error */
++			if (val != NULL) {
++				ignore_mod_err = 1;
++				anyok = 1;
++			}
++			continue;
++		}
 +
 +		r = use_option(a, mod, opt, val);
 +		if (r == ARCHIVE_FATAL) {
 +			free(data);
 +			return (ARCHIVE_FATAL);
 +		}
++		if (r == ARCHIVE_FAILED && mod != NULL) {
++			free(data);
++			return (ARCHIVE_FAILED);
++		}
++		if (r == ARCHIVE_WARN - 1) {
++			if (ignore_mod_err)
++				continue;
++			/* The module name is wrong. */
++			archive_set_error(a, ARCHIVE_ERRNO_MISC,
++			    "Unknown module name: `%s'", mod);
++			free(data);
++			return (ARCHIVE_FAILED);
++		}
++		if (r == ARCHIVE_WARN) {
++			/* The option name is wrong. No-one used this. */
++			archive_set_error(a, ARCHIVE_ERRNO_MISC,
++			    "Undefined option: `%s%s%s'",
++			    mod?mod:"", mod?":":"", opt);
++			free(data);
++			return (ARCHIVE_FAILED);
++		}
 +		if (r == ARCHIVE_OK)
 +			anyok = 1;
 +		else
 +			allok = 0;
 +	} while (s != NULL);
 +
 +	free(data);
 +	return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED;
 +}
 +
 +static const char *
 +parse_option(const char **s, const char **m, const char **o, const char **v)
 +{
 +	const char *end, *mod, *opt, *val;
 +	char *p;
 +
 +	end = NULL;
 +	mod = NULL;
 +	opt = *s;
 +	val = "1";
 +
 +	p = strchr(opt, ',');
 +
 +	if (p != NULL) {
 +		*p = '\0';
 +		end = ((const char *)p) + 1;
 +	}
 +
 +	if (0 == strlen(opt)) {
 +		*s = end;
 +		*m = NULL;
 +		*o = NULL;
 +		*v = NULL;
 +		return end;
 +	}
 +
 +	p = strchr(opt, ':');
 +	if (p != NULL) {
 +		*p = '\0';
 +		mod = opt;
 +		opt = ++p;
 +	}
 +
 +	p = strchr(opt, '=');
 +	if (p != NULL) {
 +		*p = '\0';
 +		val = ++p;
 +	} else if (opt[0] == '!') {
 +		++opt;
 +		val = NULL;
 +	}
 +
 +	*s = end;
 +	*m = mod;
 +	*o = opt;
 +	*v = val;
 +
 +	return end;
 +}
 +
diff --cc Utilities/cmlibarchive/libarchive/archive_pathmatch.c
index 0000000,505252a..505252a
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_pathmatch.c
+++ b/Utilities/cmlibarchive/libarchive/archive_pathmatch.c
diff --cc Utilities/cmlibarchive/libarchive/archive_read.c
index baf9dc4,0000000..796d37d
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read.c
@@@ -1,1342 -1,0 +1,1640 @@@
 +/*-
 + * Copyright (c) 2003-2011 Tim Kientzle
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +/*
 + * This file contains the "essential" portions of the read API, that
 + * is, stuff that will probably always be used by any client that
 + * actually needs to read an archive.  Optional pieces have been, as
 + * far as possible, separated out into separate files to avoid
 + * needlessly bloating statically-linked clients.
 + */
 +
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:23Z kientzle $");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#include <stdio.h>
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#ifdef HAVE_UNISTD_H
 +#include <unistd.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_entry.h"
 +#include "archive_private.h"
 +#include "archive_read_private.h"
 +
 +#define minimum(a, b) (a < b ? a : b)
 +
 +static int	choose_filters(struct archive_read *);
 +static int	choose_format(struct archive_read *);
- static void	free_filters(struct archive_read *);
- static int	close_filters(struct archive_read *);
 +static struct archive_vtable *archive_read_vtable(void);
 +static int64_t	_archive_filter_bytes(struct archive *, int);
 +static int	_archive_filter_code(struct archive *, int);
 +static const char *_archive_filter_name(struct archive *, int);
 +static int  _archive_filter_count(struct archive *);
 +static int	_archive_read_close(struct archive *);
 +static int	_archive_read_data_block(struct archive *,
 +		    const void **, size_t *, int64_t *);
 +static int	_archive_read_free(struct archive *);
 +static int	_archive_read_next_header(struct archive *,
 +		    struct archive_entry **);
 +static int	_archive_read_next_header2(struct archive *,
 +		    struct archive_entry *);
 +static int64_t  advance_file_pointer(struct archive_read_filter *, int64_t);
 +
 +static struct archive_vtable *
 +archive_read_vtable(void)
 +{
 +	static struct archive_vtable av;
 +	static int inited = 0;
 +
 +	if (!inited) {
 +		av.archive_filter_bytes = _archive_filter_bytes;
 +		av.archive_filter_code = _archive_filter_code;
 +		av.archive_filter_name = _archive_filter_name;
 +		av.archive_filter_count = _archive_filter_count;
 +		av.archive_read_data_block = _archive_read_data_block;
 +		av.archive_read_next_header = _archive_read_next_header;
 +		av.archive_read_next_header2 = _archive_read_next_header2;
 +		av.archive_free = _archive_read_free;
 +		av.archive_close = _archive_read_close;
 +		inited = 1;
 +	}
 +	return (&av);
 +}
 +
 +/*
 + * Allocate, initialize and return a struct archive object.
 + */
 +struct archive *
 +archive_read_new(void)
 +{
 +	struct archive_read *a;
 +
 +	a = (struct archive_read *)malloc(sizeof(*a));
 +	if (a == NULL)
 +		return (NULL);
 +	memset(a, 0, sizeof(*a));
 +	a->archive.magic = ARCHIVE_READ_MAGIC;
 +
 +	a->archive.state = ARCHIVE_STATE_NEW;
 +	a->entry = archive_entry_new2(&a->archive);
 +	a->archive.vtable = archive_read_vtable();
 +
 +	return (&a->archive);
 +}
 +
 +/*
 + * Record the do-not-extract-to file. This belongs in archive_read_extract.c.
 + */
 +void
 +archive_read_extract_set_skip_file(struct archive *_a, int64_t d, int64_t i)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +
 +	if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +		ARCHIVE_STATE_ANY, "archive_read_extract_set_skip_file"))
 +		return;
 +	a->skip_file_set = 1;
 +	a->skip_file_dev = d;
 +	a->skip_file_ino = i;
 +}
 +
 +/*
 + * Open the archive
 + */
 +int
 +archive_read_open(struct archive *a, void *client_data,
 +    archive_open_callback *client_opener, archive_read_callback *client_reader,
 +    archive_close_callback *client_closer)
 +{
 +	/* Old archive_read_open() is just a thin shell around
 +	 * archive_read_open1. */
 +	archive_read_set_open_callback(a, client_opener);
 +	archive_read_set_read_callback(a, client_reader);
 +	archive_read_set_close_callback(a, client_closer);
 +	archive_read_set_callback_data(a, client_data);
 +	return archive_read_open1(a);
 +}
 +
 +
 +int
 +archive_read_open2(struct archive *a, void *client_data,
 +    archive_open_callback *client_opener,
 +    archive_read_callback *client_reader,
 +    archive_skip_callback *client_skipper,
 +    archive_close_callback *client_closer)
 +{
 +	/* Old archive_read_open2() is just a thin shell around
 +	 * archive_read_open1. */
 +	archive_read_set_callback_data(a, client_data);
 +	archive_read_set_open_callback(a, client_opener);
 +	archive_read_set_read_callback(a, client_reader);
 +	archive_read_set_skip_callback(a, client_skipper);
 +	archive_read_set_close_callback(a, client_closer);
 +	return archive_read_open1(a);
 +}
 +
 +static ssize_t
 +client_read_proxy(struct archive_read_filter *self, const void **buff)
 +{
 +	ssize_t r;
 +	r = (self->archive->client.reader)(&self->archive->archive,
 +	    self->data, buff);
 +	return (r);
 +}
 +
 +static int64_t
 +client_skip_proxy(struct archive_read_filter *self, int64_t request)
 +{
 +	if (request < 0)
 +		__archive_errx(1, "Negative skip requested.");
 +	if (request == 0)
 +		return 0;
 +
 +	if (self->archive->client.skipper != NULL) {
 +		/* Seek requests over 1GiB are broken down into
 +		 * multiple seeks.  This avoids overflows when the
 +		 * requests get passed through 32-bit arguments. */
 +		int64_t skip_limit = (int64_t)1 << 30;
 +		int64_t total = 0;
 +		for (;;) {
 +			int64_t get, ask = request;
 +			if (ask > skip_limit)
 +				ask = skip_limit;
- 			get = (self->archive->client.skipper)(&self->archive->archive,
- 			    self->data, ask);
++			get = (self->archive->client.skipper)
++				(&self->archive->archive, self->data, ask);
 +			if (get == 0)
 +				return (total);
 +			request -= get;
 +			total += get;
 +		}
- 		return total;
 +	} else if (self->archive->client.seeker != NULL
 +		&& request > 64 * 1024) {
 +		/* If the client provided a seeker but not a skipper,
 +		 * we can use the seeker to skip forward.
 +		 *
 +		 * Note: This isn't always a good idea.  The client
 +		 * skipper is allowed to skip by less than requested
 +		 * if it needs to maintain block alignment.  The
 +		 * seeker is not allowed to play such games, so using
 +		 * the seeker here may be a performance loss compared
 +		 * to just reading and discarding.  That's why we
 +		 * only do this for skips of over 64k.
 +		 */
 +		int64_t before = self->position;
- 		int64_t after = (self->archive->client.seeker)(&self->archive->archive,
- 		    self->data, request, SEEK_CUR);
++		int64_t after = (self->archive->client.seeker)
++		    (&self->archive->archive, self->data, request, SEEK_CUR);
 +		if (after != before + request)
 +			return ARCHIVE_FATAL;
 +		return after - before;
 +	}
 +	return 0;
 +}
 +
 +static int64_t
 +client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)
 +{
 +	/* DO NOT use the skipper here!  If we transparently handled
 +	 * forward seek here by using the skipper, that will break
 +	 * other libarchive code that assumes a successful forward
 +	 * seek means it can also seek backwards.
 +	 */
 +	if (self->archive->client.seeker == NULL)
 +		return (ARCHIVE_FAILED);
 +	return (self->archive->client.seeker)(&self->archive->archive,
 +	    self->data, offset, whence);
 +}
 +
 +static int
 +client_close_proxy(struct archive_read_filter *self)
 +{
- 	int r = ARCHIVE_OK;
++	int r = ARCHIVE_OK, r2;
++	unsigned int i;
++
++	if (self->archive->client.closer == NULL)
++		return (r);
++	for (i = 0; i < self->archive->client.nodes; i++)
++	{
++		r2 = (self->archive->client.closer)
++			((struct archive *)self->archive,
++				self->archive->client.dataset[i].data);
++		if (r > r2)
++			r = r2;
++	}
++	return (r);
++}
 +
- 	if (self->archive->client.closer != NULL)
- 		r = (self->archive->client.closer)((struct archive *)self->archive,
- 		    self->data);
++static int
++client_open_proxy(struct archive_read_filter *self)
++{
++  int r = ARCHIVE_OK;
++	if (self->archive->client.opener != NULL)
++		r = (self->archive->client.opener)(
++		    (struct archive *)self->archive, self->data);
 +	return (r);
 +}
 +
++static int
++client_switch_proxy(struct archive_read_filter *self, unsigned int iindex)
++{
++  int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK;
++	void *data2 = NULL;
++
++	/* Don't do anything if already in the specified data node */
++	if (self->archive->client.cursor == iindex)
++		return (ARCHIVE_OK);
++
++	self->archive->client.cursor = iindex;
++	data2 = self->archive->client.dataset[self->archive->client.cursor].data;
++	if (self->archive->client.switcher != NULL)
++	{
++		r1 = r2 = (self->archive->client.switcher)
++			((struct archive *)self->archive, self->data, data2);
++		self->data = data2;
++	}
++	else
++	{
++		/* Attempt to call close and open instead */
++		if (self->archive->client.closer != NULL)
++			r1 = (self->archive->client.closer)
++				((struct archive *)self->archive, self->data);
++		self->data = data2;
++		if (self->archive->client.opener != NULL)
++			r2 = (self->archive->client.opener)
++				((struct archive *)self->archive, self->data);
++	}
++	return (r1 < r2) ? r1 : r2;
++}
++
 +int
 +archive_read_set_open_callback(struct archive *_a,
 +    archive_open_callback *client_opener)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_open_callback");
 +	a->client.opener = client_opener;
 +	return ARCHIVE_OK;
 +}
 +
 +int
 +archive_read_set_read_callback(struct archive *_a,
 +    archive_read_callback *client_reader)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_read_callback");
 +	a->client.reader = client_reader;
 +	return ARCHIVE_OK;
 +}
 +
 +int
 +archive_read_set_skip_callback(struct archive *_a,
 +    archive_skip_callback *client_skipper)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_skip_callback");
 +	a->client.skipper = client_skipper;
 +	return ARCHIVE_OK;
 +}
 +
 +int
 +archive_read_set_seek_callback(struct archive *_a,
 +    archive_seek_callback *client_seeker)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_seek_callback");
 +	a->client.seeker = client_seeker;
 +	return ARCHIVE_OK;
 +}
 +
 +int
 +archive_read_set_close_callback(struct archive *_a,
 +    archive_close_callback *client_closer)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_set_close_callback");
 +	a->client.closer = client_closer;
 +	return ARCHIVE_OK;
 +}
 +
 +int
++archive_read_set_switch_callback(struct archive *_a,
++    archive_switch_callback *client_switcher)
++{
++	struct archive_read *a = (struct archive_read *)_a;
++	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
++	    "archive_read_set_switch_callback");
++	a->client.switcher = client_switcher;
++	return ARCHIVE_OK;
++}
++
++int
 +archive_read_set_callback_data(struct archive *_a, void *client_data)
 +{
++	return archive_read_set_callback_data2(_a, client_data, 0);
++}
++
++int
++archive_read_set_callback_data2(struct archive *_a, void *client_data,
++    unsigned int iindex)
++{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
- 	    "archive_read_set_callback_data");
- 	a->client.data = client_data;
++	    "archive_read_set_callback_data2");
++
++	if (a->client.nodes == 0)
++	{
++		a->client.dataset = (struct archive_read_data_node *)
++		    calloc(1, sizeof(*a->client.dataset));
++		if (a->client.dataset == NULL)
++		{
++			archive_set_error(&a->archive, ENOMEM,
++				"No memory.");
++			return ARCHIVE_FATAL;
++		}
++		a->client.nodes = 1;
++	}
++
++	if (iindex > a->client.nodes - 1)
++	{
++		archive_set_error(&a->archive, EINVAL,
++			"Invalid index specified.");
++		return ARCHIVE_FATAL;
++	}
++	a->client.dataset[iindex].data = client_data;
++	a->client.dataset[iindex].begin_position = -1;
++	a->client.dataset[iindex].total_size = -1;
++	return ARCHIVE_OK;
++}
++
++int
++archive_read_add_callback_data(struct archive *_a, void *client_data,
++    unsigned int iindex)
++{
++	struct archive_read *a = (struct archive_read *)_a;
++	void *p;
++	unsigned int i;
++
++	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
++	    "archive_read_add_callback_data");
++	if (iindex > a->client.nodes) {
++		archive_set_error(&a->archive, EINVAL,
++			"Invalid index specified.");
++		return ARCHIVE_FATAL;
++	}
++	p = realloc(a->client.dataset, sizeof(*a->client.dataset)
++		* (++(a->client.nodes)));
++	if (p == NULL) {
++		archive_set_error(&a->archive, ENOMEM,
++			"No memory.");
++		return ARCHIVE_FATAL;
++	}
++	a->client.dataset = (struct archive_read_data_node *)p;
++	for (i = a->client.nodes - 1; i > iindex && i > 0; i--) {
++		a->client.dataset[i].data = a->client.dataset[i-1].data;
++		a->client.dataset[i].begin_position = -1;
++		a->client.dataset[i].total_size = -1;
++	}
++	a->client.dataset[iindex].data = client_data;
++	a->client.dataset[iindex].begin_position = -1;
++	a->client.dataset[iindex].total_size = -1;
 +	return ARCHIVE_OK;
 +}
 +
 +int
++archive_read_append_callback_data(struct archive *_a, void *client_data)
++{
++	struct archive_read *a = (struct archive_read *)_a;
++	return archive_read_add_callback_data(_a, client_data, a->client.nodes);
++}
++
++int
++archive_read_prepend_callback_data(struct archive *_a, void *client_data)
++{
++	return archive_read_add_callback_data(_a, client_data, 0);
++}
++
++int
 +archive_read_open1(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
- 	struct archive_read_filter *filter;
++	struct archive_read_filter *filter, *tmp;
 +	int slot, e;
++	unsigned int i;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "archive_read_open");
 +	archive_clear_error(&a->archive);
 +
 +	if (a->client.reader == NULL) {
 +		archive_set_error(&a->archive, EINVAL,
 +		    "No reader function provided to archive_read_open");
 +		a->archive.state = ARCHIVE_STATE_FATAL;
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Open data source. */
 +	if (a->client.opener != NULL) {
- 		e =(a->client.opener)(&a->archive, a->client.data);
++		e = (a->client.opener)(&a->archive, a->client.dataset[0].data);
 +		if (e != 0) {
 +			/* If the open failed, call the closer to clean up. */
- 			if (a->client.closer)
- 				(a->client.closer)(&a->archive, a->client.data);
++			if (a->client.closer) {
++				for (i = 0; i < a->client.nodes; i++)
++					(a->client.closer)(&a->archive,
++					    a->client.dataset[i].data);
++			}
 +			return (e);
 +		}
 +	}
 +
 +	filter = calloc(1, sizeof(*filter));
 +	if (filter == NULL)
 +		return (ARCHIVE_FATAL);
 +	filter->bidder = NULL;
 +	filter->upstream = NULL;
 +	filter->archive = a;
- 	filter->data = a->client.data;
++	filter->data = a->client.dataset[0].data;
++	filter->open = client_open_proxy;
 +	filter->read = client_read_proxy;
 +	filter->skip = client_skip_proxy;
 +	filter->seek = client_seek_proxy;
 +	filter->close = client_close_proxy;
++	filter->sswitch = client_switch_proxy;
 +	filter->name = "none";
- 	filter->code = ARCHIVE_COMPRESSION_NONE;
- 	a->filter = filter;
++	filter->code = ARCHIVE_FILTER_NONE;
 +
- 	/* Build out the input pipeline. */
- 	e = choose_filters(a);
- 	if (e < ARCHIVE_WARN) {
- 		a->archive.state = ARCHIVE_STATE_FATAL;
- 		return (ARCHIVE_FATAL);
++	a->client.dataset[0].begin_position = 0;
++	if (!a->filter || !a->bypass_filter_bidding)
++	{
++		a->filter = filter;
++		/* Build out the input pipeline. */
++		e = choose_filters(a);
++		if (e < ARCHIVE_WARN) {
++			a->archive.state = ARCHIVE_STATE_FATAL;
++			return (ARCHIVE_FATAL);
++		}
++	}
++	else
++	{
++		/* Need to add "NONE" type filter at the end of the filter chain */
++		tmp = a->filter;
++		while (tmp->upstream)
++			tmp = tmp->upstream;
++		tmp->upstream = filter;
 +	}
 +
- 	slot = choose_format(a);
- 	if (slot < 0) {
- 		close_filters(a);
- 		a->archive.state = ARCHIVE_STATE_FATAL;
- 		return (ARCHIVE_FATAL);
++	if (!a->format)
++	{
++		slot = choose_format(a);
++		if (slot < 0) {
++			__archive_read_close_filters(a);
++			a->archive.state = ARCHIVE_STATE_FATAL;
++			return (ARCHIVE_FATAL);
++		}
++		a->format = &(a->formats[slot]);
 +	}
- 	a->format = &(a->formats[slot]);
 +
 +	a->archive.state = ARCHIVE_STATE_HEADER;
++
++	/* Ensure libarchive starts from the first node in a multivolume set */
++	client_switch_proxy(a->filter, 0);
 +	return (e);
 +}
 +
 +/*
 + * Allow each registered stream transform to bid on whether
 + * it wants to handle this stream.  Repeat until we've finished
 + * building the pipeline.
 + */
 +static int
 +choose_filters(struct archive_read *a)
 +{
 +	int number_bidders, i, bid, best_bid;
 +	struct archive_read_filter_bidder *bidder, *best_bidder;
 +	struct archive_read_filter *filter;
 +	ssize_t avail;
 +	int r;
 +
 +	for (;;) {
 +		number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
 +
 +		best_bid = 0;
 +		best_bidder = NULL;
 +
 +		bidder = a->bidders;
 +		for (i = 0; i < number_bidders; i++, bidder++) {
 +			if (bidder->bid != NULL) {
 +				bid = (bidder->bid)(bidder, a->filter);
 +				if (bid > best_bid) {
 +					best_bid = bid;
 +					best_bidder = bidder;
 +				}
 +			}
 +		}
 +
 +		/* If no bidder, we're done. */
 +		if (best_bidder == NULL) {
 +			/* Verify the filter by asking it for some data. */
 +			__archive_read_filter_ahead(a->filter, 1, &avail);
 +			if (avail < 0) {
- 				close_filters(a);
- 				free_filters(a);
++				__archive_read_close_filters(a);
++				__archive_read_free_filters(a);
 +				return (ARCHIVE_FATAL);
 +			}
 +			a->archive.compression_name = a->filter->name;
 +			a->archive.compression_code = a->filter->code;
 +			return (ARCHIVE_OK);
 +		}
 +
 +		filter
 +		    = (struct archive_read_filter *)calloc(1, sizeof(*filter));
 +		if (filter == NULL)
 +			return (ARCHIVE_FATAL);
 +		filter->bidder = best_bidder;
 +		filter->archive = a;
 +		filter->upstream = a->filter;
 +		a->filter = filter;
 +		r = (best_bidder->init)(a->filter);
 +		if (r != ARCHIVE_OK) {
- 			close_filters(a);
- 			free_filters(a);
++			__archive_read_close_filters(a);
++			__archive_read_free_filters(a);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +}
 +
 +/*
 + * Read header of next entry.
 + */
 +static int
 +_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	int r1 = ARCHIVE_OK, r2;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
 +	    "archive_read_next_header");
 +
 +	archive_entry_clear(entry);
 +	archive_clear_error(&a->archive);
 +
 +	/*
 +	 * If client didn't consume entire data, skip any remainder
 +	 * (This is especially important for GNU incremental directories.)
 +	 */
 +	if (a->archive.state == ARCHIVE_STATE_DATA) {
 +		r1 = archive_read_data_skip(&a->archive);
 +		if (r1 == ARCHIVE_EOF)
 +			archive_set_error(&a->archive, EIO,
 +			    "Premature end-of-file.");
 +		if (r1 == ARCHIVE_EOF || r1 == ARCHIVE_FATAL) {
 +			a->archive.state = ARCHIVE_STATE_FATAL;
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	/* Record start-of-header offset in uncompressed stream. */
 +	a->header_position = a->filter->position;
 +
 +	++_a->file_count;
 +	r2 = (a->format->read_header)(a, entry);
 +
 +	/*
 +	 * EOF and FATAL are persistent at this layer.  By
 +	 * modifying the state, we guarantee that future calls to
 +	 * read a header or read data will fail.
 +	 */
 +	switch (r2) {
 +	case ARCHIVE_EOF:
 +		a->archive.state = ARCHIVE_STATE_EOF;
 +		--_a->file_count;/* Revert a file counter. */
 +		break;
 +	case ARCHIVE_OK:
 +		a->archive.state = ARCHIVE_STATE_DATA;
 +		break;
 +	case ARCHIVE_WARN:
 +		a->archive.state = ARCHIVE_STATE_DATA;
 +		break;
 +	case ARCHIVE_RETRY:
 +		break;
 +	case ARCHIVE_FATAL:
 +		a->archive.state = ARCHIVE_STATE_FATAL;
 +		break;
 +	}
 +
 +	a->read_data_output_offset = 0;
 +	a->read_data_remaining = 0;
++	a->read_data_is_posix_read = 0;
++	a->read_data_requested = 0;
++	a->data_start_node = a->client.cursor;
 +	/* EOF always wins; otherwise return the worst error. */
 +	return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1;
 +}
 +
 +int
 +_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
 +{
 +	int ret;
 +	struct archive_read *a = (struct archive_read *)_a;
 +	*entryp = NULL;
 +	ret = _archive_read_next_header2(_a, a->entry);
 +	*entryp = a->entry;
 +	return ret;
 +}
 +
 +/*
 + * Allow each registered format to bid on whether it wants to handle
 + * the next entry.  Return index of winning bidder.
 + */
 +static int
 +choose_format(struct archive_read *a)
 +{
 +	int slots;
 +	int i;
 +	int bid, best_bid;
 +	int best_bid_slot;
 +
 +	slots = sizeof(a->formats) / sizeof(a->formats[0]);
 +	best_bid = -1;
 +	best_bid_slot = -1;
 +
 +	/* Set up a->format for convenience of bidders. */
 +	a->format = &(a->formats[0]);
 +	for (i = 0; i < slots; i++, a->format++) {
 +		if (a->format->bid) {
 +			bid = (a->format->bid)(a, best_bid);
 +			if (bid == ARCHIVE_FATAL)
 +				return (ARCHIVE_FATAL);
 +			if (a->filter->position != 0)
 +				__archive_read_seek(a, 0, SEEK_SET);
 +			if ((bid > best_bid) || (best_bid_slot < 0)) {
 +				best_bid = bid;
 +				best_bid_slot = i;
 +			}
 +		}
 +	}
 +
 +	/*
 +	 * There were no bidders; this is a serious programmer error
 +	 * and demands a quick and definitive abort.
 +	 */
 +	if (best_bid_slot < 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "No formats registered");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * There were bidders, but no non-zero bids; this means we
 +	 * can't support this stream.
 +	 */
 +	if (best_bid < 1) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Unrecognized archive format");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	return (best_bid_slot);
 +}
 +
 +/*
 + * Return the file offset (within the uncompressed data stream) where
 + * the last header started.
 + */
 +int64_t
 +archive_read_header_position(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_ANY, "archive_read_header_position");
 +	return (a->header_position);
 +}
 +
 +/*
 + * Read data from an archive entry, using a read(2)-style interface.
 + * This is a convenience routine that just calls
 + * archive_read_data_block and copies the results into the client
 + * buffer, filling any gaps with zero bytes.  Clients using this
 + * API can be completely ignorant of sparse-file issues; sparse files
 + * will simply be padded with nulls.
 + *
 + * DO NOT intermingle calls to this function and archive_read_data_block
 + * to read a single entry body.
 + */
 +ssize_t
 +archive_read_data(struct archive *_a, void *buff, size_t s)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	char	*dest;
 +	const void *read_buf;
 +	size_t	 bytes_read;
 +	size_t	 len;
 +	int	 r;
 +
 +	bytes_read = 0;
 +	dest = (char *)buff;
 +
 +	while (s > 0) {
 +		if (a->read_data_remaining == 0) {
 +			read_buf = a->read_data_block;
++			a->read_data_is_posix_read = 1;
++			a->read_data_requested = s;
 +			r = _archive_read_data_block(&a->archive, &read_buf,
 +			    &a->read_data_remaining, &a->read_data_offset);
 +			a->read_data_block = read_buf;
 +			if (r == ARCHIVE_EOF)
 +				return (bytes_read);
 +			/*
 +			 * Error codes are all negative, so the status
 +			 * return here cannot be confused with a valid
 +			 * byte count.  (ARCHIVE_OK is zero.)
 +			 */
 +			if (r < ARCHIVE_OK)
 +				return (r);
 +		}
 +
 +		if (a->read_data_offset < a->read_data_output_offset) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Encountered out-of-order sparse blocks");
 +			return (ARCHIVE_RETRY);
 +		}
 +
 +		/* Compute the amount of zero padding needed. */
- 		if (a->read_data_output_offset + s <
++		if (a->read_data_output_offset + (int64_t)s <
 +		    a->read_data_offset) {
 +			len = s;
 +		} else if (a->read_data_output_offset <
 +		    a->read_data_offset) {
- 			len = a->read_data_offset -
- 			    a->read_data_output_offset;
++			len = (size_t)(a->read_data_offset -
++			    a->read_data_output_offset);
 +		} else
 +			len = 0;
 +
 +		/* Add zeroes. */
 +		memset(dest, 0, len);
 +		s -= len;
 +		a->read_data_output_offset += len;
 +		dest += len;
 +		bytes_read += len;
 +
 +		/* Copy data if there is any space left. */
 +		if (s > 0) {
 +			len = a->read_data_remaining;
 +			if (len > s)
 +				len = s;
 +			memcpy(dest, a->read_data_block, len);
 +			s -= len;
 +			a->read_data_block += len;
 +			a->read_data_remaining -= len;
 +			a->read_data_output_offset += len;
 +			a->read_data_offset += len;
 +			dest += len;
 +			bytes_read += len;
 +		}
 +	}
++	a->read_data_is_posix_read = 0;
++	a->read_data_requested = 0;
 +	return (bytes_read);
 +}
 +
 +/*
 + * Skip over all remaining data in this entry.
 + */
 +int
 +archive_read_data_skip(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	int r;
 +	const void *buff;
 +	size_t size;
 +	int64_t offset;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
 +	    "archive_read_data_skip");
 +
 +	if (a->format->read_data_skip != NULL)
 +		r = (a->format->read_data_skip)(a);
 +	else {
 +		while ((r = archive_read_data_block(&a->archive,
 +			    &buff, &size, &offset))
 +		    == ARCHIVE_OK)
 +			;
 +	}
 +
 +	if (r == ARCHIVE_EOF)
 +		r = ARCHIVE_OK;
 +
 +	a->archive.state = ARCHIVE_STATE_HEADER;
 +	return (r);
 +}
 +
++int64_t
++archive_seek_data(struct archive *_a, int64_t offset, int whence)
++{
++	struct archive_read *a = (struct archive_read *)_a;
++	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
++	    "archive_seek_data_block");
++
++	if (a->format->seek_data == NULL) {
++		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
++		    "Internal error: "
++		    "No format_seek_data_block function registered");
++		return (ARCHIVE_FATAL);
++	}
++
++	return (a->format->seek_data)(a, offset, whence);
++}
++
 +/*
 + * Read the next block of entry data from the archive.
 + * This is a zero-copy interface; the client receives a pointer,
 + * size, and file offset of the next available block of data.
 + *
 + * Returns ARCHIVE_OK if the operation is successful, ARCHIVE_EOF if
 + * the end of entry is encountered.
 + */
 +static int
 +_archive_read_data_block(struct archive *_a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
 +	    "archive_read_data_block");
 +
 +	if (a->format->read_data == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
 +		    "Internal error: "
 +		    "No format_read_data_block function registered");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	return (a->format->read_data)(a, buff, size, offset);
 +}
 +
- static int
- close_filters(struct archive_read *a)
++int
++__archive_read_close_filters(struct archive_read *a)
 +{
 +	struct archive_read_filter *f = a->filter;
 +	int r = ARCHIVE_OK;
 +	/* Close each filter in the pipeline. */
 +	while (f != NULL) {
 +		struct archive_read_filter *t = f->upstream;
 +		if (!f->closed && f->close != NULL) {
 +			int r1 = (f->close)(f);
 +			f->closed = 1;
 +			if (r1 < r)
 +				r = r1;
 +		}
 +		free(f->buffer);
 +		f->buffer = NULL;
 +		f = t;
 +	}
 +	return r;
 +}
 +
- static void
- free_filters(struct archive_read *a)
++void
++__archive_read_free_filters(struct archive_read *a)
 +{
 +	while (a->filter != NULL) {
 +		struct archive_read_filter *t = a->filter->upstream;
 +		free(a->filter);
 +		a->filter = t;
 +	}
 +}
 +
 +/*
 + * return the count of # of filters in use
 + */
 +static int
 +_archive_filter_count(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct archive_read_filter *p = a->filter;
 +	int count = 0;
 +	while(p) {
 +		count++;
 +		p = p->upstream;
 +	}
 +	return count;
 +}
 +
 +/*
 + * Close the file and all I/O.
 + */
 +static int
 +_archive_read_close(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
 +
 +	archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close");
 +	if (a->archive.state == ARCHIVE_STATE_CLOSED)
 +		return (ARCHIVE_OK);
 +	archive_clear_error(&a->archive);
 +	a->archive.state = ARCHIVE_STATE_CLOSED;
 +
 +	/* TODO: Clean up the formatters. */
 +
 +	/* Release the filter objects. */
- 	r1 = close_filters(a);
++	r1 = __archive_read_close_filters(a);
 +	if (r1 < r)
 +		r = r1;
 +
 +	return (r);
 +}
 +
 +/*
 + * Release memory and other resources.
 + */
 +static int
 +_archive_read_free(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	int i, n;
 +	int slots;
 +	int r = ARCHIVE_OK;
 +
 +	if (_a == NULL)
 +		return (ARCHIVE_OK);
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free");
 +	if (a->archive.state != ARCHIVE_STATE_CLOSED
 +	    && a->archive.state != ARCHIVE_STATE_FATAL)
 +		r = archive_read_close(&a->archive);
 +
 +	/* Call cleanup functions registered by optional components. */
 +	if (a->cleanup_archive_extract != NULL)
 +		r = (a->cleanup_archive_extract)(a);
 +
 +	/* Cleanup format-specific data. */
 +	slots = sizeof(a->formats) / sizeof(a->formats[0]);
 +	for (i = 0; i < slots; i++) {
 +		a->format = &(a->formats[i]);
 +		if (a->formats[i].cleanup)
 +			(a->formats[i].cleanup)(a);
 +	}
 +
 +	/* Free the filters */
- 	free_filters(a);
++	__archive_read_free_filters(a);
 +
 +	/* Release the bidder objects. */
 +	n = sizeof(a->bidders)/sizeof(a->bidders[0]);
 +	for (i = 0; i < n; i++) {
 +		if (a->bidders[i].free != NULL) {
 +			int r1 = (a->bidders[i].free)(&a->bidders[i]);
 +			if (r1 < r)
 +				r = r1;
 +		}
 +	}
 +
 +	archive_string_free(&a->archive.error_string);
 +	if (a->entry)
 +		archive_entry_free(a->entry);
 +	a->archive.magic = 0;
 +	__archive_clean(&a->archive);
++	free(a->client.dataset);
 +	free(a);
 +	return (r);
 +}
 +
 +static struct archive_read_filter *
 +get_filter(struct archive *_a, int n)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct archive_read_filter *f = a->filter;
- 	/* We use n == -1 for 'the last filter', which is always the client proxy. */
++	/* We use n == -1 for 'the last filter', which is always the
++	 * client proxy. */
 +	if (n == -1 && f != NULL) {
 +		struct archive_read_filter *last = f;
 +		f = f->upstream;
 +		while (f != NULL) {
 +			last = f;
 +			f = f->upstream;
 +		}
 +		return (last);
 +	}
 +	if (n < 0)
 +		return NULL;
 +	while (n > 0 && f != NULL) {
 +		f = f->upstream;
 +		--n;
 +	}
 +	return (f);
 +}
 +
 +static int
 +_archive_filter_code(struct archive *_a, int n)
 +{
 +	struct archive_read_filter *f = get_filter(_a, n);
 +	return f == NULL ? -1 : f->code;
 +}
 +
 +static const char *
 +_archive_filter_name(struct archive *_a, int n)
 +{
 +	struct archive_read_filter *f = get_filter(_a, n);
 +	return f != NULL ? f->name : NULL;
 +}
 +
 +static int64_t
 +_archive_filter_bytes(struct archive *_a, int n)
 +{
 +	struct archive_read_filter *f = get_filter(_a, n);
 +	return f == NULL ? -1 : f->position;
 +}
 +
 +/*
 + * Used internally by read format handlers to register their bid and
 + * initialization functions.
 + */
 +int
 +__archive_read_register_format(struct archive_read *a,
 +    void *format_data,
 +    const char *name,
 +    int (*bid)(struct archive_read *, int),
 +    int (*options)(struct archive_read *, const char *, const char *),
 +    int (*read_header)(struct archive_read *, struct archive_entry *),
 +    int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
 +    int (*read_data_skip)(struct archive_read *),
++    int64_t (*seek_data)(struct archive_read *, int64_t, int),
 +    int (*cleanup)(struct archive_read *))
 +{
 +	int i, number_slots;
 +
 +	archive_check_magic(&a->archive,
 +	    ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +	    "__archive_read_register_format");
 +
 +	number_slots = sizeof(a->formats) / sizeof(a->formats[0]);
 +
 +	for (i = 0; i < number_slots; i++) {
 +		if (a->formats[i].bid == bid)
 +			return (ARCHIVE_WARN); /* We've already installed */
 +		if (a->formats[i].bid == NULL) {
 +			a->formats[i].bid = bid;
 +			a->formats[i].options = options;
 +			a->formats[i].read_header = read_header;
 +			a->formats[i].read_data = read_data;
 +			a->formats[i].read_data_skip = read_data_skip;
++			a->formats[i].seek_data = seek_data;
 +			a->formats[i].cleanup = cleanup;
 +			a->formats[i].data = format_data;
 +			a->formats[i].name = name;
 +			return (ARCHIVE_OK);
 +		}
 +	}
 +
 +	archive_set_error(&a->archive, ENOMEM,
 +	    "Not enough slots for format registration");
 +	return (ARCHIVE_FATAL);
 +}
 +
 +/*
 + * Used internally by decompression routines to register their bid and
 + * initialization functions.
 + */
 +int
 +__archive_read_get_bidder(struct archive_read *a,
 +    struct archive_read_filter_bidder **bidder)
 +{
 +	int i, number_slots;
 +
 +	number_slots = sizeof(a->bidders) / sizeof(a->bidders[0]);
 +
 +	for (i = 0; i < number_slots; i++) {
 +		if (a->bidders[i].bid == NULL) {
 +			memset(a->bidders + i, 0, sizeof(a->bidders[0]));
 +			*bidder = (a->bidders + i);
 +			return (ARCHIVE_OK);
 +		}
 +	}
 +
 +	archive_set_error(&a->archive, ENOMEM,
 +	    "Not enough slots for filter registration");
 +	return (ARCHIVE_FATAL);
 +}
 +
 +/*
 + * The next section implements the peek/consume internal I/O
 + * system used by archive readers.  This system allows simple
 + * read-ahead for consumers while preserving zero-copy operation
 + * most of the time.
 + *
 + * The two key operations:
 + *  * The read-ahead function returns a pointer to a block of data
 + *    that satisfies a minimum request.
 + *  * The consume function advances the file pointer.
 + *
 + * In the ideal case, filters generate blocks of data
 + * and __archive_read_ahead() just returns pointers directly into
 + * those blocks.  Then __archive_read_consume() just bumps those
 + * pointers.  Only if your request would span blocks does the I/O
 + * layer use a copy buffer to provide you with a contiguous block of
 + * data.
 + *
 + * A couple of useful idioms:
 + *  * "I just want some data."  Ask for 1 byte and pay attention to
 + *    the "number of bytes available" from __archive_read_ahead().
 + *    Consume whatever you actually use.
 + *  * "I want to output a large block of data."  As above, ask for 1 byte,
 + *    emit all that's available (up to whatever limit you have), consume
 + *    it all, then repeat until you're done.  This effectively means that
 + *    you're passing along the blocks that came from your provider.
 + *  * "I want to peek ahead by a large amount."  Ask for 4k or so, then
 + *    double and repeat until you get an error or have enough.  Note
 + *    that the I/O layer will likely end up expanding its copy buffer
 + *    to fit your request, so use this technique cautiously.  This
 + *    technique is used, for example, by some of the format tasting
 + *    code that has uncertain look-ahead needs.
 + */
 +
 +/*
 + * Looks ahead in the input stream:
 + *  * If 'avail' pointer is provided, that returns number of bytes available
 + *    in the current buffer, which may be much larger than requested.
 + *  * If end-of-file, *avail gets set to zero.
 + *  * If error, *avail gets error code.
 + *  * If request can be met, returns pointer to data.
 + *  * If minimum request cannot be met, returns NULL.
 + *
 + * Note: If you just want "some data", ask for 1 byte and pay attention
 + * to *avail, which will have the actual amount available.  If you
 + * know exactly how many bytes you need, just ask for that and treat
 + * a NULL return as an error.
 + *
 + * Important:  This does NOT move the file pointer.  See
 + * __archive_read_consume() below.
 + */
 +const void *
 +__archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
 +{
 +	return (__archive_read_filter_ahead(a->filter, min, avail));
 +}
 +
 +const void *
 +__archive_read_filter_ahead(struct archive_read_filter *filter,
 +    size_t min, ssize_t *avail)
 +{
 +	ssize_t bytes_read;
 +	size_t tocopy;
 +
 +	if (filter->fatal) {
 +		if (avail)
 +			*avail = ARCHIVE_FATAL;
 +		return (NULL);
 +	}
 +
 +	/*
 +	 * Keep pulling more data until we can satisfy the request.
 +	 */
 +	for (;;) {
 +
 +		/*
 +		 * If we can satisfy from the copy buffer (and the
 +		 * copy buffer isn't empty), we're done.  In particular,
 +		 * note that min == 0 is a perfectly well-defined
 +		 * request.
 +		 */
 +		if (filter->avail >= min && filter->avail > 0) {
 +			if (avail != NULL)
 +				*avail = filter->avail;
 +			return (filter->next);
 +		}
 +
 +		/*
 +		 * We can satisfy directly from client buffer if everything
 +		 * currently in the copy buffer is still in the client buffer.
 +		 */
 +		if (filter->client_total >= filter->client_avail + filter->avail
 +		    && filter->client_avail + filter->avail >= min) {
 +			/* "Roll back" to client buffer. */
 +			filter->client_avail += filter->avail;
 +			filter->client_next -= filter->avail;
 +			/* Copy buffer is now empty. */
 +			filter->avail = 0;
 +			filter->next = filter->buffer;
 +			/* Return data from client buffer. */
 +			if (avail != NULL)
 +				*avail = filter->client_avail;
 +			return (filter->client_next);
 +		}
 +
 +		/* Move data forward in copy buffer if necessary. */
 +		if (filter->next > filter->buffer &&
 +		    filter->next + min > filter->buffer + filter->buffer_size) {
 +			if (filter->avail > 0)
- 				memmove(filter->buffer, filter->next, filter->avail);
++				memmove(filter->buffer, filter->next,
++				    filter->avail);
 +			filter->next = filter->buffer;
 +		}
 +
 +		/* If we've used up the client data, get more. */
 +		if (filter->client_avail <= 0) {
 +			if (filter->end_of_file) {
 +				if (avail != NULL)
 +					*avail = 0;
 +				return (NULL);
 +			}
 +			bytes_read = (filter->read)(filter,
 +			    &filter->client_buff);
 +			if (bytes_read < 0) {		/* Read error. */
 +				filter->client_total = filter->client_avail = 0;
- 				filter->client_next = filter->client_buff = NULL;
++				filter->client_next =
++				    filter->client_buff = NULL;
 +				filter->fatal = 1;
 +				if (avail != NULL)
 +					*avail = ARCHIVE_FATAL;
 +				return (NULL);
 +			}
- 			if (bytes_read == 0) {	/* Premature end-of-file. */
++			if (bytes_read == 0) {
++				/* Check for another client object first */
++				if (filter->archive->client.cursor !=
++				      filter->archive->client.nodes - 1) {
++					if (client_switch_proxy(filter,
++					    filter->archive->client.cursor + 1)
++					    == ARCHIVE_OK)
++						continue;
++				}
++				/* Premature end-of-file. */
 +				filter->client_total = filter->client_avail = 0;
- 				filter->client_next = filter->client_buff = NULL;
++				filter->client_next =
++				    filter->client_buff = NULL;
 +				filter->end_of_file = 1;
 +				/* Return whatever we do have. */
 +				if (avail != NULL)
 +					*avail = filter->avail;
 +				return (NULL);
 +			}
 +			filter->client_total = bytes_read;
 +			filter->client_avail = filter->client_total;
 +			filter->client_next = filter->client_buff;
- 		}
- 		else
- 		{
++		} else {
 +			/*
 +			 * We can't satisfy the request from the copy
 +			 * buffer or the existing client data, so we
 +			 * need to copy more client data over to the
 +			 * copy buffer.
 +			 */
 +
 +			/* Ensure the buffer is big enough. */
 +			if (min > filter->buffer_size) {
 +				size_t s, t;
 +				char *p;
 +
 +				/* Double the buffer; watch for overflow. */
 +				s = t = filter->buffer_size;
 +				if (s == 0)
 +					s = min;
 +				while (s < min) {
 +					t *= 2;
 +					if (t <= s) { /* Integer overflow! */
 +						archive_set_error(
- 							&filter->archive->archive,
- 							ENOMEM,
- 						    "Unable to allocate copy buffer");
++						    &filter->archive->archive,
++						    ENOMEM,
++						    "Unable to allocate copy"
++						    " buffer");
 +						filter->fatal = 1;
 +						if (avail != NULL)
 +							*avail = ARCHIVE_FATAL;
 +						return (NULL);
 +					}
 +					s = t;
 +				}
 +				/* Now s >= min, so allocate a new buffer. */
 +				p = (char *)malloc(s);
 +				if (p == NULL) {
 +					archive_set_error(
 +						&filter->archive->archive,
 +						ENOMEM,
 +					    "Unable to allocate copy buffer");
 +					filter->fatal = 1;
 +					if (avail != NULL)
 +						*avail = ARCHIVE_FATAL;
 +					return (NULL);
 +				}
 +				/* Move data into newly-enlarged buffer. */
 +				if (filter->avail > 0)
 +					memmove(p, filter->next, filter->avail);
 +				free(filter->buffer);
 +				filter->next = filter->buffer = p;
 +				filter->buffer_size = s;
 +			}
 +
 +			/* We can add client data to copy buffer. */
 +			/* First estimate: copy to fill rest of buffer. */
 +			tocopy = (filter->buffer + filter->buffer_size)
 +			    - (filter->next + filter->avail);
 +			/* Don't waste time buffering more than we need to. */
 +			if (tocopy + filter->avail > min)
 +				tocopy = min - filter->avail;
 +			/* Don't copy more than is available. */
 +			if (tocopy > filter->client_avail)
 +				tocopy = filter->client_avail;
 +
- 			memcpy(filter->next + filter->avail, filter->client_next,
- 			    tocopy);
++			memcpy(filter->next + filter->avail,
++			    filter->client_next, tocopy);
 +			/* Remove this data from client buffer. */
 +			filter->client_next += tocopy;
 +			filter->client_avail -= tocopy;
 +			/* add it to copy buffer. */
 +			filter->avail += tocopy;
 +		}
 +	}
 +}
 +
 +/*
 + * Move the file pointer forward.
 + */
 +int64_t
 +__archive_read_consume(struct archive_read *a, int64_t request)
 +{
 +	return (__archive_read_filter_consume(a->filter, request));
 +}
 +
 +int64_t
 +__archive_read_filter_consume(struct archive_read_filter * filter,
 +    int64_t request)
 +{
 +	int64_t skipped;
 +
 +	if (request == 0)
 +		return 0;
 +
 +	skipped = advance_file_pointer(filter, request);
 +	if (skipped == request)
 +		return (skipped);
 +	/* We hit EOF before we satisfied the skip request. */
 +	if (skipped < 0)  /* Map error code to 0 for error message below. */
 +		skipped = 0;
 +	archive_set_error(&filter->archive->archive,
 +	    ARCHIVE_ERRNO_MISC,
 +	    "Truncated input file (needed %jd bytes, only %jd available)",
 +	    (intmax_t)request, (intmax_t)skipped);
 +	return (ARCHIVE_FATAL);
 +}
 +
 +/*
 + * Advance the file pointer by the amount requested.
 + * Returns the amount actually advanced, which may be less than the
 + * request if EOF is encountered first.
 + * Returns a negative value if there's an I/O error.
 + */
 +static int64_t
 +advance_file_pointer(struct archive_read_filter *filter, int64_t request)
 +{
 +	int64_t bytes_skipped, total_bytes_skipped = 0;
 +	ssize_t bytes_read;
 +	size_t min;
 +
 +	if (filter->fatal)
 +		return (-1);
 +
 +	/* Use up the copy buffer first. */
 +	if (filter->avail > 0) {
- 		min = minimum(request, (int64_t)filter->avail);
++		min = (size_t)minimum(request, (int64_t)filter->avail);
 +		filter->next += min;
 +		filter->avail -= min;
 +		request -= min;
 +		filter->position += min;
 +		total_bytes_skipped += min;
 +	}
 +
 +	/* Then use up the client buffer. */
 +	if (filter->client_avail > 0) {
- 		min = minimum(request, (int64_t)filter->client_avail);
++		min = (size_t)minimum(request, (int64_t)filter->client_avail);
 +		filter->client_next += min;
 +		filter->client_avail -= min;
 +		request -= min;
 +		filter->position += min;
 +		total_bytes_skipped += min;
 +	}
 +	if (request == 0)
 +		return (total_bytes_skipped);
 +
 +	/* If there's an optimized skip function, use it. */
 +	if (filter->skip != NULL) {
 +		bytes_skipped = (filter->skip)(filter, request);
 +		if (bytes_skipped < 0) {	/* error */
 +			filter->fatal = 1;
 +			return (bytes_skipped);
 +		}
 +		filter->position += bytes_skipped;
 +		total_bytes_skipped += bytes_skipped;
 +		request -= bytes_skipped;
 +		if (request == 0)
 +			return (total_bytes_skipped);
 +	}
 +
 +	/* Use ordinary reads as necessary to complete the request. */
 +	for (;;) {
 +		bytes_read = (filter->read)(filter, &filter->client_buff);
 +		if (bytes_read < 0) {
 +			filter->client_buff = NULL;
 +			filter->fatal = 1;
 +			return (bytes_read);
 +		}
 +
 +		if (bytes_read == 0) {
++			if (filter->archive->client.cursor !=
++			      filter->archive->client.nodes - 1) {
++				if (client_switch_proxy(filter,
++				    filter->archive->client.cursor + 1)
++				    == ARCHIVE_OK)
++					continue;
++			}
 +			filter->client_buff = NULL;
 +			filter->end_of_file = 1;
 +			return (total_bytes_skipped);
 +		}
 +
 +		if (bytes_read >= request) {
 +			filter->client_next =
 +			    ((const char *)filter->client_buff) + request;
- 			filter->client_avail = bytes_read - request;
++			filter->client_avail = (size_t)(bytes_read - request);
 +			filter->client_total = bytes_read;
 +			total_bytes_skipped += request;
 +			filter->position += request;
 +			return (total_bytes_skipped);
 +		}
 +
 +		filter->position += bytes_read;
 +		total_bytes_skipped += bytes_read;
 +		request -= bytes_read;
 +	}
 +}
 +
 +/**
 + * Returns ARCHIVE_FAILED if seeking isn't supported.
 + */
 +int64_t
 +__archive_read_seek(struct archive_read *a, int64_t offset, int whence)
 +{
 +	return __archive_read_filter_seek(a->filter, offset, whence);
 +}
 +
 +int64_t
- __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, int whence)
++__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
++    int whence)
 +{
++	struct archive_read_client *client;
 +	int64_t r;
++	unsigned int cursor;
 +
 +	if (filter->closed || filter->fatal)
 +		return (ARCHIVE_FATAL);
 +	if (filter->seek == NULL)
 +		return (ARCHIVE_FAILED);
- 	r = filter->seek(filter, offset, whence);
++
++	client = &(filter->archive->client);
++	switch (whence) {
++	case SEEK_CUR:
++		/* Adjust the offset and use SEEK_SET instead */
++		offset += filter->position;			
++	case SEEK_SET:
++		cursor = 0;
++		while (1)
++		{
++			if (client->dataset[cursor].begin_position < 0 ||
++			    client->dataset[cursor].total_size < 0 ||
++			    client->dataset[cursor].begin_position +
++			      client->dataset[cursor].total_size - 1 > offset ||
++			    cursor + 1 >= client->nodes)
++				break;
++			r = client->dataset[cursor].begin_position +
++				client->dataset[cursor].total_size;
++			client->dataset[++cursor].begin_position = r;
++		}
++		while (1) {
++			r = client_switch_proxy(filter, cursor);
++			if (r != ARCHIVE_OK)
++				return r;
++			if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)
++				return r;
++			client->dataset[cursor].total_size = r;
++			if (client->dataset[cursor].begin_position +
++			    client->dataset[cursor].total_size - 1 > offset ||
++			    cursor + 1 >= client->nodes)
++				break;
++			r = client->dataset[cursor].begin_position +
++				client->dataset[cursor].total_size;
++			client->dataset[++cursor].begin_position = r;
++		}
++		offset -= client->dataset[cursor].begin_position;
++		if (offset < 0)
++			offset = 0;
++		else if (offset > client->dataset[cursor].total_size - 1)
++			offset = client->dataset[cursor].total_size - 1;
++		if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0)
++			return r;
++		break;
++
++	case SEEK_END:
++		cursor = 0;
++		while (1) {
++			if (client->dataset[cursor].begin_position < 0 ||
++			    client->dataset[cursor].total_size < 0 ||
++			    cursor + 1 >= client->nodes)
++				break;
++			r = client->dataset[cursor].begin_position +
++				client->dataset[cursor].total_size;
++			client->dataset[++cursor].begin_position = r;
++		}
++		while (1) {
++			r = client_switch_proxy(filter, cursor);
++			if (r != ARCHIVE_OK)
++				return r;
++			if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)
++				return r;
++			client->dataset[cursor].total_size = r;
++			r = client->dataset[cursor].begin_position +
++				client->dataset[cursor].total_size;
++			if (cursor + 1 >= client->nodes)
++				break;
++			client->dataset[++cursor].begin_position = r;
++		}
++		while (1) {
++			if (r + offset >=
++			    client->dataset[cursor].begin_position)
++				break;
++			offset += client->dataset[cursor].total_size;
++			if (cursor == 0)
++				break;
++			cursor--;
++			r = client->dataset[cursor].begin_position +
++				client->dataset[cursor].total_size;
++		}
++		offset = (r + offset) - client->dataset[cursor].begin_position;
++		if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK)
++			return r;
++		r = client_seek_proxy(filter, offset, SEEK_SET);
++		if (r < ARCHIVE_OK)
++			return r;
++		break;
++
++	default:
++		return (ARCHIVE_FATAL);
++	}
++	r += client->dataset[cursor].begin_position;
++
 +	if (r >= 0) {
 +		/*
 +		 * Ouch.  Clearing the buffer like this hurts, especially
 +		 * at bid time.  A lot of our efficiency at bid time comes
 +		 * from having bidders reuse the data we've already read.
 +		 *
 +		 * TODO: If the seek request is in data we already
 +		 * have, then don't call the seek callback.
 +		 *
 +		 * TODO: Zip seeks to end-of-file at bid time.  If
 +		 * other formats also start doing this, we may need to
 +		 * find a way for clients to fudge the seek offset to
 +		 * a block boundary.
 +		 *
 +		 * Hmmm... If whence was SEEK_END, we know the file
 +		 * size is (r - offset).  Can we use that to simplify
 +		 * the TODO items above?
 +		 */
 +		filter->avail = filter->client_avail = 0;
 +		filter->next = filter->buffer;
 +		filter->position = r;
 +		filter->end_of_file = 0;
 +	}
 +	return r;
 +}
diff --cc Utilities/cmlibarchive/libarchive/archive_read_append_filter.c
index 0000000,017d7c6..017d7c6
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c
diff --cc Utilities/cmlibarchive/libarchive/archive_read_set_format.c
index 0000000,190f436..190f436
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_set_format.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_set_format.c
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_filter_bzip2.c
index af618b0,0000000..2b1a5e2
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_bzip2.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_bzip2.c
@@@ -1,370 -1,0 +1,371 @@@
 +/*-
 + * 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 <cm_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->name = "bzip2";
 +	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");
++	    "Using external bzip2 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");
++	r = __archive_read_program(self, "bzip2 -d");
 +	/* Note: We set the format here even if __archive_read_program()
 +	 * above fails.  We do, after all, know what the format is
 +	 * even if we weren't able to read it. */
- 	self->code = ARCHIVE_COMPRESSION_BZIP2;
++	self->code = ARCHIVE_FILTER_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->code = ARCHIVE_FILTER_BZIP2;
 +	self->name = "bzip2";
 +
 +	state = (struct private_data *)calloc(sizeof(*state), 1);
 +	out_block = (unsigned char *)malloc(out_block_size);
 +	if (state == NULL || out_block == NULL) {
 +		archive_set_error(&self->archive->archive, ENOMEM,
 +		    "Can't allocate data for bzip2 decompression");
 +		free(out_block);
 +		free(state);
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	self->data = state;
 +	state->out_block_size = out_block_size;
 +	state->out_block = out_block;
 +	self->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 */
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_filter_grzip.c
index 0000000,84c86ae..84c86ae
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_grzip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_grzip.c
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_filter_gzip.c
index 9d03b2b,0000000..e9f59f1
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_gzip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_gzip.c
@@@ -1,476 -1,0 +1,477 @@@
 +/*-
 + * 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 <cm_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.
++ * gzip program.
 + */
 +static int	gzip_bidder_bid(struct archive_read_filter_bidder *,
 +		    struct archive_read_filter *);
 +static int	gzip_bidder_init(struct archive_read_filter *);
 +
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +/* Deprecated; remove in libarchive 4.0 */
 +int
 +archive_read_support_compression_gzip(struct archive *a)
 +{
 +	return archive_read_support_filter_gzip(a);
 +}
 +#endif
 +
 +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->name = "gzip";
 +	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");
++	    "Using external gzip program");
 +	return (ARCHIVE_WARN);
 +#endif
 +}
 +
 +/*
 + * Read and verify the header.
 + *
 + * Returns zero if the header couldn't be validated, else returns
 + * number of bytes in header.  If pbits is non-NULL, it receives a
 + * count of bits verified, suitable for use by bidder.
 + */
- static int
++static ssize_t
 +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
++ * decompression directly.  We can, however, try to run "gzip -d"
 + * in case that's available.
 + */
 +static int
 +gzip_bidder_init(struct archive_read_filter *self)
 +{
 +	int r;
 +
- 	r = __archive_read_program(self, "gunzip");
++	r = __archive_read_program(self, "gzip -d");
 +	/* Note: We set the format here even if __archive_read_program()
 +	 * above fails.  We do, after all, know what the format is
 +	 * even if we weren't able to read it. */
- 	self->code = ARCHIVE_COMPRESSION_GZIP;
++	self->code = ARCHIVE_FILTER_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->code = ARCHIVE_FILTER_GZIP;
 +	self->name = "gzip";
 +
 +	state = (struct private_data *)calloc(sizeof(*state), 1);
 +	out_block = (unsigned char *)malloc(out_block_size);
 +	if (state == NULL || out_block == NULL) {
 +		free(out_block);
 +		free(state);
 +		archive_set_error(&self->archive->archive, ENOMEM,
 +		    "Can't allocate data for gzip decompression");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	self->data = state;
 +	state->out_block_size = out_block_size;
 +	state->out_block = out_block;
 +	self->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;
++	state->stream.avail_in = (uInt)avail;
 +	ret = inflateInit2(&(state->stream),
 +	    -15 /* Don't check for zlib header */);
 +
 +	/* Decipher the error code. */
 +	switch (ret) {
 +	case Z_OK:
 +		state->in_stream = 1;
 +		return (ARCHIVE_OK);
 +	case Z_STREAM_ERROR:
 +		archive_set_error(&self->archive->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    "invalid setup parameter");
 +		break;
 +	case Z_MEM_ERROR:
 +		archive_set_error(&self->archive->archive, ENOMEM,
 +		    "Internal error initializing compression library: "
 +		    "out of memory");
 +		break;
 +	case Z_VERSION_ERROR:
 +		archive_set_error(&self->archive->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    "invalid library version");
 +		break;
 +	default:
 +		archive_set_error(&self->archive->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    " Zlib error %d", ret);
 +		break;
 +	}
 +	return (ARCHIVE_FATAL);
 +}
 +
 +static int
 +consume_trailer(struct archive_read_filter *self)
 +{
 +	struct private_data *state;
 +	const unsigned char *p;
 +	ssize_t avail;
 +
 +	state = (struct private_data *)self->data;
 +
 +	state->in_stream = 0;
 +	switch (inflateEnd(&(state->stream))) {
 +	case Z_OK:
 +		break;
 +	default:
 +		archive_set_error(&self->archive->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up gzip decompressor");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* GZip trailer is a fixed 8 byte structure. */
 +	p = __archive_read_filter_ahead(self->upstream, 8, &avail);
 +	if (p == NULL || avail == 0)
 +		return (ARCHIVE_FATAL);
 +
 +	/* XXX TODO: Verify the length and CRC. */
 +
 +	/* We've verified the trailer, so consume it now. */
 +	__archive_read_filter_consume(self->upstream, 8);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static ssize_t
 +gzip_filter_read(struct archive_read_filter *self, const void **p)
 +{
 +	struct private_data *state;
 +	size_t decompressed;
 +	ssize_t avail_in;
 +	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;
++	state->stream.avail_out = (uInt)state->out_block_size;
 +
 +	/* Try to fill the output buffer. */
 +	while (state->stream.avail_out > 0 && !state->eof) {
 +		/* If we're not in a stream, read a header
 +		 * and initialize the decompression library. */
 +		if (!state->in_stream) {
 +			ret = consume_header(self);
 +			if (ret == ARCHIVE_EOF) {
 +				state->eof = 1;
 +				break;
 +			}
 +			if (ret < ARCHIVE_OK)
 +				return (ret);
 +		}
 +
 +		/* Peek at the next available data. */
 +		/* ZLib treats stream.next_in as const but doesn't declare
 +		 * it so, hence this ugly cast. */
 +		state->stream.next_in = (unsigned char *)(uintptr_t)
 +		    __archive_read_filter_ahead(self->upstream, 1, &avail_in);
 +		if (state->stream.next_in == NULL) {
 +			archive_set_error(&self->archive->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "truncated gzip input");
 +			return (ARCHIVE_FATAL);
 +		}
- 		state->stream.avail_in = avail_in;
++		state->stream.avail_in = (uInt)avail_in;
 +
 +		/* Decompress and consume some of that data. */
 +		ret = inflate(&(state->stream), 0);
 +		switch (ret) {
 +		case Z_OK: /* Decompressor made some progress. */
 +			__archive_read_filter_consume(self->upstream,
 +			    avail_in - state->stream.avail_in);
 +			break;
 +		case Z_STREAM_END: /* Found end of stream. */
 +			__archive_read_filter_consume(self->upstream,
 +			    avail_in - state->stream.avail_in);
 +			/* Consume the stream trailer; release the
 +			 * decompression library. */
 +			ret = consume_trailer(self);
 +			if (ret < ARCHIVE_OK)
 +				return (ret);
 +			break;
 +		default:
 +			/* Return an error. */
 +			archive_set_error(&self->archive->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "gzip decompression failed");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	/* We've read as much as we can. */
 +	decompressed = state->stream.next_out - state->out_block;
 +	state->total_out += decompressed;
 +	if (decompressed == 0)
 +		*p = NULL;
 +	else
 +		*p = state->out_block;
 +	return (decompressed);
 +}
 +
 +/*
 + * Clean up the decompressor.
 + */
 +static int
 +gzip_filter_close(struct archive_read_filter *self)
 +{
 +	struct private_data *state;
 +	int ret;
 +
 +	state = (struct private_data *)self->data;
 +	ret = ARCHIVE_OK;
 +
 +	if (state->in_stream) {
 +		switch (inflateEnd(&(state->stream))) {
 +		case Z_OK:
 +			break;
 +		default:
 +			archive_set_error(&(self->archive->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Failed to clean up gzip compressor");
 +			ret = ARCHIVE_FATAL;
 +		}
 +	}
 +
 +	free(state->out_block);
 +	free(state);
 +	return (ret);
 +}
 +
 +#endif /* HAVE_ZLIB_H */
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_filter_lrzip.c
index 0000000,c82a8e2..c82a8e2
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lrzip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lrzip.c
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
index 0000000,713af31..713af31
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
index 2be2267,0000000..54ea245
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
@@@ -1,3706 -1,0 +1,3748 @@@
 +/*-
 + * Copyright (c) 2011 Michihiro NAKAJIMA
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD$");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_BZLIB_H
 +#include <cm_bzlib.h>
 +#endif
 +#ifdef HAVE_LZMA_H
 +#include <lzma.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_ppmd7_private.h"
 +#include "archive_private.h"
 +#include "archive_read_private.h"
 +#include "archive_endian.h"
 +
 +#ifndef HAVE_ZLIB_H
 +#include "archive_crc32.h"
 +#endif
 +
 +#define _7ZIP_SIGNATURE	"7z\xBC\xAF\x27\x1C"
 +#define SFX_MIN_ADDR	0x27000
 +#define SFX_MAX_ADDR	0x60000
 +
 +
 +/*
 + * Codec ID
 + */
 +#define _7Z_COPY	0
 +#define _7Z_LZMA	0x030101
 +#define _7Z_LZMA2	0x21
 +#define _7Z_DEFLATE	0x040108
 +#define _7Z_BZ2		0x040202
 +#define _7Z_PPMD	0x030401
 +#define _7Z_DELTA	0x03
 +#define _7Z_CRYPTO	0x06F10701
 +#define _7Z_X86		0x03030103
 +#define _7Z_X86_BCJ2	0x0303011B
 +#define _7Z_POWERPC	0x03030205
 +#define _7Z_IA64	0x03030401
 +#define _7Z_ARM		0x03030501
 +#define _7Z_ARMTHUMB	0x03030701
 +#define _7Z_SPARC	0x03030805
 +
 +/*
 + * 7-Zip header property IDs.
 + */
 +#define kEnd			0x00
 +#define kHeader			0x01
 +#define kArchiveProperties	0x02
 +#define kAdditionalStreamsInfo	0x03
 +#define kMainStreamsInfo	0x04
 +#define kFilesInfo		0x05
 +#define kPackInfo		0x06
 +#define kUnPackInfo		0x07
 +#define kSubStreamsInfo		0x08
 +#define kSize			0x09
 +#define kCRC			0x0A
 +#define kFolder			0x0B
 +#define kCodersUnPackSize	0x0C
 +#define kNumUnPackStream	0x0D
 +#define kEmptyStream		0x0E
 +#define kEmptyFile		0x0F
 +#define kAnti			0x10
 +#define kName			0x11
 +#define kCTime			0x12
 +#define kATime			0x13
 +#define kMTime			0x14
 +#define kAttributes		0x15
 +#define kEncodedHeader		0x17
 +
 +struct _7z_digests {
 +	unsigned char	*defineds;
 +	uint32_t	*digests;
 +};
 +
 +
 +struct _7z_folder {
 +	uint64_t		 numCoders;
 +	struct _7z_coder {
 +		unsigned long	 codec;
 +		uint64_t	 numInStreams;
 +		uint64_t	 numOutStreams;
 +		uint64_t	 propertiesSize;
 +		unsigned char	*properties;
 +	} *coders;
 +	uint64_t		 numBindPairs;
 +	struct {
 +		uint64_t	 inIndex;
 +		uint64_t	 outIndex;
 +	} *bindPairs;
 +	uint64_t		 numPackedStreams;
 +	uint64_t		*packedStreams;
 +	uint64_t		 numInStreams;
 +	uint64_t		 numOutStreams;
 +	uint64_t		*unPackSize;
 +	unsigned char		 digest_defined;
 +	uint32_t		 digest;
 +	uint64_t		 numUnpackStreams;
 +	uint32_t		 packIndex;
 +	/* Unoperated bytes. */
 +	uint64_t		 skipped_bytes;
 +};
 +
 +struct _7z_coders_info {
 +	uint64_t		 numFolders;
 +	struct _7z_folder	*folders;
 +	uint64_t		 dataStreamIndex;
 +};
 +
 +struct _7z_pack_info {
 +	uint64_t		 pos;
 +	uint64_t		 numPackStreams;
 +	uint64_t		*sizes;
 +	struct _7z_digests	 digest;
 +	/* Calculated from pos and numPackStreams. */
 +	uint64_t		*positions;
 +};
 +
 +struct _7z_substream_info {
 +	size_t			 unpack_streams;
 +	uint64_t		*unpackSizes;
 +	unsigned char		*digestsDefined;
 +	uint32_t		*digests;
 +};
 +
 +struct _7z_stream_info {
 +	struct _7z_pack_info	 pi;
 +	struct _7z_coders_info	 ci;
 +	struct _7z_substream_info ss;
 +};
 +
 +struct _7z_header_info {
 +	uint64_t		 dataIndex;
 +
 +	unsigned char		*emptyStreamBools;
 +	unsigned char		*emptyFileBools;
 +	unsigned char		*antiBools;
 +	unsigned char		*attrBools;
 +};
 +
 +struct _7zip_entry {
 +	size_t			 name_len;
 +	unsigned char		*utf16name;
 +#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
 +	const wchar_t		*wname;
 +#endif
 +	uint32_t		 folderIndex;
 +	uint32_t		 ssIndex;
 +	unsigned		 flg;
 +#define MTIME_IS_SET	(1<<0)
 +#define ATIME_IS_SET	(1<<1)
 +#define CTIME_IS_SET	(1<<2)
 +#define CRC32_IS_SET	(1<<3)
 +#define HAS_STREAM	(1<<4)
 +
 +	time_t			 mtime;
 +	time_t			 atime;
 +	time_t			 ctime;
 +	long			 mtime_ns;
 +	long			 atime_ns;
 +	long			 ctime_ns;
 +	uint32_t		 mode;
 +	uint32_t		 attr;
 +};
 +
 +struct _7zip {
 +	/* Structural information about the archive. */
 +	struct _7z_stream_info	 si;
 +
 +	int			 header_is_being_read;
 +	int			 header_is_encoded;
 +	uint64_t		 header_bytes_remaining;
 +	unsigned long		 header_crc32;
 +	/* Header offset to check that reading pointes of the file contens
 +	 * will not exceed the header. */
 +	uint64_t		 header_offset;
 +	/* Base offset of the archive file for a seek in case reading SFX. */
 +	uint64_t		 seek_base;
 +
 +	/* List of entries */
 +	size_t			 entries_remaining;
 +	uint64_t		 numFiles;
 +	struct _7zip_entry	*entries;
 +	struct _7zip_entry	*entry;
 +	unsigned char		*entry_names;
 +
 +	/* entry_bytes_remaining is the number of bytes we expect. */
 +	int64_t			 entry_offset;
 +	uint64_t		 entry_bytes_remaining;
 +
 +	/* Running CRC32 of the decompressed data */
 +	unsigned long		 entry_crc32;
 +
 +	/* Flags to mark progress of decompression. */
 +	char			 end_of_entry;
 +
 +	/* Uncompressed buffer control.  */
 +#define UBUFF_SIZE	(64 * 1024)
 +	unsigned char 		*uncompressed_buffer;
 +	unsigned char 		*uncompressed_buffer_pointer;
 +	size_t 			 uncompressed_buffer_size;
 +	size_t			 uncompressed_buffer_bytes_remaining;
 +
 +	/* Offset of the compressed data. */
 +	int64_t			 stream_offset;
 +
 +	/*
 +	 * Decompressing control data.
 +	 */
 +	unsigned		 folder_index;
 +	uint64_t		 folder_outbytes_remaining;
 +	unsigned		 pack_stream_index;
 +	unsigned		 pack_stream_remaining;
 +	uint64_t		 pack_stream_inbytes_remaining;
 +	size_t			 pack_stream_bytes_unconsumed;
 +
 +	/* The codec information of a folder. */
 +	unsigned long		 codec;
 +	unsigned long		 codec2;
 +
 +	/*
 +	 * Decompressor controllers.
 +	 */
 +	/* Decording LZMA1 and LZMA2 data. */
 +#ifdef HAVE_LZMA_H
 +	lzma_stream		 lzstream;
 +	int			 lzstream_valid;
 +#endif
 +	/* Decording bzip2 data. */
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	bz_stream		 bzstream;
 +	int			 bzstream_valid;
 +#endif
 +	/* Decording deflate data. */
 +#ifdef HAVE_ZLIB_H
 +	z_stream		 stream;
 +	int			 stream_valid;
 +#endif
 +	/* Decording PPMd data. */
 +	int			 ppmd7_stat;
 +	CPpmd7			 ppmd7_context;
 +	CPpmd7z_RangeDec	 range_dec;
 +	IByteIn			 bytein;
 +	struct {
 +		const unsigned char	*next_in;
 +		int64_t			 avail_in;
 +		int64_t			 total_in;
 +		unsigned char		*next_out;
 +		int64_t			 avail_out;
 +		int64_t			 total_out;
 +		int			 overconsumed;
 +	} ppstream;
 +	int			 ppmd7_valid;
 +
 +	/* Decoding BCJ and BCJ2 data. */
 +	uint32_t		 bcj_state;
 +	size_t			 odd_bcj_size;
 +	unsigned char		 odd_bcj[4];
 +	/* Decoding BCJ data. */
 +	size_t			 bcj_prevPosT;
 +	uint32_t		 bcj_prevMask;
 +	uint32_t		 bcj_ip;
 +
 +	/* Decoding BCJ2 data. */
 +	size_t			 main_stream_bytes_remaining;
 +	unsigned char		*sub_stream_buff[3];
 +	size_t			 sub_stream_size[3];
 +	size_t			 sub_stream_bytes_remaining[3];
 +	unsigned char		*tmp_stream_buff;
 +	size_t			 tmp_stream_buff_size;
 +	size_t			 tmp_stream_bytes_avail;
 +	size_t			 tmp_stream_bytes_remaining;
 +#ifdef _LZMA_PROB32
 +#define CProb uint32_t
 +#else
 +#define CProb uint16_t
 +#endif
 +	CProb			 bcj2_p[256 + 2];
 +	uint8_t			 bcj2_prevByte;
 +	uint32_t		 bcj2_range;
 +	uint32_t		 bcj2_code;
 +	uint64_t		 bcj2_outPos;
 +
- 	/* Filename character-set convertion data. */
++	/* Filename character-set conversion data. */
 +	struct archive_string_conv *sconv;
 +
 +	char			 format_name[64];
 +};
 +
 +static int	archive_read_format_7zip_bid(struct archive_read *, int);
 +static int	archive_read_format_7zip_cleanup(struct archive_read *);
 +static int	archive_read_format_7zip_read_data(struct archive_read *,
 +		    const void **, size_t *, int64_t *);
 +static int	archive_read_format_7zip_read_data_skip(struct archive_read *);
 +static int	archive_read_format_7zip_read_header(struct archive_read *,
 +		    struct archive_entry *);
 +static int	check_7zip_header_in_sfx(const char *);
 +static unsigned long decode_codec_id(const unsigned char *, size_t);
 +static int	decode_encoded_header_info(struct archive_read *,
 +		    struct _7z_stream_info *);
 +static int	decompress(struct archive_read *, struct _7zip *,
 +		    void *, size_t *, const void *, size_t *);
 +static ssize_t	extract_pack_stream(struct archive_read *, size_t);
 +static void	fileTimeToUtc(uint64_t, time_t *, long *);
 +static uint64_t folder_uncompressed_size(struct _7z_folder *);
 +static void	free_CodersInfo(struct _7z_coders_info *);
 +static void	free_Digest(struct _7z_digests *);
 +static void	free_Folder(struct _7z_folder *);
 +static void	free_Header(struct _7z_header_info *);
 +static void	free_PackInfo(struct _7z_pack_info *);
 +static void	free_StreamsInfo(struct _7z_stream_info *);
 +static void	free_SubStreamsInfo(struct _7z_substream_info *);
 +static int	free_decompression(struct archive_read *, struct _7zip *);
 +static ssize_t	get_uncompressed_data(struct archive_read *, const void **,
 +		    size_t, size_t);
 +static const unsigned char * header_bytes(struct archive_read *, size_t);
 +static int	init_decompression(struct archive_read *, struct _7zip *,
 +		    const struct _7z_coder *, const struct _7z_coder *);
 +static int	parse_7zip_uint64(struct archive_read *, uint64_t *);
 +static int	read_Bools(struct archive_read *, unsigned char *, size_t);
 +static int	read_CodersInfo(struct archive_read *,
 +		    struct _7z_coders_info *);
 +static int	read_Digests(struct archive_read *, struct _7z_digests *,
 +		    size_t);
 +static int	read_Folder(struct archive_read *, struct _7z_folder *);
 +static int	read_Header(struct archive_read *, struct _7z_header_info *,
 +		    int);
 +static int	read_PackInfo(struct archive_read *, struct _7z_pack_info *);
 +static int	read_StreamsInfo(struct archive_read *,
 +		    struct _7z_stream_info *);
 +static int	read_SubStreamsInfo(struct archive_read *,
 +		    struct _7z_substream_info *, struct _7z_folder *, size_t);
 +static int	read_Times(struct archive_read *, struct _7z_header_info *,
 +		    int);
 +static void	read_consume(struct archive_read *);
 +static ssize_t	read_stream(struct archive_read *, const void **, size_t,
 +		    size_t);
 +static int	seek_pack(struct archive_read *);
 +static int64_t	skip_stream(struct archive_read *, size_t);
 +static int	skip_sfx(struct archive_read *, ssize_t);
 +static int	slurp_central_directory(struct archive_read *, struct _7zip *,
 +		    struct _7z_header_info *);
 +static int	setup_decode_folder(struct archive_read *, struct _7z_folder *,
 +		    int);
 +static void	x86_Init(struct _7zip *);
 +static size_t	x86_Convert(struct _7zip *, uint8_t *, size_t);
 +static ssize_t		Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
 +
 +
 +int
 +archive_read_support_format_7zip(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct _7zip *zip;
 +	int r;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_read_support_format_7zip");
 +
 +	zip = calloc(1, sizeof(*zip));
 +	if (zip == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate 7zip data");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	r = __archive_read_register_format(a,
 +	    zip,
 +	    "7zip",
 +	    archive_read_format_7zip_bid,
 +	    NULL,
 +	    archive_read_format_7zip_read_header,
 +	    archive_read_format_7zip_read_data,
 +	    archive_read_format_7zip_read_data_skip,
++	    NULL,
 +	    archive_read_format_7zip_cleanup);
 +
 +	if (r != ARCHIVE_OK)
 +		free(zip);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_read_format_7zip_bid(struct archive_read *a, int best_bid)
 +{
 +	const char *p;
 +
 +	/* If someone has already bid more than 32, then avoid
 +	   trashing the look-ahead buffers with a seek. */
 +	if (best_bid > 32)
 +		return (-1);
 +
 +	if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
 +		return (0);
 +
 +	/* If first six bytes are the 7-Zip signature,
 +	 * return the bid right now. */
 +	if (memcmp(p, _7ZIP_SIGNATURE, 6) == 0)
 +		return (48);
 +
 +	/*
 +	 * It may a 7-Zip SFX archive file. If first two bytes are
 +	 * 'M' and 'Z' available on Windows or first four bytes are
 +	 * "\x7F\x45LF" available on posix like system, seek the 7-Zip
 +	 * signature. Although we will perform a seek when reading
 +	 * a header, what we do not use __archive_read_seek() here is
 +	 * due to a bidding performance.
 +	 */
 +	if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
 +		ssize_t offset = SFX_MIN_ADDR;
 +		ssize_t window = 4096;
 +		ssize_t bytes_avail;
 +		while (offset + window <= (SFX_MAX_ADDR)) {
 +			const char *buff = __archive_read_ahead(a,
 +					offset + window, &bytes_avail);
 +			if (buff == NULL) {
 +				/* Remaining bytes are less than window. */
 +				window >>= 1;
 +				if (window < 0x40)
 +					return (0);
 +				continue;
 +			}
 +			p = buff + offset;
 +			while (p + 32 < buff + bytes_avail) {
 +				int step = check_7zip_header_in_sfx(p);
 +				if (step == 0)
 +					return (48);
 +				p += step;
 +			}
 +			offset = p - buff;
 +		}
 +	}
 +	return (0);
 +}
 +
 +static int
 +check_7zip_header_in_sfx(const char *p)
 +{
 +	switch ((unsigned char)p[5]) {
 +	case 0x1C:
 +		if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0)
 +			return (6); 
 +		/*
 +		 * Test the CRC because its extraction code has 7-Zip
 +		 * Magic Code, so we should do this in order not to
 +		 * make a mis-detection.
 +		 */
- 		if (crc32(0, (unsigned char *)p + 12, 20)
++		if (crc32(0, (const unsigned char *)p + 12, 20)
 +			!= archive_le32dec(p + 8))
 +			return (6); 
 +		/* Hit the header! */
 +		return (0);
 +	case 0x37: return (5); 
 +	case 0x7A: return (4); 
 +	case 0xBC: return (3); 
 +	case 0xAF: return (2); 
 +	case 0x27: return (1); 
 +	default: return (6); 
 +	}
 +}
 +
 +static int
 +skip_sfx(struct archive_read *a, ssize_t bytes_avail)
 +{
 +	const void *h;
 +	const char *p, *q;
 +	size_t skip, offset;
 +	ssize_t bytes, window;
 +
 +	/*
 +	 * If bytes_avail > SFX_MIN_ADDR we do not have to call
 +	 * __archive_read_seek() at this time since we have
 +	 * alredy had enough data.
 +	 */
 +	if (bytes_avail > SFX_MIN_ADDR)
 +		__archive_read_consume(a, SFX_MIN_ADDR);
 +	else if (__archive_read_seek(a, SFX_MIN_ADDR, SEEK_SET) < 0)
 +		return (ARCHIVE_FATAL);
 +
 +	offset = 0;
 +	window = 1;
 +	while (offset + window <= SFX_MAX_ADDR - SFX_MIN_ADDR) {
 +		h = __archive_read_ahead(a, window, &bytes);
 +		if (h == NULL) {
 +			/* Remaining bytes are less than window. */
 +			window >>= 1;
 +			if (window < 0x40)
 +				goto fatal;
 +			continue;
 +		}
 +		if (bytes < 6) {
 +			/* This case might happen when window == 1. */
 +			window = 4096;
 +			continue;
 +		}
 +		p = (const char *)h;
 +		q = p + bytes;
 +
 +		/*
 +		 * Scan ahead until we find something that looks
 +		 * like the 7-Zip header.
 +		 */
 +		while (p + 32 < q) {
 +			int step = check_7zip_header_in_sfx(p);
 +			if (step == 0) {
 +				struct _7zip *zip =
 +				    (struct _7zip *)a->format->data;
 +				skip = p - (const char *)h;
 +				__archive_read_consume(a, skip);
 +				zip->seek_base = SFX_MIN_ADDR + offset + skip;
 +				return (ARCHIVE_OK);
 +			}
 +			p += step;
 +		}
 +		skip = p - (const char *)h;
 +		__archive_read_consume(a, skip);
 +		offset += skip;
 +		if (window == 1)
 +			window = 4096;
 +	}
 +fatal:
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +	    "Couldn't find out 7-Zip header");
 +	return (ARCHIVE_FATAL);
 +}
 +
 +static int
 +archive_read_format_7zip_read_header(struct archive_read *a,
 +	struct archive_entry *entry)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	struct _7zip_entry *zip_entry;
 +	int r, ret = ARCHIVE_OK;
 +
 +	a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
 +	if (a->archive.archive_format_name == NULL)
 +		a->archive.archive_format_name = "7-Zip";
 +
 +	if (zip->entries == NULL) {
 +		struct _7z_header_info header;
 +
 +		memset(&header, 0, sizeof(header));
 +		r = slurp_central_directory(a, zip, &header);
 +		free_Header(&header);
 +		if (r != ARCHIVE_OK)
 +			return (r);
- 		zip->entries_remaining = zip->numFiles;
++		zip->entries_remaining = (size_t)zip->numFiles;
 +		zip->entry = zip->entries;
 +	} else {
 +		++zip->entry;
 +	}
 +	zip_entry = zip->entry;
 +
 +	if (zip->entries_remaining <= 0)
 +		return ARCHIVE_EOF;
 +	--zip->entries_remaining;
 +
 +	zip->entry_offset = 0;
 +	zip->end_of_entry = 0;
 +	zip->entry_crc32 = crc32(0, NULL, 0);
 +
 +	/* Setup a string conversion for a filename. */
 +	if (zip->sconv == NULL) {
 +		zip->sconv = archive_string_conversion_from_charset(
 +		    &a->archive, "UTF-16LE", 1);
 +		if (zip->sconv == NULL)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	if (archive_entry_copy_pathname_l(entry,
 +	    (const char *)zip_entry->utf16name,
 +	    zip_entry->name_len, zip->sconv) != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Pathname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Pathname cannot be converted "
 +		    "from %s to current locale.",
 +		    archive_string_conversion_charset_name(zip->sconv));
 +		ret = ARCHIVE_WARN;
 +	}
 +
 +	/* Populate some additional entry fields: */
 +	archive_entry_set_mode(entry, zip_entry->mode);
 +	if (zip_entry->flg & MTIME_IS_SET)
 +		archive_entry_set_mtime(entry, zip_entry->mtime,
 +			zip_entry->mtime_ns);
 +	if (zip_entry->flg & CTIME_IS_SET)
 +		archive_entry_set_ctime(entry, zip_entry->ctime,
 +		    zip_entry->ctime_ns);
 +	if (zip_entry->flg & ATIME_IS_SET)
 +		archive_entry_set_atime(entry, zip_entry->atime,
 +		    zip_entry->atime_ns);
- 	if (zip_entry->ssIndex != -1) {
++	if (zip_entry->ssIndex != (uint32_t)-1) {
 +		zip->entry_bytes_remaining =
 +		    zip->si.ss.unpackSizes[zip_entry->ssIndex];
 +		archive_entry_set_size(entry, zip->entry_bytes_remaining);
 +	} else {
 +		zip->entry_bytes_remaining = 0;
 +		archive_entry_set_size(entry, 0);
 +	}
 +
 +	/* If there's no body, force read_data() to return EOF immediately. */
 +	if (zip->entry_bytes_remaining < 1)
 +		zip->end_of_entry = 1;
 +
 +	if ((zip_entry->mode & AE_IFMT) == AE_IFLNK) {
 +		unsigned char *symname = NULL;
 +		size_t symsize = 0;
- 		int r;
 +
 +		/*
 +		 * Symbolic-name is recorded as its contents. We have to
 +		 * read the contents at this time.
 +		 */
 +		while (zip->entry_bytes_remaining > 0) {
 +			const void *buff;
++			unsigned char *mem;
 +			size_t size;
 +			int64_t offset;
 +
 +			r = archive_read_format_7zip_read_data(a, &buff,
 +				&size, &offset);
- 			if (r < ARCHIVE_WARN)
++			if (r < ARCHIVE_WARN) {
++				free(symname);
 +				return (r);
- 			symname = realloc(symname, symsize + size + 1);
- 			if (symname == NULL) {
++			}
++			mem = realloc(symname, symsize + size + 1);
++			if (mem == NULL) {
++				free(symname);
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "Can't allocate memory for Symname");
 +				return (ARCHIVE_FATAL);
 +			}
++			symname = mem;
 +			memcpy(symname+symsize, buff, size);
 +			symsize += size;
 +		}
 +		if (symsize == 0) {
 +			/* If there is no synname, handle it as a regular
 +			 * file. */
 +			zip_entry->mode &= ~AE_IFMT;
 +			zip_entry->mode |= AE_IFREG;
 +			archive_entry_set_mode(entry, zip_entry->mode);
 +		} else {
 +			symname[symsize] = '\0';
 +			archive_entry_copy_symlink(entry,
 +			    (const char *)symname);
- 			free(symname);
 +		}
++		free(symname);
 +		archive_entry_set_size(entry, 0);
 +	}
 +
 +	/* Set up a more descriptive format name. */
 +	sprintf(zip->format_name, "7-Zip");
 +	a->archive.archive_format_name = zip->format_name;
 +
 +	return (ret);
 +}
 +
 +static int
 +archive_read_format_7zip_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	struct _7zip *zip;
 +	ssize_t bytes;
 +	int ret = ARCHIVE_OK;
 +
 +	zip = (struct _7zip *)(a->format->data);
 +
 +	if (zip->pack_stream_bytes_unconsumed)
 +		read_consume(a);
 +
++	*offset = zip->entry_offset;
++	*size = 0;
++	*buff = NULL;
 +	/*
 +	 * If we hit end-of-entry last time, clean up and return
 +	 * ARCHIVE_EOF this time.
 +	 */
- 	if (zip->end_of_entry) {
- 		*offset = zip->entry_offset;
- 		*size = 0;
- 		*buff = NULL;
++	if (zip->end_of_entry)
 +		return (ARCHIVE_EOF);
- 	}
 +
- 	bytes = read_stream(a, buff, zip->entry_bytes_remaining, 0);
++	bytes = read_stream(a, buff,
++		(size_t)zip->entry_bytes_remaining, 0);
 +	if (bytes < 0)
 +		return ((int)bytes);
 +	if (bytes == 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated 7-Zip file body");
 +		return (ARCHIVE_FATAL);
 +	}
 +	zip->entry_bytes_remaining -= bytes;
 +	if (zip->entry_bytes_remaining == 0)
 +		zip->end_of_entry = 1;
 +
 +	/* Update checksum */
 +	if ((zip->entry->flg & CRC32_IS_SET) && bytes)
- 		zip->entry_crc32 = crc32(zip->entry_crc32, *buff, bytes);
++		zip->entry_crc32 = crc32(zip->entry_crc32, *buff,
++		    (unsigned)bytes);
 +
 +	/* If we hit the end, swallow any end-of-data marker. */
 +	if (zip->end_of_entry) {
 +		/* Check computed CRC against file contents. */
 +		if ((zip->entry->flg & CRC32_IS_SET) &&
 +			zip->si.ss.digests[zip->entry->ssIndex] !=
 +		    zip->entry_crc32) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "7-Zip bad CRC: 0x%lx should be 0x%lx",
 +			    (unsigned long)zip->entry_crc32,
 +			    (unsigned long)zip->si.ss.digests[
 +			    		zip->entry->ssIndex]);
 +			ret = ARCHIVE_WARN;
 +		}
 +	}
 +
 +	*size = bytes;
 +	*offset = zip->entry_offset;
 +	zip->entry_offset += bytes;
 +
 +	return (ret);
 +}
 +
 +static int
 +archive_read_format_7zip_read_data_skip(struct archive_read *a)
 +{
 +	struct _7zip *zip;
 +	int64_t bytes_skipped;
 +
 +	zip = (struct _7zip *)(a->format->data);
 +
 +	if (zip->pack_stream_bytes_unconsumed)
 +		read_consume(a);
 +
 +	/* If we've already read to end of data, we're done. */
 +	if (zip->end_of_entry)
 +		return (ARCHIVE_OK);
 +
 +	/*
 +	 * If the length is at the beginning, we can skip the
 +	 * compressed data much more quickly.
 +	 */
- 	bytes_skipped = skip_stream(a, zip->entry_bytes_remaining);
++	bytes_skipped = skip_stream(a, (size_t)zip->entry_bytes_remaining);
 +	if (bytes_skipped < 0)
 +		return (ARCHIVE_FATAL);
 +	zip->entry_bytes_remaining = 0;
 +
 +	/* This entry is finished and done. */
 +	zip->end_of_entry = 1;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_read_format_7zip_cleanup(struct archive_read *a)
 +{
 +	struct _7zip *zip;
 +
 +	zip = (struct _7zip *)(a->format->data);
 +	free_StreamsInfo(&(zip->si));
 +	free(zip->entries);
 +	free(zip->entry_names);
 +	free_decompression(a, zip);
 +	free(zip->uncompressed_buffer);
 +	free(zip->sub_stream_buff[0]);
 +	free(zip->sub_stream_buff[1]);
 +	free(zip->sub_stream_buff[2]);
 +	free(zip->tmp_stream_buff);
 +	free(zip);
 +	(a->format->data) = NULL;
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +read_consume(struct archive_read *a)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +
 +	if (zip->pack_stream_bytes_unconsumed) {
 +		__archive_read_consume(a, zip->pack_stream_bytes_unconsumed);
 +		zip->stream_offset += zip->pack_stream_bytes_unconsumed;
 +		zip->pack_stream_bytes_unconsumed = 0;
 +	}
 +}
 +
 +#ifdef HAVE_LZMA_H
 +
 +/*
 + * Set an error code and choose an error message for liblzma.
 + */
 +static void
 +set_error(struct archive_read *a, int ret)
 +{
 +
 +	switch (ret) {
 +	case LZMA_STREAM_END: /* Found end of stream. */
 +	case LZMA_OK: /* Decompressor made some progress. */
 +		break;
 +	case LZMA_MEM_ERROR:
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Lzma library error: Cannot allocate memory");
 +		break;
 +	case LZMA_MEMLIMIT_ERROR:
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Lzma library error: Out of memory");
 +		break;
 +	case LZMA_FORMAT_ERROR:
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "Lzma library error: format not recognized");
 +		break;
 +	case LZMA_OPTIONS_ERROR:
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "Lzma library error: Invalid options");
 +		break;
 +	case LZMA_DATA_ERROR:
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "Lzma library error: Corrupted input data");
 +		break;
 +	case LZMA_BUF_ERROR:
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "Lzma library error:  No progress is possible");
 +		break;
 +	default:
 +		/* Return an error. */
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "Lzma decompression failed:  Unknown error");
 +		break;
 +	}
 +}
 +
 +#endif
 +
 +static unsigned long
 +decode_codec_id(const unsigned char *codecId, size_t id_size)
 +{
 +	unsigned i;
 +	unsigned long id = 0;
 +
 +	for (i = 0; i < id_size; i++) {
 +		id <<= 8;
 +		id += codecId[i];
 +	}
 +	return (id);
 +}
 +
 +static void *
 +ppmd_alloc(void *p, size_t size)
 +{
 +	(void)p;
 +	return malloc(size);
 +}
 +static void
 +ppmd_free(void *p, void *address)
 +{
 +	(void)p;
 +	free(address);
 +}
 +static Byte
 +ppmd_read(void *p)
 +{
 +	struct archive_read *a = ((IByteIn*)p)->a;
 +	struct _7zip *zip = (struct _7zip *)(a->format->data);
 +	Byte b;
 +
 +	if (zip->ppstream.avail_in == 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated RAR file data");
 +		zip->ppstream.overconsumed = 1;
 +		return (0);
 +	}
 +	b = *zip->ppstream.next_in++;
 +	zip->ppstream.avail_in--;
 +	zip->ppstream.total_in++;
 +	return (b);
 +}
 +
 +static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
 +
 +static int
 +init_decompression(struct archive_read *a, struct _7zip *zip,
 +    const struct _7z_coder *coder1, const struct _7z_coder *coder2)
 +{
 +	int r;
 +
 +	zip->codec = coder1->codec;
 +	zip->codec2 = -1;
 +
 +	switch (zip->codec) {
 +	case _7Z_COPY:
 +	case _7Z_BZ2:
 +	case _7Z_DEFLATE:
 +	case _7Z_PPMD:
 +		if (coder2 != NULL) {
 +			if (coder2->codec != _7Z_X86 &&
 +			    coder2->codec != _7Z_X86_BCJ2) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Unsupported filter %lx for %lx",
 +				    coder2->codec, coder1->codec);
 +				return (ARCHIVE_FAILED);
 +			}
 +			zip->codec2 = coder2->codec;
 +			zip->bcj_state = 0;
 +			if (coder2->codec == _7Z_X86)
 +				x86_Init(zip);
 +		}
 +		break;
 +	default:
 +		break;
 +	}
 +
 +	switch (zip->codec) {
 +	case _7Z_COPY:
 +		break;
 +
 +	case _7Z_LZMA: case _7Z_LZMA2:
 +#ifdef HAVE_LZMA_H
 +#if LZMA_VERSION_MAJOR >= 5
 +/* Effectively disable the limiter. */
 +#define LZMA_MEMLIMIT   UINT64_MAX
 +#else
 +/* NOTE: This needs to check memory size which running system has. */
 +#define LZMA_MEMLIMIT   (1U << 30)
 +#endif
 +	{
 +		lzma_options_delta delta_opt;
 +		lzma_filter filters[LZMA_FILTERS_MAX];
 +#if LZMA_VERSION < 50000030
 +		lzma_filter *ff;
 +#endif
 +		int fi = 0;
 +
 +		if (zip->lzstream_valid) {
 +			lzma_end(&(zip->lzstream));
 +			zip->lzstream_valid = 0;
 +		}
 +
 +		/*
 +		 * NOTE: liblzma incompletely handle the BCJ+LZMA compressed
 +		 * data made by 7-Zip because 7-Zip does not add End-Of-
 +		 * Payload Marker(EOPM) at the end of LZMA compressed data,
 +		 * and so liblzma cannot know the end of the compressed data
 +		 * without EOPM. So consequently liblzma will not return last
 +		 * three or four bytes of uncompressed data because
 +		 * LZMA_FILTER_X86 filter does not handle input data if its
 +		 * data size is less than five bytes. If liblzma detect EOPM
 +		 * or know the uncompressed data size, liblzma will flush out
 +		 * the remaining that three or four bytes of uncompressed
 +		 * data. That is why we have to use our converting program
 +		 * for BCJ+LZMA. If we were able to tell the uncompressed
 +		 * size to liblzma when using lzma_raw_decoder() liblzma
 +		 * could correctly deal with BCJ+LZMA. But unfortunately
 +		 * there is no way to do that. 
 +		 * Discussion about this can be found at XZ Utils forum.
 +		 */
 +		if (coder2 != NULL) {
 +			zip->codec2 = coder2->codec;
 +
 +			filters[fi].options = NULL;
 +			switch (zip->codec2) {
 +			case _7Z_X86:
 +				if (zip->codec == _7Z_LZMA2) {
 +					filters[fi].id = LZMA_FILTER_X86;
 +					fi++;
 +				} else
 +					/* Use our filter. */
 +					x86_Init(zip);
 +				break;
 +			case _7Z_X86_BCJ2:
 +				/* Use our filter. */
 +				zip->bcj_state = 0;
 +				break;
 +			case _7Z_DELTA:
 +				filters[fi].id = LZMA_FILTER_DELTA;
 +				memset(&delta_opt, 0, sizeof(delta_opt));
 +				delta_opt.type = LZMA_DELTA_TYPE_BYTE;
 +				delta_opt.dist = 1;
 +				filters[fi].options = &delta_opt;
 +				fi++;
 +				break;
 +			/* Following filters have not been tested yet. */
 +			case _7Z_POWERPC:
 +				filters[fi].id = LZMA_FILTER_POWERPC;
 +				fi++;
 +				break;
 +			case _7Z_IA64:
 +				filters[fi].id = LZMA_FILTER_IA64;
 +				fi++;
 +				break;
 +			case _7Z_ARM:
 +				filters[fi].id = LZMA_FILTER_ARM;
 +				fi++;
 +				break;
 +			case _7Z_ARMTHUMB:
 +				filters[fi].id = LZMA_FILTER_ARMTHUMB;
 +				fi++;
 +				break;
 +			case _7Z_SPARC:
 +				filters[fi].id = LZMA_FILTER_SPARC;
 +				fi++;
 +				break;
 +			default:
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Unexpected codec ID: %lX", zip->codec2);
 +				return (ARCHIVE_FAILED);
 +			}
 +		}
 +
 +		if (zip->codec == _7Z_LZMA2)
 +			filters[fi].id = LZMA_FILTER_LZMA2;
 +		else
 +			filters[fi].id = LZMA_FILTER_LZMA1;
 +		filters[fi].options = NULL;
 +#if LZMA_VERSION < 50000030
 +		ff = &filters[fi];
 +#endif
 +		r = lzma_properties_decode(&filters[fi], NULL,
- 		    coder1->properties, coder1->propertiesSize);
++		    coder1->properties, (size_t)coder1->propertiesSize);
 +		if (r != LZMA_OK) {
 +			set_error(a, r);
 +			return (ARCHIVE_FAILED);
 +		}
 +		fi++;
 +
 +		filters[fi].id = LZMA_VLI_UNKNOWN;
 +		filters[fi].options = NULL;
 +		r = lzma_raw_decoder(&(zip->lzstream), filters);
 +#if LZMA_VERSION < 50000030
 +		free(ff->options);
 +#endif
 +		if (r != LZMA_OK) {
 +			set_error(a, r);
 +			return (ARCHIVE_FAILED);
 +		}
 +		zip->lzstream_valid = 1;
 +		zip->lzstream.total_in = 0;
 +		zip->lzstream.total_out = 0;
 +		break;
 +	}
 +#else
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "LZMA codec is unsupported");
 +		return (ARCHIVE_FAILED);
 +#endif
 +	case _7Z_BZ2:
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +		if (zip->bzstream_valid) {
 +			BZ2_bzDecompressEnd(&(zip->bzstream));
 +			zip->bzstream_valid = 0;
 +		}
 +		r = BZ2_bzDecompressInit(&(zip->bzstream), 0, 0);
 +		if (r == BZ_MEM_ERROR)
 +			r = BZ2_bzDecompressInit(&(zip->bzstream), 0, 1);
 +		if (r != BZ_OK) {
 +			int err = ARCHIVE_ERRNO_MISC;
 +			const char *detail = NULL;
 +			switch (r) {
 +			case BZ_PARAM_ERROR:
 +				detail = "invalid setup parameter";
 +				break;
 +			case BZ_MEM_ERROR:
 +				err = ENOMEM;
 +				detail = "out of memory";
 +				break;
 +			case BZ_CONFIG_ERROR:
 +				detail = "mis-compiled library";
 +				break;
 +			}
 +			archive_set_error(&a->archive, err,
 +			    "Internal error initializing decompressor: %s",
 +			    detail != NULL ? detail : "??");
 +			zip->bzstream_valid = 0;
 +			return (ARCHIVE_FAILED);
 +		}
 +		zip->bzstream_valid = 1;
 +		zip->bzstream.total_in_lo32 = 0;
 +		zip->bzstream.total_in_hi32 = 0;
 +		zip->bzstream.total_out_lo32 = 0;
 +		zip->bzstream.total_out_hi32 = 0;
 +		break;
 +#else
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "BZ2 codec is unsupported");
 +		return (ARCHIVE_FAILED);
 +#endif
 +	case _7Z_DEFLATE:
 +#ifdef HAVE_ZLIB_H
 +		if (zip->stream_valid)
 +			r = inflateReset(&(zip->stream));
 +		else
 +			r = inflateInit2(&(zip->stream),
 +			    -15 /* Don't check for zlib header */);
 +		if (r != Z_OK) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Couldn't initialize zlib stream.");
 +			return (ARCHIVE_FAILED);
 +		}
 +		zip->stream_valid = 1;
 +		zip->stream.total_in = 0;
 +		zip->stream.total_out = 0;
 +		break;
 +#else
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "DEFLATE codec is unsupported");
 +		return (ARCHIVE_FAILED);
 +#endif
 +	case _7Z_PPMD:
 +	{
 +		unsigned order;
 +		uint32_t msize;
 +
 +		if (zip->ppmd7_valid) {
 +			__archive_ppmd7_functions.Ppmd7_Free(
 +			    &zip->ppmd7_context, &g_szalloc);
 +			zip->ppmd7_valid = 0;
 +		}
 +
 +		if (coder1->propertiesSize < 5) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Malformed PPMd parameter");
 +			return (ARCHIVE_FAILED);
 +		}
 +		order = coder1->properties[0];
 +		msize = archive_le32dec(&(coder1->properties[1]));
 +		if (order < PPMD7_MIN_ORDER || order > PPMD7_MAX_ORDER ||
 +		    msize < PPMD7_MIN_MEM_SIZE || msize > PPMD7_MAX_MEM_SIZE) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Malformed PPMd parameter");
 +			return (ARCHIVE_FAILED);
 +		}
 +		__archive_ppmd7_functions.Ppmd7_Construct(&zip->ppmd7_context);
 +		r = __archive_ppmd7_functions.Ppmd7_Alloc(
 +			&zip->ppmd7_context, msize, &g_szalloc);
 +		if (r == 0) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Coludn't allocate memory for PPMd");
 +			return (ARCHIVE_FATAL);
 +		}
 +		__archive_ppmd7_functions.Ppmd7_Init(
 +			&zip->ppmd7_context, order);
 +		__archive_ppmd7_functions.Ppmd7z_RangeDec_CreateVTable(
 +			&zip->range_dec);
 +		zip->ppmd7_valid = 1;
 +		zip->ppmd7_stat = 0;
 +		zip->ppstream.overconsumed = 0;
 +		zip->ppstream.total_in = 0;
 +		zip->ppstream.total_out = 0;
 +		break;
 +	}
 +	case _7Z_X86:
 +	case _7Z_X86_BCJ2:
 +	case _7Z_POWERPC:
 +	case _7Z_IA64:
 +	case _7Z_ARM:
 +	case _7Z_ARMTHUMB:
 +	case _7Z_SPARC:
 +	case _7Z_DELTA:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Unexpected codec ID: %lX", zip->codec);
 +		return (ARCHIVE_FAILED);
 +	default:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Unknown codec ID: %lX", zip->codec);
 +		return (ARCHIVE_FAILED);
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +decompress(struct archive_read *a, struct _7zip *zip,
 +    void *buff, size_t *outbytes, const void *b, size_t *used)
 +{
 +	const uint8_t *t_next_in;
 +	uint8_t *t_next_out;
 +	size_t o_avail_in, o_avail_out;
 +	size_t t_avail_in, t_avail_out;
 +	uint8_t *bcj2_next_out;
 +	size_t bcj2_avail_out;
 +	int r, ret = ARCHIVE_OK;
 +
 +	t_avail_in = o_avail_in = *used;
 +	t_avail_out = o_avail_out = *outbytes;
 +	t_next_in = b;
 +	t_next_out = buff;
 +
 +	if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) {
 +		int i;
 +
 +		/* Do not copy out the BCJ remaining bytes when the output
 +		 * buffer size is less than five bytes. */
 +		if (o_avail_in != 0 && t_avail_out < 5 && zip->odd_bcj_size) {
 +			*used = 0;
 +			*outbytes = 0;
 +			return (ret);
 +		}
 +		for (i = 0; zip->odd_bcj_size > 0 && t_avail_out; i++) {
 +			*t_next_out++ = zip->odd_bcj[i];
 +			t_avail_out--;
 +			zip->odd_bcj_size--;
 +		}
 +		if (o_avail_in == 0 || t_avail_out == 0) {
 +			*used = o_avail_in - t_avail_in;
 +			*outbytes = o_avail_out - t_avail_out;
 +			if (o_avail_in == 0)
 +				ret = ARCHIVE_EOF;
 +			return (ret);
 +		}
 +	}
 +
 +	bcj2_next_out = t_next_out;
 +	bcj2_avail_out = t_avail_out;
 +	if (zip->codec2 == _7Z_X86_BCJ2) {
 +		/*
 +		 * Decord a remaining decompressed main stream for BCJ2.
 +		 */
 +		if (zip->tmp_stream_bytes_remaining) {
 +			ssize_t bytes;
 +			size_t remaining = zip->tmp_stream_bytes_remaining;
 +			bytes = Bcj2_Decode(zip, t_next_out, t_avail_out);
 +			if (bytes < 0) {
 +				archive_set_error(&(a->archive),
 +				    ARCHIVE_ERRNO_MISC,
 +				    "BCJ2 conversion Failed");
 +				return (ARCHIVE_FAILED);
 +			}
 +			zip->main_stream_bytes_remaining -=
 +			    remaining - zip->tmp_stream_bytes_remaining;
 +			t_avail_out -= bytes;
 +			if (o_avail_in == 0 || t_avail_out == 0) {
 +				*used = 0;
 +				*outbytes = o_avail_out - t_avail_out;
 +				if (o_avail_in == 0 &&
 +				    zip->tmp_stream_bytes_remaining)
 +					ret = ARCHIVE_EOF;
 +				return (ret);
 +			}
 +			t_next_out += bytes;
 +			bcj2_next_out = t_next_out;
 +			bcj2_avail_out = t_avail_out;
 +		}
 +		t_next_out = zip->tmp_stream_buff;
 +		t_avail_out = zip->tmp_stream_buff_size;
 +	}
 +
 +	switch (zip->codec) {
 +	case _7Z_COPY:
 +	{
 +		size_t bytes =
 +		    (t_avail_in > t_avail_out)?t_avail_out:t_avail_in;
 +
 +		memcpy(t_next_out, t_next_in, bytes);
 +		t_avail_in -= bytes;
 +		t_avail_out -= bytes;
 +		if (o_avail_in == 0)
 +			ret = ARCHIVE_EOF;
 +		break;
 +	}
 +#ifdef HAVE_LZMA_H
 +	case _7Z_LZMA: case _7Z_LZMA2:
 +		zip->lzstream.next_in = t_next_in;
 +		zip->lzstream.avail_in = t_avail_in;
 +		zip->lzstream.next_out = t_next_out;
 +		zip->lzstream.avail_out = t_avail_out;
 +
 +		r = lzma_code(&(zip->lzstream), LZMA_RUN);
 +		switch (r) {
 +		case LZMA_STREAM_END: /* Found end of stream. */
 +			lzma_end(&(zip->lzstream));
 +			zip->lzstream_valid = 0;
 +			ret = ARCHIVE_EOF;
 +			break;
 +		case LZMA_OK: /* Decompressor made some progress. */
 +			break;
 +		default:
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +				"Decompression failed(%d)",
 +			    r);
 +			return (ARCHIVE_FAILED);
 +		}
 +		t_avail_in = zip->lzstream.avail_in;
 +		t_avail_out = zip->lzstream.avail_out;
 +		break;
 +#endif
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	case _7Z_BZ2:
 +		zip->bzstream.next_in = (char *)(uintptr_t)t_next_in;
 +		zip->bzstream.avail_in = t_avail_in;
 +		zip->bzstream.next_out = (char *)(uintptr_t)t_next_out;
 +		zip->bzstream.avail_out = t_avail_out;
 +		r = BZ2_bzDecompress(&(zip->bzstream));
 +		switch (r) {
 +		case BZ_STREAM_END: /* Found end of stream. */
 +			switch (BZ2_bzDecompressEnd(&(zip->bzstream))) {
 +			case BZ_OK:
 +				break;
 +			default:
 +				archive_set_error(&(a->archive),
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Failed to clean up decompressor");
 +				return (ARCHIVE_FAILED);
 +			}
 +			zip->bzstream_valid = 0;
 +			ret = ARCHIVE_EOF;
 +			break;
 +		case BZ_OK: /* Decompressor made some progress. */
 +			break;
 +		default:
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "bzip decompression failed");
 +			return (ARCHIVE_FAILED);
 +		}
 +		t_avail_in = zip->bzstream.avail_in;
 +		t_avail_out = zip->bzstream.avail_out;
 +		break;
 +#endif
 +#ifdef HAVE_ZLIB_H
 +	case _7Z_DEFLATE:
 +		zip->stream.next_in = (Bytef *)(uintptr_t)t_next_in;
- 		zip->stream.avail_in = t_avail_in;
++		zip->stream.avail_in = (uInt)t_avail_in;
 +		zip->stream.next_out = t_next_out;
- 		zip->stream.avail_out = t_avail_out;
++		zip->stream.avail_out = (uInt)t_avail_out;
 +		r = inflate(&(zip->stream), 0);
 +		switch (r) {
 +		case Z_STREAM_END: /* Found end of stream. */
 +			ret = ARCHIVE_EOF;
 +			break;
 +		case Z_OK: /* Decompressor made some progress.*/
 +			break;
 +		default:
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "File decompression failed (%d)", r);
 +			return (ARCHIVE_FAILED);
 +		}
 +		t_avail_in = zip->stream.avail_in;
 +		t_avail_out = zip->stream.avail_out;
 +		break;
 +#endif
 +	case _7Z_PPMD:
 +	{
 +		uint64_t flush_bytes;
 +
 +		if (!zip->ppmd7_valid || zip->ppmd7_stat < 0 ||
- 		    t_avail_in < 0 || t_avail_out <= 0) {
++		    t_avail_out <= 0) {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Decompression internal error");
 +			return (ARCHIVE_FAILED);
 +		}
 +		zip->ppstream.next_in = t_next_in;
 +		zip->ppstream.avail_in = t_avail_in;
 +		zip->ppstream.next_out = t_next_out;
 +		zip->ppstream.avail_out = t_avail_out;
 +		if (zip->ppmd7_stat == 0) {
 +			zip->bytein.a = a;
 +			zip->bytein.Read = &ppmd_read;
 +			zip->range_dec.Stream = &zip->bytein;
 +			r = __archive_ppmd7_functions.Ppmd7z_RangeDec_Init(
 +				&(zip->range_dec));
 +			if (r == 0) {
 +				zip->ppmd7_stat = -1;
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Failed to initialize PPMd range decorder");
 +				return (ARCHIVE_FAILED);
 +			}
 +			if (zip->ppstream.overconsumed) {
 +				zip->ppmd7_stat = -1;
 +				return (ARCHIVE_FAILED);
 +			}
 +			zip->ppmd7_stat = 1;
 +		}
 +
 +		if (t_avail_in == 0)
 +			/* XXX Flush out remaining decoded data XXX */
 +			flush_bytes = zip->folder_outbytes_remaining;
 +		else
 +			flush_bytes = 0;
 +
 +		do {
 +			int sym;
 +			
 +			sym = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
 +				&(zip->ppmd7_context), &(zip->range_dec.p));
 +			if (sym < 0) {
 +				zip->ppmd7_stat = -1;
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_FILE_FORMAT,
 +				    "Failed to decode PPMd");
 +				return (ARCHIVE_FAILED);
 +			}
 +			if (zip->ppstream.overconsumed) {
 +				zip->ppmd7_stat = -1;
 +				return (ARCHIVE_FAILED);
 +			}
 +			*zip->ppstream.next_out++ = (unsigned char)sym;
 +			zip->ppstream.avail_out--;
 +			zip->ppstream.total_out++;
 +			if (flush_bytes)
 +				flush_bytes--;
 +		} while (zip->ppstream.avail_out &&
 +			(zip->ppstream.avail_in || flush_bytes));
 +
- 		t_avail_in = zip->ppstream.avail_in;
- 		t_avail_out = zip->ppstream.avail_out;
++		t_avail_in = (size_t)zip->ppstream.avail_in;
++		t_avail_out = (size_t)zip->ppstream.avail_out;
 +		break;
 +	}
 +	default:
 +		archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
 +		    "Decompression internal error");
 +		return (ARCHIVE_FAILED);
 +	}
 +	if (ret != ARCHIVE_OK && ret != ARCHIVE_EOF)
 +		return (ret);
 +
 +	*used = o_avail_in - t_avail_in;
 +	*outbytes = o_avail_out - t_avail_out;
 +
 +	/*
 +	 * Decord BCJ.
 +	 */
 +	if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) {
 +		size_t l = x86_Convert(zip, buff, *outbytes);
 +		zip->odd_bcj_size = *outbytes - l;
 +		if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 &&
 +		    o_avail_in && ret != ARCHIVE_EOF) {
 +			memcpy(zip->odd_bcj, ((unsigned char *)buff) + l,
 +			    zip->odd_bcj_size);
 +			*outbytes = l;
 +		} else
 +			zip->odd_bcj_size = 0;
 +	}
 +
 +	/*
 +	 * Decord BCJ2 with a decompressed main stream.
 +	 */
 +	if (zip->codec2 == _7Z_X86_BCJ2) {
 +		ssize_t bytes;
 +
 +		zip->tmp_stream_bytes_avail =
 +		    zip->tmp_stream_buff_size - t_avail_out;
 +		if (zip->tmp_stream_bytes_avail >
 +		      zip->main_stream_bytes_remaining)
 +			zip->tmp_stream_bytes_avail =
 +			    zip->main_stream_bytes_remaining;
 +		zip->tmp_stream_bytes_remaining = zip->tmp_stream_bytes_avail;
 +		bytes = Bcj2_Decode(zip, bcj2_next_out, bcj2_avail_out);
 +		if (bytes < 0) {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC, "BCJ2 conversion Failed");
 +			return (ARCHIVE_FAILED);
 +		}
 +		zip->main_stream_bytes_remaining -=
 +		    zip->tmp_stream_bytes_avail
 +		      - zip->tmp_stream_bytes_remaining;
 +		bcj2_avail_out -= bytes;
 +		*outbytes = o_avail_out - bcj2_avail_out;
 +	}
 +
 +	return (ret);
 +}
 +
 +static int
 +free_decompression(struct archive_read *a, struct _7zip *zip)
 +{
 +	int r = ARCHIVE_OK;
 +
++#if !defined(HAVE_ZLIB_H) &&\
++	!(defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR))
++	(void)a;/* UNUSED */
++#endif
 +#ifdef HAVE_LZMA_H
 +	if (zip->lzstream_valid)
 +		lzma_end(&(zip->lzstream));
 +#endif
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	if (zip->bzstream_valid) {
 +		if (BZ2_bzDecompressEnd(&(zip->bzstream)) != BZ_OK) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Failed to clean up bzip2 decompressor");
 +			r = ARCHIVE_FATAL;
 +		}
 +		zip->bzstream_valid = 0;
 +	}
 +#endif
 +#ifdef HAVE_ZLIB_H
 +	if (zip->stream_valid) {
 +		if (inflateEnd(&(zip->stream)) != Z_OK) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Failed to clean up zlib decompressor");
 +			r = ARCHIVE_FATAL;
 +		}
 +		zip->stream_valid = 0;
 +	}
 +#endif
 +	if (zip->ppmd7_valid) {
 +		__archive_ppmd7_functions.Ppmd7_Free(
 +			&zip->ppmd7_context, &g_szalloc);
 +		zip->ppmd7_valid = 0;
 +	}
 +	return (r);
 +}
 +
 +static int
 +parse_7zip_uint64(struct archive_read *a, uint64_t *val)
 +{
 +	const unsigned char *p;
 +	unsigned char avail, mask;
 +	int i;
 +
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		return (-1);
 +	avail = *p;
 +	mask = 0x80;
 +	*val = 0;
 +	for (i = 0; i < 8; i++) {
 +		if (avail & mask) {
 +			if ((p = header_bytes(a, 1)) == NULL)
 +				return (-1);
 +			*val |= ((uint64_t)*p) << (8 * i);
 +			mask >>= 1;
 +			continue;
 +		}
 +		*val += (avail & (mask -1)) << (8 * i);
 +		break;
 +	}
 +	return (0);
 +}
 +
 +static int
 +read_Bools(struct archive_read *a, unsigned char *data, size_t num)
 +{
 +	const unsigned char *p;
 +	unsigned i, mask = 0, avail = 0;
 +
 +	for (i = 0; i < num; i++) {
 +		if (mask == 0) {
 +			if ((p = header_bytes(a, 1)) == NULL)
 +				return (-1);
 +			avail = *p;
 +			mask = 0x80;
 +		}
 +		data[i] = (avail & mask)?1:0;
 +		mask >>= 1;
 +	}
 +	return (0);
 +}
 +
 +static void
 +free_Digest(struct _7z_digests *d)
 +{
 +	free(d->defineds);
 +	free(d->digests);
 +}
 +
 +static int
 +read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num)
 +{
 +	const unsigned char *p;
 +	unsigned i;
 +
++	if (num == 0)
++		return (-1);
 +	memset(d, 0, sizeof(*d));
 +
- 
 +	d->defineds = malloc(num);
 +	if (d->defineds == NULL)
 +		return (-1);
 +	/*
 +	 * Read Bools.
 +	 */
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		return (-1);
 +	if (*p == 0) {
 +		if (read_Bools(a, d->defineds, num) < 0)
 +			return (-1);
 +	} else
 +		/* All are defined */
 +		memset(d->defineds, 1, num);
 +
 +	d->digests = calloc(num, sizeof(*d->digests));
 +	if (d->digests == NULL)
 +		return (-1);
 +	for (i = 0; i < num; i++) {
 +		if (d->defineds[i]) {
 +			if ((p = header_bytes(a, 4)) == NULL)
 +				return (-1);
 +			d->digests[i] = archive_le32dec(p);
 +		}
 +	}
 +
 +	return (0);
 +}
 +
 +static void
 +free_PackInfo(struct _7z_pack_info *pi)
 +{
 +	free(pi->sizes);
 +	free(pi->positions);
 +	free_Digest(&(pi->digest));
 +}
 +
 +static int
 +read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
 +{
 +	const unsigned char *p;
 +	unsigned i;
 +
 +	memset(pi, 0, sizeof(*pi));
 +
 +	/*
 +	 * Read PackPos.
 +	 */
 +	if (parse_7zip_uint64(a, &(pi->pos)) < 0)
 +		return (-1);
 +
 +	/*
 +	 * Read NumPackStreams.
 +	 */
 +	if (parse_7zip_uint64(a, &(pi->numPackStreams)) < 0)
 +		return (-1);
 +	if (pi->numPackStreams == 0)
 +		return (-1);
 +	if (1000000 < pi->numPackStreams)
 +		return (-1);
 +
 +	/*
 +	 * Read PackSizes[num]
 +	 */
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		return (-1);
 +	if (*p == kEnd)
 +		/* PackSizes[num] are not present. */
 +		return (0);
 +	if (*p != kSize)
 +		return (-1);
- 	pi->sizes = calloc(pi->numPackStreams, sizeof(uint64_t));
- 	pi->positions = calloc(pi->numPackStreams, sizeof(uint64_t));
++	pi->sizes = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
++	pi->positions = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
 +	if (pi->sizes == NULL || pi->positions == NULL)
 +		return (-1);
 +
 +	for (i = 0; i < pi->numPackStreams; i++) {
 +		if (parse_7zip_uint64(a, &(pi->sizes[i])) < 0)
 +			return (-1);
 +	}
 +
 +	/*
 +	 * Read PackStreamDigests[num]
 +	 */
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		return (-1);
 +	if (*p == kEnd) {
 +		/* PackStreamDigests[num] are not present. */
 +		pi->digest.defineds =
- 		    calloc(pi->numPackStreams, sizeof(*pi->digest.defineds));
++		    calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));
 +		pi->digest.digests =
- 		    calloc(pi->numPackStreams, sizeof(*pi->digest.digests));
++		    calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests));
 +		if (pi->digest.defineds == NULL || pi->digest.digests == NULL)
 +			return (-1);
 +		return (0);
 +	}
 +
 +	if (*p != kSize)
 +		return (-1);
 +
- 	if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0)
++	if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)
 +		return (-1);
 +
 +	/*
 +	 *  Must be marked by kEnd.
 +	 */
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		return (-1);
 +	if (*p != kEnd)
 +		return (-1);
 +	return (0);
 +}
 +
 +static void
 +free_Folder(struct _7z_folder *f)
 +{
 +	unsigned i;
 +
 +	if (f->coders) {
 +		for (i = 0; i< f->numCoders; i++) {
 +			free(f->coders[i].properties);
 +		}
 +		free(f->coders);
 +	}
 +	free(f->bindPairs);
 +	free(f->packedStreams);
 +	free(f->unPackSize);
 +}
 +
 +static int
 +read_Folder(struct archive_read *a, struct _7z_folder *f)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	const unsigned char *p;
 +	uint64_t numInStreamsTotal = 0;
 +	uint64_t numOutStreamsTotal = 0;
 +	unsigned i;
 +
 +	memset(f, 0, sizeof(*f));
 +
 +	/*
 +	 * Read NumCoders.
 +	 */
 +	if (parse_7zip_uint64(a, &(f->numCoders)) < 0)
 +		return (-1);
 +	if (f->numCoders > 4)
 +		/* Too many coders. */
 +		return (-1);
 +
- 	f->coders = calloc(f->numCoders, sizeof(*f->coders));
++	f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders));
 +	if (f->coders == NULL)
 +		return (-1);
 +	for (i = 0; i< f->numCoders; i++) {
 +		size_t codec_size;
 +		int simple, attr;
 +
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +		/*
 +		 * 0:3 CodecIdSize
 +		 * 4:  0 - IsSimple
 +		 *     1 - Is not Simple
 +		 * 5:  0 - No Attributes
 +		 *     1 - There are Attributes;
 +		 * 7:  Must be zero.
 +		 */
 +		codec_size = *p & 0xf;
 +		simple = (*p & 0x10)?0:1;
 +		attr = *p & 0x20;
 +		if (*p & 0x80)
 +			return (-1);/* Not supported. */
 +
 +		/*
 +		 * Read Decompression Method IDs.
 +		 */
 +		if ((p = header_bytes(a, codec_size)) == NULL)
 +			return (-1);
 +
 +		f->coders[i].codec = decode_codec_id(p, codec_size);
 +
 +		if (simple) {
 +			f->coders[i].numInStreams = 1;
 +			f->coders[i].numOutStreams = 1;
 +		} else {
 +			if (parse_7zip_uint64(
 +			    a, &(f->coders[i].numInStreams)) < 0)
 +				return (-1);
 +			if (1000000 < f->coders[i].numInStreams)
 +				return (-1);
 +			if (parse_7zip_uint64(
 +			    a, &(f->coders[i].numOutStreams)) < 0)
 +				return (-1);
 +			if (1000000 < f->coders[i].numOutStreams)
 +				return (-1);
 +		}
 +
 +		if (attr) {
 +			if (parse_7zip_uint64(
 +			    a, &(f->coders[i].propertiesSize)) < 0)
 +				return (-1);
 +			if ((p = header_bytes(
- 			    a, f->coders[i].propertiesSize)) == NULL)
++			    a, (size_t)f->coders[i].propertiesSize)) == NULL)
 +				return (-1);
 +			f->coders[i].properties =
- 			    malloc(f->coders[i].propertiesSize);
++			    malloc((size_t)f->coders[i].propertiesSize);
 +			if (f->coders[i].properties == NULL)
 +				return (-1);
 +			memcpy(f->coders[i].properties, p,
- 			    f->coders[i].propertiesSize);
++			    (size_t)f->coders[i].propertiesSize);
 +		}
 +
 +		numInStreamsTotal += f->coders[i].numInStreams;
 +		numOutStreamsTotal += f->coders[i].numOutStreams;
 +	}
 +
 +	if (numOutStreamsTotal == 0 ||
 +	    numInStreamsTotal < numOutStreamsTotal-1)
 +		return (-1);
 +
 +	f->numBindPairs = numOutStreamsTotal - 1;
 +	if (zip->header_bytes_remaining < f->numBindPairs)
 +			return (-1);
- 	f->bindPairs = calloc(f->numBindPairs, sizeof(*f->bindPairs));
- 	if (f->bindPairs == NULL)
- 		return (-1);
++	if (f->numBindPairs > 0) {
++		f->bindPairs =
++			calloc((size_t)f->numBindPairs, sizeof(*f->bindPairs));
++		if (f->bindPairs == NULL)
++			return (-1);
++	} else
++		f->bindPairs = NULL;
 +	for (i = 0; i < f->numBindPairs; i++) {
 +		if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
 +			return (-1);
 +		if (1000000 < f->bindPairs[i].inIndex)
 +			return (-1);
 +		if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)
 +			return (-1);
 +		if (1000000 < f->bindPairs[i].outIndex)
 +			return (-1);
 +	}
 +
 +	f->numPackedStreams = numInStreamsTotal - f->numBindPairs;
 +	f->packedStreams =
- 	    calloc(f->numPackedStreams, sizeof(*f->packedStreams));
++	    calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams));
 +	if (f->packedStreams == NULL)
 +		return (-1);
 +	if (f->numPackedStreams == 1) {
 +		for (i = 0; i < numInStreamsTotal; i++) {
 +			unsigned j;
 +			for (j = 0; j < f->numBindPairs; j++) {
 +				if (f->bindPairs[j].inIndex == i)
 +					break;
 +			}
 +			if (j == f->numBindPairs)
 +				break;
 +		}
 +		if (i == numInStreamsTotal)
 +			return (-1);
 +		f->packedStreams[0] = i;
 +	} else {
 +		for (i = 0; i < f->numPackedStreams; i++) {
 +			if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
 +				return (-1);
 +			if (1000000 < f->packedStreams[i])
 +				return (-1);
 +		}
 +	}
 +	f->numInStreams = numInStreamsTotal;
 +	f->numOutStreams = numOutStreamsTotal;
 +
 +	return (0);
 +}
 +
 +static void
 +free_CodersInfo(struct _7z_coders_info *ci)
 +{
 +	unsigned i;
 +
 +	if (ci->folders) {
 +		for (i = 0; i < ci->numFolders; i++)
 +			free_Folder(&(ci->folders[i]));
 +		free(ci->folders);
 +	}
 +}
 +
 +static int
 +read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
 +{
 +	const unsigned char *p;
 +	struct _7z_digests digest;
 +	unsigned i;
 +
 +	memset(ci, 0, sizeof(*ci));
 +	memset(&digest, 0, sizeof(digest));
 +
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
 +	if (*p != kFolder)
 +		goto failed;
 +
 +	/*
 +	 * Read NumFolders.
 +	 */
 +	if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
 +		goto failed;
 +	if (1000000 < ci->numFolders)
 +			return (-1);
 +
 +	/*
 +	 * Read External.
 +	 */
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
 +	switch (*p) {
 +	case 0:
- 		ci->folders = calloc(ci->numFolders, sizeof(*ci->folders));
++		ci->folders =
++			calloc((size_t)ci->numFolders, sizeof(*ci->folders));
 +		if (ci->folders == NULL)
 +			return (-1);
 +		for (i = 0; i < ci->numFolders; i++) {
 +			if (read_Folder(a, &(ci->folders[i])) < 0)
 +				goto failed;
 +		}
 +		break;
 +	case 1:
 +		if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
 +			return (-1);
 +		if (1000000 < ci->dataStreamIndex)
 +			return (-1);
 +		break;
 +	}
 +
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
 +	if (*p != kCodersUnPackSize)
 +		goto failed;
 +
 +	for (i = 0; i < ci->numFolders; i++) {
 +		struct _7z_folder *folder = &(ci->folders[i]);
 +		unsigned j;
 +
 +		folder->unPackSize =
- 		    calloc(folder->numOutStreams, sizeof(*folder->unPackSize));
++		    calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));
 +		if (folder->unPackSize == NULL)
 +			goto failed;
 +		for (j = 0; j < folder->numOutStreams; j++) {
 +			if (parse_7zip_uint64(a, &(folder->unPackSize[j])) < 0)
 +				goto failed;
 +		}
 +	}
 +
 +	/*
 +	 * Read CRCs.
 +	 */
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
 +	if (*p == kEnd)
 +		return (0);
 +	if (*p != kCRC)
 +		goto failed;
- 	if (read_Digests(a, &digest, ci->numFolders) < 0)
++	if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)
 +		goto failed;
 +	for (i = 0; i < ci->numFolders; i++) {
 +		ci->folders[i].digest_defined = digest.defineds[i];
 +		ci->folders[i].digest = digest.digests[i];
 +	}
 +
 +	/*
 +	 *  Must be kEnd.
 +	 */
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
 +	if (*p != kEnd)
 +		goto failed;
 +	free_Digest(&digest);
 +	return (0);
 +failed:
 +	free_Digest(&digest);
 +	return (-1);
 +}
 +
 +static uint64_t
 +folder_uncompressed_size(struct _7z_folder *f)
 +{
- 	int n = f->numOutStreams;
- 	unsigned pairs = f->numBindPairs;
++	int n = (int)f->numOutStreams;
++	unsigned pairs = (unsigned)f->numBindPairs;
 +
 +	while (--n >= 0) {
 +		unsigned i;
 +		for (i = 0; i < pairs; i++) {
- 			if (f->bindPairs[i].outIndex == n)
++			if (f->bindPairs[i].outIndex == (uint64_t)n)
 +				break;
 +		}
 +		if (i >= pairs)
 +			return (f->unPackSize[n]);
 +	}
 +	return (0);
 +}
 +
 +static void
 +free_SubStreamsInfo(struct _7z_substream_info *ss)
 +{
 +	free(ss->unpackSizes);
 +	free(ss->digestsDefined);
 +	free(ss->digests);
 +}
 +
 +static int
 +read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
 +    struct _7z_folder *f, size_t numFolders)
 +{
 +	const unsigned char *p;
 +	uint64_t *usizes;
 +	size_t unpack_streams;
 +	int type;
 +	unsigned i;
 +	uint32_t numDigests;
 +
 +	memset(ss, 0, sizeof(*ss));
 +
 +	for (i = 0; i < numFolders; i++)
 +		f[i].numUnpackStreams = 1;
 +
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		return (-1);
 +	type = *p;
 +
 +	if (type == kNumUnPackStream) {
 +		unpack_streams = 0;
 +		for (i = 0; i < numFolders; i++) {
 +			if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
 +				return (-1);
 +			if (1000000 < f[i].numUnpackStreams)
 +				return (-1);
- 			unpack_streams += f[i].numUnpackStreams;
++			unpack_streams += (size_t)f[i].numUnpackStreams;
 +		}
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +		type = *p;
 +	} else
 +		unpack_streams = numFolders;
 +
 +	ss->unpack_streams = unpack_streams;
 +	if (unpack_streams) {
 +		ss->unpackSizes = calloc(unpack_streams,
 +		    sizeof(*ss->unpackSizes));
 +		ss->digestsDefined = calloc(unpack_streams,
 +		    sizeof(*ss->digestsDefined));
 +		ss->digests = calloc(unpack_streams,
 +		    sizeof(*ss->digests));
 +		if (ss->unpackSizes == NULL || ss->digestsDefined == NULL ||
 +		    ss->digests == NULL)
 +			return (-1);
 +	}
 +
 +	usizes = ss->unpackSizes;
 +	for (i = 0; i < numFolders; i++) {
 +		unsigned pack;
 +		uint64_t sum;
 +
 +		if (f[i].numUnpackStreams == 0)
 +			continue;
 +
 +		sum = 0;
 +		if (type == kSize) {
 +			for (pack = 1; pack < f[i].numUnpackStreams; pack++) {
 +				if (parse_7zip_uint64(a, usizes) < 0)
 +					return (-1);
 +				sum += *usizes++;
 +			}
 +		}
 +		*usizes++ = folder_uncompressed_size(&f[i]) - sum;
 +	}
 +
 +	if (type == kSize) {
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +		type = *p;
 +	}
 +
 +	for (i = 0; i < unpack_streams; i++) {
 +		ss->digestsDefined[i] = 0;
 +		ss->digests[i] = 0;
 +	}
 +
 +	numDigests = 0;
 +	for (i = 0; i < numFolders; i++) {
 +		if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)
- 			numDigests += f[i].numUnpackStreams;
++			numDigests += (uint32_t)f[i].numUnpackStreams;
 +	}
 +
 +	if (type == kCRC) {
 +		struct _7z_digests tmpDigests;
 +		unsigned char *digestsDefined = ss->digestsDefined;
 +		uint32_t * digests = ss->digests;
 +		int di = 0;
 +
 +		memset(&tmpDigests, 0, sizeof(tmpDigests));
 +		if (read_Digests(a, &(tmpDigests), numDigests) < 0) {
 +			free_Digest(&tmpDigests);
 +			return (-1);
 +		}
 +		for (i = 0; i < numFolders; i++) {
 +			if (f[i].numUnpackStreams == 1 && f[i].digest_defined) {
 +				*digestsDefined++ = 1;
 +				*digests++ = f[i].digest;
 +			} else {
 +				unsigned j;
 +
 +				for (j = 0; j < f[i].numUnpackStreams;
 +				    j++, di++) {
 +					*digestsDefined++ =
 +					    tmpDigests.defineds[di];
 +					*digests++ =
 +					    tmpDigests.digests[di];
 +				}
 +			}
 +		}
 +		free_Digest(&tmpDigests);
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +		type = *p;
 +	}
 +
 +	/*
 +	 *  Must be kEnd.
 +	 */
 +	if (type != kEnd)
 +		return (-1);
 +	return (0);
 +}
 +
 +static void
 +free_StreamsInfo(struct _7z_stream_info *si)
 +{
 +	free_PackInfo(&(si->pi));
 +	free_CodersInfo(&(si->ci));
 +	free_SubStreamsInfo(&(si->ss));
 +}
 +
 +static int
 +read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	const unsigned char *p;
 +	unsigned i;
 +
 +	memset(si, 0, sizeof(*si));
 +
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		return (-1);
 +	if (*p == kPackInfo) {
 +		uint64_t packPos;
 +
 +		if (read_PackInfo(a, &(si->pi)) < 0)
 +			return (-1);
 +
 +		if (si->pi.positions == NULL || si->pi.sizes == NULL)
 +			return (-1);
 +		/*
 +		 * Calculate packed stream positions.
 +		 */
 +		packPos = si->pi.pos;
 +		for (i = 0; i < si->pi.numPackStreams; i++) {
 +			si->pi.positions[i] = packPos;
 +			packPos += si->pi.sizes[i];
 +			if (packPos > zip->header_offset)
 +				return (-1);
 +		}
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +	}
 +	if (*p == kUnPackInfo) {
 +		uint32_t packIndex;
 +		struct _7z_folder *f;
 +
 +		if (read_CodersInfo(a, &(si->ci)) < 0)
 +			return (-1);
 +
 +		/*
 +		 * Calculate packed stream indexes.
 +		 */
 +		packIndex = 0;
 +		f = si->ci.folders;
 +		for (i = 0; i < si->ci.numFolders; i++) {
 +			f[i].packIndex = packIndex;
- 			packIndex += f[i].numPackedStreams;
++			packIndex += (uint32_t)f[i].numPackedStreams;
 +			if (packIndex > si->pi.numPackStreams)
 +				return (-1);
 +		}
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +	}
 +
 +	if (*p == kSubStreamsInfo) {
 +		if (read_SubStreamsInfo(a, &(si->ss),
- 		    si->ci.folders, si->ci.numFolders) < 0)
++		    si->ci.folders, (size_t)si->ci.numFolders) < 0)
 +			return (-1);
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +	}
 +
 +	/*
 +	 *  Must be kEnd.
 +	 */
 +	if (*p != kEnd)
 +		return (-1);
 +	return (0);
 +}
 +
 +static void
 +free_Header(struct _7z_header_info *h)
 +{
 +	free(h->emptyStreamBools);
 +	free(h->emptyFileBools);
 +	free(h->antiBools);
 +	free(h->attrBools);
 +}
 +
 +static int
 +read_Header(struct archive_read *a, struct _7z_header_info *h,
 +    int check_header_id)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	const unsigned char *p;
 +	struct _7z_folder *folders;
 +	struct _7z_stream_info *si = &(zip->si);
 +	struct _7zip_entry *entries;
 +	uint32_t folderIndex, indexInFolder;
 +	unsigned i;
 +	int eindex, empty_streams, sindex;
 +
 +	if (check_header_id) {
 +		/*
 +		 * Read Header.
 +		 */
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +		if (*p != kHeader)
 +			return (-1);
 +	}
 +
 +	/*
 +	 * Read ArchiveProperties.
 +	 */
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		return (-1);
 +	if (*p == kArchiveProperties) {
 +		for (;;) {
 +			uint64_t size;
 +			if ((p = header_bytes(a, 1)) == NULL)
 +				return (-1);
 +			if (*p == 0)
 +				break;
 +			if (parse_7zip_uint64(a, &size) < 0)
 +				return (-1);
 +		}
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +	}
 +
 +	/*
 +	 * Read MainStreamsInfo.
 +	 */
 +	if (*p == kMainStreamsInfo) {
 +		if (read_StreamsInfo(a, &(zip->si)) < 0)
 +			return (-1);
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +	}
 +	if (*p == kEnd)
 +		return (0);
 +
 +	/*
 +	 * Read FilesInfo.
 +	 */
 +	if (*p != kFilesInfo)
 +		return (-1);
 +
 +	if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
 +		return (-1);
 +	if (1000000 < zip->numFiles)
 +			return (-1);
 +
- 	zip->entries = calloc(zip->numFiles, sizeof(*zip->entries));
++	zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
 +	if (zip->entries == NULL)
 +		return (-1);
 +	entries = zip->entries;
 +
 +	empty_streams = 0;
 +	for (;;) {
 +		int type;
 +		uint64_t size;
 +		size_t ll;
 +
 +		if ((p = header_bytes(a, 1)) == NULL)
 +			return (-1);
 +		type = *p;
 +		if (type == kEnd)
 +			break;
 +
 +		if (parse_7zip_uint64(a, &size) < 0)
 +			return (-1);
 +		if (zip->header_bytes_remaining < size)
 +			return (-1);
 +		ll = (size_t)size;
 +
 +		switch (type) {
 +		case kEmptyStream:
- 			h->emptyStreamBools = calloc(zip->numFiles,
++			h->emptyStreamBools = calloc((size_t)zip->numFiles,
 +			    sizeof(*h->emptyStreamBools));
 +			if (h->emptyStreamBools == NULL)
 +				return (-1);
 +			if (read_Bools(
- 			    a, h->emptyStreamBools, zip->numFiles) < 0)
++			    a, h->emptyStreamBools, (size_t)zip->numFiles) < 0)
 +				return (-1);
 +			empty_streams = 0;
 +			for (i = 0; i < zip->numFiles; i++) {
 +				if (h->emptyStreamBools[i])
 +					empty_streams++;
 +			}
 +			break;
 +		case kEmptyFile:
++			if (empty_streams <= 0) {
++				/* Unexcepted sequence. Skip this. */
++				if (header_bytes(a, ll) == NULL)
++					return (-1);
++				break;
++			}
 +			h->emptyFileBools = calloc(empty_streams,
 +			    sizeof(*h->emptyFileBools));
 +			if (h->emptyFileBools == NULL)
 +				return (-1);
 +			if (read_Bools(a, h->emptyFileBools, empty_streams) < 0)
 +				return (-1);
 +			break;
 +		case kAnti:
++			if (empty_streams <= 0) {
++				/* Unexcepted sequence. Skip this. */
++				if (header_bytes(a, ll) == NULL)
++					return (-1);
++				break;
++			}
 +			h->antiBools = calloc(empty_streams,
 +			    sizeof(*h->antiBools));
 +			if (h->antiBools == NULL)
 +				return (-1);
 +			if (read_Bools(a, h->antiBools, empty_streams) < 0)
 +				return (-1);
 +			break;
 +		case kCTime:
 +		case kATime:
 +		case kMTime:
 +			if (read_Times(a, h, type) < 0)
 +				return (-1);
 +			break;
 +		case kName:
 +		{
 +			unsigned char *np;
 +			size_t nl, nb;
 +
 +			/* Skip one byte. */
 +			if ((p = header_bytes(a, 1)) == NULL)
 +				return (-1);
 +			ll--;
 +
 +			if ((ll & 1) || ll < zip->numFiles * 4)
 +				return (-1);
 +
 +			zip->entry_names = malloc(ll);
 +			if (zip->entry_names == NULL)
 +				return (-1);
 +			np = zip->entry_names;
 +			nb = ll;
 +			/*
 +			 * Copy whole file names.
 +			 * NOTE: This loop prevents from expanding
 +			 * the uncompressed buffer in order not to
 +			 * use extra memory resource.
 +			 */
 +			while (nb) {
 +				size_t b;
 +				if (nb > UBUFF_SIZE)
 +					b = UBUFF_SIZE;
 +				else
 +					b = nb;
 +				if ((p = header_bytes(a, b)) == NULL)
 +					return (-1);
 +				memcpy(np, p, b);
 +				np += b;
 +				nb -= b;
 +			}
 +			np = zip->entry_names;
 +			nl = ll;
 +
 +			for (i = 0; i < zip->numFiles; i++) {
 +				entries[i].utf16name = np;
 +#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
 +				entries[i].wname = (wchar_t *)np;
 +#endif
 +
 +				/* Find a terminator. */
 +				while (nl >= 2 && (np[0] || np[1])) {
 +					np += 2;
 +					nl -= 2;
 +				}
 +				if (nl < 2)
 +					return (-1);/* Terminator not found */
 +				entries[i].name_len = np - entries[i].utf16name;
 +				np += 2;
 +				nl -= 2;
 +			}
 +			break;
 +		}
 +		case kAttributes:
 +		{
 +			int allAreDefined;
 +
 +			if ((p = header_bytes(a, 2)) == NULL)
 +				return (-1);
 +			allAreDefined = *p;
- 			h->attrBools = calloc(zip->numFiles,
++			h->attrBools = calloc((size_t)zip->numFiles,
 +			    sizeof(*h->attrBools));
 +			if (h->attrBools == NULL)
 +				return (-1);
 +			if (allAreDefined)
- 				memset(h->attrBools, 1, zip->numFiles);
++				memset(h->attrBools, 1, (size_t)zip->numFiles);
 +			else {
 +				if (read_Bools(a, h->attrBools,
- 				      zip->numFiles) < 0)
++				      (size_t)zip->numFiles) < 0)
 +					return (-1);
 +			}
 +			for (i = 0; i < zip->numFiles; i++) {
 +				if (h->attrBools[i]) {
 +					if ((p = header_bytes(a, 4)) == NULL)
 +						return (-1);
 +					entries[i].attr = archive_le32dec(p);
 +				}
 +			}
 +			break;
 +		}
 +		default:
 +			if (header_bytes(a, ll) == NULL)
 +				return (-1);
 +			break;
 +		}
 +	}
 +
 +	/*
 +	 * Set up entry's attributes.
 +	 */
 +	folders = si->ci.folders;
 +	eindex = sindex = 0;
 +	folderIndex = indexInFolder = 0;
 +	for (i = 0; i < zip->numFiles; i++) {
 +		if (h->emptyStreamBools == NULL || h->emptyStreamBools[i] == 0)
 +			entries[i].flg |= HAS_STREAM;
 +		/* The high 16 bits of attributes is a posix file mode. */
 +		entries[i].mode = entries[i].attr >> 16;
 +		if (entries[i].flg & HAS_STREAM) {
 +			if ((size_t)sindex >= si->ss.unpack_streams)
 +				return (-1);
 +			if (entries[i].mode == 0)
- 				entries[i].mode = AE_IFREG | 0777;
++				entries[i].mode = AE_IFREG | 0666;
 +			if (si->ss.digestsDefined[sindex])
 +				entries[i].flg |= CRC32_IS_SET;
 +			entries[i].ssIndex = sindex;
 +			sindex++;
 +		} else {
 +			int dir;
 +			if (h->emptyFileBools == NULL)
 +				dir = 1;
 +			else {
 +				if (h->emptyFileBools[eindex])
 +					dir = 0;
 +				else
 +					dir = 1;
 +				eindex++;
 +			}
 +			if (entries[i].mode == 0) {
 +				if (dir)
 +					entries[i].mode = AE_IFDIR | 0777;
 +				else
- 					entries[i].mode = AE_IFREG | 0777;
++					entries[i].mode = AE_IFREG | 0666;
 +			} else if (dir &&
 +			    (entries[i].mode & AE_IFMT) != AE_IFDIR) {
 +				entries[i].mode &= ~AE_IFMT;
 +				entries[i].mode |= AE_IFDIR;
 +			}
 +			if ((entries[i].mode & AE_IFMT) == AE_IFDIR &&
 +			    entries[i].name_len >= 2 &&
 +			    (entries[i].utf16name[entries[i].name_len-2] != '/' ||
 +			     entries[i].utf16name[entries[i].name_len-1] != 0)) {
 +				entries[i].utf16name[entries[i].name_len] = '/';
 +				entries[i].utf16name[entries[i].name_len+1] = 0;
 +				entries[i].name_len += 2;
 +			}
 +			entries[i].ssIndex = -1;
 +		}
 +		if (entries[i].attr & 0x01)
 +			entries[i].mode &= ~0222;/* Read only. */
 +
 +		if ((entries[i].flg & HAS_STREAM) == 0 && indexInFolder == 0) {
 +			/*
 +			 * The entry is an empty file or a directory file,
 +			 * those both have no contents.
 +			 */
 +			entries[i].folderIndex = -1;
 +			continue;
 +		}
 +		if (indexInFolder == 0) {
 +			for (;;) {
 +				if (folderIndex >= si->ci.numFolders)
 +					return (-1);
 +				if (folders[folderIndex].numUnpackStreams)
 +					break;
 +				folderIndex++;
 +			}
 +		}
 +		entries[i].folderIndex = folderIndex;
 +		if ((entries[i].flg & HAS_STREAM) == 0)
 +			continue;
 +		indexInFolder++;
 +		if (indexInFolder >= folders[folderIndex].numUnpackStreams) {
 +			folderIndex++;
 +			indexInFolder = 0;
 +		}
 +	}
 +
 +	return (0);
 +}
 +
 +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 +static void
- fileTimeToUtc(uint64_t fileTime, time_t *time, long *ns)
++fileTimeToUtc(uint64_t fileTime, time_t *timep, long *ns)
 +{
 +
 +	if (fileTime >= EPOC_TIME) {
 +		fileTime -= EPOC_TIME;
 +		/* milli seconds base */
- 		*time = (time_t)(fileTime / 10000000);
++		*timep = (time_t)(fileTime / 10000000);
 +		/* nano seconds base */
 +		*ns = (long)(fileTime % 10000000) * 100;
 +	} else {
- 		*time = 0;
++		*timep = 0;
 +		*ns = 0;
 +	}
 +}
 +
 +static int
 +read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	const unsigned char *p;
 +	struct _7zip_entry *entries = zip->entries;
 +	unsigned char *timeBools;
 +	int allAreDefined;
 +	unsigned i;
 +
- 	timeBools = calloc(zip->numFiles, sizeof(*timeBools));
++	timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools));
 +	if (timeBools == NULL)
 +		return (-1);
 +
 +	/* Read allAreDefined. */
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
 +	allAreDefined = *p;
 +	if (allAreDefined)
- 		memset(timeBools, 1, zip->numFiles);
++		memset(timeBools, 1, (size_t)zip->numFiles);
 +	else {
- 		if (read_Bools(a, timeBools, zip->numFiles) < 0)
++		if (read_Bools(a, timeBools, (size_t)zip->numFiles) < 0)
 +			goto failed;
 +	}
 +
 +	/* Read external. */
 +	if ((p = header_bytes(a, 1)) == NULL)
 +		goto failed;
 +	if (*p) {
 +		if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
 +			goto failed;
 +		if (1000000 < h->dataIndex)
- 			return (-1);
++			goto failed;
 +	}
 +
 +	for (i = 0; i < zip->numFiles; i++) {
 +		if (!timeBools[i])
 +			continue;
 +		if ((p = header_bytes(a, 8)) == NULL)
 +			goto failed;
 +		switch (type) {
 +		case kCTime:
 +			fileTimeToUtc(archive_le64dec(p),
 +			    &(entries[i].ctime),
 +			    &(entries[i].ctime_ns));
 +			entries[i].flg |= CTIME_IS_SET;
 +			break;
 +		case kATime:
 +			fileTimeToUtc(archive_le64dec(p),
 +			    &(entries[i].atime),
 +			    &(entries[i].atime_ns));
 +			entries[i].flg |= ATIME_IS_SET;
 +			break;
 +		case kMTime:
 +			fileTimeToUtc(archive_le64dec(p),
 +			    &(entries[i].mtime),
 +			    &(entries[i].mtime_ns));
 +			entries[i].flg |= MTIME_IS_SET;
 +			break;
 +		}
 +	}
 +
 +	free(timeBools);
 +	return (0);
 +failed:
 +	free(timeBools);
 +	return (-1);
 +}
 +
 +static int
 +decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +
 +	errno = 0;
 +	if (read_StreamsInfo(a, si) < 0) {
 +		if (errno == ENOMEM)
 +			archive_set_error(&a->archive, -1,
 +			    "Couldn't allocate memory");
 +		else
 +			archive_set_error(&a->archive, -1,
 +			    "Malformed 7-Zip archive");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	if (si->pi.numPackStreams == 0 || si->ci.numFolders == 0) {
 +		archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	if (zip->header_offset < si->pi.pos + si->pi.sizes[0] ||
 +	    (int64_t)(si->pi.pos + si->pi.sizes[0]) < 0 ||
 +	    si->pi.sizes[0] == 0 || (int64_t)si->pi.pos < 0) {
 +		archive_set_error(&a->archive, -1, "Malformed Header offset");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static const unsigned char *
 +header_bytes(struct archive_read *a, size_t rbytes)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	const unsigned char *p;
 +
 +	if (zip->header_bytes_remaining < rbytes)
 +		return (NULL);
 +	if (zip->pack_stream_bytes_unconsumed)
 +		read_consume(a);
 +
 +	if (zip->header_is_encoded == 0) {
 +		p = __archive_read_ahead(a, rbytes, NULL);
 +		if (p == NULL)
 +			return (NULL);
 +		zip->header_bytes_remaining -= rbytes;
 +		zip->pack_stream_bytes_unconsumed = rbytes;
 +	} else {
 +		const void *buff;
 +		ssize_t bytes;
 +
 +		bytes = read_stream(a, &buff, rbytes, rbytes);
 +		if (bytes <= 0)
 +			return (NULL);
 +		zip->header_bytes_remaining -= bytes;
 +		p = buff;
 +	}
 +
 +	/* Update checksum */
- 	zip->header_crc32 = crc32(zip->header_crc32, p, rbytes);
++	zip->header_crc32 = crc32(zip->header_crc32, p, (unsigned)rbytes);
 +	return (p);
 +}
 +
 +static int
 +slurp_central_directory(struct archive_read *a, struct _7zip *zip,
 +    struct _7z_header_info *header)
 +{
 +	const unsigned char *p;
 +	uint64_t next_header_offset;
 +	uint64_t next_header_size;
 +	uint32_t next_header_crc;
 +	ssize_t bytes_avail;
 +	int check_header_crc, r;
 +
 +	if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
 +		return (ARCHIVE_FATAL);
 +
 +	if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
 +		/* This is an executable ? Must be self-extracting... */
 +		r = skip_sfx(a, bytes_avail);
 +		if (r < ARCHIVE_WARN)
 +			return (r);
 +		if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
 +			return (ARCHIVE_FATAL);
 +	}
 +	zip->seek_base += 32;
 +
 +	if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0) {
 +		archive_set_error(&a->archive, -1, "Not 7-Zip archive file");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* CRC check. */
- 	if (crc32(0, (unsigned char *)p + 12, 20) != archive_le32dec(p + 8)) {
++	if (crc32(0, (const unsigned char *)p + 12, 20)
++	    != archive_le32dec(p + 8)) {
 +		archive_set_error(&a->archive, -1, "Header CRC error");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	next_header_offset = archive_le64dec(p + 12);
 +	next_header_size = archive_le64dec(p + 20);
 +	next_header_crc = archive_le32dec(p + 28);
 +
 +	if (next_header_size == 0)
 +		/* There is no entry in an archive file. */
 +		return (ARCHIVE_EOF);
 +
 +	if (((int64_t)next_header_offset) < 0) {
 +		archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
 +		return (ARCHIVE_FATAL);
 +	}
 +	__archive_read_consume(a, 32);
 +	if (next_header_offset != 0) {
- 		if (bytes_avail >= next_header_offset)
++		if (bytes_avail >= (ssize_t)next_header_offset)
 +			__archive_read_consume(a, next_header_offset);
 +		else if (__archive_read_seek(a,
 +		    next_header_offset + zip->seek_base, SEEK_SET) < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +	zip->stream_offset = next_header_offset;
 +	zip->header_offset = next_header_offset;
 +	zip->header_bytes_remaining = next_header_size;
 +	zip->header_crc32 = 0;
 +	zip->header_is_encoded = 0;
 +	zip->header_is_being_read = 1;
 +	check_header_crc = 1;
 +
 +	if ((p = header_bytes(a, 1)) == NULL) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated 7-Zip file body");
 +		return (ARCHIVE_FATAL);
 +	}
 +	/* Parse ArchiveProperties. */
 +	switch (p[0]) {
 +	case kEncodedHeader:
 +		/*
 +		 * The archive has an encoded header and we have to decode it
 +		 * in order to parse the header correctly.
 +		 */
 +		r = decode_encoded_header_info(a, &(zip->si));
 +
 +		/* Check the EncodedHeader CRC.*/
 +		if (r == 0 && zip->header_crc32 != next_header_crc) {
 +			archive_set_error(&a->archive, -1,
 +			    "Damaged 7-Zip archive");
 +			r = -1;
 +		}
 +		if (r == 0) {
 +			if (zip->si.ci.folders[0].digest_defined)
 +				next_header_crc = zip->si.ci.folders[0].digest;
 +			else
 +				check_header_crc = 0;
 +			if (zip->pack_stream_bytes_unconsumed)
 +				read_consume(a);
 +			r = setup_decode_folder(a, zip->si.ci.folders, 1);
 +			if (r == 0) {
 +				zip->header_bytes_remaining =
 +					zip->folder_outbytes_remaining;
 +				r = seek_pack(a);
 +			}
 +		}
 +		/* Clean up StreamsInfo. */
 +		free_StreamsInfo(&(zip->si));
 +		memset(&(zip->si), 0, sizeof(zip->si));
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +		zip->header_is_encoded = 1;
 +		zip->header_crc32 = 0;
 +		/* FALL THROUGH */
 +	case kHeader:
 +		/*
 +		 * Parse the header.
 +		 */
 +		errno = 0;
 +		r = read_Header(a, header, zip->header_is_encoded);
 +		if (r < 0) {
 +			if (errno == ENOMEM)
 +				archive_set_error(&a->archive, -1,
 +				    "Couldn't allocate memory");
 +			else
 +				archive_set_error(&a->archive, -1,
 +				    "Damaged 7-Zip archive");
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		/*
 +		 *  Must be kEnd.
 +		 */
 +		if ((p = header_bytes(a, 1)) == NULL ||*p != kEnd) {
 +			archive_set_error(&a->archive, -1,
 +			    "Malformed 7-Zip archive");
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		/* Check the Header CRC.*/
 +		if (check_header_crc && zip->header_crc32 != next_header_crc) {
 +			archive_set_error(&a->archive, -1,
 +			    "Malformed 7-Zip archive");
 +			return (ARCHIVE_FATAL);
 +		}
 +		break;
 +	default:
 +		archive_set_error(&a->archive, -1,
 +		    "Unexpected Property ID = %X", p[0]);
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Clean up variables be used for decoding the archive header */
 +	zip->pack_stream_remaining = 0;
 +	zip->pack_stream_index = 0;
 +	zip->folder_outbytes_remaining = 0;
 +	zip->uncompressed_buffer_bytes_remaining = 0;
 +	zip->pack_stream_bytes_unconsumed = 0;
 +	zip->header_is_being_read = 0;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static ssize_t
 +get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,
 +    size_t minimum)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	ssize_t bytes_avail;
 +
- 	if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
++	if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
 +		/* Copy mode. */
 +
 +		/*
 +		 * Note: '1' here is a performance optimization.
 +		 * Recall that the decompression layer returns a count of
 +		 * available bytes; asking for more than that forces the
 +		 * decompressor to combine reads by copying data.
 +		 */
 +		*buff = __archive_read_ahead(a, 1, &bytes_avail);
 +		if (bytes_avail <= 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated 7-Zip file data");
 +			return (ARCHIVE_FATAL);
 +		}
 +		if ((size_t)bytes_avail >
 +		    zip->uncompressed_buffer_bytes_remaining)
 +			bytes_avail = (ssize_t)
 +			    zip->uncompressed_buffer_bytes_remaining;
 +		if ((size_t)bytes_avail > size)
 +			bytes_avail = (ssize_t)size;
 +
 +		zip->pack_stream_bytes_unconsumed = bytes_avail;
 +	} else if (zip->uncompressed_buffer_pointer == NULL) {
 +		/* Decompression has failed. */
 +		archive_set_error(&(a->archive),
 +		    ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
 +		return (ARCHIVE_FATAL);
 +	} else {
 +		/* Packed mode. */
 +		if (minimum > zip->uncompressed_buffer_bytes_remaining) {
 +			/*
 +			 * If remaining uncompressed data size is less than
 +			 * the minimum size, fill the buffer up to the
 +			 * minimum size.
 +			 */
 +			if (extract_pack_stream(a, minimum) < 0)
 +				return (ARCHIVE_FATAL);
 +		}
 +		if (size > zip->uncompressed_buffer_bytes_remaining)
 +			bytes_avail = (ssize_t)
 +			    zip->uncompressed_buffer_bytes_remaining;
 +		else
 +			bytes_avail = (ssize_t)size;
 +		*buff = zip->uncompressed_buffer_pointer;
 +		zip->uncompressed_buffer_pointer += bytes_avail;
 +	}
 +	zip->uncompressed_buffer_bytes_remaining -= bytes_avail;
 +	return (bytes_avail);
 +}
 +
 +static ssize_t
 +extract_pack_stream(struct archive_read *a, size_t minimum)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	ssize_t bytes_avail;
 +	int r;
 +
- 	if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
++	if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
 +		if (minimum == 0)
 +			minimum = 1;
 +		if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL
 +		    || bytes_avail <= 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated 7-Zip file body");
 +			return (ARCHIVE_FATAL);
 +		}
- 		if (bytes_avail > zip->pack_stream_inbytes_remaining)
- 			bytes_avail = zip->pack_stream_inbytes_remaining;
++		if (bytes_avail > (ssize_t)zip->pack_stream_inbytes_remaining)
++			bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining;
 +		zip->pack_stream_inbytes_remaining -= bytes_avail;
- 		if (bytes_avail > zip->folder_outbytes_remaining)
- 			bytes_avail = zip->folder_outbytes_remaining;
++		if (bytes_avail > (ssize_t)zip->folder_outbytes_remaining)
++			bytes_avail = (ssize_t)zip->folder_outbytes_remaining;
 +		zip->folder_outbytes_remaining -= bytes_avail;
 +		zip->uncompressed_buffer_bytes_remaining = bytes_avail;
 +		return (ARCHIVE_OK);
 +	}
 +
 +	/* If the buffer hasn't been allocated, allocate it now. */
 +	if (zip->uncompressed_buffer == NULL) {
 +		zip->uncompressed_buffer_size = UBUFF_SIZE;
 +		if (zip->uncompressed_buffer_size < minimum) {
 +			zip->uncompressed_buffer_size = minimum + 1023;
 +			zip->uncompressed_buffer_size &= ~0x3ff;
 +		}
 +		zip->uncompressed_buffer =
 +		    malloc(zip->uncompressed_buffer_size);
 +		if (zip->uncompressed_buffer == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "No memory for 7-Zip decompression");
 +			return (ARCHIVE_FATAL);
 +		}
 +		zip->uncompressed_buffer_bytes_remaining = 0;
 +	} else if (zip->uncompressed_buffer_size < minimum ||
 +	    zip->uncompressed_buffer_bytes_remaining < minimum) {
 +		/*
 +		 * Make sure the uncompressed buffer can have bytes
 +		 * at least `minimum' bytes.
 +		 * NOTE: This case happen when reading the header.
 +		 */
 +		size_t used;
 +		if (zip->uncompressed_buffer_pointer != 0)
 +			used = zip->uncompressed_buffer_pointer -
 +				zip->uncompressed_buffer;
 +		else
 +			used = 0;
 +		if (zip->uncompressed_buffer_size < minimum) {
 +			/*
 +			 * Expand the uncompressed buffer up to
 +			 * the minimum size.
 +			 */
- 			zip->uncompressed_buffer_size = minimum + 1023;
- 			zip->uncompressed_buffer_size &= ~0x3ff;
- 			zip->uncompressed_buffer =
- 			    realloc(zip->uncompressed_buffer,
- 				zip->uncompressed_buffer_size);
- 			if (zip->uncompressed_buffer == NULL) {
++			void *p;
++			size_t new_size;
++
++			new_size = minimum + 1023;
++			new_size &= ~0x3ff;
++			p = realloc(zip->uncompressed_buffer, new_size);
++			if (p == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory for 7-Zip decompression");
 +				return (ARCHIVE_FATAL);
 +			}
++			zip->uncompressed_buffer = (unsigned char *)p;
++			zip->uncompressed_buffer_size = new_size;
 +		}
 +		/*
 +		 * Move unconsumed bytes to the head.
 +		 */
 +		if (used) {
 +			memmove(zip->uncompressed_buffer,
 +				zip->uncompressed_buffer + used,
 +				zip->uncompressed_buffer_bytes_remaining);
 +		}
 +	} else
 +		zip->uncompressed_buffer_bytes_remaining = 0;
 +	zip->uncompressed_buffer_pointer = NULL;
 +	for (;;) {
 +		size_t bytes_in, bytes_out;
 +		const void *buff_in;
 +		unsigned char *buff_out;
- 		int eof;
++		int end_of_data;
 +
 +		/*
 +		 * Note: '1' here is a performance optimization.
 +		 * Recall that the decompression layer returns a count of
 +		 * available bytes; asking for more than that forces the
 +		 * decompressor to combine reads by copying data.
 +		 */
 +		buff_in = __archive_read_ahead(a, 1, &bytes_avail);
 +		if (bytes_avail <= 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated 7-Zip file body");
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		buff_out = zip->uncompressed_buffer
 +			+ zip->uncompressed_buffer_bytes_remaining;
 +		bytes_out = zip->uncompressed_buffer_size
 +			- zip->uncompressed_buffer_bytes_remaining;
 +		bytes_in = bytes_avail;
 +		if (bytes_in > zip->pack_stream_inbytes_remaining)
- 			bytes_in = zip->pack_stream_inbytes_remaining;
++			bytes_in = (size_t)zip->pack_stream_inbytes_remaining;
 +		/* Drive decompression. */
 +		r = decompress(a, zip, buff_out, &bytes_out,
 +			buff_in, &bytes_in);
 +		switch (r) {
 +		case ARCHIVE_OK:
- 			eof = 0;
++			end_of_data = 0;
 +			break;
 +		case ARCHIVE_EOF:
- 			eof = 1;
++			end_of_data = 1;
 +			break;
 +		default:
 +			return (ARCHIVE_FATAL);
 +		}
 +		zip->pack_stream_inbytes_remaining -= bytes_in;
 +		if (bytes_out > zip->folder_outbytes_remaining)
- 			bytes_out = zip->folder_outbytes_remaining;
++			bytes_out = (size_t)zip->folder_outbytes_remaining;
 +		zip->folder_outbytes_remaining -= bytes_out;
 +		zip->uncompressed_buffer_bytes_remaining += bytes_out;
 +		zip->pack_stream_bytes_unconsumed = bytes_in;
 +
 +		/*
 +		 * Continue decompression until uncompressed_buffer is full.
 +		 */
 +		if (zip->uncompressed_buffer_bytes_remaining ==
 +		    zip->uncompressed_buffer_size)
 +			break;
 +		if (zip->codec2 == _7Z_X86 && zip->odd_bcj_size &&
 +		    zip->uncompressed_buffer_bytes_remaining + 5 >
 +		    zip->uncompressed_buffer_size)
 +			break;
 +		if (zip->pack_stream_inbytes_remaining == 0 &&
 +		    zip->folder_outbytes_remaining == 0)
 +			break;
- 		if (eof || (bytes_in == 0 && bytes_out == 0)) {
++		if (end_of_data || (bytes_in == 0 && bytes_out == 0)) {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
 +			return (ARCHIVE_FATAL);
 +		}
 +		read_consume(a);
 +	}
 +	if (zip->uncompressed_buffer_bytes_remaining < minimum) {
 +		archive_set_error(&(a->archive),
 +		    ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
 +		return (ARCHIVE_FATAL);
 +	}
 +	zip->uncompressed_buffer_pointer = zip->uncompressed_buffer;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +seek_pack(struct archive_read *a)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
- 	uint64_t pack_offset;
++	int64_t pack_offset;
 +
 +	if (zip->pack_stream_remaining <= 0) {
 +		archive_set_error(&(a->archive),
 +		    ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
 +		return (ARCHIVE_FATAL);
 +	}
 +	zip->pack_stream_inbytes_remaining =
 +	    zip->si.pi.sizes[zip->pack_stream_index];
 +	pack_offset = zip->si.pi.positions[zip->pack_stream_index];
 +	if (zip->stream_offset != pack_offset) {
 +		if (0 > __archive_read_seek(a, pack_offset + zip->seek_base,
 +		    SEEK_SET))
 +			return (ARCHIVE_FATAL);
 +		zip->stream_offset = pack_offset;
 +	}
 +	zip->pack_stream_index++;
 +	zip->pack_stream_remaining--;
 +	return (ARCHIVE_OK);
 +}
 +
 +static ssize_t
 +read_stream(struct archive_read *a, const void **buff, size_t size,
 +    size_t minimum)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	uint64_t skip_bytes = 0;
- 	int r;
++	ssize_t r;
 +
 +	if (zip->uncompressed_buffer_bytes_remaining == 0) {
 +		if (zip->pack_stream_inbytes_remaining > 0) {
 +			r = extract_pack_stream(a, 0);
 +			if (r < 0)
 +				return (r);
 +			return (get_uncompressed_data(a, buff, size, minimum));
 +		} else if (zip->folder_outbytes_remaining > 0) {
 +			/* Extract a remaining pack stream. */
 +			r = extract_pack_stream(a, 0);
 +			if (r < 0)
 +				return (r);
 +			return (get_uncompressed_data(a, buff, size, minimum));
 +		}
 +	} else
 +		return (get_uncompressed_data(a, buff, size, minimum));
 +
 +	/*
 +	 * Current pack stream has been consumed.
 +	 */
 +	if (zip->pack_stream_remaining == 0) {
 +		if (zip->header_is_being_read) {
 +			/* Invalid sequence. This might happen when
 +			 * reading a malformed archive. */
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC, "Malformed 7-Zip archive");
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		/*
 +		 * All current folder's pack streams have been
 +		 * consumed. Switch to next folder.
 +		 */
 +		if (zip->folder_index == 0 &&
 +		    (zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes
 +		     || zip->folder_index != zip->entry->folderIndex)) {
 +			zip->folder_index = zip->entry->folderIndex;
 +			skip_bytes =
 +			    zip->si.ci.folders[zip->folder_index].skipped_bytes;
 +		}
 +
 +		if (zip->folder_index >= zip->si.ci.numFolders) {
 +			/*
 +			 * We have consumed all folders and its pack streams.
 +			 */
 +			*buff = NULL;
 +			return (0);
 +		}
 +		r = setup_decode_folder(a,
 +			&(zip->si.ci.folders[zip->folder_index]), 0);
 +		if (r != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +
 +		zip->folder_index++;
 +	}
 +
 +	/*
 +	 * Switch to next pack stream.
 +	 */
 +	r = seek_pack(a);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Extract a new pack stream. */
 +	r = extract_pack_stream(a, 0);
 +	if (r < 0)
 +		return (r);
 +
 +	/*
 +	 * Skip the bytes we alrady has skipped in skip_stream(). 
 +	 */
 +	while (skip_bytes) {
 +		ssize_t skipped;
 +
 +		if (zip->uncompressed_buffer_bytes_remaining == 0) {
 +			if (zip->pack_stream_inbytes_remaining > 0) {
 +				r = extract_pack_stream(a, 0);
 +				if (r < 0)
 +					return (r);
 +			} else if (zip->folder_outbytes_remaining > 0) {
 +				/* Extract a remaining pack stream. */
 +				r = extract_pack_stream(a, 0);
 +				if (r < 0)
 +					return (r);
 +			} else {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_FILE_FORMAT,
 +				    "Truncated 7-Zip file body");
 +				return (ARCHIVE_FATAL);
 +			}
 +		}
- 		skipped = get_uncompressed_data(a, buff, skip_bytes, 0);
++		skipped = get_uncompressed_data(
++			a, buff, (size_t)skip_bytes, 0);
 +		if (skipped < 0)
 +			return (skipped);
 +		skip_bytes -= skipped;
 +		if (zip->pack_stream_bytes_unconsumed)
 +			read_consume(a);
 +	}
 +
 +	return (get_uncompressed_data(a, buff, size, minimum));
 +}
 +
 +static int
 +setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
 +    int header)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	const struct _7z_coder *coder1, *coder2;
 +	const char *cname = (header)?"archive header":"file content";
 +	unsigned i;
 +	int r, found_bcj2 = 0;
 +
 +	/*
 +	 * Release the memory which the previous folder used for BCJ2.
 +	 */
 +	for (i = 0; i < 3; i++) {
 +		if (zip->sub_stream_buff[i] != NULL)
 +			free(zip->sub_stream_buff[i]);
 +		zip->sub_stream_buff[i] = NULL;
 +	}
 +
 +	/*
 +	 * Initialize a stream reader.
 +	 */
 +	zip->pack_stream_remaining = (unsigned)folder->numPackedStreams;
 +	zip->pack_stream_index = (unsigned)folder->packIndex;
 +	zip->folder_outbytes_remaining = folder_uncompressed_size(folder);
 +	zip->uncompressed_buffer_bytes_remaining = 0;
 +
 +	/*
 +	 * Check coder types.
 +	 */
 +	for (i = 0; i < folder->numCoders; i++) {
 +		if (folder->coders[i].codec == _7Z_CRYPTO) {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "The %s is encrypted, "
 +			    "but currently not supported", cname);
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (folder->coders[i].codec == _7Z_X86_BCJ2)
 +			found_bcj2++;
 +	}
 +	if ((folder->numCoders > 2 && !found_bcj2) || found_bcj2 > 1) {
 +		archive_set_error(&(a->archive),
 +		    ARCHIVE_ERRNO_MISC,
 +		    "The %s is encoded with many filters, "
 +		    "but currently not supported", cname);
 +		return (ARCHIVE_FATAL);
 +	}
 +	coder1 = &(folder->coders[0]);
 +	if (folder->numCoders == 2)
 +		coder2 = &(folder->coders[1]);
 +	else
 +		coder2 = NULL;
 +
 +	if (found_bcj2) {
 +		/*
 +		 * Preparation to decode BCJ2.
 +		 * Decoding BCJ2 requires four sources. Those are at least,
 +		 * as far as I know, two types of the storage form.
 +		 */
 +		const struct _7z_coder *fc = folder->coders;
 +		static const struct _7z_coder coder_copy = {0, 1, 1, 0, NULL};
 +		const struct _7z_coder *scoder[3] =
 +			{&coder_copy, &coder_copy, &coder_copy};
 +		const void *buff;
 +		ssize_t bytes;
 +		unsigned char *b[3] = {NULL, NULL, NULL};
 +		uint64_t sunpack[3] ={-1, -1, -1};
 +		size_t s[3] = {0, 0, 0};
 +		int idx[3] = {0, 1, 2};
 +
 +		if (folder->numCoders == 4 && fc[3].codec == _7Z_X86_BCJ2 &&
 +		    folder->numInStreams == 7 && folder->numOutStreams == 4 &&
 +		    zip->pack_stream_remaining == 4) {
 +			/* Source type 1 made by 7zr or 7z with -m options. */
 +			if (folder->bindPairs[0].inIndex == 5) {
 +				/* The form made by 7zr */
 +				idx[0] = 1; idx[1] = 2; idx[2] = 0;
 +				scoder[1] = &(fc[1]);
 +				scoder[2] = &(fc[0]);
 +				sunpack[1] = folder->unPackSize[1];
 +				sunpack[2] = folder->unPackSize[0];
 +				coder1 = &(fc[2]);
 +			} else {
 +				/*
 +				 * NOTE: Some patterns do not work.
 +				 * work:
 +				 *  7z a -m0=BCJ2 -m1=COPY -m2=COPY
 +				 *       -m3=(any)
 +				 *  7z a -m0=BCJ2 -m1=COPY -m2=(any)
 +				 *       -m3=COPY
 +				 *  7z a -m0=BCJ2 -m1=(any) -m2=COPY
 +				 *       -m3=COPY
 +				 * not work:
 +				 *  other patterns.
 +				 *
 +				 * We have to handle this like `pipe' or
 +				 * our libarchive7s filter frame work,
 +				 * decoding the BCJ2 main stream sequentially,
 +				 * m3 -> m2 -> m1 -> BCJ2.
 +				 *
 +				 */
 +				if (fc[0].codec == _7Z_COPY &&
 +				    fc[1].codec == _7Z_COPY)
 +					coder1 = &(folder->coders[2]);
 +				else if (fc[0].codec == _7Z_COPY &&
 +				    fc[2].codec == _7Z_COPY)
 +					coder1 = &(folder->coders[1]);
 +				else if (fc[1].codec == _7Z_COPY &&
 +				    fc[2].codec == _7Z_COPY)
 +					coder1 = &(folder->coders[0]);
 +				else {
 +					archive_set_error(&(a->archive),
 +					    ARCHIVE_ERRNO_MISC,
 +					    "Unsupported form of "
 +					    "BCJ2 streams");
 +					return (ARCHIVE_FATAL);
 +				}
 +			}
 +			coder2 = &(fc[3]);
 +			zip->main_stream_bytes_remaining =
- 				folder->unPackSize[2];
++				(size_t)folder->unPackSize[2];
 +		} else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 &&
 +		    zip->pack_stream_remaining == 4 &&
 +		    folder->numInStreams == 5 && folder->numOutStreams == 2) {
 +			/* Source type 0 made by 7z */
 +			zip->main_stream_bytes_remaining =
- 				folder->unPackSize[0];
++				(size_t)folder->unPackSize[0];
 +		} else {
 +			/* We got an unexpected form. */
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Unsupported form of BCJ2 streams");
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		/* Skip the main stream at this time. */
 +		if ((r = seek_pack(a)) < 0)
 +			return (r);
 +		zip->pack_stream_bytes_unconsumed =
- 		    zip->pack_stream_inbytes_remaining;
++		    (size_t)zip->pack_stream_inbytes_remaining;
 +		read_consume(a);
 +
 +		/* Read following three sub streams. */
 +		for (i = 0; i < 3; i++) {
 +			const struct _7z_coder *coder = scoder[i];
 +
- 			if ((r = seek_pack(a)) < 0)
++			if ((r = seek_pack(a)) < 0) {
++				free(b[0]); free(b[1]); free(b[2]);
 +				return (r);
++			}
 +
- 			if (sunpack[i] == -1)
++			if (sunpack[i] == (uint64_t)-1)
 +				zip->folder_outbytes_remaining =
 +				    zip->pack_stream_inbytes_remaining;
 +			else
 +				zip->folder_outbytes_remaining = sunpack[i];
 +
 +			r = init_decompression(a, zip, coder, NULL);
- 			if (r != ARCHIVE_OK)
++			if (r != ARCHIVE_OK) {
++				free(b[0]); free(b[1]); free(b[2]);
 +				return (ARCHIVE_FATAL);
++			}
 +
 +			/* Allocate memory for the decorded data of a sub
 +			 * stream. */
- 			b[i] = malloc(zip->folder_outbytes_remaining);
++			b[i] = malloc((size_t)zip->folder_outbytes_remaining);
 +			if (b[i] == NULL) {
++				free(b[0]); free(b[1]); free(b[2]);
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory for 7-Zip decompression");
 +				return (ARCHIVE_FATAL);
 +			}
 +
 +			/* Extract a sub stream. */
 +			while (zip->pack_stream_inbytes_remaining > 0) {
- 				r = extract_pack_stream(a, 0);
- 				if (r < 0)
++				r = (int)extract_pack_stream(a, 0);
++				if (r < 0) {
++					free(b[0]); free(b[1]); free(b[2]);
 +					return (r);
++				}
 +				bytes = get_uncompressed_data(a, &buff,
 +				    zip->uncompressed_buffer_bytes_remaining,
 +				    0);
- 				if (bytes < 0)
++				if (bytes < 0) {
++					free(b[0]); free(b[1]); free(b[2]);
 +					return ((int)bytes);
++				}
 +				memcpy(b[i]+s[i], buff, bytes);
 +				s[i] += bytes;
 +				if (zip->pack_stream_bytes_unconsumed)
 +					read_consume(a);
 +			}
 +		}
 +
 +		/* Set the sub streams to the right place. */
 +		for (i = 0; i < 3; i++) {
 +			zip->sub_stream_buff[i] = b[idx[i]];
 +			zip->sub_stream_size[i] = s[idx[i]];
 +			zip->sub_stream_bytes_remaining[i] = s[idx[i]];
 +		}
 +
 +		/* Allocate memory used for decoded main stream bytes. */
 +		if (zip->tmp_stream_buff == NULL) {
 +			zip->tmp_stream_buff_size = 32 * 1024;
 +			zip->tmp_stream_buff =
 +			    malloc(zip->tmp_stream_buff_size);
 +			if (zip->tmp_stream_buff == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory for 7-Zip decompression");
 +				return (ARCHIVE_FATAL);
 +			}
 +		}
 +		zip->tmp_stream_bytes_avail = 0;
 +		zip->tmp_stream_bytes_remaining = 0;
 +		zip->odd_bcj_size = 0;
 +		zip->bcj2_outPos = 0;
 +
 +		/*
 +		 * Reset a stream reader in order to read the main stream
 +		 * of BCJ2.
 +		 */
 +		zip->pack_stream_remaining = 1;
 +		zip->pack_stream_index = (unsigned)folder->packIndex;
 +		zip->folder_outbytes_remaining =
 +		    folder_uncompressed_size(folder);
 +		zip->uncompressed_buffer_bytes_remaining = 0;
 +	}
 +
 +	/*
 +	 * Initialize the decompressor for the new folder's pack streams.
 +	 */
 +	r = init_decompression(a, zip, coder1, coder2);
 +	if (r != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int64_t
 +skip_stream(struct archive_read *a, size_t skip_bytes)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format->data;
 +	const void *p;
 +	int64_t skipped_bytes;
 +	size_t bytes = skip_bytes;
 +
 +	if (zip->folder_index == 0) {
 +		/*
 +		 * Optimization for a list mode.
 +		 * Avoid unncecessary decoding operations.
 +		 */
 +		zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes
 +		    += skip_bytes;
 +		return (skip_bytes);
 +	}
 +
 +	while (bytes) {
 +		skipped_bytes = read_stream(a, &p, bytes, 0);
 +		if (skipped_bytes < 0)
 +			return (skipped_bytes);
 +		if (skipped_bytes == 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated 7-Zip file body");
 +			return (ARCHIVE_FATAL);
 +		}
- 		bytes -= skipped_bytes;
++		bytes -= (size_t)skipped_bytes;
 +		if (zip->pack_stream_bytes_unconsumed)
 +			read_consume(a);
 +	}
 +	return (skip_bytes);
 +}
 +
 +/*
 + * Brought from LZMA SDK.
 + *
 + * Bra86.c -- Converter for x86 code (BCJ)
 + * 2008-10-04 : Igor Pavlov : Public domain
 + *
 + */
 +
 +#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
 +
 +static void
 +x86_Init(struct _7zip *zip)
 +{
 +	zip->bcj_state = 0;
 +	zip->bcj_prevPosT = (size_t)0 - 1;
 +	zip->bcj_prevMask = 0;
 +	zip->bcj_ip = 5;
 +}
 +
 +static size_t
 +x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
 +{
 +	static const uint8_t kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
 +	static const uint8_t kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
 +	size_t bufferPos, prevPosT;
 +	uint32_t ip, prevMask;
 +
 +	if (size < 5)
 +		return 0;
 +
 +	bufferPos = 0;
 +	prevPosT = zip->bcj_prevPosT;
 +	prevMask = zip->bcj_prevMask;
 +	ip = zip->bcj_ip;
 +
 +	for (;;) {
 +		uint8_t *p = data + bufferPos;
 +		uint8_t *limit = data + size - 4;
 +
 +		for (; p < limit; p++)
 +			if ((*p & 0xFE) == 0xE8)
 +				break;
 +		bufferPos = (size_t)(p - data);
 +		if (p >= limit)
 +			break;
 +		prevPosT = bufferPos - prevPosT;
 +		if (prevPosT > 3)
 +			prevMask = 0;
 +		else {
 +			prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
 +			if (prevMask != 0) {
 +				unsigned char b =
 +					p[4 - kMaskToBitNumber[prevMask]];
 +				if (!kMaskToAllowedStatus[prevMask] ||
 +				    Test86MSByte(b)) {
 +					prevPosT = bufferPos;
 +					prevMask = ((prevMask << 1) & 0x7) | 1;
 +					bufferPos++;
 +					continue;
 +				}
 +			}
 +		}
 +		prevPosT = bufferPos;
 +
 +		if (Test86MSByte(p[4])) {
 +			uint32_t src = ((uint32_t)p[4] << 24) |
 +				((uint32_t)p[3] << 16) | ((uint32_t)p[2] << 8) |
 +				((uint32_t)p[1]);
 +			uint32_t dest;
 +			for (;;) {
 +				uint8_t b;
- 				int index;
++				int b_index;
 +
 +				dest = src - (ip + (uint32_t)bufferPos);
 +				if (prevMask == 0)
 +					break;
- 				index = kMaskToBitNumber[prevMask] * 8;
- 				b = (uint8_t)(dest >> (24 - index));
++				b_index = kMaskToBitNumber[prevMask] * 8;
++				b = (uint8_t)(dest >> (24 - b_index));
 +				if (!Test86MSByte(b))
 +					break;
- 				src = dest ^ ((1 << (32 - index)) - 1);
++				src = dest ^ ((1 << (32 - b_index)) - 1);
 +			}
 +			p[4] = (uint8_t)(~(((dest >> 24) & 1) - 1));
 +			p[3] = (uint8_t)(dest >> 16);
 +			p[2] = (uint8_t)(dest >> 8);
 +			p[1] = (uint8_t)dest;
 +			bufferPos += 5;
 +		} else {
 +			prevMask = ((prevMask << 1) & 0x7) | 1;
 +			bufferPos++;
 +		}
 +	}
 +	zip->bcj_prevPosT = prevPosT;
 +	zip->bcj_prevMask = prevMask;
- 	zip->bcj_ip += bufferPos;
++	zip->bcj_ip += (uint32_t)bufferPos;
 +	return (bufferPos);
 +}
 +
 +/*
 + * Brought from LZMA SDK.
 + *
 + * Bcj2.c -- Converter for x86 code (BCJ2)
 + * 2008-10-04 : Igor Pavlov : Public domain
 + *
 + */
 +
 +#define SZ_ERROR_DATA	 ARCHIVE_FAILED
 +
 +#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
 +#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
 +
 +#define kNumTopBits 24
 +#define kTopValue ((uint32_t)1 << kNumTopBits)
 +
 +#define kNumBitModelTotalBits 11
 +#define kBitModelTotal (1 << kNumBitModelTotalBits)
 +#define kNumMoveBits 5
 +
 +#define RC_READ_BYTE (*buffer++)
 +#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
 +#define RC_INIT2 zip->bcj2_code = 0; zip->bcj2_range = 0xFFFFFFFF; \
-   { int i; for (i = 0; i < 5; i++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
++  { int ii; for (ii = 0; ii < 5; ii++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
 +
 +#define NORMALIZE if (zip->bcj2_range < kTopValue) { RC_TEST; zip->bcj2_range <<= 8; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }
 +
 +#define IF_BIT_0(p) ttt = *(p); bound = (zip->bcj2_range >> kNumBitModelTotalBits) * ttt; if (zip->bcj2_code < bound)
 +#define UPDATE_0(p) zip->bcj2_range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE;
 +#define UPDATE_1(p) zip->bcj2_range -= bound; zip->bcj2_code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE;
 +
 +static ssize_t
 +Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
 +{
 +	size_t inPos = 0, outPos = 0;
 +	const uint8_t *buf0, *buf1, *buf2, *buf3;
 +	size_t size0, size1, size2, size3;
 +	const uint8_t *buffer, *bufferLim;
 +	unsigned int i, j;
 +
 +	size0 = zip->tmp_stream_bytes_remaining;
 +	buf0 = zip->tmp_stream_buff + zip->tmp_stream_bytes_avail - size0;
 +	size1 = zip->sub_stream_bytes_remaining[0];
 +	buf1 = zip->sub_stream_buff[0] + zip->sub_stream_size[0] - size1;
 +	size2 = zip->sub_stream_bytes_remaining[1];
 +	buf2 = zip->sub_stream_buff[1] + zip->sub_stream_size[1] - size2;
 +	size3 = zip->sub_stream_bytes_remaining[2];
 +	buf3 = zip->sub_stream_buff[2] + zip->sub_stream_size[2] - size3;
 +
 +	buffer = buf3;
 +	bufferLim = buffer + size3;
 +
 +	if (zip->bcj_state == 0) {
 +		/*
 +		 * Initialize.
 +		 */
 +		zip->bcj2_prevByte = 0;
 +		for (i = 0;
 +		    i < sizeof(zip->bcj2_p) / sizeof(zip->bcj2_p[0]); i++)
 +			zip->bcj2_p[i] = kBitModelTotal >> 1;
 +		RC_INIT2;
 +		zip->bcj_state = 1;
 +	}
 +
 +	/*
 +	 * Gather the odd bytes of a previous call.
 +	 */
 +	for (i = 0; zip->odd_bcj_size > 0 && outPos < outSize; i++) {
 +		outBuf[outPos++] = zip->odd_bcj[i];
 +		zip->odd_bcj_size--;
 +	}
 +
 +	if (outSize == 0) {
 +		zip->bcj2_outPos += outPos;
 +		return (outPos);
 +	}
 +
 +	for (;;) {
 +		uint8_t b;
 +		CProb *prob;
 +		uint32_t bound;
 +		uint32_t ttt;
 +
 +		size_t limit = size0 - inPos;
 +		if (outSize - outPos < limit)
 +			limit = outSize - outPos;
 +
 +		if (zip->bcj_state == 1) {
 +			while (limit != 0) {
- 				uint8_t b = buf0[inPos];
- 				outBuf[outPos++] = b;
- 				if (IsJ(zip->bcj2_prevByte, b)) {
++				uint8_t bb = buf0[inPos];
++				outBuf[outPos++] = bb;
++				if (IsJ(zip->bcj2_prevByte, bb)) {
 +					zip->bcj_state = 2;
 +					break;
 +				}
 +				inPos++;
- 				zip->bcj2_prevByte = b;
++				zip->bcj2_prevByte = bb;
 +				limit--;
 +			}
 +		}
 +
 +		if (limit == 0 || outPos == outSize)
 +			break;
 +		zip->bcj_state = 1;
 +
 +		b = buf0[inPos++];
 +
 +		if (b == 0xE8)
 +			prob = zip->bcj2_p + zip->bcj2_prevByte;
 +		else if (b == 0xE9)
 +			prob = zip->bcj2_p + 256;
 +		else
 +			prob = zip->bcj2_p + 257;
 +
 +		IF_BIT_0(prob) {
 +			UPDATE_0(prob)
 +			zip->bcj2_prevByte = b;
 +		} else {
 +			uint32_t dest;
 +			const uint8_t *v;
 +			uint8_t out[4];
 +
 +			UPDATE_1(prob)
 +			if (b == 0xE8) {
 +				v = buf1;
 +				if (size1 < 4)
 +					return SZ_ERROR_DATA;
 +				buf1 += 4;
 +				size1 -= 4;
 +			} else {
 +				v = buf2;
 +				if (size2 < 4)
 +					return SZ_ERROR_DATA;
 +				buf2 += 4;
 +				size2 -= 4;
 +			}
 +			dest = (((uint32_t)v[0] << 24) |
 +			    ((uint32_t)v[1] << 16) |
 +			    ((uint32_t)v[2] << 8) |
 +			    ((uint32_t)v[3])) -
- 			    ((uint32_t)zip->bcj2_outPos + outPos + 4);
++			    ((uint32_t)zip->bcj2_outPos + (uint32_t)outPos + 4);
 +			out[0] = (uint8_t)dest;
 +			out[1] = (uint8_t)(dest >> 8);
 +			out[2] = (uint8_t)(dest >> 16);
 +			out[3] = zip->bcj2_prevByte = (uint8_t)(dest >> 24);
 +
 +			for (i = 0; i < 4 && outPos < outSize; i++)
 +				outBuf[outPos++] = out[i];
 +			if (i < 4) {
 +				/*
 +				 * Save odd bytes which we could not add into
 +				 * the output buffer because of out of space.
 +				 */
 +				zip->odd_bcj_size = 4 -i;
 +				for (; i < 4; i++) {
- 					j = i - 4 + zip->odd_bcj_size;
++					j = i - 4 + (unsigned)zip->odd_bcj_size;
 +					zip->odd_bcj[j] = out[i];
 +				}
 +				break;
 +			}
 +		}
 +	}
 +	zip->tmp_stream_bytes_remaining -= inPos;
 +	zip->sub_stream_bytes_remaining[0] = size1;
 +	zip->sub_stream_bytes_remaining[1] = size2;
 +	zip->sub_stream_bytes_remaining[2] = bufferLim - buffer;
 +	zip->bcj2_outPos += outPos;
 +
 +	return ((ssize_t)outPos);
 +}
 +
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
index e65010e,0000000..4dd38db
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
@@@ -1,3315 -1,0 +1,3348 @@@
 +/*-
-  * Copyright (c) 2010-2011 Michihiro NAKAJIMA
++ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "archive_platform.h"
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_LIMITS_H
 +#include <limits.h>
 +#endif
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_private.h"
 +#include "archive_read_private.h"
 +#include "archive_endian.h"
 +
 +
 +struct lzx_dec {
 +	/* Decoding status. */
 +	int     		 state;
 +
 +	/*
 +	 * Window to see last decoded data, from 32KBi to 2MBi.
 +	 */
 +	int			 w_size;
 +	int			 w_mask;
 +	/* Window buffer, which is a loop buffer. */
 +	unsigned char		*w_buff;
 +	/* The insert position to the window. */
 +	int			 w_pos;
 +	/* The position where we can copy decoded code from the window. */
 +	int     		 copy_pos;
 +	/* The length how many bytes we can copy decoded code from
 +	 * the window. */
 +	int     		 copy_len;
 +	/* Translation reversal for x86 proccessor CALL byte sequence(E8).
 +	 * This is used for LZX only. */
 +	uint32_t		 translation_size;
 +	char			 translation;
 +	char			 block_type;
 +#define VERBATIM_BLOCK		1
 +#define ALIGNED_OFFSET_BLOCK	2
 +#define UNCOMPRESSED_BLOCK	3
 +	size_t			 block_size;
 +	size_t			 block_bytes_avail;
 +	/* Repeated offset. */
 +	int			 r0, r1, r2;
 +	unsigned char		 rbytes[4];
 +	int			 rbytes_avail;
 +	int			 length_header;
 +	int			 position_slot;
 +	int			 offset_bits;
 +
 +	struct lzx_pos_tbl {
 +		int		 base;
 +		int		 footer_bits;
 +	}			*pos_tbl;
 +	/*
 +	 * Bit stream reader.
 +	 */
 +	struct lzx_br {
 +#define CACHE_TYPE		uint64_t
 +#define CACHE_BITS		(8 * sizeof(CACHE_TYPE))
 +	 	/* Cache buffer. */
 +		CACHE_TYPE	 cache_buffer;
 +		/* Indicates how many bits avail in cache_buffer. */
 +		int		 cache_avail;
 +		unsigned char	 odd;
 +		char		 have_odd;
 +	} br;
 +
 +	/*
 +	 * Huffman coding.
 +	 */
 +	struct huffman {
 +		int		 len_size;
 +		int		 freq[17];
 +		unsigned char	*bitlen;
 +
 +		/*
 +		 * Use a index table. It's faster than searching a huffman
 +		 * coding tree, which is a binary tree. But a use of a large
 +		 * index table causes L1 cache read miss many times.
 +		 */
 +#define HTBL_BITS	10
 +		int		 max_bits;
 +		int		 shift_bits;
 +		int		 tbl_bits;
 +		int		 tree_used;
 +		int		 tree_avail;
 +		/* Direct access table. */
 +		uint16_t	*tbl;
 +		/* Binary tree table for extra bits over the direct access. */
 +		struct htree_t {
 +			uint16_t left;
 +			uint16_t right;
 +		}		*tree;
 +	}			 at, lt, mt, pt;
 +
 +	int			 loop;
 +	int			 error;
 +};
 +
 +static const int slots[] = {
 +	30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
 +};
 +#define SLOT_BASE	15
 +#define SLOT_MAX	21/*->25*/
 +
 +struct lzx_stream {
 +	const unsigned char	*next_in;
 +	int64_t			 avail_in;
 +	int64_t			 total_in;
 +	unsigned char		*next_out;
 +	int64_t			 avail_out;
 +	int64_t			 total_out;
 +	struct lzx_dec		*ds;
 +};
 +
 +/*
 + * Cabinet file definitions.
 + */
 +/* CFHEADER offset */
 +#define CFHEADER_signature	0
 +#define CFHEADER_cbCabinet	8
 +#define CFHEADER_coffFiles	16
 +#define CFHEADER_versionMinor	24
 +#define CFHEADER_versionMajor	25
 +#define CFHEADER_cFolders	26
 +#define CFHEADER_cFiles		28
 +#define CFHEADER_flags		30
 +#define CFHEADER_setID		32
 +#define CFHEADER_iCabinet	34
 +#define CFHEADER_cbCFHeader	36
 +#define CFHEADER_cbCFFolder	38
 +#define CFHEADER_cbCFData	39
 +
 +/* CFFOLDER offset */
 +#define CFFOLDER_coffCabStart	0
 +#define CFFOLDER_cCFData	4
 +#define CFFOLDER_typeCompress	6
 +#define CFFOLDER_abReserve	8
 +
 +/* CFFILE offset */
 +#define CFFILE_cbFile		0
 +#define CFFILE_uoffFolderStart	4
 +#define CFFILE_iFolder		8
 +#define CFFILE_date_time	10
 +#define CFFILE_attribs		14
 +
 +/* CFDATA offset */
 +#define CFDATA_csum		0
 +#define CFDATA_cbData		4
 +#define CFDATA_cbUncomp		6
 +
 +static const char *compression_name[] = {
 +	"NONE",
 +	"MSZIP",
 +	"Quantum",
 +	"LZX",
 +};
 +
 +struct cfdata {
 +	/* Sum value of this CFDATA. */
 +	uint32_t		 sum;
 +	uint16_t		 compressed_size;
 +	uint16_t		 compressed_bytes_remaining;
 +	uint16_t		 uncompressed_size;
 +	uint16_t		 uncompressed_bytes_remaining;
 +	/* To know how many bytes we have decompressed. */
 +	uint16_t		 uncompressed_avail;
 +	/* Offset from the beginning of compressed data of this CFDATA */
 +	uint16_t		 read_offset;
 +	int64_t			 unconsumed;
 +	/* To keep memory image of this CFDATA to compute the sum. */
 +	size_t			 memimage_size;
 +	unsigned char		*memimage;
 +	/* Result of calculation of sum. */
 +	uint32_t		 sum_calculated;
 +	unsigned char		 sum_extra[4];
 +	int			 sum_extra_avail;
 +	const void		*sum_ptr;
 +};
 +
 +struct cffolder {
 +	uint32_t		 cfdata_offset_in_cab;
 +	uint16_t		 cfdata_count;
 +	uint16_t		 comptype;
 +#define COMPTYPE_NONE		0x0000
 +#define COMPTYPE_MSZIP		0x0001
 +#define COMPTYPE_QUANTUM	0x0002
 +#define COMPTYPE_LZX		0x0003
 +	uint16_t		 compdata;
 +	const char		*compname;
 +	/* At the time reading CFDATA */
 +	struct cfdata		 cfdata;
 +	int			 cfdata_index;
 +	/* Flags to mark progress of decompression. */
 +	char			 decompress_init;
 +};
 +
 +struct cffile {
 +	uint32_t		 uncompressed_size;
 +	uint32_t		 offset;
 +	time_t			 mtime;
 +	uint16_t	 	 folder;
 +#define iFoldCONTINUED_FROM_PREV	0xFFFD
 +#define iFoldCONTINUED_TO_NEXT		0xFFFE
 +#define iFoldCONTINUED_PREV_AND_NEXT	0xFFFF
 +	unsigned char		 attr;
 +#define ATTR_RDONLY		0x01
 +#define ATTR_NAME_IS_UTF	0x80
 +	struct archive_string 	 pathname;
 +};
 +
 +struct cfheader {
 +	/* Total bytes of all file size in a Cabinet. */
 +	uint32_t		 total_bytes;
 +	uint32_t		 files_offset;
 +	uint16_t		 folder_count;
 +	uint16_t		 file_count;
 +	uint16_t		 flags;
 +#define PREV_CABINET	0x0001
 +#define NEXT_CABINET	0x0002
 +#define RESERVE_PRESENT	0x0004
 +	uint16_t		 setid;
 +	uint16_t		 cabinet;
 +	/* Version number. */
 +	unsigned char		 major;
 +	unsigned char		 minor;
 +	unsigned char		 cffolder;
 +	unsigned char		 cfdata;
 +	/* All folders in a cabinet. */
 +	struct cffolder		*folder_array;
 +	/* All files in a cabinet. */
 +	struct cffile		*file_array;
 +	int			 file_index;
 +};
 +
 +struct cab {
 +	/* entry_bytes_remaining is the number of bytes we expect.	    */
 +	int64_t			 entry_offset;
 +	int64_t			 entry_bytes_remaining;
 +	int64_t			 entry_unconsumed;
 +	int64_t			 entry_compressed_bytes_read;
 +	int64_t			 entry_uncompressed_bytes_read;
 +	struct cffolder		*entry_cffolder;
 +	struct cffile		*entry_cffile;
 +	struct cfdata		*entry_cfdata;
 +
 +	/* Offset from beginning of a cabinet file. */
 +	int64_t			 cab_offset;
 +	struct cfheader		 cfheader;
 +	struct archive_wstring	 ws;
 +
 +	/* Flag to mark progress that an archive was read their first header.*/
 +	char			 found_header;
 +	char			 end_of_archive;
 +	char			 end_of_entry;
 +	char			 end_of_entry_cleanup;
++	char			 read_data_invoked;
++	int64_t			 bytes_skipped;
 +
 +	unsigned char		*uncompressed_buffer;
 +	size_t			 uncompressed_buffer_size;
 +
 +	int			 init_default_conversion;
 +	struct archive_string_conv *sconv;
 +	struct archive_string_conv *sconv_default;
 +	struct archive_string_conv *sconv_utf8;
 +	char			 format_name[64];
 +
 +#ifdef HAVE_ZLIB_H
 +	z_stream		 stream;
 +	char			 stream_valid;
 +#endif
 +	struct lzx_stream	 xstrm;
 +};
 +
 +static int	archive_read_format_cab_bid(struct archive_read *, int);
 +static int	archive_read_format_cab_options(struct archive_read *,
 +		    const char *, const char *);
 +static int	archive_read_format_cab_read_header(struct archive_read *,
 +		    struct archive_entry *);
 +static int	archive_read_format_cab_read_data(struct archive_read *,
 +		    const void **, size_t *, int64_t *);
 +static int	archive_read_format_cab_read_data_skip(struct archive_read *);
 +static int	archive_read_format_cab_cleanup(struct archive_read *);
 +
 +static int	cab_skip_sfx(struct archive_read *);
 +static time_t	cab_dos_time(const unsigned char *);
 +static int	cab_read_data(struct archive_read *, const void **,
 +		    size_t *, int64_t *);
 +static int	cab_read_header(struct archive_read *);
 +static uint32_t cab_checksum_cfdata_4(const void *, size_t bytes, uint32_t);
 +static uint32_t cab_checksum_cfdata(const void *, size_t bytes, uint32_t);
 +static void	cab_checksum_update(struct archive_read *, size_t);
 +static int	cab_checksum_finish(struct archive_read *);
 +static int	cab_next_cfdata(struct archive_read *);
 +static const void *cab_read_ahead_cfdata(struct archive_read *, ssize_t *);
 +static const void *cab_read_ahead_cfdata_none(struct archive_read *, ssize_t *);
 +static const void *cab_read_ahead_cfdata_deflate(struct archive_read *,
 +		    ssize_t *);
 +static const void *cab_read_ahead_cfdata_lzx(struct archive_read *,
 +		    ssize_t *);
 +static int64_t	cab_consume_cfdata(struct archive_read *, int64_t);
 +static int64_t	cab_minimum_consume_cfdata(struct archive_read *, int64_t);
 +static int	lzx_decode_init(struct lzx_stream *, int);
 +static int	lzx_read_blocks(struct lzx_stream *, int);
 +static int	lzx_decode_blocks(struct lzx_stream *, int);
 +static void	lzx_decode_free(struct lzx_stream *);
 +static void	lzx_translation(struct lzx_stream *, void *, size_t, uint32_t);
 +static void	lzx_cleanup_bitstream(struct lzx_stream *);
 +static int	lzx_decode(struct lzx_stream *, int);
 +static int	lzx_read_pre_tree(struct lzx_stream *);
 +static int	lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);
 +static int	lzx_huffman_init(struct huffman *, size_t, int);
 +static void	lzx_huffman_free(struct huffman *);
 +static int	lzx_make_huffman_table(struct huffman *);
- static int inline lzx_decode_huffman(struct huffman *, unsigned);
++static inline int lzx_decode_huffman(struct huffman *, unsigned);
 +static int	lzx_decode_huffman_tree(struct huffman *, unsigned, int);
 +
 +
 +int
 +archive_read_support_format_cab(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct cab *cab;
 +	int r;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_read_support_format_cab");
 +
 +	cab = (struct cab *)calloc(1, sizeof(*cab));
 +	if (cab == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate CAB data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	archive_string_init(&cab->ws);
 +	archive_wstring_ensure(&cab->ws, 256);
 +
 +	r = __archive_read_register_format(a,
 +	    cab,
 +	    "cab",
 +	    archive_read_format_cab_bid,
 +	    archive_read_format_cab_options,
 +	    archive_read_format_cab_read_header,
 +	    archive_read_format_cab_read_data,
 +	    archive_read_format_cab_read_data_skip,
++	    NULL,
 +	    archive_read_format_cab_cleanup);
 +
 +	if (r != ARCHIVE_OK)
 +		free(cab);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +find_cab_magic(const char *p)
 +{
 +	switch (p[4]) {
 +	case 0:
 +		/*
 +		 * Note: Self-Extraction program has 'MSCF' string in their
 +		 * program. If we were finding 'MSCF' string only, we got
 +		 * wrong place for Cabinet header, thus, we have to check
 +		 * following four bytes which are reserved and must be set
 +		 * to zero.
 +		 */
 +		if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
 +			return 0;
 +		return 5;
 +	case 'F': return 1;
 +	case 'C': return 2;
 +	case 'S': return 3;
 +	case 'M': return 4;
 +	default:  return 5;
 +	}
 +}
 +
 +static int
 +archive_read_format_cab_bid(struct archive_read *a, int best_bid)
 +{
 +	const char *p;
 +	ssize_t bytes_avail, offset, window;
 +
 +	/* If there's already a better bid than we can ever
 +	   make, don't bother testing. */
 +	if (best_bid > 64)
 +		return (-1);
 +
 +	if ((p = __archive_read_ahead(a, 8, NULL)) == NULL)
 +		return (-1);
 +
 +	if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
 +		return (64);
 +
 +	/*
 +	 * Attempt to handle self-extracting archives
 +	 * by noting a PE header and searching forward
 +	 * up to 128k for a 'MSCF' marker.
 +	 */
 +	if (p[0] == 'M' && p[1] == 'Z') {
 +		offset = 0;
 +		window = 4096;
 +		while (offset < (1024 * 128)) {
 +			const char *h = __archive_read_ahead(a, offset + window,
 +			    &bytes_avail);
 +			if (h == NULL) {
 +				/* Remaining bytes are less than window. */
 +				window >>= 1;
 +				if (window < 128)
 +					return (0);
 +				continue;
 +			}
 +			p = h + offset;
 +			while (p + 8 < h + bytes_avail) {
 +				int next;
 +				if ((next = find_cab_magic(p)) == 0)
 +					return (64);
 +				p += next;
 +			}
 +			offset = p - h;
 +		}
 +	}
 +	return (0);
 +}
 +
 +static int
 +archive_read_format_cab_options(struct archive_read *a,
 +    const char *key, const char *val)
 +{
 +	struct cab *cab;
 +	int ret = ARCHIVE_FAILED;
 +
 +	cab = (struct cab *)(a->format->data);
 +	if (strcmp(key, "hdrcharset")  == 0) {
 +		if (val == NULL || val[0] == 0)
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "cab: hdrcharset option needs a character-set name");
 +		else {
 +			cab->sconv = archive_string_conversion_from_charset(
 +			    &a->archive, val, 0);
 +			if (cab->sconv != NULL)
 +				ret = ARCHIVE_OK;
 +			else
 +				ret = ARCHIVE_FATAL;
 +		}
- 	} else
- 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- 		    "cab: unknown keyword ``%s''", key);
++		return (ret);
++	}
 +
- 	return (ret);
++	/* Note: The "warn" return is just to inform the options
++	 * supervisor that we didn't handle it.  It will generate
++	 * a suitable error if no one used this option. */
++	return (ARCHIVE_WARN);
 +}
 +
 +static int
 +cab_skip_sfx(struct archive_read *a)
 +{
 +	const char *p, *q;
 +	size_t skip;
 +	ssize_t bytes, window;
 +
 +	window = 4096;
 +	for (;;) {
 +		const char *h = __archive_read_ahead(a, window, &bytes);
 +		if (h == NULL) {
 +			/* Remaining size are less than window. */
 +			window >>= 1;
 +			if (window < 128) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_FILE_FORMAT,
 +				    "Couldn't find out CAB header");
 +				return (ARCHIVE_FATAL);
 +			}
 +			continue;
 +		}
 +		p = h;
 +		q = p + bytes;
 +
 +		/*
 +		 * Scan ahead until we find something that looks
 +		 * like the cab header.
 +		 */
 +		while (p + 8 < q) {
 +			int next;
 +			if ((next = find_cab_magic(p)) == 0) {
 +				skip = p - h;
 +				__archive_read_consume(a, skip);
 +				return (ARCHIVE_OK);
 +			}
 +			p += next;
 +		}
 +		skip = p - h;
 +		__archive_read_consume(a, skip);
 +	}
 +}
 +
 +static int
 +truncated_error(struct archive_read *a)
 +{
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +	    "Truncated CAB header");
 +	return (ARCHIVE_FATAL);
 +}
 +
- static int
++static ssize_t
 +cab_strnlen(const unsigned char *p, size_t maxlen)
 +{
 +	size_t i;
 +
 +	for (i = 0; i <= maxlen; i++) {
 +		if (p[i] == 0)
 +			break;
 +	}
 +	if (i > maxlen)
 +		return (-1);/* invalid */
- 	return (i);
++	return ((ssize_t)i);
 +}
 +
 +/* Read bytes as much as remaining. */
 +static const void *
 +cab_read_ahead_remaining(struct archive_read *a, size_t min, ssize_t *avail)
 +{
 +	const void *p;
 +
 +	while (min > 0) {
 +		p = __archive_read_ahead(a, min, avail);
 +		if (p != NULL)
 +			return (p);
 +		min--;
 +	}
 +	return (NULL);
 +}
 +
 +/* Convert a path separator '\' -> '/' */
 +static int
 +cab_convert_path_separator_1(struct archive_string *fn, unsigned char attr)
 +{
 +	size_t i;
 +	int mb;
 +
 +	/* Easy check if we have '\' in multi-byte string. */
 +	mb = 0;
 +	for (i = 0; i < archive_strlen(fn); i++) {
 +		if (fn->s[i] == '\\') {
 +			if (mb) {
 +				/* This may be second byte of multi-byte
 +				 * character. */
 +				break;
 +			}
 +			fn->s[i] = '/';
 +			mb = 0;
 +		} else if ((fn->s[i] & 0x80) && !(attr & ATTR_NAME_IS_UTF))
 +			mb = 1;
 +		else
 +			mb = 0;
 +	}
 +	if (i == archive_strlen(fn))
 +		return (0);
 +	return (-1);
 +}
 +
 +/*
 + * Replace a character '\' with '/' in wide character.
 + */
 +static void
 +cab_convert_path_separator_2(struct cab *cab, struct archive_entry *entry)
 +{
 +	const wchar_t *wp;
 +	size_t i;
 +
 +	/* If a conversion to wide character failed, force the replacement. */
 +	if ((wp = archive_entry_pathname_w(entry)) != NULL) {
 +		archive_wstrcpy(&(cab->ws), wp);
 +		for (i = 0; i < archive_strlen(&(cab->ws)); i++) {
 +			if (cab->ws.s[i] == L'\\')
 +				cab->ws.s[i] = L'/';
 +		}
 +		archive_entry_copy_pathname_w(entry, cab->ws.s);
 +	}
 +}
 +
 +/*
 + * Read CFHEADER, CFFOLDER and CFFILE.
 + */
 +static int
 +cab_read_header(struct archive_read *a)
 +{
 +	const unsigned char *p;
 +	struct cab *cab;
 +	struct cfheader *hd;
 +	size_t bytes, used;
++	ssize_t len;
 +	int64_t skip;
- 	int err, i, len;
++	int err, i;
 +	int cur_folder, prev_folder;
 +	uint32_t offset32;
 +	
 +	a->archive.archive_format = ARCHIVE_FORMAT_CAB;
 +	if (a->archive.archive_format_name == NULL)
 +		a->archive.archive_format_name = "CAB";
 +
 +	if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
 +		return (truncated_error(a));
 +
 +	cab = (struct cab *)(a->format->data);
 +	if (cab->found_header == 0 &&
 +	    p[0] == 'M' && p[1] == 'Z') {
 +		/* This is an executable?  Must be self-extracting... 	*/
 +		err = cab_skip_sfx(a);
 +		if (err < ARCHIVE_WARN)
 +			return (err);
 +
 +		if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL)
 +			return (truncated_error(a));
 +	}
 +
 +	cab->cab_offset = 0;
 +	/*
 +	 * Read CFHEADER.
 +	 */
 +	hd = &cab->cfheader;
 +	if (p[CFHEADER_signature+0] != 'M' || p[CFHEADER_signature+1] != 'S' ||
 +	    p[CFHEADER_signature+2] != 'C' || p[CFHEADER_signature+3] != 'F') {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Couldn't find out CAB header");
 +		return (ARCHIVE_FATAL);
 +	}
 +	hd->total_bytes = archive_le32dec(p + CFHEADER_cbCabinet);
 +	hd->files_offset = archive_le32dec(p + CFHEADER_coffFiles);
 +	hd->minor = p[CFHEADER_versionMinor];
 +	hd->major = p[CFHEADER_versionMajor];
 +	hd->folder_count = archive_le16dec(p + CFHEADER_cFolders);
 +	if (hd->folder_count == 0)
 +		goto invalid;
 +	hd->file_count = archive_le16dec(p + CFHEADER_cFiles);
 +	if (hd->file_count == 0)
 +		goto invalid;
 +	hd->flags = archive_le16dec(p + CFHEADER_flags);
 +	hd->setid = archive_le16dec(p + CFHEADER_setID);
 +	hd->cabinet = archive_le16dec(p + CFHEADER_iCabinet);
 +	used = CFHEADER_iCabinet + 2;
 +	if (hd->flags & RESERVE_PRESENT) {
 +		uint16_t cfheader;
 +		cfheader = archive_le16dec(p + CFHEADER_cbCFHeader);
 +		if (cfheader > 60000U)
 +			goto invalid;
 +		hd->cffolder = p[CFHEADER_cbCFFolder];
 +		hd->cfdata = p[CFHEADER_cbCFData];
 +		used += 4;/* cbCFHeader, cbCFFolder and cbCFData */
 +		used += cfheader;/* abReserve */
 +	} else
 +		hd->cffolder = 0;/* Avoid compiling warning. */
 +	if (hd->flags & PREV_CABINET) {
 +		/* How many bytes are used for szCabinetPrev. */
 +		if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
 +			return (truncated_error(a));
 +		if ((len = cab_strnlen(p + used, 255)) <= 0)
 +			goto invalid;
 +		used += len + 1;
 +		/* How many bytes are used for szDiskPrev. */
 +		if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
 +			return (truncated_error(a));
 +		if ((len = cab_strnlen(p + used, 255)) <= 0)
 +			goto invalid;
 +		used += len + 1;
 +	}
 +	if (hd->flags & NEXT_CABINET) {
 +		/* How many bytes are used for szCabinetNext. */
 +		if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
 +			return (truncated_error(a));
 +		if ((len = cab_strnlen(p + used, 255)) <= 0)
 +			goto invalid;
 +		used += len + 1;
 +		/* How many bytes are used for szDiskNext. */
 +		if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
 +			return (truncated_error(a));
 +		if ((len = cab_strnlen(p + used, 255)) <= 0)
 +			goto invalid;
 +		used += len + 1;
 +	}
 +	__archive_read_consume(a, used);
 +	cab->cab_offset += used;
 +	used = 0;
 +
 +	/*
 +	 * Read CFFOLDER.
 +	 */
 +	hd->folder_array = (struct cffolder *)calloc(
 +	    hd->folder_count, sizeof(struct cffolder));
 +	if (hd->folder_array == NULL)
 +		goto nomem;
 +	
 +	bytes = 8;
 +	if (hd->flags & RESERVE_PRESENT)
 +		bytes += hd->cffolder;
 +	bytes *= hd->folder_count;
 +	if ((p = __archive_read_ahead(a, bytes, NULL)) == NULL)
 +		return (truncated_error(a));
 +	offset32 = 0;
 +	for (i = 0; i < hd->folder_count; i++) {
 +		struct cffolder *folder = &(hd->folder_array[i]);
 +		folder->cfdata_offset_in_cab =
 +		    archive_le32dec(p + CFFOLDER_coffCabStart);
 +		folder->cfdata_count = archive_le16dec(p+CFFOLDER_cCFData);
 +		folder->comptype =
 +		    archive_le16dec(p+CFFOLDER_typeCompress) & 0x0F;
 +		folder->compdata =
 +		    archive_le16dec(p+CFFOLDER_typeCompress) >> 8;
 +		/* Get a compression name. */
 +		if (folder->comptype <
 +		    sizeof(compression_name) / sizeof(compression_name[0]))
 +			folder->compname = compression_name[folder->comptype];
 +		else
 +			folder->compname = "UNKNOWN";
 +		p += 8;
 +		used += 8;
 +		if (hd->flags & RESERVE_PRESENT) {
 +			p += hd->cffolder;/* abReserve */
 +			used += hd->cffolder;
 +		}
 +		/*
 +		 * Sanity check if each data is acceptable.
 +		 */
 +		if (offset32 >= folder->cfdata_offset_in_cab)
 +			goto invalid;
 +		offset32 = folder->cfdata_offset_in_cab;
 +
 +		/* Set a request to initialize zlib for the CFDATA of
 +		 * this folder. */
 +		folder->decompress_init = 0;
 +	}
 +	__archive_read_consume(a, used);
 +	cab->cab_offset += used;
 +
 +	/*
 +	 * Read CFFILE.
 +	 */
 +	/* Seek read pointer to the offset of CFFILE if needed. */
 +	skip = (int64_t)hd->files_offset - cab->cab_offset;
 +	if (skip <  0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid offset of CFFILE %jd < %jd",
 +		    (intmax_t)hd->files_offset, (intmax_t)cab->cab_offset);
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (skip) {
 +		__archive_read_consume(a, skip);
 +		cab->cab_offset += skip;
 +	}
 +	/* Allocate memory for CFDATA */
 +	hd->file_array = (struct cffile *)calloc(
 +	    hd->file_count, sizeof(struct cffile));
 +	if (hd->file_array == NULL)
 +		goto nomem;
 +
 +	prev_folder = -1;
 +	for (i = 0; i < hd->file_count; i++) {
 +		struct cffile *file = &(hd->file_array[i]);
 +		ssize_t avail;
 +
 +		if ((p = __archive_read_ahead(a, 16, NULL)) == NULL)
 +			return (truncated_error(a));
 +		file->uncompressed_size = archive_le32dec(p + CFFILE_cbFile);
 +		file->offset = archive_le32dec(p + CFFILE_uoffFolderStart);
 +		file->folder = archive_le16dec(p + CFFILE_iFolder);
 +		file->mtime = cab_dos_time(p + CFFILE_date_time);
- 		file->attr = archive_le16dec(p + CFFILE_attribs);
++		file->attr = (uint8_t)archive_le16dec(p + CFFILE_attribs);
 +		__archive_read_consume(a, 16);
 +
 +		cab->cab_offset += 16;
 +		if ((p = cab_read_ahead_remaining(a, 256, &avail)) == NULL)
 +			return (truncated_error(a));
 +		if ((len = cab_strnlen(p, avail-1)) <= 0)
 +			goto invalid;
 +
 +		/* Copy a pathname.  */
 +		archive_string_init(&(file->pathname));
 +		archive_strncpy(&(file->pathname), p, len);
 +		__archive_read_consume(a, len + 1);
 +		cab->cab_offset += len + 1;
 +
 +		/*
 +		 * Sanity check if each data is acceptable.
 +		 */
 +		if (file->uncompressed_size > 0x7FFF8000)
 +			goto invalid;/* Too large */
 +		if ((int64_t)file->offset + (int64_t)file->uncompressed_size
 +		    > ARCHIVE_LITERAL_LL(0x7FFF8000))
 +			goto invalid;/* Too large */
 +		switch (file->folder) {
 +		case iFoldCONTINUED_TO_NEXT:
 +			/* This must be last file in a folder. */
 +			if (i != hd->file_count -1)
 +				goto invalid;
 +			cur_folder = hd->folder_count -1;
 +			break;
 +		case iFoldCONTINUED_PREV_AND_NEXT:
 +			/* This must be only one file in a folder. */
 +			if (hd->file_count != 1)
 +				goto invalid;
 +			/* FALL THROUGH */
 +		case iFoldCONTINUED_FROM_PREV:
 +			/* This must be first file in a folder. */
 +			if (i != 0)
 +				goto invalid;
 +			prev_folder = cur_folder = 0;
 +			offset32 = file->offset;
 +			break;
 +		default:
 +			if (file->folder >= hd->folder_count)
 +				goto invalid;
 +			cur_folder = file->folder;
 +			break;
 +		}
 +		/* Dot not back track. */
 +		if (cur_folder < prev_folder)
 +			goto invalid;
 +		if (cur_folder != prev_folder)
 +			offset32 = 0;
 +		prev_folder = cur_folder;
 +
 +		/* Make sure there are not any blanks from last file
 +		 * contents. */
 +		if (offset32 != file->offset)
 +			goto invalid;
 +		offset32 += file->uncompressed_size;
 +
 +		/* CFDATA is available for file contents. */
 +		if (file->uncompressed_size > 0 &&
 +		    hd->folder_array[cur_folder].cfdata_count == 0)
 +			goto invalid;
 +	}
 +
 +	if (hd->cabinet != 0 || hd->flags & (PREV_CABINET | NEXT_CABINET)) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Multivolume cabinet file is unsupported");
 +		return (ARCHIVE_WARN);
 +	}
 +	return (ARCHIVE_OK);
 +invalid:
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +	    "Invalid CAB header");
 +	return (ARCHIVE_FATAL);
 +nomem:
 +	archive_set_error(&a->archive, ENOMEM,
 +	    "Can't allocate memory for CAB data");
 +	return (ARCHIVE_FATAL);
 +}
 +
 +static int
 +archive_read_format_cab_read_header(struct archive_read *a,
 +    struct archive_entry *entry)
 +{
 +	struct cab *cab;
 +	struct cfheader *hd;
 +	struct cffolder *prev_folder;
 +	struct cffile *file;
 +	struct archive_string_conv *sconv;
 +	int err = ARCHIVE_OK, r;
 +	
 +	cab = (struct cab *)(a->format->data);
 +	if (cab->found_header == 0) {
 +		err = cab_read_header(a); 
 +		if (err < ARCHIVE_WARN)
 +			return (err);
 +		/* We've found the header. */
 +		cab->found_header = 1;
 +	}
 +	hd = &cab->cfheader;
 +
 +	if (hd->file_index >= hd->file_count) {
 +		cab->end_of_archive = 1;
 +		return (ARCHIVE_EOF);
 +	}
 +	file = &hd->file_array[hd->file_index++];
 +
 +	cab->end_of_entry = 0;
 +	cab->end_of_entry_cleanup = 0;
 +	cab->entry_compressed_bytes_read = 0;
 +	cab->entry_uncompressed_bytes_read = 0;
 +	cab->entry_unconsumed = 0;
 +	cab->entry_cffile = file;
 +
 +	/*
 +	 * Choose a proper folder.
 +	 */
 +	prev_folder = cab->entry_cffolder;
 +	switch (file->folder) {
 +	case iFoldCONTINUED_FROM_PREV:
 +	case iFoldCONTINUED_PREV_AND_NEXT:
 +		cab->entry_cffolder = &hd->folder_array[0];
 +		break;
 +	case iFoldCONTINUED_TO_NEXT:
 +		cab->entry_cffolder = &hd->folder_array[hd->folder_count-1];
 +		break;
 +	default:
 +		cab->entry_cffolder = &hd->folder_array[file->folder];
 +		break;
 +	}
 +	/* If a cffolder of this file is changed, reset a cfdata to read
 +	 * file contents from next cfdata. */
 +	if (prev_folder != cab->entry_cffolder)
 +		cab->entry_cfdata = NULL;
 +
 +	/* If a pathname is UTF-8, prepare a string conversion object
 +	 * for UTF-8 and use it. */
 +	if (file->attr & ATTR_NAME_IS_UTF) {
 +		if (cab->sconv_utf8 == NULL) {
 +			cab->sconv_utf8 =
 +			    archive_string_conversion_from_charset(
 +				&(a->archive), "UTF-8", 1);
 +			if (cab->sconv_utf8 == NULL)
 +				return (ARCHIVE_FATAL);
 +		}
 +		sconv = cab->sconv_utf8;
 +	} else if (cab->sconv != NULL) {
 +		/* Choose the conversion specified by the option. */
 +		sconv = cab->sconv;
 +	} else {
 +		/* Choose the default conversion. */
 +		if (!cab->init_default_conversion) {
 +			cab->sconv_default =
 +			    archive_string_default_conversion_for_read(
 +			      &(a->archive));
 +			cab->init_default_conversion = 1;
 +		}
 +		sconv = cab->sconv_default;
 +	}
 +
 +	/*
 +	 * Set a default value and common data
 +	 */
 +	r = cab_convert_path_separator_1(&(file->pathname), file->attr);
 +	if (archive_entry_copy_pathname_l(entry, file->pathname.s,
 +	    archive_strlen(&(file->pathname)), sconv) != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Pathname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Pathname cannot be converted "
 +		    "from %s to current locale.",
 +		    archive_string_conversion_charset_name(sconv));
 +		err = ARCHIVE_WARN;
 +	}
 +	if (r < 0) {
 +		/* Convert a path separator '\' -> '/' */
 +		cab_convert_path_separator_2(cab, entry);
 +	}
 +
 +	archive_entry_set_size(entry, file->uncompressed_size);
 +	if (file->attr & ATTR_RDONLY)
 +		archive_entry_set_mode(entry, AE_IFREG | 0555);
 +	else
- 		archive_entry_set_mode(entry, AE_IFREG | 0777);
++		archive_entry_set_mode(entry, AE_IFREG | 0666);
 +	archive_entry_set_mtime(entry, file->mtime, 0);
 +
 +	cab->entry_bytes_remaining = file->uncompressed_size;
 +	cab->entry_offset = 0;
 +	/* We don't need compress data. */
 +	if (file->uncompressed_size == 0)
 +		cab->end_of_entry_cleanup = cab->end_of_entry = 1;
 +
 +	/* Set up a more descriptive format name. */
 +	sprintf(cab->format_name, "CAB %d.%d (%s)",
 +	    hd->major, hd->minor, cab->entry_cffolder->compname);
 +	a->archive.archive_format_name = cab->format_name;
 +
 +	return (err);
 +}
 +
 +static int
 +archive_read_format_cab_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	int r;
 +
 +	switch (cab->entry_cffile->folder) {
 +	case iFoldCONTINUED_FROM_PREV:
 +	case iFoldCONTINUED_TO_NEXT:
 +	case iFoldCONTINUED_PREV_AND_NEXT:
 +		*buff = NULL;
 +		*size = 0;
 +		*offset = 0;
 +		archive_clear_error(&a->archive);
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Cannot restore this file split in multivolume.");
 +		return (ARCHIVE_FAILED);
 +	default:
 +		break;
 +	}
++	if (cab->read_data_invoked == 0) {
++		if (cab->bytes_skipped) {
++			if (cab->entry_cfdata == NULL) {
++				r = cab_next_cfdata(a);
++				if (r < 0)
++					return (r);
++			}
++			if (cab_consume_cfdata(a, cab->bytes_skipped) < 0)
++				return (ARCHIVE_FATAL);
++			cab->bytes_skipped = 0;
++		}
++		cab->read_data_invoked = 1;
++	}
 +	if (cab->entry_unconsumed) {
 +		/* Consume as much as the compressor actually used. */
- 		r = cab_consume_cfdata(a, cab->entry_unconsumed);
++		r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
 +		cab->entry_unconsumed = 0;
 +		if (r < 0)
 +			return (r);
 +	}
 +	if (cab->end_of_archive || cab->end_of_entry) {
 +		if (!cab->end_of_entry_cleanup) {
 +			/* End-of-entry cleanup done. */
 +			cab->end_of_entry_cleanup = 1;
 +		}
 +		*offset = cab->entry_offset;
 +		*size = 0;
 +		*buff = NULL;
 +		return (ARCHIVE_EOF);
 +	}
 +
 +	return (cab_read_data(a, buff, size, offset));
 +}
 +
 +static uint32_t
 +cab_checksum_cfdata_4(const void *p, size_t bytes, uint32_t seed)
 +{
 +	const unsigned char *b;
- 	int u32num;
++	unsigned u32num;
 +	uint32_t sum;
 +
- 	u32num = bytes / 4;
++	u32num = (unsigned)bytes / 4;
 +	sum = seed;
 +	b = p;
- 	while (--u32num >= 0) {
++	for (;u32num > 0; --u32num) {
 +		sum ^= archive_le32dec(b);
 +		b += 4;
 +	}
 +	return (sum);
 +}
 +
 +static uint32_t
 +cab_checksum_cfdata(const void *p, size_t bytes, uint32_t seed)
 +{
 +	const unsigned char *b;
 +	uint32_t sum;
 +	uint32_t t;
 +
 +	sum = cab_checksum_cfdata_4(p, bytes, seed);
 +	b = p;
 +	b += bytes & ~3;
 +	t = 0;
 +	switch (bytes & 3) {
 +	case 3:
 +		t |= ((uint32_t)(*b++)) << 16;
 +		/* FALL THROUGH */
 +	case 2:
 +		t |= ((uint32_t)(*b++)) << 8;
 +		/* FALL THROUGH */
 +	case 1:
 +		t |= *b;
 +		/* FALL THROUGH */
 +	default:
 +		break;
 +	}
 +	sum ^= t;
 +
 +	return (sum);
 +}
 +
 +static void
 +cab_checksum_update(struct archive_read *a, size_t bytes)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	struct cfdata *cfdata = cab->entry_cfdata;
 +	const unsigned char *p;
 +	size_t sumbytes;
 +
 +	if (cfdata->sum == 0 || cfdata->sum_ptr == NULL)
 +		return;
 +	/*
 +	 * Calculate the sum of this CFDATA.
 +	 * Make sure CFDATA must be calculated in four bytes.
 +	 */
 +	p = cfdata->sum_ptr;
 +	sumbytes = bytes;
 +	if (cfdata->sum_extra_avail) {
 +		while (cfdata->sum_extra_avail < 4 && sumbytes > 0) {
 +			cfdata->sum_extra[
 +			    cfdata->sum_extra_avail++] = *p++;
 +			sumbytes--;
 +		}
 +		if (cfdata->sum_extra_avail == 4) {
 +			cfdata->sum_calculated = cab_checksum_cfdata_4(
 +			    cfdata->sum_extra, 4, cfdata->sum_calculated);
 +			cfdata->sum_extra_avail = 0;
 +		}
 +	}
 +	if (sumbytes) {
 +		int odd = sumbytes & 3;
 +		if (sumbytes - odd > 0)
 +			cfdata->sum_calculated = cab_checksum_cfdata_4(
 +			    p, sumbytes - odd, cfdata->sum_calculated);
 +		if (odd)
 +			memcpy(cfdata->sum_extra, p + sumbytes - odd, odd);
 +		cfdata->sum_extra_avail = odd;
 +	}
 +	cfdata->sum_ptr = NULL;
 +}
 +
 +static int
 +cab_checksum_finish(struct archive_read *a)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	struct cfdata *cfdata = cab->entry_cfdata;
 +	int l;
 +
 +	/* Do not need to compute a sum. */
 +	if (cfdata->sum == 0)
 +		return (ARCHIVE_OK);
 +
 +	/*
 +	 * Calculate the sum of remaining CFDATA.
 +	 */
 +	if (cfdata->sum_extra_avail) {
 +		cfdata->sum_calculated =
 +		    cab_checksum_cfdata(cfdata->sum_extra,
 +		       cfdata->sum_extra_avail, cfdata->sum_calculated);
 +		cfdata->sum_extra_avail = 0;
 +	}
 +
 +	l = 4;
 +	if (cab->cfheader.flags & RESERVE_PRESENT)
 +		l += cab->cfheader.cfdata;
 +	cfdata->sum_calculated = cab_checksum_cfdata(
 +	    cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);
 +	if (cfdata->sum_calculated != cfdata->sum) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Checksum error CFDATA[%d] %x:%x in %d bytes",
 +		    cab->entry_cffolder->cfdata_index -1,
 +		    cfdata->sum, cfdata->sum_calculated,
 +		    cfdata->compressed_size);
 +		return (ARCHIVE_FAILED);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Read CFDATA if needed.
 + */
 +static int
 +cab_next_cfdata(struct archive_read *a)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	struct cfdata *cfdata = cab->entry_cfdata;
 +
 +	/* There are remaining bytes in current CFDATA, use it first. */
 +	if (cfdata != NULL && cfdata->uncompressed_bytes_remaining > 0)
 +		return (ARCHIVE_OK);
 +
 +	if (cfdata == NULL) {
 +		int64_t skip;
 +
 +		cab->entry_cffolder->cfdata_index = 0;
 +
 +		/* Seek read pointer to the offset of CFDATA if needed. */
 +		skip = cab->entry_cffolder->cfdata_offset_in_cab
 +			- cab->cab_offset;
 +		if (skip < 0) {
 +			int folder_index;
 +			switch (cab->entry_cffile->folder) {
 +			case iFoldCONTINUED_FROM_PREV:
 +			case iFoldCONTINUED_PREV_AND_NEXT:
 +				folder_index = 0;
 +				break;
 +			case iFoldCONTINUED_TO_NEXT:
 +				folder_index = cab->cfheader.folder_count-1;
 +				break;
 +			default:
 +				folder_index = cab->entry_cffile->folder;
 +				break;
 +			}
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Invalid offset of CFDATA in folder(%d) %jd < %jd",
 +			    folder_index,
 +			    (intmax_t)cab->entry_cffolder->cfdata_offset_in_cab,
 +			    (intmax_t)cab->cab_offset);
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (skip > 0) {
 +			if (__archive_read_consume(a, skip) < 0)
 +				return (ARCHIVE_FATAL);
 +			cab->cab_offset =
 +			    cab->entry_cffolder->cfdata_offset_in_cab;
 +		}
 +	}
 +
 +	/*
 +	 * Read a CFDATA.
 +	 */
 +	if (cab->entry_cffolder->cfdata_index <
 +	    cab->entry_cffolder->cfdata_count) {
 +		const unsigned char *p;
 +		int l;
 +
 +		cfdata = &(cab->entry_cffolder->cfdata);
 +		cab->entry_cffolder->cfdata_index++;
 +		cab->entry_cfdata = cfdata;
 +		cfdata->sum_calculated = 0;
 +		cfdata->sum_extra_avail = 0;
 +		cfdata->sum_ptr = NULL;
 +		l = 8;
 +		if (cab->cfheader.flags & RESERVE_PRESENT)
 +			l += cab->cfheader.cfdata;
 +		if ((p = __archive_read_ahead(a, l, NULL)) == NULL)
 +			return (truncated_error(a));
 +		cfdata->sum = archive_le32dec(p + CFDATA_csum);
 +		cfdata->compressed_size = archive_le16dec(p + CFDATA_cbData);
 +		cfdata->compressed_bytes_remaining = cfdata->compressed_size;
 +		cfdata->uncompressed_size =
 +		    archive_le16dec(p + CFDATA_cbUncomp);
 +		cfdata->uncompressed_bytes_remaining =
 +		    cfdata->uncompressed_size;
 +		cfdata->uncompressed_avail = 0;
 +		cfdata->read_offset = 0;
 +		cfdata->unconsumed = 0;
 +
 +		/*
 +		 * Sanity check if data size is acceptable.
 +		 */
 +		if (cfdata->compressed_size == 0 ||
 +		    cfdata->compressed_size > (0x8000+6144))
 +			goto invalid;
 +		if (cfdata->uncompressed_size > 0x8000)
 +			goto invalid;
 +		if (cfdata->uncompressed_size == 0) {
 +			switch (cab->entry_cffile->folder) {
 +			case iFoldCONTINUED_PREV_AND_NEXT:
 +			case iFoldCONTINUED_TO_NEXT:
 +				break;
 +			case iFoldCONTINUED_FROM_PREV:
 +			default:
 +				goto invalid;
 +			}
 +		}
 +		/* If CFDATA is not last in a folder, an uncompressed
 +		 * size must be 0x8000(32KBi) */
 +		if ((cab->entry_cffolder->cfdata_index <
 +		     cab->entry_cffolder->cfdata_count) &&
 +		       cfdata->uncompressed_size != 0x8000)
 +			goto invalid;
 +
 +		/* A compressed data size and an uncompressed data size must
 +		 * be the same in no compression mode. */
 +		if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
 +		    cfdata->compressed_size != cfdata->uncompressed_size)
 +			goto invalid;
 +
 +		/*
 +		 * Save CFDATA image for sum check.
 +		 */
 +		if (cfdata->memimage_size < (size_t)l) {
 +			free(cfdata->memimage);
 +			cfdata->memimage = malloc(l);
 +			if (cfdata->memimage == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "Can't allocate memory for CAB data");
 +				return (ARCHIVE_FATAL);
 +			}
 +			cfdata->memimage_size = l;
 +		}
 +		memcpy(cfdata->memimage, p, l);
 +
 +		/* Consume bytes as much as we used. */
 +		__archive_read_consume(a, l);
 +		cab->cab_offset += l;
 +	} else if (cab->entry_cffolder->cfdata_count > 0) {
 +		/* Run out of all CFDATA in a folder. */
 +		cfdata->compressed_size = 0;
 +		cfdata->uncompressed_size = 0;
 +		cfdata->compressed_bytes_remaining = 0;
 +		cfdata->uncompressed_bytes_remaining = 0;
 +	} else {
 +		/* Current folder does not have any CFDATA. */
 +		cfdata = &(cab->entry_cffolder->cfdata);
 +		cab->entry_cfdata = cfdata;
 +		memset(cfdata, 0, sizeof(*cfdata));
 +	}
 +	return (ARCHIVE_OK);
 +invalid:
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +	    "Invalid CFDATA");
 +	return (ARCHIVE_FATAL);
 +}
 +
 +/*
 + * Read ahead CFDATA.
 + */
 +static const void *
 +cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	int err;
 +
 +	err = cab_next_cfdata(a);
 +	if (err < ARCHIVE_OK) {
 +		*avail = err;
 +		return (NULL);
 +	}
 +
 +	switch (cab->entry_cffolder->comptype) {
 +	case COMPTYPE_NONE:
 +		return (cab_read_ahead_cfdata_none(a, avail));
 +	case COMPTYPE_MSZIP:
 +		return (cab_read_ahead_cfdata_deflate(a, avail));
 +	case COMPTYPE_LZX:
 +		return (cab_read_ahead_cfdata_lzx(a, avail));
 +	default: /* Unsupported compression. */
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Unsupported CAB compression : %s",
 +		    cab->entry_cffolder->compname);
 +		*avail = ARCHIVE_FAILED;
 +		return (NULL);
 +	}
 +}
 +
 +/*
 + * Read ahead CFDATA as uncompressed data.
 + */
 +static const void *
 +cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	struct cfdata *cfdata;
 +	const void *d;
- 	int64_t skipped_bytes;
 +
 +	cfdata = cab->entry_cfdata;
 +
- 	if (cfdata->uncompressed_avail == 0 &&
- 		cfdata->read_offset > 0) {
- 		/* we've already skipped some bytes before really read. */
- 		skipped_bytes = cfdata->read_offset;
- 		cfdata->read_offset = 0;
- 		cfdata->uncompressed_bytes_remaining += skipped_bytes;
- 	} else
- 		skipped_bytes = 0;
- 	do {
- 		/*
- 		 * Note: '1' here is a performance optimization.
- 		 * Recall that the decompression layer returns a count of
- 		 * available bytes; asking for more than that forces the
- 		 * decompressor to combine reads by copying data.
- 		 */
- 		d = __archive_read_ahead(a, 1, avail);
- 		if (*avail <= 0) {
- 			*avail = truncated_error(a);
- 			return (NULL);
- 		}
- 		if (*avail > cfdata->uncompressed_bytes_remaining)
- 			*avail = cfdata->uncompressed_bytes_remaining;
- 		cfdata->uncompressed_avail = cfdata->uncompressed_size;
- 		cfdata->unconsumed = *avail;
- 		cfdata->sum_ptr = d;
- 		if (skipped_bytes > 0) {
- 			skipped_bytes =
- 			    cab_minimum_consume_cfdata(a, skipped_bytes);
- 			if (skipped_bytes < 0) {
- 				*avail = ARCHIVE_FATAL;
- 				return (NULL);
- 			}
- 			continue;
- 		}
- 	} while (0);
- 
++	/*
++	 * Note: '1' here is a performance optimization.
++	 * Recall that the decompression layer returns a count of
++	 * available bytes; asking for more than that forces the
++	 * decompressor to combine reads by copying data.
++	 */
++	d = __archive_read_ahead(a, 1, avail);
++	if (*avail <= 0) {
++		*avail = truncated_error(a);
++		return (NULL);
++	}
++	if (*avail > cfdata->uncompressed_bytes_remaining)
++		*avail = cfdata->uncompressed_bytes_remaining;
++	cfdata->uncompressed_avail = cfdata->uncompressed_size;
++	cfdata->unconsumed = *avail;
++	cfdata->sum_ptr = d;
 +	return (d);
 +}
 +
 +/*
 + * Read ahead CFDATA as deflate data.
 + */
 +#ifdef HAVE_ZLIB_H
 +static const void *
 +cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	struct cfdata *cfdata;
 +	const void *d;
 +	int r, mszip;
 +	uint16_t uavail;
 +	char eod = 0;
 +
 +	cfdata = cab->entry_cfdata;
 +	/* If the buffer hasn't been allocated, allocate it now. */
 +	if (cab->uncompressed_buffer == NULL) {
 +		cab->uncompressed_buffer_size = 0x8000;
 +		cab->uncompressed_buffer
 +		    = (unsigned char *)malloc(cab->uncompressed_buffer_size);
 +		if (cab->uncompressed_buffer == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "No memory for CAB reader");
 +			*avail = ARCHIVE_FATAL;
 +			return (NULL);
 +		}
 +	}
 +
 +	uavail = cfdata->uncompressed_avail;
 +	if (uavail == cfdata->uncompressed_size) {
 +		d = cab->uncompressed_buffer + cfdata->read_offset;
 +		*avail = uavail - cfdata->read_offset;
 +		return (d);
 +	}
 +
 +	if (!cab->entry_cffolder->decompress_init) {
 +		cab->stream.next_in = NULL;
 +		cab->stream.avail_in = 0;
 +		cab->stream.total_in = 0;
 +		cab->stream.next_out = NULL;
 +		cab->stream.avail_out = 0;
 +		cab->stream.total_out = 0;
 +		if (cab->stream_valid)
 +			r = inflateReset(&cab->stream);
 +		else
 +			r = inflateInit2(&cab->stream,
 +			    -15 /* Don't check for zlib header */);
 +		if (r != Z_OK) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Can't initialize deflate decompression.");
 +			*avail = ARCHIVE_FATAL;
 +			return (NULL);
 +		}
 +		/* Stream structure has been set up. */
 +		cab->stream_valid = 1;
 +		/* We've initialized decompression for this stream. */
 +		cab->entry_cffolder->decompress_init = 1;
 +	}
 +
 +	if (cfdata->compressed_bytes_remaining == cfdata->compressed_size)
 +		mszip = 2;
 +	else
 +		mszip = 0;
 +	eod = 0;
 +	cab->stream.total_out = uavail;
 +	/*
 +	 * We always uncompress all data in current CFDATA.
 +	 */
 +	while (!eod && cab->stream.total_out < cfdata->uncompressed_size) {
 +		ssize_t bytes_avail;
 +
 +		cab->stream.next_out =
 +		    cab->uncompressed_buffer + cab->stream.total_out;
 +		cab->stream.avail_out =
 +		    cfdata->uncompressed_size - cab->stream.total_out;
 +
 +		d = __archive_read_ahead(a, 1, &bytes_avail);
 +		if (bytes_avail <= 0) {
 +			*avail = truncated_error(a);
 +			return (NULL);
 +		}
 +		if (bytes_avail > cfdata->compressed_bytes_remaining)
 +			bytes_avail = cfdata->compressed_bytes_remaining;
 +		/*
 +		 * A bug in zlib.h: stream.next_in should be marked 'const'
 +		 * but isn't (the library never alters data through the
 +		 * next_in pointer, only reads it).  The result: this ugly
 +		 * cast to remove 'const'.
 +		 */
 +		cab->stream.next_in = (Bytef *)(uintptr_t)d;
- 		cab->stream.avail_in = bytes_avail;
++		cab->stream.avail_in = (uInt)bytes_avail;
 +		cab->stream.total_in = 0;
 +
 +		/* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */
 +		if (mszip > 0) {
 +			if (bytes_avail <= mszip) {
 +				if (mszip == 2) {
 +					if (cab->stream.next_in[0] != 0x43)
 +						goto nomszip;
 +					if (bytes_avail > 1 &&
 +					    cab->stream.next_in[1] != 0x4b)
 +						goto nomszip;
 +				} else if (cab->stream.next_in[0] != 0x4b)
 +					goto nomszip;
 +				cfdata->unconsumed = bytes_avail;
 +				cfdata->sum_ptr = d;
 +				if (cab_minimum_consume_cfdata(
 +				    a, cfdata->unconsumed) < 0) {
 +					*avail = ARCHIVE_FATAL;
 +					return (NULL);
 +				}
- 				mszip -= bytes_avail;
++				mszip -= (int)bytes_avail;
 +				continue;
 +			}
 +			if (mszip == 1 && cab->stream.next_in[0] != 0x4b)
 +				goto nomszip;
 +			else if (cab->stream.next_in[0] != 0x43 ||
 +			    cab->stream.next_in[1] != 0x4b)
 +				goto nomszip;
 +			cab->stream.next_in += mszip;
 +			cab->stream.avail_in -= mszip;
 +			cab->stream.total_in += mszip;
 +			mszip = 0;
 +		}
 +
 +		r = inflate(&cab->stream, 0);
 +		switch (r) {
 +		case Z_OK:
 +			break;
 +		case Z_STREAM_END:
 +			eod = 1;
 +			break;
 +		default:
 +			goto zlibfailed;
 +		}
 +		cfdata->unconsumed = cab->stream.total_in;
 +		cfdata->sum_ptr = d;
 +		if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
 +			*avail = ARCHIVE_FATAL;
 +			return (NULL);
 +		}
 +	}
- 	uavail = cab->stream.total_out;
++	uavail = (uint16_t)cab->stream.total_out;
 +
 +	if (uavail < cfdata->uncompressed_size) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid uncompressed size (%d < %d)",
 +		    uavail, cfdata->uncompressed_size);
 +		*avail = ARCHIVE_FATAL;
 +		return (NULL);
 +	}
 +
 +	/*
 +	 * Note: I suspect there is a bug in makecab.exe because, in rare
 +	 * case, compressed bytes are still remaining regardless we have
 +	 * gotten all uncompressed bytes, which size is recoded in CFDATA,
 +	 * as much as we need, and we have to use the garbage so as to
 +	 * correctly compute the sum of CFDATA accordingly.
 +	 */
 +	if (cfdata->compressed_bytes_remaining > 0) {
 +		ssize_t bytes_avail;
 +
 +		d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
 +		    &bytes_avail);
 +		if (bytes_avail <= 0) {
 +			*avail = truncated_error(a);
 +			return (NULL);
 +		}
 +		cfdata->unconsumed = cfdata->compressed_bytes_remaining;
 +		cfdata->sum_ptr = d;
 +		if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
 +			*avail = ARCHIVE_FATAL;
 +			return (NULL);
 +		}
 +	}
 +
 +	/*
 +	 * Set dictionary data for decompressing of next CFDATA, which
 +	 * in the same folder. This is why we always do decompress CFDATA
 +	 * even if beginning CFDATA or some of CFDATA are not used in
 +	 * skipping file data.
 +	 */
 +	if (cab->entry_cffolder->cfdata_index <
 +	    cab->entry_cffolder->cfdata_count) {
 +		r = inflateReset(&cab->stream);
 +		if (r != Z_OK)
 +			goto zlibfailed;
 +		r = inflateSetDictionary(&cab->stream,
 +		    cab->uncompressed_buffer, cfdata->uncompressed_size);
 +		if (r != Z_OK)
 +			goto zlibfailed;
 +	}
 +
 +	d = cab->uncompressed_buffer + cfdata->read_offset;
 +	*avail = uavail - cfdata->read_offset;
 +	cfdata->uncompressed_avail = uavail;
 +
 +	return (d);
 +
 +zlibfailed:
 +	switch (r) {
 +	case Z_MEM_ERROR:
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Out of memory for deflate decompression");
 +		break;
 +	default:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Deflate decompression failed (%d)", r);
 +		break;
 +	}
 +	*avail = ARCHIVE_FATAL;
 +	return (NULL);
 +nomszip:
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +	    "CFDATA incorrect(no MSZIP signature)");
 +	*avail = ARCHIVE_FATAL;
 +	return (NULL);
 +}
 +
 +#else /* HAVE_ZLIB_H */
 +
 +static const void *
 +cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
 +{
 +	*avail = ARCHIVE_FATAL;
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +	    "libarchive compiled without deflate support (no libz)");
 +	return (NULL);
 +}
 +
 +#endif /* HAVE_ZLIB_H */
 +
 +static const void *
 +cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	struct cfdata *cfdata;
 +	const void *d;
 +	int r;
 +	uint16_t uavail;
 +
 +	cfdata = cab->entry_cfdata;
 +	/* If the buffer hasn't been allocated, allocate it now. */
 +	if (cab->uncompressed_buffer == NULL) {
 +		cab->uncompressed_buffer_size = 0x8000;
 +		cab->uncompressed_buffer
 +		    = (unsigned char *)malloc(cab->uncompressed_buffer_size);
 +		if (cab->uncompressed_buffer == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "No memory for CAB reader");
 +			*avail = ARCHIVE_FATAL;
 +			return (NULL);
 +		}
 +	}
 +
 +	uavail = cfdata->uncompressed_avail;
 +	if (uavail == cfdata->uncompressed_size) {
 +		d = cab->uncompressed_buffer + cfdata->read_offset;
 +		*avail = uavail - cfdata->read_offset;
 +		return (d);
 +	}
 +
 +	if (!cab->entry_cffolder->decompress_init) {
 +		r = lzx_decode_init(&cab->xstrm,
 +		    cab->entry_cffolder->compdata);
 +		if (r != ARCHIVE_OK) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Can't initialize LZX decompression.");
 +			*avail = ARCHIVE_FATAL;
 +			return (NULL);
 +		}
 +		/* We've initialized decompression for this stream. */
 +		cab->entry_cffolder->decompress_init = 1;
 +	}
 +
 +	/* Clean up remaining bits of previous CFDATA. */
 +	lzx_cleanup_bitstream(&cab->xstrm);
 +	cab->xstrm.total_out = uavail;
 +	while (cab->xstrm.total_out < cfdata->uncompressed_size) {
 +		ssize_t bytes_avail;
 +
 +		cab->xstrm.next_out =
 +		    cab->uncompressed_buffer + cab->xstrm.total_out;
 +		cab->xstrm.avail_out =
 +		    cfdata->uncompressed_size - cab->xstrm.total_out;
 +
 +		d = __archive_read_ahead(a, 1, &bytes_avail);
 +		if (bytes_avail <= 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated CAB file data");
 +			*avail = ARCHIVE_FATAL;
 +			return (NULL);
 +		}
 +		if (bytes_avail > cfdata->compressed_bytes_remaining)
 +			bytes_avail = cfdata->compressed_bytes_remaining;
 +
 +		cab->xstrm.next_in = d;
 +		cab->xstrm.avail_in = bytes_avail;
 +		cab->xstrm.total_in = 0;
 +		r = lzx_decode(&cab->xstrm,
 +		    cfdata->compressed_bytes_remaining == bytes_avail);
 +		switch (r) {
 +		case ARCHIVE_OK:
 +		case ARCHIVE_EOF:
 +			break;
 +		default:
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "LZX decompression failed (%d)", r);
 +			*avail = ARCHIVE_FATAL;
 +			return (NULL);
 +		}
 +		cfdata->unconsumed = cab->xstrm.total_in;
 +		cfdata->sum_ptr = d;
 +		if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
 +			*avail = ARCHIVE_FATAL;
 +			return (NULL);
 +		}
 +	}
 +
- 	uavail = cab->xstrm.total_out;
++	uavail = (uint16_t)cab->xstrm.total_out;
 +	/*
 +	 * Make sure a read pointer advances to next CFDATA.
 +	 */
 +	if (cfdata->compressed_bytes_remaining > 0) {
 +		ssize_t bytes_avail;
 +
 +		d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
 +		    &bytes_avail);
 +		if (bytes_avail <= 0) {
 +			*avail = truncated_error(a);
 +			return (NULL);
 +		}
 +		cfdata->unconsumed = cfdata->compressed_bytes_remaining;
 +		cfdata->sum_ptr = d;
 +		if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
 +			*avail = ARCHIVE_FATAL;
 +			return (NULL);
 +		}
 +	}
 +
 +	/*
 +	 * Translation reversal of x86 proccessor CALL byte sequence(E8).
 +	 */
 +	lzx_translation(&cab->xstrm, cab->uncompressed_buffer,
 +	    cfdata->uncompressed_size,
 +	    (cab->entry_cffolder->cfdata_index-1) * 0x8000);
 +
 +	d = cab->uncompressed_buffer + cfdata->read_offset;
 +	*avail = uavail - cfdata->read_offset;
 +	cfdata->uncompressed_avail = uavail;
 +
 +	return (d);
 +}
 +
 +/*
 + * Consume CFDATA.
 + * We always decompress CFDATA to consume CFDATA as much as we need
 + * in uncompressed bytes because all CFDATA in a folder are related
 + * so we do not skip any CFDATA without decompressing.
 + * Note: If the folder of a CFFILE is iFoldCONTINUED_PREV_AND_NEXT or
 + * iFoldCONTINUED_FROM_PREV, we won't decompress because a CFDATA for
 + * the CFFILE is remaining bytes of previous Multivolume CAB file.
 + */
 +static int64_t
 +cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	struct cfdata *cfdata;
 +	int64_t cbytes, rbytes;
 +	int err;
 +
 +	rbytes = cab_minimum_consume_cfdata(a, consumed_bytes);
 +	if (rbytes < 0)
 +		return (ARCHIVE_FATAL);
 +
 +	cfdata = cab->entry_cfdata;
 +	while (rbytes > 0) {
 +		ssize_t avail;
 +
 +		if (cfdata->compressed_size == 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Invalid CFDATA");
 +			return (ARCHIVE_FATAL);
 +		}
 +		cbytes = cfdata->uncompressed_bytes_remaining;
 +		if (cbytes > rbytes)
 +			cbytes = rbytes;
 +		rbytes -= cbytes;
 +
 +		if (cfdata->uncompressed_avail == 0 &&
- 		    (cab->entry_cffolder->comptype == COMPTYPE_NONE ||
- 		     cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||
- 			 cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {
++		   (cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||
++		    cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {
 +			/* We have not read any data yet. */
 +			if (cbytes == cfdata->uncompressed_bytes_remaining) {
 +				/* Skip whole current CFDATA. */
 +				__archive_read_consume(a,
 +				    cfdata->compressed_size);
 +				cab->cab_offset += cfdata->compressed_size;
 +				cfdata->compressed_bytes_remaining = 0;
 +				cfdata->uncompressed_bytes_remaining = 0;
 +				err = cab_next_cfdata(a);
 +				if (err < 0)
 +					return (err);
 +				cfdata = cab->entry_cfdata;
 +				if (cfdata->uncompressed_size == 0) {
 +					switch (cab->entry_cffile->folder) {
 +					case iFoldCONTINUED_PREV_AND_NEXT:
 +					case iFoldCONTINUED_TO_NEXT:
 +					case iFoldCONTINUED_FROM_PREV:
 +						rbytes = 0;
 +						break;
 +					default:
 +						break;
 +					}
 +				}
 +				continue;
 +			}
- 			cfdata->read_offset += cbytes;
- 			cfdata->uncompressed_bytes_remaining -= cbytes;
++			cfdata->read_offset += (uint16_t)cbytes;
++			cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
 +			break;
 +		} else if (cbytes == 0) {
 +			err = cab_next_cfdata(a);
 +			if (err < 0)
 +				return (err);
 +			cfdata = cab->entry_cfdata;
 +			if (cfdata->uncompressed_size == 0) {
 +				switch (cab->entry_cffile->folder) {
 +				case iFoldCONTINUED_PREV_AND_NEXT:
 +				case iFoldCONTINUED_TO_NEXT:
 +				case iFoldCONTINUED_FROM_PREV:
 +					return (ARCHIVE_FATAL);
 +				default:
 +					break;
 +				}
 +			}
 +			continue;
 +		}
 +		while (cbytes > 0) {
 +			(void)cab_read_ahead_cfdata(a, &avail);
 +			if (avail <= 0)
 +				return (ARCHIVE_FATAL);
 +			if (avail > cbytes)
- 				avail = cbytes;
++				avail = (ssize_t)cbytes;
 +			if (cab_minimum_consume_cfdata(a, avail) < 0)
 +				return (ARCHIVE_FATAL);
 +			cbytes -= avail;
 +		}
 +	}
 +	return (consumed_bytes);
 +}
 +
 +/*
 + * Consume CFDATA as much as we have already gotten and
 + * compute the sum of CFDATA.
 + */
 +static int64_t
 +cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	struct cfdata *cfdata;
 +	int64_t cbytes, rbytes;
 +	int err;
 +
 +	cfdata = cab->entry_cfdata;
 +	rbytes = consumed_bytes;
 +	if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {
 +		if (consumed_bytes < cfdata->unconsumed)
 +			cbytes = consumed_bytes;
 +		else
 +			cbytes = cfdata->unconsumed;
 +		rbytes -= cbytes; 
- 		cfdata->read_offset += cbytes;
- 		cfdata->uncompressed_bytes_remaining -= cbytes;
++		cfdata->read_offset += (uint16_t)cbytes;
++		cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
 +		cfdata->unconsumed -= cbytes;
 +	} else {
 +		cbytes = cfdata->uncompressed_avail - cfdata->read_offset;
 +		if (cbytes > 0) {
 +			if (consumed_bytes < cbytes)
 +				cbytes = consumed_bytes;
 +			rbytes -= cbytes;
- 			cfdata->read_offset += cbytes;
- 			cfdata->uncompressed_bytes_remaining -= cbytes;
++			cfdata->read_offset += (uint16_t)cbytes;
++			cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
 +		}
 +
 +		if (cfdata->unconsumed) {
 +			cbytes = cfdata->unconsumed;
 +			cfdata->unconsumed = 0;
 +		} else
 +			cbytes = 0;
 +	}
 +	if (cbytes) {
 +		/* Compute the sum. */
- 		cab_checksum_update(a, cbytes);
++		cab_checksum_update(a, (size_t)cbytes);
 +
 +		/* Consume as much as the compressor actually used. */
 +		__archive_read_consume(a, cbytes);
 +		cab->cab_offset += cbytes;
- 		cfdata->compressed_bytes_remaining -= cbytes;
++		cfdata->compressed_bytes_remaining -= (uint16_t)cbytes;
 +		if (cfdata->compressed_bytes_remaining == 0) {
 +			err = cab_checksum_finish(a);
 +			if (err < 0)
 +				return (err);
 +		}
 +	}
 +	return (rbytes);
 +}
 +
 +/*
 + * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
 + * cab->end_of_entry if it consumes all of the data.
 + */
 +static int
 +cab_read_data(struct archive_read *a, const void **buff,
 +    size_t *size, int64_t *offset)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	ssize_t bytes_avail;
 +
 +	if (cab->entry_bytes_remaining == 0) {
 +		*buff = NULL;
 +		*size = 0;
 +		*offset = cab->entry_offset;
 +		cab->end_of_entry = 1;
 +		return (ARCHIVE_OK);
 +	}
 +
 +	*buff = cab_read_ahead_cfdata(a, &bytes_avail);
 +	if (bytes_avail <= 0) {
 +		*buff = NULL;
 +		*size = 0;
 +		*offset = 0;
 +		if (bytes_avail == 0 &&
 +		    cab->entry_cfdata->uncompressed_size == 0) {
 +			/* All of CFDATA in a folder has been handled. */
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA");
 +			return (ARCHIVE_FATAL);
 +		} else
- 			return (bytes_avail);
++			return ((int)bytes_avail);
 +	}
 +	if (bytes_avail > cab->entry_bytes_remaining)
- 		bytes_avail = cab->entry_bytes_remaining;
++		bytes_avail = (ssize_t)cab->entry_bytes_remaining;
 +
 +	*size = bytes_avail;
 +	*offset = cab->entry_offset;
 +	cab->entry_offset += bytes_avail;
 +	cab->entry_bytes_remaining -= bytes_avail;
 +	if (cab->entry_bytes_remaining == 0)
 +		cab->end_of_entry = 1;
 +	cab->entry_unconsumed = bytes_avail;
++	if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {
++		/* Don't consume more than current entry used. */
++		if (cab->entry_cfdata->unconsumed > cab->entry_unconsumed)
++			cab->entry_cfdata->unconsumed = cab->entry_unconsumed;
++	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_read_format_cab_read_data_skip(struct archive_read *a)
 +{
 +	struct cab *cab;
 +	int64_t bytes_skipped;
 +	int r;
 +
 +	cab = (struct cab *)(a->format->data);
 +
 +	if (cab->end_of_archive)
 +		return (ARCHIVE_EOF);
 +
++	if (!cab->read_data_invoked) {
++		cab->bytes_skipped += cab->entry_bytes_remaining;
++		cab->entry_bytes_remaining = 0;
++		/* This entry is finished and done. */
++		cab->end_of_entry_cleanup = cab->end_of_entry = 1;
++		return (ARCHIVE_OK);
++	}
++
 +	if (cab->entry_unconsumed) {
 +		/* Consume as much as the compressor actually used. */
- 		r = cab_consume_cfdata(a, cab->entry_unconsumed);
++		r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
 +		cab->entry_unconsumed = 0;
 +		if (r < 0)
 +			return (r);
 +	} else if (cab->entry_cfdata == NULL) {
 +		r = cab_next_cfdata(a);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* if we've already read to end of data, we're done. */
 +	if (cab->end_of_entry_cleanup)
 +		return (ARCHIVE_OK);
 +
 +	/*
 +	 * If the length is at the beginning, we can skip the
 +	 * compressed data much more quickly.
 +	 */
 +	bytes_skipped = cab_consume_cfdata(a, cab->entry_bytes_remaining);
 +	if (bytes_skipped < 0)
 +		return (ARCHIVE_FATAL);
 +
++	/* If the compression type is none(uncompressed), we've already
++	 * consumed data as much as the current entry size. */
++	if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
++	    cab->entry_cfdata != NULL)
++		cab->entry_cfdata->unconsumed = 0;
++
 +	/* This entry is finished and done. */
 +	cab->end_of_entry_cleanup = cab->end_of_entry = 1;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_read_format_cab_cleanup(struct archive_read *a)
 +{
 +	struct cab *cab = (struct cab *)(a->format->data);
 +	struct cfheader *hd = &cab->cfheader;
 +	int i;
 +
 +	if (hd->folder_array != NULL) {
 +		for (i = 0; i < hd->folder_count; i++)
 +			free(hd->folder_array[i].cfdata.memimage);
 +		free(hd->folder_array);
 +	}
 +	if (hd->file_array != NULL) {
 +		for (i = 0; i < cab->cfheader.file_count; i++)
 +			archive_string_free(&(hd->file_array[i].pathname));
 +		free(hd->file_array);
 +	}
 +#ifdef HAVE_ZLIB_H
 +	if (cab->stream_valid)
 +		inflateEnd(&cab->stream);
 +#endif
 +	lzx_decode_free(&cab->xstrm);
 +	archive_wstring_free(&cab->ws);
 +	free(cab->uncompressed_buffer);
 +	free(cab);
 +	(a->format->data) = NULL;
 +	return (ARCHIVE_OK);
 +}
 +
 +/* Convert an MSDOS-style date/time into Unix-style time. */
 +static time_t
 +cab_dos_time(const unsigned char *p)
 +{
 +	int msTime, msDate;
 +	struct tm ts;
 +
 +	msDate = archive_le16dec(p);
 +	msTime = archive_le16dec(p+2);
 +
 +	memset(&ts, 0, sizeof(ts));
 +	ts.tm_year = ((msDate >> 9) & 0x7f) + 80;   /* Years since 1900. */
 +	ts.tm_mon = ((msDate >> 5) & 0x0f) - 1;     /* Month number.     */
 +	ts.tm_mday = msDate & 0x1f;		    /* Day of month.     */
 +	ts.tm_hour = (msTime >> 11) & 0x1f;
 +	ts.tm_min = (msTime >> 5) & 0x3f;
 +	ts.tm_sec = (msTime << 1) & 0x3e;
 +	ts.tm_isdst = -1;
 +	return (mktime(&ts));
 +}
 +
 +/*****************************************************************
 + *
 + * LZX decompression code.
 + *
 + *****************************************************************/
 +
 +/*
 + * Initialize LZX decoder.
 + *
 + * Returns ARCHIVE_OK if initialization was successful.
 + * Returns ARCHIVE_FAILED if w_bits has unsupported value.
 + * Returns ARCHIVE_FATAL if initialization failed; memory allocation
 + * error occurred.
 + */
 +static int
 +lzx_decode_init(struct lzx_stream *strm, int w_bits)
 +{
 +	struct lzx_dec *ds;
 +	int slot, w_size, w_slot;
 +	int base, footer;
++	int base_inc[18];
 +
 +	if (strm->ds == NULL) {
 +		strm->ds = calloc(1, sizeof(*strm->ds));
 +		if (strm->ds == NULL)
 +			return (ARCHIVE_FATAL);
 +	}
 +	ds = strm->ds;
 +	ds->error = ARCHIVE_FAILED;
 +
 +	/* Allow bits from 15(32KBi) up to 21(2MBi) */
 +	if (w_bits < SLOT_BASE || w_bits > SLOT_MAX)
 +		return (ARCHIVE_FAILED);
 +
 +	ds->error = ARCHIVE_FATAL;
 +
 +	/*
 +	 * Alloc window
 +	 */
 +	w_size = ds->w_size;
 +	w_slot = slots[w_bits - SLOT_BASE];
 +	ds->w_size = 1U << w_bits;
 +	ds->w_mask = ds->w_size -1;
 +	if (ds->w_buff == NULL || w_size != ds->w_size) {
 +		free(ds->w_buff);
 +		ds->w_buff = malloc(ds->w_size);
 +		if (ds->w_buff == NULL)
 +			return (ARCHIVE_FATAL);
 +		free(ds->pos_tbl);
 +		ds->pos_tbl = malloc(sizeof(ds->pos_tbl[0]) * w_slot);
 +		if (ds->pos_tbl == NULL)
 +			return (ARCHIVE_FATAL);
 +		lzx_huffman_free(&(ds->mt));
 +	}
 +
++	for (footer = 0; footer < 18; footer++)
++		base_inc[footer] = 1 << footer;
 +	base = footer = 0;
 +	for (slot = 0; slot < w_slot; slot++) {
 +		int n;
 +		if (footer == 0)
 +			base = slot;
 +		else
- 			base += 1 << footer;
++			base += base_inc[footer];
 +		if (footer < 17) {
 +			footer = -2;
 +			for (n = base; n; n >>= 1)
 +				footer++;
 +			if (footer <= 0)
 +				footer = 0;
 +		}
 +		ds->pos_tbl[slot].base = base;
 +		ds->pos_tbl[slot].footer_bits = footer;
 +	}
 +
 +	ds->w_pos = 0;
 +	ds->state = 0;
 +	ds->br.cache_buffer = 0;
 +	ds->br.cache_avail = 0;
 +	ds->r0 = ds->r1 = ds->r2 = 1;
 +
 +	/* Initialize aligned offset tree. */
 +	if (lzx_huffman_init(&(ds->at), 8, 8) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Initialize pre-tree. */
 +	if (lzx_huffman_init(&(ds->pt), 20, 10) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Initialize Main tree. */
 +	if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)
 +	    != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Initialize Length tree. */
 +	if (lzx_huffman_init(&(ds->lt), 249, 16) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	ds->error = 0;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Release LZX decoder.
 + */
 +static void
 +lzx_decode_free(struct lzx_stream *strm)
 +{
 +
 +	if (strm->ds == NULL)
 +		return;
 +	free(strm->ds->w_buff);
 +	free(strm->ds->pos_tbl);
 +	lzx_huffman_free(&(strm->ds->at));
 +	lzx_huffman_free(&(strm->ds->pt));
 +	lzx_huffman_free(&(strm->ds->mt));
 +	lzx_huffman_free(&(strm->ds->lt));
 +	free(strm->ds);
 +	strm->ds = NULL;
 +}
 +
 +/*
 + * E8 Call Translation reversal.
 + */
 +static void
 +lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
 +{
 +	struct lzx_dec *ds = strm->ds;
 +	unsigned char *b, *end;
 +
 +	if (!ds->translation || size <= 10)
 +		return;
 +	b = p;
 +	end = b + size - 10;
 +	while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {
 +		size_t i = b - (unsigned char *)p;
- 		long cp, displacement, value;
++		int32_t cp, displacement, value;
 +
- 		cp = offset + i;
++		cp = (int32_t)(offset + (uint32_t)i);
 +		value = archive_le32dec(&b[1]);
- 		if (value >= -cp && value < (long)ds->translation_size) {
++		if (value >= -cp && value < (int32_t)ds->translation_size) {
 +			if (value >= 0)
 +				displacement = value - cp;
 +			else
 +				displacement = value + ds->translation_size;
 +			archive_le32enc(&b[1], (uint32_t)displacement);
 +		}
 +		b += 5;
 +	}
 +}
 +
 +/*
 + * Bit stream reader.
 + */
 +/* Check that the cache buffer has enough bits. */
 +#define lzx_br_has(br, n)	((br)->cache_avail >= n)
 +/* Get compressed data by bit. */
 +#define lzx_br_bits(br, n)				\
 +	(((uint32_t)((br)->cache_buffer >>		\
 +		((br)->cache_avail - (n)))) & cache_masks[n])
 +#define lzx_br_bits_forced(br, n)			\
 +	(((uint32_t)((br)->cache_buffer <<		\
 +		((n) - (br)->cache_avail))) & cache_masks[n])
 +/* Read ahead to make sure the cache buffer has enough compressed data we
 + * will use.
 + *  True  : completed, there is enough data in the cache buffer.
 + *  False : we met that strm->next_in is empty, we have to get following
 + *          bytes. */
 +#define lzx_br_read_ahead_0(strm, br, n)	\
 +	(lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))
 +/*  True  : the cache buffer has some bits as much as we need.
 + *  False : there are no enough bits in the cache buffer to be used,
 + *          we have to get following bytes if we could. */
 +#define lzx_br_read_ahead(strm, br, n)	\
 +	(lzx_br_read_ahead_0((strm), (br), (n)) || lzx_br_has((br), (n)))
 +
 +/* Notify how many bits we consumed. */
 +#define lzx_br_consume(br, n)	((br)->cache_avail -= (n))
- #define lzx_br_consume_unalined_bits(br) ((br)->cache_avail &= ~0x0f)
++#define lzx_br_consume_unaligned_bits(br) ((br)->cache_avail &= ~0x0f)
++
++#define lzx_br_is_unaligned(br)	((br)->cache_avail & 0x0f)
 +
 +static const uint32_t cache_masks[] = {
 +	0x00000000, 0x00000001, 0x00000003, 0x00000007,
 +	0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
 +	0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
 +	0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
 +	0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
 +	0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
 +	0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
 +	0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,
 +	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
 +};
 +
 +/*
 + * Shift away used bits in the cache data and fill it up with following bits.
 + * Call this when cache buffer does not have enough bits you need.
 + *
 + * Returns 1 if the cache buffer is full.
 + * Returns 0 if the cache buffer is not full; input buffer is empty.
 + */
 +static int
 +lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
 +{
 +/*
 + * x86 proccessor family can read misaligned data without an access error.
 + */
 +	int n = CACHE_BITS - br->cache_avail;
 +
 +	for (;;) {
 +		switch (n >> 4) {
 +		case 4:
 +			if (strm->avail_in >= 8) {
 +				br->cache_buffer =
 +				    ((uint64_t)strm->next_in[1]) << 56 |
 +				    ((uint64_t)strm->next_in[0]) << 48 |
 +				    ((uint64_t)strm->next_in[3]) << 40 |
 +				    ((uint64_t)strm->next_in[2]) << 32 |
 +				    ((uint32_t)strm->next_in[5]) << 24 |
 +				    ((uint32_t)strm->next_in[4]) << 16 |
 +				    ((uint32_t)strm->next_in[7]) << 8 |
 +				     (uint32_t)strm->next_in[6];
 +				strm->next_in += 8;
 +				strm->avail_in -= 8;
 +				br->cache_avail += 8 * 8;
 +				return (1);
 +			}
 +			break;
 +		case 3:
 +			if (strm->avail_in >= 6) {
 +				br->cache_buffer =
 +		 		   (br->cache_buffer << 48) |
 +				    ((uint64_t)strm->next_in[1]) << 40 |
 +				    ((uint64_t)strm->next_in[0]) << 32 |
 +				    ((uint32_t)strm->next_in[3]) << 24 |
 +				    ((uint32_t)strm->next_in[2]) << 16 |
 +				    ((uint32_t)strm->next_in[5]) << 8 |
 +				     (uint32_t)strm->next_in[4];
 +				strm->next_in += 6;
 +				strm->avail_in -= 6;
 +				br->cache_avail += 6 * 8;
 +				return (1);
 +			}
 +			break;
 +		case 0:
 +			/* We have enough compressed data in
 +			 * the cache buffer.*/
 +			return (1);
 +		default:
 +			break;
 +		}
 +		if (strm->avail_in < 2) {
 +			/* There is not enough compressed data to
 +			 * fill up the cache buffer. */
 +			if (strm->avail_in == 1) {
 +				br->odd = *strm->next_in++;
 +				strm->avail_in--;
 +				br->have_odd = 1;
 +			}
 +			return (0);
 +		}
 +		br->cache_buffer =
 +		   (br->cache_buffer << 16) |
 +		    archive_le16dec(strm->next_in);
 +		strm->next_in += 2;
 +		strm->avail_in -= 2;
 +		br->cache_avail += 16;
 +		n -= 16;
 +	}
 +}
 +
 +static void
 +lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br)
 +{
 +	int n = CACHE_BITS - br->cache_avail;
 +
 +	if (br->have_odd && n >= 16 && strm->avail_in > 0) {
 +		br->cache_buffer =
 +		   (br->cache_buffer << 16) |
 +		   ((uint16_t)(*strm->next_in)) << 8 | br->odd;
 +		strm->next_in++;
 +		strm->avail_in--;
 +		br->cache_avail += 16;
 +		br->have_odd = 0;
 +	}
 +}
 +
 +static void
 +lzx_cleanup_bitstream(struct lzx_stream *strm)
 +{
 +	strm->ds->br.cache_avail = 0;
 +	strm->ds->br.have_odd = 0;
 +}
 +
 +/*
 + * Decode LZX.
 + *
 + * 1. Returns ARCHIVE_OK if output buffer or input buffer are empty.
 + *    Please set available buffer and call this function again.
 + * 2. Returns ARCHIVE_EOF if decompression has been completed.
 + * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data
 + *    is broken or you do not set 'last' flag properly.
 + */
 +#define ST_RD_TRANSLATION	0
 +#define ST_RD_TRANSLATION_SIZE	1
 +#define ST_RD_BLOCK_TYPE	2
 +#define ST_RD_BLOCK_SIZE	3
- #define ST_RD_R0		4
- #define ST_RD_R1		5
- #define ST_RD_R2		6
- #define ST_COPY_UNCOMP1		7
- #define ST_COPY_UNCOMP2		8
- #define ST_RD_ALIGNED_OFFSET	9
- #define ST_RD_VERBATIM		10
- #define ST_RD_PRE_MAIN_TREE_256	11
- #define ST_MAIN_TREE_256	12
- #define ST_RD_PRE_MAIN_TREE_REM	13
- #define ST_MAIN_TREE_REM	14
- #define ST_RD_PRE_LENGTH_TREE	15
- #define ST_LENGTH_TREE		16
- #define ST_MAIN			17
- #define ST_LENGTH		18
- #define ST_OFFSET		19
- #define ST_REAL_POS		20
- #define ST_COPY			21
++#define ST_RD_ALIGNMENT		4
++#define ST_RD_R0		5
++#define ST_RD_R1		6
++#define ST_RD_R2		7
++#define ST_COPY_UNCOMP1		8
++#define ST_COPY_UNCOMP2		9
++#define ST_RD_ALIGNED_OFFSET	10
++#define ST_RD_VERBATIM		11
++#define ST_RD_PRE_MAIN_TREE_256	12
++#define ST_MAIN_TREE_256	13
++#define ST_RD_PRE_MAIN_TREE_REM	14
++#define ST_MAIN_TREE_REM	15
++#define ST_RD_PRE_LENGTH_TREE	16
++#define ST_LENGTH_TREE		17
++#define ST_MAIN			18
++#define ST_LENGTH		19
++#define ST_OFFSET		20
++#define ST_REAL_POS		21
++#define ST_COPY			22
 +
 +static int
 +lzx_decode(struct lzx_stream *strm, int last)
 +{
 +	struct lzx_dec *ds = strm->ds;
 +	int64_t avail_in;
 +	int r;
 +
 +	if (ds->error)
 +		return (ds->error);
 +
 +	avail_in = strm->avail_in;
 +	lzx_br_fixup(strm, &(ds->br));
 +	do {
 +		if (ds->state < ST_MAIN)
 +			r = lzx_read_blocks(strm, last);
 +		else {
 +			int64_t bytes_written = strm->avail_out;
 +			r = lzx_decode_blocks(strm, last);
 +			bytes_written -= strm->avail_out;
 +			strm->next_out += bytes_written;
 +			strm->total_out += bytes_written;
 +		}
 +	} while (r == 100);
 +	strm->total_in += avail_in - strm->avail_in;
 +	return (r);
 +}
 +
 +static int
 +lzx_read_blocks(struct lzx_stream *strm, int last)
 +{
 +	struct lzx_dec *ds = strm->ds;
 +	struct lzx_br *br = &(ds->br);
 +	int i, r;
 +
 +	for (;;) {
 +		switch (ds->state) {
 +		case ST_RD_TRANSLATION:
 +			if (!lzx_br_read_ahead(strm, br, 1)) {
 +				ds->state = ST_RD_TRANSLATION;
 +				if (last)
 +					goto failed;
 +				return (ARCHIVE_OK);
 +			}
 +			ds->translation = lzx_br_bits(br, 1);
 +			lzx_br_consume(br, 1);
 +			/* FALL THROUGH */
 +		case ST_RD_TRANSLATION_SIZE:
 +			if (ds->translation) {
 +				if (!lzx_br_read_ahead(strm, br, 32)) {
 +					ds->state = ST_RD_TRANSLATION_SIZE;
 +					if (last)
 +						goto failed;
 +					return (ARCHIVE_OK);
 +				}
 +				ds->translation_size = lzx_br_bits(br, 16);
 +				lzx_br_consume(br, 16);
 +				ds->translation_size <<= 16;
 +				ds->translation_size |= lzx_br_bits(br, 16);
 +				lzx_br_consume(br, 16);
 +			}
 +			/* FALL THROUGH */
 +		case ST_RD_BLOCK_TYPE:
 +			if (!lzx_br_read_ahead(strm, br, 3)) {
 +				ds->state = ST_RD_BLOCK_TYPE;
 +				if (last)
 +					goto failed;
 +				return (ARCHIVE_OK);
 +			}
 +			ds->block_type = lzx_br_bits(br, 3);
 +			lzx_br_consume(br, 3);
 +			/* Check a block type. */
 +			switch (ds->block_type) {
 +			case VERBATIM_BLOCK:
 +			case ALIGNED_OFFSET_BLOCK:
 +			case UNCOMPRESSED_BLOCK:
 +				break;
 +			default:
 +				goto failed;/* Invalid */
 +			}
 +			/* FALL THROUGH */
 +		case ST_RD_BLOCK_SIZE:
 +			if (!lzx_br_read_ahead(strm, br, 24)) {
 +				ds->state = ST_RD_BLOCK_SIZE;
 +				if (last)
 +					goto failed;
 +				return (ARCHIVE_OK);
 +			}
 +			ds->block_size = lzx_br_bits(br, 8);
 +			lzx_br_consume(br, 8);
 +			ds->block_size <<= 16;
 +			ds->block_size |= lzx_br_bits(br, 16);
 +			lzx_br_consume(br, 16);
 +			if (ds->block_size == 0)
 +				goto failed;
 +			ds->block_bytes_avail = ds->block_size;
 +			if (ds->block_type != UNCOMPRESSED_BLOCK) {
 +				if (ds->block_type == VERBATIM_BLOCK)
 +					ds->state = ST_RD_VERBATIM;
 +				else
 +					ds->state = ST_RD_ALIGNED_OFFSET;
 +				break;
 +			}
++			/* FALL THROUGH */
++		case ST_RD_ALIGNMENT:
 +			/*
 +			 * Handle an Uncompressed Block.
 +			 */
 +			/* Skip padding to align following field on
 +			 * 16-bit boundary. */
- 			lzx_br_consume_unalined_bits(br);
++			if (lzx_br_is_unaligned(br))
++				lzx_br_consume_unaligned_bits(br);
++			else {
++				if (lzx_br_read_ahead(strm, br, 16))
++					lzx_br_consume(br, 16);
++				else {
++					ds->state = ST_RD_ALIGNMENT;
++					if (last)
++						goto failed;
++					return (ARCHIVE_OK);
++				}
++			}
 +			/* Preparation to read repeated offsets R0,R1 and R2. */
 +			ds->rbytes_avail = 0;
 +			ds->state = ST_RD_R0;
 +			/* FALL THROUGH */
 +		case ST_RD_R0:
 +		case ST_RD_R1:
 +		case ST_RD_R2:
 +			do {
 +				uint16_t u16;
 +				/* Drain bits in the cache buffer of
 +				 * bit-stream. */
 +				if (lzx_br_has(br, 32)) {
 +					u16 = lzx_br_bits(br, 16);
 +					lzx_br_consume(br, 16);
 +					archive_le16enc(ds->rbytes, u16);
 +					u16 = lzx_br_bits(br, 16);
 +					lzx_br_consume(br, 16);
 +					archive_le16enc(ds->rbytes+2, u16);
 +					ds->rbytes_avail = 4;
 +				} else if (lzx_br_has(br, 16)) {
 +					u16 = lzx_br_bits(br, 16);
 +					lzx_br_consume(br, 16);
 +					archive_le16enc(ds->rbytes, u16);
 +					ds->rbytes_avail = 2;
- 				} else
- 					ds->rbytes_avail = 0;
++				}
 +				if (ds->rbytes_avail < 4 && ds->br.have_odd) {
 +					ds->rbytes[ds->rbytes_avail++] =
 +					    ds->br.odd;
 +					ds->br.have_odd = 0;
 +				}
 +				while (ds->rbytes_avail < 4) {
 +					if (strm->avail_in <= 0) {
 +						if (last)
 +							goto failed;
 +						return (ARCHIVE_OK);
 +					}
 +					ds->rbytes[ds->rbytes_avail++] =
 +					    *strm->next_in++;
 +					strm->avail_in--;
 +				}
++				ds->rbytes_avail = 0;
 +				if (ds->state == ST_RD_R0) {
 +					ds->r0 = archive_le32dec(ds->rbytes);
 +					if (ds->r0 < 0)
 +						goto failed;
 +					ds->state = ST_RD_R1;
 +				} else if (ds->state == ST_RD_R1) {
 +					ds->r1 = archive_le32dec(ds->rbytes);
 +					if (ds->r1 < 0)
 +						goto failed;
 +					ds->state = ST_RD_R2;
 +				} else if (ds->state == ST_RD_R2) {
 +					ds->r2 = archive_le32dec(ds->rbytes);
 +					if (ds->r2 < 0)
 +						goto failed;
 +					/* We've gotten all repeated offsets. */
 +					ds->state = ST_COPY_UNCOMP1;
 +				}
 +			} while (ds->state != ST_COPY_UNCOMP1);
 +			/* FALL THROUGH */
 +		case ST_COPY_UNCOMP1:
 +			/*
 +			 * Copy bytes form next_in to next_out directly.
 +			 */
 +			while (ds->block_bytes_avail) {
- 				unsigned char *d;
- 				int l,ll;
++				int l;
 +
 +				if (strm->avail_out <= 0)
 +					/* Output buffer is empty. */
 +					return (ARCHIVE_OK);
 +				if (strm->avail_in <= 0) {
 +					/* Input buffer is empty. */
 +					if (last)
 +						goto failed;
 +					return (ARCHIVE_OK);
 +				}
- 				l = ds->block_bytes_avail;
++				l = (int)ds->block_bytes_avail;
 +				if (l > ds->w_size - ds->w_pos)
 +					l = ds->w_size - ds->w_pos;
 +				if (l > strm->avail_out)
 +					l = (int)strm->avail_out;
 +				if (l > strm->avail_in)
 +					l = (int)strm->avail_in;
- 				ll = l;
- 				d = &(ds->w_buff[ds->w_pos]);
- 				while (--l >= 0) {
- 					*strm->next_out++ = *strm->next_in;
- 					*d++ = *strm->next_in++;
- 				}
- 				strm->avail_out -= ll;
- 				strm->total_out += ll;
- 				strm->avail_in -= ll;
- 				ds->w_pos = (ds->w_pos + ll) & ds->w_mask;
- 				ds->block_bytes_avail -= ll;
++				memcpy(strm->next_out, strm->next_in, l);
++				memcpy(&(ds->w_buff[ds->w_pos]),
++				    strm->next_in, l);
++				strm->next_in += l;
++				strm->avail_in -= l;
++				strm->next_out += l;
++				strm->avail_out -= l;
++				strm->total_out += l;
++				ds->w_pos = (ds->w_pos + l) & ds->w_mask;
++				ds->block_bytes_avail -= l;
 +			}
 +			/* FALL THROUGH */
 +		case ST_COPY_UNCOMP2:
 +			/* Re-align; skip padding byte. */
 +			if (ds->block_size & 1) {
 +				if (strm->avail_in <= 0) {
 +					/* Input buffer is empty. */
 +					ds->state = ST_COPY_UNCOMP2;
 +					if (last)
 +						goto failed;
 +					return (ARCHIVE_OK);
 +				}
 +				strm->next_in++;
 +				strm->avail_in --;
 +			}
 +			/* This block ended. */
 +			ds->state = ST_RD_BLOCK_TYPE;
 +			return (ARCHIVE_EOF);
 +			/********************/
 +		case ST_RD_ALIGNED_OFFSET:
 +			/*
 +			 * Read Aligned offset tree.
 +			 */
 +			if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {
 +				ds->state = ST_RD_ALIGNED_OFFSET;
 +				if (last)
 +					goto failed;
 +				return (ARCHIVE_OK);
 +			}
 +			memset(ds->at.freq, 0, sizeof(ds->at.freq));
 +			for (i = 0; i < ds->at.len_size; i++) {
 +				ds->at.bitlen[i] = lzx_br_bits(br, 3);
 +				ds->at.freq[ds->at.bitlen[i]]++;
 +				lzx_br_consume(br, 3);
 +			}
 +			if (!lzx_make_huffman_table(&ds->at))
 +				goto failed;
 +			/* FALL THROUGH */
 +		case ST_RD_VERBATIM:
 +			ds->loop = 0;
 +			/* FALL THROUGH */
 +		case ST_RD_PRE_MAIN_TREE_256:
 +			/*
 +			 * Read Pre-tree for first 256 elements of main tree.
 +			 */
 +			if (!lzx_read_pre_tree(strm)) {
 +				ds->state = ST_RD_PRE_MAIN_TREE_256;
 +				if (last)
 +					goto failed;
 +				return (ARCHIVE_OK);
 +			}
 +			if (!lzx_make_huffman_table(&ds->pt))
 +				goto failed;
 +			ds->loop = 0;
 +			/* FALL THROUGH */
 +		case ST_MAIN_TREE_256:
 +			/*
 +			 * Get path lengths of first 256 elements of main tree.
 +			 */
 +			r = lzx_read_bitlen(strm, &ds->mt, 256);
 +			if (r < 0)
 +				goto failed;
 +			else if (!r) {
 +				ds->state = ST_MAIN_TREE_256;
 +				if (last)
 +					goto failed;
 +				return (ARCHIVE_OK);
 +			}
 +			ds->loop = 0;
 +			/* FALL THROUGH */
 +		case ST_RD_PRE_MAIN_TREE_REM:
 +			/*
 +			 * Read Pre-tree for remaining elements of main tree.
 +			 */
 +			if (!lzx_read_pre_tree(strm)) {
 +				ds->state = ST_RD_PRE_MAIN_TREE_REM;
 +				if (last)
 +					goto failed;
 +				return (ARCHIVE_OK);
 +			}
 +			if (!lzx_make_huffman_table(&ds->pt))
 +				goto failed;
 +			ds->loop = 256;
 +			/* FALL THROUGH */
 +		case ST_MAIN_TREE_REM:
 +			/*
 +			 * Get path lengths of remaining elements of main tree.
 +			 */
 +			r = lzx_read_bitlen(strm, &ds->mt, -1);
 +			if (r < 0)
 +				goto failed;
 +			else if (!r) {
 +				ds->state = ST_MAIN_TREE_REM;
 +				if (last)
 +					goto failed;
 +				return (ARCHIVE_OK);
 +			}
 +			if (!lzx_make_huffman_table(&ds->mt))
 +				goto failed;
 +			ds->loop = 0;
 +			/* FALL THROUGH */
 +		case ST_RD_PRE_LENGTH_TREE:
 +			/*
 +			 * Read Pre-tree for remaining elements of main tree.
 +			 */
 +			if (!lzx_read_pre_tree(strm)) {
 +				ds->state = ST_RD_PRE_LENGTH_TREE;
 +				if (last)
 +					goto failed;
 +				return (ARCHIVE_OK);
 +			}
 +			if (!lzx_make_huffman_table(&ds->pt))
 +				goto failed;
 +			ds->loop = 0;
 +			/* FALL THROUGH */
 +		case ST_LENGTH_TREE:
 +			/*
 +			 * Get path lengths of remaining elements of main tree.
 +			 */
 +			r = lzx_read_bitlen(strm, &ds->lt, -1);
 +			if (r < 0)
 +				goto failed;
 +			else if (!r) {
 +				ds->state = ST_LENGTH_TREE;
 +				if (last)
 +					goto failed;
 +				return (ARCHIVE_OK);
 +			}
 +			if (!lzx_make_huffman_table(&ds->lt))
 +				goto failed;
 +			ds->state = ST_MAIN;
 +			return (100);
 +		}
 +	}
 +failed:
 +	return (ds->error = ARCHIVE_FAILED);
 +}
 +
 +static int
 +lzx_decode_blocks(struct lzx_stream *strm, int last)
 +{
 +	struct lzx_dec *ds = strm->ds;
 +	struct lzx_br bre = ds->br;
 +	struct huffman *at = &(ds->at), *lt = &(ds->lt), *mt = &(ds->mt);
 +	const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
- 	unsigned char *outp = strm->next_out;
- 	unsigned char *endp = outp + strm->avail_out;
++	unsigned char *noutp = strm->next_out;
++	unsigned char *endp = noutp + strm->avail_out;
 +	unsigned char *w_buff = ds->w_buff;
 +	unsigned char *at_bitlen = at->bitlen;
 +	unsigned char *lt_bitlen = lt->bitlen;
 +	unsigned char *mt_bitlen = mt->bitlen;
 +	size_t block_bytes_avail = ds->block_bytes_avail;
 +	int at_max_bits = at->max_bits;
 +	int lt_max_bits = lt->max_bits;
 +	int mt_max_bits = mt->max_bits;
 +	int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;
 +	int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
 +	int length_header = ds->length_header;
 +	int offset_bits = ds->offset_bits;
 +	int position_slot = ds->position_slot;
 +	int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
 +	int state = ds->state;
 +	char block_type = ds->block_type;
 +
 +	for (;;) {
 +		switch (state) {
 +		case ST_MAIN:
 +			for (;;) {
 +				if (block_bytes_avail == 0) {
 +					/* This block ended. */
 +					ds->state = ST_RD_BLOCK_TYPE;
 +					ds->br = bre;
 +					ds->block_bytes_avail =
 +					    block_bytes_avail;
 +					ds->copy_len = copy_len;
 +					ds->copy_pos = copy_pos;
 +					ds->length_header = length_header;
 +					ds->position_slot = position_slot;
 +					ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
 +					ds->w_pos = w_pos;
- 					strm->avail_out = endp - outp;
++					strm->avail_out = endp - noutp;
 +					return (ARCHIVE_EOF);
 +				}
- 				if (outp >= endp)
++				if (noutp >= endp)
 +					/* Output buffer is empty. */
 +					goto next_data;
 +
 +				if (!lzx_br_read_ahead(strm, &bre,
 +				    mt_max_bits)) {
 +					if (!last)
 +						goto next_data;
 +					/* Remaining bits are less than
 +					 * maximum bits(mt.max_bits) but maybe
 +					 * it still remains as much as we need,
 +					 * so we should try to use it with
 +					 * dummy bits. */
 +					c = lzx_decode_huffman(mt,
 +					      lzx_br_bits_forced(
 +				 	        &bre, mt_max_bits));
 +					lzx_br_consume(&bre, mt_bitlen[c]);
 +					if (!lzx_br_has(&bre, 0))
 +						goto failed;/* Over read. */
 +				} else {
 +					c = lzx_decode_huffman(mt,
 +					      lzx_br_bits(&bre, mt_max_bits));
 +					lzx_br_consume(&bre, mt_bitlen[c]);
 +				}
 +				if (c > UCHAR_MAX)
 +					break;
 +				/*
 +				 * 'c' is exactly literal code.
 +				 */
 +				/* Save a decoded code to reference it
 +				 * afterward. */
 +				w_buff[w_pos] = c;
 +				w_pos = (w_pos + 1) & w_mask;
 +				/* Store the decoded code to output buffer. */
- 				*outp++ = c;
++				*noutp++ = c;
 +				block_bytes_avail--;
 +			}
 +			/*
 +			 * Get a match code, its length and offset.
 +			 */
 +			c -= UCHAR_MAX + 1;
 +			length_header = c & 7;
 +			position_slot = c >> 3;
 +			/* FALL THROUGH */
 +		case ST_LENGTH:
 +			/*
 +			 * Get a length.
 +			 */
 +			if (length_header == 7) {
 +				if (!lzx_br_read_ahead(strm, &bre,
 +				    lt_max_bits)) {
 +					if (!last) {
 +						state = ST_LENGTH;
 +						goto next_data;
 +					}
 +					c = lzx_decode_huffman(lt,
 +					      lzx_br_bits_forced(
 +					        &bre, lt_max_bits));
 +					lzx_br_consume(&bre, lt_bitlen[c]);
 +					if (!lzx_br_has(&bre, 0))
 +						goto failed;/* Over read. */
 +				} else {
 +					c = lzx_decode_huffman(lt,
 +					    lzx_br_bits(&bre, lt_max_bits));
 +					lzx_br_consume(&bre, lt_bitlen[c]);
 +				}
 +				copy_len = c + 7 + 2;
 +			} else
 +				copy_len = length_header + 2;
 +			if ((size_t)copy_len > block_bytes_avail)
 +				goto failed;
 +			/*
 +			 * Get an offset.
 +			 */
 +			switch (position_slot) {
 +			case 0: /* Use repeated offset 0. */
 +				copy_pos = r0;
 +				state = ST_REAL_POS;
 +				continue;
 +			case 1: /* Use repeated offset 1. */
 +				copy_pos = r1;
 +				/* Swap repeated offset. */
 +				r1 = r0;
 +				r0 = copy_pos;
 +				state = ST_REAL_POS;
 +				continue;
 +			case 2: /* Use repeated offset 2. */
 +				copy_pos = r2;
 +				/* Swap repeated offset. */
 +				r2 = r0;
 +				r0 = copy_pos;
 +				state = ST_REAL_POS;
 +				continue;
 +			default:
 +				offset_bits =
 +				    pos_tbl[position_slot].footer_bits;
 +				break;
 +			}
 +			/* FALL THROUGH */
 +		case ST_OFFSET:
 +			/*
 +			 * Get the offset, which is a distance from
 +			 * current window position.
 +			 */
 +			if (block_type == ALIGNED_OFFSET_BLOCK &&
 +			    offset_bits >= 3) {
 +				int offbits = offset_bits - 3;
 +
 +				if (!lzx_br_read_ahead(strm, &bre, offbits)) {
 +					state = ST_OFFSET;
 +					if (last)
 +						goto failed;
 +					goto next_data;
 +				}
 +				copy_pos = lzx_br_bits(&bre, offbits) << 3;
 +
 +				/* Get an aligned number. */
 +				if (!lzx_br_read_ahead(strm, &bre,
 +				    offbits + at_max_bits)) {
 +					if (!last) {
 +						state = ST_OFFSET;
 +						goto next_data;
 +					}
 +					lzx_br_consume(&bre, offbits);
 +					c = lzx_decode_huffman(at,
 +					      lzx_br_bits_forced(&bre,
 +					        at_max_bits));
 +					lzx_br_consume(&bre, at_bitlen[c]);
 +					if (!lzx_br_has(&bre, 0))
 +						goto failed;/* Over read. */
 +				} else {
 +					lzx_br_consume(&bre, offbits);
 +					c = lzx_decode_huffman(at,
 +					      lzx_br_bits(&bre, at_max_bits));
 +					lzx_br_consume(&bre, at_bitlen[c]);
 +				}
 +				/* Add an aligned number. */
 +				copy_pos += c;
 +			} else {
 +				if (!lzx_br_read_ahead(strm, &bre,
 +				    offset_bits)) {
 +					state = ST_OFFSET;
 +					if (last)
 +						goto failed;
 +					goto next_data;
 +				}
 +				copy_pos = lzx_br_bits(&bre, offset_bits);
 +				lzx_br_consume(&bre, offset_bits);
 +			}
 +			copy_pos += pos_tbl[position_slot].base -2;
 +
 +			/* Update repeated offset LRU queue. */
 +			r2 = r1;
 +			r1 = r0;
 +			r0 = copy_pos;
 +			/* FALL THROUGH */
 +		case ST_REAL_POS:
 +			/*
 +			 * Compute a real position in window.
 +			 */
 +			copy_pos = (w_pos - copy_pos) & w_mask;
 +			/* FALL THROUGH */
 +		case ST_COPY:
 +			/*
 +			 * Copy several bytes as extracted data from the window
 +			 * into the output buffer.
 +			 */
 +			for (;;) {
 +				const unsigned char *s;
 +				int l;
 +
 +				l = copy_len;
 +				if (copy_pos > w_pos) {
 +					if (l > w_size - copy_pos)
 +						l = w_size - copy_pos;
 +				} else {
 +					if (l > w_size - w_pos)
 +						l = w_size - w_pos;
 +				}
- 				if (outp + l >= endp)
- 					l = endp - outp;
++				if (noutp + l >= endp)
++					l = (int)(endp - noutp);
 +				s = w_buff + copy_pos;
 +				if (l >= 8 && ((copy_pos + l < w_pos)
 +				  || (w_pos + l < copy_pos))) {
 +					memcpy(w_buff + w_pos, s, l);
- 					memcpy(outp, s, l);
++					memcpy(noutp, s, l);
 +				} else {
 +					unsigned char *d;
 +					int li;
 +
 +					d = w_buff + w_pos;
 +					for (li = 0; li < l; li++)
- 						outp[li] = d[li] = s[li];
++						noutp[li] = d[li] = s[li];
 +				}
- 				outp += l;
++				noutp += l;
 +				copy_pos = (copy_pos + l) & w_mask;
 +				w_pos = (w_pos + l) & w_mask;
 +				block_bytes_avail -= l;
 +				if (copy_len <= l)
 +					/* A copy of current pattern ended. */
 +					break;
 +				copy_len -= l;
- 				if (outp >= endp) {
++				if (noutp >= endp) {
 +					/* Output buffer is empty. */
 +					state = ST_COPY;
 +					goto next_data;
 +				}
 +			}
 +			state = ST_MAIN;
 +			break;
 +		}
 +	}
 +failed:
 +	return (ds->error = ARCHIVE_FAILED);
 +next_data:
 +	ds->br = bre;
 +	ds->block_bytes_avail = block_bytes_avail;
 +	ds->copy_len = copy_len;
 +	ds->copy_pos = copy_pos;
 +	ds->length_header = length_header;
 +	ds->offset_bits = offset_bits;
 +	ds->position_slot = position_slot;
 +	ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
 +	ds->state = state;
 +	ds->w_pos = w_pos;
- 	strm->avail_out = endp - outp;
++	strm->avail_out = endp - noutp;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +lzx_read_pre_tree(struct lzx_stream *strm)
 +{
 +	struct lzx_dec *ds = strm->ds;
 +	struct lzx_br *br = &(ds->br);
 +	int i;
 +
 +	if (ds->loop == 0)
 +		memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
 +	for (i = ds->loop; i < ds->pt.len_size; i++) {
 +		if (!lzx_br_read_ahead(strm, br, 4)) {
 +			ds->loop = i;
 +			return (0);
 +		}
 +		ds->pt.bitlen[i] = lzx_br_bits(br, 4);
 +		ds->pt.freq[ds->pt.bitlen[i]]++;
 +		lzx_br_consume(br, 4);
 +	}
 +	ds->loop = i;
 +	return (1);
 +}
 +
 +/*
 + * Read a bunch of bit-lengths from pre-tree.
 + */
 +static int
 +lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)
 +{
 +	struct lzx_dec *ds = strm->ds;
 +	struct lzx_br *br = &(ds->br);
 +	int c, i, j, ret, same;
 +	unsigned rbits;
 +
 +	i = ds->loop;
 +	if (i == 0)
 +		memset(d->freq, 0, sizeof(d->freq));
 +	ret = 0;
 +	if (end < 0)
 +		end = d->len_size;
 +	while (i < end) {
 +		ds->loop = i;
 +		if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))
 +			goto getdata;
 +		rbits = lzx_br_bits(br, ds->pt.max_bits);
 +		c = lzx_decode_huffman(&(ds->pt), rbits);
 +		switch (c) {
 +		case 17:/* several zero lengths, from 4 to 19. */
 +			if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))
 +				goto getdata;
 +			lzx_br_consume(br, ds->pt.bitlen[c]);
 +			same = lzx_br_bits(br, 4) + 4;
 +			if (i + same > end)
 +				return (-1);/* Invalid */
 +			lzx_br_consume(br, 4);
 +			for (j = 0; j < same; j++)
 +				d->bitlen[i++] = 0;
 +			break;
 +		case 18:/* many zero lengths, from 20 to 51. */
 +			if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))
 +				goto getdata;
 +			lzx_br_consume(br, ds->pt.bitlen[c]);
 +			same = lzx_br_bits(br, 5) + 20;
 +			if (i + same > end)
 +				return (-1);/* Invalid */
 +			lzx_br_consume(br, 5);
 +			memset(d->bitlen + i, 0, same);
 +			i += same;
 +			break;
 +		case 19:/* a few same lengths. */
 +			if (!lzx_br_read_ahead(strm, br,
 +			    ds->pt.bitlen[c]+1+ds->pt.max_bits))
 +				goto getdata;
 +			lzx_br_consume(br, ds->pt.bitlen[c]);
 +			same = lzx_br_bits(br, 1) + 4;
 +			if (i + same > end)
 +				return (-1);
 +			lzx_br_consume(br, 1);
 +			rbits = lzx_br_bits(br, ds->pt.max_bits);
 +			c = lzx_decode_huffman(&(ds->pt), rbits);
 +			lzx_br_consume(br, ds->pt.bitlen[c]);
 +			c = (d->bitlen[i] - c + 17) % 17;
 +			if (c < 0)
 +				return (-1);/* Invalid */
 +			for (j = 0; j < same; j++)
 +				d->bitlen[i++] = c;
 +			d->freq[c] += same;
 +			break;
 +		default:
 +			lzx_br_consume(br, ds->pt.bitlen[c]);
 +			c = (d->bitlen[i] - c + 17) % 17;
 +			if (c < 0)
 +				return (-1);/* Invalid */
 +			d->freq[c]++;
 +			d->bitlen[i++] = c;
 +			break;
 +		}
 +	}
 +	ret = 1;
 +getdata:
 +	ds->loop = i;
 +	return (ret);
 +}
 +
 +static int
 +lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 +{
 +	int bits;
 +
 +	if (hf->bitlen == NULL || hf->len_size != (int)len_size) {
 +		free(hf->bitlen);
 +		hf->bitlen = calloc(len_size,  sizeof(hf->bitlen[0]));
 +		if (hf->bitlen == NULL)
 +			return (ARCHIVE_FATAL);
- 		hf->len_size = len_size;
++		hf->len_size = (int)len_size;
 +	} else
 +		memset(hf->bitlen, 0, len_size *  sizeof(hf->bitlen[0]));
 +	if (hf->tbl == NULL) {
 +		if (tbl_bits < HTBL_BITS)
 +			bits = tbl_bits;
 +		else
 +			bits = HTBL_BITS;
- 		hf->tbl = malloc((1 << bits) * sizeof(hf->tbl[0]));
++		hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0]));
 +		if (hf->tbl == NULL)
 +			return (ARCHIVE_FATAL);
 +		hf->tbl_bits = tbl_bits;
 +	}
 +	if (hf->tree == NULL && tbl_bits > HTBL_BITS) {
 +		hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4);
 +		hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0]));
 +		if (hf->tree == NULL)
 +			return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +lzx_huffman_free(struct huffman *hf)
 +{
 +	free(hf->bitlen);
 +	free(hf->tbl);
 +	free(hf->tree);
 +}
 +
 +/*
 + * Make a huffman coding table.
 + */
 +static int
 +lzx_make_huffman_table(struct huffman *hf)
 +{
 +	uint16_t *tbl;
 +	const unsigned char *bitlen;
 +	int bitptn[17], weight[17];
 +	int i, maxbits = 0, ptn, tbl_size, w;
 +	int diffbits, len_avail;
 +
 +	/*
 +	 * Initialize bit patterns.
 +	 */
 +	ptn = 0;
 +	for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {
 +		bitptn[i] = ptn;
 +		weight[i] = w;
 +		if (hf->freq[i]) {
 +			ptn += hf->freq[i] * w;
 +			maxbits = i;
 +		}
 +	}
 +	if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)
 +		return (0);/* Invalid */
 +
 +	hf->max_bits = maxbits;
 +
 +	/*
 +	 * Cut out extra bits which we won't house in the table.
 +	 * This preparation reduces the same calculation in the for-loop
 +	 * making the table.
 +	 */
 +	if (maxbits < 16) {
 +		int ebits = 16 - maxbits;
 +		for (i = 1; i <= maxbits; i++) {
 +			bitptn[i] >>= ebits;
 +			weight[i] >>= ebits;
 +		}
 +	}
 +	if (maxbits > HTBL_BITS) {
 +		int htbl_max;
 +		uint16_t *p;
 +
 +		diffbits = maxbits - HTBL_BITS;
 +		for (i = 1; i <= HTBL_BITS; i++) {
 +			bitptn[i] >>= diffbits;
 +			weight[i] >>= diffbits;
 +		}
 +		htbl_max = bitptn[HTBL_BITS] +
 +		    weight[HTBL_BITS] * hf->freq[HTBL_BITS];
 +		p = &(hf->tbl[htbl_max]);
 +		while (p < &hf->tbl[1U<<HTBL_BITS])
 +			*p++ = 0;
 +	} else
 +		diffbits = 0;
 +	hf->shift_bits = diffbits;
 +
 +	/*
 +	 * Make the table.
 +	 */
 +	tbl_size = 1 << HTBL_BITS;
 +	tbl = hf->tbl;
 +	bitlen = hf->bitlen;
 +	len_avail = hf->len_size;
 +	hf->tree_used = 0;
 +	for (i = 0; i < len_avail; i++) {
 +		uint16_t *p;
 +		int len, cnt;
 +		uint16_t bit;
 +		int extlen;
 +		struct htree_t *ht;
 +
 +		if (bitlen[i] == 0)
 +			continue;
 +		/* Get a bit pattern */
 +		len = bitlen[i];
 +		ptn = bitptn[len];
 +		cnt = weight[len];
 +		if (len <= HTBL_BITS) {
 +			/* Calculate next bit pattern */
 +			if ((bitptn[len] = ptn + cnt) > tbl_size)
 +				return (0);/* Invalid */
 +			/* Update the table */
 +			p = &(tbl[ptn]);
 +			while (--cnt >= 0)
 +				p[cnt] = (uint16_t)i;
 +			continue;
 +		}
 +
 +		/*
 +		 * A bit length is too big to be housed to a direct table,
 +		 * so we use a tree model for its extra bits.
 +		 */
 +		bitptn[len] = ptn + cnt;
 +		bit = 1U << (diffbits -1);
 +		extlen = len - HTBL_BITS;
 +		
 +		p = &(tbl[ptn >> diffbits]);
 +		if (*p == 0) {
 +			*p = len_avail + hf->tree_used;
 +			ht = &(hf->tree[hf->tree_used++]);
 +			if (hf->tree_used > hf->tree_avail)
 +				return (0);/* Invalid */
 +			ht->left = 0;
 +			ht->right = 0;
 +		} else {
 +			if (*p < len_avail ||
 +			    *p >= (len_avail + hf->tree_used))
 +				return (0);/* Invalid */
 +			ht = &(hf->tree[*p - len_avail]);
 +		}
 +		while (--extlen > 0) {
 +			if (ptn & bit) {
 +				if (ht->left < len_avail) {
 +					ht->left = len_avail + hf->tree_used;
 +					ht = &(hf->tree[hf->tree_used++]);
 +					if (hf->tree_used > hf->tree_avail)
 +						return (0);/* Invalid */
 +					ht->left = 0;
 +					ht->right = 0;
 +				} else {
 +					ht = &(hf->tree[ht->left - len_avail]);
 +				}
 +			} else {
 +				if (ht->right < len_avail) {
 +					ht->right = len_avail + hf->tree_used;
 +					ht = &(hf->tree[hf->tree_used++]);
 +					if (hf->tree_used > hf->tree_avail)
 +						return (0);/* Invalid */
 +					ht->left = 0;
 +					ht->right = 0;
 +				} else {
 +					ht = &(hf->tree[ht->right - len_avail]);
 +				}
 +			}
 +			bit >>= 1;
 +		}
 +		if (ptn & bit) {
 +			if (ht->left != 0)
 +				return (0);/* Invalid */
 +			ht->left = (uint16_t)i;
 +		} else {
 +			if (ht->right != 0)
 +				return (0);/* Invalid */
 +			ht->right = (uint16_t)i;
 +		}
 +	}
 +	return (1);
 +}
 +
 +static int
 +lzx_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c)
 +{
 +	struct htree_t *ht;
 +	int extlen;
 +
 +	ht = hf->tree;
 +	extlen = hf->shift_bits;
 +	while (c >= hf->len_size) {
 +		c -= hf->len_size;
 +		if (extlen-- <= 0 || c >= hf->tree_used)
 +			return (0);
 +		if (rbits & (1U << extlen))
 +			c = ht[c].left;
 +		else
 +			c = ht[c].right;
 +	}
 +	return (c);
 +}
 +
 +static inline int
 +lzx_decode_huffman(struct huffman *hf, unsigned rbits)
 +{
 +	int c;
 +	/*
 +	 * At first search an index table for a bit pattern.
 +	 * If it fails, search a huffman tree for.
 +	 */
 +	c = hf->tbl[rbits >> hf->shift_bits];
 +	if (c < hf->len_size)
 +		return (c);
 +	/* This bit pattern needs to be found out at a huffman tree. */
 +	return (lzx_decode_huffman_tree(hf, rbits, c));
 +}
 +
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
index db7aa9d,0000000..8147461
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
@@@ -1,3213 -1,0 +1,3233 @@@
 +/*-
 + * Copyright (c) 2003-2007 Tim Kientzle
 + * Copyright (c) 2009 Andreas Henriksson <andreas at fatal.se>
-  * Copyright (c) 2009-2011 Michihiro NAKAJIMA
++ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_iso9660.c 201246 2009-12-30 05:30:35Z kientzle $");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +/* #include <stdint.h> */ /* See archive_platform.h */
 +#include <stdio.h>
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#include <time.h>
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_private.h"
 +#include "archive_read_private.h"
 +#include "archive_string.h"
 +
 +/*
 + * An overview of ISO 9660 format:
 + *
 + * Each disk is laid out as follows:
 + *   * 32k reserved for private use
 + *   * Volume descriptor table.  Each volume descriptor
 + *     is 2k and specifies basic format information.
 + *     The "Primary Volume Descriptor" (PVD) is defined by the
 + *     standard and should always be present; other volume
 + *     descriptors include various vendor-specific extensions.
 + *   * Files and directories.  Each file/dir is specified by
 + *     an "extent" (starting sector and length in bytes).
 + *     Dirs are just files with directory records packed one
 + *     after another.  The PVD contains a single dir entry
 + *     specifying the location of the root directory.  Everything
 + *     else follows from there.
 + *
 + * This module works by first reading the volume descriptors, then
 + * building a list of directory entries, sorted by starting
 + * sector.  At each step, I look for the earliest dir entry that
 + * hasn't yet been read, seek forward to that location and read
 + * that entry.  If it's a dir, I slurp in the new dir entries and
 + * add them to the heap; if it's a regular file, I return the
 + * corresponding archive_entry and wait for the client to request
 + * the file body.  This strategy allows us to read most compliant
 + * CDs with a single pass through the data, as required by libarchive.
 + */
 +#define	LOGICAL_BLOCK_SIZE	2048
 +#define	SYSTEM_AREA_BLOCK	16
 +
 +/* Structure of on-disk primary volume descriptor. */
 +#define PVD_type_offset 0
 +#define PVD_type_size 1
 +#define PVD_id_offset (PVD_type_offset + PVD_type_size)
 +#define PVD_id_size 5
 +#define PVD_version_offset (PVD_id_offset + PVD_id_size)
 +#define PVD_version_size 1
 +#define PVD_reserved1_offset (PVD_version_offset + PVD_version_size)
 +#define PVD_reserved1_size 1
 +#define PVD_system_id_offset (PVD_reserved1_offset + PVD_reserved1_size)
 +#define PVD_system_id_size 32
 +#define PVD_volume_id_offset (PVD_system_id_offset + PVD_system_id_size)
 +#define PVD_volume_id_size 32
 +#define PVD_reserved2_offset (PVD_volume_id_offset + PVD_volume_id_size)
 +#define PVD_reserved2_size 8
 +#define PVD_volume_space_size_offset (PVD_reserved2_offset + PVD_reserved2_size)
 +#define PVD_volume_space_size_size 8
 +#define PVD_reserved3_offset (PVD_volume_space_size_offset + PVD_volume_space_size_size)
 +#define PVD_reserved3_size 32
 +#define PVD_volume_set_size_offset (PVD_reserved3_offset + PVD_reserved3_size)
 +#define PVD_volume_set_size_size 4
 +#define PVD_volume_sequence_number_offset (PVD_volume_set_size_offset + PVD_volume_set_size_size)
 +#define PVD_volume_sequence_number_size 4
 +#define PVD_logical_block_size_offset (PVD_volume_sequence_number_offset + PVD_volume_sequence_number_size)
 +#define PVD_logical_block_size_size 4
 +#define PVD_path_table_size_offset (PVD_logical_block_size_offset + PVD_logical_block_size_size)
 +#define PVD_path_table_size_size 8
 +#define PVD_type_1_path_table_offset (PVD_path_table_size_offset + PVD_path_table_size_size)
 +#define PVD_type_1_path_table_size 4
 +#define PVD_opt_type_1_path_table_offset (PVD_type_1_path_table_offset + PVD_type_1_path_table_size)
 +#define PVD_opt_type_1_path_table_size 4
 +#define PVD_type_m_path_table_offset (PVD_opt_type_1_path_table_offset + PVD_opt_type_1_path_table_size)
 +#define PVD_type_m_path_table_size 4
 +#define PVD_opt_type_m_path_table_offset (PVD_type_m_path_table_offset + PVD_type_m_path_table_size)
 +#define PVD_opt_type_m_path_table_size 4
 +#define PVD_root_directory_record_offset (PVD_opt_type_m_path_table_offset + PVD_opt_type_m_path_table_size)
 +#define PVD_root_directory_record_size 34
 +#define PVD_volume_set_id_offset (PVD_root_directory_record_offset + PVD_root_directory_record_size)
 +#define PVD_volume_set_id_size 128
 +#define PVD_publisher_id_offset (PVD_volume_set_id_offset + PVD_volume_set_id_size)
 +#define PVD_publisher_id_size 128
 +#define PVD_preparer_id_offset (PVD_publisher_id_offset + PVD_publisher_id_size)
 +#define PVD_preparer_id_size 128
 +#define PVD_application_id_offset (PVD_preparer_id_offset + PVD_preparer_id_size)
 +#define PVD_application_id_size 128
 +#define PVD_copyright_file_id_offset (PVD_application_id_offset + PVD_application_id_size)
 +#define PVD_copyright_file_id_size 37
 +#define PVD_abstract_file_id_offset (PVD_copyright_file_id_offset + PVD_copyright_file_id_size)
 +#define PVD_abstract_file_id_size 37
 +#define PVD_bibliographic_file_id_offset (PVD_abstract_file_id_offset + PVD_abstract_file_id_size)
 +#define PVD_bibliographic_file_id_size 37
 +#define PVD_creation_date_offset (PVD_bibliographic_file_id_offset + PVD_bibliographic_file_id_size)
 +#define PVD_creation_date_size 17
 +#define PVD_modification_date_offset (PVD_creation_date_offset + PVD_creation_date_size)
 +#define PVD_modification_date_size 17
 +#define PVD_expiration_date_offset (PVD_modification_date_offset + PVD_modification_date_size)
 +#define PVD_expiration_date_size 17
 +#define PVD_effective_date_offset (PVD_expiration_date_offset + PVD_expiration_date_size)
 +#define PVD_effective_date_size 17
 +#define PVD_file_structure_version_offset (PVD_effective_date_offset + PVD_effective_date_size)
 +#define PVD_file_structure_version_size 1
 +#define PVD_reserved4_offset (PVD_file_structure_version_offset + PVD_file_structure_version_size)
 +#define PVD_reserved4_size 1
 +#define PVD_application_data_offset (PVD_reserved4_offset + PVD_reserved4_size)
 +#define PVD_application_data_size 512
 +#define PVD_reserved5_offset (PVD_application_data_offset + PVD_application_data_size)
 +#define PVD_reserved5_size (2048 - PVD_reserved5_offset)
 +
 +/* TODO: It would make future maintenance easier to just hardcode the
 + * above values.  In particular, ECMA119 states the offsets as part of
 + * the standard.  That would eliminate the need for the following check.*/
 +#if PVD_reserved5_offset != 1395
 +#error PVD offset and size definitions are wrong.
 +#endif
 +
 +
 +/* Structure of optional on-disk supplementary volume descriptor. */
 +#define SVD_type_offset 0
 +#define SVD_type_size 1
 +#define SVD_id_offset (SVD_type_offset + SVD_type_size)
 +#define SVD_id_size 5
 +#define SVD_version_offset (SVD_id_offset + SVD_id_size)
 +#define SVD_version_size 1
 +/* ... */
 +#define SVD_reserved1_offset	72
 +#define SVD_reserved1_size	8
 +#define SVD_volume_space_size_offset 80
 +#define SVD_volume_space_size_size 8
 +#define SVD_escape_sequences_offset (SVD_volume_space_size_offset + SVD_volume_space_size_size)
 +#define SVD_escape_sequences_size 32
 +/* ... */
 +#define SVD_logical_block_size_offset 128
 +#define SVD_logical_block_size_size 4
 +#define SVD_type_L_path_table_offset 140
 +#define SVD_type_M_path_table_offset 148
 +/* ... */
 +#define SVD_root_directory_record_offset 156
 +#define SVD_root_directory_record_size 34
 +#define SVD_file_structure_version_offset 881
 +#define SVD_reserved2_offset	882
 +#define SVD_reserved2_size	1
 +#define SVD_reserved3_offset	1395
 +#define SVD_reserved3_size	653
 +/* ... */
 +/* FIXME: validate correctness of last SVD entry offset. */
 +
 +/* Structure of an on-disk directory record. */
 +/* Note:  ISO9660 stores each multi-byte integer twice, once in
 + * each byte order.  The sizes here are the size of just one
 + * of the two integers.  (This is why the offset of a field isn't
 + * the same as the offset+size of the previous field.) */
 +#define DR_length_offset 0
 +#define DR_length_size 1
 +#define DR_ext_attr_length_offset 1
 +#define DR_ext_attr_length_size 1
 +#define DR_extent_offset 2
 +#define DR_extent_size 4
 +#define DR_size_offset 10
 +#define DR_size_size 4
 +#define DR_date_offset 18
 +#define DR_date_size 7
 +#define DR_flags_offset 25
 +#define DR_flags_size 1
 +#define DR_file_unit_size_offset 26
 +#define DR_file_unit_size_size 1
 +#define DR_interleave_offset 27
 +#define DR_interleave_size 1
 +#define DR_volume_sequence_number_offset 28
 +#define DR_volume_sequence_number_size 2
 +#define DR_name_len_offset 32
 +#define DR_name_len_size 1
 +#define DR_name_offset 33
 +
 +#ifdef HAVE_ZLIB_H
 +static const unsigned char zisofs_magic[8] = {
 +	0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07
 +};
 +
 +struct zisofs {
 +	/* Set 1 if this file compressed by paged zlib */
 +	int		 pz;
 +	int		 pz_log2_bs; /* Log2 of block size */
 +	uint64_t	 pz_uncompressed_size;
 +
 +	int		 initialized;
 +	unsigned char	*uncompressed_buffer;
 +	size_t		 uncompressed_buffer_size;
 +
 +	uint32_t	 pz_offset;
 +	unsigned char	 header[16];
 +	size_t		 header_avail;
 +	int		 header_passed;
 +	unsigned char	*block_pointers;
 +	size_t		 block_pointers_alloc;
 +	size_t		 block_pointers_size;
 +	size_t		 block_pointers_avail;
 +	size_t		 block_off;
 +	uint32_t	 block_avail;
 +
 +	z_stream	 stream;
 +	int		 stream_valid;
 +};
 +#else
 +struct zisofs {
 +	/* Set 1 if this file compressed by paged zlib */
 +	int		 pz;
 +};
 +#endif
 +
 +struct content {
 +	uint64_t	 offset;/* Offset on disk.		*/
 +	uint64_t	 size;	/* File size in bytes.		*/
 +	struct content	*next;
 +};
 +
 +/* In-memory storage for a directory record. */
 +struct file_info {
 +	struct file_info	*use_next;
 +	struct file_info	*parent;
 +	struct file_info	*next;
 +	struct file_info	*re_next;
 +	int		 subdirs;
 +	uint64_t	 key;		/* Heap Key.			*/
 +	uint64_t	 offset;	/* Offset on disk.		*/
 +	uint64_t	 size;		/* File size in bytes.		*/
 +	uint32_t	 ce_offset;	/* Offset of CE.		*/
 +	uint32_t	 ce_size;	/* Size of CE.			*/
 +	char		 rr_moved;	/* Flag to rr_moved.		*/
 +	char		 rr_moved_has_re_only;
 +	char		 re;		/* Having RRIP "RE" extension.	*/
 +	char		 re_descendant;
 +	uint64_t	 cl_offset;	/* Having RRIP "CL" extension.	*/
 +	int		 birthtime_is_set;
 +	time_t		 birthtime;	/* File created time.		*/
 +	time_t		 mtime;		/* File last modified time.	*/
 +	time_t		 atime;		/* File last accessed time.	*/
 +	time_t		 ctime;		/* File attribute change time.	*/
 +	uint64_t	 rdev;		/* Device number.		*/
 +	mode_t		 mode;
 +	uid_t		 uid;
 +	gid_t		 gid;
 +	int64_t		 number;
 +	int		 nlinks;
 +	struct archive_string name; /* Pathname */
 +	unsigned char	*utf16be_name;
 +	size_t		 utf16be_bytes;
 +	char		 name_continues; /* Non-zero if name continues */
 +	struct archive_string symlink;
 +	char		 symlink_continues; /* Non-zero if link continues */
 +	/* Set 1 if this file compressed by paged zlib(zisofs) */
 +	int		 pz;
 +	int		 pz_log2_bs; /* Log2 of block size */
 +	uint64_t	 pz_uncompressed_size;
 +	/* Set 1 if this file is multi extent. */
 +	int		 multi_extent;
 +	struct {
 +		struct content	*first;
 +		struct content	**last;
 +	} contents;
 +	struct {
 +		struct file_info	*first;
 +		struct file_info	**last;
 +	} rede_files;
 +};
 +
 +struct heap_queue {
 +	struct file_info **files;
 +	int		 allocated;
 +	int		 used;
 +};
 +
 +struct iso9660 {
 +	int	magic;
 +#define ISO9660_MAGIC   0x96609660
 +
 +	int opt_support_joliet;
 +	int opt_support_rockridge;
 +
 +	struct archive_string pathname;
 +	char	seenRockridge;	/* Set true if RR extensions are used. */
 +	char	seenSUSP;	/* Set true if SUSP is beging used. */
 +	char	seenJoliet;
 +
 +	unsigned char	suspOffset;
 +	struct file_info *rr_moved;
 +	struct read_ce_queue {
 +		struct read_ce_req {
 +			uint64_t	 offset;/* Offset of CE on disk. */
 +			struct file_info *file;
 +		}		*reqs;
 +		int		 cnt;
 +		int		 allocated;
 +	}	read_ce_req;
 +
 +	int64_t		previous_number;
 +	struct archive_string previous_pathname;
 +
 +	struct file_info		*use_files;
 +	struct heap_queue		 pending_files;
 +	struct {
 +		struct file_info	*first;
 +		struct file_info	**last;
 +	}	cache_files;
 +	struct {
 +		struct file_info	*first;
 +		struct file_info	**last;
 +	}	re_files;
 +
 +	uint64_t current_position;
 +	ssize_t	logical_block_size;
 +	uint64_t volume_size; /* Total size of volume in bytes. */
 +	int32_t  volume_block;/* Total size of volume in logical blocks. */
 +
 +	struct vd {
 +		int		location;	/* Location of Extent.	*/
 +		uint32_t	size;
 +	} primary, joliet;
 +
 +	int64_t	entry_sparse_offset;
 +	int64_t	entry_bytes_remaining;
 +	size_t  entry_bytes_unconsumed;
 +	struct zisofs	 entry_zisofs;
 +	struct content	*entry_content;
 +	struct archive_string_conv *sconv_utf16be;
 +	/*
 +	 * Buffers for a full pathname in UTF-16BE in Joliet extensions.
 +	 */
 +#define UTF16_NAME_MAX	1024
 +	unsigned char *utf16be_path;
 +	size_t		 utf16be_path_len;
 +	unsigned char *utf16be_previous_path;
 +	size_t		 utf16be_previous_path_len;
++	/* Null buufer used in bidder to improve its performance. */
++	unsigned char	 null[2048];
 +};
 +
 +static int	archive_read_format_iso9660_bid(struct archive_read *, int);
 +static int	archive_read_format_iso9660_options(struct archive_read *,
 +		    const char *, const char *);
 +static int	archive_read_format_iso9660_cleanup(struct archive_read *);
 +static int	archive_read_format_iso9660_read_data(struct archive_read *,
 +		    const void **, size_t *, int64_t *);
 +static int	archive_read_format_iso9660_read_data_skip(struct archive_read *);
 +static int	archive_read_format_iso9660_read_header(struct archive_read *,
 +		    struct archive_entry *);
 +static const char *build_pathname(struct archive_string *, struct file_info *);
 +static int	build_pathname_utf16be(unsigned char *, size_t, size_t *,
 +		    struct file_info *);
 +#if DEBUG
 +static void	dump_isodirrec(FILE *, const unsigned char *isodirrec);
 +#endif
 +static time_t	time_from_tm(struct tm *);
 +static time_t	isodate17(const unsigned char *);
 +static time_t	isodate7(const unsigned char *);
 +static int	isBootRecord(struct iso9660 *, const unsigned char *);
 +static int	isVolumePartition(struct iso9660 *, const unsigned char *);
 +static int	isVDSetTerminator(struct iso9660 *, const unsigned char *);
 +static int	isJolietSVD(struct iso9660 *, const unsigned char *);
 +static int	isSVD(struct iso9660 *, const unsigned char *);
 +static int	isEVD(struct iso9660 *, const unsigned char *);
 +static int	isPVD(struct iso9660 *, const unsigned char *);
 +static int	next_cache_entry(struct archive_read *, struct iso9660 *,
 +		    struct file_info **);
 +static int	next_entry_seek(struct archive_read *, struct iso9660 *,
 +		    struct file_info **);
 +static struct file_info *
 +		parse_file_info(struct archive_read *a,
 +		    struct file_info *parent, const unsigned char *isodirrec);
 +static int	parse_rockridge(struct archive_read *a,
 +		    struct file_info *file, const unsigned char *start,
 +		    const unsigned char *end);
 +static int	register_CE(struct archive_read *a, int32_t location,
 +		    struct file_info *file);
 +static int	read_CE(struct archive_read *a, struct iso9660 *iso9660);
 +static void	parse_rockridge_NM1(struct file_info *,
 +		    const unsigned char *, int);
 +static void	parse_rockridge_SL1(struct file_info *,
 +		    const unsigned char *, int);
 +static void	parse_rockridge_TF1(struct file_info *,
 +		    const unsigned char *, int);
 +static void	parse_rockridge_ZF1(struct file_info *,
 +		    const unsigned char *, int);
 +static void	register_file(struct iso9660 *, struct file_info *);
 +static void	release_files(struct iso9660 *);
 +static unsigned	toi(const void *p, int n);
 +static inline void re_add_entry(struct iso9660 *, struct file_info *);
 +static inline struct file_info * re_get_entry(struct iso9660 *);
 +static inline int rede_add_entry(struct file_info *);
 +static inline struct file_info * rede_get_entry(struct file_info *);
 +static inline void cache_add_entry(struct iso9660 *iso9660,
 +		    struct file_info *file);
 +static inline struct file_info *cache_get_entry(struct iso9660 *iso9660);
 +static int	heap_add_entry(struct archive_read *a, struct heap_queue *heap,
 +		    struct file_info *file, uint64_t key);
 +static struct file_info *heap_get_entry(struct heap_queue *heap);
 +
 +#define add_entry(arch, iso9660, file)	\
 +	heap_add_entry(arch, &((iso9660)->pending_files), file, file->offset)
 +#define next_entry(iso9660)		\
 +	heap_get_entry(&((iso9660)->pending_files))
 +
 +int
 +archive_read_support_format_iso9660(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct iso9660 *iso9660;
 +	int r;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_read_support_format_iso9660");
 +
 +	iso9660 = (struct iso9660 *)calloc(1, sizeof(*iso9660));
 +	if (iso9660 == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate iso9660 data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	iso9660->magic = ISO9660_MAGIC;
 +	iso9660->cache_files.first = NULL;
 +	iso9660->cache_files.last = &(iso9660->cache_files.first);
 +	iso9660->re_files.first = NULL;
 +	iso9660->re_files.last = &(iso9660->re_files.first);
 +	/* Enable to support Joliet extensions by default.	*/
 +	iso9660->opt_support_joliet = 1;
 +	/* Enable to support Rock Ridge extensions by default.	*/
 +	iso9660->opt_support_rockridge = 1;
 +
 +	r = __archive_read_register_format(a,
 +	    iso9660,
 +	    "iso9660",
 +	    archive_read_format_iso9660_bid,
 +	    archive_read_format_iso9660_options,
 +	    archive_read_format_iso9660_read_header,
 +	    archive_read_format_iso9660_read_data,
 +	    archive_read_format_iso9660_read_data_skip,
++	    NULL,
 +	    archive_read_format_iso9660_cleanup);
 +
 +	if (r != ARCHIVE_OK) {
 +		free(iso9660);
 +		return (r);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +
 +static int
 +archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
 +{
 +	struct iso9660 *iso9660;
 +	ssize_t bytes_read;
 +	const unsigned char *p;
 +	int seenTerminator;
 +
 +	/* If there's already a better bid than we can ever
 +	   make, don't bother testing. */
 +	if (best_bid > 48)
 +		return (-1);
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	/*
 +	 * Skip the first 32k (reserved area) and get the first
 +	 * 8 sectors of the volume descriptor table.  Of course,
 +	 * if the I/O layer gives us more, we'll take it.
 +	 */
 +#define RESERVED_AREA	(SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE)
 +	p = __archive_read_ahead(a,
 +	    RESERVED_AREA + 8 * LOGICAL_BLOCK_SIZE,
 +	    &bytes_read);
 +	if (p == NULL)
 +	    return (-1);
 +
 +	/* Skip the reserved area. */
 +	bytes_read -= RESERVED_AREA;
 +	p += RESERVED_AREA;
 +
 +	/* Check each volume descriptor. */
 +	seenTerminator = 0;
 +	for (; bytes_read > LOGICAL_BLOCK_SIZE;
 +	    bytes_read -= LOGICAL_BLOCK_SIZE, p += LOGICAL_BLOCK_SIZE) {
 +		/* Do not handle undefined Volume Descriptor Type. */
 +		if (p[0] >= 4 && p[0] <= 254)
 +			return (0);
 +		/* Standard Identifier must be "CD001" */
 +		if (memcmp(p + 1, "CD001", 5) != 0)
 +			return (0);
 +		if (isPVD(iso9660, p))
 +			continue;
 +		if (!iso9660->joliet.location) {
 +			if (isJolietSVD(iso9660, p))
 +				continue;
 +		}
 +		if (isBootRecord(iso9660, p))
 +			continue;
 +		if (isEVD(iso9660, p))
 +			continue;
 +		if (isSVD(iso9660, p))
 +			continue;
 +		if (isVolumePartition(iso9660, p))
 +			continue;
 +		if (isVDSetTerminator(iso9660, p)) {
 +			seenTerminator = 1;
 +			break;
 +		}
 +		return (0);
 +	}
 +	/*
 +	 * ISO 9660 format must have Primary Volume Descriptor and
 +	 * Volume Descriptor Set Terminator.
 +	 */
 +	if (seenTerminator && iso9660->primary.location > 16)
 +		return (48);
 +
 +	/* We didn't find a valid PVD; return a bid of zero. */
 +	return (0);
 +}
 +
 +static int
 +archive_read_format_iso9660_options(struct archive_read *a,
 +		const char *key, const char *val)
 +{
 +	struct iso9660 *iso9660;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	if (strcmp(key, "joliet") == 0) {
 +		if (val == NULL || strcmp(val, "off") == 0 ||
 +				strcmp(val, "ignore") == 0 ||
 +				strcmp(val, "disable") == 0 ||
 +				strcmp(val, "0") == 0)
 +			iso9660->opt_support_joliet = 0;
 +		else
 +			iso9660->opt_support_joliet = 1;
 +		return (ARCHIVE_OK);
 +	}
 +	if (strcmp(key, "rockridge") == 0 ||
 +	    strcmp(key, "Rockridge") == 0) {
 +		iso9660->opt_support_rockridge = val != NULL;
 +		return (ARCHIVE_OK);
 +	}
 +
 +	/* Note: The "warn" return is just to inform the options
 +	 * supervisor that we didn't handle it.  It will generate
 +	 * a suitable error if no one used this option. */
 +	return (ARCHIVE_WARN);
 +}
 +
 +static int
++isNull(struct iso9660 *iso9660, const unsigned char *h, unsigned offset,
++unsigned bytes)
++{
++
++	while (bytes >= sizeof(iso9660->null)) {
++		if (!memcmp(iso9660->null, h + offset, sizeof(iso9660->null)))
++			return (0);
++		offset += sizeof(iso9660->null);
++		bytes -= sizeof(iso9660->null);
++	}
++	if (bytes)
++		return memcmp(iso9660->null, h + offset, bytes) == 0;
++	else
++		return (1);
++}
++
++static int
 +isBootRecord(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	(void)iso9660; /* UNUSED */
 +
 +	/* Type of the Volume Descriptor Boot Record must be 0. */
 +	if (h[0] != 0)
 +		return (0);
 +
 +	/* Volume Descriptor Version must be 1. */
 +	if (h[6] != 1)
 +		return (0);
 +
 +	return (1);
 +}
 +
 +static int
 +isVolumePartition(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	int32_t location;
 +
 +	/* Type of the Volume Partition Descriptor must be 3. */
 +	if (h[0] != 3)
 +		return (0);
 +
 +	/* Volume Descriptor Version must be 1. */
 +	if (h[6] != 1)
 +		return (0);
 +	/* Unused Field */
 +	if (h[7] != 0)
 +		return (0);
 +
 +	location = archive_le32dec(h + 72);
 +	if (location <= SYSTEM_AREA_BLOCK ||
 +	    location >= iso9660->volume_block)
 +		return (0);
 +	if ((uint32_t)location != archive_be32dec(h + 76))
 +		return (0);
 +
 +	return (1);
 +}
 +
 +static int
 +isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
 +{
- 	int i;
- 
 +	(void)iso9660; /* UNUSED */
 +
 +	/* Type of the Volume Descriptor Set Terminator must be 255. */
 +	if (h[0] != 255)
 +		return (0);
 +
 +	/* Volume Descriptor Version must be 1. */
 +	if (h[6] != 1)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
- 	for (i = 7; i < 2048; ++i)
- 		if (h[i] != 0)
- 			return (0);
++	if (!isNull(iso9660, h, 7, 2048-7))
++		return (0);
 +
 +	return (1);
 +}
 +
 +static int
 +isJolietSVD(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	const unsigned char *p;
 +	ssize_t logical_block_size;
 +	int32_t volume_block;
 +
 +	/* Check if current sector is a kind of Supplementary Volume
 +	 * Descriptor. */
 +	if (!isSVD(iso9660, h))
 +		return (0);
 +
 +	/* FIXME: do more validations according to joliet spec. */
 +
 +	/* check if this SVD contains joliet extension! */
 +	p = h + SVD_escape_sequences_offset;
 +	/* N.B. Joliet spec says p[1] == '\\', but.... */
 +	if (p[0] == '%' && p[1] == '/') {
 +		int level = 0;
 +
 +		if (p[2] == '@')
 +			level = 1;
 +		else if (p[2] == 'C')
 +			level = 2;
 +		else if (p[2] == 'E')
 +			level = 3;
 +		else /* not joliet */
 +			return (0);
 +
 +		iso9660->seenJoliet = level;
 +
 +	} else /* not joliet */
 +		return (0);
 +
 +	logical_block_size =
 +	    archive_le16dec(h + SVD_logical_block_size_offset);
 +	volume_block = archive_le32dec(h + SVD_volume_space_size_offset);
 +
 +	iso9660->logical_block_size = logical_block_size;
 +	iso9660->volume_block = volume_block;
 +	iso9660->volume_size = logical_block_size * (uint64_t)volume_block;
 +	/* Read Root Directory Record in Volume Descriptor. */
 +	p = h + SVD_root_directory_record_offset;
 +	iso9660->joliet.location = archive_le32dec(p + DR_extent_offset);
 +	iso9660->joliet.size = archive_le32dec(p + DR_size_offset);
 +
 +	return (48);
 +}
 +
 +static int
 +isSVD(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	const unsigned char *p;
 +	ssize_t logical_block_size;
 +	int32_t volume_block;
 +	int32_t location;
- 	int i;
 +
 +	(void)iso9660; /* UNUSED */
 +
 +	/* Type 2 means it's a SVD. */
 +	if (h[SVD_type_offset] != 2)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
- 	for (i = 0; i < SVD_reserved1_size; ++i)
- 		if (h[SVD_reserved1_offset + i] != 0)
- 			return (0);
- 	for (i = 0; i < SVD_reserved2_size; ++i)
- 		if (h[SVD_reserved2_offset + i] != 0)
- 			return (0);
- 	for (i = 0; i < SVD_reserved3_size; ++i)
- 		if (h[SVD_reserved3_offset + i] != 0)
- 			return (0);
++	if (!isNull(iso9660, h, SVD_reserved1_offset, SVD_reserved1_size))
++		return (0);
++	if (!isNull(iso9660, h, SVD_reserved2_offset, SVD_reserved2_size))
++		return (0);
++	if (!isNull(iso9660, h, SVD_reserved3_offset, SVD_reserved3_size))
++		return (0);
 +
 +	/* File structure version must be 1 for ISO9660/ECMA119. */
 +	if (h[SVD_file_structure_version_offset] != 1)
 +		return (0);
 +
 +	logical_block_size =
 +	    archive_le16dec(h + SVD_logical_block_size_offset);
 +	if (logical_block_size <= 0)
 +		return (0);
 +
 +	volume_block = archive_le32dec(h + SVD_volume_space_size_offset);
 +	if (volume_block <= SYSTEM_AREA_BLOCK+4)
 +		return (0);
 +
 +	/* Location of Occurrence of Type L Path Table must be
 +	 * available location,
 +	 * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_le32dec(h+SVD_type_L_path_table_offset);
 +	if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)
 +		return (0);
 +
 +	/* The Type M Path Table must be at a valid location (WinISO
 +	 * and probably other programs omit this, so we allow zero)
 +	 *
 +	 * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_be32dec(h+SVD_type_M_path_table_offset);
 +	if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)
 +	    || location >= volume_block)
 +		return (0);
 +
 +	/* Read Root Directory Record in Volume Descriptor. */
 +	p = h + SVD_root_directory_record_offset;
 +	if (p[DR_length_offset] != 34)
 +		return (0);
 +
 +	return (48);
 +}
 +
 +static int
 +isEVD(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	const unsigned char *p;
 +	ssize_t logical_block_size;
 +	int32_t volume_block;
 +	int32_t location;
- 	int i;
 +
 +	(void)iso9660; /* UNUSED */
 +
 +	/* Type of the Enhanced Volume Descriptor must be 2. */
 +	if (h[PVD_type_offset] != 2)
 +		return (0);
 +
 +	/* EVD version must be 2. */
 +	if (h[PVD_version_offset] != 2)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	if (h[PVD_reserved1_offset] != 0)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
- 	for (i = 0; i < PVD_reserved2_size; ++i)
- 		if (h[PVD_reserved2_offset + i] != 0)
- 			return (0);
++	if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
++		return (0);
 +
 +	/* Reserved field must be 0. */
- 	for (i = 0; i < PVD_reserved3_size; ++i)
- 		if (h[PVD_reserved3_offset + i] != 0)
- 			return (0);
++	if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
++		return (0);
 +
 +	/* Logical block size must be > 0. */
 +	/* I've looked at Ecma 119 and can't find any stronger
 +	 * restriction on this field. */
 +	logical_block_size =
 +	    archive_le16dec(h + PVD_logical_block_size_offset);
 +	if (logical_block_size <= 0)
 +		return (0);
 +
 +	volume_block =
 +	    archive_le32dec(h + PVD_volume_space_size_offset);
 +	if (volume_block <= SYSTEM_AREA_BLOCK+4)
 +		return (0);
 +
 +	/* File structure version must be 2 for ISO9660:1999. */
 +	if (h[PVD_file_structure_version_offset] != 2)
 +		return (0);
 +
 +	/* Location of Occurrence of Type L Path Table must be
 +	 * available location,
 +	 * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_le32dec(h+PVD_type_1_path_table_offset);
 +	if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)
 +		return (0);
 +
 +	/* Location of Occurrence of Type M Path Table must be
 +	 * available location,
 +	 * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_be32dec(h+PVD_type_m_path_table_offset);
 +	if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)
 +	    || location >= volume_block)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
- 	for (i = 0; i < PVD_reserved4_size; ++i)
- 		if (h[PVD_reserved4_offset + i] != 0)
- 			return (0);
++	if (!isNull(iso9660, h, PVD_reserved4_offset, PVD_reserved4_size))
++		return (0);
 +
 +	/* Reserved field must be 0. */
- 	for (i = 0; i < PVD_reserved5_size; ++i)
- 		if (h[PVD_reserved5_offset + i] != 0)
- 			return (0);
++	if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
++		return (0);
 +
 +	/* Read Root Directory Record in Volume Descriptor. */
 +	p = h + PVD_root_directory_record_offset;
 +	if (p[DR_length_offset] != 34)
 +		return (0);
 +
 +	return (48);
 +}
 +
 +static int
 +isPVD(struct iso9660 *iso9660, const unsigned char *h)
 +{
 +	const unsigned char *p;
 +	ssize_t logical_block_size;
 +	int32_t volume_block;
 +	int32_t location;
 +	int i;
 +
 +	/* Type of the Primary Volume Descriptor must be 1. */
 +	if (h[PVD_type_offset] != 1)
 +		return (0);
 +
 +	/* PVD version must be 1. */
 +	if (h[PVD_version_offset] != 1)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	if (h[PVD_reserved1_offset] != 0)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
- 	for (i = 0; i < PVD_reserved2_size; ++i)
- 		if (h[PVD_reserved2_offset + i] != 0)
- 			return (0);
++	if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
++		return (0);
 +
 +	/* Reserved field must be 0. */
- 	for (i = 0; i < PVD_reserved3_size; ++i)
- 		if (h[PVD_reserved3_offset + i] != 0)
- 			return (0);
++	if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
++		return (0);
 +
 +	/* Logical block size must be > 0. */
 +	/* I've looked at Ecma 119 and can't find any stronger
 +	 * restriction on this field. */
 +	logical_block_size =
 +	    archive_le16dec(h + PVD_logical_block_size_offset);
 +	if (logical_block_size <= 0)
 +		return (0);
 +
 +	volume_block = archive_le32dec(h + PVD_volume_space_size_offset);
 +	if (volume_block <= SYSTEM_AREA_BLOCK+4)
 +		return (0);
 +
 +	/* File structure version must be 1 for ISO9660/ECMA119. */
 +	if (h[PVD_file_structure_version_offset] != 1)
 +		return (0);
 +
 +	/* Location of Occurrence of Type L Path Table must be
 +	 * available location,
 +	 * > SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_le32dec(h+PVD_type_1_path_table_offset);
 +	if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)
 +		return (0);
 +
 +	/* The Type M Path Table must also be at a valid location
 +	 * (although ECMA 119 requires a Type M Path Table, WinISO and
 +	 * probably other programs omit it, so we permit a zero here)
 +	 *
 +	 * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
 +	location = archive_be32dec(h+PVD_type_m_path_table_offset);
 +	if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)
 +	    || location >= volume_block)
 +		return (0);
 +
 +	/* Reserved field must be 0. */
 +	/* But accept NetBSD/FreeBSD "makefs" images with 0x20 here. */
 +	for (i = 0; i < PVD_reserved4_size; ++i)
 +		if (h[PVD_reserved4_offset + i] != 0
 +		    && h[PVD_reserved4_offset + i] != 0x20)
 +			return (0);
 +
 +	/* Reserved field must be 0. */
- 	for (i = 0; i < PVD_reserved5_size; ++i)
- 		if (h[PVD_reserved5_offset + i] != 0)
- 			return (0);
++	if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
++		return (0);
 +
 +	/* XXX TODO: Check other values for sanity; reject more
 +	 * malformed PVDs. XXX */
 +
 +	/* Read Root Directory Record in Volume Descriptor. */
 +	p = h + PVD_root_directory_record_offset;
 +	if (p[DR_length_offset] != 34)
 +		return (0);
 +
 +	if (!iso9660->primary.location) {
 +		iso9660->logical_block_size = logical_block_size;
 +		iso9660->volume_block = volume_block;
- 		iso9660->volume_size = logical_block_size * (uint64_t)volume_block;
- 		iso9660->primary.location = archive_le32dec(p + DR_extent_offset);
++		iso9660->volume_size =
++		    logical_block_size * (uint64_t)volume_block;
++		iso9660->primary.location =
++		    archive_le32dec(p + DR_extent_offset);
 +		iso9660->primary.size = archive_le32dec(p + DR_size_offset);
 +	}
 +
 +	return (48);
 +}
 +
 +static int
 +read_children(struct archive_read *a, struct file_info *parent)
 +{
 +	struct iso9660 *iso9660;
 +	const unsigned char *b, *p;
 +	struct file_info *multi;
 +	size_t step, skip_size;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
++	/* flush any remaining bytes from the last round to ensure
++	 * we're positioned */
++	if (iso9660->entry_bytes_unconsumed) {
++		__archive_read_consume(a, iso9660->entry_bytes_unconsumed);
++		iso9660->entry_bytes_unconsumed = 0;
++	}
 +	if (iso9660->current_position > parent->offset) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Ignoring out-of-order directory (%s) %jd > %jd",
 +		    parent->name.s,
 +		    (intmax_t)iso9660->current_position,
 +		    (intmax_t)parent->offset);
 +		return (ARCHIVE_WARN);
 +	}
 +	if (parent->offset + parent->size > iso9660->volume_size) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Directory is beyond end-of-media: %s",
 +		    parent->name.s);
 +		return (ARCHIVE_WARN);
 +	}
 +	if (iso9660->current_position < parent->offset) {
 +		int64_t skipsize;
 +
 +		skipsize = parent->offset - iso9660->current_position;
 +		skipsize = __archive_read_consume(a, skipsize);
 +		if (skipsize < 0)
 +			return ((int)skipsize);
 +		iso9660->current_position = parent->offset;
 +	}
 +
- 	step = ((parent->size + iso9660->logical_block_size -1) /
- 	    iso9660->logical_block_size) * iso9660->logical_block_size;
++	step = (size_t)(((parent->size + iso9660->logical_block_size -1) /
++	    iso9660->logical_block_size) * iso9660->logical_block_size);
 +	b = __archive_read_ahead(a, step, NULL);
 +	if (b == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Failed to read full block when scanning "
 +		    "ISO9660 directory list");
 +		return (ARCHIVE_FATAL);
 +	}
 +	iso9660->current_position += step;
 +	multi = NULL;
 +	skip_size = step;
 +	while (step) {
 +		p = b;
 +		b += iso9660->logical_block_size;
 +		step -= iso9660->logical_block_size;
 +		for (; *p != 0 && p < b && p + *p <= b; p += *p) {
 +			struct file_info *child;
 +
 +			/* N.B.: these special directory identifiers
 +			 * are 8 bit "values" even on a
 +			 * Joliet CD with UCS-2 (16bit) encoding.
 +			 */
 +
 +			/* Skip '.' entry. */
 +			if (*(p + DR_name_len_offset) == 1
 +			    && *(p + DR_name_offset) == '\0')
 +				continue;
 +			/* Skip '..' entry. */
 +			if (*(p + DR_name_len_offset) == 1
 +			    && *(p + DR_name_offset) == '\001')
 +				continue;
 +			child = parse_file_info(a, parent, p);
 +			if (child == NULL) {
 +				__archive_read_consume(a, skip_size);
 +				return (ARCHIVE_FATAL);
 +			}
 +			if (child->cl_offset == 0 &&
 +			    (child->multi_extent || multi != NULL)) {
 +				struct content *con;
 +
 +				if (multi == NULL) {
 +					multi = child;
 +					multi->contents.first = NULL;
 +					multi->contents.last =
 +					    &(multi->contents.first);
 +				}
 +				con = malloc(sizeof(struct content));
 +				if (con == NULL) {
 +					archive_set_error(
 +					    &a->archive, ENOMEM,
 +					    "No memory for multi extent");
 +					__archive_read_consume(a, skip_size);
 +					return (ARCHIVE_FATAL);
 +				}
 +				con->offset = child->offset;
 +				con->size = child->size;
 +				con->next = NULL;
 +				*multi->contents.last = con;
 +				multi->contents.last = &(con->next);
 +				if (multi == child) {
 +					if (add_entry(a, iso9660, child)
 +					    != ARCHIVE_OK)
 +						return (ARCHIVE_FATAL);
 +				} else {
 +					multi->size += child->size;
 +					if (!child->multi_extent)
 +						multi = NULL;
 +				}
 +			} else
 +				if (add_entry(a, iso9660, child) != ARCHIVE_OK)
 +					return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	__archive_read_consume(a, skip_size);
 +
 +	/* Read data which recorded by RRIP "CE" extension. */
 +	if (read_CE(a, iso9660) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
- archive_read_format_iso9660_read_header(struct archive_read *a,
-     struct archive_entry *entry)
++choose_volume(struct archive_read *a, struct iso9660 *iso9660)
 +{
- 	struct iso9660 *iso9660;
 +	struct file_info *file;
- 	int r, rd_r = ARCHIVE_OK;
- 
- 	iso9660 = (struct iso9660 *)(a->format->data);
++	int64_t skipsize;
++	struct vd *vd;
++	const void *block;
++	char seenJoliet;
 +
- 	if (!a->archive.archive_format) {
- 		a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
- 		a->archive.archive_format_name = "ISO9660";
++	vd = &(iso9660->primary);
++	if (!iso9660->opt_support_joliet)
++		iso9660->seenJoliet = 0;
++	if (iso9660->seenJoliet &&
++		vd->location > iso9660->joliet.location)
++		/* This condition is unlikely; by way of caution. */
++		vd = &(iso9660->joliet);
++
++	skipsize = LOGICAL_BLOCK_SIZE * vd->location;
++	skipsize = __archive_read_consume(a, skipsize);
++	if (skipsize < 0)
++		return ((int)skipsize);
++	iso9660->current_position = skipsize;
++
++	block = __archive_read_ahead(a, vd->size, NULL);
++	if (block == NULL) {
++		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++		    "Failed to read full block when scanning "
++		    "ISO9660 directory list");
++		return (ARCHIVE_FATAL);
 +	}
 +
- 	if (iso9660->current_position == 0) {
- 		int64_t skipsize;
- 		struct vd *vd;
- 		const void *block;
- 		char seenJoliet;
- 
- 		vd = &(iso9660->primary);
- 		if (!iso9660->opt_support_joliet)
- 			iso9660->seenJoliet = 0;
- 		if (iso9660->seenJoliet &&
- 			vd->location > iso9660->joliet.location)
- 			/* This condition is unlikely; by way of caution. */
- 			vd = &(iso9660->joliet);
++	/*
++	 * While reading Root Directory, flag seenJoliet must be zero to
++	 * avoid converting special name 0x00(Current Directory) and
++	 * next byte to UCS2.
++	 */
++	seenJoliet = iso9660->seenJoliet;/* Save flag. */
++	iso9660->seenJoliet = 0;
++	file = parse_file_info(a, NULL, block);
++	if (file == NULL)
++		return (ARCHIVE_FATAL);
++	iso9660->seenJoliet = seenJoliet;
 +
++	/*
++	 * If the iso image has both RockRidge and Joliet, we preferentially
++	 * use RockRidge Extensions rather than Joliet ones.
++	 */
++	if (vd == &(iso9660->primary) && iso9660->seenRockridge
++	    && iso9660->seenJoliet)
++		iso9660->seenJoliet = 0;
++
++	if (vd == &(iso9660->primary) && !iso9660->seenRockridge
++	    && iso9660->seenJoliet) {
++		/* Switch reading data from primary to joliet. */
++		vd = &(iso9660->joliet);
 +		skipsize = LOGICAL_BLOCK_SIZE * vd->location;
++		skipsize -= iso9660->current_position;
 +		skipsize = __archive_read_consume(a, skipsize);
 +		if (skipsize < 0)
 +			return ((int)skipsize);
- 		iso9660->current_position = skipsize;
++		iso9660->current_position += skipsize;
 +
 +		block = __archive_read_ahead(a, vd->size, NULL);
 +		if (block == NULL) {
- 			archive_set_error(&a->archive,
- 			    ARCHIVE_ERRNO_MISC,
++			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Failed to read full block when scanning "
 +			    "ISO9660 directory list");
 +			return (ARCHIVE_FATAL);
 +		}
- 
- 		/*
- 		 * While reading Root Directory, flag seenJoliet
- 		 * must be zero to avoid converting special name
- 		 * 0x00(Current Directory) and next byte to UCS2.
- 		 */
- 		seenJoliet = iso9660->seenJoliet;/* Save flag. */
 +		iso9660->seenJoliet = 0;
 +		file = parse_file_info(a, NULL, block);
 +		if (file == NULL)
 +			return (ARCHIVE_FATAL);
 +		iso9660->seenJoliet = seenJoliet;
- 		if (vd == &(iso9660->primary) && iso9660->seenRockridge
- 		    && iso9660->seenJoliet)
- 			/*
- 			 * If iso image has RockRidge and Joliet,
- 			 * we use RockRidge Extensions.
- 			 */
- 			iso9660->seenJoliet = 0;
- 		if (vd == &(iso9660->primary) && !iso9660->seenRockridge
- 		    && iso9660->seenJoliet) {
- 			/* Switch reading data from primary to joliet. */ 
- 			vd = &(iso9660->joliet);
- 			skipsize = LOGICAL_BLOCK_SIZE * vd->location;
- 			skipsize -= iso9660->current_position;
- 			skipsize = __archive_read_consume(a, skipsize);
- 			if (skipsize < 0)
- 				return ((int)skipsize);
- 			iso9660->current_position += skipsize;
- 
- 			block = __archive_read_ahead(a, vd->size, NULL);
- 			if (block == NULL) {
- 				archive_set_error(&a->archive,
- 				    ARCHIVE_ERRNO_MISC,
- 				    "Failed to read full block when scanning "
- 				    "ISO9660 directory list");
- 				return (ARCHIVE_FATAL);
- 			}
- 			iso9660->seenJoliet = 0;
- 			file = parse_file_info(a, NULL, block);
- 			if (file == NULL)
- 				return (ARCHIVE_FATAL);
- 			iso9660->seenJoliet = seenJoliet;
- 		}
- 		/* Store the root directory in the pending list. */
- 		if (add_entry(a, iso9660, file) != ARCHIVE_OK)
- 			return (ARCHIVE_FATAL);
- 		if (iso9660->seenRockridge) {
- 			a->archive.archive_format =
- 			    ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
- 			a->archive.archive_format_name =
- 			    "ISO9660 with Rockridge extensions";
- 		}
++	}
++
++	/* Store the root directory in the pending list. */
++	if (add_entry(a, iso9660, file) != ARCHIVE_OK)
++		return (ARCHIVE_FATAL);
++	if (iso9660->seenRockridge) {
++		a->archive.archive_format = ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
++		a->archive.archive_format_name =
++		    "ISO9660 with Rockridge extensions";
++	}
++
++	return (ARCHIVE_OK);
++}
++
++static int
++archive_read_format_iso9660_read_header(struct archive_read *a,
++    struct archive_entry *entry)
++{
++	struct iso9660 *iso9660;
++	struct file_info *file;
++	int r, rd_r = ARCHIVE_OK;
++
++	iso9660 = (struct iso9660 *)(a->format->data);
++
++	if (!a->archive.archive_format) {
++		a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
++		a->archive.archive_format_name = "ISO9660";
++	}
++
++	if (iso9660->current_position == 0) {
++		r = choose_volume(a, iso9660);
++		if (r != ARCHIVE_OK)
++			return (r);
 +	}
 +
 +	file = NULL;/* Eliminate a warning. */
 +	/* Get the next entry that appears after the current offset. */
 +	r = next_entry_seek(a, iso9660, &file);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +
 +	if (iso9660->seenJoliet) {
 +		/*
 +		 * Convert UTF-16BE of a filename to local locale MBS
 +		 * and store the result into a filename field.
 +		 */
 +		if (iso9660->sconv_utf16be == NULL) {
 +			iso9660->sconv_utf16be =
 +			    archive_string_conversion_from_charset(
 +				&(a->archive), "UTF-16BE", 1);
 +			if (iso9660->sconv_utf16be == NULL)
 +				/* Coundn't allocate memory */
 +				return (ARCHIVE_FATAL);
 +		}
 +		if (iso9660->utf16be_path == NULL) {
 +			iso9660->utf16be_path = malloc(UTF16_NAME_MAX);
 +			if (iso9660->utf16be_path == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory");
 +				return (ARCHIVE_FATAL);
 +			}
 +		}
 +		if (iso9660->utf16be_previous_path == NULL) {
 +			iso9660->utf16be_previous_path = malloc(UTF16_NAME_MAX);
 +			if (iso9660->utf16be_previous_path == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory");
 +				return (ARCHIVE_FATAL);
 +			}
 +		}
 +
 +		iso9660->utf16be_path_len = 0;
 +		if (build_pathname_utf16be(iso9660->utf16be_path,
 +		    UTF16_NAME_MAX, &(iso9660->utf16be_path_len), file) != 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Pathname is too long");
 +		}
 +
 +		r = archive_entry_copy_pathname_l(entry,
 +		    (const char *)iso9660->utf16be_path,
 +		    iso9660->utf16be_path_len,
 +		    iso9660->sconv_utf16be);
 +		if (r != 0) {
 +			if (errno == ENOMEM) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory for Pathname");
 +				return (ARCHIVE_FATAL);
 +			}
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Pathname cannot be converted "
 +			    "from %s to current locale.",
 +			    archive_string_conversion_charset_name(
 +			      iso9660->sconv_utf16be));
 +
 +			rd_r = ARCHIVE_WARN;
 +		}
 +	} else {
 +		archive_string_empty(&iso9660->pathname);
 +		archive_entry_set_pathname(entry,
 +		    build_pathname(&iso9660->pathname, file));
 +	}
 +
 +	iso9660->entry_bytes_remaining = file->size;
- 	iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */
++	/* Offset for sparse-file-aware clients. */
++	iso9660->entry_sparse_offset = 0;
 +
 +	if (file->offset + file->size > iso9660->volume_size) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "File is beyond end-of-media: %s",
 +		    archive_entry_pathname(entry));
 +		iso9660->entry_bytes_remaining = 0;
- 		iso9660->entry_sparse_offset = 0;
 +		return (ARCHIVE_WARN);
 +	}
 +
 +	/* Set up the entry structure with information about this entry. */
 +	archive_entry_set_mode(entry, file->mode);
 +	archive_entry_set_uid(entry, file->uid);
 +	archive_entry_set_gid(entry, file->gid);
 +	archive_entry_set_nlink(entry, file->nlinks);
 +	if (file->birthtime_is_set)
 +		archive_entry_set_birthtime(entry, file->birthtime, 0);
 +	else
 +		archive_entry_unset_birthtime(entry);
 +	archive_entry_set_mtime(entry, file->mtime, 0);
 +	archive_entry_set_ctime(entry, file->ctime, 0);
 +	archive_entry_set_atime(entry, file->atime, 0);
 +	/* N.B.: Rock Ridge supports 64-bit device numbers. */
 +	archive_entry_set_rdev(entry, (dev_t)file->rdev);
 +	archive_entry_set_size(entry, iso9660->entry_bytes_remaining);
 +	if (file->symlink.s != NULL)
 +		archive_entry_copy_symlink(entry, file->symlink.s);
 +
 +	/* Note: If the input isn't seekable, we can't rewind to
 +	 * return the same body again, so if the next entry refers to
 +	 * the same data, we have to return it as a hardlink to the
 +	 * original entry. */
 +	if (file->number != -1 &&
 +	    file->number == iso9660->previous_number) {
 +		if (iso9660->seenJoliet) {
 +			r = archive_entry_copy_hardlink_l(entry,
 +			    (const char *)iso9660->utf16be_previous_path,
 +			    iso9660->utf16be_previous_path_len,
 +			    iso9660->sconv_utf16be);
 +			if (r != 0) {
 +				if (errno == ENOMEM) {
 +					archive_set_error(&a->archive, ENOMEM,
 +					    "No memory for Linkname");
 +					return (ARCHIVE_FATAL);
 +				}
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_FILE_FORMAT,
 +				    "Linkname cannot be converted "
 +				    "from %s to current locale.",
 +				    archive_string_conversion_charset_name(
 +				      iso9660->sconv_utf16be));
 +				rd_r = ARCHIVE_WARN;
 +			}
 +		} else
 +			archive_entry_set_hardlink(entry,
 +			    iso9660->previous_pathname.s);
 +		archive_entry_unset_size(entry);
 +		iso9660->entry_bytes_remaining = 0;
- 		iso9660->entry_sparse_offset = 0;
 +		return (rd_r);
 +	}
 +
- 	/* Except for the hardlink case above, if the offset of the
- 	 * next entry is before our current position, we can't seek
- 	 * backwards to extract it, so issue a warning.  Note that
- 	 * this can only happen if this entry was added to the heap
- 	 * after we passed this offset, that is, only if the directory
- 	 * mentioning this entry is later than the body of the entry.
- 	 * Such layouts are very unusual; most ISO9660 writers lay out
- 	 * and record all directory information first, then store
- 	 * all file bodies. */
- 	/* TODO: Someday, libarchive's I/O core will support optional
- 	 * seeking.  When that day comes, this code should attempt to
- 	 * seek and only return the error if the seek fails.  That
- 	 * will give us support for whacky ISO images that require
- 	 * seeking while retaining the ability to read almost all ISO
- 	 * images in a streaming fashion. */
 +	if ((file->mode & AE_IFMT) != AE_IFDIR &&
 +	    file->offset < iso9660->current_position) {
- 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- 		    "Ignoring out-of-order file @%jx (%s) %jd < %jd",
- 		    (intmax_t)file->number,
- 		    iso9660->pathname.s,
- 		    (intmax_t)file->offset,
- 		    (intmax_t)iso9660->current_position);
- 		iso9660->entry_bytes_remaining = 0;
- 		iso9660->entry_sparse_offset = 0;
- 		return (ARCHIVE_WARN);
++		int64_t r64;
++
++		r64 = __archive_read_seek(a, file->offset, SEEK_SET);
++		if (r64 != (int64_t)file->offset) {
++			/* We can't seek backwards to extract it, so issue
++			 * a warning.  Note that this can only happen if
++			 * this entry was added to the heap after we passed
++			 * this offset, that is, only if the directory
++			 * mentioning this entry is later than the body of
++			 * the entry. Such layouts are very unusual; most
++			 * ISO9660 writers lay out and record all directory
++			 * information first, then store all file bodies. */
++			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++			    "Ignoring out-of-order file @%jx (%s) %jd < %jd",
++			    (intmax_t)file->number,
++			    iso9660->pathname.s,
++			    (intmax_t)file->offset,
++			    (intmax_t)iso9660->current_position);
++			iso9660->entry_bytes_remaining = 0;
++			return (ARCHIVE_WARN);
++		}
++		iso9660->current_position = (uint64_t)r64;
 +	}
 +
 +	/* Initialize zisofs variables. */
 +	iso9660->entry_zisofs.pz = file->pz;
 +	if (file->pz) {
 +#ifdef HAVE_ZLIB_H
 +		struct zisofs  *zisofs;
 +
 +		zisofs = &iso9660->entry_zisofs;
 +		zisofs->initialized = 0;
 +		zisofs->pz_log2_bs = file->pz_log2_bs;
 +		zisofs->pz_uncompressed_size = file->pz_uncompressed_size;
 +		zisofs->pz_offset = 0;
 +		zisofs->header_avail = 0;
 +		zisofs->header_passed = 0;
 +		zisofs->block_pointers_avail = 0;
 +#endif
 +		archive_entry_set_size(entry, file->pz_uncompressed_size);
 +	}
 +
 +	iso9660->previous_number = file->number;
 +	if (iso9660->seenJoliet) {
 +		memcpy(iso9660->utf16be_previous_path, iso9660->utf16be_path,
 +		    iso9660->utf16be_path_len);
 +		iso9660->utf16be_previous_path_len = iso9660->utf16be_path_len;
 +	} else
 +		archive_strcpy(
 +		    &iso9660->previous_pathname, iso9660->pathname.s);
 +
 +	/* Reset entry_bytes_remaining if the file is multi extent. */
 +	iso9660->entry_content = file->contents.first;
 +	if (iso9660->entry_content != NULL)
 +		iso9660->entry_bytes_remaining = iso9660->entry_content->size;
 +
 +	if (archive_entry_filetype(entry) == AE_IFDIR) {
 +		/* Overwrite nlinks by proper link number which is
 +		 * calculated from number of sub directories. */
 +		archive_entry_set_nlink(entry, 2 + file->subdirs);
 +		/* Directory data has been read completely. */
 +		iso9660->entry_bytes_remaining = 0;
- 		iso9660->entry_sparse_offset = 0;
 +	}
 +
 +	if (rd_r != ARCHIVE_OK)
 +		return (rd_r);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_read_format_iso9660_read_data_skip(struct archive_read *a)
 +{
 +	/* Because read_next_header always does an explicit skip
 +	 * to the next entry, we don't need to do anything here. */
 +	(void)a; /* UNUSED */
 +	return (ARCHIVE_OK);
 +}
 +
 +#ifdef HAVE_ZLIB_H
 +
 +static int
 +zisofs_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	struct iso9660 *iso9660;
 +	struct zisofs  *zisofs;
 +	const unsigned char *p;
 +	size_t avail;
 +	ssize_t bytes_read;
 +	size_t uncompressed_size;
 +	int r;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +	zisofs = &iso9660->entry_zisofs;
 +
 +	p = __archive_read_ahead(a, 1, &bytes_read);
 +	if (bytes_read <= 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated zisofs file body");
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (bytes_read > iso9660->entry_bytes_remaining)
- 		bytes_read = iso9660->entry_bytes_remaining;
++		bytes_read = (ssize_t)iso9660->entry_bytes_remaining;
 +	avail = bytes_read;
 +	uncompressed_size = 0;
 +
 +	if (!zisofs->initialized) {
 +		size_t ceil, xsize;
 +
 +		/* Allocate block pointers buffer. */
- 		ceil = (zisofs->pz_uncompressed_size +
++		ceil = (size_t)((zisofs->pz_uncompressed_size +
 +			(((int64_t)1) << zisofs->pz_log2_bs) - 1)
- 			>> zisofs->pz_log2_bs;
++			>> zisofs->pz_log2_bs);
 +		xsize = (ceil + 1) * 4;
 +		if (zisofs->block_pointers_alloc < xsize) {
 +			size_t alloc;
 +
 +			if (zisofs->block_pointers != NULL)
 +				free(zisofs->block_pointers);
 +			alloc = ((xsize >> 10) + 1) << 10;
 +			zisofs->block_pointers = malloc(alloc);
 +			if (zisofs->block_pointers == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory for zisofs decompression");
 +				return (ARCHIVE_FATAL);
 +			}
 +			zisofs->block_pointers_alloc = alloc;
 +		}
 +		zisofs->block_pointers_size = xsize;
 +
 +		/* Allocate uncompressed data buffer. */
- 		xsize = 1UL << zisofs->pz_log2_bs;
++		xsize = (size_t)1UL << zisofs->pz_log2_bs;
 +		if (zisofs->uncompressed_buffer_size < xsize) {
 +			if (zisofs->uncompressed_buffer != NULL)
 +				free(zisofs->uncompressed_buffer);
 +			zisofs->uncompressed_buffer = malloc(xsize);
 +			if (zisofs->uncompressed_buffer == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "No memory for zisofs decompression");
 +				return (ARCHIVE_FATAL);
 +			}
 +		}
 +		zisofs->uncompressed_buffer_size = xsize;
 +
 +		/*
 +		 * Read the file header, and check the magic code of zisofs.
 +		 */
 +		if (zisofs->header_avail < sizeof(zisofs->header)) {
 +			xsize = sizeof(zisofs->header) - zisofs->header_avail;
 +			if (avail < xsize)
 +				xsize = avail;
 +			memcpy(zisofs->header + zisofs->header_avail, p, xsize);
 +			zisofs->header_avail += xsize;
 +			avail -= xsize;
 +			p += xsize;
 +		}
 +		if (!zisofs->header_passed &&
 +		    zisofs->header_avail == sizeof(zisofs->header)) {
 +			int err = 0;
 +
 +			if (memcmp(zisofs->header, zisofs_magic,
 +			    sizeof(zisofs_magic)) != 0)
 +				err = 1;
 +			if (archive_le32dec(zisofs->header + 8)
 +			    != zisofs->pz_uncompressed_size)
 +				err = 1;
 +			if (zisofs->header[12] != 4)
 +				err = 1;
 +			if (zisofs->header[13] != zisofs->pz_log2_bs)
 +				err = 1;
 +			if (err) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_FILE_FORMAT,
 +				    "Illegal zisofs file body");
 +				return (ARCHIVE_FATAL);
 +			}
 +			zisofs->header_passed = 1;
 +		}
 +		/*
 +		 * Read block pointers.
 +		 */
 +		if (zisofs->header_passed &&
 +		    zisofs->block_pointers_avail < zisofs->block_pointers_size) {
 +			xsize = zisofs->block_pointers_size
 +			    - zisofs->block_pointers_avail;
 +			if (avail < xsize)
 +				xsize = avail;
 +			memcpy(zisofs->block_pointers
 +			    + zisofs->block_pointers_avail, p, xsize);
 +			zisofs->block_pointers_avail += xsize;
 +			avail -= xsize;
 +			p += xsize;
 +		    	if (zisofs->block_pointers_avail
 +			    == zisofs->block_pointers_size) {
 +				/* We've got all block pointers and initialize
 +				 * related variables.	*/
 +				zisofs->block_off = 0;
 +				zisofs->block_avail = 0;
 +				/* Complete a initialization */
 +				zisofs->initialized = 1;
 +			}
 +		}
 +
 +		if (!zisofs->initialized)
 +			goto next_data; /* We need more data. */
 +	}
 +
 +	/*
 +	 * Get block offsets from block pointers.
 +	 */
 +	if (zisofs->block_avail == 0) {
 +		uint32_t bst, bed;
 +
 +		if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {
 +			/* There isn't a pair of offsets. */
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs block pointers");
 +			return (ARCHIVE_FATAL);
 +		}
 +		bst = archive_le32dec(
 +		    zisofs->block_pointers + zisofs->block_off);
 +		if (bst != zisofs->pz_offset + (bytes_read - avail)) {
 +			/* TODO: Should we seek offset of current file
 +			 * by bst ? */
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs block pointers(cannot seek)");
 +			return (ARCHIVE_FATAL);
 +		}
 +		bed = archive_le32dec(
 +		    zisofs->block_pointers + zisofs->block_off + 4);
 +		if (bed < bst) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs block pointers");
 +			return (ARCHIVE_FATAL);
 +		}
 +		zisofs->block_avail = bed - bst;
 +		zisofs->block_off += 4;
 +
 +		/* Initialize compression library for new block. */
 +		if (zisofs->stream_valid)
 +			r = inflateReset(&zisofs->stream);
 +		else
 +			r = inflateInit(&zisofs->stream);
 +		if (r != Z_OK) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Can't initialize zisofs decompression.");
 +			return (ARCHIVE_FATAL);
 +		}
 +		zisofs->stream_valid = 1;
 +		zisofs->stream.total_in = 0;
 +		zisofs->stream.total_out = 0;
 +	}
 +
 +	/*
 +	 * Make uncompressed data.
 +	 */
 +	if (zisofs->block_avail == 0) {
 +		memset(zisofs->uncompressed_buffer, 0,
 +		    zisofs->uncompressed_buffer_size);
 +		uncompressed_size = zisofs->uncompressed_buffer_size;
 +	} else {
 +		zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;
 +		if (avail > zisofs->block_avail)
 +			zisofs->stream.avail_in = zisofs->block_avail;
 +		else
- 			zisofs->stream.avail_in = avail;
++			zisofs->stream.avail_in = (uInt)avail;
 +		zisofs->stream.next_out = zisofs->uncompressed_buffer;
- 		zisofs->stream.avail_out = zisofs->uncompressed_buffer_size;
++		zisofs->stream.avail_out =
++		    (uInt)zisofs->uncompressed_buffer_size;
 +
 +		r = inflate(&zisofs->stream, 0);
 +		switch (r) {
 +		case Z_OK: /* Decompressor made some progress.*/
 +		case Z_STREAM_END: /* Found end of stream. */
 +			break;
 +		default:
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "zisofs decompression failed (%d)", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		uncompressed_size =
 +		    zisofs->uncompressed_buffer_size - zisofs->stream.avail_out;
 +		avail -= zisofs->stream.next_in - p;
- 		zisofs->block_avail -= zisofs->stream.next_in - p;
++		zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);
 +	}
 +next_data:
 +	bytes_read -= avail;
 +	*buff = zisofs->uncompressed_buffer;
 +	*size = uncompressed_size;
 +	*offset = iso9660->entry_sparse_offset;
 +	iso9660->entry_sparse_offset += uncompressed_size;
 +	iso9660->entry_bytes_remaining -= bytes_read;
 +	iso9660->current_position += bytes_read;
- 	zisofs->pz_offset += bytes_read;
++	zisofs->pz_offset += (uint32_t)bytes_read;
 +	iso9660->entry_bytes_unconsumed += bytes_read;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +#else /* HAVE_ZLIB_H */
 +
 +static int
 +zisofs_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +
 +	(void)buff;/* UNUSED */
 +	(void)size;/* UNUSED */
 +	(void)offset;/* UNUSED */
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +	    "zisofs is not supported on this platform.");
 +	return (ARCHIVE_FAILED);
 +}
 +
 +#endif /* HAVE_ZLIB_H */
 +
 +static int
 +archive_read_format_iso9660_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	ssize_t bytes_read;
 +	struct iso9660 *iso9660;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	if (iso9660->entry_bytes_unconsumed) {
 +		__archive_read_consume(a, iso9660->entry_bytes_unconsumed);
 +		iso9660->entry_bytes_unconsumed = 0;
 +	}
 +
 +	if (iso9660->entry_bytes_remaining <= 0) {
 +		if (iso9660->entry_content != NULL)
 +			iso9660->entry_content = iso9660->entry_content->next;
 +		if (iso9660->entry_content == NULL) {
 +			*buff = NULL;
 +			*size = 0;
 +			*offset = iso9660->entry_sparse_offset;
 +			return (ARCHIVE_EOF);
 +		}
 +		/* Seek forward to the start of the entry. */
 +		if (iso9660->current_position < iso9660->entry_content->offset) {
 +			int64_t step;
 +
 +			step = iso9660->entry_content->offset -
 +			    iso9660->current_position;
 +			step = __archive_read_consume(a, step);
 +			if (step < 0)
 +				return ((int)step);
 +			iso9660->current_position =
 +			    iso9660->entry_content->offset;
 +		}
 +		if (iso9660->entry_content->offset < iso9660->current_position) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Ignoring out-of-order file (%s) %jd < %jd",
 +			    iso9660->pathname.s,
 +			    (intmax_t)iso9660->entry_content->offset,
 +			    (intmax_t)iso9660->current_position);
 +			*buff = NULL;
 +			*size = 0;
 +			*offset = iso9660->entry_sparse_offset;
 +			return (ARCHIVE_WARN);
 +		}
 +		iso9660->entry_bytes_remaining = iso9660->entry_content->size;
 +	}
 +	if (iso9660->entry_zisofs.pz)
 +		return (zisofs_read_data(a, buff, size, offset));
 +
 +	*buff = __archive_read_ahead(a, 1, &bytes_read);
 +	if (bytes_read == 0)
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Truncated input file");
 +	if (*buff == NULL)
 +		return (ARCHIVE_FATAL);
 +	if (bytes_read > iso9660->entry_bytes_remaining)
- 		bytes_read = iso9660->entry_bytes_remaining;
++		bytes_read = (ssize_t)iso9660->entry_bytes_remaining;
 +	*size = bytes_read;
 +	*offset = iso9660->entry_sparse_offset;
 +	iso9660->entry_sparse_offset += bytes_read;
 +	iso9660->entry_bytes_remaining -= bytes_read;
 +	iso9660->entry_bytes_unconsumed = bytes_read;
 +	iso9660->current_position += bytes_read;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_read_format_iso9660_cleanup(struct archive_read *a)
 +{
 +	struct iso9660 *iso9660;
 +	int r = ARCHIVE_OK;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +	release_files(iso9660);
 +	free(iso9660->read_ce_req.reqs);
 +	archive_string_free(&iso9660->pathname);
 +	archive_string_free(&iso9660->previous_pathname);
 +	if (iso9660->pending_files.files)
 +		free(iso9660->pending_files.files);
 +#ifdef HAVE_ZLIB_H
 +	free(iso9660->entry_zisofs.uncompressed_buffer);
 +	free(iso9660->entry_zisofs.block_pointers);
 +	if (iso9660->entry_zisofs.stream_valid) {
 +		if (inflateEnd(&iso9660->entry_zisofs.stream) != Z_OK) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Failed to clean up zlib decompressor");
 +			r = ARCHIVE_FATAL;
 +		}
 +	}
 +#endif
 +	free(iso9660->utf16be_path);
 +	free(iso9660->utf16be_previous_path);
 +	free(iso9660);
 +	(a->format->data) = NULL;
 +	return (r);
 +}
 +
 +/*
 + * This routine parses a single ISO directory record, makes sense
 + * of any extensions, and stores the result in memory.
 + */
 +static struct file_info *
 +parse_file_info(struct archive_read *a, struct file_info *parent,
 +    const unsigned char *isodirrec)
 +{
 +	struct iso9660 *iso9660;
 +	struct file_info *file;
 +	size_t name_len;
 +	const unsigned char *rr_start, *rr_end;
 +	const unsigned char *p;
 +	size_t dr_len;
 +	uint64_t fsize;
 +	int32_t location;
 +	int flags;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	dr_len = (size_t)isodirrec[DR_length_offset];
 +	name_len = (size_t)isodirrec[DR_name_len_offset];
 +	location = archive_le32dec(isodirrec + DR_extent_offset);
 +	fsize = toi(isodirrec + DR_size_offset, DR_size_size);
 +	/* Sanity check that dr_len needs at least 34. */
 +	if (dr_len < 34) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid length of directory record");
 +		return (NULL);
 +	}
 +	/* Sanity check that name_len doesn't exceed dr_len. */
 +	if (dr_len - 33 < name_len || name_len == 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid length of file identifier");
 +		return (NULL);
 +	}
 +	/* Sanity check that location doesn't exceed volume block.
 +	 * Don't check lower limit of location; it's possibility
 +	 * the location has negative value when file type is symbolic
 +	 * link or file size is zero. As far as I know latest mkisofs
 +	 * do that.
 +	 */
 +	if (location > 0 &&
 +	    (location + ((fsize + iso9660->logical_block_size -1)
- 	       / iso9660->logical_block_size)) > iso9660->volume_block) {
++	       / iso9660->logical_block_size))
++			> (uint32_t)iso9660->volume_block) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid location of extent of file");
 +		return (NULL);
 +	}
 +	/* Sanity check that location doesn't have a negative value
 +	 * when the file is not empty. it's too large. */
 +	if (fsize != 0 && location < 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid location of extent of file");
 +		return (NULL);
 +	}
 +
 +	/* Create a new file entry and copy data from the ISO dir record. */
 +	file = (struct file_info *)calloc(1, sizeof(*file));
 +	if (file == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "No memory for file entry");
 +		return (NULL);
 +	}
 +	file->parent = parent;
 +	file->offset = iso9660->logical_block_size * (uint64_t)location;
 +	file->size = fsize;
 +	file->mtime = isodate7(isodirrec + DR_date_offset);
 +	file->ctime = file->atime = file->mtime;
 +	file->rede_files.first = NULL;
 +	file->rede_files.last = &(file->rede_files.first);
 +
 +	p = isodirrec + DR_name_offset;
 +	/* Rockridge extensions (if any) follow name.  Compute this
 +	 * before fidgeting the name_len below. */
 +	rr_start = p + name_len + (name_len & 1 ? 0 : 1);
 +	rr_end = isodirrec + dr_len;
 +
 +	if (iso9660->seenJoliet) {
 +		/* Joliet names are max 64 chars (128 bytes) according to spec,
 +		 * but genisoimage/mkisofs allows recording longer Joliet
 +		 * names which are 103 UCS2 characters(206 bytes) by their
 +		 * option '-joliet-long'.
 +		 */
 +		if (name_len > 206)
 +			name_len = 206;
 +		name_len &= ~1;
 +
 +		/* trim trailing first version and dot from filename.
 +		 *
 +		 * Remember we were in UTF-16BE land!
 +		 * SEPARATOR 1 (.) and SEPARATOR 2 (;) are both
 +		 * 16 bits big endian characters on Joliet.
 +		 *
 +		 * TODO: sanitize filename?
 +		 *       Joliet allows any UCS-2 char except:
 +		 *       *, /, :, ;, ? and \.
 +		 */
 +		/* Chop off trailing ';1' from files. */
 +		if (name_len > 4 && p[name_len-4] == 0 && p[name_len-3] == ';'
 +		    && p[name_len-2] == 0 && p[name_len-1] == '1')
 +			name_len -= 4;
 +#if 0 /* XXX: this somehow manages to strip of single-character file extensions, like '.c'. */
 +		/* Chop off trailing '.' from filenames. */
 +		if (name_len > 2 && p[name_len-2] == 0 && p[name_len-1] == '.')
 +			name_len -= 2;
 +#endif
 +		if ((file->utf16be_name = malloc(name_len)) == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "No memory for file name");
 +			return (NULL);
 +		}
 +		memcpy(file->utf16be_name, p, name_len);
 +		file->utf16be_bytes = name_len;
 +	} else {
 +		/* Chop off trailing ';1' from files. */
 +		if (name_len > 2 && p[name_len - 2] == ';' &&
 +				p[name_len - 1] == '1')
 +			name_len -= 2;
 +		/* Chop off trailing '.' from filenames. */
 +		if (name_len > 1 && p[name_len - 1] == '.')
 +			--name_len;
 +
 +		archive_strncpy(&file->name, (const char *)p, name_len);
 +	}
 +
 +	flags = isodirrec[DR_flags_offset];
 +	if (flags & 0x02)
 +		file->mode = AE_IFDIR | 0700;
 +	else
 +		file->mode = AE_IFREG | 0400;
 +	if (flags & 0x80)
 +		file->multi_extent = 1;
 +	else
 +		file->multi_extent = 0;
 +	/*
 +	 * Use a location for the file number, which is treated as an inode
 +	 * number to find out hardlink target. If Rockridge extensions is
 +	 * being used, the file number will be overwritten by FILE SERIAL
 +	 * NUMBER of RRIP "PX" extension.
 +	 * Note: Old mkisofs did not record that FILE SERIAL NUMBER
 +	 * in ISO images.
 +	 * Note2: xorriso set 0 to the location of a symlink file. 
 +	 */
 +	if (file->size == 0 && location >= 0) {
 +		/* If file->size is zero, its location points wrong place,
 +		 * and so we should not use it for the file number.
 +		 * When the location has negative value, it can be used
 +		 * for the file number.
 +		 */
 +		file->number = -1;
 +		/* Do not appear before any directory entries. */
 +		file->offset = -1;
 +	} else
 +		file->number = (int64_t)(uint32_t)location;
 +
 +	/* Rockridge extensions overwrite information from above. */
 +	if (iso9660->opt_support_rockridge) {
 +		if (parent == NULL && rr_end - rr_start >= 7) {
 +			p = rr_start;
- 			if (p[0] == 'S' && p[1] == 'P'
- 			    && p[2] == 7 && p[3] == 1
- 			    && p[4] == 0xBE && p[5] == 0xEF) {
++			if (memcmp(p, "SP\x07\x01\xbe\xef", 6) == 0) {
 +				/*
 +				 * SP extension stores the suspOffset
 +				 * (Number of bytes to skip between
 +				 * filename and SUSP records.)
 +				 * It is mandatory by the SUSP standard
 +				 * (IEEE 1281).
 +				 *
 +				 * It allows SUSP to coexist with
 +				 * non-SUSP uses of the System
 +				 * Use Area by placing non-SUSP data
 +				 * before SUSP data.
 +				 *
 +				 * SP extension must be in the root
 +				 * directory entry, disable all SUSP
 +				 * processing if not found.
 +				 */
 +				iso9660->suspOffset = p[6];
 +				iso9660->seenSUSP = 1;
 +				rr_start += 7;
 +			}
 +		}
 +		if (iso9660->seenSUSP) {
 +			int r;
 +
 +			file->name_continues = 0;
 +			file->symlink_continues = 0;
 +			rr_start += iso9660->suspOffset;
 +			r = parse_rockridge(a, file, rr_start, rr_end);
 +			if (r != ARCHIVE_OK) {
 +				free(file);
 +				return (NULL);
 +			}
++			/*
++			 * A file size of symbolic link files in ISO images
++			 * made by makefs is not zero and its location is
++			 * the same as those of next regular file. That is
++			 * the same as hard like file and it causes unexpected
++			 * error. 
++			 */
++			if (file->size > 0 &&
++			    (file->mode & AE_IFMT) == AE_IFLNK) {
++				file->size = 0;
++				file->number = -1;
++				file->offset = -1;
++			}
 +		} else
 +			/* If there isn't SUSP, disable parsing
 +			 * rock ridge extensions. */
 +			iso9660->opt_support_rockridge = 0;
 +	}
 +
 +	file->nlinks = 1;/* Reset nlink. we'll calculate it later. */
 +	/* Tell file's parent how many children that parent has. */
 +	if (parent != NULL && (flags & 0x02))
 +		parent->subdirs++;
 +
 +	if (iso9660->seenRockridge) {
 +		if (parent != NULL && parent->parent == NULL &&
 +		    (flags & 0x02) && iso9660->rr_moved == NULL &&
++		    file->name.s &&
 +		    (strcmp(file->name.s, "rr_moved") == 0 ||
 +		     strcmp(file->name.s, ".rr_moved") == 0)) {
 +			iso9660->rr_moved = file;
 +			file->rr_moved = 1;
 +			file->rr_moved_has_re_only = 1;
 +			file->re = 0;
 +			parent->subdirs--;
 +		} else if (file->re) {
 +			/*
 +			 * Sanity check: file's parent is rr_moved.
 +			 */
 +			if (parent == NULL || parent->rr_moved == 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge RE");
 +				return (NULL);
 +			}
 +			/*
 +			 * Sanity check: file does not have "CL" extension.
 +			 */
 +			if (file->cl_offset) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge RE and CL");
 +				return (NULL);
 +			}
 +			/*
 +			 * Sanity check: The file type must be a directory.
 +			 */
 +			if ((flags & 0x02) == 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge RE");
 +				return (NULL);
 +			}
 +		} else if (parent != NULL && parent->rr_moved)
 +			file->rr_moved_has_re_only = 0;
 +		else if (parent != NULL && (flags & 0x02) &&
 +		    (parent->re || parent->re_descendant))
 +			file->re_descendant = 1;
 +		if (file->cl_offset) {
 +			struct file_info *r;
 +
 +			if (parent == NULL || parent->parent == NULL) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge CL");
 +				return (NULL);
 +			}
 +			/*
 +			 * Sanity check: The file type must be a regular file.
 +			 */
 +			if ((flags & 0x02) != 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge CL");
 +				return (NULL);
 +			}
 +			parent->subdirs++;
 +			/* Overwrite an offset and a number of this "CL" entry
 +			 * to appear before other dirs. "+1" to those is to
 +			 * make sure to appear after "RE" entry which this
 +			 * "CL" entry should be connected with. */
 +			file->offset = file->number = file->cl_offset + 1;
 +
 +			/*
 +			 * Sanity check: cl_offset does not point at its
 +			 * the parents or itself.
 +			 */
 +			for (r = parent; r; r = r->parent) {
 +				if (r->offset == file->cl_offset) {
 +					archive_set_error(&a->archive,
 +					    ARCHIVE_ERRNO_MISC,
 +					    "Invalid Rockridge CL");
 +					return (NULL);
 +				}
 +			}
 +			if (file->cl_offset == file->offset ||
 +			    parent->rr_moved) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Invalid Rockridge CL");
 +				return (NULL);
 +			}
 +		}
 +	}
 +
 +#if DEBUG
 +	/* DEBUGGING: Warn about attributes I don't yet fully support. */
 +	if ((flags & ~0x02) != 0) {
 +		fprintf(stderr, "\n ** Unrecognized flag: ");
 +		dump_isodirrec(stderr, isodirrec);
 +		fprintf(stderr, "\n");
 +	} else if (toi(isodirrec + DR_volume_sequence_number_offset, 2) != 1) {
 +		fprintf(stderr, "\n ** Unrecognized sequence number: ");
 +		dump_isodirrec(stderr, isodirrec);
 +		fprintf(stderr, "\n");
 +	} else if (*(isodirrec + DR_file_unit_size_offset) != 0) {
 +		fprintf(stderr, "\n ** Unexpected file unit size: ");
 +		dump_isodirrec(stderr, isodirrec);
 +		fprintf(stderr, "\n");
 +	} else if (*(isodirrec + DR_interleave_offset) != 0) {
 +		fprintf(stderr, "\n ** Unexpected interleave: ");
 +		dump_isodirrec(stderr, isodirrec);
 +		fprintf(stderr, "\n");
 +	} else if (*(isodirrec + DR_ext_attr_length_offset) != 0) {
 +		fprintf(stderr, "\n ** Unexpected extended attribute length: ");
 +		dump_isodirrec(stderr, isodirrec);
 +		fprintf(stderr, "\n");
 +	}
 +#endif
 +	register_file(iso9660, file);
 +	return (file);
 +}
 +
 +static int
 +parse_rockridge(struct archive_read *a, struct file_info *file,
 +    const unsigned char *p, const unsigned char *end)
 +{
 +	struct iso9660 *iso9660;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +
 +	while (p + 4 <= end  /* Enough space for another entry. */
 +	    && p[0] >= 'A' && p[0] <= 'Z' /* Sanity-check 1st char of name. */
 +	    && p[1] >= 'A' && p[1] <= 'Z' /* Sanity-check 2nd char of name. */
 +	    && p[2] >= 4 /* Sanity-check length. */
 +	    && p + p[2] <= end) { /* Sanity-check length. */
 +		const unsigned char *data = p + 4;
 +		int data_length = p[2] - 4;
 +		int version = p[3];
 +
- 		/*
- 		 * Yes, each 'if' here does test p[0] again.
- 		 * Otherwise, the fall-through handling to catch
- 		 * unsupported extensions doesn't work.
- 		 */
 +		switch(p[0]) {
 +		case 'C':
- 			if (p[0] == 'C' && p[1] == 'E') {
++			if (p[1] == 'E') {
 +				if (version == 1 && data_length == 24) {
 +					/*
 +					 * CE extension comprises:
 +					 *   8 byte sector containing extension
 +					 *   8 byte offset w/in above sector
 +					 *   8 byte length of continuation
 +					 */
 +					int32_t location =
 +					    archive_le32dec(data);
 +					file->ce_offset =
 +					    archive_le32dec(data+8);
 +					file->ce_size =
 +					    archive_le32dec(data+16);
 +					if (register_CE(a, location, file)
 +					    != ARCHIVE_OK)
 +						return (ARCHIVE_FATAL);
 +				}
- 				break;
 +			}
- 			if (p[0] == 'C' && p[1] == 'L') {
++			else if (p[1] == 'L') {
 +				if (version == 1 && data_length == 8) {
 +					file->cl_offset = (uint64_t)
 +					    iso9660->logical_block_size *
 +					    (uint64_t)archive_le32dec(data);
 +					iso9660->seenRockridge = 1;
 +				}
- 				break;
 +			}
- 			/* FALLTHROUGH */
++			break;
 +		case 'N':
- 			if (p[0] == 'N' && p[1] == 'M') {
++			if (p[1] == 'M') {
 +				if (version == 1) {
 +					parse_rockridge_NM1(file,
 +					    data, data_length);
 +					iso9660->seenRockridge = 1;
 +				}
- 				break;
 +			}
- 			/* FALLTHROUGH */
++			break;
 +		case 'P':
- 			if (p[0] == 'P' && p[1] == 'D') {
- 				/*
- 				 * PD extension is padding;
- 				 * contents are always ignored.
- 				 */
- 				break;
- 			}
- 			if (p[0] == 'P' && p[1] == 'L') {
- 				/*
- 				 * PL extension won't appear;
- 				 * contents are always ignored.
- 				 */
- 				break;
- 			}
- 			if (p[0] == 'P' && p[1] == 'N') {
++			/*
++			 * PD extension is padding;
++			 * contents are always ignored.
++			 *
++			 * PL extension won't appear;
++			 * contents are always ignored.
++			 */
++			if (p[1] == 'N') {
 +				if (version == 1 && data_length == 16) {
 +					file->rdev = toi(data,4);
 +					file->rdev <<= 32;
 +					file->rdev |= toi(data + 8, 4);
 +					iso9660->seenRockridge = 1;
 +				}
- 				break;
 +			}
- 			if (p[0] == 'P' && p[1] == 'X') {
++			else if (p[1] == 'X') {
 +				/*
 +				 * PX extension comprises:
 +				 *   8 bytes for mode,
 +				 *   8 bytes for nlinks,
 +				 *   8 bytes for uid,
 +				 *   8 bytes for gid,
 +				 *   8 bytes for inode.
 +				 */
 +				if (version == 1) {
 +					if (data_length >= 8)
 +						file->mode
 +						    = toi(data, 4);
 +					if (data_length >= 16)
 +						file->nlinks
 +						    = toi(data + 8, 4);
 +					if (data_length >= 24)
 +						file->uid
 +						    = toi(data + 16, 4);
 +					if (data_length >= 32)
 +						file->gid
 +						    = toi(data + 24, 4);
 +					if (data_length >= 40)
 +						file->number
 +						    = toi(data + 32, 4);
 +					iso9660->seenRockridge = 1;
 +				}
- 				break;
 +			}
- 			/* FALLTHROUGH */
++			break;
 +		case 'R':
- 			if (p[0] == 'R' && p[1] == 'E' && version == 1) {
++			if (p[1] == 'E' && version == 1) {
 +				file->re = 1;
 +				iso9660->seenRockridge = 1;
- 				break;
 +			}
- 			if (p[0] == 'R' && p[1] == 'R' && version == 1) {
++			else if (p[1] == 'R' && version == 1) {
 +				/*
 +				 * RR extension comprises:
 +				 *    one byte flag value
 +				 * This extension is obsolete,
 +				 * so contents are always ignored.
 +				 */
- 				break;
 +			}
- 			/* FALLTHROUGH */
++			break;
 +		case 'S':
- 			if (p[0] == 'S' && p[1] == 'L') {
++			if (p[1] == 'L') {
 +				if (version == 1) {
 +					parse_rockridge_SL1(file,
 +					    data, data_length);
 +					iso9660->seenRockridge = 1;
 +				}
- 				break;
 +			}
- 			if (p[0] == 'S' && p[1] == 'T'
++			else if (p[1] == 'T'
 +			    && data_length == 0 && version == 1) {
 +				/*
 +				 * ST extension marks end of this
 +				 * block of SUSP entries.
 +				 *
 +				 * It allows SUSP to coexist with
 +				 * non-SUSP uses of the System
 +				 * Use Area by placing non-SUSP data
 +				 * after SUSP data.
 +				 */
 +				iso9660->seenSUSP = 0;
 +				iso9660->seenRockridge = 0;
 +				return (ARCHIVE_OK);
 +			}
++			break;
 +		case 'T':
- 			if (p[0] == 'T' && p[1] == 'F') {
++			if (p[1] == 'F') {
 +				if (version == 1) {
 +					parse_rockridge_TF1(file,
 +					    data, data_length);
 +					iso9660->seenRockridge = 1;
 +				}
- 				break;
 +			}
- 			/* FALLTHROUGH */
++			break;
 +		case 'Z':
- 			if (p[0] == 'Z' && p[1] == 'F') {
++			if (p[1] == 'F') {
 +				if (version == 1)
 +					parse_rockridge_ZF1(file,
 +					    data, data_length);
- 				break;
 +			}
- 			/* FALLTHROUGH */
++			break;
 +		default:
- 			/* The FALLTHROUGHs above leave us here for
- 			 * any unsupported extension. */
 +			break;
 +		}
 +
- 
- 
 +		p += p[2];
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +register_CE(struct archive_read *a, int32_t location,
 +    struct file_info *file)
 +{
 +	struct iso9660 *iso9660;
 +	struct read_ce_queue *heap;
 +	struct read_ce_req *p;
 +	uint64_t offset, parent_offset;
 +	int hole, parent;
 +
 +	iso9660 = (struct iso9660 *)(a->format->data);
 +	offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size;
 +	if (((file->mode & AE_IFMT) == AE_IFREG &&
 +	    offset >= file->offset) ||
 +	    offset < iso9660->current_position ||
 +	    (((uint64_t)file->ce_offset) + file->ce_size)
- 	      > iso9660->logical_block_size ||
++	      > (uint64_t)iso9660->logical_block_size ||
 +	    offset + file->ce_offset + file->ce_size
 +		  > iso9660->volume_size) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid parameter in SUSP \"CE\" extension");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Expand our CE list as necessary. */
 +	heap = &(iso9660->read_ce_req);
 +	if (heap->cnt >= heap->allocated) {
 +		int new_size;
 +
 +		if (heap->allocated < 16)
 +			new_size = 16;
 +		else
 +			new_size = heap->allocated * 2;
 +		/* Overflow might keep us from growing the list. */
 +		if (new_size <= heap->allocated) {
 +			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
- 		p = malloc(new_size * sizeof(p[0]));
++		p = calloc(new_size, sizeof(p[0]));
 +		if (p == NULL) {
 +			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (heap->reqs != NULL) {
 +			memcpy(p, heap->reqs, heap->cnt * sizeof(*p));
 +			free(heap->reqs);
 +		}
 +		heap->reqs = p;
 +		heap->allocated = new_size;
 +	}
 +
 +	/*
 +	 * Start with hole at end, walk it up tree to find insertion point.
 +	 */
 +	hole = heap->cnt++;
 +	while (hole > 0) {
 +		parent = (hole - 1)/2;
 +		parent_offset = heap->reqs[parent].offset;
 +		if (offset >= parent_offset) {
 +			heap->reqs[hole].offset = offset;
 +			heap->reqs[hole].file = file;
 +			return (ARCHIVE_OK);
 +		}
 +		/* Move parent into hole <==> move hole up tree. */
 +		heap->reqs[hole] = heap->reqs[parent];
 +		hole = parent;
 +	}
 +	heap->reqs[0].offset = offset;
 +	heap->reqs[0].file = file;
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +next_CE(struct read_ce_queue *heap)
 +{
 +	uint64_t a_offset, b_offset, c_offset;
 +	int a, b, c;
 +	struct read_ce_req tmp;
 +
 +	if (heap->cnt < 1)
 +		return;
 +
 +	/*
 +	 * Move the last item in the heap to the root of the tree
 +	 */
 +	heap->reqs[0] = heap->reqs[--(heap->cnt)];
 +
 +	/*
 +	 * Rebalance the heap.
 +	 */
 +	a = 0; /* Starting element and its offset */
 +	a_offset = heap->reqs[a].offset;
 +	for (;;) {
 +		b = a + a + 1; /* First child */
 +		if (b >= heap->cnt)
 +			return;
 +		b_offset = heap->reqs[b].offset;
 +		c = b + 1; /* Use second child if it is smaller. */
 +		if (c < heap->cnt) {
 +			c_offset = heap->reqs[c].offset;
 +			if (c_offset < b_offset) {
 +				b = c;
 +				b_offset = c_offset;
 +			}
 +		}
 +		if (a_offset <= b_offset)
 +			return;
 +		tmp = heap->reqs[a];
 +		heap->reqs[a] = heap->reqs[b];
 +		heap->reqs[b] = tmp;
 +		a = b;
 +	}
 +}
 +
 +
 +static int
 +read_CE(struct archive_read *a, struct iso9660 *iso9660)
 +{
 +	struct read_ce_queue *heap;
 +	const unsigned char *b, *p, *end;
 +	struct file_info *file;
 +	size_t step;
 +	int r;
 +
 +	/* Read data which RRIP "CE" extension points. */
 +	heap = &(iso9660->read_ce_req);
 +	step = iso9660->logical_block_size;
 +	while (heap->cnt &&
 +	    heap->reqs[0].offset == iso9660->current_position) {
 +		b = __archive_read_ahead(a, step, NULL);
 +		if (b == NULL) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Failed to read full block when scanning "
 +			    "ISO9660 directory list");
 +			return (ARCHIVE_FATAL);
 +		}
 +		do {
 +			file = heap->reqs[0].file;
 +			if (file->ce_offset + file->ce_size > step) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_FILE_FORMAT,
 +				    "Malformed CE information");
 +				return (ARCHIVE_FATAL);
 +			}
 +			p = b + file->ce_offset;
 +			end = p + file->ce_size;
 +			next_CE(heap);
 +			r = parse_rockridge(a, file, p, end);
 +			if (r != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		} while (heap->cnt &&
 +		    heap->reqs[0].offset == iso9660->current_position);
 +		/* NOTE: Do not move this consume's code to fron of
 +		 * do-while loop. Registration of nested CE extension
 +		 * might cause error because of current position. */
 +		__archive_read_consume(a, step);
 +		iso9660->current_position += step;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +parse_rockridge_NM1(struct file_info *file,
 +		    const unsigned char *data, int data_length)
 +{
 +	if (!file->name_continues)
 +		archive_string_empty(&file->name);
 +	file->name_continues = 0;
 +	if (data_length < 1)
 +		return;
 +	/*
 +	 * NM version 1 extension comprises:
 +	 *   1 byte flag, value is one of:
 +	 *     = 0: remainder is name
 +	 *     = 1: remainder is name, next NM entry continues name
 +	 *     = 2: "."
 +	 *     = 4: ".."
 +	 *     = 32: Implementation specific
 +	 *     All other values are reserved.
 +	 */
 +	switch(data[0]) {
 +	case 0:
 +		if (data_length < 2)
 +			return;
 +		archive_strncat(&file->name,
 +		    (const char *)data + 1, data_length - 1);
 +		break;
 +	case 1:
 +		if (data_length < 2)
 +			return;
 +		archive_strncat(&file->name,
 +		    (const char *)data + 1, data_length - 1);
 +		file->name_continues = 1;
 +		break;
 +	case 2:
 +		archive_strcat(&file->name, ".");
 +		break;
 +	case 4:
 +		archive_strcat(&file->name, "..");
 +		break;
 +	default:
 +		return;
 +	}
 +
 +}
 +
 +static void
 +parse_rockridge_TF1(struct file_info *file, const unsigned char *data,
 +    int data_length)
 +{
 +	char flag;
 +	/*
 +	 * TF extension comprises:
 +	 *   one byte flag
 +	 *   create time (optional)
 +	 *   modify time (optional)
 +	 *   access time (optional)
 +	 *   attribute time (optional)
 +	 *  Time format and presence of fields
 +	 *  is controlled by flag bits.
 +	 */
 +	if (data_length < 1)
 +		return;
 +	flag = data[0];
 +	++data;
 +	--data_length;
 +	if (flag & 0x80) {
 +		/* Use 17-byte time format. */
 +		if ((flag & 1) && data_length >= 17) {
 +			/* Create time. */
 +			file->birthtime_is_set = 1;
 +			file->birthtime = isodate17(data);
 +			data += 17;
 +			data_length -= 17;
 +		}
 +		if ((flag & 2) && data_length >= 17) {
 +			/* Modify time. */
 +			file->mtime = isodate17(data);
 +			data += 17;
 +			data_length -= 17;
 +		}
 +		if ((flag & 4) && data_length >= 17) {
 +			/* Access time. */
 +			file->atime = isodate17(data);
 +			data += 17;
 +			data_length -= 17;
 +		}
 +		if ((flag & 8) && data_length >= 17) {
 +			/* Attribute change time. */
 +			file->ctime = isodate17(data);
 +		}
 +	} else {
 +		/* Use 7-byte time format. */
 +		if ((flag & 1) && data_length >= 7) {
 +			/* Create time. */
 +			file->birthtime_is_set = 1;
 +			file->birthtime = isodate7(data);
 +			data += 7;
 +			data_length -= 7;
 +		}
 +		if ((flag & 2) && data_length >= 7) {
 +			/* Modify time. */
 +			file->mtime = isodate7(data);
 +			data += 7;
 +			data_length -= 7;
 +		}
 +		if ((flag & 4) && data_length >= 7) {
 +			/* Access time. */
 +			file->atime = isodate7(data);
 +			data += 7;
 +			data_length -= 7;
 +		}
 +		if ((flag & 8) && data_length >= 7) {
 +			/* Attribute change time. */
 +			file->ctime = isodate7(data);
 +		}
 +	}
 +}
 +
 +static void
 +parse_rockridge_SL1(struct file_info *file, const unsigned char *data,
 +    int data_length)
 +{
 +	const char *separator = "";
 +
 +	if (!file->symlink_continues || file->symlink.length < 1)
 +		archive_string_empty(&file->symlink);
- 	else if (!file->symlink_continues &&
- 	    file->symlink.s[file->symlink.length - 1] != '/')
- 		separator = "/";
 +	file->symlink_continues = 0;
 +
 +	/*
 +	 * Defined flag values:
 +	 *  0: This is the last SL record for this symbolic link
 +	 *  1: this symbolic link field continues in next SL entry
 +	 *  All other values are reserved.
 +	 */
 +	if (data_length < 1)
 +		return;
 +	switch(*data) {
 +	case 0:
 +		break;
 +	case 1:
 +		file->symlink_continues = 1;
 +		break;
 +	default:
 +		return;
 +	}
 +	++data;  /* Skip flag byte. */
 +	--data_length;
 +
 +	/*
 +	 * SL extension body stores "components".
 +	 * Basically, this is a complicated way of storing
 +	 * a POSIX path.  It also interferes with using
 +	 * symlinks for storing non-path data. <sigh>
 +	 *
 +	 * Each component is 2 bytes (flag and length)
 +	 * possibly followed by name data.
 +	 */
 +	while (data_length >= 2) {
 +		unsigned char flag = *data++;
 +		unsigned char nlen = *data++;
 +		data_length -= 2;
 +
 +		archive_strcat(&file->symlink, separator);
 +		separator = "/";
 +
 +		switch(flag) {
 +		case 0: /* Usual case, this is text. */
 +			if (data_length < nlen)
 +				return;
 +			archive_strncat(&file->symlink,
 +			    (const char *)data, nlen);
 +			break;
 +		case 0x01: /* Text continues in next component. */
 +			if (data_length < nlen)
 +				return;
 +			archive_strncat(&file->symlink,
 +			    (const char *)data, nlen);
 +			separator = "";
 +			break;
 +		case 0x02: /* Current dir. */
 +			archive_strcat(&file->symlink, ".");
 +			break;
 +		case 0x04: /* Parent dir. */
 +			archive_strcat(&file->symlink, "..");
 +			break;
 +		case 0x08: /* Root of filesystem. */
 +			archive_strcat(&file->symlink, "/");
 +			separator = "";
 +			break;
 +		case 0x10: /* Undefined (historically "volume root" */
 +			archive_string_empty(&file->symlink);
 +			archive_strcat(&file->symlink, "ROOT");
 +			break;
 +		case 0x20: /* Undefined (historically "hostname") */
 +			archive_strcat(&file->symlink, "hostname");
 +			break;
 +		default:
 +			/* TODO: issue a warning ? */
 +			return;
 +		}
 +		data += nlen;
 +		data_length -= nlen;
 +	}
 +}
 +
 +static void
 +parse_rockridge_ZF1(struct file_info *file, const unsigned char *data,
 +    int data_length)
 +{
 +
 +	if (data[0] == 0x70 && data[1] == 0x7a && data_length == 12) {
 +		/* paged zlib */
 +		file->pz = 1;
 +		file->pz_log2_bs = data[3];
 +		file->pz_uncompressed_size = archive_le32dec(&data[4]);
 +	}
 +}
 +
 +static void
 +register_file(struct iso9660 *iso9660, struct file_info *file)
 +{
 +
 +	file->use_next = iso9660->use_files;
 +	iso9660->use_files = file;
 +}
 +
 +static void
 +release_files(struct iso9660 *iso9660)
 +{
 +	struct content *con, *connext;
 +	struct file_info *file;
 +
 +	file = iso9660->use_files;
 +	while (file != NULL) {
 +		struct file_info *next = file->use_next;
 +
 +		archive_string_free(&file->name);
 +		archive_string_free(&file->symlink);
 +		free(file->utf16be_name);
 +		con = file->contents.first;
 +		while (con != NULL) {
 +			connext = con->next;
 +			free(con);
 +			con = connext;
 +		}
 +		free(file);
 +		file = next;
 +	}
 +}
 +
 +static int
 +next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
 +    struct file_info **pfile)
 +{
 +	struct file_info *file;
 +	int r;
 +
 +	r = next_cache_entry(a, iso9660, pfile);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	file = *pfile;
 +
 +	/* Don't waste time seeking for zero-length bodies. */
 +	if (file->size == 0)
 +		file->offset = iso9660->current_position;
 +
 +	/* flush any remaining bytes from the last round to ensure
 +	 * we're positioned */
 +	if (iso9660->entry_bytes_unconsumed) {
 +		__archive_read_consume(a, iso9660->entry_bytes_unconsumed);
 +		iso9660->entry_bytes_unconsumed = 0;
 +	}
 +
 +	/* Seek forward to the start of the entry. */
 +	if (iso9660->current_position < file->offset) {
 +		int64_t step;
 +
 +		step = file->offset - iso9660->current_position;
 +		step = __archive_read_consume(a, step);
 +		if (step < 0)
 +			return ((int)step);
 +		iso9660->current_position = file->offset;
 +	}
 +
 +	/* We found body of file; handle it now. */
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,
 +    struct file_info **pfile)
 +{
 +	struct file_info *file;
 +	struct {
 +		struct file_info	*first;
 +		struct file_info	**last;
 +	}	empty_files;
 +	int64_t number;
 +	int count;
 +
 +	file = cache_get_entry(iso9660);
 +	if (file != NULL) {
 +		*pfile = file;
 +		return (ARCHIVE_OK);
 +	}
 +
 +	for (;;) {
 +		struct file_info *re, *d;
 +
 +		*pfile = file = next_entry(iso9660);
 +		if (file == NULL) {
 +			/*
 +			 * If directory entries all which are descendant of
 +			 * rr_moved are stil remaning, expose their. 
 +			 */
 +			if (iso9660->re_files.first != NULL && 
 +			    iso9660->rr_moved != NULL &&
 +			    iso9660->rr_moved->rr_moved_has_re_only)
 +				/* Expose "rr_moved" entry. */
 +				cache_add_entry(iso9660, iso9660->rr_moved);
 +			while ((re = re_get_entry(iso9660)) != NULL) {
 +				/* Expose its descendant dirs. */
 +				while ((d = rede_get_entry(re)) != NULL)
 +					cache_add_entry(iso9660, d);
 +			}
 +			if (iso9660->cache_files.first != NULL)
 +				return (next_cache_entry(a, iso9660, pfile));
 +			return (ARCHIVE_EOF);
 +		}
 +
 +		if (file->cl_offset) {
 +			struct file_info *first_re = NULL;
 +			int nexted_re = 0;
 +
 +			/*
 +			 * Find "RE" dir for the current file, which
 +			 * has "CL" flag.
 +			 */
 +			while ((re = re_get_entry(iso9660))
 +			    != first_re) {
 +				if (first_re == NULL)
 +					first_re = re;
 +				if (re->offset == file->cl_offset) {
 +					re->parent->subdirs--;
 +					re->parent = file->parent;
 +					re->re = 0;
 +					if (re->parent->re_descendant) {
 +						nexted_re = 1;
 +						re->re_descendant = 1;
 +						if (rede_add_entry(re) < 0)
 +							goto fatal_rr;
 +						/* Move a list of descendants
 +						 * to a new ancestor. */
 +						while ((d = rede_get_entry(
 +						    re)) != NULL)
 +							if (rede_add_entry(d)
 +							    < 0)
 +								goto fatal_rr;
 +						break;
 +					}
 +					/* Replace the current file
 +					 * with "RE" dir */
 +					*pfile = file = re;
 +					/* Expose its descendant */
 +					while ((d = rede_get_entry(
 +					    file)) != NULL)
 +						cache_add_entry(
 +						    iso9660, d);
 +					break;
 +				} else
 +					re_add_entry(iso9660, re);
 +			}
 +			if (nexted_re) {
 +				/*
 +				 * Do not expose this at this time
 +				 * because we have not gotten its full-path
 +				 * name yet.
 +				 */
 +				continue;
 +			}
 +		} else if ((file->mode & AE_IFMT) == AE_IFDIR) {
 +			int r;
 +
 +			/* Read file entries in this dir. */
 +			r = read_children(a, file);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +
 +			/*
 +			 * Handle a special dir of Rockridge extensions,
 +			 * "rr_moved".
 +			 */
 +			if (file->rr_moved) {
 +				/*
 +				 * If this has only the subdirectories which
 +				 * have "RE" flags, do not expose at this time.
 +				 */
 +				if (file->rr_moved_has_re_only)
 +					continue;
 +				/* Otherwise expose "rr_moved" entry. */
 +			} else if (file->re) {
 +				/*
 +				 * Do not expose this at this time
 +				 * because we have not gotten its full-path
 +				 * name yet.
 +				 */
 +				re_add_entry(iso9660, file);
 +				continue;
 +			} else if (file->re_descendant) {
 +				/*
 +				 * If the top level "RE" entry of this entry
 +				 * is not exposed, we, accordingly, should not
 +				 * expose this entry at this time because
 +				 * we cannot make its proper full-path name.
 +				 */
 +				if (rede_add_entry(file) == 0)
 +					continue;
 +				/* Otherwise we can expose this entry because
 +				 * it seems its top level "RE" has already been
 +				 * exposed. */
 +			}
 +		}
 +		break;
 +	}
 +
 +	if ((file->mode & AE_IFMT) != AE_IFREG || file->number == -1)
 +		return (ARCHIVE_OK);
 +
 +	count = 0;
 +	number = file->number;
 +	iso9660->cache_files.first = NULL;
 +	iso9660->cache_files.last = &(iso9660->cache_files.first);
 +	empty_files.first = NULL;
 +	empty_files.last = &empty_files.first;
 +	/* Collect files which has the same file serial number.
 +	 * Peek pending_files so that file which number is different
 +	 * is not put bak. */
 +	while (iso9660->pending_files.used > 0 &&
 +	    (iso9660->pending_files.files[0]->number == -1 ||
 +	     iso9660->pending_files.files[0]->number == number)) {
 +		if (file->number == -1) {
 +			/* This file has the same offset
 +			 * but it's wrong offset which empty files
 +			 * and symlink files have.
 +			 * NOTE: This wrong offse was recorded by
 +			 * old mkisofs utility. If ISO images is
 +			 * created by latest mkisofs, this does not
 +			 * happen.
 +			 */
 +			file->next = NULL;
 +			*empty_files.last = file;
 +			empty_files.last = &(file->next);
 +		} else {
 +			count++;
 +			cache_add_entry(iso9660, file);
 +		}
 +		file = next_entry(iso9660);
 +	}
 +
 +	if (count == 0) {
 +		*pfile = file;
 +		return ((file == NULL)?ARCHIVE_EOF:ARCHIVE_OK);
 +	}
 +	if (file->number == -1) {
 +		file->next = NULL;
 +		*empty_files.last = file;
 +		empty_files.last = &(file->next);
 +	} else {
 +		count++;
 +		cache_add_entry(iso9660, file);
 +	}
 +
 +	if (count > 1) {
 +		/* The count is the same as number of hardlink,
 +		 * so much so that each nlinks of files in cache_file
 +		 * is overwritten by value of the count.
 +		 */
 +		for (file = iso9660->cache_files.first;
 +		    file != NULL; file = file->next)
 +			file->nlinks = count;
 +	}
 +	/* If there are empty files, that files are added
 +	 * to the tail of the cache_files. */
 +	if (empty_files.first != NULL) {
 +		*iso9660->cache_files.last = empty_files.first;
 +		iso9660->cache_files.last = empty_files.last;
 +	}
 +	*pfile = cache_get_entry(iso9660);
 +	return ((*pfile == NULL)?ARCHIVE_EOF:ARCHIVE_OK);
 +
 +fatal_rr:
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- 	    "Failed to connect 'CL' pointer to 'RE' rr_moved pointer of"
- 	    "Rockridge extensions");
++	    "Failed to connect 'CL' pointer to 'RE' rr_moved pointer of "
++	    "Rockridge extensions: current position = %jd, CL offset = %jd",
++	    (intmax_t)iso9660->current_position, (intmax_t)file->cl_offset);
 +	return (ARCHIVE_FATAL);
 +}
 +
 +static inline void
 +re_add_entry(struct iso9660 *iso9660, struct file_info *file)
 +{
 +	file->re_next = NULL;
 +	*iso9660->re_files.last = file;
 +	iso9660->re_files.last = &(file->re_next);
 +}
 +
 +static inline struct file_info *
 +re_get_entry(struct iso9660 *iso9660)
 +{
 +	struct file_info *file;
 +
 +	if ((file = iso9660->re_files.first) != NULL) {
 +		iso9660->re_files.first = file->re_next;
 +		if (iso9660->re_files.first == NULL)
 +			iso9660->re_files.last =
 +			    &(iso9660->re_files.first);
 +	}
 +	return (file);
 +}
 +
 +static inline int
 +rede_add_entry(struct file_info *file)
 +{
 +	struct file_info *re;
 +
 +	/*
 +	 * Find "RE" entry.
 +	 */
 +	re = file->parent;
 +	while (re != NULL && !re->re)
 +		re = re->parent;
 +	if (re == NULL)
 +		return (-1);
 +
 +	file->re_next = NULL;
 +	*re->rede_files.last = file;
 +	re->rede_files.last = &(file->re_next);
 +	return (0);
 +}
 +
 +static inline struct file_info *
 +rede_get_entry(struct file_info *re)
 +{
 +	struct file_info *file;
 +
 +	if ((file = re->rede_files.first) != NULL) {
 +		re->rede_files.first = file->re_next;
 +		if (re->rede_files.first == NULL)
 +			re->rede_files.last =
 +			    &(re->rede_files.first);
 +	}
 +	return (file);
 +}
 +
 +static inline void
 +cache_add_entry(struct iso9660 *iso9660, struct file_info *file)
 +{
 +	file->next = NULL;
 +	*iso9660->cache_files.last = file;
 +	iso9660->cache_files.last = &(file->next);
 +}
 +
 +static inline struct file_info *
 +cache_get_entry(struct iso9660 *iso9660)
 +{
 +	struct file_info *file;
 +
 +	if ((file = iso9660->cache_files.first) != NULL) {
 +		iso9660->cache_files.first = file->next;
 +		if (iso9660->cache_files.first == NULL)
 +			iso9660->cache_files.last =
 +			    &(iso9660->cache_files.first);
 +	}
 +	return (file);
 +}
 +
 +static int
 +heap_add_entry(struct archive_read *a, struct heap_queue *heap,
 +    struct file_info *file, uint64_t key)
 +{
 +	uint64_t file_key, parent_key;
 +	int hole, parent;
 +
 +	/* Expand our pending files list as necessary. */
 +	if (heap->used >= heap->allocated) {
 +		struct file_info **new_pending_files;
 +		int new_size = heap->allocated * 2;
 +
 +		if (heap->allocated < 1024)
 +			new_size = 1024;
 +		/* Overflow might keep us from growing the list. */
 +		if (new_size <= heap->allocated) {
 +			archive_set_error(&a->archive,
 +			    ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		new_pending_files = (struct file_info **)
 +		    malloc(new_size * sizeof(new_pending_files[0]));
 +		if (new_pending_files == NULL) {
 +			archive_set_error(&a->archive,
 +			    ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		memcpy(new_pending_files, heap->files,
 +		    heap->allocated * sizeof(new_pending_files[0]));
 +		if (heap->files != NULL)
 +			free(heap->files);
 +		heap->files = new_pending_files;
 +		heap->allocated = new_size;
 +	}
 +
 +	file_key = file->key = key;
 +
 +	/*
 +	 * Start with hole at end, walk it up tree to find insertion point.
 +	 */
 +	hole = heap->used++;
 +	while (hole > 0) {
 +		parent = (hole - 1)/2;
 +		parent_key = heap->files[parent]->key;
 +		if (file_key >= parent_key) {
 +			heap->files[hole] = file;
 +			return (ARCHIVE_OK);
 +		}
 +		/* Move parent into hole <==> move hole up tree. */
 +		heap->files[hole] = heap->files[parent];
 +		hole = parent;
 +	}
 +	heap->files[0] = file;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static struct file_info *
 +heap_get_entry(struct heap_queue *heap)
 +{
 +	uint64_t a_key, b_key, c_key;
 +	int a, b, c;
 +	struct file_info *r, *tmp;
 +
 +	if (heap->used < 1)
 +		return (NULL);
 +
 +	/*
 +	 * The first file in the list is the earliest; we'll return this.
 +	 */
 +	r = heap->files[0];
 +
 +	/*
 +	 * Move the last item in the heap to the root of the tree
 +	 */
 +	heap->files[0] = heap->files[--(heap->used)];
 +
 +	/*
 +	 * Rebalance the heap.
 +	 */
 +	a = 0; /* Starting element and its heap key */
 +	a_key = heap->files[a]->key;
 +	for (;;) {
 +		b = a + a + 1; /* First child */
 +		if (b >= heap->used)
 +			return (r);
 +		b_key = heap->files[b]->key;
 +		c = b + 1; /* Use second child if it is smaller. */
 +		if (c < heap->used) {
 +			c_key = heap->files[c]->key;
 +			if (c_key < b_key) {
 +				b = c;
 +				b_key = c_key;
 +			}
 +		}
 +		if (a_key <= b_key)
 +			return (r);
 +		tmp = heap->files[a];
 +		heap->files[a] = heap->files[b];
 +		heap->files[b] = tmp;
 +		a = b;
 +	}
 +}
 +
 +static unsigned int
 +toi(const void *p, int n)
 +{
 +	const unsigned char *v = (const unsigned char *)p;
 +	if (n > 1)
 +		return v[0] + 256 * toi(v + 1, n - 1);
 +	if (n == 1)
 +		return v[0];
 +	return (0);
 +}
 +
 +static time_t
 +isodate7(const unsigned char *v)
 +{
 +	struct tm tm;
 +	int offset;
++	time_t t;
++
 +	memset(&tm, 0, sizeof(tm));
 +	tm.tm_year = v[0];
 +	tm.tm_mon = v[1] - 1;
 +	tm.tm_mday = v[2];
 +	tm.tm_hour = v[3];
 +	tm.tm_min = v[4];
 +	tm.tm_sec = v[5];
 +	/* v[6] is the signed timezone offset, in 1/4-hour increments. */
 +	offset = ((const signed char *)v)[6];
 +	if (offset > -48 && offset < 52) {
 +		tm.tm_hour -= offset / 4;
 +		tm.tm_min -= (offset % 4) * 15;
 +	}
- 	return (time_from_tm(&tm));
++	t = time_from_tm(&tm);
++	if (t == (time_t)-1)
++		return ((time_t)0);
++	return (t);
 +}
 +
 +static time_t
 +isodate17(const unsigned char *v)
 +{
 +	struct tm tm;
 +	int offset;
++	time_t t;
++
 +	memset(&tm, 0, sizeof(tm));
 +	tm.tm_year = (v[0] - '0') * 1000 + (v[1] - '0') * 100
 +	    + (v[2] - '0') * 10 + (v[3] - '0')
 +	    - 1900;
 +	tm.tm_mon = (v[4] - '0') * 10 + (v[5] - '0');
 +	tm.tm_mday = (v[6] - '0') * 10 + (v[7] - '0');
 +	tm.tm_hour = (v[8] - '0') * 10 + (v[9] - '0');
 +	tm.tm_min = (v[10] - '0') * 10 + (v[11] - '0');
 +	tm.tm_sec = (v[12] - '0') * 10 + (v[13] - '0');
 +	/* v[16] is the signed timezone offset, in 1/4-hour increments. */
 +	offset = ((const signed char *)v)[16];
 +	if (offset > -48 && offset < 52) {
 +		tm.tm_hour -= offset / 4;
 +		tm.tm_min -= (offset % 4) * 15;
 +	}
- 	return (time_from_tm(&tm));
++	t = time_from_tm(&tm);
++	if (t == (time_t)-1)
++		return ((time_t)0);
++	return (t);
 +}
 +
 +static time_t
 +time_from_tm(struct tm *t)
 +{
 +#if HAVE_TIMEGM
 +	/* Use platform timegm() if available. */
 +	return (timegm(t));
 +#elif HAVE__MKGMTIME64
 +	return (_mkgmtime64(t));
 +#else
 +	/* Else use direct calculation using POSIX assumptions. */
 +	/* First, fix up tm_yday based on the year/month/day. */
- 	mktime(t);
++	if (mktime(t) == (time_t)-1)
++		return ((time_t)-1);
 +	/* Then we can compute timegm() from first principles. */
 +	return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600
 +	    + t->tm_yday * 86400 + (t->tm_year - 70) * 31536000
 +	    + ((t->tm_year - 69) / 4) * 86400 -
 +	    ((t->tm_year - 1) / 100) * 86400
 +	    + ((t->tm_year + 299) / 400) * 86400);
 +#endif
 +}
 +
 +static const char *
 +build_pathname(struct archive_string *as, struct file_info *file)
 +{
 +	if (file->parent != NULL && archive_strlen(&file->parent->name) > 0) {
 +		build_pathname(as, file->parent);
 +		archive_strcat(as, "/");
 +	}
 +	if (archive_strlen(&file->name) == 0)
 +		archive_strcat(as, ".");
 +	else
 +		archive_string_concat(as, &file->name);
 +	return (as->s);
 +}
 +
 +static int
 +build_pathname_utf16be(unsigned char *p, size_t max, size_t *len,
 +    struct file_info *file)
 +{
 +	if (file->parent != NULL && file->parent->utf16be_bytes > 0) {
 +		if (build_pathname_utf16be(p, max, len, file->parent) != 0)
 +			return (-1);
 +		p[*len] = 0;
 +		p[*len + 1] = '/';
 +		*len += 2;
 +	}
 +	if (file->utf16be_bytes == 0) {
 +		if (*len + 2 > max)
 +			return (-1);/* Path is too long! */
 +		p[*len] = 0;
 +		p[*len + 1] = '.';
 +		*len += 2;
 +	} else {
 +		if (*len + file->utf16be_bytes > max)
 +			return (-1);/* Path is too long! */
 +		memcpy(p + *len, file->utf16be_name, file->utf16be_bytes);
 +		*len += file->utf16be_bytes;
 +	}
 +	return (0);
 +}
 +
 +#if DEBUG
 +static void
 +dump_isodirrec(FILE *out, const unsigned char *isodirrec)
 +{
 +	fprintf(out, " l %d,",
 +	    toi(isodirrec + DR_length_offset, DR_length_size));
 +	fprintf(out, " a %d,",
 +	    toi(isodirrec + DR_ext_attr_length_offset, DR_ext_attr_length_size));
 +	fprintf(out, " ext 0x%x,",
 +	    toi(isodirrec + DR_extent_offset, DR_extent_size));
 +	fprintf(out, " s %d,",
 +	    toi(isodirrec + DR_size_offset, DR_extent_size));
 +	fprintf(out, " f 0x%x,",
 +	    toi(isodirrec + DR_flags_offset, DR_flags_size));
 +	fprintf(out, " u %d,",
 +	    toi(isodirrec + DR_file_unit_size_offset, DR_file_unit_size_size));
 +	fprintf(out, " ilv %d,",
 +	    toi(isodirrec + DR_interleave_offset, DR_interleave_size));
 +	fprintf(out, " seq %d,",
- 	    toi(isodirrec + DR_volume_sequence_number_offset, DR_volume_sequence_number_size));
++	    toi(isodirrec + DR_volume_sequence_number_offset,
++		DR_volume_sequence_number_size));
 +	fprintf(out, " nl %d:",
 +	    toi(isodirrec + DR_name_len_offset, DR_name_len_size));
 +	fprintf(out, " `%.*s'",
- 	    toi(isodirrec + DR_name_len_offset, DR_name_len_size), isodirrec + DR_name_offset);
++	    toi(isodirrec + DR_name_len_offset, DR_name_len_size),
++		isodirrec + DR_name_offset);
 +}
 +#endif
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
index d5a8d86,0000000..dc1563d
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
@@@ -1,2574 -1,0 +1,2858 @@@
 +/*-
 +* Copyright (c) 2003-2007 Tim Kientzle
 +* Copyright (c) 2011 Andres Mejia
 +* All rights reserved.
 +*
 +* Redistribution and use in source and binary forms, with or without
 +* modification, are permitted provided that the following conditions
 +* are met:
 +* 1. Redistributions of source code must retain the above copyright
 +*    notice, this list of conditions and the following disclaimer.
 +* 2. Redistributions in binary form must reproduce the above copyright
 +*    notice, this list of conditions and the following disclaimer in the
 +*    documentation and/or other materials provided with the distribution.
 +*
 +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 +* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 +*/
 +
 +#include "archive_platform.h"
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#include <time.h>
 +#include <limits.h>
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h> /* crc32 */
 +#endif
 +
 +#include "archive.h"
 +#ifndef HAVE_ZLIB_H
 +#include "archive_crc32.h"
 +#endif
 +#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_ppmd7_private.h"
 +#include "archive_private.h"
 +#include "archive_read_private.h"
 +
 +/* RAR signature, also known as the mark header */
 +#define RAR_SIGNATURE "\x52\x61\x72\x21\x1A\x07\x00"
 +
 +/* Header types */
 +#define MARK_HEAD    0x72
 +#define MAIN_HEAD    0x73
 +#define FILE_HEAD    0x74
 +#define COMM_HEAD    0x75
 +#define AV_HEAD      0x76
 +#define SUB_HEAD     0x77
 +#define PROTECT_HEAD 0x78
 +#define SIGN_HEAD    0x79
 +#define NEWSUB_HEAD  0x7a
 +#define ENDARC_HEAD  0x7b
 +
 +/* Main Header Flags */
 +#define MHD_VOLUME       0x0001
 +#define MHD_COMMENT      0x0002
 +#define MHD_LOCK         0x0004
 +#define MHD_SOLID        0x0008
 +#define MHD_NEWNUMBERING 0x0010
 +#define MHD_AV           0x0020
 +#define MHD_PROTECT      0x0040
 +#define MHD_PASSWORD     0x0080
 +#define MHD_FIRSTVOLUME  0x0100
 +#define MHD_ENCRYPTVER   0x0200
 +
 +/* Flags common to all headers */
 +#define HD_MARKDELETION     0x4000
 +#define HD_ADD_SIZE_PRESENT 0x8000
 +
 +/* File Header Flags */
 +#define FHD_SPLIT_BEFORE 0x0001
 +#define FHD_SPLIT_AFTER  0x0002
 +#define FHD_PASSWORD     0x0004
 +#define FHD_COMMENT      0x0008
 +#define FHD_SOLID        0x0010
 +#define FHD_LARGE        0x0100
 +#define FHD_UNICODE      0x0200
 +#define FHD_SALT         0x0400
 +#define FHD_VERSION      0x0800
 +#define FHD_EXTTIME      0x1000
 +#define FHD_EXTFLAGS     0x2000
 +
 +/* File dictionary sizes */
 +#define DICTIONARY_SIZE_64   0x00
 +#define DICTIONARY_SIZE_128  0x20
 +#define DICTIONARY_SIZE_256  0x40
 +#define DICTIONARY_SIZE_512  0x60
 +#define DICTIONARY_SIZE_1024 0x80
 +#define DICTIONARY_SIZE_2048 0xA0
 +#define DICTIONARY_SIZE_4096 0xC0
 +#define FILE_IS_DIRECTORY    0xE0
 +#define DICTIONARY_MASK      FILE_IS_DIRECTORY
 +
 +/* OS Flags */
 +#define OS_MSDOS  0
 +#define OS_OS2    1
 +#define OS_WIN32  2
 +#define OS_UNIX   3
 +#define OS_MAC_OS 4
 +#define OS_BEOS   5
 +
 +/* Compression Methods */
 +#define COMPRESS_METHOD_STORE   0x30
 +/* LZSS */
 +#define COMPRESS_METHOD_FASTEST 0x31
 +#define COMPRESS_METHOD_FAST    0x32
 +#define COMPRESS_METHOD_NORMAL  0x33
 +/* PPMd Variant H */
 +#define COMPRESS_METHOD_GOOD    0x34
 +#define COMPRESS_METHOD_BEST    0x35
 +
 +#define CRC_POLYNOMIAL 0xEDB88320
 +
 +#define NS_UNIT 10000000
 +
 +#define DICTIONARY_MAX_SIZE 0x400000
 +
 +#define MAINCODE_SIZE      299
 +#define OFFSETCODE_SIZE    60
 +#define LOWOFFSETCODE_SIZE 17
 +#define LENGTHCODE_SIZE    28
 +#define HUFFMAN_TABLE_SIZE \
 +  MAINCODE_SIZE + OFFSETCODE_SIZE + LOWOFFSETCODE_SIZE + LENGTHCODE_SIZE
 +
 +#define MAX_SYMBOL_LENGTH 0xF
 +#define MAX_SYMBOLS       20
 +
 +/*
-  * Considering L1,L2 cache miss and a calling of write sytem-call,
++ * Considering L1,L2 cache miss and a calling of write system-call,
 + * the best size of the output buffer(uncompressed buffer) is 128K.
 + * If the structure of extracting process is changed, this value
 + * might be researched again.
 + */
 +#define UNP_BUFFER_SIZE   (128 * 1024)
 +
 +/* Define this here for non-Windows platforms */
 +#if !((defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__))
 +#define FILE_ATTRIBUTE_DIRECTORY 0x10
 +#endif
 +
 +/* Fields common to all headers */
 +struct rar_header
 +{
 +  char crc[2];
 +  char type;
 +  char flags[2];
 +  char size[2];
 +};
 +
 +/* Fields common to all file headers */
 +struct rar_file_header
 +{
 +  char pack_size[4];
 +  char unp_size[4];
 +  char host_os;
 +  char file_crc[4];
 +  char file_time[4];
 +  char unp_ver;
 +  char method;
 +  char name_size[2];
 +  char file_attr[4];
 +};
 +
 +struct huffman_tree_node
 +{
 +  int branches[2];
 +};
 +
 +struct huffman_table_entry
 +{
 +  unsigned int length;
 +  int value;
 +};
 +
 +struct huffman_code
 +{
 +  struct huffman_tree_node *tree;
 +  int numentries;
 +  int minlength;
 +  int maxlength;
 +  int tablesize;
 +  struct huffman_table_entry *table;
 +};
 +
 +struct lzss
 +{
 +  unsigned char *window;
 +  int mask;
 +  int64_t position;
 +};
 +
++struct data_block_offsets
++{
++  int64_t header_size;
++  int64_t start_offset;
++  int64_t end_offset;
++};
++
 +struct rar
 +{
 +  /* Entries from main RAR header */
 +  unsigned main_flags;
 +  unsigned long file_crc;
 +  char reserved1[2];
 +  char reserved2[4];
 +  char encryptver;
 +
 +  /* File header entries */
 +  char compression_method;
 +  unsigned file_flags;
 +  int64_t packed_size;
 +  int64_t unp_size;
 +  time_t mtime;
 +  long mnsec;
 +  mode_t mode;
 +  char *filename;
++  char *filename_save;
 +  size_t filename_allocated;
 +
 +  /* File header optional entries */
 +  char salt[8];
 +  time_t atime;
 +  long ansec;
 +  time_t ctime;
 +  long cnsec;
 +  time_t arctime;
 +  long arcnsec;
 +
 +  /* Fields to help with tracking decompression of files. */
 +  int64_t bytes_unconsumed;
 +  int64_t bytes_remaining;
 +  int64_t bytes_uncopied;
 +  int64_t offset;
 +  int64_t offset_outgoing;
++  int64_t offset_seek;
 +  char valid;
 +  unsigned int unp_offset;
 +  unsigned int unp_buffer_size;
 +  unsigned char *unp_buffer;
 +  unsigned int dictionary_size;
 +  char start_new_block;
 +  char entry_eof;
 +  unsigned long crc_calculated;
 +  int found_first_header;
++  char has_endarc_header;
++  struct data_block_offsets *dbo;
++  unsigned int cursor;
++  unsigned int nodes;
 +
 +  /* LZSS members */
 +  struct huffman_code maincode;
 +  struct huffman_code offsetcode;
 +  struct huffman_code lowoffsetcode;
 +  struct huffman_code lengthcode;
 +  unsigned char lengthtable[HUFFMAN_TABLE_SIZE];
 +  struct lzss lzss;
 +  char output_last_match;
 +  unsigned int lastlength;
 +  unsigned int lastoffset;
 +  unsigned int oldoffset[4];
 +  unsigned int lastlowoffset;
 +  unsigned int numlowoffsetrepeats;
 +  int64_t filterstart;
 +  char start_new_table;
 +
 +  /* PPMd Variant H members */
 +  char ppmd_valid;
 +  char ppmd_eod;
 +  char is_ppmd_block;
 +  int ppmd_escape;
 +  CPpmd7 ppmd7_context;
 +  CPpmd7z_RangeDec range_dec;
 +  IByteIn bytein;
 +
 +  /*
 +   * String conversion object.
 +   */
 +  int init_default_conversion;
 +  struct archive_string_conv *sconv_default;
 +  struct archive_string_conv *opt_sconv;
 +  struct archive_string_conv *sconv_utf8;
 +  struct archive_string_conv *sconv_utf16be;
 +
 +  /*
 +   * Bit stream reader.
 +   */
 +  struct rar_br {
 +#define CACHE_TYPE	uint64_t
 +#define CACHE_BITS	(8 * sizeof(CACHE_TYPE))
 +    /* Cache buffer. */
 +    CACHE_TYPE		 cache_buffer;
 +    /* Indicates how many bits avail in cache_buffer. */
 +    int			 cache_avail;
 +    ssize_t		 avail_in;
 +    const unsigned char *next_in;
 +  } br;
 +};
 +
 +static int archive_read_format_rar_bid(struct archive_read *, int);
 +static int archive_read_format_rar_options(struct archive_read *,
 +    const char *, const char *);
 +static int archive_read_format_rar_read_header(struct archive_read *,
 +    struct archive_entry *);
 +static int archive_read_format_rar_read_data(struct archive_read *,
 +    const void **, size_t *, int64_t *);
 +static int archive_read_format_rar_read_data_skip(struct archive_read *a);
++static int64_t archive_read_format_rar_seek_data(struct archive_read *, int64_t,
++    int);
 +static int archive_read_format_rar_cleanup(struct archive_read *);
 +
 +/* Support functions */
 +static int read_header(struct archive_read *, struct archive_entry *, char);
- static time_t get_time(int time);
++static time_t get_time(int);
 +static int read_exttime(const char *, struct rar *, const char *);
 +static int read_symlink_stored(struct archive_read *, struct archive_entry *,
 +                               struct archive_string_conv *);
 +static int read_data_stored(struct archive_read *, const void **, size_t *,
 +                            int64_t *);
 +static int read_data_compressed(struct archive_read *, const void **, size_t *,
 +                          int64_t *);
 +static int rar_br_preparation(struct archive_read *, struct rar_br *);
 +static int parse_codes(struct archive_read *);
 +static void free_codes(struct archive_read *);
 +static int read_next_symbol(struct archive_read *, struct huffman_code *);
 +static int create_code(struct archive_read *, struct huffman_code *,
 +                        unsigned char *, int, char);
 +static int add_value(struct archive_read *, struct huffman_code *, int, int,
 +                     int);
 +static int new_node(struct huffman_code *);
 +static int make_table(struct archive_read *, struct huffman_code *);
 +static int make_table_recurse(struct archive_read *, struct huffman_code *, int,
 +                              struct huffman_table_entry *, int, int);
 +static int64_t expand(struct archive_read *, int64_t);
 +static int copy_from_lzss_window(struct archive_read *, const void **,
 +                                   int64_t, int);
++static const void *rar_read_ahead(struct archive_read *, size_t, ssize_t *);
 +
 +/*
 + * Bit stream reader.
 + */
 +/* Check that the cache buffer has enough bits. */
 +#define rar_br_has(br, n) ((br)->cache_avail >= n)
 +/* Get compressed data by bit. */
 +#define rar_br_bits(br, n)        \
 +  (((uint32_t)((br)->cache_buffer >>    \
 +    ((br)->cache_avail - (n)))) & cache_masks[n])
 +#define rar_br_bits_forced(br, n)     \
 +  (((uint32_t)((br)->cache_buffer <<    \
 +    ((n) - (br)->cache_avail))) & cache_masks[n])
 +/* Read ahead to make sure the cache buffer has enough compressed data we
 + * will use.
 + *  True  : completed, there is enough data in the cache buffer.
 + *  False : there is no data in the stream. */
 +#define rar_br_read_ahead(a, br, n) \
 +  ((rar_br_has(br, (n)) || rar_br_fillup(a, br)) || rar_br_has(br, (n)))
 +/* Notify how many bits we consumed. */
 +#define rar_br_consume(br, n) ((br)->cache_avail -= (n))
 +#define rar_br_consume_unalined_bits(br) ((br)->cache_avail &= ~7)
 +
 +static const uint32_t cache_masks[] = {
 +  0x00000000, 0x00000001, 0x00000003, 0x00000007,
 +  0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
 +  0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
 +  0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
 +  0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
 +  0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
 +  0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
 +  0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,
 +  0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
 +};
 +
 +/*
 + * Shift away used bits in the cache data and fill it up with following bits.
 + * Call this when cache buffer does not have enough bits you need.
 + *
 + * Returns 1 if the cache buffer is full.
 + * Returns 0 if the cache buffer is not full; input buffer is empty.
 + */
 +static int
 +rar_br_fillup(struct archive_read *a, struct rar_br *br)
 +{
 +  struct rar *rar = (struct rar *)(a->format->data);
 +  int n = CACHE_BITS - br->cache_avail;
 +
 +  for (;;) {
 +    switch (n >> 3) {
 +    case 8:
 +      if (br->avail_in >= 8) {
 +        br->cache_buffer =
 +            ((uint64_t)br->next_in[0]) << 56 |
 +            ((uint64_t)br->next_in[1]) << 48 |
 +            ((uint64_t)br->next_in[2]) << 40 |
 +            ((uint64_t)br->next_in[3]) << 32 |
 +            ((uint32_t)br->next_in[4]) << 24 |
 +            ((uint32_t)br->next_in[5]) << 16 |
 +            ((uint32_t)br->next_in[6]) << 8 |
 +             (uint32_t)br->next_in[7];
 +        br->next_in += 8;
 +        br->avail_in -= 8;
 +        br->cache_avail += 8 * 8;
 +        rar->bytes_unconsumed += 8;
 +        rar->bytes_remaining -= 8;
 +        return (1);
 +      }
 +      break;
 +    case 7:
 +      if (br->avail_in >= 7) {
 +        br->cache_buffer =
 +           (br->cache_buffer << 56) |
 +            ((uint64_t)br->next_in[0]) << 48 |
 +            ((uint64_t)br->next_in[1]) << 40 |
 +            ((uint64_t)br->next_in[2]) << 32 |
 +            ((uint32_t)br->next_in[3]) << 24 |
 +            ((uint32_t)br->next_in[4]) << 16 |
 +            ((uint32_t)br->next_in[5]) << 8 |
 +             (uint32_t)br->next_in[6];
 +        br->next_in += 7;
 +        br->avail_in -= 7;
 +        br->cache_avail += 7 * 8;
 +        rar->bytes_unconsumed += 7;
 +        rar->bytes_remaining -= 7;
 +        return (1);
 +      }
 +      break;
 +    case 6:
 +      if (br->avail_in >= 6) {
 +        br->cache_buffer =
 +           (br->cache_buffer << 48) |
 +            ((uint64_t)br->next_in[0]) << 40 |
 +            ((uint64_t)br->next_in[1]) << 32 |
 +            ((uint32_t)br->next_in[2]) << 24 |
 +            ((uint32_t)br->next_in[3]) << 16 |
 +            ((uint32_t)br->next_in[4]) << 8 |
 +             (uint32_t)br->next_in[5];
 +        br->next_in += 6;
 +        br->avail_in -= 6;
 +        br->cache_avail += 6 * 8;
 +        rar->bytes_unconsumed += 6;
 +        rar->bytes_remaining -= 6;
 +        return (1);
 +      }
 +      break;
 +    case 0:
 +      /* We have enough compressed data in
 +       * the cache buffer.*/
 +      return (1);
 +    default:
 +      break;
 +    }
 +    if (br->avail_in <= 0) {
 +
 +      if (rar->bytes_unconsumed > 0) {
 +        /* Consume as much as the decompressor
 +         * actually used. */
 +        __archive_read_consume(a, rar->bytes_unconsumed);
 +        rar->bytes_unconsumed = 0;
 +      }
-       br->next_in = __archive_read_ahead(a, 1, &(br->avail_in));
++      br->next_in = rar_read_ahead(a, 1, &(br->avail_in));
 +      if (br->next_in == NULL)
 +        return (0);
-       if (br->avail_in > rar->bytes_remaining)
-         br->avail_in = rar->bytes_remaining;
 +      if (br->avail_in == 0)
 +        return (0);
 +    }
 +    br->cache_buffer =
 +       (br->cache_buffer << 8) | *br->next_in++;
 +    br->avail_in--;
 +    br->cache_avail += 8;
 +    n -= 8;
 +    rar->bytes_unconsumed++;
 +    rar->bytes_remaining--;
 +  }
 +}
 +
 +static int
 +rar_br_preparation(struct archive_read *a, struct rar_br *br)
 +{
 +  struct rar *rar = (struct rar *)(a->format->data);
 +
 +  if (rar->bytes_remaining > 0) {
-     br->next_in = __archive_read_ahead(a, 1, &(br->avail_in));
++    br->next_in = rar_read_ahead(a, 1, &(br->avail_in));
 +    if (br->next_in == NULL) {
 +      archive_set_error(&a->archive,
 +          ARCHIVE_ERRNO_FILE_FORMAT,
 +          "Truncated RAR file data");
 +      return (ARCHIVE_FATAL);
 +    }
-     if (br->avail_in > rar->bytes_remaining)
-       br->avail_in = rar->bytes_remaining;
 +    if (br->cache_avail == 0)
 +      (void)rar_br_fillup(a, br);
 +  }
 +  return (ARCHIVE_OK);
 +}
 +
 +/* Find last bit set */
 +static inline int
 +rar_fls(unsigned int word)
 +{
 +  word |= (word >>  1);
 +  word |= (word >>  2);
 +  word |= (word >>  4);
 +  word |= (word >>  8);
 +  word |= (word >> 16);
 +  return word - (word >> 1);
 +}
 +
 +/* LZSS functions */
 +static inline int64_t
 +lzss_position(struct lzss *lzss)
 +{
 +  return lzss->position;
 +}
 +
 +static inline int
 +lzss_mask(struct lzss *lzss)
 +{
 +  return lzss->mask;
 +}
 +
 +static inline int
 +lzss_size(struct lzss *lzss)
 +{
 +  return lzss->mask + 1;
 +}
 +
 +static inline int
 +lzss_offset_for_position(struct lzss *lzss, int64_t pos)
 +{
-   return pos & lzss->mask;
++  return (int)(pos & lzss->mask);
 +}
 +
 +static inline unsigned char *
 +lzss_pointer_for_position(struct lzss *lzss, int64_t pos)
 +{
 +  return &lzss->window[lzss_offset_for_position(lzss, pos)];
 +}
 +
 +static inline int
 +lzss_current_offset(struct lzss *lzss)
 +{
 +  return lzss_offset_for_position(lzss, lzss->position);
 +}
 +
 +static inline uint8_t *
 +lzss_current_pointer(struct lzss *lzss)
 +{
 +  return lzss_pointer_for_position(lzss, lzss->position);
 +}
 +
 +static inline void
 +lzss_emit_literal(struct rar *rar, uint8_t literal)
 +{
 +  *lzss_current_pointer(&rar->lzss) = literal;
 +  rar->lzss.position++;
 +}
 +
 +static inline void
 +lzss_emit_match(struct rar *rar, int offset, int length)
 +{
 +  int dstoffs = lzss_current_offset(&rar->lzss);
 +  int srcoffs = (dstoffs - offset) & lzss_mask(&rar->lzss);
 +  int l, li, remaining;
 +  unsigned char *d, *s;
 +
 +  remaining = length;
 +  while (remaining > 0) {
 +    l = remaining;
 +    if (dstoffs > srcoffs) {
 +      if (l > lzss_size(&rar->lzss) - dstoffs)
 +        l = lzss_size(&rar->lzss) - dstoffs;
 +    } else {
 +      if (l > lzss_size(&rar->lzss) - srcoffs)
 +        l = lzss_size(&rar->lzss) - srcoffs;
 +    }
 +    d = &(rar->lzss.window[dstoffs]);
 +    s = &(rar->lzss.window[srcoffs]);
 +    if ((dstoffs + l < srcoffs) || (srcoffs + l < dstoffs))
 +      memcpy(d, s, l);
 +    else {
 +      for (li = 0; li < l; li++)
 +        d[li] = s[li];
 +    }
 +    remaining -= l;
 +    dstoffs = (dstoffs + l) & lzss_mask(&(rar->lzss));
 +    srcoffs = (srcoffs + l) & lzss_mask(&(rar->lzss));
 +  }
 +  rar->lzss.position += length;
 +}
 +
 +static void *
 +ppmd_alloc(void *p, size_t size)
 +{
 +  (void)p;
 +  return malloc(size);
 +}
 +static void
 +ppmd_free(void *p, void *address)
 +{
 +  (void)p;
 +  free(address);
 +}
 +static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
 +
 +static Byte
 +ppmd_read(void *p)
 +{
 +  struct archive_read *a = ((IByteIn*)p)->a;
 +  struct rar *rar = (struct rar *)(a->format->data);
 +  struct rar_br *br = &(rar->br);
 +  Byte b;
 +  if (!rar_br_read_ahead(a, br, 8))
 +  {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Truncated RAR file data");
 +    rar->valid = 0;
 +    return 0;
 +  }
 +  b = rar_br_bits(br, 8);
 +  rar_br_consume(br, 8);
 +  return b;
 +}
 +
 +int
 +archive_read_support_format_rar(struct archive *_a)
 +{
 +  struct archive_read *a = (struct archive_read *)_a;
 +  struct rar *rar;
 +  int r;
 +
 +  archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 +                      "archive_read_support_format_rar");
 +
 +  rar = (struct rar *)malloc(sizeof(*rar));
 +  if (rar == NULL)
 +  {
 +    archive_set_error(&a->archive, ENOMEM, "Can't allocate rar data");
 +    return (ARCHIVE_FATAL);
 +  }
 +  memset(rar, 0, sizeof(*rar));
 +
 +  r = __archive_read_register_format(a,
 +                                     rar,
 +                                     "rar",
 +                                     archive_read_format_rar_bid,
 +                                     archive_read_format_rar_options,
 +                                     archive_read_format_rar_read_header,
 +                                     archive_read_format_rar_read_data,
 +                                     archive_read_format_rar_read_data_skip,
++                                     archive_read_format_rar_seek_data,
 +                                     archive_read_format_rar_cleanup);
 +
 +  if (r != ARCHIVE_OK)
 +    free(rar);
 +  return (r);
 +}
 +
 +static int
 +archive_read_format_rar_bid(struct archive_read *a, int best_bid)
 +{
 +  const char *p;
 +
 +  /* If there's already a bid > 30, we'll never win. */
 +  if (best_bid > 30)
 +	  return (-1);
 +
 +  if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)
 +    return (-1);
 +
 +  if (memcmp(p, RAR_SIGNATURE, 7) == 0)
 +    return (30);
 +
 +  if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
 +    /* This is a PE file */
 +    ssize_t offset = 0x10000;
 +    ssize_t window = 4096;
 +    ssize_t bytes_avail;
 +    while (offset + window <= (1024 * 128)) {
 +      const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail);
 +      if (buff == NULL) {
 +        /* Remaining bytes are less than window. */
 +        window >>= 1;
 +        if (window < 0x40)
 +          return (0);
 +        continue;
 +      }
 +      p = buff + offset;
 +      while (p + 7 < buff + bytes_avail) {
 +        if (memcmp(p, RAR_SIGNATURE, 7) == 0)
 +          return (30);
 +        p += 0x10;
 +      }
 +      offset = p - buff;
 +    }
 +  }
 +  return (0);
 +}
 +
 +static int
 +skip_sfx(struct archive_read *a)
 +{
 +  const void *h;
 +  const char *p, *q;
 +  size_t skip, total;
 +  ssize_t bytes, window;
 +
 +  total = 0;
 +  window = 4096;
 +  while (total + window <= (1024 * 128)) {
 +    h = __archive_read_ahead(a, window, &bytes);
 +    if (h == NULL) {
 +      /* Remaining bytes are less than window. */
 +      window >>= 1;
 +      if (window < 0x40)
 +      	goto fatal;
 +      continue;
 +    }
 +    if (bytes < 0x40)
 +      goto fatal;
 +    p = h;
 +    q = p + bytes;
 +
 +    /*
 +     * Scan ahead until we find something that looks
 +     * like the RAR header.
 +     */
 +    while (p + 7 < q) {
 +      if (memcmp(p, RAR_SIGNATURE, 7) == 0) {
 +      	skip = p - (const char *)h;
 +      	__archive_read_consume(a, skip);
 +      	return (ARCHIVE_OK);
 +      }
 +      p += 0x10;
 +    }
 +    skip = p - (const char *)h;
 +    __archive_read_consume(a, skip);
 +	total += skip;
 +  }
 +fatal:
 +  archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +      "Couldn't find out RAR header");
 +  return (ARCHIVE_FATAL);
 +}
 +
 +static int
 +archive_read_format_rar_options(struct archive_read *a,
 +    const char *key, const char *val)
 +{
 +  struct rar *rar;
 +  int ret = ARCHIVE_FAILED;
 +        
 +  rar = (struct rar *)(a->format->data);
 +  if (strcmp(key, "hdrcharset")  == 0) {
 +    if (val == NULL || val[0] == 0)
 +      archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +          "rar: hdrcharset option needs a character-set name");
 +    else {
 +      rar->opt_sconv =
 +          archive_string_conversion_from_charset(
 +              &a->archive, val, 0);
 +      if (rar->opt_sconv != NULL)
 +        ret = ARCHIVE_OK;
 +      else
 +        ret = ARCHIVE_FATAL;
 +    }
-   } else
-     archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-         "rar: unknown keyword ``%s''", key);
-                 
-   return (ret);
++    return (ret);
++  }
++
++  /* Note: The "warn" return is just to inform the options
++   * supervisor that we didn't handle it.  It will generate
++   * a suitable error if no one used this option. */
++  return (ARCHIVE_WARN);
 +}
 +
 +static int
 +archive_read_format_rar_read_header(struct archive_read *a,
 +                                    struct archive_entry *entry)
 +{
 +  const void *h;
 +  const char *p;
 +  struct rar *rar;
 +  size_t skip;
 +  char head_type;
 +  int ret;
 +  unsigned flags;
 +
 +  a->archive.archive_format = ARCHIVE_FORMAT_RAR;
 +  if (a->archive.archive_format_name == NULL)
 +    a->archive.archive_format_name = "RAR";
 +
 +  rar = (struct rar *)(a->format->data);
 +
 +  /* RAR files can be generated without EOF headers, so return ARCHIVE_EOF if
 +  * this fails.
 +  */
 +  if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
 +    return (ARCHIVE_EOF);
 +
 +  p = h;
 +  if (rar->found_first_header == 0 &&
 +     ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0)) {
 +    /* This is an executable ? Must be self-extracting... */
 +    ret = skip_sfx(a);
 +    if (ret < ARCHIVE_WARN)
 +      return (ret);
 +  }
 +  rar->found_first_header = 1;
 +
 +  while (1)
 +  {
 +    unsigned long crc32_val;
 +
 +    if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
 +      return (ARCHIVE_FATAL);
 +    p = h;
 +
 +    head_type = p[2];
 +    switch(head_type)
 +    {
 +    case MARK_HEAD:
 +      if (memcmp(p, RAR_SIGNATURE, 7) != 0) {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +          "Invalid marker header");
 +        return (ARCHIVE_FATAL);
 +      }
 +      __archive_read_consume(a, 7);
 +      break;
 +
 +    case MAIN_HEAD:
 +      rar->main_flags = archive_le16dec(p + 3);
 +      skip = archive_le16dec(p + 5);
 +      if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)) {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +          "Invalid header size");
 +        return (ARCHIVE_FATAL);
 +      }
 +      if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
 +        return (ARCHIVE_FATAL);
 +      p = h;
 +      memcpy(rar->reserved1, p + 7, sizeof(rar->reserved1));
 +      memcpy(rar->reserved2, p + 7 + sizeof(rar->reserved1),
 +             sizeof(rar->reserved2));
 +      if (rar->main_flags & MHD_ENCRYPTVER) {
 +        if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)+1) {
 +          archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +            "Invalid header size");
 +          return (ARCHIVE_FATAL);
 +        }
 +        rar->encryptver = *(p + 7 + sizeof(rar->reserved1) +
 +                            sizeof(rar->reserved2));
 +      }
 +
-       if (rar->main_flags & MHD_VOLUME ||
-           rar->main_flags & MHD_FIRSTVOLUME)
-       {
-         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                           "RAR volume support unavailable.");
-         return (ARCHIVE_FATAL);
-       }
 +      if (rar->main_flags & MHD_PASSWORD)
 +      {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                          "RAR encryption support unavailable.");
 +        return (ARCHIVE_FATAL);
 +      }
 +
-       crc32_val = crc32(0, (const unsigned char *)p + 2, skip - 2);
++      crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);
 +      if ((crc32_val & 0xffff) != archive_le16dec(p)) {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +          "Header CRC error");
 +        return (ARCHIVE_FATAL);
 +      }
 +      __archive_read_consume(a, skip);
 +      break;
 +
 +    case FILE_HEAD:
 +      return read_header(a, entry, head_type);
 +
 +    case COMM_HEAD:
 +    case AV_HEAD:
 +    case SUB_HEAD:
 +    case PROTECT_HEAD:
 +    case SIGN_HEAD:
++    case ENDARC_HEAD:
 +      flags = archive_le16dec(p + 3);
 +      skip = archive_le16dec(p + 5);
 +      if (skip < 7) {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +          "Invalid header size");
 +        return (ARCHIVE_FATAL);
 +      }
 +      if (skip > 7) {
 +        if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
 +          return (ARCHIVE_FATAL);
 +        p = h;
 +      }
 +      if (flags & HD_ADD_SIZE_PRESENT)
 +      {
 +        if (skip < 7 + 4) {
 +          archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +            "Invalid header size");
 +          return (ARCHIVE_FATAL);
 +        }
 +        skip += archive_le32dec(p + 7);
 +        if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
 +          return (ARCHIVE_FATAL);
 +        p = h;
 +      }
 +
-       crc32_val = crc32(0, (const unsigned char *)p + 2, skip - 2);
++      crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);
 +      if ((crc32_val & 0xffff) != archive_le16dec(p)) {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +          "Header CRC error");
 +        return (ARCHIVE_FATAL);
 +      }
 +      __archive_read_consume(a, skip);
++      if (head_type == ENDARC_HEAD)
++        return (ARCHIVE_EOF);
 +      break;
 +
 +    case NEWSUB_HEAD:
 +      if ((ret = read_header(a, entry, head_type)) < ARCHIVE_WARN)
 +        return ret;
 +      break;
 +
-     case ENDARC_HEAD:
-       return (ARCHIVE_EOF);
- 
 +    default:
 +      archive_set_error(&a->archive,  ARCHIVE_ERRNO_FILE_FORMAT,
 +                        "Bad RAR file");
 +      return (ARCHIVE_FATAL);
 +    }
 +  }
 +}
 +
 +static int
 +archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
 +                                  size_t *size, int64_t *offset)
 +{
 +  struct rar *rar = (struct rar *)(a->format->data);
 +  int ret;
 +
 +  if (rar->bytes_unconsumed > 0) {
 +      /* Consume as much as the decompressor actually used. */
 +      __archive_read_consume(a, rar->bytes_unconsumed);
 +      rar->bytes_unconsumed = 0;
 +  }
 +
-   if (rar->entry_eof) {
++  if (rar->entry_eof || rar->offset_seek >= rar->unp_size) {
 +    *buff = NULL;
 +    *size = 0;
 +    *offset = rar->offset;
++    if (*offset < rar->unp_size)
++      *offset = rar->unp_size;
 +    return (ARCHIVE_EOF);
 +  }
 +
 +  switch (rar->compression_method)
 +  {
 +  case COMPRESS_METHOD_STORE:
 +    ret = read_data_stored(a, buff, size, offset);
 +    break; 
 +
 +  case COMPRESS_METHOD_FASTEST:
 +  case COMPRESS_METHOD_FAST:
 +  case COMPRESS_METHOD_NORMAL:
 +  case COMPRESS_METHOD_GOOD:
 +  case COMPRESS_METHOD_BEST:
 +    ret = read_data_compressed(a, buff, size, offset);
 +    if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN)
 +      __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
 +    break; 
 +
 +  default:
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Unsupported compression method for RAR file.");
 +    ret = ARCHIVE_FATAL;
 +    break; 
 +  }
 +  return (ret);
 +}
 +
 +static int
 +archive_read_format_rar_read_data_skip(struct archive_read *a)
 +{
 +  struct rar *rar;
 +  int64_t bytes_skipped;
++  int ret;
 +
 +  rar = (struct rar *)(a->format->data);
 +
 +  if (rar->bytes_unconsumed > 0) {
 +      /* Consume as much as the decompressor actually used. */
 +      __archive_read_consume(a, rar->bytes_unconsumed);
 +      rar->bytes_unconsumed = 0;
 +  }
 +
 +  if (rar->bytes_remaining > 0) {
 +    bytes_skipped = __archive_read_consume(a, rar->bytes_remaining);
 +    if (bytes_skipped < 0)
 +      return (ARCHIVE_FATAL);
 +  }
++
++  /* Compressed data to skip must be read from each header in a multivolume
++   * archive.
++   */
++  if (rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER)
++  {
++    ret = archive_read_format_rar_read_header(a, a->entry);
++    if (ret == (ARCHIVE_EOF))
++      ret = archive_read_format_rar_read_header(a, a->entry);
++    if (ret != (ARCHIVE_OK))
++      return ret;
++    return archive_read_format_rar_read_data_skip(a);
++  }
++
 +  return (ARCHIVE_OK);
 +}
 +
++static int64_t
++archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
++    int whence)
++{
++  int64_t client_offset, ret;
++  unsigned int i;
++  struct rar *rar = (struct rar *)(a->format->data);
++
++  if (rar->compression_method == COMPRESS_METHOD_STORE)
++  {
++    /* Modify the offset for use with SEEK_SET */
++    switch (whence)
++    {
++      case SEEK_CUR:
++        client_offset = rar->offset_seek;
++        break;
++      case SEEK_END:
++        client_offset = rar->unp_size;
++        break;
++      case SEEK_SET:
++      default:
++        client_offset = 0;
++    }
++    client_offset += offset;
++    if (client_offset < 0)
++    {
++      /* Can't seek past beginning of data block */
++      return -1;
++    }
++    else if (client_offset > rar->unp_size)
++    {
++      /*
++       * Set the returned offset but only seek to the end of
++       * the data block.
++       */
++      rar->offset_seek = client_offset;
++      client_offset = rar->unp_size;
++    }
++
++    client_offset += rar->dbo[0].start_offset;
++    i = 0;
++    while (i < rar->cursor)
++    {
++      i++;
++      client_offset += rar->dbo[i].start_offset - rar->dbo[i-1].end_offset;
++    }
++    if (rar->main_flags & MHD_VOLUME)
++    {
++      /* Find the appropriate offset among the multivolume archive */
++      while (1)
++      {
++        if (client_offset < rar->dbo[rar->cursor].start_offset &&
++          rar->file_flags & FHD_SPLIT_BEFORE)
++        {
++          /* Search backwards for the correct data block */
++          if (rar->cursor == 0)
++          {
++            archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++              "Attempt to seek past beginning of RAR data block");
++            return (ARCHIVE_FAILED);
++          }
++          rar->cursor--;
++          client_offset -= rar->dbo[rar->cursor+1].start_offset -
++            rar->dbo[rar->cursor].end_offset;
++          if (client_offset < rar->dbo[rar->cursor].start_offset)
++            continue;
++          ret = __archive_read_seek(a, rar->dbo[rar->cursor].start_offset -
++            rar->dbo[rar->cursor].header_size, SEEK_SET);
++          if (ret < (ARCHIVE_OK))
++            return ret;
++          ret = archive_read_format_rar_read_header(a, a->entry);
++          if (ret != (ARCHIVE_OK))
++          {
++            archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++              "Error during seek of RAR file");
++            return (ARCHIVE_FAILED);
++          }
++          rar->cursor--;
++          break;
++        }
++        else if (client_offset > rar->dbo[rar->cursor].end_offset &&
++          rar->file_flags & FHD_SPLIT_AFTER)
++        {
++          /* Search forward for the correct data block */
++          rar->cursor++;
++          if (rar->cursor < rar->nodes &&
++            client_offset > rar->dbo[rar->cursor].end_offset)
++          {
++            client_offset += rar->dbo[rar->cursor].start_offset -
++              rar->dbo[rar->cursor-1].end_offset;
++            continue;
++          }
++          rar->cursor--;
++          ret = __archive_read_seek(a, rar->dbo[rar->cursor].end_offset,
++                                    SEEK_SET);
++          if (ret < (ARCHIVE_OK))
++            return ret;
++          ret = archive_read_format_rar_read_header(a, a->entry);
++          if (ret == (ARCHIVE_EOF))
++          {
++            rar->has_endarc_header = 1;
++            ret = archive_read_format_rar_read_header(a, a->entry);
++          }
++          if (ret != (ARCHIVE_OK))
++          {
++            archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++              "Error during seek of RAR file");
++            return (ARCHIVE_FAILED);
++          }
++          client_offset += rar->dbo[rar->cursor].start_offset -
++            rar->dbo[rar->cursor-1].end_offset;
++          continue;
++        }
++        break;
++      }
++    }
++
++    ret = __archive_read_seek(a, client_offset, SEEK_SET);
++    if (ret < (ARCHIVE_OK))
++      return ret;
++    rar->bytes_remaining = rar->dbo[rar->cursor].end_offset - ret;
++    i = rar->cursor;
++    while (i > 0)
++    {
++      i--;
++      ret -= rar->dbo[i+1].start_offset - rar->dbo[i].end_offset;
++    }
++    ret -= rar->dbo[0].start_offset;
++
++    /* Always restart reading the file after a seek */
++    a->read_data_block = NULL;
++    a->read_data_offset = 0;
++    a->read_data_output_offset = 0;
++    a->read_data_remaining = 0;
++    rar->bytes_unconsumed = 0;
++    rar->offset = 0;
++
++    /*
++     * If a seek past the end of file was requested, return the requested
++     * offset.
++     */
++    if (ret == rar->unp_size && rar->offset_seek > rar->unp_size)
++      return rar->offset_seek;
++
++    /* Return the new offset */
++    rar->offset_seek = ret;
++    return rar->offset_seek;
++  }
++  else
++  {
++    archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++      "Seeking of compressed RAR files is unsupported");
++  }
++  return (ARCHIVE_FAILED);
++}
++
 +static int
 +archive_read_format_rar_cleanup(struct archive_read *a)
 +{
 +  struct rar *rar;
 +
 +  rar = (struct rar *)(a->format->data);
 +  free_codes(a);
 +  free(rar->filename);
++  free(rar->filename_save);
++  free(rar->dbo);
 +  free(rar->unp_buffer);
 +  free(rar->lzss.window);
 +  __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
 +  free(rar);
 +  (a->format->data) = NULL;
 +  return (ARCHIVE_OK);
 +}
 +
 +static int
 +read_header(struct archive_read *a, struct archive_entry *entry,
 +            char head_type)
 +{
 +  const void *h;
 +  const char *p, *endp;
 +  struct rar *rar;
 +  struct rar_header rar_header;
 +  struct rar_file_header file_header;
 +  int64_t header_size;
 +  unsigned filename_size, end;
 +  char *filename;
 +  char *strp;
 +  char packed_size[8];
 +  char unp_size[8];
-   int time;
++  int ttime;
 +  struct archive_string_conv *sconv, *fn_sconv;
 +  unsigned long crc32_val;
 +  int ret = (ARCHIVE_OK), ret2;
 +
 +  rar = (struct rar *)(a->format->data);
 +
 +  /* Setup a string conversion object for non-rar-unicode filenames. */
 +  sconv = rar->opt_sconv;
 +  if (sconv == NULL) {
 +    if (!rar->init_default_conversion) {
 +      rar->sconv_default =
 +          archive_string_default_conversion_for_read(
 +            &(a->archive));
 +      rar->init_default_conversion = 1;
 +    }
 +    sconv = rar->sconv_default;
 +  }
 +
 +
 +  if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
 +    return (ARCHIVE_FATAL);
 +  p = h;
 +  memcpy(&rar_header, p, sizeof(rar_header));
 +  rar->file_flags = archive_le16dec(rar_header.flags);
 +  header_size = archive_le16dec(rar_header.size);
-   if (header_size < sizeof(file_header) + 7) {
++  if (header_size < (int64_t)sizeof(file_header) + 7) {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +      "Invalid header size");
 +    return (ARCHIVE_FATAL);
 +  }
 +  crc32_val = crc32(0, (const unsigned char *)p + 2, 7 - 2);
 +  __archive_read_consume(a, 7);
 +
 +  if (!(rar->file_flags & FHD_SOLID))
 +  {
 +    rar->compression_method = 0;
 +    rar->packed_size = 0;
 +    rar->unp_size = 0;
 +    rar->mtime = 0;
 +    rar->ctime = 0;
 +    rar->atime = 0;
 +    rar->arctime = 0;
 +    rar->mode = 0;
 +    memset(&rar->salt, 0, sizeof(rar->salt));
 +    rar->atime = 0;
 +    rar->ansec = 0;
 +    rar->ctime = 0;
 +    rar->cnsec = 0;
 +    rar->mtime = 0;
 +    rar->mnsec = 0;
 +    rar->arctime = 0;
 +    rar->arcnsec = 0;
 +  }
 +  else
 +  {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "RAR solid archive support unavailable.");
 +    return (ARCHIVE_FATAL);
 +  }
 +
-   if ((h = __archive_read_ahead(a, header_size - 7, NULL)) == NULL)
++  if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
 +    return (ARCHIVE_FATAL);
 +
 +  /* File Header CRC check. */
-   crc32_val = crc32(crc32_val, h, header_size - 7);
++  crc32_val = crc32(crc32_val, h, (unsigned)(header_size - 7));
 +  if ((crc32_val & 0xffff) != archive_le16dec(rar_header.crc)) {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +      "Header CRC error");
 +    return (ARCHIVE_FATAL);
 +  }
 +  /* If no CRC error, Go on parsing File Header. */
 +  p = h;
 +  endp = p + header_size - 7;
 +  memcpy(&file_header, p, sizeof(file_header));
 +  p += sizeof(file_header);
 +
 +  rar->compression_method = file_header.method;
 +
-   time = archive_le32dec(file_header.file_time);
-   rar->mtime = get_time(time);
++  ttime = archive_le32dec(file_header.file_time);
++  rar->mtime = get_time(ttime);
 +
 +  rar->file_crc = archive_le32dec(file_header.file_crc);
 +
 +  if (rar->file_flags & FHD_PASSWORD)
 +  {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "RAR encryption support unavailable.");
 +    return (ARCHIVE_FATAL);
 +  }
 +
 +  if (rar->file_flags & FHD_LARGE)
 +  {
 +    memcpy(packed_size, file_header.pack_size, 4);
 +    memcpy(packed_size + 4, p, 4); /* High pack size */
 +    p += 4;
 +    memcpy(unp_size, file_header.unp_size, 4);
 +    memcpy(unp_size + 4, p, 4); /* High unpack size */
 +    p += 4;
 +    rar->packed_size = archive_le64dec(&packed_size);
 +    rar->unp_size = archive_le64dec(&unp_size);
 +  }
 +  else
 +  {
 +    rar->packed_size = archive_le32dec(file_header.pack_size);
 +    rar->unp_size = archive_le32dec(file_header.unp_size);
 +  }
 +
-   /* TODO: Need to use CRC check for these kind of cases.
-    * For now, check if sizes are not < 0.
-    */
 +  if (rar->packed_size < 0 || rar->unp_size < 0)
 +  {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Invalid sizes specified.");
 +    return (ARCHIVE_FATAL);
 +  }
 +
++  rar->bytes_remaining = rar->packed_size;
++
 +  /* TODO: RARv3 subblocks contain comments. For now the complete block is
 +   * consumed at the end.
 +   */
 +  if (head_type == NEWSUB_HEAD) {
 +    size_t distance = p - (const char *)h;
 +    header_size += rar->packed_size;
 +    /* Make sure we have the extended data. */
-     if ((h = __archive_read_ahead(a, header_size - 7, NULL)) == NULL)
++    if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
 +        return (ARCHIVE_FATAL);
 +    p = h;
 +    endp = p + header_size - 7;
 +    p += distance;
 +  }
 +
 +  filename_size = archive_le16dec(file_header.name_size);
 +  if (p + filename_size > endp) {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +      "Invalid filename size");
 +    return (ARCHIVE_FATAL);
 +  }
-   if (rar->filename_allocated < filename_size+2) {
-     rar->filename = realloc(rar->filename, filename_size+2);
-     if (rar->filename == NULL) {
++  if (rar->filename_allocated < filename_size * 2 + 2) {
++    char *newptr;
++    size_t newsize = filename_size * 2 + 2;
++    newptr = realloc(rar->filename, newsize);
++    if (newptr == NULL) {
 +      archive_set_error(&a->archive, ENOMEM,
 +                        "Couldn't allocate memory.");
 +      return (ARCHIVE_FATAL);
 +    }
++    rar->filename = newptr;
++    rar->filename_allocated = newsize;
 +  }
 +  filename = rar->filename;
 +  memcpy(filename, p, filename_size);
 +  filename[filename_size] = '\0';
 +  if (rar->file_flags & FHD_UNICODE)
 +  {
 +    if (filename_size != strlen(filename))
 +    {
-       unsigned char highbyte, flagbits, flagbyte, length, offset;
++      unsigned char highbyte, flagbits, flagbyte;
++      unsigned fn_end, offset;
 +
 +      end = filename_size;
++      fn_end = filename_size * 2;
 +      filename_size = 0;
-       offset = strlen(filename) + 1;
++      offset = (unsigned)strlen(filename) + 1;
 +      highbyte = *(p + offset++);
 +      flagbits = 0;
 +      flagbyte = 0;
-       while (offset < end && filename_size < end)
++      while (offset < end && filename_size < fn_end)
 +      {
 +        if (!flagbits)
 +        {
 +          flagbyte = *(p + offset++);
 +          flagbits = 8;
 +        }
 +	
 +        flagbits -= 2;
 +        switch((flagbyte >> flagbits) & 3)
 +        {
 +          case 0:
 +            filename[filename_size++] = '\0';
 +            filename[filename_size++] = *(p + offset++);
 +            break;
 +          case 1:
 +            filename[filename_size++] = highbyte;
 +            filename[filename_size++] = *(p + offset++);
 +            break;
 +          case 2:
 +            filename[filename_size++] = *(p + offset + 1);
 +            filename[filename_size++] = *(p + offset);
 +            offset += 2;
 +            break;
 +          case 3:
 +          {
-             length = *(p + offset++);
-             while (length)
-             {
- 	          if (filename_size >= end)
- 			    break;
-               filename[filename_size++] = *(p + offset);
++            char extra, high;
++            uint8_t length = *(p + offset++);
++
++            if (length & 0x80) {
++              extra = *(p + offset++);
++              high = (char)highbyte;
++            } else
++              extra = high = 0;
++            length = (length & 0x7f) + 2;
++            while (length && filename_size < fn_end) {
++              unsigned cp = filename_size >> 1;
++              filename[filename_size++] = high;
++              filename[filename_size++] = p[cp] + extra;
 +              length--;
 +            }
 +          }
 +          break;
 +        }
 +      }
-       if (filename_size >= end) {
++      if (filename_size > fn_end) {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +          "Invalid filename");
 +        return (ARCHIVE_FATAL);
 +      }
 +      filename[filename_size++] = '\0';
 +      filename[filename_size++] = '\0';
 +
 +      /* Decoded unicode form is UTF-16BE, so we have to update a string
 +       * conversion object for it. */
 +      if (rar->sconv_utf16be == NULL) {
 +        rar->sconv_utf16be = archive_string_conversion_from_charset(
 +           &a->archive, "UTF-16BE", 1);
 +        if (rar->sconv_utf16be == NULL)
 +          return (ARCHIVE_FATAL);
 +      }
 +      fn_sconv = rar->sconv_utf16be;
 +
 +      strp = filename;
 +      while (memcmp(strp, "\x00\x00", 2))
 +      {
 +        if (!memcmp(strp, "\x00\\", 2))
 +          *(strp + 1) = '/';
 +        strp += 2;
 +      }
 +      p += offset;
 +    } else {
 +      /*
 +       * If FHD_UNICODE is set but no unicode data, this file name form
 +       * is UTF-8, so we have to update a string conversion object for
 +       * it accordingly.
 +       */
 +      if (rar->sconv_utf8 == NULL) {
 +        rar->sconv_utf8 = archive_string_conversion_from_charset(
 +           &a->archive, "UTF-8", 1);
 +        if (rar->sconv_utf8 == NULL)
 +          return (ARCHIVE_FATAL);
 +      }
 +      fn_sconv = rar->sconv_utf8;
 +      while ((strp = strchr(filename, '\\')) != NULL)
 +        *strp = '/';
 +      p += filename_size;
 +    }
 +  }
 +  else
 +  {
 +    fn_sconv = sconv;
 +    while ((strp = strchr(filename, '\\')) != NULL)
 +      *strp = '/';
 +    p += filename_size;
 +  }
 +
++  /* Split file in multivolume RAR. No more need to process header. */
++  if (rar->filename_save &&
++    !memcmp(rar->filename, rar->filename_save, filename_size + 1))
++  {
++    __archive_read_consume(a, header_size - 7);
++    rar->cursor++;
++    if (rar->cursor >= rar->nodes)
++    {
++      rar->nodes++;
++      if ((rar->dbo =
++        realloc(rar->dbo, sizeof(*rar->dbo) * rar->nodes)) == NULL)
++      {
++        archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
++        return (ARCHIVE_FATAL);
++      }
++      rar->dbo[rar->cursor].header_size = header_size;
++      rar->dbo[rar->cursor].start_offset = -1;
++      rar->dbo[rar->cursor].end_offset = -1;
++    }
++    if (rar->dbo[rar->cursor].start_offset < 0)
++    {
++      rar->dbo[rar->cursor].start_offset = a->filter->position;
++      rar->dbo[rar->cursor].end_offset = rar->dbo[rar->cursor].start_offset +
++        rar->packed_size;
++    }
++    return ret;
++  }
++
++  rar->filename_save = (char*)realloc(rar->filename_save,
++                                      filename_size + 1);
++  memcpy(rar->filename_save, rar->filename, filename_size + 1);
++
++  /* Set info for seeking */
++  free(rar->dbo);
++  if ((rar->dbo = calloc(1, sizeof(*rar->dbo))) == NULL)
++  {
++    archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
++    return (ARCHIVE_FATAL);
++  }
++  rar->dbo[0].header_size = header_size;
++  rar->dbo[0].start_offset = -1;
++  rar->dbo[0].end_offset = -1;
++  rar->cursor = 0;
++  rar->nodes = 1;
++
 +  if (rar->file_flags & FHD_SALT)
 +  {
 +    if (p + 8 > endp) {
 +      archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +        "Invalid header size");
 +      return (ARCHIVE_FATAL);
 +    }
 +    memcpy(rar->salt, p, 8);
 +    p += 8;
 +  }
 +
 +  if (rar->file_flags & FHD_EXTTIME) {
 +    if (read_exttime(p, rar, endp) < 0) {
 +      archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +        "Invalid header size");
 +      return (ARCHIVE_FATAL);
 +    }
 +  }
 +
 +  __archive_read_consume(a, header_size - 7);
++  rar->dbo[0].start_offset = a->filter->position;
++  rar->dbo[0].end_offset = rar->dbo[0].start_offset + rar->packed_size;
 +
 +  switch(file_header.host_os)
 +  {
 +  case OS_MSDOS:
 +  case OS_OS2:
 +  case OS_WIN32:
 +    rar->mode = archive_le32dec(file_header.file_attr);
 +    if (rar->mode & FILE_ATTRIBUTE_DIRECTORY)
 +      rar->mode = AE_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
 +    else
 +      rar->mode = AE_IFREG;
 +    rar->mode |= S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
 +    break;
 +
 +  case OS_UNIX:
 +  case OS_MAC_OS:
 +  case OS_BEOS:
 +    rar->mode = archive_le32dec(file_header.file_attr);
 +    break;
 +
 +  default:
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Unknown file attributes from RAR file's host OS");
 +    return (ARCHIVE_FATAL);
 +  }
 +
-   rar->bytes_remaining = rar->packed_size;
 +  rar->bytes_uncopied = rar->bytes_unconsumed = 0;
-   rar->lzss.position = rar->dictionary_size = rar->offset = 0;
++  rar->lzss.position = rar->offset = 0;
++  rar->offset_seek = 0;
++  rar->dictionary_size = 0;
 +  rar->offset_outgoing = 0;
 +  rar->br.cache_avail = 0;
 +  rar->br.avail_in = 0;
 +  rar->crc_calculated = 0;
 +  rar->entry_eof = 0;
 +  rar->valid = 1;
 +  rar->is_ppmd_block = 0;
 +  rar->start_new_table = 1;
 +  free(rar->unp_buffer);
 +  rar->unp_buffer = NULL;
 +  rar->unp_offset = 0;
 +  rar->unp_buffer_size = UNP_BUFFER_SIZE;
 +  memset(rar->lengthtable, 0, sizeof(rar->lengthtable));
 +  __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
 +  rar->ppmd_valid = rar->ppmd_eod = 0;
 +
 +  /* Don't set any archive entries for non-file header types */
 +  if (head_type == NEWSUB_HEAD)
 +    return ret;
 +
 +  archive_entry_set_mtime(entry, rar->mtime, rar->mnsec);
 +  archive_entry_set_ctime(entry, rar->ctime, rar->cnsec);
 +  archive_entry_set_atime(entry, rar->atime, rar->ansec);
 +  archive_entry_set_size(entry, rar->unp_size);
 +  archive_entry_set_mode(entry, rar->mode);
 +
 +  if (archive_entry_copy_pathname_l(entry, filename, filename_size, fn_sconv))
 +  {
 +    if (errno == ENOMEM)
 +    {
 +      archive_set_error(&a->archive, ENOMEM,
 +                        "Can't allocate memory for Pathname");
 +      return (ARCHIVE_FATAL);
 +    }
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Pathname cannot be converted from %s to current locale.",
 +                      archive_string_conversion_charset_name(fn_sconv));
 +    ret = (ARCHIVE_WARN);
 +  }
 +
 +  if (((rar->mode) & AE_IFMT) == AE_IFLNK)
 +  {
 +    /* Make sure a symbolic-link file does not have its body. */
 +    rar->bytes_remaining = 0;
 +    archive_entry_set_size(entry, 0);
 +
 +    /* Read a symbolic-link name. */
 +    if ((ret2 = read_symlink_stored(a, entry, sconv)) < (ARCHIVE_WARN))
 +      return ret2;
 +    if (ret > ret2)
 +      ret = ret2;
 +  }
 +
 +  if (rar->bytes_remaining == 0)
 +    rar->entry_eof = 1;
 +
 +  return ret;
 +}
 +
 +static time_t
- get_time(int time)
++get_time(int ttime)
 +{
 +  struct tm tm;
-   tm.tm_sec = 2 * (time & 0x1f);
-   tm.tm_min = (time >> 5) & 0x3f;
-   tm.tm_hour = (time >> 11) & 0x1f;
-   tm.tm_mday = (time >> 16) & 0x1f;
-   tm.tm_mon = ((time >> 21) & 0x0f) - 1;
-   tm.tm_year = ((time >> 25) & 0x7f) + 80;
++  tm.tm_sec = 2 * (ttime & 0x1f);
++  tm.tm_min = (ttime >> 5) & 0x3f;
++  tm.tm_hour = (ttime >> 11) & 0x1f;
++  tm.tm_mday = (ttime >> 16) & 0x1f;
++  tm.tm_mon = ((ttime >> 21) & 0x0f) - 1;
++  tm.tm_year = ((ttime >> 25) & 0x7f) + 80;
 +  tm.tm_isdst = -1;
 +  return mktime(&tm);
 +}
 +
 +static int
 +read_exttime(const char *p, struct rar *rar, const char *endp)
 +{
 +  unsigned rmode, flags, rem, j, count;
-   int time, i;
++  int ttime, i;
 +  struct tm *tm;
 +  time_t t;
 +  long nsec;
 +
 +  if (p + 2 > endp)
 +    return (-1);
 +  flags = archive_le16dec(p);
 +  p += 2;
 +
 +  for (i = 3; i >= 0; i--)
 +  {
 +    t = 0;
 +    if (i == 3)
 +      t = rar->mtime;
 +    rmode = flags >> i * 4;
 +    if (rmode & 8)
 +    {
 +      if (!t)
 +      {
 +        if (p + 4 > endp)
 +          return (-1);
-         time = archive_le32dec(p);
-         t = get_time(time);
++        ttime = archive_le32dec(p);
++        t = get_time(ttime);
 +        p += 4;
 +      }
 +      rem = 0;
 +      count = rmode & 3;
 +      if (p + count > endp)
 +        return (-1);
 +      for (j = 0; j < count; j++)
 +      {
 +        rem = ((*p) << 16) | (rem >> 8);
 +        p++;
 +      }
 +      tm = localtime(&t);
 +      nsec = tm->tm_sec + rem / NS_UNIT;
 +      if (rmode & 4)
 +      {
 +        tm->tm_sec++;
 +        t = mktime(tm);
 +      }
 +      if (i == 3)
 +      {
 +        rar->mtime = t;
 +        rar->mnsec = nsec;
 +      }
 +      else if (i == 2)
 +      {
 +        rar->ctime = t;
 +        rar->cnsec = nsec;
 +      }
 +      else if (i == 1)
 +      {
 +        rar->atime = t;
 +        rar->ansec = nsec;
 +      }
 +      else
 +      {
 +        rar->arctime = t;
 +        rar->arcnsec = nsec;
 +      }
 +    }
 +  }
 +  return (0);
 +}
 +
 +static int
 +read_symlink_stored(struct archive_read *a, struct archive_entry *entry,
 +                    struct archive_string_conv *sconv)
 +{
 +  const void *h;
 +  const char *p;
 +  struct rar *rar;
 +  int ret = (ARCHIVE_OK);
 +
 +  rar = (struct rar *)(a->format->data);
-   if ((h = __archive_read_ahead(a, rar->packed_size, NULL)) == NULL)
++  if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL)
 +    return (ARCHIVE_FATAL);
 +  p = h;
 +
-   if (archive_entry_copy_symlink_l(entry, p, rar->packed_size, sconv))
++  if (archive_entry_copy_symlink_l(entry,
++      p, (size_t)rar->packed_size, sconv))
 +  {
 +    if (errno == ENOMEM)
 +    {
 +      archive_set_error(&a->archive, ENOMEM,
 +                        "Can't allocate memory for link");
 +      return (ARCHIVE_FATAL);
 +    }
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "link cannot be converted from %s to current locale.",
 +                      archive_string_conversion_charset_name(sconv));
 +    ret = (ARCHIVE_WARN);
 +  }
 +  __archive_read_consume(a, rar->packed_size);
 +  return ret;
 +}
 +
 +static int
 +read_data_stored(struct archive_read *a, const void **buff, size_t *size,
 +                 int64_t *offset)
 +{
 +  struct rar *rar;
 +  ssize_t bytes_avail;
 +
 +  rar = (struct rar *)(a->format->data);
-   if (rar->bytes_remaining == 0)
++  if (rar->bytes_remaining == 0 &&
++    !(rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER))
 +  {
 +    *buff = NULL;
 +    *size = 0;
 +    *offset = rar->offset;
 +    if (rar->file_crc != rar->crc_calculated) {
 +      archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                        "File CRC error");
 +      return (ARCHIVE_FATAL);
 +    }
 +    rar->entry_eof = 1;
 +    return (ARCHIVE_EOF);
 +  }
 +
-   *buff = __archive_read_ahead(a, 1, &bytes_avail);
++  *buff = rar_read_ahead(a, 1, &bytes_avail);
 +  if (bytes_avail <= 0)
 +  {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Truncated RAR file data");
 +    return (ARCHIVE_FATAL);
 +  }
-   if (bytes_avail > rar->bytes_remaining)
-     bytes_avail = rar->bytes_remaining;
 +
 +  *size = bytes_avail;
 +  *offset = rar->offset;
 +  rar->offset += bytes_avail;
++  rar->offset_seek += bytes_avail;
 +  rar->bytes_remaining -= bytes_avail;
 +  rar->bytes_unconsumed = bytes_avail;
 +  /* Calculate File CRC. */
-   rar->crc_calculated = crc32(rar->crc_calculated, *buff, bytes_avail);
++  rar->crc_calculated = crc32(rar->crc_calculated, *buff,
++    (unsigned)bytes_avail);
 +  return (ARCHIVE_OK);
 +}
 +
 +static int
 +read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
 +               int64_t *offset)
 +{
 +  struct rar *rar;
 +  int64_t start, end, actualend;
 +  size_t bs;
 +  int ret = (ARCHIVE_OK), sym, code, lzss_offset, length, i;
 +
 +  rar = (struct rar *)(a->format->data);
 +
 +  do {
 +    if (!rar->valid)
 +      return (ARCHIVE_FATAL);
 +    if (rar->ppmd_eod ||
 +       (rar->dictionary_size && rar->offset >= rar->unp_size))
 +    {
 +      if (rar->unp_offset > 0) {
 +        /*
 +         * We have unprocessed extracted data. write it out.
 +         */
 +        *buff = rar->unp_buffer;
 +        *size = rar->unp_offset;
 +        *offset = rar->offset_outgoing;
 +        rar->offset_outgoing += *size;
 +        /* Calculate File CRC. */
-         rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
++        rar->crc_calculated = crc32(rar->crc_calculated, *buff,
++          (unsigned)*size);
 +        rar->unp_offset = 0;
 +        return (ARCHIVE_OK);
 +      }
 +      *buff = NULL;
 +      *size = 0;
 +      *offset = rar->offset;
 +      if (rar->file_crc != rar->crc_calculated) {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                          "File CRC error");
 +        return (ARCHIVE_FATAL);
 +      }
 +      rar->entry_eof = 1;
 +      return (ARCHIVE_EOF);
 +    }
 +
 +    if (!rar->is_ppmd_block && rar->dictionary_size && rar->bytes_uncopied > 0)
 +    {
 +      if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
 +        bs = rar->unp_buffer_size - rar->unp_offset;
 +      else
-         bs = rar->bytes_uncopied;
-       ret = copy_from_lzss_window(a, buff, rar->offset, bs);
++        bs = (size_t)rar->bytes_uncopied;
++      ret = copy_from_lzss_window(a, buff, rar->offset, (int)bs);
 +      if (ret != ARCHIVE_OK)
 +        return (ret);
 +      rar->offset += bs;
 +      rar->bytes_uncopied -= bs;
 +      if (*buff != NULL) {
 +        rar->unp_offset = 0;
 +        *size = rar->unp_buffer_size;
 +        *offset = rar->offset_outgoing;
 +        rar->offset_outgoing += *size;
 +        /* Calculate File CRC. */
-         rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
++        rar->crc_calculated = crc32(rar->crc_calculated, *buff,
++          (unsigned)*size);
 +        return (ret);
 +      }
 +      continue;
 +    }
 +
 +    if (!rar->br.next_in &&
 +      (ret = rar_br_preparation(a, &(rar->br))) < ARCHIVE_WARN)
 +      return (ret);
 +    if (rar->start_new_table && ((ret = parse_codes(a)) < (ARCHIVE_WARN)))
 +      return (ret);
 +
 +    if (rar->is_ppmd_block)
 +    {
 +      if ((sym = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
 +        &rar->ppmd7_context, &rar->range_dec.p)) < 0)
 +      {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                          "Invalid symbol");
 +        return (ARCHIVE_FATAL);
 +      }
 +      if(sym != rar->ppmd_escape)
 +      {
 +        lzss_emit_literal(rar, sym);
 +        rar->bytes_uncopied++;
 +      }
 +      else
 +      {
 +        if ((code = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
 +          &rar->ppmd7_context, &rar->range_dec.p)) < 0)
 +        {
 +          archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                            "Invalid symbol");
 +          return (ARCHIVE_FATAL);
 +        }
 +
 +        switch(code)
 +        {
 +          case 0:
 +            rar->start_new_table = 1;
 +            return read_data_compressed(a, buff, size, offset);
 +
 +          case 2:
 +            rar->ppmd_eod = 1;/* End Of ppmd Data. */
 +            continue;
 +
 +          case 3:
 +            archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +                              "Parsing filters is unsupported.");
 +            return (ARCHIVE_FAILED);
 +
 +          case 4:
 +            lzss_offset = 0;
 +            for (i = 2; i >= 0; i--)
 +            {
 +              if ((code = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
 +                &rar->ppmd7_context, &rar->range_dec.p)) < 0)
 +              {
 +                archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                                  "Invalid symbol");
 +                return (ARCHIVE_FATAL);
 +              }
 +              lzss_offset |= code << (i * 8);
 +            }
 +            if ((length = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
 +              &rar->ppmd7_context, &rar->range_dec.p)) < 0)
 +            {
 +              archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                                "Invalid symbol");
 +              return (ARCHIVE_FATAL);
 +            }
 +            lzss_emit_match(rar, lzss_offset + 2, length + 32);
 +            rar->bytes_uncopied += length + 32;
 +            break;
 +
 +          case 5:
 +            if ((length = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
 +              &rar->ppmd7_context, &rar->range_dec.p)) < 0)
 +            {
 +              archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                                "Invalid symbol");
 +              return (ARCHIVE_FATAL);
 +            }
 +            lzss_emit_match(rar, 1, length + 4);
 +            rar->bytes_uncopied += length + 4;
 +            break;
 +
 +         default:
 +           lzss_emit_literal(rar, sym);
 +           rar->bytes_uncopied++;
 +        }
 +      }
 +    }
 +    else
 +    {
 +      start = rar->offset;
 +      end = start + rar->dictionary_size;
 +      rar->filterstart = INT64_MAX;
 +
 +      if ((actualend = expand(a, end)) < 0)
 +        return ((int)actualend);
 +
 +      rar->bytes_uncopied = actualend - start;
 +      if (rar->bytes_uncopied == 0) {
 +          /* Broken RAR files cause this case.
 +          * NOTE: If this case were possible on a normal RAR file
 +          * we would find out where it was actually bad and
 +          * what we would do to solve it. */
 +          archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                            "Internal error extracting RAR file");
 +          return (ARCHIVE_FATAL);
 +      }
 +    }
 +    if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
 +      bs = rar->unp_buffer_size - rar->unp_offset;
 +    else
-       bs = rar->bytes_uncopied;
-     ret = copy_from_lzss_window(a, buff, rar->offset, bs);
++      bs = (size_t)rar->bytes_uncopied;
++    ret = copy_from_lzss_window(a, buff, rar->offset, (int)bs);
 +    if (ret != ARCHIVE_OK)
 +      return (ret);
 +    rar->offset += bs;
 +    rar->bytes_uncopied -= bs;
 +    /*
 +     * If *buff is NULL, it means unp_buffer is not full.
 +     * So we have to continue extracting a RAR file.
 +     */
 +  } while (*buff == NULL);
 +
 +  rar->unp_offset = 0;
 +  *size = rar->unp_buffer_size;
 +  *offset = rar->offset_outgoing;
 +  rar->offset_outgoing += *size;
 +  /* Calculate File CRC. */
-   rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
++  rar->crc_calculated = crc32(rar->crc_calculated, *buff, (unsigned)*size);
 +  return ret;
 +}
 +
 +static int
 +parse_codes(struct archive_read *a)
 +{
 +  int i, j, val, n, r;
 +  unsigned char bitlengths[MAX_SYMBOLS], zerocount, ppmd_flags;
 +  unsigned int maxorder;
 +  struct huffman_code precode;
 +  struct rar *rar = (struct rar *)(a->format->data);
 +  struct rar_br *br = &(rar->br);
 +
 +  free_codes(a);
 +
 +  /* Skip to the next byte */
 +  rar_br_consume_unalined_bits(br);
 +
 +  /* PPMd block flag */
 +  if (!rar_br_read_ahead(a, br, 1))
 +    goto truncated_data;
 +  if ((rar->is_ppmd_block = rar_br_bits(br, 1)) != 0)
 +  {
 +    rar_br_consume(br, 1);
 +    if (!rar_br_read_ahead(a, br, 7))
 +      goto truncated_data;
 +    ppmd_flags = rar_br_bits(br, 7);
 +    rar_br_consume(br, 7);
 +
 +    /* Memory is allocated in MB */
 +    if (ppmd_flags & 0x20)
 +    {
 +      if (!rar_br_read_ahead(a, br, 8))
 +        goto truncated_data;
 +      rar->dictionary_size = (rar_br_bits(br, 8) + 1) << 20;
 +      rar_br_consume(br, 8);
 +    }
 +
 +    if (ppmd_flags & 0x40)
 +    {
 +      if (!rar_br_read_ahead(a, br, 8))
 +        goto truncated_data;
 +      rar->ppmd_escape = rar->ppmd7_context.InitEsc = rar_br_bits(br, 8);
 +      rar_br_consume(br, 8);
 +    }
 +    else
 +      rar->ppmd_escape = 2;
 +
 +    if (ppmd_flags & 0x20)
 +    {
 +      maxorder = (ppmd_flags & 0x1F) + 1;
 +      if(maxorder > 16)
 +        maxorder = 16 + (maxorder - 16) * 3;
 +
 +      if (maxorder == 1)
 +      {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                          "Truncated RAR file data");
 +        return (ARCHIVE_FATAL);
 +      }
 +
 +      /* Make sure ppmd7_contest is freed before Ppmd7_Construct
 +       * because reading a broken file cause this abnormal sequence. */
 +      __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
 +
 +      rar->bytein.a = a;
 +      rar->bytein.Read = &ppmd_read;
 +      __archive_ppmd7_functions.PpmdRAR_RangeDec_CreateVTable(&rar->range_dec);
 +      rar->range_dec.Stream = &rar->bytein;
 +      __archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context);
 +
 +      if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
 +        rar->dictionary_size, &g_szalloc))
 +      {
 +        archive_set_error(&a->archive, ENOMEM,
 +                          "Out of memory");
 +        return (ARCHIVE_FATAL);
 +      }
 +      if (!__archive_ppmd7_functions.PpmdRAR_RangeDec_Init(&rar->range_dec))
 +      {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                          "Unable to initialize PPMd range decoder");
 +        return (ARCHIVE_FATAL);
 +      }
 +      __archive_ppmd7_functions.Ppmd7_Init(&rar->ppmd7_context, maxorder);
 +      rar->ppmd_valid = 1;
 +    }
 +    else
 +    {
 +      if (!rar->ppmd_valid) {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                          "Invalid PPMd sequence");
 +        return (ARCHIVE_FATAL);
 +      }
 +      if (!__archive_ppmd7_functions.PpmdRAR_RangeDec_Init(&rar->range_dec))
 +      {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                          "Unable to initialize PPMd range decoder");
 +        return (ARCHIVE_FATAL);
 +      }
 +    }
 +  }
 +  else
 +  {
 +    rar_br_consume(br, 1);
 +
 +    /* Keep existing table flag */
 +    if (!rar_br_read_ahead(a, br, 1))
 +      goto truncated_data;
 +    if (!rar_br_bits(br, 1))
 +      memset(rar->lengthtable, 0, sizeof(rar->lengthtable));
 +    rar_br_consume(br, 1);
 +
 +    memset(&bitlengths, 0, sizeof(bitlengths));
 +    for (i = 0; i < MAX_SYMBOLS;)
 +    {
 +      if (!rar_br_read_ahead(a, br, 4))
 +        goto truncated_data;
 +      bitlengths[i++] = rar_br_bits(br, 4);
 +      rar_br_consume(br, 4);
 +      if (bitlengths[i-1] == 0xF)
 +      {
 +        if (!rar_br_read_ahead(a, br, 4))
 +          goto truncated_data;
 +        zerocount = rar_br_bits(br, 4);
 +        rar_br_consume(br, 4);
 +        if (zerocount)
 +        {
 +          i--;
 +          for (j = 0; j < zerocount + 2 && i < MAX_SYMBOLS; j++)
 +            bitlengths[i++] = 0;
 +        }
 +      }
 +    }
 +
 +    memset(&precode, 0, sizeof(precode));
 +    r = create_code(a, &precode, bitlengths, MAX_SYMBOLS, MAX_SYMBOL_LENGTH);
 +    if (r != ARCHIVE_OK) {
 +      free(precode.tree);
 +      free(precode.table);
 +      return (r);
 +    }
 +
 +    for (i = 0; i < HUFFMAN_TABLE_SIZE;)
 +    {
 +      if ((val = read_next_symbol(a, &precode)) < 0) {
 +        free(precode.tree);
 +        free(precode.table);
 +        return (ARCHIVE_FATAL);
 +      }
 +      if (val < 16)
 +      {
 +        rar->lengthtable[i] = (rar->lengthtable[i] + val) & 0xF;
 +        i++;
 +      }
 +      else if (val < 18)
 +      {
 +        if (i == 0)
 +        {
 +          free(precode.tree);
 +          free(precode.table);
 +          archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                            "Internal error extracting RAR file.");
 +          return (ARCHIVE_FATAL);
 +        }
 +
 +        if(val == 16) {
 +          if (!rar_br_read_ahead(a, br, 3)) {
 +            free(precode.tree);
 +            free(precode.table);
 +            goto truncated_data;
 +          }
 +          n = rar_br_bits(br, 3) + 3;
 +          rar_br_consume(br, 3);
 +        } else {
 +          if (!rar_br_read_ahead(a, br, 7)) {
 +            free(precode.tree);
 +            free(precode.table);
 +            goto truncated_data;
 +          }
 +          n = rar_br_bits(br, 7) + 11;
 +          rar_br_consume(br, 7);
 +        }
 +
 +        for (j = 0; j < n && i < HUFFMAN_TABLE_SIZE; j++)
 +        {
 +          rar->lengthtable[i] = rar->lengthtable[i-1];
 +          i++;
 +        }
 +      }
 +      else
 +      {
 +        if(val == 18) {
 +          if (!rar_br_read_ahead(a, br, 3)) {
 +            free(precode.tree);
 +            free(precode.table);
 +            goto truncated_data;
 +          }
 +          n = rar_br_bits(br, 3) + 3;
 +          rar_br_consume(br, 3);
 +        } else {
 +          if (!rar_br_read_ahead(a, br, 7)) {
 +            free(precode.tree);
 +            free(precode.table);
 +            goto truncated_data;
 +          }
 +          n = rar_br_bits(br, 7) + 11;
 +          rar_br_consume(br, 7);
 +        }
 +
 +        for(j = 0; j < n && i < HUFFMAN_TABLE_SIZE; j++)
 +          rar->lengthtable[i++] = 0;
 +      }
 +    }
 +    free(precode.tree);
 +    free(precode.table);
 +
 +    r = create_code(a, &rar->maincode, &rar->lengthtable[0], MAINCODE_SIZE,
 +                MAX_SYMBOL_LENGTH);
 +    if (r != ARCHIVE_OK)
 +      return (r);
 +    r = create_code(a, &rar->offsetcode, &rar->lengthtable[MAINCODE_SIZE],
 +                OFFSETCODE_SIZE, MAX_SYMBOL_LENGTH);
 +    if (r != ARCHIVE_OK)
 +      return (r);
 +    r = create_code(a, &rar->lowoffsetcode,
 +                &rar->lengthtable[MAINCODE_SIZE + OFFSETCODE_SIZE],
 +                LOWOFFSETCODE_SIZE, MAX_SYMBOL_LENGTH);
 +    if (r != ARCHIVE_OK)
 +      return (r);
 +    r = create_code(a, &rar->lengthcode,
 +                &rar->lengthtable[MAINCODE_SIZE + OFFSETCODE_SIZE +
 +                LOWOFFSETCODE_SIZE], LENGTHCODE_SIZE, MAX_SYMBOL_LENGTH);
 +    if (r != ARCHIVE_OK)
 +      return (r);
 +  }
 +
 +  if (!rar->dictionary_size || !rar->lzss.window)
 +  {
 +    /* Seems as though dictionary sizes are not used. Even so, minimize
 +     * memory usage as much as possible.
 +     */
++    void *new_window;
++    unsigned int new_size;
++
 +    if (rar->unp_size >= DICTIONARY_MAX_SIZE)
-       rar->dictionary_size = DICTIONARY_MAX_SIZE;
++      new_size = DICTIONARY_MAX_SIZE;
 +    else
-       rar->dictionary_size = rar_fls(rar->unp_size) << 1;
-     rar->lzss.window = (unsigned char *)realloc(rar->lzss.window,
-                                                 rar->dictionary_size);
-     if (rar->lzss.window == NULL) {
++      new_size = rar_fls((unsigned int)rar->unp_size) << 1;
++    new_window = realloc(rar->lzss.window, new_size);
++    if (new_window == NULL) {
 +      archive_set_error(&a->archive, ENOMEM,
 +                        "Unable to allocate memory for uncompressed data.");
 +      return (ARCHIVE_FATAL);
 +    }
++    rar->lzss.window = (unsigned char *)new_window;
++    rar->dictionary_size = new_size;
 +    memset(rar->lzss.window, 0, rar->dictionary_size);
 +    rar->lzss.mask = rar->dictionary_size - 1;
 +  }
 +
 +  rar->start_new_table = 0;
 +  return (ARCHIVE_OK);
 +truncated_data:
 +  archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                    "Truncated RAR file data");
 +  rar->valid = 0;
 +  return (ARCHIVE_FATAL);
 +}
 +
 +static void
 +free_codes(struct archive_read *a)
 +{
 +  struct rar *rar = (struct rar *)(a->format->data);
 +  free(rar->maincode.tree);
 +  free(rar->offsetcode.tree);
 +  free(rar->lowoffsetcode.tree);
 +  free(rar->lengthcode.tree);
 +  free(rar->maincode.table);
 +  free(rar->offsetcode.table);
 +  free(rar->lowoffsetcode.table);
 +  free(rar->lengthcode.table);
 +  memset(&rar->maincode, 0, sizeof(rar->maincode));
 +  memset(&rar->offsetcode, 0, sizeof(rar->offsetcode));
 +  memset(&rar->lowoffsetcode, 0, sizeof(rar->lowoffsetcode));
 +  memset(&rar->lengthcode, 0, sizeof(rar->lengthcode));
 +}
 +
 +
 +static int
 +read_next_symbol(struct archive_read *a, struct huffman_code *code)
 +{
 +  unsigned char bit;
 +  unsigned int bits;
 +  int length, value, node;
 +  struct rar *rar;
 +  struct rar_br *br;
 +
 +  if (!code->table)
 +  {
 +    if (make_table(a, code) != (ARCHIVE_OK))
 +      return -1;
 +  }
 +
 +  rar = (struct rar *)(a->format->data);
 +  br = &(rar->br);
 +
 +  /* Look ahead (peek) at bits */
 +  if (!rar_br_read_ahead(a, br, code->tablesize)) {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Truncated RAR file data");
 +    rar->valid = 0;
 +    return -1;
 +  }
 +  bits = rar_br_bits(br, code->tablesize);
 +
 +  length = code->table[bits].length;
 +  value = code->table[bits].value;
 +
 +  if (length < 0)
 +  {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Invalid prefix code in bitstream");
 +    return -1;
 +  }
 +
 +  if (length <= code->tablesize)
 +  {
 +    /* Skip length bits */
 +    rar_br_consume(br, length);
 +    return value;
 +  }
 +
 +  /* Skip tablesize bits */
 +  rar_br_consume(br, code->tablesize);
 +
 +  node = value;
 +  while (!(code->tree[node].branches[0] ==
 +    code->tree[node].branches[1]))
 +  {
 +    if (!rar_br_read_ahead(a, br, 1)) {
 +      archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                        "Truncated RAR file data");
 +      rar->valid = 0;
 +      return -1;
 +    }
 +    bit = rar_br_bits(br, 1);
 +    rar_br_consume(br, 1);
 +
 +    if (code->tree[node].branches[bit] < 0)
 +    {
 +      archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                        "Invalid prefix code in bitstream");
 +      return -1;
 +    }
 +    node = code->tree[node].branches[bit];
 +  }
 +
 +  return code->tree[node].branches[0];
 +}
 +
 +static int
 +create_code(struct archive_read *a, struct huffman_code *code,
 +            unsigned char *lengths, int numsymbols, char maxlength)
 +{
 +  int i, j, codebits = 0, symbolsleft = numsymbols;
 +
 +  if (new_node(code) < 0) {
 +    archive_set_error(&a->archive, ENOMEM,
 +                      "Unable to allocate memory for node data.");
 +    return (ARCHIVE_FATAL);
 +  }
 +  code->numentries = 1;
 +  code->minlength = INT_MAX;
 +  code->maxlength = INT_MIN;
 +  codebits = 0;
 +  for(i = 1; i <= maxlength; i++)
 +  {
 +    for(j = 0; j < numsymbols; j++)
 +    {
 +      if (lengths[j] != i) continue;
 +      if (add_value(a, code, j, codebits, i) != ARCHIVE_OK)
 +        return (ARCHIVE_FATAL);
 +      codebits++;
 +      if (--symbolsleft <= 0) { break; break; }
 +    }
 +    codebits <<= 1;
 +  }
 +  return (ARCHIVE_OK);
 +}
 +
 +static int
 +add_value(struct archive_read *a, struct huffman_code *code, int value,
 +          int codebits, int length)
 +{
 +  int repeatpos, lastnode, bitpos, bit, repeatnode, nextnode;
 +
 +  free(code->table);
 +  code->table = NULL;
 +
 +  if(length > code->maxlength)
 +    code->maxlength = length;
 +  if(length < code->minlength)
 +    code->minlength = length;
 +
 +  repeatpos = -1;
 +  if (repeatpos == 0 || (repeatpos >= 0
 +    && (((codebits >> (repeatpos - 1)) & 3) == 0
 +    || ((codebits >> (repeatpos - 1)) & 3) == 3)))
 +  {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Invalid repeat position");
 +    return (ARCHIVE_FATAL);
 +  }
 +
 +  lastnode = 0;
 +  for (bitpos = length - 1; bitpos >= 0; bitpos--)
 +  {
 +    bit = (codebits >> bitpos) & 1;
 +
 +    /* Leaf node check */
 +    if (code->tree[lastnode].branches[0] ==
 +      code->tree[lastnode].branches[1])
 +    {
 +      archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                        "Prefix found");
 +      return (ARCHIVE_FATAL);
 +    }
 +
 +    if (bitpos == repeatpos)
 +    {
 +      /* Open branch check */
 +      if (!(code->tree[lastnode].branches[bit] < 0))
 +      {
 +        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                          "Invalid repeating code");
 +        return (ARCHIVE_FATAL);
 +      }
 +
 +      if ((repeatnode = new_node(code)) < 0) {
 +        archive_set_error(&a->archive, ENOMEM,
 +                          "Unable to allocate memory for node data.");
 +        return (ARCHIVE_FATAL);
 +      }
 +      if ((nextnode = new_node(code)) < 0) {
 +        archive_set_error(&a->archive, ENOMEM,
 +                          "Unable to allocate memory for node data.");
 +        return (ARCHIVE_FATAL);
 +      }
 +
 +      /* Set branches */
 +      code->tree[lastnode].branches[bit] = repeatnode;
 +      code->tree[repeatnode].branches[bit] = repeatnode;
 +      code->tree[repeatnode].branches[bit^1] = nextnode;
 +      lastnode = nextnode;
 +
 +      bitpos++; /* terminating bit already handled, skip it */
 +    }
 +    else
 +    {
 +      /* Open branch check */
 +      if (code->tree[lastnode].branches[bit] < 0)
 +      {
 +        if (new_node(code) < 0) {
 +          archive_set_error(&a->archive, ENOMEM,
 +                            "Unable to allocate memory for node data.");
 +          return (ARCHIVE_FATAL);
 +        }
 +        code->tree[lastnode].branches[bit] = code->numentries++;
 +      }
 +
 +      /* set to branch */
 +      lastnode = code->tree[lastnode].branches[bit];
 +    }
 +  }
 +
 +  if (!(code->tree[lastnode].branches[0] == -1
 +    && code->tree[lastnode].branches[1] == -2))
 +  {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Prefix found");
 +    return (ARCHIVE_FATAL);
 +  }
 +
 +  /* Set leaf value */
 +  code->tree[lastnode].branches[0] = value;
 +  code->tree[lastnode].branches[1] = value;
 +
 +  return (ARCHIVE_OK);
 +}
 +
 +static int
 +new_node(struct huffman_code *code)
 +{
-   code->tree = (struct huffman_tree_node *)realloc(code->tree,
-     (code->numentries + 1) * sizeof(*code->tree));
-   if (code->tree == NULL)
++  void *new_tree;
++
++  new_tree = realloc(code->tree, (code->numentries + 1) * sizeof(*code->tree));
++  if (new_tree == NULL)
 +    return (-1);
++  code->tree = (struct huffman_tree_node *)new_tree;
 +  code->tree[code->numentries].branches[0] = -1;
 +  code->tree[code->numentries].branches[1] = -2;
 +  return 1;
 +}
 +
 +static int
 +make_table(struct archive_read *a, struct huffman_code *code)
 +{
 +  if (code->maxlength < code->minlength || code->maxlength > 10)
 +    code->tablesize = 10;
 +  else
 +    code->tablesize = code->maxlength;
 +
 +  code->table =
-     (struct huffman_table_entry *)malloc(sizeof(*code->table)
-     * (1 << code->tablesize));
++    (struct huffman_table_entry *)calloc(1, sizeof(*code->table)
++    * ((size_t)1 << code->tablesize));
 +
 +  return make_table_recurse(a, code, 0, code->table, 0, code->tablesize);
 +}
 +
 +static int
 +make_table_recurse(struct archive_read *a, struct huffman_code *code, int node,
 +                   struct huffman_table_entry *table, int depth,
 +                   int maxdepth)
 +{
 +  int currtablesize, i, ret = (ARCHIVE_OK);
 +
 +  if (!code->tree)
 +  {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Huffman tree was not created.");
 +    return (ARCHIVE_FATAL);
 +  }
 +  if (node < 0 || node >= code->numentries)
 +  {
 +    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                      "Invalid location to Huffman tree specified.");
 +    return (ARCHIVE_FATAL);
 +  }
 +
 +  currtablesize = 1 << (maxdepth - depth);
 +
 +  if (code->tree[node].branches[0] ==
 +    code->tree[node].branches[1])
 +  {
 +    for(i = 0; i < currtablesize; i++)
 +    {
 +      table[i].length = depth;
 +      table[i].value = code->tree[node].branches[0];
 +    }
 +  }
 +  else if (node < 0)
 +  {
 +    for(i = 0; i < currtablesize; i++)
 +      table[i].length = -1;
 +  }
 +  else
 +  {
 +    if(depth == maxdepth)
 +    {
 +      table[0].length = maxdepth + 1;
 +      table[0].value = node;
 +    }
 +    else
 +    {
 +      ret |= make_table_recurse(a, code, code->tree[node].branches[0], table,
 +                                depth + 1, maxdepth);
 +      ret |= make_table_recurse(a, code, code->tree[node].branches[1],
 +                         table + currtablesize / 2, depth + 1, maxdepth);
 +    }
 +  }
 +  return ret;
 +}
 +
 +static int64_t
 +expand(struct archive_read *a, int64_t end)
 +{
 +  static const unsigned char lengthbases[] =
 +    {   0,   1,   2,   3,   4,   5,   6,
 +        7,   8,  10,  12,  14,  16,  20,
 +       24,  28,  32,  40,  48,  56,  64,
 +       80,  96, 112, 128, 160, 192, 224 };
 +  static const unsigned char lengthbits[] =
 +    { 0, 0, 0, 0, 0, 0, 0,
 +      0, 1, 1, 1, 1, 2, 2,
 +      2, 2, 3, 3, 3, 3, 4,
 +      4, 4, 4, 5, 5, 5, 5 };
 +  static const unsigned int offsetbases[] =
 +    {       0,       1,       2,       3,       4,       6,
 +            8,      12,      16,      24,      32,      48,
 +           64,      96,     128,     192,     256,     384,
 +          512,     768,    1024,    1536,    2048,    3072,
 +         4096,    6144,    8192,   12288,   16384,   24576,
 +        32768,   49152,   65536,   98304,  131072,  196608,
 +       262144,  327680,  393216,  458752,  524288,  589824,
 +       655360,  720896,  786432,  851968,  917504,  983040,
 +      1048576, 1310720, 1572864, 1835008, 2097152, 2359296,
 +      2621440, 2883584, 3145728, 3407872, 3670016, 3932160 };
 +  static const unsigned char offsetbits[] =
 +    {  0,  0,  0,  0,  1,  1,  2,  2,  3,  3,  4,  4,
 +       5,  5,  6,  6,  7,  7,  8,  8,  9,  9, 10, 10,
 +      11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
 +      16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
 +      18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 };
 +  static const unsigned char shortbases[] =
 +    { 0, 4, 8, 16, 32, 64, 128, 192 };
 +  static const unsigned char shortbits[] =
 +    { 2, 2, 3, 4, 5, 6, 6, 6 };
 +
 +  int symbol, offs, len, offsindex, lensymbol, i, offssymbol, lowoffsetsymbol;
 +  unsigned char newfile;
 +  struct rar *rar = (struct rar *)(a->format->data);
 +  struct rar_br *br = &(rar->br);
 +
 +  if (rar->filterstart < end)
 +    end = rar->filterstart;
 +
 +  while (1)
 +  {
 +    if (rar->output_last_match &&
 +      lzss_position(&rar->lzss) + rar->lastlength <= end)
 +    {
 +      lzss_emit_match(rar, rar->lastoffset, rar->lastlength);
 +      rar->output_last_match = 0;
 +    }
 +
 +    if(rar->is_ppmd_block || rar->output_last_match ||
 +      lzss_position(&rar->lzss) >= end)
 +      return lzss_position(&rar->lzss);
 +
 +    if ((symbol = read_next_symbol(a, &rar->maincode)) < 0)
 +      return (ARCHIVE_FATAL);
 +    rar->output_last_match = 0;
 +    
 +    if (symbol < 256)
 +    {
 +      lzss_emit_literal(rar, symbol);
 +      continue;
 +    }
 +    else if (symbol == 256)
 +    {
 +      if (!rar_br_read_ahead(a, br, 1))
 +        goto truncated_data;
 +      newfile = !rar_br_bits(br, 1);
 +      rar_br_consume(br, 1);
 +
 +      if(newfile)
 +      {
 +        rar->start_new_block = 1;
 +        if (!rar_br_read_ahead(a, br, 1))
 +          goto truncated_data;
 +        rar->start_new_table = rar_br_bits(br, 1);
 +        rar_br_consume(br, 1);
 +        return lzss_position(&rar->lzss);
 +      }
 +      else
 +      {
 +        if (parse_codes(a) != ARCHIVE_OK)
 +          return (ARCHIVE_FATAL);
 +        continue;
 +      }
 +    }
 +    else if(symbol==257)
 +    {
 +      archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +                        "Parsing filters is unsupported.");
 +      return (ARCHIVE_FAILED);
 +    }
 +    else if(symbol==258)
 +    {
 +      if(rar->lastlength == 0)
 +        continue;
 +
 +      offs = rar->lastoffset;
 +      len = rar->lastlength;
 +    }
 +    else if (symbol <= 262)
 +    {
 +      offsindex = symbol - 259;
 +      offs = rar->oldoffset[offsindex];
 +
 +      if ((lensymbol = read_next_symbol(a, &rar->lengthcode)) < 0)
 +        goto bad_data;
-       if (lensymbol > sizeof(lengthbases)/sizeof(lengthbases[0]))
++      if (lensymbol > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
 +        goto bad_data;
-       if (lensymbol > sizeof(lengthbits)/sizeof(lengthbits[0]))
++      if (lensymbol > (int)(sizeof(lengthbits)/sizeof(lengthbits[0])))
 +        goto bad_data;
 +      len = lengthbases[lensymbol] + 2;
 +      if (lengthbits[lensymbol] > 0) {
 +        if (!rar_br_read_ahead(a, br, lengthbits[lensymbol]))
 +          goto truncated_data;
 +        len += rar_br_bits(br, lengthbits[lensymbol]);
 +        rar_br_consume(br, lengthbits[lensymbol]);
 +      }
 +
 +      for (i = offsindex; i > 0; i--)
 +        rar->oldoffset[i] = rar->oldoffset[i-1];
 +      rar->oldoffset[0] = offs;
 +    }
 +    else if(symbol<=270)
 +    {
 +      offs = shortbases[symbol-263] + 1;
 +      if(shortbits[symbol-263] > 0) {
 +        if (!rar_br_read_ahead(a, br, shortbits[symbol-263]))
 +          goto truncated_data;
 +        offs += rar_br_bits(br, shortbits[symbol-263]);
 +        rar_br_consume(br, shortbits[symbol-263]);
 +      }
 +
 +      len = 2;
 +
 +      for(i = 3; i > 0; i--)
 +        rar->oldoffset[i] = rar->oldoffset[i-1];
 +      rar->oldoffset[0] = offs;
 +    }
 +    else
 +    {
-       if (symbol-271 > sizeof(lengthbases)/sizeof(lengthbases[0]))
++      if (symbol-271 > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
 +        goto bad_data;
-       if (symbol-271 > sizeof(lengthbits)/sizeof(lengthbits[0]))
++      if (symbol-271 > (int)(sizeof(lengthbits)/sizeof(lengthbits[0])))
 +        goto bad_data;
 +      len = lengthbases[symbol-271]+3;
 +      if(lengthbits[symbol-271] > 0) {
 +        if (!rar_br_read_ahead(a, br, lengthbits[symbol-271]))
 +          goto truncated_data;
 +        len += rar_br_bits(br, lengthbits[symbol-271]);
 +        rar_br_consume(br, lengthbits[symbol-271]);
 +      }
 +
 +      if ((offssymbol = read_next_symbol(a, &rar->offsetcode)) < 0)
 +        goto bad_data;
-       if (offssymbol > sizeof(offsetbases)/sizeof(offsetbases[0]))
++      if (offssymbol > (int)(sizeof(offsetbases)/sizeof(offsetbases[0])))
 +        goto bad_data;
-       if (offssymbol > sizeof(offsetbits)/sizeof(offsetbits[0]))
++      if (offssymbol > (int)(sizeof(offsetbits)/sizeof(offsetbits[0])))
 +        goto bad_data;
 +      offs = offsetbases[offssymbol]+1;
 +      if(offsetbits[offssymbol] > 0)
 +      {
 +        if(offssymbol > 9)
 +        {
 +          if(offsetbits[offssymbol] > 4) {
 +            if (!rar_br_read_ahead(a, br, offsetbits[offssymbol] - 4))
 +              goto truncated_data;
 +            offs += rar_br_bits(br, offsetbits[offssymbol] - 4) << 4;
 +            rar_br_consume(br, offsetbits[offssymbol] - 4);
 +	  }
 +
 +          if(rar->numlowoffsetrepeats > 0)
 +          {
 +            rar->numlowoffsetrepeats--;
 +            offs += rar->lastlowoffset;
 +          }
 +          else
 +          {
 +            if ((lowoffsetsymbol =
 +              read_next_symbol(a, &rar->lowoffsetcode)) < 0)
 +              return (ARCHIVE_FATAL);
 +            if(lowoffsetsymbol == 16)
 +            {
 +              rar->numlowoffsetrepeats = 15;
 +              offs += rar->lastlowoffset;
 +            }
 +            else
 +            {
 +              offs += lowoffsetsymbol;
 +              rar->lastlowoffset = lowoffsetsymbol;
 +            }
 +          }
 +        }
 +        else {
 +          if (!rar_br_read_ahead(a, br, offsetbits[offssymbol]))
 +            goto truncated_data;
 +          offs += rar_br_bits(br, offsetbits[offssymbol]);
 +          rar_br_consume(br, offsetbits[offssymbol]);
 +        }
 +      }
 +
 +      if (offs >= 0x40000)
 +        len++;
 +      if (offs >= 0x2000)
 +        len++;
 +
 +      for(i = 3; i > 0; i--)
 +        rar->oldoffset[i] = rar->oldoffset[i-1];
 +      rar->oldoffset[0] = offs;
 +    }
 +
 +    rar->lastoffset = offs;
 +    rar->lastlength = len;
 +    rar->output_last_match = 1;
 +  }
 +truncated_data:
 +  archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                    "Truncated RAR file data");
 +  rar->valid = 0;
 +  return (ARCHIVE_FATAL);
 +bad_data:
 +  archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                    "Bad RAR file data");
 +  return (ARCHIVE_FATAL);
 +}
 +
 +static int
 +copy_from_lzss_window(struct archive_read *a, const void **buffer,
 +                        int64_t startpos, int length)
 +{
 +  int windowoffs, firstpart;
 +  struct rar *rar = (struct rar *)(a->format->data);
 +
 +  if (!rar->unp_buffer)
 +  {
 +    if ((rar->unp_buffer = malloc(rar->unp_buffer_size)) == NULL)
 +    {
 +      archive_set_error(&a->archive, ENOMEM,
 +                        "Unable to allocate memory for uncompressed data.");
 +      return (ARCHIVE_FATAL);
 +    }
 +  }
 +
 +  windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
 +  if(windowoffs + length <= lzss_size(&rar->lzss))
 +    memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs],
 +           length);
 +  else
 +  {
 +    firstpart = lzss_size(&rar->lzss) - windowoffs;
 +    if (firstpart < 0) {
 +      archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +                        "Bad RAR file data");
 +      return (ARCHIVE_FATAL);
 +    }
 +    if (firstpart < length) {
 +      memcpy(&rar->unp_buffer[rar->unp_offset],
 +             &rar->lzss.window[windowoffs], firstpart);
 +      memcpy(&rar->unp_buffer[rar->unp_offset + firstpart],
 +             &rar->lzss.window[0], length - firstpart);
 +    } else
 +      memcpy(&rar->unp_buffer[rar->unp_offset],
 +             &rar->lzss.window[windowoffs], length);
 +  }
 +  rar->unp_offset += length;
 +  if (rar->unp_offset >= rar->unp_buffer_size)
 +    *buffer = rar->unp_buffer;
 +  else
 +    *buffer = NULL;
 +  return (ARCHIVE_OK);
 +}
++
++static const void *
++rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
++{
++  struct rar *rar = (struct rar *)(a->format->data);
++  const void *h = __archive_read_ahead(a, min, avail);
++  int ret;
++  if (avail)
++  {
++    if (a->read_data_is_posix_read && *avail > (ssize_t)a->read_data_requested)
++      *avail = a->read_data_requested;
++    if (*avail > rar->bytes_remaining)
++      *avail = (ssize_t)rar->bytes_remaining;
++    if (*avail < 0)
++      return NULL;
++    else if (*avail == 0 && rar->main_flags & MHD_VOLUME &&
++      rar->file_flags & FHD_SPLIT_AFTER)
++    {
++      ret = archive_read_format_rar_read_header(a, a->entry);
++      if (ret == (ARCHIVE_EOF))
++      {
++        rar->has_endarc_header = 1;
++        ret = archive_read_format_rar_read_header(a, a->entry);
++      }
++      if (ret != (ARCHIVE_OK))
++        return NULL;
++      return rar_read_ahead(a, min, avail);
++    }
++  }
++  return h;
++}
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
index 0834e6f,0000000..2530e34
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
@@@ -1,3324 -1,0 +1,3331 @@@
 +/*-
 + * Copyright (c) 2009 Michihiro NAKAJIMA
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD$");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#if HAVE_LIBXML_XMLREADER_H
 +#include <libxml/xmlreader.h>
 +#elif HAVE_BSDXML_H
 +#include <bsdxml.h>
 +#elif HAVE_EXPAT_H
 +#include <expat.h>
 +#endif
 +#ifdef HAVE_BZLIB_H
 +#include <cm_bzlib.h>
 +#endif
 +#if HAVE_LZMA_H
 +#include <lzma.h>
 +#elif HAVE_LZMADEC_H
 +#include <lzmadec.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_crypto_private.h"
 +#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_private.h"
 +#include "archive_read_private.h"
 +
 +#if (!defined(HAVE_LIBXML_XMLREADER_H) && \
 +     !defined(HAVE_BSDXML_H) && !defined(HAVE_EXPAT_H)) ||\
 +	!defined(HAVE_ZLIB_H) || \
 +	!defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
 +/*
 + * xar needs several external libraries.
 + *   o libxml2 or expat --- XML parser
 + *   o openssl or MD5/SHA1 hash function
 + *   o zlib
 + *   o bzlib2 (option)
 + *   o liblzma (option)
 + */
 +int
 +archive_read_support_format_xar(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_read_support_format_xar");
 +
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +	    "Xar not supported on this platform");
 +	return (ARCHIVE_WARN);
 +}
 +
 +#else	/* Support xar format */
 +
 +/* #define DEBUG 1 */
 +/* #define DEBUG_PRINT_TOC 1 */
 +#if DEBUG_PRINT_TOC
 +#define PRINT_TOC(d, outbytes)	do {				\
 +	unsigned char *x = (unsigned char *)(uintptr_t)d;	\
 +	unsigned char c = x[outbytes-1];			\
 +	x[outbytes - 1] = 0;					\
 +	fprintf(stderr, "%s", x);				\
 +	fprintf(stderr, "%c", c);				\
 +	x[outbytes - 1] = c;					\
 +} while (0)
 +#else
 +#define PRINT_TOC(d, outbytes)
 +#endif
 +
 +#define HEADER_MAGIC	0x78617221
 +#define HEADER_SIZE	28
 +#define HEADER_VERSION	1
 +#define CKSUM_NONE	0
 +#define CKSUM_SHA1	1
 +#define CKSUM_MD5	2
 +
 +#define MD5_SIZE	16
 +#define SHA1_SIZE	20
 +#define MAX_SUM_SIZE	20
 +
 +enum enctype {
 +	NONE,
 +	GZIP,
 +	BZIP2,
 +	LZMA,
 +	XZ,
 +};
 +
 +struct chksumval {
 +	int			 alg;
 +	size_t			 len;
 +	unsigned char		 val[MAX_SUM_SIZE];
 +};
 +
 +struct chksumwork {
 +	int			 alg;
 +#ifdef ARCHIVE_HAS_MD5
 +	archive_md5_ctx		 md5ctx;
 +#endif
 +#ifdef ARCHIVE_HAS_SHA1
 +	archive_sha1_ctx	 sha1ctx;
 +#endif
 +};
 +
 +struct xattr {
 +	struct xattr		*next;
 +	struct archive_string	 name;
 +	uint64_t		 id;
 +	uint64_t		 length;
 +	uint64_t		 offset;
 +	uint64_t		 size;
 +	enum enctype		 encoding;
 +	struct chksumval	 a_sum;
 +	struct chksumval	 e_sum;
 +	struct archive_string	 fstype;
 +};
 +
 +struct xar_file {
 +	struct xar_file		*next;
 +	struct xar_file		*hdnext;
 +	struct xar_file		*parent;
 +	int			 subdirs;
 +
 +	unsigned int		 has;
 +#define HAS_DATA		0x00001
 +#define HAS_PATHNAME		0x00002
 +#define HAS_SYMLINK		0x00004
 +#define HAS_TIME		0x00008
 +#define HAS_UID			0x00010
 +#define HAS_GID			0x00020
 +#define HAS_MODE		0x00040
 +#define HAS_TYPE		0x00080
 +#define HAS_DEV			0x00100
 +#define HAS_DEVMAJOR		0x00200
 +#define HAS_DEVMINOR		0x00400
 +#define HAS_INO			0x00800
 +#define HAS_FFLAGS		0x01000
 +#define HAS_XATTR		0x02000
 +#define HAS_ACL			0x04000
 +
 +	uint64_t		 id;
 +	uint64_t		 length;
 +	uint64_t		 offset;
 +	uint64_t		 size;
 +	enum enctype		 encoding;
 +	struct chksumval	 a_sum;
 +	struct chksumval	 e_sum;
 +	struct archive_string	 pathname;
 +	struct archive_string	 symlink;
 +	time_t			 ctime;
 +	time_t			 mtime;
 +	time_t			 atime;
 +	struct archive_string	 uname;
- 	uid_t			 uid;
++	int64_t			 uid;
 +	struct archive_string	 gname;
- 	gid_t			 gid;
++	int64_t			 gid;
 +	mode_t			 mode;
 +	dev_t			 dev;
 +	dev_t			 devmajor;
 +	dev_t			 devminor;
 +	int64_t			 ino64;
 +	struct archive_string	 fflags_text;
 +	unsigned int		 link;
 +	unsigned int		 nlink;
 +	struct archive_string	 hardlink;
 +	struct xattr		*xattr_list;
 +};
 +
 +struct hdlink {
 +	struct hdlink		 *next;
 +
 +	unsigned int		 id;
 +	int			 cnt;
 +	struct xar_file		 *files;
 +};
 +
 +struct heap_queue {
 +	struct xar_file		**files;
 +	int			 allocated;
 +	int			 used;
 +};
 +
 +enum xmlstatus {
 +	INIT,
 +	XAR,
 +	TOC,
 +	TOC_CREATION_TIME,
 +	TOC_CHECKSUM,
 +	TOC_CHECKSUM_OFFSET,
 +	TOC_CHECKSUM_SIZE,
 +	TOC_FILE,
 +	FILE_DATA,
 +	FILE_DATA_LENGTH,
 +	FILE_DATA_OFFSET,
 +	FILE_DATA_SIZE,
 +	FILE_DATA_ENCODING,
 +	FILE_DATA_A_CHECKSUM,
 +	FILE_DATA_E_CHECKSUM,
 +	FILE_DATA_CONTENT,
 +	FILE_EA,
 +	FILE_EA_LENGTH,
 +	FILE_EA_OFFSET,
 +	FILE_EA_SIZE,
 +	FILE_EA_ENCODING,
 +	FILE_EA_A_CHECKSUM,
 +	FILE_EA_E_CHECKSUM,
 +	FILE_EA_NAME,
 +	FILE_EA_FSTYPE,
 +	FILE_CTIME,
 +	FILE_MTIME,
 +	FILE_ATIME,
 +	FILE_GROUP,
 +	FILE_GID,
 +	FILE_USER,
 +	FILE_UID,
 +	FILE_MODE,
 +	FILE_DEVICE,
 +	FILE_DEVICE_MAJOR,
 +	FILE_DEVICE_MINOR,
 +	FILE_DEVICENO,
 +	FILE_INODE,
 +	FILE_LINK,
 +	FILE_TYPE,
 +	FILE_NAME,
 +	FILE_ACL,
 +	FILE_ACL_DEFAULT,
 +	FILE_ACL_ACCESS,
 +	FILE_ACL_APPLEEXTENDED,
 +	/* BSD file flags. */
 +	FILE_FLAGS,
 +	FILE_FLAGS_USER_NODUMP,
 +	FILE_FLAGS_USER_IMMUTABLE,
 +	FILE_FLAGS_USER_APPEND,
 +	FILE_FLAGS_USER_OPAQUE,
 +	FILE_FLAGS_USER_NOUNLINK,
 +	FILE_FLAGS_SYS_ARCHIVED,
 +	FILE_FLAGS_SYS_IMMUTABLE,
 +	FILE_FLAGS_SYS_APPEND,
 +	FILE_FLAGS_SYS_NOUNLINK,
 +	FILE_FLAGS_SYS_SNAPSHOT,
 +	/* Linux file flags. */
 +	FILE_EXT2,
 +	FILE_EXT2_SecureDeletion,
 +	FILE_EXT2_Undelete,
 +	FILE_EXT2_Compress,
 +	FILE_EXT2_Synchronous,
 +	FILE_EXT2_Immutable,
 +	FILE_EXT2_AppendOnly,
 +	FILE_EXT2_NoDump,
 +	FILE_EXT2_NoAtime,
 +	FILE_EXT2_CompDirty,
 +	FILE_EXT2_CompBlock,
 +	FILE_EXT2_NoCompBlock,
 +	FILE_EXT2_CompError,
 +	FILE_EXT2_BTree,
 +	FILE_EXT2_HashIndexed,
 +	FILE_EXT2_iMagic,
 +	FILE_EXT2_Journaled,
 +	FILE_EXT2_NoTail,
 +	FILE_EXT2_DirSync,
 +	FILE_EXT2_TopDir,
 +	FILE_EXT2_Reserved,
 +	UNKNOWN,
 +};
 +
 +struct unknown_tag {
 +	struct unknown_tag	*next;
 +	struct archive_string	 name;
 +};
 +
 +struct xar {
 +	uint64_t		 offset; /* Current position in the file. */
 +	int64_t			 total;
 +	uint64_t		 h_base;
 +	int			 end_of_file;
 +#define OUTBUFF_SIZE	(1024 * 64)
 +	unsigned char		*outbuff;
 +
 +	enum xmlstatus		 xmlsts;
 +	enum xmlstatus		 xmlsts_unknown;
 +	struct unknown_tag	*unknowntags;
 +	int			 base64text;
 +
 +	/*
 +	 * TOC
 +	 */
 +	uint64_t		 toc_remaining;
 +	uint64_t		 toc_total;
 +	uint64_t		 toc_chksum_offset;
 +	uint64_t		 toc_chksum_size;
 +
 +	/*
 +	 * For Decoding data.
 +	 */
 +	enum enctype 		 rd_encoding;
 +	z_stream		 stream;
 +	int			 stream_valid;
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	bz_stream		 bzstream;
 +	int			 bzstream_valid;
 +#endif
 +#if HAVE_LZMA_H && HAVE_LIBLZMA
 +	lzma_stream		 lzstream;
 +	int			 lzstream_valid;
 +#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
 +	lzmadec_stream		 lzstream;
 +	int			 lzstream_valid;
 +#endif
 +	/*
 +	 * For Checksum data.
 +	 */
 +	struct chksumwork	 a_sumwrk;
 +	struct chksumwork	 e_sumwrk;
 +
 +	struct xar_file		*file;	/* current reading file. */
 +	struct xattr		*xattr; /* current reading extended attribute. */
 +	struct heap_queue	 file_queue;
 +	struct xar_file		*hdlink_orgs;
 +	struct hdlink		*hdlink_list;
 +
 +	int	 		 entry_init;
 +	uint64_t		 entry_total;
 +	uint64_t		 entry_remaining;
 +	size_t			 entry_unconsumed;
 +	uint64_t		 entry_size;
 +	enum enctype 		 entry_encoding;
 +	struct chksumval	 entry_a_sum;
 +	struct chksumval	 entry_e_sum;
 +
 +	struct archive_string_conv *sconv;
 +};
 +
 +struct xmlattr {
 +	struct xmlattr	*next;
 +	char		*name;
 +	char		*value;
 +};
 +
 +struct xmlattr_list {
 +	struct xmlattr	*first;
 +	struct xmlattr	**last;
 +};
 +
 +static int	xar_bid(struct archive_read *, int);
 +static int	xar_read_header(struct archive_read *,
 +		    struct archive_entry *);
 +static int	xar_read_data(struct archive_read *,
 +		    const void **, size_t *, int64_t *);
 +static int	xar_read_data_skip(struct archive_read *);
 +static int	xar_cleanup(struct archive_read *);
 +static int	move_reading_point(struct archive_read *, uint64_t);
 +static int	rd_contents_init(struct archive_read *,
 +		    enum enctype, int, int);
 +static int	rd_contents(struct archive_read *, const void **,
 +		    size_t *, size_t *, uint64_t);
 +static uint64_t	atol10(const char *, size_t);
 +static int64_t	atol8(const char *, size_t);
 +static size_t	atohex(unsigned char *, size_t, const char *, size_t);
 +static time_t	parse_time(const char *p, size_t n);
 +static int	heap_add_entry(struct archive_read *a,
 +    struct heap_queue *, struct xar_file *);
 +static struct xar_file *heap_get_entry(struct heap_queue *);
 +static int	add_link(struct archive_read *,
 +    struct xar *, struct xar_file *);
 +static void	checksum_init(struct archive_read *, int, int);
 +static void	checksum_update(struct archive_read *, const void *,
 +		    size_t, const void *, size_t);
 +static int	checksum_final(struct archive_read *, const void *,
 +		    size_t, const void *, size_t);
 +static int	decompression_init(struct archive_read *, enum enctype);
 +static int	decompress(struct archive_read *, const void **,
 +		    size_t *, const void *, size_t *);
 +static int	decompression_cleanup(struct archive_read *);
 +static void	xmlattr_cleanup(struct xmlattr_list *);
 +static int	file_new(struct archive_read *,
 +    struct xar *, struct xmlattr_list *);
 +static void	file_free(struct xar_file *);
 +static int	xattr_new(struct archive_read *,
 +    struct xar *, struct xmlattr_list *);
 +static void	xattr_free(struct xattr *);
 +static int	getencoding(struct xmlattr_list *);
 +static int	getsumalgorithm(struct xmlattr_list *);
 +static int	unknowntag_start(struct archive_read *,
 +    struct xar *, const char *);
 +static void	unknowntag_end(struct xar *, const char *);
 +static int	xml_start(struct archive_read *,
 +    const char *, struct xmlattr_list *);
 +static void	xml_end(void *, const char *);
 +static void	xml_data(void *, const char *, int);
 +static int	xml_parse_file_flags(struct xar *, const char *);
 +static int	xml_parse_file_ext2(struct xar *, const char *);
 +#if defined(HAVE_LIBXML_XMLREADER_H)
 +static int	xml2_xmlattr_setup(struct archive_read *,
 +    struct xmlattr_list *, xmlTextReaderPtr);
 +static int	xml2_read_cb(void *, char *, int);
 +static int	xml2_close_cb(void *);
 +static void	xml2_error_hdr(void *, const char *, xmlParserSeverities,
 +		    xmlTextReaderLocatorPtr);
 +static int	xml2_read_toc(struct archive_read *);
 +#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
 +struct expat_userData {
 +	int state;
 +	struct archive_read *archive;
 +};
 +static int	expat_xmlattr_setup(struct archive_read *,
 +    struct xmlattr_list *, const XML_Char **);
 +static void	expat_start_cb(void *, const XML_Char *, const XML_Char **);
 +static void	expat_end_cb(void *, const XML_Char *);
 +static void	expat_data_cb(void *, const XML_Char *, int);
 +static int	expat_read_toc(struct archive_read *);
 +#endif
 +
 +int
 +archive_read_support_format_xar(struct archive *_a)
 +{
 +	struct xar *xar;
 +	struct archive_read *a = (struct archive_read *)_a;
 +	int r;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_read_support_format_xar");
 +
 +	xar = (struct xar *)calloc(1, sizeof(*xar));
 +	if (xar == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate xar data");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	r = __archive_read_register_format(a,
 +	    xar,
 +	    "xar",
 +	    xar_bid,
 +	    NULL,
 +	    xar_read_header,
 +	    xar_read_data,
 +	    xar_read_data_skip,
++	    NULL,
 +	    xar_cleanup);
 +	if (r != ARCHIVE_OK)
 +		free(xar);
 +	return (r);
 +}
 +
 +static int
 +xar_bid(struct archive_read *a, int best_bid)
 +{
 +	const unsigned char *b;
 +	int bid;
 +
 +	(void)best_bid; /* UNUSED */
 +
 +	b = __archive_read_ahead(a, HEADER_SIZE, NULL);
 +	if (b == NULL)
 +		return (-1);
 +
 +	bid = 0;
 +	/*
 +	 * Verify magic code
 +	 */
 +	if (archive_be32dec(b) != HEADER_MAGIC)
 +		return (0);
 +	bid += 32;
 +	/*
 +	 * Verify header size
 +	 */
 +	if (archive_be16dec(b+4) != HEADER_SIZE)
 +		return (0);
 +	bid += 16;
 +	/*
 +	 * Verify header version
 +	 */
 +	if (archive_be16dec(b+6) != HEADER_VERSION)
 +		return (0);
 +	bid += 16;
 +	/*
 +	 * Verify type of checksum
 +	 */
 +	switch (archive_be32dec(b+24)) {
 +	case CKSUM_NONE:
 +	case CKSUM_SHA1:
 +	case CKSUM_MD5:
 +		bid += 32;
 +		break;
 +	default:
 +		return (0);
 +	}
 +
 +	return (bid);
 +}
 +
 +static int
 +read_toc(struct archive_read *a)
 +{
 +	struct xar *xar;
 +	struct xar_file *file;
 +	const unsigned char *b;
 +	uint64_t toc_compressed_size;
 +	uint64_t toc_uncompressed_size;
 +	uint32_t toc_chksum_alg;
 +	ssize_t bytes;
 +	int r;
 +
 +	xar = (struct xar *)(a->format->data);
 +
 +	/*
 +	 * Read xar header.
 +	 */
 +	b = __archive_read_ahead(a, HEADER_SIZE, &bytes);
 +	if (bytes < 0)
 +		return ((int)bytes);
 +	if (bytes < HEADER_SIZE) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated archive header");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	if (archive_be32dec(b) != HEADER_MAGIC) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Invalid header magic");
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (archive_be16dec(b+6) != HEADER_VERSION) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Unsupported header version(%d)",
 +		    archive_be16dec(b+6));
 +		return (ARCHIVE_FATAL);
 +	}
 +	toc_compressed_size = archive_be64dec(b+8);
 +	xar->toc_remaining = toc_compressed_size;
 +	toc_uncompressed_size = archive_be64dec(b+16);
 +	toc_chksum_alg = archive_be32dec(b+24);
 +	__archive_read_consume(a, HEADER_SIZE);
 +	xar->offset += HEADER_SIZE;
 +	xar->toc_total = 0;
 +
 +	/*
 +	 * Read TOC(Table of Contents).
 +	 */
 +	/* Initialize reading contents. */
 +	r = move_reading_point(a, HEADER_SIZE);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	r = rd_contents_init(a, GZIP, toc_chksum_alg, CKSUM_NONE);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +
 +#ifdef HAVE_LIBXML_XMLREADER_H
 +	r = xml2_read_toc(a);
 +#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
 +	r = expat_read_toc(a);
 +#endif
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +
 +	/* Set 'The HEAP' base. */
 +	xar->h_base = xar->offset;
 +	if (xar->toc_total != toc_uncompressed_size) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "TOC uncompressed size error");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Checksum TOC
 +	 */
 +	if (toc_chksum_alg != CKSUM_NONE) {
 +		r = move_reading_point(a, xar->toc_chksum_offset);
 +		if (r != ARCHIVE_OK)
 +			return (r);
- 		b = __archive_read_ahead(a, xar->toc_chksum_size, &bytes);
++		b = __archive_read_ahead(a,
++			(size_t)xar->toc_chksum_size, &bytes);
 +		if (bytes < 0)
 +			return ((int)bytes);
 +		if ((uint64_t)bytes < xar->toc_chksum_size) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated archive file");
 +			return (ARCHIVE_FATAL);
 +		}
- 		r = checksum_final(a, b, xar->toc_chksum_size, NULL, 0);
++		r = checksum_final(a, b,
++			(size_t)xar->toc_chksum_size, NULL, 0);
 +		__archive_read_consume(a, xar->toc_chksum_size);
 +		xar->offset += xar->toc_chksum_size;
 +		if (r != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Connect hardlinked files.
 +	 */
 +	for (file = xar->hdlink_orgs; file != NULL; file = file->hdnext) {
 +		struct hdlink **hdlink;
 +
 +		for (hdlink = &(xar->hdlink_list); *hdlink != NULL;
 +		    hdlink = &((*hdlink)->next)) {
 +			if ((*hdlink)->id == file->id) {
 +				struct hdlink *hltmp;
 +				struct xar_file *f2;
 +				int nlink = (*hdlink)->cnt + 1;
 +
 +				file->nlink = nlink;
 +				for (f2 = (*hdlink)->files; f2 != NULL;
 +				    f2 = f2->hdnext) {
 +					f2->nlink = nlink;
 +					archive_string_copy(
 +					    &(f2->hardlink), &(file->pathname));
 +				}
 +				/* Remove resolved files from hdlist_list. */
 +				hltmp = *hdlink;
 +				*hdlink = hltmp->next;
 +				free(hltmp);
 +				break;
 +			}
 +		}
 +	}
 +	a->archive.archive_format = ARCHIVE_FORMAT_XAR;
 +	a->archive.archive_format_name = "xar";
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xar_read_header(struct archive_read *a, struct archive_entry *entry)
 +{
 +	struct xar *xar;
 +	struct xar_file *file;
 +	struct xattr *xattr;
 +	int r;
 +
 +	xar = (struct xar *)(a->format->data);
 +	r = ARCHIVE_OK;
 +
 +	if (xar->offset == 0) {
 +		/* Create a character conversion object. */
 +		if (xar->sconv == NULL) {
 +			xar->sconv = archive_string_conversion_from_charset(
 +			    &(a->archive), "UTF-8", 1);
 +			if (xar->sconv == NULL)
 +				return (ARCHIVE_FATAL);
 +		}
 +
 +		/* Read TOC. */
 +		r = read_toc(a);
 +		if (r != ARCHIVE_OK)
 +			return (r);
 +	}
 +
 +	for (;;) {
 +		file = xar->file = heap_get_entry(&(xar->file_queue));
 +		if (file == NULL) {
 +			xar->end_of_file = 1;
 +			return (ARCHIVE_EOF);
 +		}
 +		if ((file->mode & AE_IFMT) != AE_IFDIR)
 +			break;
 +		if (file->has != (HAS_PATHNAME | HAS_TYPE))
 +			break;
 +		/*
 +		 * If a file type is a directory and it does not have
 +		 * any metadata, do not export.
 +		 */
 +		file_free(file);
 +	}
 +	archive_entry_set_atime(entry, file->atime, 0);
 +	archive_entry_set_ctime(entry, file->ctime, 0);
 +	archive_entry_set_mtime(entry, file->mtime, 0);
 +	archive_entry_set_gid(entry, file->gid);
 +	if (file->gname.length > 0 &&
 +	    archive_entry_copy_gname_l(entry, file->gname.s,
 +		archive_strlen(&(file->gname)), xar->sconv) != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Gname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Gname cannot be converted from %s to current locale.",
 +		    archive_string_conversion_charset_name(xar->sconv));
 +		r = ARCHIVE_WARN;
 +	}
 +	archive_entry_set_uid(entry, file->uid);
 +	if (file->uname.length > 0 &&
 +	    archive_entry_copy_uname_l(entry, file->uname.s,
 +		archive_strlen(&(file->uname)), xar->sconv) != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Uname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Uname cannot be converted from %s to current locale.",
 +		    archive_string_conversion_charset_name(xar->sconv));
 +		r = ARCHIVE_WARN;
 +	}
 +	archive_entry_set_mode(entry, file->mode);
 +	if (archive_entry_copy_pathname_l(entry, file->pathname.s,
 +	    archive_strlen(&(file->pathname)), xar->sconv) != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Pathname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Pathname cannot be converted from %s to current locale.",
 +		    archive_string_conversion_charset_name(xar->sconv));
 +		r = ARCHIVE_WARN;
 +	}
 +
 +
 +	if (file->symlink.length > 0 &&
 +	    archive_entry_copy_symlink_l(entry, file->symlink.s,
 +		archive_strlen(&(file->symlink)), xar->sconv) != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Linkname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Linkname cannot be converted from %s to current locale.",
 +		    archive_string_conversion_charset_name(xar->sconv));
 +		r = ARCHIVE_WARN;
 +	}
 +	/* Set proper nlink. */
 +	if ((file->mode & AE_IFMT) == AE_IFDIR)
 +		archive_entry_set_nlink(entry, file->subdirs + 2);
 +	else
 +		archive_entry_set_nlink(entry, file->nlink);
 +	archive_entry_set_size(entry, file->size);
 +	if (archive_strlen(&(file->hardlink)) > 0)
 +		archive_entry_set_hardlink(entry, file->hardlink.s);
 +	archive_entry_set_ino64(entry, file->ino64);
 +	if (file->has & HAS_DEV)
 +		archive_entry_set_dev(entry, file->dev);
 +	if (file->has & HAS_DEVMAJOR)
 +		archive_entry_set_devmajor(entry, file->devmajor);
 +	if (file->has & HAS_DEVMINOR)
 +		archive_entry_set_devminor(entry, file->devminor);
 +	if (archive_strlen(&(file->fflags_text)) > 0)
 +		archive_entry_copy_fflags_text(entry, file->fflags_text.s);
 +
 +	xar->entry_init = 1;
 +	xar->entry_total = 0;
 +	xar->entry_remaining = file->length;
 +	xar->entry_size = file->size;
 +	xar->entry_encoding = file->encoding;
 +	xar->entry_a_sum = file->a_sum;
 +	xar->entry_e_sum = file->e_sum;
 +	/*
 +	 * Read extended attributes.
 +	 */
 +	xattr = file->xattr_list;
 +	while (xattr != NULL) {
 +		const void *d;
 +		size_t outbytes, used;
 +
 +		r = move_reading_point(a, xattr->offset);
 +		if (r != ARCHIVE_OK)
 +			break;
 +		r = rd_contents_init(a, xattr->encoding,
 +		    xattr->a_sum.alg, xattr->e_sum.alg);
 +		if (r != ARCHIVE_OK)
 +			break;
 +		d = NULL;
 +		r = rd_contents(a, &d, &outbytes, &used, xattr->length);
 +		if (r != ARCHIVE_OK)
 +			break;
 +		if (outbytes != xattr->size) {
 +			archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
 +			    "Decompressed size error");
 +			r = ARCHIVE_FATAL;
 +			break;
 +		}
 +		r = checksum_final(a,
 +		    xattr->a_sum.val, xattr->a_sum.len,
 +		    xattr->e_sum.val, xattr->e_sum.len);
 +		if (r != ARCHIVE_OK)
 +			break;
 +		archive_entry_xattr_add_entry(entry,
 +		    xattr->name.s, d, outbytes);
 +		xattr = xattr->next;
 +	}
 +	if (r != ARCHIVE_OK) {
 +		file_free(file);
 +		return (r);
 +	}
 +
 +	if (xar->entry_remaining > 0)
 +		/* Move reading point to the beginning of current
 +		 * file contents. */
 +		r = move_reading_point(a, file->offset);
 +	else
 +		r = ARCHIVE_OK;
 +
 +	file_free(file);
 +	return (r);
 +}
 +
 +static int
 +xar_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	struct xar *xar;
 +	size_t used;
 +	int r;
 +
 +	xar = (struct xar *)(a->format->data);
 +
 +	if (xar->entry_unconsumed) {
 +		__archive_read_consume(a, xar->entry_unconsumed);
 +		xar->entry_unconsumed = 0;
 +	}
 +
 +	if (xar->end_of_file || xar->entry_remaining <= 0) {
 +		r = ARCHIVE_EOF;
 +		goto abort_read_data;
 +	}
 +
 +	if (xar->entry_init) {
 +		r = rd_contents_init(a, xar->entry_encoding,
 +		    xar->entry_a_sum.alg, xar->entry_e_sum.alg);
 +		if (r != ARCHIVE_OK) {
 +			xar->entry_remaining = 0;
 +			return (r);
 +		}
 +		xar->entry_init = 0;
 +	}
 +
 +	*buff = NULL;
 +	r = rd_contents(a, buff, size, &used, xar->entry_remaining);
 +	if (r != ARCHIVE_OK)
 +		goto abort_read_data;
 +
 +	*offset = xar->entry_total;
 +	xar->entry_total += *size;
 +	xar->total += *size;
 +	xar->offset += used;
 +	xar->entry_remaining -= used;
 +	xar->entry_unconsumed = used;
 +
 +	if (xar->entry_remaining == 0) {
 +		if (xar->entry_total != xar->entry_size) {
 +			archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
 +			    "Decompressed size error");
 +			r = ARCHIVE_FATAL;
 +			goto abort_read_data;
 +		}
 +		r = checksum_final(a,
 +		    xar->entry_a_sum.val, xar->entry_a_sum.len,
 +		    xar->entry_e_sum.val, xar->entry_e_sum.len);
 +		if (r != ARCHIVE_OK)
 +			goto abort_read_data;
 +	}
 +
 +	return (ARCHIVE_OK);
 +abort_read_data:
 +	*buff = NULL;
 +	*size = 0;
 +	*offset = xar->total;
 +	return (r);
 +}
 +
 +static int
 +xar_read_data_skip(struct archive_read *a)
 +{
 +	struct xar *xar;
 +	int64_t bytes_skipped;
 +
 +	xar = (struct xar *)(a->format->data);
 +	if (xar->end_of_file)
 +		return (ARCHIVE_EOF);
 +	bytes_skipped = __archive_read_consume(a, xar->entry_remaining +
 +		xar->entry_unconsumed);
 +	if (bytes_skipped < 0)
 +		return (ARCHIVE_FATAL);
 +	xar->offset += bytes_skipped;
 +	xar->entry_unconsumed = 0;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xar_cleanup(struct archive_read *a)
 +{
 +	struct xar *xar;
 +	struct hdlink *hdlink;
 +	int i;
 +	int r;
 +
 +	xar = (struct xar *)(a->format->data);
 +	r = decompression_cleanup(a);
 +	hdlink = xar->hdlink_list;
 +	while (hdlink != NULL) {
 +		struct hdlink *next = hdlink->next;
 +
 +		free(hdlink);
 +		hdlink = next;
 +	}
 +	for (i = 0; i < xar->file_queue.used; i++)
 +		file_free(xar->file_queue.files[i]);
 +	while (xar->unknowntags != NULL) {
 +		struct unknown_tag *tag;
 +
 +		tag = xar->unknowntags;
 +		xar->unknowntags = tag->next;
 +		archive_string_free(&(tag->name));
 +		free(tag);
 +	}
 +	free(xar->outbuff);
 +	free(xar);
 +	a->format->data = NULL;
 +	return (r);
 +}
 +
 +static int
 +move_reading_point(struct archive_read *a, uint64_t offset)
 +{
 +	struct xar *xar;
 +
 +	xar = (struct xar *)(a->format->data);
 +	if (xar->offset - xar->h_base != offset) {
 +		/* Seek forward to the start of file contents. */
 +		int64_t step;
 +
 +		step = offset - (xar->offset - xar->h_base);
 +		if (step > 0) {
 +			step = __archive_read_consume(a, step);
 +			if (step < 0)
 +				return ((int)step);
 +			xar->offset += step;
 +		} else {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Cannot seek.");
 +			return (ARCHIVE_FAILED);
 +		}
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +rd_contents_init(struct archive_read *a, enum enctype encoding,
 +    int a_sum_alg, int e_sum_alg)
 +{
 +	int r;
 +
 +	/* Init decompress library. */
 +	if ((r = decompression_init(a, encoding)) != ARCHIVE_OK)
 +		return (r);
 +	/* Init checksum library. */
 +	checksum_init(a, a_sum_alg, e_sum_alg);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +rd_contents(struct archive_read *a, const void **buff, size_t *size,
 +    size_t *used, uint64_t remaining)
 +{
 +	const unsigned char *b;
 +	ssize_t bytes;
 +
 +	/* Get whatever bytes are immediately available. */
 +	b = __archive_read_ahead(a, 1, &bytes);
 +	if (bytes < 0)
 +		return ((int)bytes);
 +	if (bytes == 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Truncated archive file");
 +		return (ARCHIVE_FATAL);
 +	}
 +	if ((uint64_t)bytes > remaining)
 +		bytes = (ssize_t)remaining;
 +
 +	/*
 +	 * Decompress contents of file.
 +	 */
 +	*used = bytes;
 +	if (decompress(a, buff, size, b, used) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/*
 +	 * Update checksum of a compressed data and a extracted data.
 +	 */
 +	checksum_update(a, b, *used, *buff, *size);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Note that this implementation does not (and should not!) obey
 + * locale settings; you cannot simply substitute strtol here, since
 + * it does obey locale.
 + */
 +
 +static uint64_t
 +atol10(const char *p, size_t char_cnt)
 +{
 +	uint64_t l;
 +	int digit;
 +
 +	l = 0;
 +	digit = *p - '0';
 +	while (digit >= 0 && digit < 10  && char_cnt-- > 0) {
 +		l = (l * 10) + digit;
 +		digit = *++p - '0';
 +	}
 +	return (l);
 +}
 +
 +static int64_t
 +atol8(const char *p, size_t char_cnt)
 +{
 +	int64_t l;
 +	int digit;
 +        
 +	l = 0;
 +	while (char_cnt-- > 0) {
 +		if (*p >= '0' && *p <= '7')
 +			digit = *p - '0';
 +		else
 +			break;
 +		p++;
 +		l <<= 3;
 +		l |= digit;
 +	}
 +	return (l);
 +}
 +
 +static size_t
 +atohex(unsigned char *b, size_t bsize, const char *p, size_t psize)
 +{
 +	size_t fbsize = bsize;
 +
 +	while (bsize && psize > 1) {
 +		unsigned char x;
 +
 +		if (p[0] >= 'a' && p[0] <= 'z')
 +			x = (p[0] - 'a' + 0x0a) << 4;
 +		else if (p[0] >= 'A' && p[0] <= 'Z')
 +			x = (p[0] - 'A' + 0x0a) << 4;
 +		else if (p[0] >= '0' && p[0] <= '9')
 +			x = (p[0] - '0') << 4;
 +		else
 +			return (-1);
 +		if (p[1] >= 'a' && p[1] <= 'z')
 +			x |= p[1] - 'a' + 0x0a;
 +		else if (p[1] >= 'A' && p[1] <= 'Z')
 +			x |= p[1] - 'A' + 0x0a;
 +		else if (p[1] >= '0' && p[1] <= '9')
 +			x |= p[1] - '0';
 +		else
 +			return (-1);
 +		
 +		*b++ = x;
 +		bsize--;
 +		p += 2;
 +		psize -= 2;
 +	}
 +	return (fbsize - bsize);
 +}
 +
 +static time_t
 +time_from_tm(struct tm *t)
 +{
 +#if HAVE_TIMEGM
 +	/* Use platform timegm() if available. */
 +	return (timegm(t));
 +#elif HAVE__MKGMTIME64
 +	return (_mkgmtime64(t));
 +#else
 +	/* Else use direct calculation using POSIX assumptions. */
 +	/* First, fix up tm_yday based on the year/month/day. */
 +	mktime(t);
 +	/* Then we can compute timegm() from first principles. */
 +	return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600
 +	    + t->tm_yday * 86400 + (t->tm_year - 70) * 31536000
 +	    + ((t->tm_year - 69) / 4) * 86400 -
 +	    ((t->tm_year - 1) / 100) * 86400
 +	    + ((t->tm_year + 299) / 400) * 86400);
 +#endif
 +}
 +
 +static time_t
 +parse_time(const char *p, size_t n)
 +{
 +	struct tm tm;
 +	time_t t = 0;
 +	int64_t data;
 +
 +	memset(&tm, 0, sizeof(tm));
 +	if (n != 20)
 +		return (t);
 +	data = atol10(p, 4);
 +	if (data < 1900)
 +		return (t);
 +	tm.tm_year = (int)data - 1900;
 +	p += 4;
 +	if (*p++ != '-')
 +		return (t);
 +	data = atol10(p, 2);
 +	if (data < 1 || data > 12)
 +		return (t);
 +	tm.tm_mon = (int)data -1;
 +	p += 2;
 +	if (*p++ != '-')
 +		return (t);
 +	data = atol10(p, 2);
 +	if (data < 1 || data > 31)
 +		return (t);
 +	tm.tm_mday = (int)data;
 +	p += 2;
 +	if (*p++ != 'T')
 +		return (t);
 +	data = atol10(p, 2);
 +	if (data < 0 || data > 23)
 +		return (t);
 +	tm.tm_hour = (int)data;
 +	p += 2;
 +	if (*p++ != ':')
 +		return (t);
 +	data = atol10(p, 2);
 +	if (data < 0 || data > 59)
 +		return (t);
 +	tm.tm_min = (int)data;
 +	p += 2;
 +	if (*p++ != ':')
 +		return (t);
 +	data = atol10(p, 2);
 +	if (data < 0 || data > 60)
 +		return (t);
 +	tm.tm_sec = (int)data;
 +#if 0
 +	p += 2;
 +	if (*p != 'Z')
 +		return (t);
 +#endif
 +
 +	t = time_from_tm(&tm);
 +
 +	return (t);
 +}
 +
 +static int
 +heap_add_entry(struct archive_read *a,
 +    struct heap_queue *heap, struct xar_file *file)
 +{
 +	uint64_t file_id, parent_id;
 +	int hole, parent;
 +
 +	/* Expand our pending files list as necessary. */
 +	if (heap->used >= heap->allocated) {
 +		struct xar_file **new_pending_files;
 +		int new_size = heap->allocated * 2;
 +
 +		if (heap->allocated < 1024)
 +			new_size = 1024;
 +		/* Overflow might keep us from growing the list. */
 +		if (new_size <= heap->allocated) {
 +			archive_set_error(&a->archive,
 +			    ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		new_pending_files = (struct xar_file **)
 +		    malloc(new_size * sizeof(new_pending_files[0]));
 +		if (new_pending_files == NULL) {
 +			archive_set_error(&a->archive,
 +			    ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		memcpy(new_pending_files, heap->files,
 +		    heap->allocated * sizeof(new_pending_files[0]));
 +		if (heap->files != NULL)
 +			free(heap->files);
 +		heap->files = new_pending_files;
 +		heap->allocated = new_size;
 +	}
 +
 +	file_id = file->id;
 +
 +	/*
 +	 * Start with hole at end, walk it up tree to find insertion point.
 +	 */
 +	hole = heap->used++;
 +	while (hole > 0) {
 +		parent = (hole - 1)/2;
 +		parent_id = heap->files[parent]->id;
 +		if (file_id >= parent_id) {
 +			heap->files[hole] = file;
 +			return (ARCHIVE_OK);
 +		}
 +		/* Move parent into hole <==> move hole up tree. */
 +		heap->files[hole] = heap->files[parent];
 +		hole = parent;
 +	}
 +	heap->files[0] = file;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static struct xar_file *
 +heap_get_entry(struct heap_queue *heap)
 +{
 +	uint64_t a_id, b_id, c_id;
 +	int a, b, c;
 +	struct xar_file *r, *tmp;
 +
 +	if (heap->used < 1)
 +		return (NULL);
 +
 +	/*
 +	 * The first file in the list is the earliest; we'll return this.
 +	 */
 +	r = heap->files[0];
 +
 +	/*
 +	 * Move the last item in the heap to the root of the tree
 +	 */
 +	heap->files[0] = heap->files[--(heap->used)];
 +
 +	/*
 +	 * Rebalance the heap.
 +	 */
 +	a = 0; /* Starting element and its heap key */
 +	a_id = heap->files[a]->id;
 +	for (;;) {
 +		b = a + a + 1; /* First child */
 +		if (b >= heap->used)
 +			return (r);
 +		b_id = heap->files[b]->id;
 +		c = b + 1; /* Use second child if it is smaller. */
 +		if (c < heap->used) {
 +			c_id = heap->files[c]->id;
 +			if (c_id < b_id) {
 +				b = c;
 +				b_id = c_id;
 +			}
 +		}
 +		if (a_id <= b_id)
 +			return (r);
 +		tmp = heap->files[a];
 +		heap->files[a] = heap->files[b];
 +		heap->files[b] = tmp;
 +		a = b;
 +	}
 +}
 +
 +static int
 +add_link(struct archive_read *a, struct xar *xar, struct xar_file *file)
 +{
 +	struct hdlink *hdlink;
 +
 +	for (hdlink = xar->hdlink_list; hdlink != NULL; hdlink = hdlink->next) {
 +		if (hdlink->id == file->link) {
 +			file->hdnext = hdlink->files;
 +			hdlink->cnt++;
 +			hdlink->files = file;
 +			return (ARCHIVE_OK);
 +		}
 +	}
 +	hdlink = malloc(sizeof(*hdlink));
 +	if (hdlink == NULL) {
 +		archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	file->hdnext = NULL;
 +	hdlink->id = file->link;
 +	hdlink->cnt = 1;
 +	hdlink->files = file;
 +	hdlink->next = xar->hdlink_list;
 +	xar->hdlink_list = hdlink;
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +_checksum_init(struct chksumwork *sumwrk, int sum_alg)
 +{
 +	sumwrk->alg = sum_alg;
 +	switch (sum_alg) {
 +	case CKSUM_NONE:
 +		break;
 +	case CKSUM_SHA1:
 +		archive_sha1_init(&(sumwrk->sha1ctx));
 +		break;
 +	case CKSUM_MD5:
 +		archive_md5_init(&(sumwrk->md5ctx));
 +		break;
 +	}
 +}
 +
 +static void
 +_checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
 +{
 +
 +	switch (sumwrk->alg) {
 +	case CKSUM_NONE:
 +		break;
 +	case CKSUM_SHA1:
 +		archive_sha1_update(&(sumwrk->sha1ctx), buff, size);
 +		break;
 +	case CKSUM_MD5:
 +		archive_md5_update(&(sumwrk->md5ctx), buff, size);
 +		break;
 +	}
 +}
 +
 +static int
 +_checksum_final(struct chksumwork *sumwrk, const void *val, size_t len)
 +{
 +	unsigned char sum[MAX_SUM_SIZE];
 +	int r = ARCHIVE_OK;
 +
 +	switch (sumwrk->alg) {
 +	case CKSUM_NONE:
 +		break;
 +	case CKSUM_SHA1:
 +		archive_sha1_final(&(sumwrk->sha1ctx), sum);
 +		if (len != SHA1_SIZE ||
 +		    memcmp(val, sum, SHA1_SIZE) != 0)
 +			r = ARCHIVE_FAILED;
 +		break;
 +	case CKSUM_MD5:
 +		archive_md5_final(&(sumwrk->md5ctx), sum);
 +		if (len != MD5_SIZE ||
 +		    memcmp(val, sum, MD5_SIZE) != 0)
 +			r = ARCHIVE_FAILED;
 +		break;
 +	}
 +	return (r);
 +}
 +
 +static void
 +checksum_init(struct archive_read *a, int a_sum_alg, int e_sum_alg)
 +{
 +	struct xar *xar;
 +
 +	xar = (struct xar *)(a->format->data);
 +	_checksum_init(&(xar->a_sumwrk), a_sum_alg);
 +	_checksum_init(&(xar->e_sumwrk), e_sum_alg);
 +}
 +
 +static void
 +checksum_update(struct archive_read *a, const void *abuff, size_t asize,
 +    const void *ebuff, size_t esize)
 +{
 +	struct xar *xar;
 +
 +	xar = (struct xar *)(a->format->data);
 +	_checksum_update(&(xar->a_sumwrk), abuff, asize);
 +	_checksum_update(&(xar->e_sumwrk), ebuff, esize);
 +}
 +
 +static int
 +checksum_final(struct archive_read *a, const void *a_sum_val,
 +    size_t a_sum_len, const void *e_sum_val, size_t e_sum_len)
 +{
 +	struct xar *xar;
 +	int r;
 +
 +	xar = (struct xar *)(a->format->data);
 +	r = _checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len);
 +	if (r == ARCHIVE_OK)
 +		r = _checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len);
 +	if (r != ARCHIVE_OK)
 +		archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
 +		    "Sumcheck error");
 +	return (r);
 +}
 +
 +static int
 +decompression_init(struct archive_read *a, enum enctype encoding)
 +{
 +	struct xar *xar;
 +	const char *detail;
 +	int r;
 +
 +	xar = (struct xar *)(a->format->data);
 +	xar->rd_encoding = encoding;
 +	switch (encoding) {
 +	case NONE:
 +		break;
 +	case GZIP:
 +		if (xar->stream_valid)
 +			r = inflateReset(&(xar->stream));
 +		else
 +			r = inflateInit(&(xar->stream));
 +		if (r != Z_OK) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Couldn't initialize zlib stream.");
 +			return (ARCHIVE_FATAL);
 +		}
 +		xar->stream_valid = 1;
 +		xar->stream.total_in = 0;
 +		xar->stream.total_out = 0;
 +		break;
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	case BZIP2:
 +		if (xar->bzstream_valid) {
 +			BZ2_bzDecompressEnd(&(xar->bzstream));
 +			xar->bzstream_valid = 0;
 +		}
 +		r = BZ2_bzDecompressInit(&(xar->bzstream), 0, 0);
 +		if (r == BZ_MEM_ERROR)
 +			r = BZ2_bzDecompressInit(&(xar->bzstream), 0, 1);
 +		if (r != BZ_OK) {
 +			int err = ARCHIVE_ERRNO_MISC;
 +			detail = NULL;
 +			switch (r) {
 +			case BZ_PARAM_ERROR:
 +				detail = "invalid setup parameter";
 +				break;
 +			case BZ_MEM_ERROR:
 +				err = ENOMEM;
 +				detail = "out of memory";
 +				break;
 +			case BZ_CONFIG_ERROR:
 +				detail = "mis-compiled library";
 +				break;
 +			}
 +			archive_set_error(&a->archive, err,
 +			    "Internal error initializing decompressor: %s",
 +			    detail == NULL ? "??" : detail);
 +			xar->bzstream_valid = 0;
 +			return (ARCHIVE_FATAL);
 +		}
 +		xar->bzstream_valid = 1;
 +		xar->bzstream.total_in_lo32 = 0;
 +		xar->bzstream.total_in_hi32 = 0;
 +		xar->bzstream.total_out_lo32 = 0;
 +		xar->bzstream.total_out_hi32 = 0;
 +		break;
 +#endif
 +#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
 +#if LZMA_VERSION_MAJOR >= 5
 +/* Effectively disable the limiter. */
 +#define LZMA_MEMLIMIT   UINT64_MAX
 +#else
 +/* NOTE: This needs to check memory size which running system has. */
 +#define LZMA_MEMLIMIT   (1U << 30)
 +#endif
 +	case XZ:
 +	case LZMA:
 +		if (xar->lzstream_valid) {
 +			lzma_end(&(xar->lzstream));
 +			xar->lzstream_valid = 0;
 +		}
 +		if (xar->entry_encoding == XZ)
 +			r = lzma_stream_decoder(&(xar->lzstream),
 +			    LZMA_MEMLIMIT,/* memlimit */
 +			    LZMA_CONCATENATED);
 +		else
 +			r = lzma_alone_decoder(&(xar->lzstream),
 +			    LZMA_MEMLIMIT);/* memlimit */
 +		if (r != LZMA_OK) {
 +			switch (r) {
 +			case LZMA_MEM_ERROR:
 +				archive_set_error(&a->archive,
 +				    ENOMEM,
 +				    "Internal error initializing "
 +				    "compression library: "
 +				    "Cannot allocate memory");
 +				break;
 +			case LZMA_OPTIONS_ERROR:
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Internal error initializing "
 +				    "compression library: "
 +				    "Invalid or unsupported options");
 +				break;
 +			default:
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Internal error initializing "
 +				    "lzma library");
 +				break;
 +			}
 +			return (ARCHIVE_FATAL);
 +		}
 +		xar->lzstream_valid = 1;
 +		xar->lzstream.total_in = 0;
 +		xar->lzstream.total_out = 0;
 +		break;
 +#elif defined(HAVE_LZMADEC_H) && defined(HAVE_LIBLZMADEC)
 +	case LZMA:
 +		if (xar->lzstream_valid)
 +			lzmadec_end(&(xar->lzstream));
 +		r = lzmadec_init(&(xar->lzstream));
 +		if (r != LZMADEC_OK) {
 +			switch (r) {
 +			case LZMADEC_HEADER_ERROR:
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Internal error initializing "
 +				    "compression library: "
 +				    "invalid header");
 +				break;
 +			case LZMADEC_MEM_ERROR:
 +				archive_set_error(&a->archive,
 +				    ENOMEM,
 +				    "Internal error initializing "
 +				    "compression library: "
 +				    "out of memory");
 +				break;
 +			}
 +			return (ARCHIVE_FATAL);
 +		}
 +		xar->lzstream_valid = 1;
 +		xar->lzstream.total_in = 0;
 +		xar->lzstream.total_out = 0;
 +		break;
 +#endif
 +	/*
 +	 * Unsupported compression.
 +	 */
 +	default:
 +#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
 +	case BZIP2:
 +#endif
 +#if !defined(HAVE_LZMA_H) || !defined(HAVE_LIBLZMA)
 +#if !defined(HAVE_LZMADEC_H) || !defined(HAVE_LIBLZMADEC)
 +	case LZMA:
 +#endif
 +	case XZ:
 +#endif
 +		switch (xar->entry_encoding) {
 +		case BZIP2: detail = "bzip2"; break;
 +		case LZMA: detail = "lzma"; break;
 +		case XZ: detail = "xz"; break;
 +		default: detail = "??"; break;
 +		}
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "%s compression not supported on this platform",
 +		    detail);
 +		return (ARCHIVE_FAILED);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +decompress(struct archive_read *a, const void **buff, size_t *outbytes,
 +    const void *b, size_t *used)
 +{
 +	struct xar *xar;
 +	void *outbuff;
 +	size_t avail_in, avail_out;
 +	int r;
 +
 +	xar = (struct xar *)(a->format->data);
 +	avail_in = *used;
 +	outbuff = (void *)(uintptr_t)*buff;
 +	if (outbuff == NULL) {
 +		if (xar->outbuff == NULL) {
 +			xar->outbuff = malloc(OUTBUFF_SIZE);
 +			if (xar->outbuff == NULL) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "Couldn't allocate memory for out buffer");
 +				return (ARCHIVE_FATAL);
 +			}
 +		}
 +		outbuff = xar->outbuff;
 +		*buff = outbuff;
 +		avail_out = OUTBUFF_SIZE;
 +	} else
 +		avail_out = *outbytes;
 +	switch (xar->rd_encoding) {
 +	case GZIP:
 +		xar->stream.next_in = (Bytef *)(uintptr_t)b;
 +		xar->stream.avail_in = avail_in;
 +		xar->stream.next_out = (unsigned char *)outbuff;
 +		xar->stream.avail_out = avail_out;
 +		r = inflate(&(xar->stream), 0);
 +		switch (r) {
 +		case Z_OK: /* Decompressor made some progress.*/
 +		case Z_STREAM_END: /* Found end of stream. */
 +			break;
 +		default:
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "File decompression failed (%d)", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		*used = avail_in - xar->stream.avail_in;
 +		*outbytes = avail_out - xar->stream.avail_out;
 +		break;
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	case BZIP2:
 +		xar->bzstream.next_in = (char *)(uintptr_t)b;
 +		xar->bzstream.avail_in = avail_in;
 +		xar->bzstream.next_out = (char *)outbuff;
 +		xar->bzstream.avail_out = avail_out;
 +		r = BZ2_bzDecompress(&(xar->bzstream));
 +		switch (r) {
 +		case BZ_STREAM_END: /* Found end of stream. */
 +			switch (BZ2_bzDecompressEnd(&(xar->bzstream))) {
 +			case BZ_OK:
 +				break;
 +			default:
 +				archive_set_error(&(a->archive),
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Failed to clean up decompressor");
 +				return (ARCHIVE_FATAL);
 +			}
 +			xar->bzstream_valid = 0;
 +			/* FALLTHROUGH */
 +		case BZ_OK: /* Decompressor made some progress. */
 +			break;
 +		default:
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "bzip decompression failed");
 +			return (ARCHIVE_FATAL);
 +		}
 +		*used = avail_in - xar->bzstream.avail_in;
 +		*outbytes = avail_out - xar->bzstream.avail_out;
 +		break;
 +#endif
 +#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
 +	case LZMA:
 +	case XZ:
 +		xar->lzstream.next_in = b;
 +		xar->lzstream.avail_in = avail_in;
 +		xar->lzstream.next_out = (unsigned char *)outbuff;
 +		xar->lzstream.avail_out = avail_out;
 +		r = lzma_code(&(xar->lzstream), LZMA_RUN);
 +		switch (r) {
 +		case LZMA_STREAM_END: /* Found end of stream. */
 +			lzma_end(&(xar->lzstream));
 +			xar->lzstream_valid = 0;
 +			/* FALLTHROUGH */
 +		case LZMA_OK: /* Decompressor made some progress. */
 +			break;
 +		default:
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "%s decompression failed(%d)",
 +			    (xar->entry_encoding == XZ)?"xz":"lzma",
 +			    r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		*used = avail_in - xar->lzstream.avail_in;
 +		*outbytes = avail_out - xar->lzstream.avail_out;
 +		break;
 +#elif defined(HAVE_LZMADEC_H) && defined(HAVE_LIBLZMADEC)
 +	case LZMA:
 +		xar->lzstream.next_in = (unsigned char *)(uintptr_t)b;
 +		xar->lzstream.avail_in = avail_in;
 +		xar->lzstream.next_out = (unsigned char *)outbuff;
 +		xar->lzstream.avail_out = avail_out;
 +		r = lzmadec_decode(&(xar->lzstream), 0);
 +		switch (r) {
 +		case LZMADEC_STREAM_END: /* Found end of stream. */
 +			switch (lzmadec_end(&(xar->lzstream))) {
 +			case LZMADEC_OK:
 +				break;
 +			default:
 +				archive_set_error(&(a->archive),
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Failed to clean up lzmadec decompressor");
 +				return (ARCHIVE_FATAL);
 +			}
 +			xar->lzstream_valid = 0;
 +			/* FALLTHROUGH */
 +		case LZMADEC_OK: /* Decompressor made some progress. */
 +			break;
 +		default:
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "lzmadec decompression failed(%d)",
 +			    r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		*used = avail_in - xar->lzstream.avail_in;
 +		*outbytes = avail_out - xar->lzstream.avail_out;
 +		break;
 +#endif
 +#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
 +	case BZIP2:
 +#endif
 +#if !defined(HAVE_LZMA_H) || !defined(HAVE_LIBLZMA)
 +#if !defined(HAVE_LZMADEC_H) || !defined(HAVE_LIBLZMADEC)
 +	case LZMA:
 +#endif
 +	case XZ:
 +#endif
 +	case NONE:
 +	default:
 +		if (outbuff == xar->outbuff) {
 +			*buff = b;
 +			*used = avail_in;
 +			*outbytes = avail_in;
 +		} else {
 +			if (avail_out > avail_in)
 +				avail_out = avail_in;
 +			memcpy(outbuff, b, avail_out);
 +			*used = avail_out;
 +			*outbytes = avail_out;
 +		}
 +		break;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +decompression_cleanup(struct archive_read *a)
 +{
 +	struct xar *xar;
 +	int r;
 +
 +	xar = (struct xar *)(a->format->data);
 +	r = ARCHIVE_OK;
 +	if (xar->stream_valid) {
 +		if (inflateEnd(&(xar->stream)) != Z_OK) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Failed to clean up zlib decompressor");
 +			r = ARCHIVE_FATAL;
 +		}
 +	}
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	if (xar->bzstream_valid) {
 +		if (BZ2_bzDecompressEnd(&(xar->bzstream)) != BZ_OK) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Failed to clean up bzip2 decompressor");
 +			r = ARCHIVE_FATAL;
 +		}
 +	}
 +#endif
 +#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
 +	if (xar->lzstream_valid)
 +		lzma_end(&(xar->lzstream));
 +#elif defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
 +	if (xar->lzstream_valid) {
 +		if (lzmadec_end(&(xar->lzstream)) != LZMADEC_OK) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Failed to clean up lzmadec decompressor");
 +			r = ARCHIVE_FATAL;
 +		}
 +	}
 +#endif
 +	return (r);
 +}
 +
 +static void
 +xmlattr_cleanup(struct xmlattr_list *list)
 +{
 +	struct xmlattr *attr, *next;
 +
 +	attr = list->first;
 +	while (attr != NULL) {
 +		next = attr->next;
 +		free(attr->name);
 +		free(attr->value);
 +		free(attr);
 +		attr = next;
 +	}
 +	list->first = NULL;
 +	list->last = &(list->first);
 +}
 +
 +static int
 +file_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)
 +{
 +	struct xar_file *file;
 +	struct xmlattr *attr;
 +
 +	file = calloc(1, sizeof(*file));
 +	if (file == NULL) {
 +		archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	file->parent = xar->file;
 +	file->mode = 0777 | AE_IFREG;
 +	file->atime = time(NULL);
 +	file->mtime = time(NULL);
 +	xar->file = file;
 +	xar->xattr = NULL;
 +	for (attr = list->first; attr != NULL; attr = attr->next) {
 +		if (strcmp(attr->name, "id") == 0)
 +			file->id = atol10(attr->value, strlen(attr->value));
 +	}
 +	file->nlink = 1;
 +	if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +file_free(struct xar_file *file)
 +{
 +	struct xattr *xattr;
 +
 +	archive_string_free(&(file->pathname));
 +	archive_string_free(&(file->symlink));
 +	archive_string_free(&(file->uname));
 +	archive_string_free(&(file->gname));
 +	archive_string_free(&(file->hardlink));
 +	xattr = file->xattr_list;
 +	while (xattr != NULL) {
 +		struct xattr *next;
 +
 +		next = xattr->next;
 +		xattr_free(xattr);
 +		xattr = next;
 +	}
 +
 +	free(file);
 +}
 +
 +static int
 +xattr_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)
 +{
 +	struct xattr *xattr, **nx;
 +	struct xmlattr *attr;
 +
 +	xattr = calloc(1, sizeof(*xattr));
 +	if (xattr == NULL) {
 +		archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	xar->xattr = xattr;
 +	for (attr = list->first; attr != NULL; attr = attr->next) {
 +		if (strcmp(attr->name, "id") == 0)
 +			xattr->id = atol10(attr->value, strlen(attr->value));
 +	}
 +	/* Chain to xattr list. */
 +	for (nx = &(xar->file->xattr_list);
 +	    *nx != NULL; nx = &((*nx)->next)) {
 +		if (xattr->id < (*nx)->id)
 +			break;
 +	}
 +	xattr->next = *nx;
 +	*nx = xattr;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +xattr_free(struct xattr *xattr)
 +{
 +	archive_string_free(&(xattr->name));
 +	free(xattr);
 +}
 +
 +static int
 +getencoding(struct xmlattr_list *list)
 +{
 +	struct xmlattr *attr;
 +	enum enctype encoding = NONE;
 +
 +	for (attr = list->first; attr != NULL; attr = attr->next) {
 +		if (strcmp(attr->name, "style") == 0) {
 +			if (strcmp(attr->value, "application/octet-stream") == 0)
 +				encoding = NONE;
 +			else if (strcmp(attr->value, "application/x-gzip") == 0)
 +				encoding = GZIP;
 +			else if (strcmp(attr->value, "application/x-bzip2") == 0)
 +				encoding = BZIP2;
 +			else if (strcmp(attr->value, "application/x-lzma") == 0)
 +				encoding = LZMA;
 +			else if (strcmp(attr->value, "application/x-xz") == 0)
 +				encoding = XZ;
 +		}
 +	}
 +	return (encoding);
 +}
 +
 +static int
 +getsumalgorithm(struct xmlattr_list *list)
 +{
 +	struct xmlattr *attr;
 +	int alg = CKSUM_NONE;
 +
 +	for (attr = list->first; attr != NULL; attr = attr->next) {
 +		if (strcmp(attr->name, "style") == 0) {
 +			const char *v = attr->value;
 +			if ((v[0] == 'S' || v[0] == 's') &&
 +			    (v[1] == 'H' || v[1] == 'h') &&
 +			    (v[2] == 'A' || v[2] == 'a') &&
 +			    v[3] == '1' && v[4] == '\0')
 +				alg = CKSUM_SHA1;
 +			if ((v[0] == 'M' || v[0] == 'm') &&
 +			    (v[1] == 'D' || v[1] == 'd') &&
 +			    v[2] == '5' && v[3] == '\0')
 +				alg = CKSUM_MD5;
 +		}
 +	}
 +	return (alg);
 +}
 +
 +static int
 +unknowntag_start(struct archive_read *a, struct xar *xar, const char *name)
 +{
 +	struct unknown_tag *tag;
 +
 +#if DEBUG
 +	fprintf(stderr, "unknowntag_start:%s\n", name);
 +#endif
 +	tag = malloc(sizeof(*tag));
 +	if (tag == NULL) {
 +		archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	tag->next = xar->unknowntags;
 +	archive_string_init(&(tag->name));
 +	archive_strcpy(&(tag->name), name);
 +	if (xar->unknowntags == NULL) {
 +		xar->xmlsts_unknown = xar->xmlsts;
 +		xar->xmlsts = UNKNOWN;
 +	}
 +	xar->unknowntags = tag;
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +unknowntag_end(struct xar *xar, const char *name)
 +{
 +	struct unknown_tag *tag;
 +
 +#if DEBUG
 +	fprintf(stderr, "unknowntag_end:%s\n", name);
 +#endif
 +	tag = xar->unknowntags;
 +	if (tag == NULL || name == NULL)
 +		return;
 +	if (strcmp(tag->name.s, name) == 0) {
 +		xar->unknowntags = tag->next;
 +		archive_string_free(&(tag->name));
 +		free(tag);
 +		if (xar->unknowntags == NULL)
 +			xar->xmlsts = xar->xmlsts_unknown;
 +	}
 +}
 +
 +static int
 +xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
 +{
 +	struct xar *xar;
 +	struct xmlattr *attr;
 +
 +	xar = (struct xar *)(a->format->data);
 +
 +#if DEBUG
 +	fprintf(stderr, "xml_sta:[%s]\n", name);
 +	for (attr = list->first; attr != NULL; attr = attr->next)
 +		fprintf(stderr, "    attr:\"%s\"=\"%s\"\n",
 +		    attr->name, attr->value);
 +#endif
 +	xar->base64text = 0;
 +	switch (xar->xmlsts) {
 +	case INIT:
 +		if (strcmp(name, "xar") == 0)
 +			xar->xmlsts = XAR;
 +		else
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case XAR:
 +		if (strcmp(name, "toc") == 0)
 +			xar->xmlsts = TOC;
 +		else
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case TOC:
 +		if (strcmp(name, "creation-time") == 0)
 +			xar->xmlsts = TOC_CREATION_TIME;
 +		else if (strcmp(name, "checksum") == 0)
 +			xar->xmlsts = TOC_CHECKSUM;
 +		else if (strcmp(name, "file") == 0) {
 +			if (file_new(a, xar, list) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			xar->xmlsts = TOC_FILE;
 +		}
 +		else
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case TOC_CHECKSUM:
 +		if (strcmp(name, "offset") == 0)
 +			xar->xmlsts = TOC_CHECKSUM_OFFSET;
 +		else if (strcmp(name, "size") == 0)
 +			xar->xmlsts = TOC_CHECKSUM_SIZE;
 +		else
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case TOC_FILE:
 +		if (strcmp(name, "file") == 0) {
 +			if (file_new(a, xar, list) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		}
 +		else if (strcmp(name, "data") == 0)
 +			xar->xmlsts = FILE_DATA;
 +		else if (strcmp(name, "ea") == 0) {
 +			if (xattr_new(a, xar, list) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			xar->xmlsts = FILE_EA;
 +		}
 +		else if (strcmp(name, "ctime") == 0)
 +			xar->xmlsts = FILE_CTIME;
 +		else if (strcmp(name, "mtime") == 0)
 +			xar->xmlsts = FILE_MTIME;
 +		else if (strcmp(name, "atime") == 0)
 +			xar->xmlsts = FILE_ATIME;
 +		else if (strcmp(name, "group") == 0)
 +			xar->xmlsts = FILE_GROUP;
 +		else if (strcmp(name, "gid") == 0)
 +			xar->xmlsts = FILE_GID;
 +		else if (strcmp(name, "user") == 0)
 +			xar->xmlsts = FILE_USER;
 +		else if (strcmp(name, "uid") == 0)
 +			xar->xmlsts = FILE_UID;
 +		else if (strcmp(name, "mode") == 0)
 +			xar->xmlsts = FILE_MODE;
 +		else if (strcmp(name, "device") == 0)
 +			xar->xmlsts = FILE_DEVICE;
 +		else if (strcmp(name, "deviceno") == 0)
 +			xar->xmlsts = FILE_DEVICENO;
 +		else if (strcmp(name, "inode") == 0)
 +			xar->xmlsts = FILE_INODE;
 +		else if (strcmp(name, "link") == 0)
 +			xar->xmlsts = FILE_LINK;
 +		else if (strcmp(name, "type") == 0) {
 +			xar->xmlsts = FILE_TYPE;
 +			for (attr = list->first; attr != NULL;
 +			    attr = attr->next) {
 +				if (strcmp(attr->name, "link") != 0)
 +					continue;
 +				if (strcmp(attr->value, "original") == 0) {
 +					xar->file->hdnext = xar->hdlink_orgs;
 +					xar->hdlink_orgs = xar->file;
 +				} else {
- 					xar->file->link = atol10(attr->value,
++					xar->file->link = (unsigned)atol10(attr->value,
 +					    strlen(attr->value));
 +					if (xar->file->link > 0)
 +						if (add_link(a, xar, xar->file) != ARCHIVE_OK) {
 +							return (ARCHIVE_FATAL);
 +						};
 +				}
 +			}
 +		}
 +		else if (strcmp(name, "name") == 0) {
 +			xar->xmlsts = FILE_NAME;
 +			for (attr = list->first; attr != NULL;
 +			    attr = attr->next) {
 +				if (strcmp(attr->name, "enctype") == 0 &&
 +				    strcmp(attr->value, "base64") == 0)
 +					xar->base64text = 1;
 +			}
 +		}
 +		else if (strcmp(name, "acl") == 0)
 +			xar->xmlsts = FILE_ACL;
 +		else if (strcmp(name, "flags") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		else if (strcmp(name, "ext2") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		else
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case FILE_DATA:
 +		if (strcmp(name, "length") == 0)
 +			xar->xmlsts = FILE_DATA_LENGTH;
 +		else if (strcmp(name, "offset") == 0)
 +			xar->xmlsts = FILE_DATA_OFFSET;
 +		else if (strcmp(name, "size") == 0)
 +			xar->xmlsts = FILE_DATA_SIZE;
 +		else if (strcmp(name, "encoding") == 0) {
 +			xar->xmlsts = FILE_DATA_ENCODING;
 +			xar->file->encoding = getencoding(list);
 +		}
 +		else if (strcmp(name, "archived-checksum") == 0) {
 +			xar->xmlsts = FILE_DATA_A_CHECKSUM;
 +			xar->file->a_sum.alg = getsumalgorithm(list);
 +		}
 +		else if (strcmp(name, "extracted-checksum") == 0) {
 +			xar->xmlsts = FILE_DATA_E_CHECKSUM;
 +			xar->file->e_sum.alg = getsumalgorithm(list);
 +		}
 +		else if (strcmp(name, "content") == 0)
 +			xar->xmlsts = FILE_DATA_CONTENT;
 +		else
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case FILE_DEVICE:
 +		if (strcmp(name, "major") == 0)
 +			xar->xmlsts = FILE_DEVICE_MAJOR;
 +		else if (strcmp(name, "minor") == 0)
 +			xar->xmlsts = FILE_DEVICE_MINOR;
 +		else
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case FILE_DATA_CONTENT:
 +		if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		break;
 +	case FILE_EA:
 +		if (strcmp(name, "length") == 0)
 +			xar->xmlsts = FILE_EA_LENGTH;
 +		else if (strcmp(name, "offset") == 0)
 +			xar->xmlsts = FILE_EA_OFFSET;
 +		else if (strcmp(name, "size") == 0)
 +			xar->xmlsts = FILE_EA_SIZE;
 +		else if (strcmp(name, "encoding") == 0) {
 +			xar->xmlsts = FILE_EA_ENCODING;
 +			xar->xattr->encoding = getencoding(list);
 +		} else if (strcmp(name, "archived-checksum") == 0)
 +			xar->xmlsts = FILE_EA_A_CHECKSUM;
 +		else if (strcmp(name, "extracted-checksum") == 0)
 +			xar->xmlsts = FILE_EA_E_CHECKSUM;
 +		else if (strcmp(name, "name") == 0)
 +			xar->xmlsts = FILE_EA_NAME;
 +		else if (strcmp(name, "fstype") == 0)
 +			xar->xmlsts = FILE_EA_FSTYPE;
 +		else
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case FILE_ACL:
 +		if (strcmp(name, "appleextended") == 0)
 +			xar->xmlsts = FILE_ACL_APPLEEXTENDED;
 +		if (strcmp(name, "default") == 0)
 +			xar->xmlsts = FILE_ACL_DEFAULT;
 +		else if (strcmp(name, "access") == 0)
 +			xar->xmlsts = FILE_ACL_ACCESS;
 +		else
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case FILE_FLAGS:
 +		if (!xml_parse_file_flags(xar, name))
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case FILE_EXT2:
 +		if (!xml_parse_file_ext2(xar, name))
 +			if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		break;
 +	case TOC_CREATION_TIME:
 +	case TOC_CHECKSUM_OFFSET:
 +	case TOC_CHECKSUM_SIZE:
 +	case FILE_DATA_LENGTH:
 +	case FILE_DATA_OFFSET:
 +	case FILE_DATA_SIZE:
 +	case FILE_DATA_ENCODING:
 +	case FILE_DATA_A_CHECKSUM:
 +	case FILE_DATA_E_CHECKSUM:
 +	case FILE_EA_LENGTH:
 +	case FILE_EA_OFFSET:
 +	case FILE_EA_SIZE:
 +	case FILE_EA_ENCODING:
 +	case FILE_EA_A_CHECKSUM:
 +	case FILE_EA_E_CHECKSUM:
 +	case FILE_EA_NAME:
 +	case FILE_EA_FSTYPE:
 +	case FILE_CTIME:
 +	case FILE_MTIME:
 +	case FILE_ATIME:
 +	case FILE_GROUP:
 +	case FILE_GID:
 +	case FILE_USER:
 +	case FILE_UID:
 +	case FILE_INODE:
 +	case FILE_DEVICE_MAJOR:
 +	case FILE_DEVICE_MINOR:
 +	case FILE_DEVICENO:
 +	case FILE_MODE:
 +	case FILE_TYPE:
 +	case FILE_LINK:
 +	case FILE_NAME:
 +	case FILE_ACL_DEFAULT:
 +	case FILE_ACL_ACCESS:
 +	case FILE_ACL_APPLEEXTENDED:
 +	case FILE_FLAGS_USER_NODUMP:
 +	case FILE_FLAGS_USER_IMMUTABLE:
 +	case FILE_FLAGS_USER_APPEND:
 +	case FILE_FLAGS_USER_OPAQUE:
 +	case FILE_FLAGS_USER_NOUNLINK:
 +	case FILE_FLAGS_SYS_ARCHIVED:
 +	case FILE_FLAGS_SYS_IMMUTABLE:
 +	case FILE_FLAGS_SYS_APPEND:
 +	case FILE_FLAGS_SYS_NOUNLINK:
 +	case FILE_FLAGS_SYS_SNAPSHOT:
 +	case FILE_EXT2_SecureDeletion:
 +	case FILE_EXT2_Undelete:
 +	case FILE_EXT2_Compress:
 +	case FILE_EXT2_Synchronous:
 +	case FILE_EXT2_Immutable:
 +	case FILE_EXT2_AppendOnly:
 +	case FILE_EXT2_NoDump:
 +	case FILE_EXT2_NoAtime:
 +	case FILE_EXT2_CompDirty:
 +	case FILE_EXT2_CompBlock:
 +	case FILE_EXT2_NoCompBlock:
 +	case FILE_EXT2_CompError:
 +	case FILE_EXT2_BTree:
 +	case FILE_EXT2_HashIndexed:
 +	case FILE_EXT2_iMagic:
 +	case FILE_EXT2_Journaled:
 +	case FILE_EXT2_NoTail:
 +	case FILE_EXT2_DirSync:
 +	case FILE_EXT2_TopDir:
 +	case FILE_EXT2_Reserved:
 +	case UNKNOWN:
 +		if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		break;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +xml_end(void *userData, const char *name)
 +{
 +	struct archive_read *a;
 +	struct xar *xar;
 +
 +	a = (struct archive_read *)userData;
 +	xar = (struct xar *)(a->format->data);
 +
 +#if DEBUG
 +	fprintf(stderr, "xml_end:[%s]\n", name);
 +#endif
 +	switch (xar->xmlsts) {
 +	case INIT:
 +		break;
 +	case XAR:
 +		if (strcmp(name, "xar") == 0)
 +			xar->xmlsts = INIT;
 +		break;
 +	case TOC:
 +		if (strcmp(name, "toc") == 0)
 +			xar->xmlsts = XAR;
 +		break;
 +	case TOC_CREATION_TIME:
 +		if (strcmp(name, "creation-time") == 0)
 +			xar->xmlsts = TOC;
 +		break;
 +	case TOC_CHECKSUM:
 +		if (strcmp(name, "checksum") == 0)
 +			xar->xmlsts = TOC;
 +		break;
 +	case TOC_CHECKSUM_OFFSET:
 +		if (strcmp(name, "offset") == 0)
 +			xar->xmlsts = TOC_CHECKSUM;
 +		break;
 +	case TOC_CHECKSUM_SIZE:
 +		if (strcmp(name, "size") == 0)
 +			xar->xmlsts = TOC_CHECKSUM;
 +		break;
 +	case TOC_FILE:
 +		if (strcmp(name, "file") == 0) {
 +			if (xar->file->parent != NULL &&
 +			    ((xar->file->mode & AE_IFMT) == AE_IFDIR))
 +				xar->file->parent->subdirs++;
 +			xar->file = xar->file->parent;
 +			if (xar->file == NULL)
 +				xar->xmlsts = TOC;
 +		}
 +		break;
 +	case FILE_DATA:
 +		if (strcmp(name, "data") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_DATA_LENGTH:
 +		if (strcmp(name, "length") == 0)
 +			xar->xmlsts = FILE_DATA;
 +		break;
 +	case FILE_DATA_OFFSET:
 +		if (strcmp(name, "offset") == 0)
 +			xar->xmlsts = FILE_DATA;
 +		break;
 +	case FILE_DATA_SIZE:
 +		if (strcmp(name, "size") == 0)
 +			xar->xmlsts = FILE_DATA;
 +		break;
 +	case FILE_DATA_ENCODING:
 +		if (strcmp(name, "encoding") == 0)
 +			xar->xmlsts = FILE_DATA;
 +		break;
 +	case FILE_DATA_A_CHECKSUM:
 +		if (strcmp(name, "archived-checksum") == 0)
 +			xar->xmlsts = FILE_DATA;
 +		break;
 +	case FILE_DATA_E_CHECKSUM:
 +		if (strcmp(name, "extracted-checksum") == 0)
 +			xar->xmlsts = FILE_DATA;
 +		break;
 +	case FILE_DATA_CONTENT:
 +		if (strcmp(name, "content") == 0)
 +			xar->xmlsts = FILE_DATA;
 +		break;
 +	case FILE_EA:
 +		if (strcmp(name, "ea") == 0) {
 +			xar->xmlsts = TOC_FILE;
 +			xar->xattr = NULL;
 +		}
 +		break;
 +	case FILE_EA_LENGTH:
 +		if (strcmp(name, "length") == 0)
 +			xar->xmlsts = FILE_EA;
 +		break;
 +	case FILE_EA_OFFSET:
 +		if (strcmp(name, "offset") == 0)
 +			xar->xmlsts = FILE_EA;
 +		break;
 +	case FILE_EA_SIZE:
 +		if (strcmp(name, "size") == 0)
 +			xar->xmlsts = FILE_EA;
 +		break;
 +	case FILE_EA_ENCODING:
 +		if (strcmp(name, "encoding") == 0)
 +			xar->xmlsts = FILE_EA;
 +		break;
 +	case FILE_EA_A_CHECKSUM:
 +		if (strcmp(name, "archived-checksum") == 0)
 +			xar->xmlsts = FILE_EA;
 +		break;
 +	case FILE_EA_E_CHECKSUM:
 +		if (strcmp(name, "extracted-checksum") == 0)
 +			xar->xmlsts = FILE_EA;
 +		break;
 +	case FILE_EA_NAME:
 +		if (strcmp(name, "name") == 0)
 +			xar->xmlsts = FILE_EA;
 +		break;
 +	case FILE_EA_FSTYPE:
 +		if (strcmp(name, "fstype") == 0)
 +			xar->xmlsts = FILE_EA;
 +		break;
 +	case FILE_CTIME:
 +		if (strcmp(name, "ctime") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_MTIME:
 +		if (strcmp(name, "mtime") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_ATIME:
 +		if (strcmp(name, "atime") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_GROUP:
 +		if (strcmp(name, "group") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_GID:
 +		if (strcmp(name, "gid") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_USER:
 +		if (strcmp(name, "user") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_UID:
 +		if (strcmp(name, "uid") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_MODE:
 +		if (strcmp(name, "mode") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_DEVICE:
 +		if (strcmp(name, "device") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_DEVICE_MAJOR:
 +		if (strcmp(name, "major") == 0)
 +			xar->xmlsts = FILE_DEVICE;
 +		break;
 +	case FILE_DEVICE_MINOR:
 +		if (strcmp(name, "minor") == 0)
 +			xar->xmlsts = FILE_DEVICE;
 +		break;
 +	case FILE_DEVICENO:
 +		if (strcmp(name, "deviceno") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_INODE:
 +		if (strcmp(name, "inode") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_LINK:
 +		if (strcmp(name, "link") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_TYPE:
 +		if (strcmp(name, "type") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_NAME:
 +		if (strcmp(name, "name") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_ACL:
 +		if (strcmp(name, "acl") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_ACL_DEFAULT:
 +		if (strcmp(name, "default") == 0)
 +			xar->xmlsts = FILE_ACL;
 +		break;
 +	case FILE_ACL_ACCESS:
 +		if (strcmp(name, "access") == 0)
 +			xar->xmlsts = FILE_ACL;
 +		break;
 +	case FILE_ACL_APPLEEXTENDED:
 +		if (strcmp(name, "appleextended") == 0)
 +			xar->xmlsts = FILE_ACL;
 +		break;
 +	case FILE_FLAGS:
 +		if (strcmp(name, "flags") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_FLAGS_USER_NODUMP:
 +		if (strcmp(name, "UserNoDump") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		break;
 +	case FILE_FLAGS_USER_IMMUTABLE:
 +		if (strcmp(name, "UserImmutable") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		break;
 +	case FILE_FLAGS_USER_APPEND:
 +		if (strcmp(name, "UserAppend") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		break;
 +	case FILE_FLAGS_USER_OPAQUE:
 +		if (strcmp(name, "UserOpaque") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		break;
 +	case FILE_FLAGS_USER_NOUNLINK:
 +		if (strcmp(name, "UserNoUnlink") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		break;
 +	case FILE_FLAGS_SYS_ARCHIVED:
 +		if (strcmp(name, "SystemArchived") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		break;
 +	case FILE_FLAGS_SYS_IMMUTABLE:
 +		if (strcmp(name, "SystemImmutable") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		break;
 +	case FILE_FLAGS_SYS_APPEND:
 +		if (strcmp(name, "SystemAppend") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		break;
 +	case FILE_FLAGS_SYS_NOUNLINK:
 +		if (strcmp(name, "SystemNoUnlink") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		break;
 +	case FILE_FLAGS_SYS_SNAPSHOT:
 +		if (strcmp(name, "SystemSnapshot") == 0)
 +			xar->xmlsts = FILE_FLAGS;
 +		break;
 +	case FILE_EXT2:
 +		if (strcmp(name, "ext2") == 0)
 +			xar->xmlsts = TOC_FILE;
 +		break;
 +	case FILE_EXT2_SecureDeletion:
 +		if (strcmp(name, "SecureDeletion") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_Undelete:
 +		if (strcmp(name, "Undelete") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_Compress:
 +		if (strcmp(name, "Compress") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_Synchronous:
 +		if (strcmp(name, "Synchronous") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_Immutable:
 +		if (strcmp(name, "Immutable") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_AppendOnly:
 +		if (strcmp(name, "AppendOnly") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_NoDump:
 +		if (strcmp(name, "NoDump") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_NoAtime:
 +		if (strcmp(name, "NoAtime") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_CompDirty:
 +		if (strcmp(name, "CompDirty") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_CompBlock:
 +		if (strcmp(name, "CompBlock") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_NoCompBlock:
 +		if (strcmp(name, "NoCompBlock") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_CompError:
 +		if (strcmp(name, "CompError") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_BTree:
 +		if (strcmp(name, "BTree") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_HashIndexed:
 +		if (strcmp(name, "HashIndexed") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_iMagic:
 +		if (strcmp(name, "iMagic") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_Journaled:
 +		if (strcmp(name, "Journaled") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_NoTail:
 +		if (strcmp(name, "NoTail") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_DirSync:
 +		if (strcmp(name, "DirSync") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_TopDir:
 +		if (strcmp(name, "TopDir") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case FILE_EXT2_Reserved:
 +		if (strcmp(name, "Reserved") == 0)
 +			xar->xmlsts = FILE_EXT2;
 +		break;
 +	case UNKNOWN:
 +		unknowntag_end(xar, name);
 +		break;
 +	}
 +}
 +
 +static const int base64[256] = {
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, -1, -1, -1, -1, -1, /* 00 - 0F */
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, -1, -1, -1, -1, -1, /* 10 - 1F */
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, 62, -1, -1, -1, 63, /* 20 - 2F */
 +	52, 53, 54, 55, 56, 57, 58, 59,
 +	60, 61, -1, -1, -1, -1, -1, -1, /* 30 - 3F */
 +	-1,  0,  1,  2,  3,  4,  5,  6,
 +	 7,  8,  9, 10, 11, 12, 13, 14, /* 40 - 4F */
 +	15, 16, 17, 18, 19, 20, 21, 22,
 +	23, 24, 25, -1, -1, -1, -1, -1, /* 50 - 5F */
 +	-1, 26, 27, 28, 29, 30, 31, 32,
 +	33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */
 +	41, 42, 43, 44, 45, 46, 47, 48,
 +	49, 50, 51, -1, -1, -1, -1, -1, /* 70 - 7F */
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, -1, -1, -1, -1, -1, /* 80 - 8F */
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, -1, -1, -1, -1, -1, /* 90 - 9F */
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, -1, -1, -1, -1, -1, /* A0 - AF */
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, -1, -1, -1, -1, -1, /* B0 - BF */
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, -1, -1, -1, -1, -1, /* C0 - CF */
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, -1, -1, -1, -1, -1, /* D0 - DF */
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, -1, -1, -1, -1, -1, /* E0 - EF */
 +	-1, -1, -1, -1, -1, -1, -1, -1,
 +	-1, -1, -1, -1, -1, -1, -1, -1, /* F0 - FF */
 +};
 +
 +static void
 +strappend_base64(struct xar *xar,
 +    struct archive_string *as, const char *s, size_t l)
 +{
 +	unsigned char buff[256];
 +	unsigned char *out;
 +	const unsigned char *b;
 +	size_t len;
 +
++	(void)xar; /* UNUSED */
 +	len = 0;
 +	out = buff;
 +	b = (const unsigned char *)s;
 +	while (l > 0) {
 +		int n = 0;
 +
 +		if (l > 0) {
 +			if (base64[b[0]] < 0 || base64[b[1]] < 0)
 +				break;
 +			n = base64[*b++] << 18;
 +			n |= base64[*b++] << 12;
 +			*out++ = n >> 16;
 +			len++;
 +			l -= 2;
 +		}
 +		if (l > 0) {
 +			if (base64[*b] < 0)
 +				break;
 +			n |= base64[*b++] << 6;
 +			*out++ = (n >> 8) & 0xFF;
 +			len++;
 +			--l;
 +		}
 +		if (l > 0) {
 +			if (base64[*b] < 0)
 +				break;
 +			n |= base64[*b++];
 +			*out++ = n & 0xFF;
 +			len++;
 +			--l;
 +		}
 +		if (len+3 >= sizeof(buff)) {
 +			archive_strncat(as, (const char *)buff, len);
 +			len = 0;
 +			out = buff;
 +		}
 +	}
 +	if (len > 0)
 +		archive_strncat(as, (const char *)buff, len);
 +}
 +
 +static void
 +xml_data(void *userData, const char *s, int len)
 +{
 +	struct archive_read *a;
 +	struct xar *xar;
 +
 +	a = (struct archive_read *)userData;
 +	xar = (struct xar *)(a->format->data);
 +
 +#if DEBUG
 +	{
 +		char buff[1024];
 +		if (len > sizeof(buff)-1)
 +			len = sizeof(buff)-1;
 +		memcpy(buff, s, len);
 +		buff[len] = 0;
 +		fprintf(stderr, "\tlen=%d:\"%s\"\n", len, buff);
 +	}
 +#endif
 +	switch (xar->xmlsts) {
 +	case TOC_CHECKSUM_OFFSET:
 +		xar->toc_chksum_offset = atol10(s, len);
 +		break;
 +	case TOC_CHECKSUM_SIZE:
 +		xar->toc_chksum_size = atol10(s, len);
 +		break;
 +	default:
 +		break;
 +	}
 +	if (xar->file == NULL)
 +		return;
 +
 +	switch (xar->xmlsts) {
 +	case FILE_NAME:
 +		if (xar->file->parent != NULL) {
 +			archive_string_concat(&(xar->file->pathname),
 +			    &(xar->file->parent->pathname));
 +			archive_strappend_char(&(xar->file->pathname), '/');
 +		}
 +		xar->file->has |= HAS_PATHNAME;
 +		if (xar->base64text) {
 +			strappend_base64(xar,
 +			    &(xar->file->pathname), s, len);
 +		} else
 +			archive_strncat(&(xar->file->pathname), s, len);
 +		break;
 +	case FILE_LINK:
 +		xar->file->has |= HAS_SYMLINK;
 +		archive_strncpy(&(xar->file->symlink), s, len);
 +		break;
 +	case FILE_TYPE:
 +		if (strncmp("file", s, len) == 0 ||
 +		    strncmp("hardlink", s, len) == 0)
 +			xar->file->mode =
 +			    (xar->file->mode & ~AE_IFMT) | AE_IFREG;
 +		if (strncmp("directory", s, len) == 0)
 +			xar->file->mode =
 +			    (xar->file->mode & ~AE_IFMT) | AE_IFDIR;
 +		if (strncmp("symlink", s, len) == 0)
 +			xar->file->mode =
 +			    (xar->file->mode & ~AE_IFMT) | AE_IFLNK;
 +		if (strncmp("character special", s, len) == 0)
 +			xar->file->mode =
 +			    (xar->file->mode & ~AE_IFMT) | AE_IFCHR;
 +		if (strncmp("block special", s, len) == 0)
 +			xar->file->mode =
 +			    (xar->file->mode & ~AE_IFMT) | AE_IFBLK;
 +		if (strncmp("socket", s, len) == 0)
 +			xar->file->mode =
 +			    (xar->file->mode & ~AE_IFMT) | AE_IFSOCK;
 +		if (strncmp("fifo", s, len) == 0)
 +			xar->file->mode =
 +			    (xar->file->mode & ~AE_IFMT) | AE_IFIFO;
 +		xar->file->has |= HAS_TYPE;
 +		break;
 +	case FILE_INODE:
 +		xar->file->has |= HAS_INO;
 +		xar->file->ino64 = atol10(s, len);
 +		break;
 +	case FILE_DEVICE_MAJOR:
 +		xar->file->has |= HAS_DEVMAJOR;
 +		xar->file->devmajor = (dev_t)atol10(s, len);
 +		break;
 +	case FILE_DEVICE_MINOR:
 +		xar->file->has |= HAS_DEVMINOR;
 +		xar->file->devminor = (dev_t)atol10(s, len);
 +		break;
 +	case FILE_DEVICENO:
 +		xar->file->has |= HAS_DEV;
 +		xar->file->dev = (dev_t)atol10(s, len);
 +		break;
 +	case FILE_MODE:
 +		xar->file->has |= HAS_MODE;
 +		xar->file->mode =
 +		    (xar->file->mode & AE_IFMT) |
- 		    (atol8(s, len) & ~AE_IFMT);
++		    ((mode_t)(atol8(s, len)) & ~AE_IFMT);
 +		break;
 +	case FILE_GROUP:
 +		xar->file->has |= HAS_GID;
 +		archive_strncpy(&(xar->file->gname), s, len);
 +		break;
 +	case FILE_GID:
 +		xar->file->has |= HAS_GID;
 +		xar->file->gid = atol10(s, len);
 +		break;
 +	case FILE_USER:
 +		xar->file->has |= HAS_UID;
 +		archive_strncpy(&(xar->file->uname), s, len);
 +		break;
 +	case FILE_UID:
 +		xar->file->has |= HAS_UID;
 +		xar->file->uid = atol10(s, len);
 +		break;
 +	case FILE_CTIME:
 +		xar->file->has |= HAS_TIME;
 +		xar->file->ctime = parse_time(s, len);
 +		break;
 +	case FILE_MTIME:
 +		xar->file->has |= HAS_TIME;
 +		xar->file->mtime = parse_time(s, len);
 +		break;
 +	case FILE_ATIME:
 +		xar->file->has |= HAS_TIME;
 +		xar->file->atime = parse_time(s, len);
 +		break;
 +	case FILE_DATA_LENGTH:
 +		xar->file->has |= HAS_DATA;
 +		xar->file->length = atol10(s, len);
 +		break;
 +	case FILE_DATA_OFFSET:
 +		xar->file->has |= HAS_DATA;
 +		xar->file->offset = atol10(s, len);
 +		break;
 +	case FILE_DATA_SIZE:
 +		xar->file->has |= HAS_DATA;
 +		xar->file->size = atol10(s, len);
 +		break;
 +	case FILE_DATA_A_CHECKSUM:
 +		xar->file->a_sum.len = atohex(xar->file->a_sum.val,
 +		    sizeof(xar->file->a_sum.val), s, len);
 +		break;
 +	case FILE_DATA_E_CHECKSUM:
 +		xar->file->e_sum.len = atohex(xar->file->e_sum.val,
 +		    sizeof(xar->file->e_sum.val), s, len);
 +		break;
 +	case FILE_EA_LENGTH:
 +		xar->file->has |= HAS_XATTR;
 +		xar->xattr->length = atol10(s, len);
 +		break;
 +	case FILE_EA_OFFSET:
 +		xar->file->has |= HAS_XATTR;
 +		xar->xattr->offset = atol10(s, len);
 +		break;
 +	case FILE_EA_SIZE:
 +		xar->file->has |= HAS_XATTR;
 +		xar->xattr->size = atol10(s, len);
 +		break;
 +	case FILE_EA_A_CHECKSUM:
 +		xar->file->has |= HAS_XATTR;
 +		xar->xattr->a_sum.len = atohex(xar->xattr->a_sum.val,
 +		    sizeof(xar->xattr->a_sum.val), s, len);
 +		break;
 +	case FILE_EA_E_CHECKSUM:
 +		xar->file->has |= HAS_XATTR;
 +		xar->xattr->e_sum.len = atohex(xar->xattr->e_sum.val,
 +		    sizeof(xar->xattr->e_sum.val), s, len);
 +		break;
 +	case FILE_EA_NAME:
 +		xar->file->has |= HAS_XATTR;
 +		archive_strncpy(&(xar->xattr->name), s, len);
 +		break;
 +	case FILE_EA_FSTYPE:
 +		xar->file->has |= HAS_XATTR;
 +		archive_strncpy(&(xar->xattr->fstype), s, len);
 +		break;
 +		break;
 +	case FILE_ACL_DEFAULT:
 +	case FILE_ACL_ACCESS:
 +	case FILE_ACL_APPLEEXTENDED:
 +		xar->file->has |= HAS_ACL;
 +		/* TODO */
 +		break;
 +	case INIT:
 +	case XAR:
 +	case TOC:
 +	case TOC_CREATION_TIME:
 +	case TOC_CHECKSUM:
 +	case TOC_CHECKSUM_OFFSET:
 +	case TOC_CHECKSUM_SIZE:
 +	case TOC_FILE:
 +	case FILE_DATA:
 +	case FILE_DATA_ENCODING:
 +	case FILE_DATA_CONTENT:
 +	case FILE_DEVICE:
 +	case FILE_EA:
 +	case FILE_EA_ENCODING:
 +	case FILE_ACL:
 +	case FILE_FLAGS:
 +	case FILE_FLAGS_USER_NODUMP:
 +	case FILE_FLAGS_USER_IMMUTABLE:
 +	case FILE_FLAGS_USER_APPEND:
 +	case FILE_FLAGS_USER_OPAQUE:
 +	case FILE_FLAGS_USER_NOUNLINK:
 +	case FILE_FLAGS_SYS_ARCHIVED:
 +	case FILE_FLAGS_SYS_IMMUTABLE:
 +	case FILE_FLAGS_SYS_APPEND:
 +	case FILE_FLAGS_SYS_NOUNLINK:
 +	case FILE_FLAGS_SYS_SNAPSHOT:
 +	case FILE_EXT2:
 +	case FILE_EXT2_SecureDeletion:
 +	case FILE_EXT2_Undelete:
 +	case FILE_EXT2_Compress:
 +	case FILE_EXT2_Synchronous:
 +	case FILE_EXT2_Immutable:
 +	case FILE_EXT2_AppendOnly:
 +	case FILE_EXT2_NoDump:
 +	case FILE_EXT2_NoAtime:
 +	case FILE_EXT2_CompDirty:
 +	case FILE_EXT2_CompBlock:
 +	case FILE_EXT2_NoCompBlock:
 +	case FILE_EXT2_CompError:
 +	case FILE_EXT2_BTree:
 +	case FILE_EXT2_HashIndexed:
 +	case FILE_EXT2_iMagic:
 +	case FILE_EXT2_Journaled:
 +	case FILE_EXT2_NoTail:
 +	case FILE_EXT2_DirSync:
 +	case FILE_EXT2_TopDir:
 +	case FILE_EXT2_Reserved:
 +	case UNKNOWN:
 +		break;
 +	}
 +}
 +
 +/*
 + * BSD file flags.
 + */
 +static int
 +xml_parse_file_flags(struct xar *xar, const char *name)
 +{
 +	const char *flag = NULL;
 +
 +	if (strcmp(name, "UserNoDump") == 0) {
 +		xar->xmlsts = FILE_FLAGS_USER_NODUMP;
 +		flag = "nodump";
 +	}
 +	else if (strcmp(name, "UserImmutable") == 0) {
 +		xar->xmlsts = FILE_FLAGS_USER_IMMUTABLE;
 +		flag = "uimmutable";
 +	}
 +	else if (strcmp(name, "UserAppend") == 0) {
 +		xar->xmlsts = FILE_FLAGS_USER_APPEND;
 +		flag = "uappend";
 +	}
 +	else if (strcmp(name, "UserOpaque") == 0) {
 +		xar->xmlsts = FILE_FLAGS_USER_OPAQUE;
 +		flag = "opaque";
 +	}
 +	else if (strcmp(name, "UserNoUnlink") == 0) {
 +		xar->xmlsts = FILE_FLAGS_USER_NOUNLINK;
 +		flag = "nouunlink";
 +	}
 +	else if (strcmp(name, "SystemArchived") == 0) {
 +		xar->xmlsts = FILE_FLAGS_SYS_ARCHIVED;
 +		flag = "archived";
 +	}
 +	else if (strcmp(name, "SystemImmutable") == 0) {
 +		xar->xmlsts = FILE_FLAGS_SYS_IMMUTABLE;
 +		flag = "simmutable";
 +	}
 +	else if (strcmp(name, "SystemAppend") == 0) {
 +		xar->xmlsts = FILE_FLAGS_SYS_APPEND;
 +		flag = "sappend";
 +	}
 +	else if (strcmp(name, "SystemNoUnlink") == 0) {
 +		xar->xmlsts = FILE_FLAGS_SYS_NOUNLINK;
 +		flag = "nosunlink";
 +	}
 +	else if (strcmp(name, "SystemSnapshot") == 0) {
 +		xar->xmlsts = FILE_FLAGS_SYS_SNAPSHOT;
 +		flag = "snapshot";
 +	}
 +
 +	if (flag == NULL)
 +		return (0);
 +	xar->file->has |= HAS_FFLAGS;
 +	if (archive_strlen(&(xar->file->fflags_text)) > 0)
 +		archive_strappend_char(&(xar->file->fflags_text), ',');
 +	archive_strcat(&(xar->file->fflags_text), flag);
 +	return (1);
 +}
 +
 +/*
 + * Linux file flags.
 + */
 +static int
 +xml_parse_file_ext2(struct xar *xar, const char *name)
 +{
 +	const char *flag = NULL;
 +
 +	if (strcmp(name, "SecureDeletion") == 0) {
 +		xar->xmlsts = FILE_EXT2_SecureDeletion;
 +		flag = "securedeletion";
 +	}
 +	else if (strcmp(name, "Undelete") == 0) {
 +		xar->xmlsts = FILE_EXT2_Undelete;
 +		flag = "nouunlink";
 +	}
 +	else if (strcmp(name, "Compress") == 0) {
 +		xar->xmlsts = FILE_EXT2_Compress;
 +		flag = "compress";
 +	}
 +	else if (strcmp(name, "Synchronous") == 0) {
 +		xar->xmlsts = FILE_EXT2_Synchronous;
 +		flag = "sync";
 +	}
 +	else if (strcmp(name, "Immutable") == 0) {
 +		xar->xmlsts = FILE_EXT2_Immutable;
 +		flag = "simmutable";
 +	}
 +	else if (strcmp(name, "AppendOnly") == 0) {
 +		xar->xmlsts = FILE_EXT2_AppendOnly;
 +		flag = "sappend";
 +	}
 +	else if (strcmp(name, "NoDump") == 0) {
 +		xar->xmlsts = FILE_EXT2_NoDump;
 +		flag = "nodump";
 +	}
 +	else if (strcmp(name, "NoAtime") == 0) {
 +		xar->xmlsts = FILE_EXT2_NoAtime;
 +		flag = "noatime";
 +	}
 +	else if (strcmp(name, "CompDirty") == 0) {
 +		xar->xmlsts = FILE_EXT2_CompDirty;
 +		flag = "compdirty";
 +	}
 +	else if (strcmp(name, "CompBlock") == 0) {
 +		xar->xmlsts = FILE_EXT2_CompBlock;
 +		flag = "comprblk";
 +	}
 +	else if (strcmp(name, "NoCompBlock") == 0) {
 +		xar->xmlsts = FILE_EXT2_NoCompBlock;
 +		flag = "nocomprblk";
 +	}
 +	else if (strcmp(name, "CompError") == 0) {
 +		xar->xmlsts = FILE_EXT2_CompError;
 +		flag = "comperr";
 +	}
 +	else if (strcmp(name, "BTree") == 0) {
 +		xar->xmlsts = FILE_EXT2_BTree;
 +		flag = "btree";
 +	}
 +	else if (strcmp(name, "HashIndexed") == 0) {
 +		xar->xmlsts = FILE_EXT2_HashIndexed;
 +		flag = "hashidx";
 +	}
 +	else if (strcmp(name, "iMagic") == 0) {
 +		xar->xmlsts = FILE_EXT2_iMagic;
 +		flag = "imagic";
 +	}
 +	else if (strcmp(name, "Journaled") == 0) {
 +		xar->xmlsts = FILE_EXT2_Journaled;
 +		flag = "journal";
 +	}
 +	else if (strcmp(name, "NoTail") == 0) {
 +		xar->xmlsts = FILE_EXT2_NoTail;
 +		flag = "notail";
 +	}
 +	else if (strcmp(name, "DirSync") == 0) {
 +		xar->xmlsts = FILE_EXT2_DirSync;
 +		flag = "dirsync";
 +	}
 +	else if (strcmp(name, "TopDir") == 0) {
 +		xar->xmlsts = FILE_EXT2_TopDir;
 +		flag = "topdir";
 +	}
 +	else if (strcmp(name, "Reserved") == 0) {
 +		xar->xmlsts = FILE_EXT2_Reserved;
 +		flag = "reserved";
 +	}
 +
 +	if (flag == NULL)
 +		return (0);
 +	if (archive_strlen(&(xar->file->fflags_text)) > 0)
 +		archive_strappend_char(&(xar->file->fflags_text), ',');
 +	archive_strcat(&(xar->file->fflags_text), flag);
 +	return (1);
 +}
 +
 +#ifdef HAVE_LIBXML_XMLREADER_H
 +
 +static int
 +xml2_xmlattr_setup(struct archive_read *a,
 +    struct xmlattr_list *list, xmlTextReaderPtr reader)
 +{
 +	struct xmlattr *attr;
 +	int r;
 +
 +	list->first = NULL;
 +	list->last = &(list->first);
 +	r = xmlTextReaderMoveToFirstAttribute(reader);
 +	while (r == 1) {
 +		attr = malloc(sizeof*(attr));
 +		if (attr == NULL) {
 +			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		attr->name = strdup(
 +		    (const char *)xmlTextReaderConstLocalName(reader));
 +		if (attr->name == NULL) {
++			free(attr);
 +			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		attr->value = strdup(
 +		    (const char *)xmlTextReaderConstValue(reader));
 +		if (attr->value == NULL) {
++			free(attr->name);
++			free(attr);
 +			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		attr->next = NULL;
 +		*list->last = attr;
 +		list->last = &(attr->next);
 +		r = xmlTextReaderMoveToNextAttribute(reader);
 +	}
 +	return (r);
 +}
 +
 +static int
 +xml2_read_cb(void *context, char *buffer, int len)
 +{
 +	struct archive_read *a;
 +	struct xar *xar;
 +	const void *d;
 +	size_t outbytes;
 +	size_t used;
 +	int r;
 +
 +	a = (struct archive_read *)context;
 +	xar = (struct xar *)(a->format->data);
 +
 +	if (xar->toc_remaining <= 0)
 +		return (0);
 +	d = buffer;
 +	outbytes = len;
 +	r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	__archive_read_consume(a, used);
 +	xar->toc_remaining -= used;
 +	xar->offset += used;
 +	xar->toc_total += outbytes;
 +	PRINT_TOC(buffer, len);
 +
 +	return ((int)outbytes);
 +}
 +
 +static int
 +xml2_close_cb(void *context)
 +{
 +
 +	(void)context; /* UNUSED */
 +	return (0);
 +}
 +
 +static void
 +xml2_error_hdr(void *arg, const char *msg, xmlParserSeverities severity,
 +    xmlTextReaderLocatorPtr locator)
 +{
 +	struct archive_read *a;
 +
 +	(void)locator; /* UNUSED */
 +	a = (struct archive_read *)arg;
 +	switch (severity) {
 +	case XML_PARSER_SEVERITY_VALIDITY_WARNING:
 +	case XML_PARSER_SEVERITY_WARNING:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "XML Parsing error: %s", msg);
 +		break;
 +	case XML_PARSER_SEVERITY_VALIDITY_ERROR:
 +	case XML_PARSER_SEVERITY_ERROR:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "XML Parsing error: %s", msg);
 +		break;
 +	}
 +}
 +
 +static int
 +xml2_read_toc(struct archive_read *a)
 +{
 +	xmlTextReaderPtr reader;
 +	struct xmlattr_list list;
 +	int r;
 +
 +	reader = xmlReaderForIO(xml2_read_cb, xml2_close_cb, a, NULL, NULL, 0);
 +	if (reader == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Couldn't allocate memory for xml parser");
 +		return (ARCHIVE_FATAL);
 +	}
 +	xmlTextReaderSetErrorHandler(reader, xml2_error_hdr, a);
 +
 +	while ((r = xmlTextReaderRead(reader)) == 1) {
 +		const char *name, *value;
 +		int type, empty;
 +
 +		type = xmlTextReaderNodeType(reader);
 +		name = (const char *)xmlTextReaderConstLocalName(reader);
 +		switch (type) {
 +		case XML_READER_TYPE_ELEMENT:
 +			empty = xmlTextReaderIsEmptyElement(reader);
 +			r = xml2_xmlattr_setup(a, &list, reader);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +			r = xml_start(a, name, &list);
 +			xmlattr_cleanup(&list);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +			if (empty)
 +				xml_end(a, name);
 +			break;
 +		case XML_READER_TYPE_END_ELEMENT:
 +			xml_end(a, name);
 +			break;
 +		case XML_READER_TYPE_TEXT:
 +			value = (const char *)xmlTextReaderConstValue(reader);
 +			xml_data(a, value, strlen(value));
 +			break;
 +		case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
 +		default:
 +			break;
 +		}
 +		if (r < 0)
 +			break;
 +	}
 +	xmlFreeTextReader(reader);
 +	xmlCleanupParser();
 +
 +	return ((r == 0)?ARCHIVE_OK:ARCHIVE_FATAL);
 +}
 +
 +#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
 +
 +static int
 +expat_xmlattr_setup(struct archive_read *a,
 +    struct xmlattr_list *list, const XML_Char **atts)
 +{
 +	struct xmlattr *attr;
 +	char *name, *value;
 +
 +	list->first = NULL;
 +	list->last = &(list->first);
 +	if (atts == NULL)
 +		return (ARCHIVE_OK);
 +	while (atts[0] != NULL && atts[1] != NULL) {
 +		attr = malloc(sizeof*(attr));
 +		name = strdup(atts[0]);
 +		value = strdup(atts[1]);
 +		if (attr == NULL || name == NULL || value == NULL) {
 +			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		attr->name = name;
 +		attr->value = value;
 +		attr->next = NULL;
 +		*list->last = attr;
 +		list->last = &(attr->next);
 +		atts += 2;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +expat_start_cb(void *userData, const XML_Char *name, const XML_Char **atts)
 +{
 +	struct expat_userData *ud = (struct expat_userData *)userData;
 +	struct archive_read *a = ud->archive;
 +	struct xmlattr_list list;
 +	int r;
 +
 +	r = expat_xmlattr_setup(a, &list, atts);
 +	if (r == ARCHIVE_OK)
 +		r = xml_start(a, (const char *)name, &list);
 +	xmlattr_cleanup(&list);
 +	ud->state = r;
 +}
 +
 +static void
 +expat_end_cb(void *userData, const XML_Char *name)
 +{
 +	struct expat_userData *ud = (struct expat_userData *)userData;
 +
 +	xml_end(ud->archive, (const char *)name);
 +}
 +
 +static void
 +expat_data_cb(void *userData, const XML_Char *s, int len)
 +{
 +	struct expat_userData *ud = (struct expat_userData *)userData;
 +
 +	xml_data(ud->archive, s, len);
 +}
 +
 +static int
 +expat_read_toc(struct archive_read *a)
 +{
 +	struct xar *xar;
 +	XML_Parser parser;
 +	struct expat_userData ud;
 +
 +	ud.state = ARCHIVE_OK;
 +	ud.archive = a;
 +
 +	xar = (struct xar *)(a->format->data);
 +
 +	/* Initialize XML Parser library. */
 +	parser = XML_ParserCreate(NULL);
 +	if (parser == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Couldn't allocate memory for xml parser");
 +		return (ARCHIVE_FATAL);
 +	}
 +	XML_SetUserData(parser, &ud);
 +	XML_SetElementHandler(parser, expat_start_cb, expat_end_cb);
 +	XML_SetCharacterDataHandler(parser, expat_data_cb);
 +	xar->xmlsts = INIT;
 +
 +	while (xar->toc_remaining && ud.state == ARCHIVE_OK) {
 +		enum XML_Status xr;
 +		const void *d;
 +		size_t outbytes;
 +		size_t used;
 +		int r;
 +
 +		d = NULL;
 +		r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);
 +		if (r != ARCHIVE_OK)
 +			return (r);
 +		xar->toc_remaining -= used;
 +		xar->offset += used;
 +		xar->toc_total += outbytes;
 +		PRINT_TOC(d, outbytes);
 +
 +		xr = XML_Parse(parser, d, outbytes, xar->toc_remaining == 0);
 +		__archive_read_consume(a, used);
 +		if (xr == XML_STATUS_ERROR) {
 +			XML_ParserFree(parser);
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "XML Parsing failed");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +	XML_ParserFree(parser);
 +	return (ud.state);
 +}
 +#endif /* defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) */
 +
 +#endif /* Support xar format */
diff --cc Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
index d150802,0000000..2fdc08b
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
@@@ -1,1266 -1,0 +1,1742 @@@
 +/*-
 + * Copyright (c) 2004 Tim Kientzle
-  * Copyright (c) 2011 Michihiro NAKAJIMA
++ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102 2009-12-28 03:11:36Z kientzle $");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
++#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_private.h"
++#include "archive_rb.h"
 +#include "archive_read_private.h"
- #include "archive_endian.h"
 +
 +#ifndef HAVE_ZLIB_H
 +#include "archive_crc32.h"
 +#endif
 +
 +struct zip_entry {
++	struct archive_rb_node	node;
 +	int64_t			local_header_offset;
 +	int64_t			compressed_size;
 +	int64_t			uncompressed_size;
 +	int64_t			gid;
 +	int64_t			uid;
 +	struct archive_entry	*entry;
++	struct archive_string	rsrcname;
 +	time_t			mtime;
 +	time_t			atime;
 +	time_t			ctime;
 +	uint32_t		crc32;
 +	uint16_t		mode;
 +	uint16_t		flags;
 +	char			compression;
 +	char			system;
 +};
 +
 +struct zip {
 +	/* Structural information about the archive. */
++	int64_t			end_of_central_directory_offset;
 +	int64_t			central_directory_offset;
 +	size_t			central_directory_size;
 +	size_t			central_directory_entries;
 +	char			have_central_directory;
++	int64_t			offset;
 +
 +	/* List of entries (seekable Zip only) */
 +	size_t			entries_remaining;
 +	struct zip_entry	*zip_entries;
 +	struct zip_entry	*entry;
++	struct archive_rb_tree	tree;
++	struct archive_rb_tree	tree_rsrc;
 +
 +	size_t			unconsumed;
 +
 +	/* entry_bytes_remaining is the number of bytes we expect. */
 +	int64_t			entry_bytes_remaining;
 +
 +	/* These count the number of bytes actually read for the entry. */
 +	int64_t			entry_compressed_bytes_read;
 +	int64_t			entry_uncompressed_bytes_read;
 +
 +	/* Running CRC32 of the decompressed data */
 +	unsigned long		entry_crc32;
 +
 +	/* Flags to mark progress of decompression. */
 +	char			decompress_init;
 +	char			end_of_entry;
 +
 +	ssize_t			filename_length;
 +	ssize_t			extra_length;
 +
 +	unsigned char 		*uncompressed_buffer;
 +	size_t 			uncompressed_buffer_size;
 +#ifdef HAVE_ZLIB_H
 +	z_stream		stream;
 +	char			stream_valid;
 +#endif
 +
 +	struct archive_string	extra;
 +	struct archive_string_conv *sconv;
 +	struct archive_string_conv *sconv_default;
 +	struct archive_string_conv *sconv_utf8;
 +	int			init_default_conversion;
 +	char	format_name[64];
 +};
 +
 +#define ZIP_LENGTH_AT_END	8
 +#define ZIP_ENCRYPTED		(1<<0)	
 +#define ZIP_STRONG_ENCRYPTED	(1<<6)	
 +#define ZIP_UTF8_NAME		(1<<11)	
 +
- static int	archive_read_format_zip_streamable_bid(struct archive_read *, int);
- static int	archive_read_format_zip_seekable_bid(struct archive_read *, int);
++static int	archive_read_format_zip_streamable_bid(struct archive_read *,
++		    int);
++static int	archive_read_format_zip_seekable_bid(struct archive_read *,
++		    int);
 +static int	archive_read_format_zip_options(struct archive_read *,
 +		    const char *, const char *);
 +static int	archive_read_format_zip_cleanup(struct archive_read *);
 +static int	archive_read_format_zip_read_data(struct archive_read *,
 +		    const void **, size_t *, int64_t *);
 +static int	archive_read_format_zip_read_data_skip(struct archive_read *a);
- static int	archive_read_format_zip_seekable_read_header(struct archive_read *,
- 		    struct archive_entry *);
- static int	archive_read_format_zip_streamable_read_header(struct archive_read *,
- 		    struct archive_entry *);
++static int	archive_read_format_zip_seekable_read_header(
++		    struct archive_read *, struct archive_entry *);
++static int	archive_read_format_zip_streamable_read_header(
++		    struct archive_read *, struct archive_entry *);
++static ssize_t	zip_get_local_file_header_size(struct archive_read *, size_t);
 +#ifdef HAVE_ZLIB_H
++static int	zip_deflate_init(struct archive_read *, struct zip *);
 +static int	zip_read_data_deflate(struct archive_read *a, const void **buff,
 +		    size_t *size, int64_t *offset);
 +#endif
 +static int	zip_read_data_none(struct archive_read *a, const void **buff,
 +		    size_t *size, int64_t *offset);
 +static int	zip_read_local_file_header(struct archive_read *a,
-     struct archive_entry *entry, struct zip *);
++		    struct archive_entry *entry, struct zip *);
 +static time_t	zip_time(const char *);
 +static const char *compression_name(int compression);
- static void process_extra(const char *, size_t, struct zip_entry *);
++static void	process_extra(const char *, size_t, struct zip_entry *);
++
++int	archive_read_support_format_zip_streamable(struct archive *);
++int	archive_read_support_format_zip_seekable(struct archive *);
 +
 +int
 +archive_read_support_format_zip_streamable(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct zip *zip;
 +	int r;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_read_support_format_zip");
 +
 +	zip = (struct zip *)malloc(sizeof(*zip));
 +	if (zip == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate zip data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	memset(zip, 0, sizeof(*zip));
 +
 +	r = __archive_read_register_format(a,
 +	    zip,
 +	    "zip",
 +	    archive_read_format_zip_streamable_bid,
 +	    archive_read_format_zip_options,
 +	    archive_read_format_zip_streamable_read_header,
 +	    archive_read_format_zip_read_data,
 +	    archive_read_format_zip_read_data_skip,
++	    NULL,
 +	    archive_read_format_zip_cleanup);
 +
 +	if (r != ARCHIVE_OK)
 +		free(zip);
 +	return (ARCHIVE_OK);
 +}
 +
 +int
 +archive_read_support_format_zip_seekable(struct archive *_a)
 +{
 +	struct archive_read *a = (struct archive_read *)_a;
 +	struct zip *zip;
 +	int r;
 +
 +	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_read_support_format_zip_seekable");
 +
 +	zip = (struct zip *)malloc(sizeof(*zip));
 +	if (zip == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate zip data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	memset(zip, 0, sizeof(*zip));
 +
 +	r = __archive_read_register_format(a,
 +	    zip,
 +	    "zip",
 +	    archive_read_format_zip_seekable_bid,
 +	    archive_read_format_zip_options,
 +	    archive_read_format_zip_seekable_read_header,
 +	    archive_read_format_zip_read_data,
 +	    archive_read_format_zip_read_data_skip,
++	    NULL,
 +	    archive_read_format_zip_cleanup);
 +
 +	if (r != ARCHIVE_OK)
 +		free(zip);
 +	return (ARCHIVE_OK);
 +}
 +
 +int
 +archive_read_support_format_zip(struct archive *a)
 +{
 +	int r;
 +	r = archive_read_support_format_zip_streamable(a);
 +	if (r != ARCHIVE_OK)
 +		return r;
 +	return (archive_read_support_format_zip_seekable(a));
 +}
 +
 +/*
-  * TODO: This is a performance sink because it forces
-  * the read core to drop buffered data from the start
-  * of file, which will then have to be re-read again
-  * if this bidder loses.
++ * TODO: This is a performance sink because it forces the read core to
++ * drop buffered data from the start of file, which will then have to
++ * be re-read again if this bidder loses.
 + *
-  * Consider passing in the winning bid value to subsequent
-  * bidders so that this bidder in particular can avoid
-  * seeking if it knows it's going to lose anyway.
++ * We workaround this a little by passing in the best bid so far so
++ * that later bidders can do nothing if they know they'll never
++ * outbid.  But we can certainly do better...
 + */
 +static int
 +archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
 +{
 +	struct zip *zip = (struct zip *)a->format->data;
 +	int64_t filesize;
 +	const char *p;
 +
 +	/* If someone has already bid more than 32, then avoid
 +	   trashing the look-ahead buffers with a seek. */
 +	if (best_bid > 32)
 +		return (-1);
 +
 +	filesize = __archive_read_seek(a, -22, SEEK_END);
 +	/* If we can't seek, then we can't bid. */
 +	if (filesize <= 0)
 +		return 0;
 +
 +	/* TODO: More robust search for end of central directory record. */
 +	if ((p = __archive_read_ahead(a, 22, NULL)) == NULL)
 +		return 0;
 +	/* First four bytes are signature for end of central directory
 +	   record.  Four zero bytes ensure this isn't a multi-volume
 +	   Zip file (which we don't yet support). */
- 	if (memcmp(p, "PK\005\006\000\000\000\000", 8) != 0)
- 		return 0;
++	if (memcmp(p, "PK\005\006\000\000\000\000", 8) != 0) {
++		int64_t i, tail;
++		int found;
++
++		/*
++		 * If there is a comment in end of central directory
++		 * record, 22 bytes are too short. we have to read more
++		 * to properly detect the record. Hopefully, a length
++		 * of the comment is not longer than 16362 bytes(16K-22).
++		 */
++		if (filesize + 22 > 1024 * 16) {
++			tail = 1024 * 16;
++			filesize = __archive_read_seek(a, tail * -1, SEEK_END);
++		} else {
++			tail = filesize + 22;
++			filesize = __archive_read_seek(a, 0, SEEK_SET);
++		}
++		if (filesize < 0)
++			return 0;
++		if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL)
++			return 0;
++		for (found = 0, i = 0;!found && i < tail - 22;) {
++			switch (p[i]) {
++			case 'P':
++				if (memcmp(p+i,
++				    "PK\005\006\000\000\000\000", 8) == 0) {
++					p += i;
++					filesize += tail -
++					    (22 + archive_le16dec(p+20));
++					found = 1;
++				} else
++					i += 8;
++				break;
++			case 'K': i += 7; break;
++			case 005: i += 6; break;
++			case 006: i += 5; break;
++			default: i += 1; break;
++			}
++		}
++		if (!found)
++			return 0;
++	}
 +
 +	/* Since we've already done the hard work of finding the
 +	   end of central directory record, let's save the important
 +	   information. */
 +	zip->central_directory_entries = archive_le16dec(p + 10);
 +	zip->central_directory_size = archive_le32dec(p + 12);
 +	zip->central_directory_offset = archive_le32dec(p + 16);
++	zip->end_of_central_directory_offset = filesize;
 +
 +	/* Just one volume, so central dir must all be on this volume. */
 +	if (zip->central_directory_entries != archive_le16dec(p + 8))
 +		return 0;
 +	/* Central directory can't extend beyond end of this file. */
- 	if (zip->central_directory_offset + zip->central_directory_size > filesize)
++	if (zip->central_directory_offset +
++	    (int64_t)zip->central_directory_size > filesize)
 +		return 0;
 +
 +	/* This is just a tiny bit higher than the maximum returned by
 +	   the streaming Zip bidder.  This ensures that the more accurate
 +	   seeking Zip parser wins whenever seek is available. */
 +	return 32;
 +}
 +
 +static int
++cmp_node(const struct archive_rb_node *n1, const struct archive_rb_node *n2)
++{
++	const struct zip_entry *e1 = (const struct zip_entry *)n1;
++	const struct zip_entry *e2 = (const struct zip_entry *)n2;
++
++	return ((int)(e2->local_header_offset - e1->local_header_offset));
++}
++
++static int
++cmp_key(const struct archive_rb_node *n, const void *key)
++{
++	/* This function won't be called */
++	(void)n; /* UNUSED */
++	(void)key; /* UNUSED */
++	return 1;
++}
++
++static int
++rsrc_cmp_node(const struct archive_rb_node *n1,
++    const struct archive_rb_node *n2)
++{
++	const struct zip_entry *e1 = (const struct zip_entry *)n1;
++	const struct zip_entry *e2 = (const struct zip_entry *)n2;
++
++	return (strcmp(e2->rsrcname.s, e1->rsrcname.s));
++}
++
++static int
++rsrc_cmp_key(const struct archive_rb_node *n, const void *key)
++{
++	const struct zip_entry *e = (const struct zip_entry *)n;
++	return (strcmp((const char *)key, e->rsrcname.s));
++}
++
++static const char *
++rsrc_basename(const char *name, size_t name_length)
++{
++	const char *s, *r;
++
++	r = s = name;
++	for (;;) {
++		s = memchr(s, '/', name_length - (s - name));
++		if (s == NULL)
++			break;
++		r = ++s;
++	}
++	return (r);
++}
++
++static void
++expose_parent_dirs(struct zip *zip, const char *name, size_t name_length)
++{
++	struct archive_string str;
++	struct zip_entry *dir;
++	char *s;
++
++	archive_string_init(&str);
++	archive_strncpy(&str, name, name_length);
++	for (;;) {
++		s = strrchr(str.s, '/');
++		if (s == NULL)
++			break;
++		*s = '\0';
++		/* Transfer the parent directory from zip->tree_rsrc RB
++		 * tree to zip->tree RB tree to expose. */
++		dir = (struct zip_entry *)
++		    __archive_rb_tree_find_node(&zip->tree_rsrc, str.s);
++		if (dir == NULL)
++			break;
++		__archive_rb_tree_remove_node(&zip->tree_rsrc, &dir->node);
++		archive_string_free(&dir->rsrcname);
++		__archive_rb_tree_insert_node(&zip->tree, &dir->node);
++	}
++	archive_string_free(&str);
++}
++
++static int
 +slurp_central_directory(struct archive_read *a, struct zip *zip)
 +{
 +	unsigned i;
++	int64_t correction;
++	static const struct archive_rb_tree_ops rb_ops = {
++		&cmp_node, &cmp_key
++	};
++	static const struct archive_rb_tree_ops rb_rsrc_ops = {
++		&rsrc_cmp_node, &rsrc_cmp_key
++	};
++
++	/*
++	 * Consider the archive file we are reading may be SFX.
++	 * So we have to calculate a SFX header size to revise
++	 * ZIP header offsets.
++	 */
++	correction = zip->end_of_central_directory_offset -
++	    (zip->central_directory_offset + zip->central_directory_size);
++	/* The central directory offset is relative value, and so
++	 * we revise this offset for SFX. */
++	zip->central_directory_offset += correction;
 +
 +	__archive_read_seek(a, zip->central_directory_offset, SEEK_SET);
++	zip->offset = zip->central_directory_offset;
++	__archive_rb_tree_init(&zip->tree, &rb_ops);
++	__archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops);
 +
- 	zip->zip_entries = calloc(zip->central_directory_entries, sizeof(struct zip_entry));
++	zip->zip_entries = calloc(zip->central_directory_entries,
++				sizeof(struct zip_entry));
 +	for (i = 0; i < zip->central_directory_entries; ++i) {
 +		struct zip_entry *zip_entry = &zip->zip_entries[i];
 +		size_t filename_length, extra_length, comment_length;
 +		uint32_t external_attributes;
- 		const char *p;
++		const char *name, *p, *r;
 +
 +		if ((p = __archive_read_ahead(a, 46, NULL)) == NULL)
 +			return ARCHIVE_FATAL;
 +		if (memcmp(p, "PK\001\002", 4) != 0) {
 +			archive_set_error(&a->archive,
 +			    -1, "Invalid central directory signature");
 +			return ARCHIVE_FATAL;
 +		}
 +		zip->have_central_directory = 1;
 +		/* version = p[4]; */
 +		zip_entry->system = p[5];
 +		/* version_required = archive_le16dec(p + 6); */
 +		zip_entry->flags = archive_le16dec(p + 8);
- 		zip_entry->compression = archive_le16dec(p + 10);
++		zip_entry->compression = (char)archive_le16dec(p + 10);
 +		zip_entry->mtime = zip_time(p + 12);
 +		zip_entry->crc32 = archive_le32dec(p + 16);
 +		zip_entry->compressed_size = archive_le32dec(p + 20);
 +		zip_entry->uncompressed_size = archive_le32dec(p + 24);
 +		filename_length = archive_le16dec(p + 28);
 +		extra_length = archive_le16dec(p + 30);
 +		comment_length = archive_le16dec(p + 32);
 +		/* disk_start = archive_le16dec(p + 34); */ /* Better be zero. */
 +		/* internal_attributes = archive_le16dec(p + 36); */ /* text bit */
 +		external_attributes = archive_le32dec(p + 38);
- 		zip_entry->local_header_offset = archive_le32dec(p + 42);
++		zip_entry->local_header_offset =
++		    archive_le32dec(p + 42) + correction;
 +
++		/* If we can't guess the mode, leave it zero here;
++		   when we read the local file header we might get
++		   more information. */
++		zip_entry->mode = 0;
 +		if (zip_entry->system == 3) {
 +			zip_entry->mode = external_attributes >> 16;
++		}
++
++		/*
++		 * Mac resource fork files are stored under the
++		 * "__MACOSX/" directory, so we should check if
++		 * it is.
++		 */
++		/* Make sure we have the file name. */
++		if ((p = __archive_read_ahead(a, 46 + filename_length, NULL))
++		    == NULL)
++			return ARCHIVE_FATAL;
++		name = p + 46;
++		r = rsrc_basename(name, filename_length);
++		if (filename_length >= 9 &&
++		    strncmp("__MACOSX/", name, 9) == 0) {
++			/* If this file is not a resource fork nor
++			 * a directory. We should treat it as a non
++			 * resource fork file to expose it. */
++			if (name[filename_length-1] != '/' &&
++			    (r - name < 3 || r[0] != '.' || r[1] != '_')) {
++				__archive_rb_tree_insert_node(&zip->tree,
++				    &zip_entry->node);
++				/* Expose its parent directories. */
++				expose_parent_dirs(zip, name, filename_length);
++			} else {
++				/* This file is a resource fork file or
++				 * a directory. */
++				archive_strncpy(&(zip_entry->rsrcname), name,
++				    filename_length);
++				__archive_rb_tree_insert_node(&zip->tree_rsrc,
++				    &zip_entry->node);
++			}
 +		} else {
- 			zip_entry->mode = AE_IFREG | 0777;
++			/* Generate resource fork name to find its resource
++			 * file at zip->tree_rsrc. */
++			archive_strcpy(&(zip_entry->rsrcname), "__MACOSX/");
++			archive_strncat(&(zip_entry->rsrcname), name, r - name);
++			archive_strcat(&(zip_entry->rsrcname), "._");
++			archive_strncat(&(zip_entry->rsrcname),
++			    name + (r - name), filename_length - (r - name));
++			/* Register an entry to RB tree to sort it by
++			 * file offset. */
++			__archive_rb_tree_insert_node(&zip->tree,
++			    &zip_entry->node);
 +		}
 +
- 		/* Do we need to parse filename here? */
- 		/* Or can we wait until we read the local header? */
++		/* We don't read the filename until we get to the
++		   local file header.  Reading it here would speed up
++		   table-of-contents operations (removing the need to
++		   find and read local file header to get the
++		   filename) at the cost of requiring a lot of extra
++		   space. */
++		/* We don't read the extra block here.  We assume it
++		   will be duplicated at the local file header. */
 +		__archive_read_consume(a,
 +		    46 + filename_length + extra_length + comment_length);
 +	}
 +
- 	/* TODO: Sort zip entries. */
- 
 +	return ARCHIVE_OK;
 +}
 +
++static int64_t
++zip_read_consume(struct archive_read *a, int64_t bytes)
++{
++	struct zip *zip = (struct zip *)a->format->data;
++	int64_t skip;
++
++	skip = __archive_read_consume(a, bytes);
++	if (skip > 0)
++		zip->offset += skip;
++	return (skip);
++}
++
++static int
++zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
++    struct zip_entry *rsrc)
++{
++	struct zip *zip = (struct zip *)a->format->data;
++	unsigned char *metadata, *mp;
++	int64_t offset = zip->offset;
++	size_t remaining_bytes, metadata_bytes;
++	ssize_t hsize;
++	int ret = ARCHIVE_OK, eof;
++
++	switch(rsrc->compression) {
++	case 0:  /* No compression. */
++#ifdef HAVE_ZLIB_H
++	case 8: /* Deflate compression. */
++#endif
++		break;
++	default: /* Unsupported compression. */
++		/* Return a warning. */
++		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++		    "Unsupported ZIP compression method (%s)",
++		    compression_name(rsrc->compression));
++		/* We can't decompress this entry, but we will
++		 * be able to skip() it and try the next entry. */
++		return (ARCHIVE_WARN);
++	}
++
++	if (rsrc->uncompressed_size > (128 * 1024)) {
++		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++		    "Mac metadata is too large: %jd > 128K bytes",
++		    (intmax_t)rsrc->uncompressed_size);
++		return (ARCHIVE_WARN);
++	}
++
++	metadata = malloc((size_t)rsrc->uncompressed_size);
++	if (metadata == NULL) {
++		archive_set_error(&a->archive, ENOMEM,
++		    "Can't allocate memory for Mac metadata");
++		return (ARCHIVE_FATAL);
++	}
++
++	if (zip->offset < rsrc->local_header_offset)
++		zip_read_consume(a, rsrc->local_header_offset - zip->offset);
++	else if (zip->offset != rsrc->local_header_offset) {
++		__archive_read_seek(a, rsrc->local_header_offset, SEEK_SET);
++		zip->offset = zip->entry->local_header_offset;
++	}
++
++	hsize = zip_get_local_file_header_size(a, 0);
++	zip_read_consume(a, hsize);
++
++	remaining_bytes = (size_t)rsrc->compressed_size;
++	metadata_bytes = (size_t)rsrc->uncompressed_size;
++	mp = metadata;
++	eof = 0;
++	while (!eof && remaining_bytes) {
++		const unsigned char *p;
++		ssize_t bytes_avail;
++		size_t bytes_used;
++
++		p = __archive_read_ahead(a, 1, &bytes_avail);
++		if (p == NULL) {
++			archive_set_error(&a->archive,
++			    ARCHIVE_ERRNO_FILE_FORMAT,
++			    "Truncated ZIP file header");
++			ret = ARCHIVE_WARN;
++			goto exit_mac_metadata;
++		}
++		if ((size_t)bytes_avail > remaining_bytes)
++			bytes_avail = remaining_bytes;
++		switch(rsrc->compression) {
++		case 0:  /* No compression. */
++			memcpy(mp, p, bytes_avail);
++			bytes_used = (size_t)bytes_avail;
++			metadata_bytes -= bytes_used;
++			mp += bytes_used;
++			if (metadata_bytes == 0)
++				eof = 1;
++			break;
++#ifdef HAVE_ZLIB_H
++		case 8: /* Deflate compression. */
++		{
++			int r;
++
++			ret = zip_deflate_init(a, zip);
++			if (ret != ARCHIVE_OK)
++				goto exit_mac_metadata;
++			zip->stream.next_in =
++			    (Bytef *)(uintptr_t)(const void *)p;
++			zip->stream.avail_in = (uInt)bytes_avail;
++			zip->stream.total_in = 0;
++			zip->stream.next_out = mp;
++			zip->stream.avail_out = (uInt)metadata_bytes;
++			zip->stream.total_out = 0;
++
++			r = inflate(&zip->stream, 0);
++			switch (r) {
++			case Z_OK:
++				break;
++			case Z_STREAM_END:
++				eof = 1;
++				break;
++			case Z_MEM_ERROR:
++				archive_set_error(&a->archive, ENOMEM,
++				    "Out of memory for ZIP decompression");
++				ret = ARCHIVE_FATAL;
++				goto exit_mac_metadata;
++			default:
++				archive_set_error(&a->archive,
++				    ARCHIVE_ERRNO_MISC,
++				    "ZIP decompression failed (%d)", r);
++				ret = ARCHIVE_FATAL;
++				goto exit_mac_metadata;
++			}
++			bytes_used = zip->stream.total_in;
++			metadata_bytes -= zip->stream.total_out;
++			mp += zip->stream.total_out;
++			break;
++		}
++#endif
++		default:
++			bytes_used = 0;
++			break;
++		}
++		zip_read_consume(a, bytes_used);
++		remaining_bytes -= bytes_used;
++	}
++	archive_entry_copy_mac_metadata(entry, metadata,
++	    (size_t)rsrc->uncompressed_size - metadata_bytes);
++
++	__archive_read_seek(a, offset, SEEK_SET);
++	zip->offset = offset;
++exit_mac_metadata:
++	zip->decompress_init = 0;
++	free(metadata);
++	return (ret);
++}
++
 +static int
 +archive_read_format_zip_seekable_read_header(struct archive_read *a,
 +	struct archive_entry *entry)
 +{
 +	struct zip *zip = (struct zip *)a->format->data;
- 	int r;
++	struct zip_entry *rsrc;
++	int r, ret = ARCHIVE_OK;
 +
 +	a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
 +	if (a->archive.archive_format_name == NULL)
 +		a->archive.archive_format_name = "ZIP";
 +
 +	if (zip->zip_entries == NULL) {
 +		r = slurp_central_directory(a, zip);
 +		zip->entries_remaining = zip->central_directory_entries;
 +		if (r != ARCHIVE_OK)
 +			return r;
- 		zip->entry = zip->zip_entries;
- 	} else {
- 		++zip->entry;
++		/* Get first entry whose local header offset is lower than
++		 * other entries in the archive file. */
++		zip->entry =
++		    (struct zip_entry *)ARCHIVE_RB_TREE_MIN(&zip->tree);
++	} else if (zip->entry != NULL) {
++		/* Get next entry in local header offset order. */
++		zip->entry = (struct zip_entry *)__archive_rb_tree_iterate(
++		    &zip->tree, &zip->entry->node, ARCHIVE_RB_DIR_RIGHT);
 +	}
 +
- 	if (zip->entries_remaining <= 0)
++	if (zip->entries_remaining <= 0 || zip->entry == NULL)
 +		return ARCHIVE_EOF;
 +	--zip->entries_remaining;
 +
- 	/* TODO: If entries are sorted by offset within the file, we
- 	   should be able to skip here instead of seeking.  Skipping is
- 	   typically faster (easier for I/O layer to optimize). */
- 	__archive_read_seek(a, zip->entry->local_header_offset, SEEK_SET);
++	if (zip->entry->rsrcname.s)
++		rsrc = (struct zip_entry *)__archive_rb_tree_find_node(
++		    &zip->tree_rsrc, zip->entry->rsrcname.s);
++	else
++		rsrc = NULL;
++
++	/* File entries are sorted by the header offset, we should mostly
++	 * use zip_read_consume to advance a read point to avoid redundant
++	 * data reading.  */
++	if (zip->offset < zip->entry->local_header_offset)
++		zip_read_consume(a,
++		    zip->entry->local_header_offset - zip->offset);
++	else if (zip->offset != zip->entry->local_header_offset) {
++		__archive_read_seek(a, zip->entry->local_header_offset,
++			SEEK_SET);
++		zip->offset = zip->entry->local_header_offset;
++	}
 +	zip->unconsumed = 0;
 +	r = zip_read_local_file_header(a, entry, zip);
 +	if (r != ARCHIVE_OK)
 +		return r;
 +	if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) {
 +		const void *p;
- 		size_t linkname_length = archive_entry_size(entry);
++		struct archive_string_conv *sconv;
++		size_t linkname_length = (size_t)archive_entry_size(entry);
 +
 +		archive_entry_set_size(entry, 0);
 +		p = __archive_read_ahead(a, linkname_length, NULL);
 +		if (p == NULL) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Truncated Zip file");
 +			return ARCHIVE_FATAL;
 +		}
 +
++		sconv = zip->sconv;
++		if (sconv == NULL && (zip->entry->flags & ZIP_UTF8_NAME))
++			sconv = zip->sconv_utf8;
++		if (sconv == NULL)
++			sconv = zip->sconv_default;
 +		if (archive_entry_copy_symlink_l(entry, p, linkname_length,
- 		    NULL) != 0) {
- 			/* NOTE: If the last argument is NULL, this will
- 			 * fail only by memeory allocation failure. */
- 			archive_set_error(&a->archive, ENOMEM,
- 			    "Can't allocate memory for Symlink");
- 			return (ARCHIVE_FATAL);
++		    sconv) != 0) {
++			if (errno != ENOMEM && sconv == zip->sconv_utf8 &&
++			    (zip->entry->flags & ZIP_UTF8_NAME))
++			    archive_entry_copy_symlink_l(entry, p,
++				linkname_length, NULL);
++			if (errno == ENOMEM) {
++				archive_set_error(&a->archive, ENOMEM,
++				    "Can't allocate memory for Symlink");
++				return (ARCHIVE_FATAL);
++			}
++			/*
++			 * Since there is no character-set regulation for
++			 * symlink name, do not report the conversion error
++			 * in an automatic conversion.
++			 */
++			if (sconv != zip->sconv_utf8 ||
++			    (zip->entry->flags & ZIP_UTF8_NAME) == 0) {
++				archive_set_error(&a->archive,
++				    ARCHIVE_ERRNO_FILE_FORMAT,
++				    "Symlink cannot be converted "
++				    "from %s to current locale.",
++				    archive_string_conversion_charset_name(
++					sconv));
++				ret = ARCHIVE_WARN;
++			}
 +		}
- 		/* TODO: handle character-set issues? */
 +	}
- 	return ARCHIVE_OK;
++	if (rsrc) {
++		int ret2 = zip_read_mac_metadata(a, entry, rsrc);
++		if (ret2 < ret)
++			ret = ret2;
++	}
++	return (ret);
 +}
 +
 +static int
 +archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid)
 +{
 +	const char *p;
 +
 +	(void)best_bid; /* UNUSED */
 +
 +	if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)
 +		return (-1);
 +
 +	/*
 +	 * Bid of 30 here is: 16 bits for "PK",
 +	 * next 16-bit field has four options (-2 bits).
 +	 * 16 + 16-2 = 30.
 +	 */
 +	if (p[0] == 'P' && p[1] == 'K') {
 +		if ((p[2] == '\001' && p[3] == '\002')
 +		    || (p[2] == '\003' && p[3] == '\004')
 +		    || (p[2] == '\005' && p[3] == '\006')
 +		    || (p[2] == '\007' && p[3] == '\010')
 +		    || (p[2] == '0' && p[3] == '0'))
 +			return (30);
 +	}
 +
++	/* TODO: It's worth looking ahead a little bit for a valid
++	 * PK signature.  In particular, that would make it possible
++	 * to read some UUEncoded SFX files or SFX files coming from
++	 * a network socket. */
++
 +	return (0);
 +}
 +
 +static int
 +archive_read_format_zip_options(struct archive_read *a,
 +    const char *key, const char *val)
 +{
 +	struct zip *zip;
 +	int ret = ARCHIVE_FAILED;
 +
 +	zip = (struct zip *)(a->format->data);
 +	if (strcmp(key, "compat-2x")  == 0) {
 +		/* Handle filnames as libarchive 2.x */
 +		zip->init_default_conversion = (val != NULL) ? 1 : 0;
- 		ret = ARCHIVE_OK;
++		return (ARCHIVE_OK);
 +	} else if (strcmp(key, "hdrcharset")  == 0) {
 +		if (val == NULL || val[0] == 0)
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- 			    "zip: hdrcharset option needs a character-set name");
++			    "zip: hdrcharset option needs a character-set name"
++			);
 +		else {
 +			zip->sconv = archive_string_conversion_from_charset(
 +			    &a->archive, val, 0);
 +			if (zip->sconv != NULL) {
 +				if (strcmp(val, "UTF-8") == 0)
 +					zip->sconv_utf8 = zip->sconv;
 +				ret = ARCHIVE_OK;
 +			} else
 +				ret = ARCHIVE_FATAL;
 +		}
- 	} else
- 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- 		    "zip: unknown keyword ``%s''", key);
++		return (ret);
++	}
 +
- 	return (ret);
++	/* Note: The "warn" return is just to inform the options
++	 * supervisor that we didn't handle it.  It will generate
++	 * a suitable error if no one used this option. */
++	return (ARCHIVE_WARN);
 +}
 +
 +static int
 +archive_read_format_zip_streamable_read_header(struct archive_read *a,
 +    struct archive_entry *entry)
 +{
 +	struct zip *zip;
 +
 +	a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
 +	if (a->archive.archive_format_name == NULL)
 +		a->archive.archive_format_name = "ZIP";
 +
 +	zip = (struct zip *)(a->format->data);
 +
 +	/* Make sure we have a zip_entry structure to use. */
 +	if (zip->zip_entries == NULL) {
 +		zip->zip_entries = malloc(sizeof(struct zip_entry));
 +		if (zip->zip_entries == NULL) {
- 			archive_set_error(&a->archive, ENOMEM, "Out  of memory");
++			archive_set_error(&a->archive, ENOMEM,
++			    "Out  of memory");
 +			return ARCHIVE_FATAL;
 +		}
 +	}
 +	zip->entry = zip->zip_entries;
 +	memset(zip->entry, 0, sizeof(struct zip_entry));
 +
 +	/* Search ahead for the next local file header. */
- 	__archive_read_consume(a, zip->unconsumed);
++	zip_read_consume(a, zip->unconsumed);
 +	zip->unconsumed = 0;
 +	for (;;) {
 +		int64_t skipped = 0;
 +		const char *p, *end;
 +		ssize_t bytes;
 +
 +		p = __archive_read_ahead(a, 4, &bytes);
 +		if (p == NULL)
 +			return (ARCHIVE_FATAL);
 +		end = p + bytes;
 +
 +		while (p + 4 <= end) {
 +			if (p[0] == 'P' && p[1] == 'K') {
 +				if (p[2] == '\001' && p[3] == '\002')
 +					/* Beginning of central directory. */
 +					return (ARCHIVE_EOF);
 +
 +				if (p[2] == '\003' && p[3] == '\004') {
 +					/* Regular file entry. */
- 					__archive_read_consume(a, skipped);
- 					return zip_read_local_file_header(a, entry, zip);
++					zip_read_consume(a, skipped);
++					return zip_read_local_file_header(a,
++					    entry, zip);
 +				}
 +
 +				if (p[2] == '\005' && p[3] == '\006')
 +					/* End of central directory. */
 +					return (ARCHIVE_EOF);
 +			}
 +			++p;
 +			++skipped;
 +		}
- 		__archive_read_consume(a, skipped);
++		zip_read_consume(a, skipped);
++	}
++}
++
++static ssize_t
++zip_get_local_file_header_size(struct archive_read *a, size_t extra)
++{
++	const char *p;
++	ssize_t filename_length, extra_length;
++
++	if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) {
++		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++		    "Truncated ZIP file header");
++		return (ARCHIVE_WARN);
++	}
++	p += extra;
++
++	if (memcmp(p, "PK\003\004", 4) != 0) {
++		archive_set_error(&a->archive, -1, "Damaged Zip archive");
++		return ARCHIVE_WARN;
 +	}
++	filename_length = archive_le16dec(p + 26);
++	extra_length = archive_le16dec(p + 28);
++
++	return (30 + filename_length + extra_length);
 +}
 +
 +/*
 + * Assumes file pointer is at beginning of local file header.
 + */
 +static int
 +zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
 +    struct zip *zip)
 +{
 +	const char *p;
 +	const void *h;
 +	const wchar_t *wp;
 +	const char *cp;
 +	size_t len, filename_length, extra_length;
 +	struct archive_string_conv *sconv;
 +	struct zip_entry *zip_entry = zip->entry;
 +	uint32_t local_crc32;
 +	int64_t compressed_size, uncompressed_size;
 +	int ret = ARCHIVE_OK;
 +	char version;
 +
 +	zip->decompress_init = 0;
 +	zip->end_of_entry = 0;
 +	zip->entry_uncompressed_bytes_read = 0;
 +	zip->entry_compressed_bytes_read = 0;
 +	zip->entry_crc32 = crc32(0, NULL, 0);
 +
 +	/* Setup default conversion. */
 +	if (zip->sconv == NULL && !zip->init_default_conversion) {
 +		zip->sconv_default =
 +		    archive_string_default_conversion_for_read(&(a->archive));
 +		zip->init_default_conversion = 1;
 +	}
 +
 +	if ((p = __archive_read_ahead(a, 30, NULL)) == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated ZIP file header");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	if (memcmp(p, "PK\003\004", 4) != 0) {
 +		archive_set_error(&a->archive, -1, "Damaged Zip archive");
 +		return ARCHIVE_FATAL;
 +	}
 +	version = p[4];
 +	zip_entry->system = p[5];
 +	zip_entry->flags = archive_le16dec(p + 6);
- 	zip_entry->compression = archive_le16dec(p + 8);
++	zip_entry->compression = (char)archive_le16dec(p + 8);
 +	zip_entry->mtime = zip_time(p + 10);
 +	local_crc32 = archive_le32dec(p + 14);
 +	compressed_size = archive_le32dec(p + 18);
 +	uncompressed_size = archive_le32dec(p + 22);
 +	filename_length = archive_le16dec(p + 26);
 +	extra_length = archive_le16dec(p + 28);
 +
- 	__archive_read_consume(a, 30);
++	zip_read_consume(a, 30);
 +
 +	if (zip->have_central_directory) {
- 		/* If we read the central dir entry, we must have size information
- 		   as well, so ignore the length-at-end flag. */
++		/* If we read the central dir entry, we must have size
++		 * information as well, so ignore the length-at-end flag. */
 +		zip_entry->flags &= ~ZIP_LENGTH_AT_END;
 +		/* If we have values from both the local file header
 +		   and the central directory, warn about mismatches
 +		   which might indicate a damaged file.  But some
 +		   writers always put zero in the local header; don't
 +		   bother warning about that. */
 +		if (local_crc32 != 0 && local_crc32 != zip_entry->crc32) {
- 			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++			archive_set_error(&a->archive,
++			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Inconsistent CRC32 values");
 +			ret = ARCHIVE_WARN;
 +		}
 +		if (compressed_size != 0
 +		    && compressed_size != zip_entry->compressed_size) {
- 			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++			archive_set_error(&a->archive,
++			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Inconsistent compressed size");
 +			ret = ARCHIVE_WARN;
 +		}
 +		if (uncompressed_size != 0
 +		    && uncompressed_size != zip_entry->uncompressed_size) {
- 			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++			archive_set_error(&a->archive,
++			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Inconsistent uncompressed size");
 +			ret = ARCHIVE_WARN;
 +		}
 +	} else {
 +		/* If we don't have the CD info, use whatever we do have. */
 +		zip_entry->crc32 = local_crc32;
 +		zip_entry->compressed_size = compressed_size;
 +		zip_entry->uncompressed_size = uncompressed_size;
 +	}
 +
 +	/* Read the filename. */
 +	if ((h = __archive_read_ahead(a, filename_length, NULL)) == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated ZIP file header");
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (zip_entry->flags & ZIP_UTF8_NAME) {
 +		/* The filename is stored to be UTF-8. */
 +		if (zip->sconv_utf8 == NULL) {
 +			zip->sconv_utf8 =
 +			    archive_string_conversion_from_charset(
 +				&a->archive, "UTF-8", 1);
 +			if (zip->sconv_utf8 == NULL)
 +				return (ARCHIVE_FATAL);
 +		}
 +		sconv = zip->sconv_utf8;
 +	} else if (zip->sconv != NULL)
 +		sconv = zip->sconv;
 +	else
 +		sconv = zip->sconv_default;
 +
 +	if (archive_entry_copy_pathname_l(entry,
 +	    h, filename_length, sconv) != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Pathname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Pathname cannot be converted "
 +		    "from %s to current locale.",
 +		    archive_string_conversion_charset_name(sconv));
 +		ret = ARCHIVE_WARN;
 +	}
- 	__archive_read_consume(a, filename_length);
++	zip_read_consume(a, filename_length);
 +
 +	if (zip_entry->mode == 0) {
 +		/* Especially in streaming mode, we can end up
 +		   here without having seen any mode information.
 +		   Guess from the filename. */
 +		wp = archive_entry_pathname_w(entry);
 +		if (wp != NULL) {
 +			len = wcslen(wp);
 +			if (len > 0 && wp[len - 1] == L'/')
 +				zip_entry->mode = AE_IFDIR | 0777;
 +			else
- 				zip_entry->mode = AE_IFREG | 0777;
++				zip_entry->mode = AE_IFREG | 0666;
 +		} else {
 +			cp = archive_entry_pathname(entry);
 +			len = (cp != NULL)?strlen(cp):0;
 +			if (len > 0 && cp[len - 1] == '/')
 +				zip_entry->mode = AE_IFDIR | 0777;
 +			else
- 				zip_entry->mode = AE_IFREG | 0777;
++				zip_entry->mode = AE_IFREG | 0666;
 +		}
 +	}
 +
 +	/* Read the extra data. */
 +	if ((h = __archive_read_ahead(a, extra_length, NULL)) == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated ZIP file header");
 +		return (ARCHIVE_FATAL);
 +	}
 +	process_extra(h, extra_length, zip_entry);
- 	__archive_read_consume(a, extra_length);
++	zip_read_consume(a, extra_length);
 +
 +	/* Populate some additional entry fields: */
 +	archive_entry_set_mode(entry, zip_entry->mode);
 +	archive_entry_set_uid(entry, zip_entry->uid);
 +	archive_entry_set_gid(entry, zip_entry->gid);
 +	archive_entry_set_mtime(entry, zip_entry->mtime, 0);
 +	archive_entry_set_ctime(entry, zip_entry->ctime, 0);
 +	archive_entry_set_atime(entry, zip_entry->atime, 0);
 +	/* Set the size only if it's meaningful. */
 +	if (0 == (zip_entry->flags & ZIP_LENGTH_AT_END))
 +		archive_entry_set_size(entry, zip_entry->uncompressed_size);
 +
 +	zip->entry_bytes_remaining = zip_entry->compressed_size;
 +
 +	/* If there's no body, force read_data() to return EOF immediately. */
 +	if (0 == (zip_entry->flags & ZIP_LENGTH_AT_END)
 +	    && zip->entry_bytes_remaining < 1)
 +		zip->end_of_entry = 1;
 +
 +	/* Set up a more descriptive format name. */
 +	sprintf(zip->format_name, "ZIP %d.%d (%s)",
 +	    version / 10, version % 10,
 +	    compression_name(zip->entry->compression));
 +	a->archive.archive_format_name = zip->format_name;
 +
 +	return (ret);
 +}
 +
 +static const char *
 +compression_name(int compression)
 +{
 +	static const char *compression_names[] = {
 +		"uncompressed",
 +		"shrinking",
 +		"reduced-1",
 +		"reduced-2",
 +		"reduced-3",
 +		"reduced-4",
 +		"imploded",
 +		"reserved",
 +		"deflation"
 +	};
 +
- 	if (compression <
- 	    sizeof(compression_names)/sizeof(compression_names[0]))
++	if (0 <= compression && compression <
++	    (int)(sizeof(compression_names)/sizeof(compression_names[0])))
 +		return compression_names[compression];
 +	else
 +		return "??";
 +}
 +
 +/* Convert an MSDOS-style date/time into Unix-style time. */
 +static time_t
 +zip_time(const char *p)
 +{
 +	int msTime, msDate;
 +	struct tm ts;
 +
 +	msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]);
 +	msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]);
 +
 +	memset(&ts, 0, sizeof(ts));
 +	ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
 +	ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
 +	ts.tm_mday = msDate & 0x1f; /* Day of month. */
 +	ts.tm_hour = (msTime >> 11) & 0x1f;
 +	ts.tm_min = (msTime >> 5) & 0x3f;
 +	ts.tm_sec = (msTime << 1) & 0x3e;
 +	ts.tm_isdst = -1;
 +	return mktime(&ts);
 +}
 +
 +static int
 +archive_read_format_zip_read_data(struct archive_read *a,
 +    const void **buff, size_t *size, int64_t *offset)
 +{
 +	int r;
 +	struct zip *zip = (struct zip *)(a->format->data);
 +
 +	*offset = zip->entry_uncompressed_bytes_read;
 +	*size = 0;
 +	*buff = NULL;
 +
 +	/* If we hit end-of-entry last time, return ARCHIVE_EOF. */
 +	if (zip->end_of_entry)
 +		return (ARCHIVE_EOF);
 +
 +	/* Return EOF immediately if this is a non-regular file. */
 +	if (AE_IFREG != (zip->entry->mode & AE_IFMT))
 +		return (ARCHIVE_EOF);
 +
 +	if (zip->entry->flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Encrypted file is unsupported");
 +		return (ARCHIVE_FAILED);
 +	}
 +
- 	__archive_read_consume(a, zip->unconsumed);
++	zip_read_consume(a, zip->unconsumed);
 +	zip->unconsumed = 0;
 +
 +	switch(zip->entry->compression) {
 +	case 0:  /* No compression. */
 +		r =  zip_read_data_none(a, buff, size, offset);
 +		break;
 +#ifdef HAVE_ZLIB_H
 +	case 8: /* Deflate compression. */
 +		r =  zip_read_data_deflate(a, buff, size, offset);
 +		break;
 +#endif
 +	default: /* Unsupported compression. */
 +		/* Return a warning. */
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Unsupported ZIP compression method (%s)",
 +		    compression_name(zip->entry->compression));
 +		/* We can't decompress this entry, but we will
 +		 * be able to skip() it and try the next entry. */
 +		return (ARCHIVE_FAILED);
 +		break;
 +	}
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Update checksum */
 +	if (*size)
- 		zip->entry_crc32 = crc32(zip->entry_crc32, *buff, *size);
++		zip->entry_crc32 = crc32(zip->entry_crc32, *buff,
++		    (unsigned)*size);
 +	/* If we hit the end, swallow any end-of-data marker. */
 +	if (zip->end_of_entry) {
 +		/* Check file size, CRC against these values. */
- 		if (zip->entry->compressed_size != zip->entry_compressed_bytes_read) {
++		if (zip->entry->compressed_size !=
++		    zip->entry_compressed_bytes_read) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- 			    "ZIP compressed data is wrong size (read %jd, expected %jd)",
++			    "ZIP compressed data is wrong size "
++			    "(read %jd, expected %jd)",
 +			    (intmax_t)zip->entry_compressed_bytes_read,
 +			    (intmax_t)zip->entry->compressed_size);
 +			return (ARCHIVE_WARN);
 +		}
 +		/* Size field only stores the lower 32 bits of the actual
 +		 * size. */
 +		if ((zip->entry->uncompressed_size & UINT32_MAX)
 +		    != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- 			    "ZIP uncompressed data is wrong size (read %jd, expected %jd)",
++			    "ZIP uncompressed data is wrong size "
++			    "(read %jd, expected %jd)",
 +			    (intmax_t)zip->entry_uncompressed_bytes_read,
 +			    (intmax_t)zip->entry->uncompressed_size);
 +			return (ARCHIVE_WARN);
 +		}
 +		/* Check computed CRC against header */
 +		if (zip->entry->crc32 != zip->entry_crc32) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "ZIP bad CRC: 0x%lx should be 0x%lx",
 +			    (unsigned long)zip->entry_crc32,
 +			    (unsigned long)zip->entry->crc32);
 +			return (ARCHIVE_WARN);
 +		}
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Read "uncompressed" data.  There are three cases:
 + *  1) We know the size of the data.  This is always true for the
 + * seeking reader (we've examined the Central Directory already).
 + *  2) ZIP_LENGTH_AT_END was set, but only the CRC was deferred.
 + * Info-ZIP seems to do this; we know the size but have to grab
 + * the CRC from the data descriptor afterwards.
 + *  3) We're streaming and ZIP_LENGTH_AT_END was specified and
 + * we have no size information.  In this case, we can do pretty
 + * well by watching for the data descriptor record.  The data
 + * descriptor is 16 bytes and includes a computed CRC that should
 + * provide a strong check.
 + *
 + * TODO: Technically, the PK\007\010 signature is optional.
 + * In the original spec, the data descriptor contained CRC
 + * and size fields but had no leading signature.  In practice,
 + * newer writers seem to provide the signature pretty consistently,
 + * but we might need to do something more complex here if
 + * we want to handle older archives that lack that signature.
 + *
 + * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
 + * zip->end_of_entry if it consumes all of the data.
 + */
 +static int
 +zip_read_data_none(struct archive_read *a, const void **_buff,
 +    size_t *size, int64_t *offset)
 +{
 +	struct zip *zip;
 +	const char *buff;
 +	ssize_t bytes_avail;
 +
++	(void)offset; /* UNUSED */
++
 +	zip = (struct zip *)(a->format->data);
 +
 +	if (zip->entry->flags & ZIP_LENGTH_AT_END) {
 +		const char *p;
 +
 +		/* Grab at least 16 bytes. */
 +		buff = __archive_read_ahead(a, 16, &bytes_avail);
 +		if (bytes_avail < 16) {
 +			/* Zip archives have end-of-archive markers
 +			   that are longer than this, so a failure to get at
 +			   least 16 bytes really does indicate a truncated
 +			   file. */
- 			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++			archive_set_error(&a->archive,
++			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated ZIP file data");
 +			return (ARCHIVE_FATAL);
 +		}
 +		/* Check for a complete PK\007\010 signature. */
 +		p = buff;
 +		if (p[0] == 'P' && p[1] == 'K' 
 +		    && p[2] == '\007' && p[3] == '\010'
 +		    && archive_le32dec(p + 4) == zip->entry_crc32
- 		    && archive_le32dec(p + 8) == zip->entry_compressed_bytes_read
- 		    && archive_le32dec(p + 12) == zip->entry_uncompressed_bytes_read) {
++		    && archive_le32dec(p + 8) ==
++			    zip->entry_compressed_bytes_read
++		    && archive_le32dec(p + 12) ==
++			    zip->entry_uncompressed_bytes_read) {
 +			zip->entry->crc32 = archive_le32dec(p + 4);
 +			zip->entry->compressed_size = archive_le32dec(p + 8);
 +			zip->entry->uncompressed_size = archive_le32dec(p + 12);
 +			zip->end_of_entry = 1;
 +			zip->unconsumed = 16;
 +			return (ARCHIVE_OK);
 +		}
 +		/* If not at EOF, ensure we consume at least one byte. */
 +		++p;
 +
- 		/* Scan forward until we see where a PK\007\010 signature might be. */
- 		/* Return bytes up until that point.  On the next call, the code
- 		   above will verify the data descriptor. */
++		/* Scan forward until we see where a PK\007\010 signature
++		 * might be. */
++		/* Return bytes up until that point.  On the next call,
++		 * the code above will verify the data descriptor. */
 +		while (p < buff + bytes_avail - 4) {
 +			if (p[3] == 'P') { p += 3; }
 +			else if (p[3] == 'K') { p += 2; }
 +			else if (p[3] == '\007') { p += 1; }
 +			else if (p[3] == '\010' && p[2] == '\007'
 +			    && p[1] == 'K' && p[0] == 'P') {
 +				break;
 +			} else { p += 4; }
 +		}
 +		bytes_avail = p - buff;
 +	} else {
 +		if (zip->entry_bytes_remaining == 0) {
 +			zip->end_of_entry = 1;
 +			return (ARCHIVE_OK);
 +		}
 +		/* Grab a bunch of bytes. */
 +		buff = __archive_read_ahead(a, 1, &bytes_avail);
 +		if (bytes_avail <= 0) {
- 			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++			archive_set_error(&a->archive,
++			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated ZIP file data");
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (bytes_avail > zip->entry_bytes_remaining)
- 			bytes_avail = zip->entry_bytes_remaining;
++			bytes_avail = (ssize_t)zip->entry_bytes_remaining;
 +	}
 +	*size = bytes_avail;
 +	zip->entry_bytes_remaining -= bytes_avail;
 +	zip->entry_uncompressed_bytes_read += bytes_avail;
 +	zip->entry_compressed_bytes_read += bytes_avail;
 +	zip->unconsumed += bytes_avail;
 +	*_buff = buff;
 +	return (ARCHIVE_OK);
 +}
 +
 +#ifdef HAVE_ZLIB_H
 +static int
++zip_deflate_init(struct archive_read *a, struct zip *zip)
++{
++	int r;
++
++	/* If we haven't yet read any data, initialize the decompressor. */
++	if (!zip->decompress_init) {
++		if (zip->stream_valid)
++			r = inflateReset(&zip->stream);
++		else
++			r = inflateInit2(&zip->stream,
++			    -15 /* Don't check for zlib header */);
++		if (r != Z_OK) {
++			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++			    "Can't initialize ZIP decompression.");
++			return (ARCHIVE_FATAL);
++		}
++		/* Stream structure has been set up. */
++		zip->stream_valid = 1;
++		/* We've initialized decompression for this stream. */
++		zip->decompress_init = 1;
++	}
++	return (ARCHIVE_OK);
++}
++
++static int
 +zip_read_data_deflate(struct archive_read *a, const void **buff,
 +    size_t *size, int64_t *offset)
 +{
 +	struct zip *zip;
 +	ssize_t bytes_avail;
 +	const void *compressed_buff;
 +	int r;
 +
++	(void)offset; /* UNUSED */
++
 +	zip = (struct zip *)(a->format->data);
 +
 +	/* If the buffer hasn't been allocated, allocate it now. */
 +	if (zip->uncompressed_buffer == NULL) {
 +		zip->uncompressed_buffer_size = 256 * 1024;
 +		zip->uncompressed_buffer
 +		    = (unsigned char *)malloc(zip->uncompressed_buffer_size);
 +		if (zip->uncompressed_buffer == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "No memory for ZIP decompression");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
- 	/* If we haven't yet read any data, initialize the decompressor. */
- 	if (!zip->decompress_init) {
- 		if (zip->stream_valid)
- 			r = inflateReset(&zip->stream);
- 		else
- 			r = inflateInit2(&zip->stream,
- 			    -15 /* Don't check for zlib header */);
- 		if (r != Z_OK) {
- 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- 			    "Can't initialize ZIP decompression.");
- 			return (ARCHIVE_FATAL);
- 		}
- 		/* Stream structure has been set up. */
- 		zip->stream_valid = 1;
- 		/* We've initialized decompression for this stream. */
- 		zip->decompress_init = 1;
- 	}
++	r = zip_deflate_init(a, zip);
++	if (r != ARCHIVE_OK)
++		return (r);
 +
 +	/*
 +	 * Note: '1' here is a performance optimization.
 +	 * Recall that the decompression layer returns a count of
 +	 * available bytes; asking for more than that forces the
 +	 * decompressor to combine reads by copying data.
 +	 */
 +	compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
 +	if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)
 +	    && bytes_avail > zip->entry_bytes_remaining) {
- 		bytes_avail = zip->entry_bytes_remaining;
++		bytes_avail = (ssize_t)zip->entry_bytes_remaining;
 +	}
 +	if (bytes_avail <= 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Truncated ZIP file body");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * A bug in zlib.h: stream.next_in should be marked 'const'
 +	 * but isn't (the library never alters data through the
 +	 * next_in pointer, only reads it).  The result: this ugly
 +	 * cast to remove 'const'.
 +	 */
 +	zip->stream.next_in = (Bytef *)(uintptr_t)(const void *)compressed_buff;
- 	zip->stream.avail_in = bytes_avail;
++	zip->stream.avail_in = (uInt)bytes_avail;
 +	zip->stream.total_in = 0;
 +	zip->stream.next_out = zip->uncompressed_buffer;
- 	zip->stream.avail_out = zip->uncompressed_buffer_size;
++	zip->stream.avail_out = (uInt)zip->uncompressed_buffer_size;
 +	zip->stream.total_out = 0;
 +
 +	r = inflate(&zip->stream, 0);
 +	switch (r) {
 +	case Z_OK:
 +		break;
 +	case Z_STREAM_END:
 +		zip->end_of_entry = 1;
 +		break;
 +	case Z_MEM_ERROR:
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Out of memory for ZIP decompression");
 +		return (ARCHIVE_FATAL);
 +	default:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "ZIP decompression failed (%d)", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Consume as much as the compressor actually used. */
 +	bytes_avail = zip->stream.total_in;
- 	__archive_read_consume(a, bytes_avail);
++	zip_read_consume(a, bytes_avail);
 +	zip->entry_bytes_remaining -= bytes_avail;
 +	zip->entry_compressed_bytes_read += bytes_avail;
 +
 +	*size = zip->stream.total_out;
 +	zip->entry_uncompressed_bytes_read += zip->stream.total_out;
 +	*buff = zip->uncompressed_buffer;
 +
 +	if (zip->end_of_entry && (zip->entry->flags & ZIP_LENGTH_AT_END)) {
 +		const char *p;
 +
 +		if (NULL == (p = __archive_read_ahead(a, 16, NULL))) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Truncated ZIP end-of-file record");
 +			return (ARCHIVE_FATAL);
 +		}
 +		/* Consume the optional PK\007\010 marker. */
- 		if (p[0] == 'P' && p[1] == 'K' && p[2] == '\007' && p[3] == '\010') {
++		if (p[0] == 'P' && p[1] == 'K' &&
++		    p[2] == '\007' && p[3] == '\010') {
 +			zip->entry->crc32 = archive_le32dec(p + 4);
 +			zip->entry->compressed_size = archive_le32dec(p + 8);
 +			zip->entry->uncompressed_size = archive_le32dec(p + 12);
 +			zip->unconsumed = 16;
 +		}
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +#endif
 +
 +static int
 +archive_read_format_zip_read_data_skip(struct archive_read *a)
 +{
 +	struct zip *zip;
 +
 +	zip = (struct zip *)(a->format->data);
 +
 +	/* If we've already read to end of data, we're done. */
 +	if (zip->end_of_entry)
 +		return (ARCHIVE_OK);
- 	/* If we're seeking, we're done. */
- 	if (zip->have_central_directory)
- 		return (ARCHIVE_OK);
 +
 +	/* So we know we're streaming... */
 +	if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)) {
 +		/* We know the compressed length, so we can just skip. */
- 		int64_t bytes_skipped = __archive_read_consume(a,
++		int64_t bytes_skipped = zip_read_consume(a,
 +		    zip->entry_bytes_remaining + zip->unconsumed);
 +		if (bytes_skipped < 0)
 +			return (ARCHIVE_FATAL);
 +		zip->unconsumed = 0;
 +		return (ARCHIVE_OK);
 +	}
 +
 +	/* We're streaming and we don't know the length. */
 +	/* If the body is compressed and we know the format, we can
 +	 * find an exact end-of-entry by decompressing it. */
 +	switch (zip->entry->compression) {
 +#ifdef HAVE_ZLIB_H
 +	case 8: /* Deflate compression. */
 +		while (!zip->end_of_entry) {
 +			int64_t offset = 0;
 +			const void *buff = NULL;
 +			size_t size = 0;
 +			int r;
 +			r =  zip_read_data_deflate(a, &buff, &size, &offset);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +		}
- 		break;
++		return ARCHIVE_OK;
 +#endif
 +	default: /* Uncompressed or unknown. */
 +		/* Scan for a PK\007\010 signature. */
- 		__archive_read_consume(a, zip->unconsumed);
++		zip_read_consume(a, zip->unconsumed);
 +		zip->unconsumed = 0;
 +		for (;;) {
 +			const char *p, *buff;
 +			ssize_t bytes_avail;
 +			buff = __archive_read_ahead(a, 16, &bytes_avail);
 +			if (bytes_avail < 16) {
- 				archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
++				archive_set_error(&a->archive,
++				    ARCHIVE_ERRNO_FILE_FORMAT,
 +				    "Truncated ZIP file data");
 +				return (ARCHIVE_FATAL);
 +			}
 +			p = buff;
- 			while (p < buff + bytes_avail - 16) {
++			while (p <= buff + bytes_avail - 16) {
 +				if (p[3] == 'P') { p += 3; }
 +				else if (p[3] == 'K') { p += 2; }
 +				else if (p[3] == '\007') { p += 1; }
 +				else if (p[3] == '\010' && p[2] == '\007'
 +				    && p[1] == 'K' && p[0] == 'P') {
- 					__archive_read_consume(a, p - buff + 16);
++					zip_read_consume(a, p - buff + 16);
 +					return ARCHIVE_OK;
 +				} else { p += 4; }
 +			}
- 			__archive_read_consume(a, p - buff);
++			zip_read_consume(a, p - buff);
 +		}
 +	}
- 	return ARCHIVE_OK;
 +}
 +
 +static int
 +archive_read_format_zip_cleanup(struct archive_read *a)
 +{
 +	struct zip *zip;
 +
 +	zip = (struct zip *)(a->format->data);
 +#ifdef HAVE_ZLIB_H
 +	if (zip->stream_valid)
 +		inflateEnd(&zip->stream);
 +#endif
++	if (zip->zip_entries && zip->central_directory_entries) {
++		unsigned i;
++		for (i = 0; i < zip->central_directory_entries; i++)
++			archive_string_free(&(zip->zip_entries[i].rsrcname));
++	}
 +	free(zip->zip_entries);
 +	free(zip->uncompressed_buffer);
 +	archive_string_free(&(zip->extra));
 +	free(zip);
 +	(a->format->data) = NULL;
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * The extra data is stored as a list of
 + *	id1+size1+data1 + id2+size2+data2 ...
 + *  triplets.  id and size are 2 bytes each.
 + */
 +static void
 +process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
 +{
 +	unsigned offset = 0;
 +
 +	while (offset < extra_length - 4)
 +	{
 +		unsigned short headerid = archive_le16dec(p + offset);
 +		unsigned short datasize = archive_le16dec(p + offset + 2);
 +		offset += 4;
 +		if (offset + datasize > extra_length)
 +			break;
 +#ifdef DEBUG
 +		fprintf(stderr, "Header id 0x%x, length %d\n",
 +		    headerid, datasize);
 +#endif
 +		switch (headerid) {
 +		case 0x0001:
 +			/* Zip64 extended information extra field. */
 +			if (datasize >= 8)
 +				zip_entry->uncompressed_size =
 +				    archive_le64dec(p + offset);
 +			if (datasize >= 16)
 +				zip_entry->compressed_size =
 +				    archive_le64dec(p + offset + 8);
 +			break;
 +		case 0x5455:
 +		{
 +			/* Extended time field "UT". */
 +			int flags = p[offset];
 +			offset++;
 +			datasize--;
 +			/* Flag bits indicate which dates are present. */
 +			if (flags & 0x01)
 +			{
 +#ifdef DEBUG
 +				fprintf(stderr, "mtime: %lld -> %d\n",
 +				    (long long)zip_entry->mtime,
 +				    archive_le32dec(p + offset));
 +#endif
 +				if (datasize < 4)
 +					break;
 +				zip_entry->mtime = archive_le32dec(p + offset);
 +				offset += 4;
 +				datasize -= 4;
 +			}
 +			if (flags & 0x02)
 +			{
 +				if (datasize < 4)
 +					break;
 +				zip_entry->atime = archive_le32dec(p + offset);
 +				offset += 4;
 +				datasize -= 4;
 +			}
 +			if (flags & 0x04)
 +			{
 +				if (datasize < 4)
 +					break;
 +				zip_entry->ctime = archive_le32dec(p + offset);
 +				offset += 4;
 +				datasize -= 4;
 +			}
 +			break;
 +		}
 +		case 0x5855:
 +		{
 +			/* Info-ZIP Unix Extra Field (old version) "UX". */
 +			if (datasize >= 8) {
 +				zip_entry->atime = archive_le32dec(p + offset);
- 				zip_entry->mtime = archive_le32dec(p + offset + 4);
++				zip_entry->mtime =
++				    archive_le32dec(p + offset + 4);
 +			}
 +			if (datasize >= 12) {
- 				zip_entry->uid = archive_le16dec(p + offset + 8);
- 				zip_entry->gid = archive_le16dec(p + offset + 10);
++				zip_entry->uid =
++				    archive_le16dec(p + offset + 8);
++				zip_entry->gid =
++				    archive_le16dec(p + offset + 10);
 +			}
 +			break;
 +		}
 +		case 0x7855:
 +			/* Info-ZIP Unix Extra Field (type 2) "Ux". */
 +#ifdef DEBUG
 +			fprintf(stderr, "uid %d gid %d\n",
 +			    archive_le16dec(p + offset),
 +			    archive_le16dec(p + offset + 2));
 +#endif
 +			if (datasize >= 2)
 +				zip_entry->uid = archive_le16dec(p + offset);
 +			if (datasize >= 4)
- 				zip_entry->gid = archive_le16dec(p + offset + 2);
++				zip_entry->gid =
++				    archive_le16dec(p + offset + 2);
 +			break;
 +		case 0x7875:
 +		{
 +			/* Info-Zip Unix Extra Field (type 3) "ux". */
 +			int uidsize = 0, gidsize = 0;
 +
 +			if (datasize >= 1 && p[offset] == 1) {/* version=1 */
 +				if (datasize >= 4) {
 +					/* get a uid size. */
 +					uidsize = p[offset+1];
 +					if (uidsize == 2)
- 						zip_entry->uid = archive_le16dec(
- 						     p + offset + 2);
++						zip_entry->uid =
++						    archive_le16dec(
++						        p + offset + 2);
 +					else if (uidsize == 4 && datasize >= 6)
- 						zip_entry->uid = archive_le32dec(
- 						     p + offset + 2);
++						zip_entry->uid =
++						    archive_le32dec(
++						        p + offset + 2);
 +				}
 +				if (datasize >= (2 + uidsize + 3)) {
 +					/* get a gid size. */
 +					gidsize = p[offset+2+uidsize];
 +					if (gidsize == 2)
- 						zip_entry->gid = archive_le16dec(
- 						    p+offset+2+uidsize+1);
++						zip_entry->gid =
++						    archive_le16dec(
++						        p+offset+2+uidsize+1);
 +					else if (gidsize == 4 &&
 +					    datasize >= (2 + uidsize + 5))
- 						zip_entry->gid = archive_le32dec(
- 						    p+offset+2+uidsize+1);
++						zip_entry->gid =
++						    archive_le32dec(
++						        p+offset+2+uidsize+1);
 +				}
 +			}
 +			break;
 +		}
 +		default:
 +			break;
 +		}
 +		offset += datasize;
 +	}
 +#ifdef DEBUG
 +	if (offset != extra_length)
 +	{
 +		fprintf(stderr,
 +		    "Extra data field contents do not match reported size!\n");
 +	}
 +#endif
 +}
diff --cc Utilities/cmlibarchive/libarchive/archive_windows.h
index c581af3,0000000..620810c
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_windows.h
+++ b/Utilities/cmlibarchive/libarchive/archive_windows.h
@@@ -1,297 -1,0 +1,310 @@@
 +/*-
 + * Copyright (c) 2009-2011 Michihiro NAKAJIMA
 + * Copyright (c) 2003-2006 Tim Kientzle
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer
 + *    in this position and unchanged.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + * $FreeBSD$
 + */
 +
 +#ifndef __LIBARCHIVE_BUILD
 +#error This header is only to be used internally to libarchive.
 +#endif
 +
 +/*
 + * TODO: A lot of stuff in here isn't actually used by libarchive and
 + * can be trimmed out.  Note that this file is used by libarchive and
 + * libarchive_test but nowhere else.  (But note that it gets compiled
 + * with many different Windows environments, including MinGW, Visual
 + * Studio, and Cygwin.  Significant changes should be tested in all three.)
 + */
 +
 +/*
 + * TODO: Don't use off_t in here.  Use __int64 instead.  Note that
 + * Visual Studio and the Windows SDK define off_t as 32 bits; Win32's
 + * more modern file handling APIs all use __int64 instead of off_t.
 + */
 +
 +#ifndef LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED
 +#define	LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED
 +
 +/* Start of configuration for native Win32  */
++#ifndef MINGW_HAS_SECURE_API
++#define MINGW_HAS_SECURE_API 1
++#endif
 +
 +#include <errno.h>
 +#define	set_errno(val)	((errno)=val)
 +#include <io.h>
 +#include <stdlib.h>   //brings in NULL
 +#if defined(HAVE_STDINT_H)
 +#include <stdint.h>
 +#endif
 +#include <stdio.h>
 +#include <fcntl.h>
 +#include <sys/stat.h>
 +#include <process.h>
 +#include <direct.h>
 +#if defined(__MINGW32__) && defined(HAVE_UNISTD_H)
 +/* Prevent build error from a type mismatch of ftruncate().
 + * This unistd.h defines it as ftruncate(int, off_t). */
 +#include <unistd.h>
 +#endif
 +#define NOCRYPT
 +#include <windows.h>
 +//#define	EFTYPE 7
 +
 +#if defined(_MSC_VER)
- /* TODO: Fix the code, don't suppress the warnings. */
 +#pragma warning(push,1)
 +#pragma warning(disable:4761)   /* integral size mismatch in argument; conversion supplied */
 +#endif
 +#if defined(__BORLANDC__)
 +#pragma warn -8068	/* Constant out of range in comparison. */
 +#pragma warn -8072	/* Suspicious pointer arithmetic. */
 +#endif
 +
 +#ifndef NULL
 +#ifdef  __cplusplus
 +#define	NULL    0
 +#else
 +#define	NULL    ((void *)0)
 +#endif
 +#endif
 +
 +/* Alias the Windows _function to the POSIX equivalent. */
 +#define	close		_close
 +#define	fcntl(fd, cmd, flg)	/* No operation. */		
 +#ifndef fileno
 +#define	fileno		_fileno
 +#endif
++#ifdef fstat
++#undef fstat
++#endif
 +#define	fstat		__la_fstat
 +#if !defined(__BORLANDC__)
++#ifdef lseek
++#undef lseek
++#endif
 +#define	lseek		_lseeki64
 +#else
 +#define	lseek		__la_lseek
 +#define __LA_LSEEK_NEEDED
 +#endif
 +#define	lstat		__la_stat
 +#define	open		__la_open
 +#define	read		__la_read
 +#if !defined(__BORLANDC__)
 +#define setmode		_setmode
 +#endif
++#ifdef stat
++#undef stat
++#endif
 +#define	stat(path,stref)		__la_stat(path,stref)
 +#if !defined(__BORLANDC__)
 +#define	strdup		_strdup
 +#endif
 +#define	tzset		_tzset
 +#if !defined(__BORLANDC__)
 +#define	umask		_umask
 +#endif
 +#define	waitpid		__la_waitpid
 +#define	write		__la_write
 +
 +#ifndef O_RDONLY
 +#define	O_RDONLY	_O_RDONLY
 +#define	O_WRONLY	_O_WRONLY
 +#define	O_TRUNC		_O_TRUNC
 +#define	O_CREAT		_O_CREAT
 +#define	O_EXCL		_O_EXCL
 +#define	O_BINARY	_O_BINARY
 +#endif
 +
 +#ifndef _S_IFIFO
 +  #define	_S_IFIFO        0010000   /* pipe */
 +#endif
 +#ifndef _S_IFCHR
 +  #define	_S_IFCHR        0020000   /* character special */
 +#endif
 +#ifndef _S_IFDIR
 +  #define	_S_IFDIR        0040000   /* directory */
 +#endif
 +#ifndef _S_IFBLK
 +  #define	_S_IFBLK        0060000   /* block special */
 +#endif
 +#ifndef _S_IFLNK
 +  #define	_S_IFLNK        0120000   /* symbolic link */
 +#endif
 +#ifndef _S_IFSOCK
 +  #define	_S_IFSOCK       0140000   /* socket */
 +#endif
 +#ifndef	_S_IFREG
 +  #define	_S_IFREG        0100000   /* regular */
 +#endif
 +#ifndef	_S_IFMT
 +  #define	_S_IFMT         0170000   /* file type mask */
 +#endif
 +
 +#ifndef S_IFIFO
 +#define	S_IFIFO     _S_IFIFO
 +#endif
 +//#define	S_IFCHR  _S_IFCHR
 +//#define	S_IFDIR  _S_IFDIR
 +#ifndef S_IFBLK
 +#define	S_IFBLK     _S_IFBLK
 +#endif
 +#ifndef S_IFLNK
 +#define	S_IFLNK     _S_IFLNK
 +#endif
 +#ifndef S_IFSOCK
 +#define	S_IFSOCK    _S_IFSOCK
 +#endif
 +//#define	S_IFREG  _S_IFREG
 +//#define	S_IFMT   _S_IFMT
 +
 +#ifndef S_ISBLK
 +#define	S_ISBLK(m)	(((m) & S_IFMT) == S_IFBLK)	/* block special */
 +#define	S_ISFIFO(m)	(((m) & S_IFMT) == S_IFIFO)	/* fifo or socket */
 +#define	S_ISCHR(m)	(((m) & S_IFMT) == S_IFCHR)	/* char special */
 +#define	S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)	/* directory */
 +#define	S_ISREG(m)	(((m) & S_IFMT) == S_IFREG)	/* regular file */
 +#endif
 +#define	S_ISLNK(m)  (((m) & S_IFMT) == S_IFLNK) /* Symbolic link */
 +#define	S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* Socket */
 +
 +#define	_S_ISUID        0004000   /* set user id on execution */
 +#define	_S_ISGID        0002000   /* set group id on execution */
 +#define	_S_ISVTX        0001000   /* save swapped text even after use */
 +
 +#define	S_ISUID        _S_ISUID
 +#define	S_ISGID        _S_ISGID
 +#define	S_ISVTX        _S_ISVTX
 +
 +#define	_S_IRWXU	     (_S_IREAD | _S_IWRITE | _S_IEXEC)
 +#define	_S_IXUSR	     _S_IEXEC  /* read permission, user */
 +#define	_S_IWUSR	     _S_IWRITE /* write permission, user */
 +#define	_S_IRUSR	     _S_IREAD  /* execute/search permission, user */
 +#define	_S_IRWXG        (_S_IRWXU >> 3)
 +#define	_S_IXGRP        (_S_IXUSR >> 3) /* read permission, group */
 +#define	_S_IWGRP        (_S_IWUSR >> 3) /* write permission, group */
 +#define	_S_IRGRP        (_S_IRUSR >> 3) /* execute/search permission, group */
 +#define	_S_IRWXO        (_S_IRWXG >> 3) 
 +#define	_S_IXOTH        (_S_IXGRP >> 3) /* read permission, other */
 +#define	_S_IWOTH        (_S_IWGRP >> 3) /* write permission, other */
 +#define	_S_IROTH        (_S_IRGRP  >> 3) /* execute/search permission, other */
 +
 +#ifndef S_IRWXU
 +#define	S_IRWXU	     _S_IRWXU
 +#define	S_IXUSR	     _S_IXUSR
 +#define	S_IWUSR	     _S_IWUSR
 +#define	S_IRUSR	     _S_IRUSR
 +#endif
 +#define	S_IRWXG        _S_IRWXG
 +#define	S_IXGRP        _S_IXGRP
 +#define	S_IWGRP        _S_IWGRP
 +#define	S_IRGRP        _S_IRGRP
 +#define	S_IRWXO        _S_IRWXO
 +#define	S_IXOTH        _S_IXOTH
 +#define	S_IWOTH        _S_IWOTH
 +#define	S_IROTH        _S_IROTH
 +
 +#define	F_DUPFD	  	0	/* Duplicate file descriptor.  */
 +#define	F_GETFD		1	/* Get file descriptor flags.  */
 +#define	F_SETFD		2	/* Set file descriptor flags.  */
 +#define	F_GETFL		3	/* Get file status flags.  */
 +#define	F_SETFL		4	/* Set file status flags.  */
 +#define	F_GETOWN		5	/* Get owner (receiver of SIGIO).  */
 +#define	F_SETOWN		6	/* Set owner (receiver of SIGIO).  */
 +#define	F_GETLK		7	/* Get record locking info.  */
 +#define	F_SETLK		8	/* Set record locking info (non-blocking).  */
 +#define	F_SETLKW		9	/* Set record locking info (blocking).  */
 +
 +/* XXX missing */
 +#define	F_GETLK64	7	/* Get record locking info.  */
 +#define	F_SETLK64	8	/* Set record locking info (non-blocking).  */
 +#define	F_SETLKW64	9	/* Set record locking info (blocking).  */
 +
 +/* File descriptor flags used with F_GETFD and F_SETFD.  */
 +#define	FD_CLOEXEC	1	/* Close on exec.  */
 +
 +//NOT SURE IF O_NONBLOCK is OK here but at least the 0x0004 flag is not used by anything else...
 +#define	O_NONBLOCK 0x0004 /* Non-blocking I/O.  */
 +//#define	O_NDELAY   O_NONBLOCK
 +
 +/* Symbolic constants for the access() function */
 +#if !defined(F_OK)
 +    #define	R_OK    4       /*  Test for read permission    */
 +    #define	W_OK    2       /*  Test for write permission   */
 +    #define	X_OK    1       /*  Test for execute permission */
 +    #define	F_OK    0       /*  Test for existence of file  */
 +#endif
 +
 +
 +/* Replacement POSIX function */
 +extern int	 __la_fstat(int fd, struct stat *st);
 +extern int	 __la_lstat(const char *path, struct stat *st);
 +#if defined(__LA_LSEEK_NEEDED)
 +extern __int64	 __la_lseek(int fd, __int64 offset, int whence);
 +#endif
 +extern int	 __la_open(const char *path, int flags, ...);
 +extern ssize_t	 __la_read(int fd, void *buf, size_t nbytes);
 +extern int	 __la_stat(const char *path, struct stat *st);
- extern pid_t	 __la_waitpid(pid_t wpid, int *status, int option);
++extern pid_t	 __la_waitpid(HANDLE child, int *status, int option);
 +extern ssize_t	 __la_write(int fd, const void *buf, size_t nbytes);
 +
 +#define _stat64i32(path, st)	__la_stat(path, st)
 +#define _stat64(path, st)	__la_stat(path, st)
 +/* for status returned by la_waitpid */
 +#define WIFEXITED(sts)		((sts & 0x100) == 0)
 +#define WEXITSTATUS(sts)	(sts & 0x0FF)
 +
 +extern wchar_t *__la_win_permissive_name(const char *name);
 +extern wchar_t *__la_win_permissive_name_w(const wchar_t *wname);
 +extern void __la_dosmaperr(unsigned long e);
 +#define la_dosmaperr(e) __la_dosmaperr(e)
++extern struct archive_entry *__la_win_entry_in_posix_pathseparator(
++    struct archive_entry *);
 +
 +#if defined(HAVE_WCRTOMB) && defined(__BORLANDC__)
 +typedef int mbstate_t;
 +size_t wcrtomb(char *, wchar_t, mbstate_t *);
 +#endif
 +
 +#if defined(_MSC_VER) && _MSC_VER < 1300
 +WINBASEAPI BOOL WINAPI GetVolumePathNameW(
- 	LPCWSTR lpszFileName,
- 	LPWSTR lpszVolumePathName,
- 	DWORD cchBufferLength
- 	);
++       LPCWSTR lpszFileName,
++       LPWSTR lpszVolumePathName,
++       DWORD cchBufferLength
++       );
 +# if _WIN32_WINNT < 0x0500 /* windows.h not providing 0x500 API */
 +typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
- 	LARGE_INTEGER FileOffset;
- 	LARGE_INTEGER Length;
++       LARGE_INTEGER FileOffset;
++       LARGE_INTEGER Length;
 +} FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER;
 +#  define FSCTL_SET_SPARSE \
 +     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_WRITE_DATA)
 +#  define FSCTL_QUERY_ALLOCATED_RANGES \
 +     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51,  METHOD_NEITHER, FILE_READ_DATA)
 +# endif
 +#endif
 +
 +#endif /* LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */
diff --cc Utilities/cmlibarchive/libarchive/archive_write.c
index b4b3867,0000000..b296069
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write.c
@@@ -1,709 -1,0 +1,715 @@@
 +/*-
 + * Copyright (c) 2003-2010 Tim Kientzle
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write.c 201099 2009-12-28 03:03:00Z kientzle $");
 +
 +/*
 + * This file contains the "essential" portions of the write API, that
 + * is, stuff that will essentially always be used by any client that
 + * actually needs to write an archive.  Optional pieces have been, as
 + * far as possible, separated out into separate files to reduce
 + * needlessly bloating statically-linked clients.
 + */
 +
 +#ifdef HAVE_SYS_WAIT_H
 +#include <sys/wait.h>
 +#endif
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_LIMITS_H
 +#include <limits.h>
 +#endif
 +#include <stdio.h>
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#include <time.h>
 +#ifdef HAVE_UNISTD_H
 +#include <unistd.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_entry.h"
 +#include "archive_private.h"
 +#include "archive_write_private.h"
 +
 +static struct archive_vtable *archive_write_vtable(void);
 +
 +static int	_archive_filter_code(struct archive *, int);
 +static const char *_archive_filter_name(struct archive *, int);
 +static int64_t	_archive_filter_bytes(struct archive *, int);
 +static int  _archive_write_filter_count(struct archive *);
 +static int	_archive_write_close(struct archive *);
 +static int	_archive_write_free(struct archive *);
 +static int	_archive_write_header(struct archive *, struct archive_entry *);
 +static int	_archive_write_finish_entry(struct archive *);
 +static ssize_t	_archive_write_data(struct archive *, const void *, size_t);
 +
 +struct archive_none {
 +	size_t buffer_size;
 +	size_t avail;
 +	char *buffer;
 +	char *next;
 +};
 +
 +static struct archive_vtable *
 +archive_write_vtable(void)
 +{
 +	static struct archive_vtable av;
 +	static int inited = 0;
 +
 +	if (!inited) {
 +		av.archive_close = _archive_write_close;
 +		av.archive_filter_bytes = _archive_filter_bytes;
 +		av.archive_filter_code = _archive_filter_code;
 +		av.archive_filter_name = _archive_filter_name;
 +		av.archive_filter_count = _archive_write_filter_count;
 +		av.archive_free = _archive_write_free;
 +		av.archive_write_header = _archive_write_header;
 +		av.archive_write_finish_entry = _archive_write_finish_entry;
 +		av.archive_write_data = _archive_write_data;
 +		inited = 1;
 +	}
 +	return (&av);
 +}
 +
 +/*
 + * Allocate, initialize and return an archive object.
 + */
 +struct archive *
 +archive_write_new(void)
 +{
 +	struct archive_write *a;
 +	unsigned char *nulls;
 +
 +	a = (struct archive_write *)malloc(sizeof(*a));
 +	if (a == NULL)
 +		return (NULL);
 +	memset(a, 0, sizeof(*a));
 +	a->archive.magic = ARCHIVE_WRITE_MAGIC;
 +	a->archive.state = ARCHIVE_STATE_NEW;
 +	a->archive.vtable = archive_write_vtable();
 +	/*
 +	 * The value 10240 here matches the traditional tar default,
 +	 * but is otherwise arbitrary.
 +	 * TODO: Set the default block size from the format selected.
 +	 */
 +	a->bytes_per_block = 10240;
 +	a->bytes_in_last_block = -1;	/* Default */
 +
 +	/* Initialize a block of nulls for padding purposes. */
 +	a->null_length = 1024;
 +	nulls = (unsigned char *)malloc(a->null_length);
 +	if (nulls == NULL) {
 +		free(a);
 +		return (NULL);
 +	}
 +	memset(nulls, 0, a->null_length);
 +	a->nulls = nulls;
 +	return (&a->archive);
 +}
 +
 +/*
 + * Set the block size.  Returns 0 if successful.
 + */
 +int
 +archive_write_set_bytes_per_block(struct archive *_a, int bytes_per_block)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_set_bytes_per_block");
 +	a->bytes_per_block = bytes_per_block;
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Get the current block size.  -1 if it has never been set.
 + */
 +int
 +archive_write_get_bytes_per_block(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_ANY, "archive_write_get_bytes_per_block");
 +	return (a->bytes_per_block);
 +}
 +
 +/*
 + * Set the size for the last block.
 + * Returns 0 if successful.
 + */
 +int
 +archive_write_set_bytes_in_last_block(struct archive *_a, int bytes)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_ANY, "archive_write_set_bytes_in_last_block");
 +	a->bytes_in_last_block = bytes;
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Return the value set above.  -1 indicates it has not been set.
 + */
 +int
 +archive_write_get_bytes_in_last_block(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_ANY, "archive_write_get_bytes_in_last_block");
 +	return (a->bytes_in_last_block);
 +}
 +
 +/*
 + * dev/ino of a file to be rejected.  Used to prevent adding
 + * an archive to itself recursively.
 + */
 +int
 +archive_write_set_skip_file(struct archive *_a, int64_t d, int64_t i)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_ANY, "archive_write_set_skip_file");
 +	a->skip_file_set = 1;
 +	a->skip_file_dev = d;
 +	a->skip_file_ino = i;
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Allocate and return the next filter structure.
 + */
 +struct archive_write_filter *
 +__archive_write_allocate_filter(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct archive_write_filter *f;
 +
 +	f = calloc(1, sizeof(*f));
 +	f->archive = _a;
 +	if (a->filter_first == NULL)
 +		a->filter_first = f;
 +	else
 +		a->filter_last->next_filter = f;
 +	a->filter_last = f;
 +	return f;
 +}
 +
 +/*
 + * Write data to a particular filter.
 + */
 +int
 +__archive_write_filter(struct archive_write_filter *f,
 +    const void *buff, size_t length)
 +{
 +	int r;
 +	if (length == 0)
 +		return(ARCHIVE_OK);
++	if (f->write == NULL)
++		/* If unset, a fatal error has already ocuured, so this filter
++		 * didn't open. We cannot write anything. */
++		return(ARCHIVE_FATAL);
 +	r = (f->write)(f, buff, length);
 +	f->bytes_written += length;
 +	return (r);
 +}
 +
 +/*
 + * Open a filter.
 + */
 +int
 +__archive_write_open_filter(struct archive_write_filter *f)
 +{
 +	if (f->open == NULL)
 +		return (ARCHIVE_OK);
 +	return (f->open)(f);
 +}
 +
 +/*
 + * Close a filter.
 + */
 +int
 +__archive_write_close_filter(struct archive_write_filter *f)
 +{
 +	if (f->close != NULL)
 +		return (f->close)(f);
 +	if (f->next_filter != NULL)
 +		return (__archive_write_close_filter(f->next_filter));
 +	return (ARCHIVE_OK);
 +}
 +
 +int
 +__archive_write_output(struct archive_write *a, const void *buff, size_t length)
 +{
 +	return (__archive_write_filter(a->filter_first, buff, length));
 +}
 +
 +int
 +__archive_write_nulls(struct archive_write *a, size_t length)
 +{
 +	if (length == 0)
 +		return (ARCHIVE_OK);
 +
 +	while (length > 0) {
 +		size_t to_write = length < a->null_length ? length : a->null_length;
 +		int r = __archive_write_output(a, a->nulls, to_write);
 +		if (r < ARCHIVE_OK)
 +			return (r);
 +		length -= to_write;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_write_client_open(struct archive_write_filter *f)
 +{
 +	struct archive_write *a = (struct archive_write *)f->archive;
 +	struct archive_none *state;
 +	void *buffer;
 +	size_t buffer_size;
 +
 +	f->bytes_per_block = archive_write_get_bytes_per_block(f->archive);
 +	f->bytes_in_last_block =
 +	    archive_write_get_bytes_in_last_block(f->archive);
 +	buffer_size = f->bytes_per_block;
 +
 +	state = (struct archive_none *)calloc(1, sizeof(*state));
 +	buffer = (char *)malloc(buffer_size);
 +	if (state == NULL || buffer == NULL) {
 +		free(state);
 +		free(buffer);
 +		archive_set_error(f->archive, ENOMEM,
 +		    "Can't allocate data for output buffering");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	state->buffer_size = buffer_size;
 +	state->buffer = buffer;
 +	state->next = state->buffer;
 +	state->avail = state->buffer_size;
 +	f->data = state;
 +
 +	if (a->client_opener == NULL)
 +		return (ARCHIVE_OK);
 +	return (a->client_opener(f->archive, a->client_data));
 +}
 +
 +static int
 +archive_write_client_write(struct archive_write_filter *f,
 +    const void *_buff, size_t length)
 +{
 +	struct archive_write *a = (struct archive_write *)f->archive;
 +        struct archive_none *state = (struct archive_none *)f->data;
-         const char *buff = (const char *)_buff;
-         ssize_t remaining, to_copy;
-         ssize_t bytes_written;
- 
-         remaining = length;
- 
-         /*
-          * If there is no buffer for blocking, just pass the data
-          * straight through to the client write callback.  In
-          * particular, this supports "no write delay" operation for
-          * special applications.  Just set the block size to zero.
-          */
-         if (state->buffer_size == 0) {
-                 while (remaining > 0) {
-                         bytes_written = (a->client_writer)(&a->archive,
-                             a->client_data, buff, remaining);
-                         if (bytes_written <= 0)
-                                 return (ARCHIVE_FATAL);
-                         remaining -= bytes_written;
-                         buff += bytes_written;
-                 }
-                 return (ARCHIVE_OK);
-         }
- 
-         /* If the copy buffer isn't empty, try to fill it. */
-         if (state->avail < state->buffer_size) {
-                 /* If buffer is not empty... */
-                 /* ... copy data into buffer ... */
-                 to_copy = ((size_t)remaining > state->avail) ?
++	const char *buff = (const char *)_buff;
++	ssize_t remaining, to_copy;
++	ssize_t bytes_written;
++
++	remaining = length;
++
++	/*
++	 * If there is no buffer for blocking, just pass the data
++	 * straight through to the client write callback.  In
++	 * particular, this supports "no write delay" operation for
++	 * special applications.  Just set the block size to zero.
++	 */
++	if (state->buffer_size == 0) {
++		while (remaining > 0) {
++			bytes_written = (a->client_writer)(&a->archive,
++			    a->client_data, buff, remaining);
++			if (bytes_written <= 0)
++				return (ARCHIVE_FATAL);
++			remaining -= bytes_written;
++			buff += bytes_written;
++		}
++		return (ARCHIVE_OK);
++	}
++
++	/* If the copy buffer isn't empty, try to fill it. */
++	if (state->avail < state->buffer_size) {
++		/* If buffer is not empty... */
++		/* ... copy data into buffer ... */
++		to_copy = ((size_t)remaining > state->avail) ?
 +			state->avail : (size_t)remaining;
-                 memcpy(state->next, buff, to_copy);
-                 state->next += to_copy;
-                 state->avail -= to_copy;
-                 buff += to_copy;
-                 remaining -= to_copy;
-                 /* ... if it's full, write it out. */
-                 if (state->avail == 0) {
++		memcpy(state->next, buff, to_copy);
++		state->next += to_copy;
++		state->avail -= to_copy;
++		buff += to_copy;
++		remaining -= to_copy;
++		/* ... if it's full, write it out. */
++		if (state->avail == 0) {
 +			char *p = state->buffer;
 +			size_t to_write = state->buffer_size;
 +			while (to_write > 0) {
 +				bytes_written = (a->client_writer)(&a->archive,
 +				    a->client_data, p, to_write);
 +				if (bytes_written <= 0)
 +					return (ARCHIVE_FATAL);
 +				if ((size_t)bytes_written > to_write) {
 +					archive_set_error(&(a->archive),
 +					    -1, "write overrun");
 +					return (ARCHIVE_FATAL);
 +				}
 +				p += bytes_written;
 +				to_write -= bytes_written;
 +			}
-                         state->next = state->buffer;
-                         state->avail = state->buffer_size;
-                 }
-         }
- 
-         while ((size_t)remaining > state->buffer_size) {
-                 /* Write out full blocks directly to client. */
-                 bytes_written = (a->client_writer)(&a->archive,
-                     a->client_data, buff, state->buffer_size);
-                 if (bytes_written <= 0)
-                         return (ARCHIVE_FATAL);
-                 buff += bytes_written;
-                 remaining -= bytes_written;
-         }
- 
-         if (remaining > 0) {
-                 /* Copy last bit into copy buffer. */
-                 memcpy(state->next, buff, remaining);
-                 state->next += remaining;
-                 state->avail -= remaining;
-         }
-         return (ARCHIVE_OK);
++			state->next = state->buffer;
++			state->avail = state->buffer_size;
++		}
++	}
++
++	while ((size_t)remaining >= state->buffer_size) {
++		/* Write out full blocks directly to client. */
++		bytes_written = (a->client_writer)(&a->archive,
++		    a->client_data, buff, state->buffer_size);
++		if (bytes_written <= 0)
++			return (ARCHIVE_FATAL);
++		buff += bytes_written;
++		remaining -= bytes_written;
++	}
++
++	if (remaining > 0) {
++		/* Copy last bit into copy buffer. */
++		memcpy(state->next, buff, remaining);
++		state->next += remaining;
++		state->avail -= remaining;
++	}
++	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_write_client_close(struct archive_write_filter *f)
 +{
 +	struct archive_write *a = (struct archive_write *)f->archive;
-         struct archive_none *state = (struct archive_none *)f->data;
-         ssize_t block_length;
-         ssize_t target_block_length;
-         ssize_t bytes_written;
-         int ret = ARCHIVE_OK;
- 
-         /* If there's pending data, pad and write the last block */
-         if (state->next != state->buffer) {
-                 block_length = state->buffer_size - state->avail;
- 
-                 /* Tricky calculation to determine size of last block */
-                 if (a->bytes_in_last_block <= 0)
-                         /* Default or Zero: pad to full block */
-                         target_block_length = a->bytes_per_block;
-                 else
-                         /* Round to next multiple of bytes_in_last_block. */
-                         target_block_length = a->bytes_in_last_block *
-                             ( (block_length + a->bytes_in_last_block - 1) /
-                                 a->bytes_in_last_block);
-                 if (target_block_length > a->bytes_per_block)
-                         target_block_length = a->bytes_per_block;
-                 if (block_length < target_block_length) {
-                         memset(state->next, 0,
-                             target_block_length - block_length);
-                         block_length = target_block_length;
-                 }
-                 bytes_written = (a->client_writer)(&a->archive,
-                     a->client_data, state->buffer, block_length);
-                 ret = bytes_written <= 0 ? ARCHIVE_FATAL : ARCHIVE_OK;
-         }
++	struct archive_none *state = (struct archive_none *)f->data;
++	ssize_t block_length;
++	ssize_t target_block_length;
++	ssize_t bytes_written;
++	int ret = ARCHIVE_OK;
++
++	/* If there's pending data, pad and write the last block */
++	if (state->next != state->buffer) {
++		block_length = state->buffer_size - state->avail;
++
++		/* Tricky calculation to determine size of last block */
++		if (a->bytes_in_last_block <= 0)
++			/* Default or Zero: pad to full block */
++			target_block_length = a->bytes_per_block;
++		else
++			/* Round to next multiple of bytes_in_last_block. */
++			target_block_length = a->bytes_in_last_block *
++			    ( (block_length + a->bytes_in_last_block - 1) /
++			        a->bytes_in_last_block);
++		if (target_block_length > a->bytes_per_block)
++			target_block_length = a->bytes_per_block;
++		if (block_length < target_block_length) {
++			memset(state->next, 0,
++			    target_block_length - block_length);
++			block_length = target_block_length;
++		}
++		bytes_written = (a->client_writer)(&a->archive,
++		    a->client_data, state->buffer, block_length);
++		ret = bytes_written <= 0 ? ARCHIVE_FATAL : ARCHIVE_OK;
++	}
 +	if (a->client_closer)
 +		(*a->client_closer)(&a->archive, a->client_data);
 +	free(state->buffer);
-         free(state);
-         a->client_data = NULL;
-         return (ret);
++	free(state);
++	/* Clear the close handler myself not to be called again. */
++	f->close = NULL;
++	a->client_data = NULL;
++	return (ret);
 +}
 +
 +/*
 + * Open the archive using the current settings.
 + */
 +int
 +archive_write_open(struct archive *_a, void *client_data,
 +    archive_open_callback *opener, archive_write_callback *writer,
 +    archive_close_callback *closer)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct archive_write_filter *client_filter;
 +	int ret, r1;
 +
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_open");
 +	archive_clear_error(&a->archive);
 +
 +	a->client_writer = writer;
 +	a->client_opener = opener;
 +	a->client_closer = closer;
 +	a->client_data = client_data;
 +
 +	client_filter = __archive_write_allocate_filter(_a);
 +	client_filter->open = archive_write_client_open;
 +	client_filter->write = archive_write_client_write;
 +	client_filter->close = archive_write_client_close;
 +
 +	ret = __archive_write_open_filter(a->filter_first);
 +	if (ret < ARCHIVE_WARN) {
 +		r1 = __archive_write_close_filter(a->filter_first);
 +		return (r1 < ret ? r1 : ret);
 +	}
 +
 +	a->archive.state = ARCHIVE_STATE_HEADER;
 +	if (a->format_init)
 +		ret = (a->format_init)(a);
 +	return (ret);
 +}
 +
 +/*
 + * Close out the archive.
 + */
 +static int
 +_archive_write_close(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
 +
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL,
 +	    "archive_write_close");
 +	if (a->archive.state == ARCHIVE_STATE_NEW
 +	    || a->archive.state == ARCHIVE_STATE_CLOSED)
 +		return (ARCHIVE_OK); /* Okay to close() when not open. */
 +
 +	archive_clear_error(&a->archive);
 +
 +	/* Finish the last entry. */
 +	if (a->archive.state == ARCHIVE_STATE_DATA)
 +		r = ((a->format_finish_entry)(a));
 +
 +	/* Finish off the archive. */
 +	/* TODO: have format closers invoke compression close. */
 +	if (a->format_close != NULL) {
 +		r1 = (a->format_close)(a);
 +		if (r1 < r)
 +			r = r1;
 +	}
 +
 +	/* Finish the compression and close the stream. */
 +	r1 = __archive_write_close_filter(a->filter_first);
 +	if (r1 < r)
 +		r = r1;
 +
 +	if (a->archive.state != ARCHIVE_STATE_FATAL)
 +		a->archive.state = ARCHIVE_STATE_CLOSED;
 +	return (r);
 +}
 +
 +static int
 +_archive_write_filter_count(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct archive_write_filter *p = a->filter_first;
 +	int count = 0;
 +	while(p) {
 +		count++;
 +		p = p->next_filter;
 +	}
 +	return count;
 +}
 +
 +void
 +__archive_write_filters_free(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	int r = ARCHIVE_OK, r1;
 +
 +	while (a->filter_first != NULL) {
 +		struct archive_write_filter *next
 +		    = a->filter_first->next_filter;
 +		if (a->filter_first->free != NULL) {
 +			r1 = (*a->filter_first->free)(a->filter_first);
 +			if (r > r1)
 +				r = r1;
 +		}
 +		free(a->filter_first);
 +		a->filter_first = next;
 +	}
 +	a->filter_last = NULL;
 +}
 +
 +/*
 + * Destroy the archive structure.
 + *
 + * Be careful: user might just call write_new and then write_free.
 + * Don't assume we actually wrote anything or performed any non-trivial
 + * initialization.
 + */
 +static int
 +_archive_write_free(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	int r = ARCHIVE_OK, r1;
 +
 +	if (_a == NULL)
 +		return (ARCHIVE_OK);
 +	/* It is okay to call free() in state FATAL. */
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_free");
 +	if (a->archive.state != ARCHIVE_STATE_FATAL)
 +		r = archive_write_close(&a->archive);
 +
 +	/* Release format resources. */
 +	if (a->format_free != NULL) {
 +		r1 = (a->format_free)(a);
 +		if (r1 < r)
 +			r = r1;
 +	}
 +
 +	__archive_write_filters_free(_a);
 +
 +	/* Release various dynamic buffers. */
 +	free((void *)(uintptr_t)(const void *)a->nulls);
 +	archive_string_free(&a->archive.error_string);
 +	a->archive.magic = 0;
 +	__archive_clean(&a->archive);
 +	free(a);
 +	return (r);
 +}
 +
 +/*
 + * Write the appropriate header.
 + */
 +static int
 +_archive_write_header(struct archive *_a, struct archive_entry *entry)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	int ret, r2;
 +
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_DATA | ARCHIVE_STATE_HEADER, "archive_write_header");
 +	archive_clear_error(&a->archive);
 +
 +	if (a->format_write_header == NULL) {
 +		archive_set_error(&(a->archive), -1,
 +		    "Format must be set before you can write to an archive.");
 +		a->archive.state = ARCHIVE_STATE_FATAL;
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* In particular, "retry" and "fatal" get returned immediately. */
 +	ret = archive_write_finish_entry(&a->archive);
 +	if (ret == ARCHIVE_FATAL) {
 +		a->archive.state = ARCHIVE_STATE_FATAL;
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (ret < ARCHIVE_OK && ret != ARCHIVE_WARN)
 +		return (ret);
 +
 +	if (a->skip_file_set &&
 +	    archive_entry_dev_is_set(entry) &&
 +	    archive_entry_ino_is_set(entry) &&
- 	    archive_entry_dev(entry) == a->skip_file_dev &&
++	    archive_entry_dev(entry) == (dev_t)a->skip_file_dev &&
 +	    archive_entry_ino64(entry) == a->skip_file_ino) {
 +		archive_set_error(&a->archive, 0,
 +		    "Can't add archive to itself");
 +		return (ARCHIVE_FAILED);
 +	}
 +
 +	/* Format and write header. */
 +	r2 = ((a->format_write_header)(a, entry));
 +	if (r2 == ARCHIVE_FATAL) {
 +		a->archive.state = ARCHIVE_STATE_FATAL;
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (r2 < ret)
 +		ret = r2;
 +
 +	a->archive.state = ARCHIVE_STATE_DATA;
 +	return (ret);
 +}
 +
 +static int
 +_archive_write_finish_entry(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	int ret = ARCHIVE_OK;
 +
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
 +	    "archive_write_finish_entry");
 +	if (a->archive.state & ARCHIVE_STATE_DATA)
 +		ret = (a->format_finish_entry)(a);
 +	a->archive.state = ARCHIVE_STATE_HEADER;
 +	return (ret);
 +}
 +
 +/*
 + * Note that the compressor is responsible for blocking.
 + */
 +static ssize_t
 +_archive_write_data(struct archive *_a, const void *buff, size_t s)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_DATA, "archive_write_data");
 +	archive_clear_error(&a->archive);
 +	return ((a->format_write_data)(a, buff, s));
 +}
 +
 +static struct archive_write_filter *
 +filter_lookup(struct archive *_a, int n)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct archive_write_filter *f = a->filter_first;
 +	if (n == -1)
 +		return a->filter_last;
 +	if (n < 0)
 +		return NULL;
 +	while (n > 0 && f != NULL) {
 +		f = f->next_filter;
 +		--n;
 +	}
 +	return f;
 +}
 +
 +static int
 +_archive_filter_code(struct archive *_a, int n)
 +{
 +	struct archive_write_filter *f = filter_lookup(_a, n);
 +	return f == NULL ? -1 : f->code;
 +}
 +
 +static const char *
 +_archive_filter_name(struct archive *_a, int n)
 +{
 +	struct archive_write_filter *f = filter_lookup(_a, n);
 +	return f != NULL ? f->name : NULL;
 +}
 +
 +static int64_t
 +_archive_filter_bytes(struct archive *_a, int n)
 +{
 +	struct archive_write_filter *f = filter_lookup(_a, n);
 +	return f == NULL ? -1 : f->bytes_written;
 +}
diff --cc Utilities/cmlibarchive/libarchive/archive_write_add_filter_b64encode.c
index 0000000,85eb087..85eb087
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_b64encode.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_b64encode.c
diff --cc Utilities/cmlibarchive/libarchive/archive_write_add_filter_bzip2.c
index 096a6a4,0000000..6526f51
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_bzip2.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_bzip2.c
@@@ -1,335 -1,0 +1,407 @@@
 +/*-
 + * Copyright (c) 2003-2007 Tim Kientzle
++ * Copyright (c) 2012 Michihiro NAKAJIMA
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "archive_platform.h"
 +
 +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_bzip2.c 201091 2009-12-28 02:22:41Z kientzle $");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#include <stdio.h>
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#ifdef HAVE_BZLIB_H
 +#include <cm_bzlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_private.h"
 +#include "archive_write_private.h"
 +
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +int
 +archive_write_set_compression_bzip2(struct archive *a)
 +{
 +	__archive_write_filters_free(a);
 +	return (archive_write_add_filter_bzip2(a));
 +}
 +#endif
 +
- #if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
- int
- archive_write_add_filter_bzip2(struct archive *a)
- {
- 	archive_set_error(a, ARCHIVE_ERRNO_MISC,
- 	    "bzip2 compression not supported on this platform");
- 	return (ARCHIVE_FATAL);
- }
- #else
- /* Don't compile this if we don't have bzlib. */
- 
 +struct private_data {
 +	int		 compression_level;
++#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	bz_stream	 stream;
 +	int64_t		 total_in;
 +	char		*compressed;
 +	size_t		 compressed_buffer_size;
++#else
++	struct archive_write_program_data *pdata;
++#endif
 +};
 +
- /*
-  * Yuck.  bzlib.h is not const-correct, so I need this one bit
-  * of ugly hackery to convert a const * pointer to a non-const pointer.
-  */
- #define	SET_NEXT_IN(st,src)					\
- 	(st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
- 
 +static int archive_compressor_bzip2_close(struct archive_write_filter *);
 +static int archive_compressor_bzip2_free(struct archive_write_filter *);
 +static int archive_compressor_bzip2_open(struct archive_write_filter *);
 +static int archive_compressor_bzip2_options(struct archive_write_filter *,
 +		    const char *, const char *);
 +static int archive_compressor_bzip2_write(struct archive_write_filter *,
 +		    const void *, size_t);
- static int drive_compressor(struct archive_write_filter *,
- 		    struct private_data *, int finishing);
 +
 +/*
 + * Add a bzip2 compression filter to this write handle.
 + */
 +int
 +archive_write_add_filter_bzip2(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct archive_write_filter *f = __archive_write_allocate_filter(_a);
 +	struct private_data *data;
 +
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_add_filter_bzip2");
 +
 +	data = calloc(1, sizeof(*data));
 +	if (data == NULL) {
 +		archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	data->compression_level = 9; /* default */
 +
 +	f->data = data;
 +	f->options = &archive_compressor_bzip2_options;
 +	f->close = &archive_compressor_bzip2_close;
 +	f->free = &archive_compressor_bzip2_free;
 +	f->open = &archive_compressor_bzip2_open;
- 	f->code = ARCHIVE_COMPRESSION_BZIP2;
++	f->code = ARCHIVE_FILTER_BZIP2;
 +	f->name = "bzip2";
++#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	return (ARCHIVE_OK);
++#else
++	data->pdata = __archive_write_program_allocate();
++	if (data->pdata == NULL) {
++		free(data);
++		archive_set_error(&a->archive, ENOMEM, "Out of memory");
++		return (ARCHIVE_FATAL);
++	}
++	data->compression_level = 0;
++	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++	    "Using external bzip2 program");
++	return (ARCHIVE_WARN);
++#endif
++}
++
++/*
++ * Set write options.
++ */
++static int
++archive_compressor_bzip2_options(struct archive_write_filter *f,
++    const char *key, const char *value)
++{
++	struct private_data *data = (struct private_data *)f->data;
++
++	if (strcmp(key, "compression-level") == 0) {
++		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
++		    value[1] != '\0')
++			return (ARCHIVE_WARN);
++		data->compression_level = value[0] - '0';
++		/* Make '0' be a synonym for '1'. */
++		/* This way, bzip2 compressor supports the same 0..9
++		 * range of levels as gzip. */
++		if (data->compression_level < 1)
++			data->compression_level = 1;
++		return (ARCHIVE_OK);
++	}
++
++	/* Note: The "warn" return is just to inform the options
++	 * supervisor that we didn't handle it.  It will generate
++	 * a suitable error if no one used this option. */
++	return (ARCHIVE_WARN);
 +}
 +
++#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
++/* Don't compile this if we don't have bzlib. */
++
++/*
++ * Yuck.  bzlib.h is not const-correct, so I need this one bit
++ * of ugly hackery to convert a const * pointer to a non-const pointer.
++ */
++#define	SET_NEXT_IN(st,src)					\
++	(st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
++static int drive_compressor(struct archive_write_filter *,
++		    struct private_data *, int finishing);
++
 +/*
 + * Setup callback.
 + */
 +static int
 +archive_compressor_bzip2_open(struct archive_write_filter *f)
 +{
 +	struct private_data *data = (struct private_data *)f->data;
 +	int ret;
 +
 +	ret = __archive_write_open_filter(f->next_filter);
 +	if (ret != 0)
 +		return (ret);
 +
- 	/* TODO: Find a better way to size this.  (Maybe look at the */
- 	/* block size expected by the following filter?) */
 +	if (data->compressed == NULL) {
- 		data->compressed_buffer_size = 65536;
++		size_t bs = 65536, bpb;
++		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
++			/* Buffer size should be a multiple number of the of bytes
++			 * per block for performance. */
++			bpb = archive_write_get_bytes_per_block(f->archive);
++			if (bpb > bs)
++				bs = bpb;
++			else if (bpb != 0)
++				bs -= bs % bpb;
++		}
++		data->compressed_buffer_size = bs;
 +		data->compressed
 +		    = (char *)malloc(data->compressed_buffer_size);
 +		if (data->compressed == NULL) {
 +			archive_set_error(f->archive, ENOMEM,
 +			    "Can't allocate data for compression buffer");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	memset(&data->stream, 0, sizeof(data->stream));
 +	data->stream.next_out = data->compressed;
 +	data->stream.avail_out = data->compressed_buffer_size;
 +	f->write = archive_compressor_bzip2_write;
 +
 +	/* Initialize compression library */
 +	ret = BZ2_bzCompressInit(&(data->stream),
 +	    data->compression_level, 0, 30);
 +	if (ret == BZ_OK) {
 +		f->data = data;
 +		return (ARCHIVE_OK);
 +	}
 +
 +	/* Library setup failed: clean up. */
 +	archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 +	    "Internal error initializing compression library");
 +
 +	/* Override the error message if we know what really went wrong. */
 +	switch (ret) {
 +	case BZ_PARAM_ERROR:
 +		archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    "invalid setup parameter");
 +		break;
 +	case BZ_MEM_ERROR:
 +		archive_set_error(f->archive, ENOMEM,
 +		    "Internal error initializing compression library: "
 +		    "out of memory");
 +		break;
 +	case BZ_CONFIG_ERROR:
 +		archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    "mis-compiled library");
 +		break;
 +	}
 +
 +	return (ARCHIVE_FATAL);
 +
 +}
 +
 +/*
-  * Set write options.
-  */
- static int
- archive_compressor_bzip2_options(struct archive_write_filter *f,
-     const char *key, const char *value)
- {
- 	struct private_data *data = (struct private_data *)f->data;
- 
- 	if (strcmp(key, "compression-level") == 0) {
- 		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
- 		    value[1] != '\0')
- 			return (ARCHIVE_WARN);
- 		data->compression_level = value[0] - '0';
- 		/* Make '0' be a synonym for '1'. */
- 		/* This way, bzip2 compressor supports the same 0..9
- 		 * range of levels as gzip. */
- 		if (data->compression_level < 1)
- 			data->compression_level = 1;
- 		return (ARCHIVE_OK);
- 	}
- 
- 	return (ARCHIVE_WARN);
- }
- 
- /*
 + * Write data to the compressed stream.
 + *
 + * Returns ARCHIVE_OK if all data written, error otherwise.
 + */
 +static int
 +archive_compressor_bzip2_write(struct archive_write_filter *f,
 +    const void *buff, size_t length)
 +{
 +	struct private_data *data = (struct private_data *)f->data;
 +
 +	/* Update statistics */
 +	data->total_in += length;
 +
 +	/* Compress input data to output buffer */
 +	SET_NEXT_IN(data, buff);
 +	data->stream.avail_in = length;
 +	if (drive_compressor(f, data, 0))
 +		return (ARCHIVE_FATAL);
 +	return (ARCHIVE_OK);
 +}
 +
 +
 +/*
 + * Finish the compression.
 + */
 +static int
 +archive_compressor_bzip2_close(struct archive_write_filter *f)
 +{
 +	struct private_data *data = (struct private_data *)f->data;
 +	int ret, r1;
 +
 +	/* Finish compression cycle. */
 +	ret = drive_compressor(f, data, 1);
 +	if (ret == ARCHIVE_OK) {
 +		/* Write the last block */
 +		ret = __archive_write_filter(f->next_filter,
 +		    data->compressed,
 +		    data->compressed_buffer_size - data->stream.avail_out);
 +	}
 +
 +	switch (BZ2_bzCompressEnd(&(data->stream))) {
 +	case BZ_OK:
 +		break;
 +	default:
 +		archive_set_error(f->archive, ARCHIVE_ERRNO_PROGRAMMER,
 +		    "Failed to clean up compressor");
 +		ret = ARCHIVE_FATAL;
 +	}
 +
 +	r1 = __archive_write_close_filter(f->next_filter);
 +	return (r1 < ret ? r1 : ret);
 +}
 +
 +static int
 +archive_compressor_bzip2_free(struct archive_write_filter *f)
 +{
 +	struct private_data *data = (struct private_data *)f->data;
 +	free(data->compressed);
 +	free(data);
 +	f->data = NULL;
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Utility function to push input data through compressor, writing
 + * full output blocks as necessary.
 + *
 + * Note that this handles both the regular write case (finishing ==
 + * false) and the end-of-archive case (finishing == true).
 + */
 +static int
 +drive_compressor(struct archive_write_filter *f,
 +    struct private_data *data, int finishing)
 +{
 +	int ret;
 +
 +	for (;;) {
 +		if (data->stream.avail_out == 0) {
 +			ret = __archive_write_filter(f->next_filter,
 +			    data->compressed,
 +			    data->compressed_buffer_size);
 +			if (ret != ARCHIVE_OK) {
 +				/* TODO: Handle this write failure */
 +				return (ARCHIVE_FATAL);
 +			}
 +			data->stream.next_out = data->compressed;
 +			data->stream.avail_out = data->compressed_buffer_size;
 +		}
 +
 +		/* If there's nothing to do, we're done. */
 +		if (!finishing && data->stream.avail_in == 0)
 +			return (ARCHIVE_OK);
 +
 +		ret = BZ2_bzCompress(&(data->stream),
 +		    finishing ? BZ_FINISH : BZ_RUN);
 +
 +		switch (ret) {
 +		case BZ_RUN_OK:
 +			/* In non-finishing case, did compressor
 +			 * consume everything? */
 +			if (!finishing && data->stream.avail_in == 0)
 +				return (ARCHIVE_OK);
 +			break;
 +		case BZ_FINISH_OK:  /* Finishing: There's more work to do */
 +			break;
 +		case BZ_STREAM_END: /* Finishing: all done */
 +			/* Only occurs in finishing case */
 +			return (ARCHIVE_OK);
 +		default:
 +			/* Any other return value indicates an error */
 +			archive_set_error(f->archive,
 +			    ARCHIVE_ERRNO_PROGRAMMER,
 +			    "Bzip2 compression failed;"
 +			    " BZ2_bzCompress() returned %d",
 +			    ret);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +}
 +
++#else /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
++
++static int
++archive_compressor_bzip2_open(struct archive_write_filter *f)
++{
++	struct private_data *data = (struct private_data *)f->data;
++	struct archive_string as;
++	int r;
++
++	archive_string_init(&as);
++	archive_strcpy(&as, "bzip2");
++
++	/* Specify compression level. */
++	if (data->compression_level > 0) {
++		archive_strcat(&as, " -");
++		archive_strappend_char(&as, '0' + data->compression_level);
++	}
++	f->write = archive_compressor_bzip2_write;
++
++	r = __archive_write_program_open(f, data->pdata, as.s);
++	archive_string_free(&as);
++	return (r);
++}
++
++static int
++archive_compressor_bzip2_write(struct archive_write_filter *f, const void *buff,
++    size_t length)
++{
++	struct private_data *data = (struct private_data *)f->data;
++
++	return __archive_write_program_write(f, data->pdata, buff, length);
++}
++
++static int
++archive_compressor_bzip2_close(struct archive_write_filter *f)
++{
++	struct private_data *data = (struct private_data *)f->data;
++
++	return __archive_write_program_close(f, data->pdata);
++}
++
++static int
++archive_compressor_bzip2_free(struct archive_write_filter *f)
++{
++	struct private_data *data = (struct private_data *)f->data;
++
++	__archive_write_program_free(data->pdata);
++	free(data);
++	return (ARCHIVE_OK);
++}
++
 +#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
diff --cc Utilities/cmlibarchive/libarchive/archive_write_add_filter_grzip.c
index 0000000,8dc287e..8dc287e
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_grzip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_grzip.c
diff --cc Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c
index d08ee26,0000000..db18fd9
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c
@@@ -1,356 -1,0 +1,442 @@@
 +/*-
 + * Copyright (c) 2003-2007 Tim Kientzle
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "archive_platform.h"
 +
 +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_gzip.c 201081 2009-12-28 02:04:42Z kientzle $");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#include <time.h>
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_private.h"
++#include "archive_string.h"
 +#include "archive_write_private.h"
 +
 +#if ARCHIVE_VERSION_NUMBER < 4000000
 +int
 +archive_write_set_compression_gzip(struct archive *a)
 +{
 +	__archive_write_filters_free(a);
 +	return (archive_write_add_filter_gzip(a));
 +}
 +#endif
 +
- #ifndef HAVE_ZLIB_H
- int
- archive_write_add_filter_gzip(struct archive *a)
- {
- 	archive_set_error(a, ARCHIVE_ERRNO_MISC,
- 	    "gzip compression not supported on this platform");
- 	return (ARCHIVE_FATAL);
- }
- #else
 +/* Don't compile this if we don't have zlib. */
 +
 +struct private_data {
 +	int		 compression_level;
++	int		 timestamp;
++#ifdef HAVE_ZLIB_H
 +	z_stream	 stream;
 +	int64_t		 total_in;
 +	unsigned char	*compressed;
 +	size_t		 compressed_buffer_size;
 +	unsigned long	 crc;
++#else
++	struct archive_write_program_data *pdata;
++#endif
 +};
 +
 +/*
 + * Yuck.  zlib.h is not const-correct, so I need this one bit
 + * of ugly hackery to convert a const * pointer to a non-const pointer.
 + */
 +#define	SET_NEXT_IN(st,src)					\
 +	(st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src)
 +
 +static int archive_compressor_gzip_options(struct archive_write_filter *,
 +		    const char *, const char *);
 +static int archive_compressor_gzip_open(struct archive_write_filter *);
 +static int archive_compressor_gzip_write(struct archive_write_filter *,
 +		    const void *, size_t);
 +static int archive_compressor_gzip_close(struct archive_write_filter *);
 +static int archive_compressor_gzip_free(struct archive_write_filter *);
++#ifdef HAVE_ZLIB_H
 +static int drive_compressor(struct archive_write_filter *,
 +		    struct private_data *, int finishing);
++#endif
 +
 +
 +/*
 + * Add a gzip compression filter to this write handle.
 + */
 +int
 +archive_write_add_filter_gzip(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct archive_write_filter *f = __archive_write_allocate_filter(_a);
 +	struct private_data *data;
 +	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_add_filter_gzip");
 +
 +	data = calloc(1, sizeof(*data));
 +	if (data == NULL) {
 +		archive_set_error(&a->archive, ENOMEM, "Out of memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	f->data = data;
- 	data->compression_level = Z_DEFAULT_COMPRESSION;
 +	f->open = &archive_compressor_gzip_open;
 +	f->options = &archive_compressor_gzip_options;
 +	f->close = &archive_compressor_gzip_close;
 +	f->free = &archive_compressor_gzip_free;
- 	f->code = ARCHIVE_COMPRESSION_GZIP;
++	f->code = ARCHIVE_FILTER_GZIP;
 +	f->name = "gzip";
++#ifdef HAVE_ZLIB_H
++	data->compression_level = Z_DEFAULT_COMPRESSION;
 +	return (ARCHIVE_OK);
++#else
++	data->pdata = __archive_write_program_allocate();
++	if (data->pdata == NULL) {
++		free(data);
++		archive_set_error(&a->archive, ENOMEM, "Out of memory");
++		return (ARCHIVE_FATAL);
++	}
++	data->compression_level = 0;
++	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++	    "Using external gzip program");
++	return (ARCHIVE_WARN);
++#endif
 +}
 +
++static int
++archive_compressor_gzip_free(struct archive_write_filter *f)
++{
++	struct private_data *data = (struct private_data *)f->data;
++
++#ifdef HAVE_ZLIB_H
++	free(data->compressed);
++#else
++	__archive_write_program_free(data->pdata);
++#endif
++	free(data);
++	f->data = NULL;
++	return (ARCHIVE_OK);
++}
++
++/*
++ * Set write options.
++ */
++static int
++archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
++    const char *value)
++{
++	struct private_data *data = (struct private_data *)f->data;
++
++	if (strcmp(key, "compression-level") == 0) {
++		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
++		    value[1] != '\0')
++			return (ARCHIVE_WARN);
++		data->compression_level = value[0] - '0';
++		return (ARCHIVE_OK);
++	}
++	if (strcmp(key, "timestamp") == 0) {
++		data->timestamp = (value == NULL)?-1:1;
++		return (ARCHIVE_OK);
++	}
++
++	/* Note: The "warn" return is just to inform the options
++	 * supervisor that we didn't handle it.  It will generate
++	 * a suitable error if no one used this option. */
++	return (ARCHIVE_WARN);
++}
++
++#ifdef HAVE_ZLIB_H
 +/*
 + * Setup callback.
 + */
 +static int
 +archive_compressor_gzip_open(struct archive_write_filter *f)
 +{
 +	struct private_data *data = (struct private_data *)f->data;
 +	int ret;
- 	time_t t;
 +
 +	ret = __archive_write_open_filter(f->next_filter);
 +	if (ret != ARCHIVE_OK)
 +		return (ret);
 +
 +	if (data->compressed == NULL) {
- 		data->compressed_buffer_size = 65536;
++		size_t bs = 65536, bpb;
++		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
++			/* Buffer size should be a multiple number of
++			 * the of bytes per block for performance. */
++			bpb = archive_write_get_bytes_per_block(f->archive);
++			if (bpb > bs)
++				bs = bpb;
++			else if (bpb != 0)
++				bs -= bs % bpb;
++		}
++		data->compressed_buffer_size = bs;
 +		data->compressed
 +		    = (unsigned char *)malloc(data->compressed_buffer_size);
 +		if (data->compressed == NULL) {
 +			archive_set_error(f->archive, ENOMEM,
 +			    "Can't allocate data for compression buffer");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	data->crc = crc32(0L, NULL, 0);
 +	data->stream.next_out = data->compressed;
- 	data->stream.avail_out = data->compressed_buffer_size;
++	data->stream.avail_out = (uInt)data->compressed_buffer_size;
 +
 +	/* Prime output buffer with a gzip header. */
- 	t = time(NULL);
 +	data->compressed[0] = 0x1f; /* GZip signature bytes */
 +	data->compressed[1] = 0x8b;
 +	data->compressed[2] = 0x08; /* "Deflate" compression */
 +	data->compressed[3] = 0; /* No options */
- 	data->compressed[4] = (t)&0xff;  /* Timestamp */
- 	data->compressed[5] = (t>>8)&0xff;
- 	data->compressed[6] = (t>>16)&0xff;
- 	data->compressed[7] = (t>>24)&0xff;
++	if (data->timestamp >= 0) {
++		time_t t = time(NULL);
++		data->compressed[4] = (uint8_t)(t)&0xff;  /* Timestamp */
++		data->compressed[5] = (uint8_t)(t>>8)&0xff;
++		data->compressed[6] = (uint8_t)(t>>16)&0xff;
++		data->compressed[7] = (uint8_t)(t>>24)&0xff;
++	} else
++		memset(&data->compressed[4], 0, 4);
 +	data->compressed[8] = 0; /* No deflate options */
 +	data->compressed[9] = 3; /* OS=Unix */
 +	data->stream.next_out += 10;
 +	data->stream.avail_out -= 10;
 +
 +	f->write = archive_compressor_gzip_write;
 +
 +	/* Initialize compression library. */
 +	ret = deflateInit2(&(data->stream),
 +	    data->compression_level,
 +	    Z_DEFLATED,
 +	    -15 /* < 0 to suppress zlib header */,
 +	    8,
 +	    Z_DEFAULT_STRATEGY);
 +
 +	if (ret == Z_OK) {
 +		f->data = data;
 +		return (ARCHIVE_OK);
 +	}
 +
 +	/* Library setup failed: clean up. */
 +	archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Internal error "
 +	    "initializing compression library");
 +
 +	/* Override the error message if we know what really went wrong. */
 +	switch (ret) {
 +	case Z_STREAM_ERROR:
 +		archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing "
 +		    "compression library: invalid setup parameter");
 +		break;
 +	case Z_MEM_ERROR:
- 		archive_set_error(f->archive, ENOMEM, "Internal error initializing "
- 		    "compression library");
++		archive_set_error(f->archive, ENOMEM,
++		    "Internal error initializing compression library");
 +		break;
 +	case Z_VERSION_ERROR:
 +		archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing "
 +		    "compression library: invalid library version");
 +		break;
 +	}
 +
 +	return (ARCHIVE_FATAL);
 +}
 +
 +/*
-  * Set write options.
-  */
- static int
- archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
-     const char *value)
- {
- 	struct private_data *data = (struct private_data *)f->data;
- 
- 	if (strcmp(key, "compression-level") == 0) {
- 		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
- 		    value[1] != '\0')
- 			return (ARCHIVE_WARN);
- 		data->compression_level = value[0] - '0';
- 		return (ARCHIVE_OK);
- 	}
- 	return (ARCHIVE_WARN);
- }
- 
- /*
 + * Write data to the compressed stream.
 + */
 +static int
 +archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
 +    size_t length)
 +{
 +	struct private_data *data = (struct private_data *)f->data;
 +	int ret;
 +
 +	/* Update statistics */
- 	data->crc = crc32(data->crc, (const Bytef *)buff, length);
++	data->crc = crc32(data->crc, (const Bytef *)buff, (uInt)length);
 +	data->total_in += length;
 +
 +	/* Compress input data to output buffer */
 +	SET_NEXT_IN(data, buff);
- 	data->stream.avail_in = length;
++	data->stream.avail_in = (uInt)length;
 +	if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)
 +		return (ret);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Finish the compression...
 + */
 +static int
 +archive_compressor_gzip_close(struct archive_write_filter *f)
 +{
 +	unsigned char trailer[8];
 +	struct private_data *data = (struct private_data *)f->data;
 +	int ret, r1;
 +
 +	/* Finish compression cycle */
 +	ret = drive_compressor(f, data, 1);
 +	if (ret == ARCHIVE_OK) {
 +		/* Write the last compressed data. */
 +		ret = __archive_write_filter(f->next_filter,
 +		    data->compressed,
 +		    data->compressed_buffer_size - data->stream.avail_out);
 +	}
 +	if (ret == ARCHIVE_OK) {
 +		/* Build and write out 8-byte trailer. */
- 		trailer[0] = (data->crc)&0xff;
- 		trailer[1] = (data->crc >> 8)&0xff;
- 		trailer[2] = (data->crc >> 16)&0xff;
- 		trailer[3] = (data->crc >> 24)&0xff;
- 		trailer[4] = (data->total_in)&0xff;
- 		trailer[5] = (data->total_in >> 8)&0xff;
- 		trailer[6] = (data->total_in >> 16)&0xff;
- 		trailer[7] = (data->total_in >> 24)&0xff;
++		trailer[0] = (uint8_t)(data->crc)&0xff;
++		trailer[1] = (uint8_t)(data->crc >> 8)&0xff;
++		trailer[2] = (uint8_t)(data->crc >> 16)&0xff;
++		trailer[3] = (uint8_t)(data->crc >> 24)&0xff;
++		trailer[4] = (uint8_t)(data->total_in)&0xff;
++		trailer[5] = (uint8_t)(data->total_in >> 8)&0xff;
++		trailer[6] = (uint8_t)(data->total_in >> 16)&0xff;
++		trailer[7] = (uint8_t)(data->total_in >> 24)&0xff;
 +		ret = __archive_write_filter(f->next_filter, trailer, 8);
 +	}
 +
 +	switch (deflateEnd(&(data->stream))) {
 +	case Z_OK:
 +		break;
 +	default:
 +		archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		ret = ARCHIVE_FATAL;
 +	}
 +	r1 = __archive_write_close_filter(f->next_filter);
 +	return (r1 < ret ? r1 : ret);
 +}
 +
- static int
- archive_compressor_gzip_free(struct archive_write_filter *f)
- {
- 	struct private_data *data = (struct private_data *)f->data;
- 	free(data->compressed);
- 	free(data);
- 	f->data = NULL;
- 	return (ARCHIVE_OK);
- }
- 
 +/*
 + * Utility function to push input data through compressor,
 + * writing full output blocks as necessary.
 + *
 + * Note that this handles both the regular write case (finishing ==
 + * false) and the end-of-archive case (finishing == true).
 + */
 +static int
 +drive_compressor(struct archive_write_filter *f,
 +    struct private_data *data, int finishing)
 +{
 +	int ret;
 +
 +	for (;;) {
 +		if (data->stream.avail_out == 0) {
 +			ret = __archive_write_filter(f->next_filter,
 +			    data->compressed,
 +			    data->compressed_buffer_size);
 +			if (ret != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			data->stream.next_out = data->compressed;
- 			data->stream.avail_out = data->compressed_buffer_size;
++			data->stream.avail_out =
++			    (uInt)data->compressed_buffer_size;
 +		}
 +
 +		/* If there's nothing to do, we're done. */
 +		if (!finishing && data->stream.avail_in == 0)
 +			return (ARCHIVE_OK);
 +
 +		ret = deflate(&(data->stream),
 +		    finishing ? Z_FINISH : Z_NO_FLUSH );
 +
 +		switch (ret) {
 +		case Z_OK:
 +			/* In non-finishing case, check if compressor
 +			 * consumed everything */
 +			if (!finishing && data->stream.avail_in == 0)
 +				return (ARCHIVE_OK);
 +			/* In finishing case, this return always means
 +			 * there's more work */
 +			break;
 +		case Z_STREAM_END:
 +			/* This return can only occur in finishing case. */
 +			return (ARCHIVE_OK);
 +		default:
 +			/* Any other return value indicates an error. */
 +			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
 +			    "GZip compression failed:"
 +			    " deflate() call returned status %d",
 +			    ret);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +}
 +
++#else /* HAVE_ZLIB_H */
++
++static int
++archive_compressor_gzip_open(struct archive_write_filter *f)
++{
++	struct private_data *data = (struct private_data *)f->data;
++	struct archive_string as;
++	int r;
++
++	archive_string_init(&as);
++	archive_strcpy(&as, "gzip");
++
++	/* Specify compression level. */
++	if (data->compression_level > 0) {
++		archive_strcat(&as, " -");
++		archive_strappend_char(&as, '0' + data->compression_level);
++	}
++	if (data->timestamp < 0)
++		/* Do not save timestamp. */
++		archive_strcat(&as, " -n");
++	else if (data->timestamp > 0)
++		/* Save timestamp. */
++		archive_strcat(&as, " -N");
++
++	f->write = archive_compressor_gzip_write;
++	r = __archive_write_program_open(f, data->pdata, as.s);
++	archive_string_free(&as);
++	return (r);
++}
++
++static int
++archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
++    size_t length)
++{
++	struct private_data *data = (struct private_data *)f->data;
++
++	return __archive_write_program_write(f, data->pdata, buff, length);
++}
++
++static int
++archive_compressor_gzip_close(struct archive_write_filter *f)
++{
++	struct private_data *data = (struct private_data *)f->data;
++
++	return __archive_write_program_close(f, data->pdata);
++}
++
 +#endif /* HAVE_ZLIB_H */
diff --cc Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c
index 0000000,85fdf6a..85fdf6a
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c
diff --cc Utilities/cmlibarchive/libarchive/archive_write_add_filter_lzop.c
index 0000000,088ecea..088ecea
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lzop.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lzop.c
diff --cc Utilities/cmlibarchive/libarchive/archive_write_add_filter_uuencode.c
index 0000000,23d9c15..23d9c15
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_uuencode.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_uuencode.c
diff --cc Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c
index 0000000,9797203..9797203
mode 000000,100644..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c
diff --cc Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
index b6589dd,0000000..4f1bc26
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
@@@ -1,2303 -1,0 +1,2324 @@@
 +/*-
-  * Copyright (c) 2011 Michihiro NAKAJIMA
++ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD$");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#include <stdlib.h>
 +#ifdef HAVE_BZLIB_H
 +#include <cm_bzlib.h>
 +#endif
 +#if HAVE_LZMA_H
 +#include <lzma.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#ifndef HAVE_ZLIB_H
 +#include "archive_crc32.h"
 +#endif
 +#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_ppmd7_private.h"
 +#include "archive_private.h"
 +#include "archive_rb.h"
 +#include "archive_string.h"
 +#include "archive_write_private.h"
 +
 +/*
 + * Codec ID
 + */
 +#define _7Z_COPY	0
 +#define _7Z_LZMA1	0x030101
 +#define _7Z_LZMA2	0x21
 +#define _7Z_DEFLATE	0x040108
 +#define _7Z_BZIP2	0x040202
 +#define _7Z_PPMD	0x030401
 +
 +/*
 + * 7-Zip header property IDs.
 + */
 +#define kEnd			0x00
 +#define kHeader			0x01
 +#define kArchiveProperties	0x02
 +#define kAdditionalStreamsInfo	0x03
 +#define kMainStreamsInfo	0x04
 +#define kFilesInfo		0x05
 +#define kPackInfo		0x06
 +#define kUnPackInfo		0x07
 +#define kSubStreamsInfo		0x08
 +#define kSize			0x09
 +#define kCRC			0x0A
 +#define kFolder			0x0B
 +#define kCodersUnPackSize	0x0C
 +#define kNumUnPackStream	0x0D
 +#define kEmptyStream		0x0E
 +#define kEmptyFile		0x0F
 +#define kAnti			0x10
 +#define kName			0x11
 +#define kCTime			0x12
 +#define kATime			0x13
 +#define kMTime			0x14
 +#define kAttributes		0x15
 +#define kEncodedHeader		0x17
 +
 +enum la_zaction {
 +	ARCHIVE_Z_FINISH,
 +	ARCHIVE_Z_RUN
 +};
 +
 +/*
 + * A stream object of universal compressor.
 + */
 +struct la_zstream {
 +	const uint8_t		*next_in;
 +	size_t			 avail_in;
 +	uint64_t		 total_in;
 +
 +	uint8_t			*next_out;
 +	size_t			 avail_out;
 +	uint64_t		 total_out;
 +
 +	uint32_t		 prop_size;
 +	uint8_t			*props;
 +
 +	int			 valid;
 +	void			*real_stream;
 +	int			 (*code) (struct archive *a,
 +				    struct la_zstream *lastrm,
 +				    enum la_zaction action);
 +	int			 (*end)(struct archive *a,
 +				    struct la_zstream *lastrm);
 +};
 +
 +#define PPMD7_DEFAULT_ORDER	6
 +#define PPMD7_DEFAULT_MEM_SIZE	(1 << 24)
 +
 +struct ppmd_stream {
 +	int			 stat;
 +	CPpmd7			 ppmd7_context;
 +	CPpmd7z_RangeEnc	 range_enc;
 +	IByteOut		 byteout;
 +	uint8_t			*buff;
 +	uint8_t			*buff_ptr;
 +	uint8_t			*buff_end;
 +	size_t			 buff_bytes;
 +};
 +
 +struct coder {
 +	unsigned		 codec;
 +	size_t			 prop_size;
 +	uint8_t			*props;
 +};
 +
 +struct file {
 +	struct archive_rb_node	 rbnode;
 +
 +	struct file		*next;
 +	unsigned		 name_len;
 +	uint8_t			*utf16name;/* UTF16-LE name. */
 +	uint64_t		 size;
 +	unsigned		 flg;
 +#define MTIME_IS_SET	(1<<0)
 +#define ATIME_IS_SET	(1<<1)
 +#define CTIME_IS_SET	(1<<2)
 +#define CRC32_IS_SET	(1<<3)
 +#define HAS_STREAM	(1<<4)
 +
 +	struct {
 +		time_t		 time;
 +		long		 time_ns;
 +	}			 times[3];
 +#define MTIME 0
 +#define ATIME 1
 +#define CTIME 2
 +
 +	mode_t			 mode;
 +	uint32_t		 crc32;
 +
 +	int			 dir:1;
 +};
 +
 +struct _7zip {
 +	int			 temp_fd;
 +	uint64_t		 temp_offset;
 +
 +	struct file		*cur_file;
 +	size_t			 total_number_entry;
 +	size_t			 total_number_nonempty_entry;
 +	size_t			 total_number_empty_entry;
 +	size_t			 total_number_dir_entry;
 +	size_t			 total_bytes_entry_name;
 +	size_t			 total_number_time_defined[3];
 +	uint64_t		 total_bytes_compressed;
 +	uint64_t		 total_bytes_uncompressed;
 +	uint64_t		 entry_bytes_remaining;
 +	uint32_t		 entry_crc32;
 +	uint32_t		 precode_crc32;
 +	uint32_t		 encoded_crc32;
 +	int			 crc32flg;
 +#define	PRECODE_CRC32	1
 +#define	ENCODED_CRC32	2
 +
 +	unsigned		 opt_compression;
 +	int			 opt_compression_level;
 +
 +	struct la_zstream	 stream;
 +	struct coder		 coder;
 +
 +	struct archive_string_conv *sconv;
 +
 +	/*
 +	 * Compressed data buffer.
 +	 */
- 	unsigned char		 wbuff[1024 * 64];
++	unsigned char		 wbuff[512 * 20 * 6];
 +	size_t			 wbuff_remaining;
 +
 +	/*
 +	 * The list of the file entries which has its contents is used to
 +	 * manage struct file objects.
 +	 * We use 'next' a menber of struct file to chain.
 +	 */
 +	struct {
 +		struct file	*first;
 +		struct file	**last;
 +	}			 file_list, empty_list;
 +	struct archive_rb_tree	 rbtree;/* for empty files */
 +};
 +
 +static int	_7z_options(struct archive_write *,
 +		    const char *, const char *);
 +static int	_7z_write_header(struct archive_write *,
 +		    struct archive_entry *);
 +static ssize_t	_7z_write_data(struct archive_write *,
 +		    const void *, size_t);
 +static int	_7z_finish_entry(struct archive_write *);
 +static int	_7z_close(struct archive_write *);
 +static int	_7z_free(struct archive_write *);
 +static int	file_cmp_node(const struct archive_rb_node *,
 +		    const struct archive_rb_node *);
 +static int	file_cmp_key(const struct archive_rb_node *, const void *);
 +static int	file_new(struct archive_write *a, struct archive_entry *,
 +		    struct file **);
 +static void	file_free(struct file *);
 +static void	file_register(struct _7zip *, struct file *);
 +static void	file_register_empty(struct _7zip *, struct file *);
 +static void	file_init_register(struct _7zip *);
 +static void	file_init_register_empty(struct _7zip *);
 +static void	file_free_register(struct _7zip *);
 +static ssize_t	compress_out(struct archive_write *, const void *, size_t ,
 +		    enum la_zaction);
 +static int	compression_init_encoder_copy(struct archive *,
 +		    struct la_zstream *);
 +static int	compression_code_copy(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_copy(struct archive *, struct la_zstream *);
 +static int	compression_init_encoder_deflate(struct archive *,
 +		    struct la_zstream *, int, int);
 +#ifdef HAVE_ZLIB_H
 +static int	compression_code_deflate(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_deflate(struct archive *, struct la_zstream *);
 +#endif
 +static int	compression_init_encoder_bzip2(struct archive *,
 +		    struct la_zstream *, int);
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +static int	compression_code_bzip2(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_bzip2(struct archive *, struct la_zstream *);
 +#endif
 +static int	compression_init_encoder_lzma1(struct archive *,
 +		    struct la_zstream *, int);
 +static int	compression_init_encoder_lzma2(struct archive *,
 +		    struct la_zstream *, int);
 +#if defined(HAVE_LZMA_H)
 +static int	compression_code_lzma(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_lzma(struct archive *, struct la_zstream *);
 +#endif
 +static int	compression_init_encoder_ppmd(struct archive *,
 +		    struct la_zstream *, unsigned, uint32_t);
 +static int	compression_code_ppmd(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_ppmd(struct archive *, struct la_zstream *);
 +static int	_7z_compression_init_encoder(struct archive_write *, unsigned,
 +		    int);
 +static int	compression_code(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end(struct archive *,
 +		    struct la_zstream *);
 +static int	enc_uint64(struct archive_write *, uint64_t);
 +static int	make_header(struct archive_write *, uint64_t, uint64_t,
 +		    uint64_t, int, struct coder *);
 +static int	make_streamsInfo(struct archive_write *, uint64_t, uint64_t,
 +		    	uint64_t, int, struct coder *, int, uint32_t);
 +
 +int
 +archive_write_set_format_7zip(struct archive *_a)
 +{
 +	static const struct archive_rb_tree_ops rb_ops = {
 +		file_cmp_node, file_cmp_key
 +	};
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct _7zip *zip;
 +
 +	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_set_format_7zip");
 +
 +	/* If another format was already registered, unregister it. */
 +	if (a->format_free != NULL)
 +		(a->format_free)(a);
 +
 +	zip = calloc(1, sizeof(*zip));
 +	if (zip == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate 7-Zip data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	zip->temp_fd = -1;
 +	__archive_rb_tree_init(&(zip->rbtree), &rb_ops);
 +	file_init_register(zip);
 +	file_init_register_empty(zip);
 +
 +	/* Set default compression type and its level. */
 +#if HAVE_LZMA_H
 +	zip->opt_compression = _7Z_LZMA1;
 +#elif defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +	zip->opt_compression = _7Z_BZIP2;
 +#elif defined(HAVE_ZLIB_H)
 +	zip->opt_compression = _7Z_DEFLATE;
 +#else
 +	zip->opt_compression = _7Z_COPY;
 +#endif
 +	zip->opt_compression_level = 6;
 +
 +	a->format_data = zip;
 +
 +	a->format_name = "7zip";
 +	a->format_options = _7z_options;
 +	a->format_write_header = _7z_write_header;
 +	a->format_write_data = _7z_write_data;
 +	a->format_finish_entry = _7z_finish_entry;
 +	a->format_close = _7z_close;
 +	a->format_free = _7z_free;
 +	a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
 +	a->archive.archive_format_name = "7zip";
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +_7z_options(struct archive_write *a, const char *key, const char *value)
 +{
 +	struct _7zip *zip;
 +
 +	zip = (struct _7zip *)a->format_data;
 +
 +	if (strcmp(key, "compression") == 0) {
 +		const char *name = NULL;
 +
 +		if (value == NULL || strcmp(value, "copy") == 0 ||
 +		    strcmp(value, "COPY") == 0 ||
 +		    strcmp(value, "store") == 0 ||
 +		    strcmp(value, "STORE") == 0)
 +			zip->opt_compression = _7Z_COPY;
 +		else if (strcmp(value, "deflate") == 0 ||
 +		    strcmp(value, "DEFLATE") == 0)
 +#if HAVE_ZLIB_H
 +			zip->opt_compression = _7Z_DEFLATE;
 +#else
 +			name = "deflate";
 +#endif
 +		else if (strcmp(value, "bzip2") == 0 ||
 +		    strcmp(value, "BZIP2") == 0)
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +			zip->opt_compression = _7Z_BZIP2;
 +#else
 +			name = "bzip2";
 +#endif
 +		else if (strcmp(value, "lzma1") == 0 ||
 +		    strcmp(value, "LZMA1") == 0)
 +#if HAVE_LZMA_H
 +			zip->opt_compression = _7Z_LZMA1;
 +#else
 +			name = "lzma1";
 +#endif
 +		else if (strcmp(value, "lzma2") == 0 ||
 +		    strcmp(value, "LZMA2") == 0)
 +#if HAVE_LZMA_H
 +			zip->opt_compression = _7Z_LZMA2;
 +#else
 +			name = "lzma2";
 +#endif
 +		else if (strcmp(value, "ppmd") == 0 ||
 +		    strcmp(value, "PPMD") == 0 ||
 +		    strcmp(value, "PPMd") == 0)
 +			zip->opt_compression = _7Z_PPMD;
 +		else {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Unknown compression name: `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		if (name != NULL) {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "`%s' compression not supported "
 +			    "on this platform",
 +			    name);
 +			return (ARCHIVE_FAILED);
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +	if (strcmp(key, "compression-level") == 0) {
 +		if (value == NULL ||
 +		    !(value[0] >= '0' && value[0] <= '9') ||
 +		    value[1] != '\0') {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
- 			    "Illeagal value `%s'",
++			    "Illegal value `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		zip->opt_compression_level = value[0] - '0';
 +		return (ARCHIVE_OK);
 +	}
 +
- 	return (ARCHIVE_FAILED);
++	/* Note: The "warn" return is just to inform the options
++	 * supervisor that we didn't handle it.  It will generate
++	 * a suitable error if no one used this option. */
++	return (ARCHIVE_WARN);
 +}
 +
 +static int
 +_7z_write_header(struct archive_write *a, struct archive_entry *entry)
 +{
 +	struct _7zip *zip;
 +	struct file *file;
 +	int r;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	zip->cur_file = NULL;
 +	zip->entry_bytes_remaining = 0;
 +
 +	if (zip->sconv == NULL) {
 +		zip->sconv = archive_string_conversion_to_charset(
 +		    &a->archive, "UTF-16LE", 1);
 +		if (zip->sconv == NULL)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	r = file_new(a, entry, &file);
 +	if (r < ARCHIVE_WARN) {
 +		file_free(file);
 +		return (r);
 +	}
++	if (file->size == 0 && file->dir) {
++		if (!__archive_rb_tree_insert_node(&(zip->rbtree),
++		    (struct archive_rb_node *)file)) {
++			/* We have already had the same file. */
++			file_free(file);
++			return (ARCHIVE_OK);
++		}
++	}
 +
 +	if (file->flg & MTIME_IS_SET)
 +		zip->total_number_time_defined[MTIME]++;
 +	if (file->flg & CTIME_IS_SET)
 +		zip->total_number_time_defined[CTIME]++;
 +	if (file->flg & ATIME_IS_SET)
 +		zip->total_number_time_defined[ATIME]++;
 +
- 	if (file->size == 0 && file->dir) {
- 		if (!__archive_rb_tree_insert_node(&(zip->rbtree),
- 		    (struct archive_rb_node *)file))
- 			file_free(file);
- 	}
 +	zip->total_number_entry++;
 +	zip->total_bytes_entry_name += file->name_len + 2;
 +	if (file->size == 0) {
 +		/* Count up the number of empty files. */
 +		zip->total_number_empty_entry++;
 +		if (file->dir)
 +			zip->total_number_dir_entry++;
 +		else
 +			file_register_empty(zip, file);
 +		return (r);
 +	}
 +
 +	/*
 +	 * Init compression.
 +	 */
 +	if ((zip->total_number_entry - zip->total_number_empty_entry) == 1) {
 +		r = _7z_compression_init_encoder(a, zip->opt_compression,
 +			zip->opt_compression_level);
 +		if (r < 0) {
 +			file_free(file);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	/* Register a non-empty file. */
 +	file_register(zip, file);
 +
 +	/*
 +	 * Set the current file to cur_file to read its contents.
 +	 */
 +	zip->cur_file = file;
 +
 +
 +	/* Save a offset of current file in temporary file. */
 +	zip->entry_bytes_remaining = file->size;
 +	zip->entry_crc32 = 0;
 +
 +	/*
 +	 * Store a symbolic link name as file contents.
 +	 */
 +	if (archive_entry_filetype(entry) == AE_IFLNK) {
 +		ssize_t bytes;
 +		const void *p = (const void *)archive_entry_symlink(entry);
- 		bytes = compress_out(a, p, file->size, ARCHIVE_Z_RUN);
++		bytes = compress_out(a, p, (size_t)file->size, ARCHIVE_Z_RUN);
 +		if (bytes < 0)
 +			return ((int)bytes);
- 		zip->entry_crc32 = crc32(zip->entry_crc32, p, bytes);
++		zip->entry_crc32 = crc32(zip->entry_crc32, p, (unsigned)bytes);
 +		zip->entry_bytes_remaining -= bytes;
 +	}
 +
 +	return (r);
 +}
 +
 +/*
 + * Write data to a temporary file.
 + */
 +static int
 +write_to_temp(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct _7zip *zip;
- 	unsigned char *p;
++	const unsigned char *p;
 +	ssize_t ws;
 +
 +	zip = (struct _7zip *)a->format_data;
 +
 +	/*
 +	 * Open a temporary file.
 +	 */
 +	if (zip->temp_fd == -1) {
 +		zip->temp_offset = 0;
 +		zip->temp_fd = __archive_mktemp(NULL);
 +		if (zip->temp_fd < 0) {
 +			archive_set_error(&a->archive, errno,
 +			    "Couldn't create temporary file");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
- 	p = (unsigned char *)buff;
++	p = (const unsigned char *)buff;
 +	while (s) {
 +		ws = write(zip->temp_fd, p, s);
 +		if (ws < 0) {
 +			archive_set_error(&(a->archive), errno,
 +			    "fwrite function failed");
 +			return (ARCHIVE_FATAL);
 +		}
 +		s -= ws;
 +		p += ws;
 +		zip->temp_offset += ws;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static ssize_t
 +compress_out(struct archive_write *a, const void *buff, size_t s,
 +    enum la_zaction run)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +	int r;
 +
 +	if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)
 +		return (0);
 +
 +	if ((zip->crc32flg & PRECODE_CRC32) && s)
- 		zip->precode_crc32 = crc32(zip->precode_crc32, buff, s);
++		zip->precode_crc32 = crc32(zip->precode_crc32, buff,
++		    (unsigned)s);
 +	zip->stream.next_in = (const unsigned char *)buff;
 +	zip->stream.avail_in = s;
- 	do {
++	for (;;) {
 +		/* Compress file data. */
 +		r = compression_code(&(a->archive), &(zip->stream), run);
 +		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
 +			return (ARCHIVE_FATAL);
 +		if (zip->stream.avail_out == 0) {
 +			if (write_to_temp(a, zip->wbuff, sizeof(zip->wbuff))
 +			    != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			zip->stream.next_out = zip->wbuff;
 +			zip->stream.avail_out = sizeof(zip->wbuff);
 +			if (zip->crc32flg & ENCODED_CRC32)
 +				zip->encoded_crc32 = crc32(zip->encoded_crc32,
 +				    zip->wbuff, sizeof(zip->wbuff));
++			if (run == ARCHIVE_Z_FINISH && r != ARCHIVE_EOF)
++				continue;
 +		}
- 	} while (zip->stream.avail_in);
++		if (zip->stream.avail_in == 0)
++			break;
++	}
 +	if (run == ARCHIVE_Z_FINISH) {
 +		uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out;
- 		if (write_to_temp(a, zip->wbuff, bytes) != ARCHIVE_OK)
++		if (write_to_temp(a, zip->wbuff, (size_t)bytes) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		if ((zip->crc32flg & ENCODED_CRC32) && bytes)
 +			zip->encoded_crc32 = crc32(zip->encoded_crc32,
- 			    zip->wbuff, bytes);
++			    zip->wbuff, (unsigned)bytes);
 +	}
 +
 +	return (s);
 +}
 +
 +static ssize_t
 +_7z_write_data(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct _7zip *zip;
 +	ssize_t bytes;
 +
 +	zip = (struct _7zip *)a->format_data;
 +
 +	if (s > zip->entry_bytes_remaining)
- 		s = zip->entry_bytes_remaining;
++		s = (size_t)zip->entry_bytes_remaining;
 +	if (s == 0 || zip->cur_file == NULL)
 +		return (0);
 +	bytes = compress_out(a, buff, s, ARCHIVE_Z_RUN);
 +	if (bytes < 0)
 +		return (bytes);
- 	zip->entry_crc32 = crc32(zip->entry_crc32, buff, bytes);
++	zip->entry_crc32 = crc32(zip->entry_crc32, buff, (unsigned)bytes);
 +	zip->entry_bytes_remaining -= bytes;
 +	return (bytes);
 +}
 +
 +static int
 +_7z_finish_entry(struct archive_write *a)
 +{
 +	struct _7zip *zip;
 +	size_t s;
 +	ssize_t r;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	if (zip->cur_file == NULL)
 +		return (ARCHIVE_OK);
 +
 +	while (zip->entry_bytes_remaining > 0) {
- 		s = zip->entry_bytes_remaining;
++		s = (size_t)zip->entry_bytes_remaining;
 +		if (s > a->null_length)
 +			s = a->null_length;
 +		r = _7z_write_data(a, a->nulls, s);
 +		if (r < 0)
- 			return (r);
++			return ((int)r);
 +	}
 +	zip->total_bytes_compressed += zip->stream.total_in;
 +	zip->total_bytes_uncompressed += zip->stream.total_out;
 +	zip->cur_file->crc32 = zip->entry_crc32;
 +	zip->cur_file = NULL;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +flush_wbuff(struct archive_write *a)
 +{
 +	struct _7zip *zip;
 +	int r;
 +	size_t s;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	s = sizeof(zip->wbuff) - zip->wbuff_remaining;
 +	r = __archive_write_output(a, zip->wbuff, s);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	zip->wbuff_remaining = sizeof(zip->wbuff);
 +	return (r);
 +}
 +
 +static int
 +copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
 +{
 +	struct _7zip *zip;
 +	int r;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	if (zip->temp_offset > 0 &&
 +	    lseek(zip->temp_fd, offset, SEEK_SET) < 0) {
 +		archive_set_error(&(a->archive), errno, "lseek failed");
 +		return (ARCHIVE_FATAL);
 +	}
 +	while (length) {
 +		size_t rsize;
 +		ssize_t rs;
 +		unsigned char *wb;
 +
 +		if (length > zip->wbuff_remaining)
 +			rsize = zip->wbuff_remaining;
 +		else
 +			rsize = (size_t)length;
 +		wb = zip->wbuff + (sizeof(zip->wbuff) - zip->wbuff_remaining);
 +		rs = read(zip->temp_fd, wb, rsize);
 +		if (rs < 0) {
 +			archive_set_error(&(a->archive), errno,
 +			    "Can't read temporary file(%jd)",
 +			    (intmax_t)rs);
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (rs == 0) {
 +			archive_set_error(&(a->archive), 0,
 +			    "Truncated 7-Zip archive");
 +			return (ARCHIVE_FATAL);
 +		}
 +		zip->wbuff_remaining -= rs;
 +		length -= rs;
 +		if (zip->wbuff_remaining == 0) {
 +			r = flush_wbuff(a);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +		}
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +_7z_close(struct archive_write *a)
 +{
 +	struct _7zip *zip;
 +	unsigned char *wb;
 +	uint64_t header_offset, header_size, header_unpacksize;
 +	uint64_t length;
 +	uint32_t header_crc32;
 +	int r;
 +
 +	zip = (struct _7zip *)a->format_data;
 +
 +	if (zip->total_number_entry > 0) {
 +		struct archive_rb_node *n;
 +		uint64_t data_offset, data_size, data_unpacksize;
 +		unsigned header_compression;
 +
 +		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
 +		if (r < 0)
 +			return (r);
 +		data_offset = 0;
 +		data_size = zip->stream.total_out;
 +		data_unpacksize = zip->stream.total_in;
 +		zip->coder.codec = zip->opt_compression;
 +		zip->coder.prop_size = zip->stream.prop_size;
 +		zip->coder.props = zip->stream.props;
 +		zip->stream.prop_size = 0;
 +		zip->stream.props = NULL;
 +		zip->total_number_nonempty_entry =
 +		    zip->total_number_entry - zip->total_number_empty_entry;
 +
 +		/* Connect an empty file list. */
- 		*zip->file_list.last = zip->empty_list.first;
- 		zip->file_list.last = zip->empty_list.last;
++		if (zip->empty_list.first != NULL) {
++			*zip->file_list.last = zip->empty_list.first;
++			zip->file_list.last = zip->empty_list.last;
++		}
 +		/* Connect a directory file list. */
 +		ARCHIVE_RB_TREE_FOREACH(n, &(zip->rbtree)) {
 +			file_register(zip, (struct file *)n);
 +		}
 +
 +		/*
 +		 * NOTE: 7z command supports just LZMA1, LZMA2 and COPY for
 +		 * the compression type for encoding the header.
 +		 */
 +#if HAVE_LZMA_H
 +		header_compression = _7Z_LZMA1;
 +		/* If the stored file is only one, do not encode the header.
 +		 * This is the same way 7z command does. */
 +		if (zip->total_number_entry == 1)
 +			header_compression = _7Z_COPY;
 +#else
 +		header_compression = _7Z_COPY;
 +#endif
 +		r = _7z_compression_init_encoder(a, header_compression, 6);
 +		if (r < 0)
 +			return (r);
 +		zip->crc32flg = PRECODE_CRC32;
 +		zip->precode_crc32 = 0;
 +		r = make_header(a, data_offset, data_size, data_unpacksize,
 +			1, &(zip->coder));
 +		if (r < 0)
 +			return (r);
 +		r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
 +		if (r < 0)
 +			return (r);
 +		header_offset = data_offset + data_size;
 +		header_size = zip->stream.total_out;
 +		header_crc32 = zip->precode_crc32;
 +		header_unpacksize = zip->stream.total_in;
 +
 +		if (header_compression != _7Z_COPY) {
 +			/*
 +			 * Encode the header in order to reduce the size
 +			 * of the archive.
 +			 */
 +			free(zip->coder.props);
 +			zip->coder.codec = header_compression;
 +			zip->coder.prop_size = zip->stream.prop_size;
 +			zip->coder.props = zip->stream.props;
 +			zip->stream.prop_size = 0;
 +			zip->stream.props = NULL;
 +
 +			r = _7z_compression_init_encoder(a, _7Z_COPY, 0);
 +			if (r < 0)
 +				return (r);
 +			zip->crc32flg = ENCODED_CRC32;
 +			zip->encoded_crc32 = 0;
 +
 +			/*
 +			 * Make EncodedHeader.
 +			 */
 +			r = enc_uint64(a, kEncodedHeader);
 +			if (r < 0)
 +				return (r);
 +			r = make_streamsInfo(a, header_offset, header_size,
 +			      header_unpacksize, 1, &(zip->coder), 0,
 +			      header_crc32);
 +			if (r < 0)
 +				return (r);
 +			r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
 +			if (r < 0)
 +				return (r);
 +			header_offset = header_offset + header_size;
 +			header_size = zip->stream.total_out;
 +			header_crc32 = zip->encoded_crc32;
 +		}
 +		zip->crc32flg = 0;
 +	} else {
 +		header_offset = header_size = 0;
 +		header_crc32 = 0;
 +	}
 +	
 +	length = zip->temp_offset;
 +
 +	/*
 +	 * Make the zip header on wbuff(write buffer).
 +	 */
 +	wb = zip->wbuff;
 +	zip->wbuff_remaining = sizeof(zip->wbuff);
 +	memcpy(&wb[0], "7z\xBC\xAF\x27\x1C", 6);
 +	wb[6] = 0;/* Major version. */
 +	wb[7] = 3;/* Minor version. */
 +	archive_le64enc(&wb[12], header_offset);/* Next Header Offset */
 +	archive_le64enc(&wb[20], header_size);/* Next Header Size */
 +	archive_le32enc(&wb[28], header_crc32);/* Next Header CRC */
 +	archive_le32enc(&wb[8], crc32(0, &wb[12], 20));/* Start Header CRC */
 +	zip->wbuff_remaining -= 32;
 +
 +	/*
 +	 * Read all file contents and an encoded header from the temporary
 +	 * file and write out it.
 +	 */
 +	r = copy_out(a, 0, length);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	r = flush_wbuff(a);
 +	return (r);
 +}
 +
 +/*
 + * Encode 64 bits value into 7-Zip's encoded UINT64 value.
 + */
 +static int
 +enc_uint64(struct archive_write *a, uint64_t val)
 +{
 +	unsigned mask = 0x80;
 +	uint8_t numdata[9];
 +	int i;
 +
 +	numdata[0] = 0;
- 	for (i = 1; i < sizeof(numdata); i++) {
++	for (i = 1; i < (int)sizeof(numdata); i++) {
 +		if (val < mask) {
 +			numdata[0] |= (uint8_t)val;
 +			break;
 +		}
 +		numdata[i] = (uint8_t)val;
 +		val >>= 8;
 +		numdata[0] |= mask;
 +		mask >>= 1;
 +	}
- 	return (compress_out(a, numdata, i, ARCHIVE_Z_RUN));
++	return ((int)compress_out(a, numdata, i, ARCHIVE_Z_RUN));
 +}
 +
 +static int
 +make_substreamsInfo(struct archive_write *a, struct coder *coders)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +	struct file *file;
 +	int r;
 +
 +	/*
 +	 * Make SubStreamsInfo.
 +	 */
 +	r = enc_uint64(a, kSubStreamsInfo);
 +	if (r < 0)
 +		return (r);
 +
 +	if (zip->total_number_nonempty_entry > 1 && coders->codec != _7Z_COPY) {
 +		/*
 +		 * Make NumUnPackStream.
 +		 */
 +		r = enc_uint64(a, kNumUnPackStream);
 +		if (r < 0)
 +			return (r);
 +
 +		/* Write numUnpackStreams */
 +		r = enc_uint64(a, zip->total_number_nonempty_entry);
 +		if (r < 0)
 +			return (r);
 +
 +		/*
 +		 * Make kSize.
 +		 */
 +		r = enc_uint64(a, kSize);
 +		if (r < 0)
 +			return (r);
 +		file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->next == NULL ||
 +			    file->next->size == 0)
 +				break;
 +			r = enc_uint64(a, file->size);
 +			if (r < 0)
 +				return (r);
 +		}
 +	}
 +
 +	/*
 +	 * Make CRC.
 +	 */
 +	r = enc_uint64(a, kCRC);
 +	if (r < 0)
 +		return (r);
 +
 +
 +	/* All are defined */
 +	r = enc_uint64(a, 1);
 +	if (r < 0)
 +		return (r);
 +	file = zip->file_list.first;
 +	for (;file != NULL; file = file->next) {
 +		uint8_t crc[4];
 +		if (file->size == 0)
 +			break;
 +		archive_le32enc(crc, file->crc32);
- 		r = compress_out(a, crc, 4, ARCHIVE_Z_RUN);
++		r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Write End. */
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 +    uint64_t unpack_size, int num_coder, struct coder *coders, int substrm,
 +    uint32_t header_crc)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +	uint8_t codec_buff[8];
 +	int numFolders, fi;
 +	int codec_size;
 +	int i, r;
 +
 +	if (coders->codec == _7Z_COPY)
- 		numFolders = zip->total_number_nonempty_entry;
++		numFolders = (int)zip->total_number_nonempty_entry;
 +	else
 +		numFolders = 1;
 +
 +	/*
 +	 * Make PackInfo.
 +	 */
 +	r = enc_uint64(a, kPackInfo);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write PackPos. */
 +	r = enc_uint64(a, offset);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write NumPackStreams. */
 +	r = enc_uint64(a, numFolders);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Make Size. */
 +	r = enc_uint64(a, kSize);
 +	if (r < 0)
 +		return (r);
 +
 +	if (numFolders > 1) {
 +		struct file *file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->size == 0)
 +				break;
 +			r = enc_uint64(a, file->size);
 +			if (r < 0)
 +				return (r);
 +		}
 +	} else {
 +		/* Write size. */
 +		r = enc_uint64(a, pack_size);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +
 +	/*
 +	 * Make UnPackInfo.
 +	 */
 +	r = enc_uint64(a, kUnPackInfo);
 +	if (r < 0)
 +		return (r);
 +
 +	/*
 +	 * Make Folder.
 +	 */
 +	r = enc_uint64(a, kFolder);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write NumFolders. */
 +	r = enc_uint64(a, numFolders);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write External. */
 +	r = enc_uint64(a, 0);
 +	if (r < 0)
 +		return (r);
 +
 +	for (fi = 0; fi < numFolders; fi++) {
 +		/* Write NumCoders. */
 +		r = enc_uint64(a, num_coder);
 +		if (r < 0)
 +			return (r);
 +
 +		for (i = 0; i < num_coder; i++) {
 +			unsigned codec_id = coders[i].codec;
 +
 +			/* Write Codec flag. */
 +			archive_be64enc(codec_buff, codec_id);
 +			for (codec_size = 8; codec_size > 0; codec_size--) {
 +				if (codec_buff[8 - codec_size])
 +					break;
 +			}
 +			if (codec_size == 0)
 +				codec_size = 1;
 +			if (coders[i].prop_size)
 +				r = enc_uint64(a, codec_size | 0x20);
 +			else
 +				r = enc_uint64(a, codec_size);
 +			if (r < 0)
 +				return (r);
 +
 +			/* Write Codec ID. */
 +			codec_size &= 0x0f;
- 			r = compress_out(a, &codec_buff[8-codec_size],
++			r = (int)compress_out(a, &codec_buff[8-codec_size],
 +				codec_size, ARCHIVE_Z_RUN);
 +			if (r < 0)
 +				return (r);
 +
 +			if (coders[i].prop_size) {
 +				/* Write Codec property size. */
 +				r = enc_uint64(a, coders[i].prop_size);
 +				if (r < 0)
 +					return (r);
 +
 +				/* Write Codec properties. */
- 				r = compress_out(a, coders[i].props,
++				r = (int)compress_out(a, coders[i].props,
 +					coders[i].prop_size, ARCHIVE_Z_RUN);
 +				if (r < 0)
 +					return (r);
 +			}
 +		}
 +	}
 +
 +	/*
 +	 * Make CodersUnPackSize.
 +	 */
 +	r = enc_uint64(a, kCodersUnPackSize);
 +	if (r < 0)
 +		return (r);
 +
 +	if (numFolders > 1) {
 +		struct file *file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->size == 0)
 +				break;
 +			r = enc_uint64(a, file->size);
 +			if (r < 0)
 +				return (r);
 +		}
 +
 +	} else {
 +		/* Write UnPackSize. */
 +		r = enc_uint64(a, unpack_size);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	if (!substrm) {
 +		uint8_t crc[4];
 +		/*
 +		 * Make CRC.
 +		 */
 +		r = enc_uint64(a, kCRC);
 +		if (r < 0)
 +			return (r);
 +
 +		/* All are defined */
 +		r = enc_uint64(a, 1);
 +		if (r < 0)
 +			return (r);
 +		archive_le32enc(crc, header_crc);
- 		r = compress_out(a, crc, 4, ARCHIVE_Z_RUN);
++		r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Write End. */
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +
 +	if (substrm) {
 +		/*
 +		 * Make SubStreamsInfo.
 +		 */
 +		r = make_substreamsInfo(a, coders);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +
 +	/* Write End. */
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +
 +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 +static uint64_t
- utcToFiletime(time_t time, long ns)
++utcToFiletime(time_t t, long ns)
 +{
 +	uint64_t fileTime;
 +
- 	fileTime = time;
++	fileTime = t;
 +	fileTime *= 10000000;
 +	fileTime += ns / 100;
 +	fileTime += EPOC_TIME;
 +	return (fileTime);
 +}
 +
 +static int
 +make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
 +{
 +	uint8_t filetime[8];
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +	struct file *file;
 +	int r;
- 	uint8_t mask, byte;
++	uint8_t b, mask;
 +
 +	/*
 +	 * Make Time Bools.
 +	 */
 +	if (zip->total_number_time_defined[ti] == zip->total_number_entry) {
 +		/* Write Time Type. */
 +		r = enc_uint64(a, type);
 +		if (r < 0)
 +			return (r);
 +		/* Write EmptyStream Size. */
 +		r = enc_uint64(a, 2 + zip->total_number_entry * 8);
 +		if (r < 0)
 +			return (r);
 +		/* All are defined. */
 +		r = enc_uint64(a, 1);
 +		if (r < 0)
 +			return (r);
 +	} else {
 +		if (zip->total_number_time_defined[ti] == 0)
 +			return (ARCHIVE_OK);
 +
 +		/* Write Time Type. */
 +		r = enc_uint64(a, type);
 +		if (r < 0)
 +			return (r);
 +		/* Write EmptyStream Size. */
 +		r = enc_uint64(a, 2 + ((zip->total_number_entry + 7) >> 3)
 +			+ zip->total_number_time_defined[ti] * 8);
 +		if (r < 0)
 +			return (r);
 +
 +		/* All are not defined. */
 +		r = enc_uint64(a, 0);
 +		if (r < 0)
 +			return (r);
 +
- 		byte = 0;
++		b = 0;
 +		mask = 0x80;
 +		file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->flg & flg)
- 				byte |= mask;
++				b |= mask;
 +			mask >>= 1;
 +			if (mask == 0) {
- 				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
++				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 +				if (r < 0)
 +					return (r);
 +				mask = 0x80;
- 				byte = 0;
++				b = 0;
 +			}
 +		}
 +		if (mask != 0x80) {
- 			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
++			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 +			if (r < 0)
 +				return (r);
 +		}
 +	}
 +
 +	/* External. */
 +	r = enc_uint64(a, 0);
 +	if (r < 0)
 +		return (r);
 +
 +
 +	/*
 +	 * Make Times.
 +	 */
 +	file = zip->file_list.first;
 +	for (;file != NULL; file = file->next) {
 +		if ((file->flg & flg) == 0)
 +			continue;
 +		archive_le64enc(filetime, utcToFiletime(file->times[ti].time,
 +			file->times[ti].time_ns));
- 		r = compress_out(a, filetime, 8, ARCHIVE_Z_RUN);
++		r = (int)compress_out(a, filetime, 8, ARCHIVE_Z_RUN);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 +    uint64_t unpack_size, int codernum, struct coder *coders)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +	struct file *file;
 +	int r;
- 	uint8_t mask, byte;
++	uint8_t b, mask;
 +
 +	/*
 +	 * Make FilesInfo.
 +	 */
 +	r = enc_uint64(a, kHeader);
 +	if (r < 0)
 +		return (r);
 +
 +	/*
 +	 * If there are empty files only, do not write MainStreamInfo.
 +	 */
 +	if (zip->total_number_nonempty_entry) {
 +		/*
 +		 * Make MainStreamInfo.
 +		 */
 +		r = enc_uint64(a, kMainStreamsInfo);
 +		if (r < 0)
 +			return (r);
 +		r = make_streamsInfo(a, offset, pack_size, unpack_size,
 +		      codernum, coders, 1, 0);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/*
 +	 * Make FilesInfo.
 +	 */
 +	r = enc_uint64(a, kFilesInfo);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write numFiles. */
 +	r = enc_uint64(a, zip->total_number_entry);
 +	if (r < 0)
 +		return (r);
 +
 +	if (zip->total_number_empty_entry > 0) {
 +		/* Make EmptyStream. */
 +		r = enc_uint64(a, kEmptyStream);
 +		if (r < 0)
 +			return (r);
 +
 +		/* Write EmptyStream Size. */
 +		r = enc_uint64(a, (zip->total_number_entry+7)>>3);
 +		if (r < 0)
 +			return (r);
 +
- 		byte = 0;
++		b = 0;
 +		mask = 0x80;
 +		file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->size == 0)
- 				byte |= mask;
++				b |= mask;
 +			mask >>= 1;
 +			if (mask == 0) {
- 				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
++				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 +				if (r < 0)
 +					return (r);
 +				mask = 0x80;
- 				byte = 0;
++				b = 0;
 +			}
 +		}
 +		if (mask != 0x80) {
- 			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
++			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 +			if (r < 0)
 +				return (r);
 +		}
 +	}
 +
 +	if (zip->total_number_empty_entry > zip->total_number_dir_entry) {
 +		/* Make EmptyFile. */
 +		r = enc_uint64(a, kEmptyFile);
 +		if (r < 0)
 +			return (r);
 +
 +		/* Write EmptyFile Size. */
 +		r = enc_uint64(a, (zip->total_number_empty_entry + 7) >> 3);
 +		if (r < 0)
 +			return (r);
 +
- 		byte = 0;
++		b = 0;
 +		mask = 0x80;
 +		file = zip->file_list.first;
 +		for (;file != NULL; file = file->next) {
 +			if (file->size)
 +				continue;
 +			if (!file->dir)
- 				byte |= mask;
++				b |= mask;
 +			mask >>= 1;
 +			if (mask == 0) {
- 				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
++				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 +				if (r < 0)
 +					return (r);
 +				mask = 0x80;
- 				byte = 0;
++				b = 0;
 +			}
 +		}
 +		if (mask != 0x80) {
- 			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
++			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 +			if (r < 0)
 +				return (r);
 +		}
 +	}
 +
 +	/* Make Name. */
 +	r = enc_uint64(a, kName);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write Nume size. */
 +	r = enc_uint64(a, zip->total_bytes_entry_name+1);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write dmy byte. */
 +	r = enc_uint64(a, 0);
 +	if (r < 0)
 +		return (r);
 +
 +	file = zip->file_list.first;
 +	for (;file != NULL; file = file->next) {
- 		r = compress_out(a, file->utf16name, file->name_len+2,
++		r = (int)compress_out(a, file->utf16name, file->name_len+2,
 +			ARCHIVE_Z_RUN);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Make MTime. */
 +	r = make_time(a, kMTime, MTIME_IS_SET, MTIME);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Make CTime. */
 +	r = make_time(a, kCTime, CTIME_IS_SET, CTIME);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Make ATime. */
 +	r = make_time(a, kATime, ATIME_IS_SET, ATIME);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Make Attributes. */
 +	r = enc_uint64(a, kAttributes);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write Attributes size. */
 +	r = enc_uint64(a, 2 + zip->total_number_entry * 4);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write "All Are Defined". */
 +	r = enc_uint64(a, 1);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write dmy byte. */
 +	r = enc_uint64(a, 0);
 +	if (r < 0)
 +		return (r);
 +
 +	file = zip->file_list.first;
 +	for (;file != NULL; file = file->next) {
 +		/*
 +		 * High 16bits is unix mode.
 +		 * Low 16bits is Windows attributes.
 +		 */
 +		uint32_t encattr, attr;
 +		if (file->dir)
 +			attr = 0x8010;
 +		else
 +			attr = 0x8020;
 +		if ((file->mode & 0222) == 0)
 +			attr |= 1;/* Read Only. */
 +		attr |= ((uint32_t)file->mode) << 16;
 +		archive_le32enc(&encattr, attr);
- 		r = compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
++		r = (int)compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Write End. */
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +
 +	/* Write End. */
 +	r = enc_uint64(a, kEnd);
 +	if (r < 0)
 +		return (r);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +
 +static int
 +_7z_free(struct archive_write *a)
 +{
 +	struct _7zip *zip = (struct _7zip *)a->format_data;
 +
 +	file_free_register(zip);
 +	compression_end(&(a->archive), &(zip->stream));
 +	free(zip->coder.props);
 +	free(zip);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +file_cmp_node(const struct archive_rb_node *n1,
 +    const struct archive_rb_node *n2)
 +{
- 	struct file *f1 = (struct file *)n1;
- 	struct file *f2 = (struct file *)n2;
++	const struct file *f1 = (const struct file *)n1;
++	const struct file *f2 = (const struct file *)n2;
 +
 +	if (f1->name_len == f2->name_len)
 +		return (memcmp(f1->utf16name, f2->utf16name, f1->name_len));
 +	return (f1->name_len > f2->name_len)?1:-1;
 +}
 +        
 +static int
 +file_cmp_key(const struct archive_rb_node *n, const void *key)
 +{
- 	struct file *f = (struct file *)n;
++	const struct file *f = (const struct file *)n;
 +
 +	return (f->name_len - *(const char *)key);
 +}
 +
 +static int
 +file_new(struct archive_write *a, struct archive_entry *entry,
 +    struct file **newfile)
 +{
 +	struct _7zip *zip;
 +	struct file *file;
 +	const char *u16;
 +	size_t u16len;
 +	int ret = ARCHIVE_OK;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	*newfile = NULL;
 +
 +	file = calloc(1, sizeof(*file));
 +	if (file == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) {
 +		if (errno == ENOMEM) {
++			free(file);
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for UTF-16LE");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "A filename cannot be converted to UTF-16LE;"
 +		    "You should disable making Joliet extension");
 +		ret = ARCHIVE_WARN;
 +	}
 +	file->utf16name = malloc(u16len + 2);
 +	if (file->utf16name == NULL) {
++		free(file);
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory for Name");
 +		return (ARCHIVE_FATAL);
 +	}
 +	memcpy(file->utf16name, u16, u16len);
 +	file->utf16name[u16len+0] = 0;
 +	file->utf16name[u16len+1] = 0;
- 	file->name_len = u16len;
++	file->name_len = (unsigned)u16len;
 +	file->mode = archive_entry_mode(entry);
 +	if (archive_entry_filetype(entry) == AE_IFREG)
 +		file->size = archive_entry_size(entry);
 +	else
 +		archive_entry_set_size(entry, 0);
 +	if (archive_entry_filetype(entry) == AE_IFDIR)
 +		file->dir = 1;
 +	else if (archive_entry_filetype(entry) == AE_IFLNK)
 +		file->size = strlen(archive_entry_symlink(entry));
 +	if (archive_entry_mtime_is_set(entry)) {
 +		file->flg |= MTIME_IS_SET;
 +		file->times[MTIME].time = archive_entry_mtime(entry);
 +		file->times[MTIME].time_ns = archive_entry_mtime_nsec(entry);
 +	}
 +	if (archive_entry_atime_is_set(entry)) {
 +		file->flg |= ATIME_IS_SET;
 +		file->times[ATIME].time = archive_entry_atime(entry);
 +		file->times[ATIME].time_ns = archive_entry_atime_nsec(entry);
 +	}
 +	if (archive_entry_ctime_is_set(entry)) {
 +		file->flg |= CTIME_IS_SET;
 +		file->times[CTIME].time = archive_entry_ctime(entry);
 +		file->times[CTIME].time_ns = archive_entry_ctime_nsec(entry);
 +	}
 +
 +	*newfile = file;
 +	return (ret);
 +}
 +
 +static void
 +file_free(struct file *file)
 +{
 +	free(file->utf16name);
 +	free(file);
 +}
 +
 +static void
 +file_register(struct _7zip *zip, struct file *file)
 +{
 +	file->next = NULL;
 +	*zip->file_list.last = file;
 +	zip->file_list.last = &(file->next);
 +}
 +
 +static void
 +file_init_register(struct _7zip *zip)
 +{
 +	zip->file_list.first = NULL;
 +	zip->file_list.last = &(zip->file_list.first);
 +}
 +
 +static void
 +file_free_register(struct _7zip *zip)
 +{
 +	struct file *file, *file_next;
 +
 +	file = zip->file_list.first;
 +	while (file != NULL) {
 +		file_next = file->next;
 +		file_free(file);
 +		file = file_next;
 +	}
 +}
 +
 +static void
 +file_register_empty(struct _7zip *zip, struct file *file)
 +{
 +	file->next = NULL;
 +	*zip->empty_list.last = file;
 +	zip->empty_list.last = &(file->next);
 +}
 +
 +static void
 +file_init_register_empty(struct _7zip *zip)
 +{
 +	zip->empty_list.first = NULL;
 +	zip->empty_list.last = &(zip->empty_list.first);
 +}
 +
- #if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
++#if !defined(HAVE_ZLIB_H) || !defined(HAVE_BZLIB_H) ||\
++	 !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
 +static int
 +compression_unsupported_encoder(struct archive *a,
 +    struct la_zstream *lastrm, const char *name)
 +{
 +
 +	archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +	    "%s compression not supported on this platform", name);
 +	lastrm->valid = 0;
 +	lastrm->real_stream = NULL;
 +	return (ARCHIVE_FAILED);
 +}
 +#endif
 +
 +/*
 + * _7_COPY compressor.
 + */
 +static int
 +compression_init_encoder_copy(struct archive *a, struct la_zstream *lastrm)
 +{
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_copy;
 +	lastrm->end = compression_end_copy;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_copy(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	size_t bytes;
 +
 +	(void)a; /* UNUSED */
 +	if (lastrm->avail_out > lastrm->avail_in)
 +		bytes = lastrm->avail_in;
 +	else
 +		bytes = lastrm->avail_out;
 +	if (bytes) {
 +		memcpy(lastrm->next_out, lastrm->next_in, bytes);
 +		lastrm->next_in += bytes;
 +		lastrm->avail_in -= bytes;
 +		lastrm->total_in += bytes;
 +		lastrm->next_out += bytes;
 +		lastrm->avail_out -= bytes;
 +		lastrm->total_out += bytes;
 +	}
 +	if (action == ARCHIVE_Z_FINISH && lastrm->avail_in == 0)
 +		return (ARCHIVE_EOF);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_end_copy(struct archive *a, struct la_zstream *lastrm)
 +{
 +	(void)a; /* UNUSED */
 +	lastrm->valid = 0;
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * _7_DEFLATE compressor.
 + */
 +#ifdef HAVE_ZLIB_H
 +static int
 +compression_init_encoder_deflate(struct archive *a,
 +    struct la_zstream *lastrm, int level, int withheader)
 +{
 +	z_stream *strm;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for gzip stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	/* zlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
- 	strm->avail_in = lastrm->avail_in;
- 	strm->total_in = lastrm->total_in;
++	strm->avail_in = (uInt)lastrm->avail_in;
++	strm->total_in = (uLong)lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
- 	strm->avail_out = lastrm->avail_out;
- 	strm->total_out = lastrm->total_out;
++	strm->avail_out = (uInt)lastrm->avail_out;
++	strm->total_out = (uLong)lastrm->total_out;
 +	if (deflateInit2(strm, level, Z_DEFLATED,
 +	    (withheader)?15:-15,
 +	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lastrm->real_stream = strm;
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_deflate;
 +	lastrm->end = compression_end_deflate;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_deflate(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	z_stream *strm;
 +	int r;
 +
 +	strm = (z_stream *)lastrm->real_stream;
 +	/* zlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
- 	strm->avail_in = lastrm->avail_in;
- 	strm->total_in = lastrm->total_in;
++	strm->avail_in = (uInt)lastrm->avail_in;
++	strm->total_in = (uLong)lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
- 	strm->avail_out = lastrm->avail_out;
- 	strm->total_out = lastrm->total_out;
++	strm->avail_out = (uInt)lastrm->avail_out;
++	strm->total_out = (uLong)lastrm->total_out;
 +	r = deflate(strm,
 +	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
 +	lastrm->next_in = strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in = strm->total_in;
 +	lastrm->next_out = strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out = strm->total_out;
 +	switch (r) {
 +	case Z_OK:
 +		return (ARCHIVE_OK);
 +	case Z_STREAM_END:
 +		return (ARCHIVE_EOF);
 +	default:
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "GZip compression failed:"
 +		    " deflate() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_deflate(struct archive *a, struct la_zstream *lastrm)
 +{
 +	z_stream *strm;
 +	int r;
 +
 +	strm = (z_stream *)lastrm->real_stream;
 +	r = deflateEnd(strm);
 +	free(strm);
 +	lastrm->real_stream = NULL;
 +	lastrm->valid = 0;
 +	if (r != Z_OK) {
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +#else
 +static int
 +compression_init_encoder_deflate(struct archive *a,
 +    struct la_zstream *lastrm, int level, int withheader)
 +{
 +
 +	(void) level; /* UNUSED */
 +	(void) withheader; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "deflate"));
 +}
 +#endif
 +
 +/*
 + * _7_BZIP2 compressor.
 + */
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +static int
 +compression_init_encoder_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	bz_stream *strm;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for bzip2 stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	/* bzlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
 +	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
 +	strm->next_out = (char *)lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
 +	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
 +	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lastrm->real_stream = strm;
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_bzip2;
 +	lastrm->end = compression_end_bzip2;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	bz_stream *strm;
 +	int r;
 +
 +	strm = (bz_stream *)lastrm->real_stream;
 +	/* bzlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
 +	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
 +	strm->next_out = (char *)lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
 +	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
 +	r = BZ2_bzCompress(strm,
 +	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
 +	lastrm->next_in = (const unsigned char *)strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in =
 +	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
 +	    + (uint64_t)(uint32_t)strm->total_in_lo32;
 +	lastrm->next_out = (unsigned char *)strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out =
 +	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
 +	    + (uint64_t)(uint32_t)strm->total_out_lo32;
 +	switch (r) {
 +	case BZ_RUN_OK:     /* Non-finishing */
 +	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
 +		return (ARCHIVE_OK);
 +	case BZ_STREAM_END: /* Finishing: all done */
 +		/* Only occurs in finishing case */
 +		return (ARCHIVE_EOF);
 +	default:
 +		/* Any other return value indicates an error */
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Bzip2 compression failed:"
 +		    " BZ2_bzCompress() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
 +{
 +	bz_stream *strm;
 +	int r;
 +
 +	strm = (bz_stream *)lastrm->real_stream;
 +	r = BZ2_bzCompressEnd(strm);
 +	free(strm);
 +	lastrm->real_stream = NULL;
 +	lastrm->valid = 0;
 +	if (r != BZ_OK) {
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +#else
 +static int
 +compression_init_encoder_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
 +}
 +#endif
 +
 +/*
 + * _7_LZMA1, _7_LZMA2 compressor.
 + */
 +#if defined(HAVE_LZMA_H)
 +static int
 +compression_init_encoder_lzma(struct archive *a,
 +    struct la_zstream *lastrm, int level, uint64_t filter_id)
 +{
 +	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
 +	lzma_stream *strm;
 +	lzma_filter *lzmafilters;
 +	lzma_options_lzma lzma_opt;
 +	int r;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for lzma stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lzmafilters = (lzma_filter *)(strm+1);
 +	if (level > 6)
 +		level = 6;
 +	if (lzma_lzma_preset(&lzma_opt, level)) {
++		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lzmafilters[0].id = filter_id;
 +	lzmafilters[0].options = &lzma_opt;
 +	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
 +
 +	r = lzma_properties_size(&(lastrm->prop_size), lzmafilters);
 +	if (r != LZMA_OK) {
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "lzma_properties_size failed");
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (lastrm->prop_size) {
 +		lastrm->props = malloc(lastrm->prop_size);
 +		if (lastrm->props == NULL) {
 +			free(strm);
 +			lastrm->real_stream = NULL;
 +			archive_set_error(a, ENOMEM,
 +			    "Cannot allocate memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = lzma_properties_encode(lzmafilters,  lastrm->props);
 +		if (r != LZMA_OK) {
 +			free(strm);
 +			lastrm->real_stream = NULL;
 +			archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +			    "lzma_properties_encode failed");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	*strm = lzma_init_data;
 +	r = lzma_raw_encoder(strm, lzmafilters);
 +	switch (r) {
 +	case LZMA_OK:
 +		lastrm->real_stream = strm;
 +		lastrm->valid = 1;
 +		lastrm->code = compression_code_lzma;
 +		lastrm->end = compression_end_lzma;
 +		r = ARCHIVE_OK;
 +		break;
 +	case LZMA_MEM_ERROR:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library: "
 +		    "Cannot allocate memory");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +        default:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    "It's a bug in liblzma");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +	}
 +	return (r);
 +}
 +
 +static int
 +compression_init_encoder_lzma1(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	return compression_init_encoder_lzma(a, lastrm, level,
 +		    LZMA_FILTER_LZMA1);
 +}
 +
 +static int
 +compression_init_encoder_lzma2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	return compression_init_encoder_lzma(a, lastrm, level,
 +		    LZMA_FILTER_LZMA2);
 +}
 +
 +static int
 +compression_code_lzma(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	lzma_stream *strm;
 +	int r;
 +
 +	strm = (lzma_stream *)lastrm->real_stream;
 +	strm->next_in = lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in = lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out = lastrm->total_out;
 +	r = lzma_code(strm,
 +	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
 +	lastrm->next_in = strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in = strm->total_in;
 +	lastrm->next_out = strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out = strm->total_out;
 +	switch (r) {
 +	case LZMA_OK:
 +		/* Non-finishing case */
 +		return (ARCHIVE_OK);
 +	case LZMA_STREAM_END:
 +		/* This return can only occur in finishing case. */
 +		return (ARCHIVE_EOF);
 +	case LZMA_MEMLIMIT_ERROR:
 +		archive_set_error(a, ENOMEM,
 +		    "lzma compression error:"
 +		    " %ju MiB would have been needed",
 +		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
 +			/ (1024 * 1024)));
 +		return (ARCHIVE_FATAL);
 +	default:
 +		/* Any other return value indicates an error */
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "lzma compression failed:"
 +		    " lzma_code() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_lzma(struct archive *a, struct la_zstream *lastrm)
 +{
 +	lzma_stream *strm;
 +
 +	(void)a; /* UNUSED */
 +	strm = (lzma_stream *)lastrm->real_stream;
 +	lzma_end(strm);
 +	free(strm);
 +	lastrm->valid = 0;
 +	lastrm->real_stream = NULL;
 +	return (ARCHIVE_OK);
 +}
 +#else
 +static int
 +compression_init_encoder_lzma1(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "lzma"));
 +}
 +static int
 +compression_init_encoder_lzma2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "lzma"));
 +}
 +#endif
 +
 +/*
 + * _7_PPMD compressor.
 + */
 +static void *
 +ppmd_alloc(void *p, size_t size)
 +{
 +	(void)p;
 +	return malloc(size);
 +}
 +static void
 +ppmd_free(void *p, void *address)
 +{
 +	(void)p;
 +	free(address);
 +}
 +static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
 +static void
 +ppmd_write(void *p, Byte b)
 +{
 +	struct archive_write *a = ((IByteOut *)p)->a;
 +	struct _7zip *zip = (struct _7zip *)(a->format_data);
 +	struct la_zstream *lastrm = &(zip->stream);
 +	struct ppmd_stream *strm;
 +
 +	if (lastrm->avail_out) {
 +		*lastrm->next_out++ = b;
 +		lastrm->avail_out--;
 +		lastrm->total_out++;
 +		return;
 +	}
 +	strm = (struct ppmd_stream *)lastrm->real_stream;
 +	if (strm->buff_ptr < strm->buff_end) {
 +		*strm->buff_ptr++ = b;
 +		strm->buff_bytes++;
 +	}
 +}
 +
 +static int
 +compression_init_encoder_ppmd(struct archive *a,
 +    struct la_zstream *lastrm, unsigned maxOrder, uint32_t msize)
 +{
 +	struct ppmd_stream *strm;
 +	uint8_t *props;
 +	int r;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for PPMd");
 +		return (ARCHIVE_FATAL);
 +	}
 +	strm->buff = malloc(32);
 +	if (strm->buff == NULL) {
 +		free(strm);
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for PPMd");
 +		return (ARCHIVE_FATAL);
 +	}
 +	strm->buff_ptr = strm->buff;
 +	strm->buff_end = strm->buff + 32;
 +
 +	props = malloc(1+4);
 +	if (props == NULL) {
 +		free(strm->buff);
 +		free(strm);
 +		archive_set_error(a, ENOMEM,
 +		    "Coludn't allocate memory for PPMd");
 +		return (ARCHIVE_FATAL);
 +	}
 +	props[0] = maxOrder;
 +	archive_le32enc(props+1, msize);
 +	__archive_ppmd7_functions.Ppmd7_Construct(&strm->ppmd7_context);
 +	r = __archive_ppmd7_functions.Ppmd7_Alloc(
 +		&strm->ppmd7_context, msize, &g_szalloc);
 +	if (r == 0) {
 +		free(strm->buff);
 +		free(strm);
 +		free(props);
 +		archive_set_error(a, ENOMEM,
 +		    "Coludn't allocate memory for PPMd");
 +		return (ARCHIVE_FATAL);
 +	}
 +	__archive_ppmd7_functions.Ppmd7_Init(&(strm->ppmd7_context), maxOrder);
 +	strm->byteout.a = (struct archive_write *)a;
 +	strm->byteout.Write = ppmd_write;
 +	strm->range_enc.Stream = &(strm->byteout);
 +	__archive_ppmd7_functions.Ppmd7z_RangeEnc_Init(&(strm->range_enc));
 +	strm->stat = 0;
 +
 +	lastrm->real_stream = strm;
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_ppmd;
 +	lastrm->end = compression_end_ppmd;
 +	lastrm->prop_size = 5;
 +	lastrm->props = props;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_ppmd(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	struct ppmd_stream *strm;
 +
++	(void)a; /* UNUSED */
++
 +	strm = (struct ppmd_stream *)lastrm->real_stream;
 +
 +	/* Copy encoded data if there are remaining bytes from previous call. */
 +	if (strm->buff_bytes) {
 +		uint8_t *p = strm->buff_ptr - strm->buff_bytes;
 +		while (lastrm->avail_out && strm->buff_bytes) {
 +			*lastrm->next_out++ = *p++;
 +			lastrm->avail_out--;
 +			lastrm->total_out++;
 +			strm->buff_bytes--;
 +		}
 +		if (strm->buff_bytes)
 +			return (ARCHIVE_OK);
 +		if (strm->stat == 1)
 +			return (ARCHIVE_EOF);
 +		strm->buff_ptr = strm->buff;
 +	}
 +	while (lastrm->avail_in && lastrm->avail_out) {
 +		__archive_ppmd7_functions.Ppmd7_EncodeSymbol(
 +			&(strm->ppmd7_context), &(strm->range_enc),
 +			*lastrm->next_in++);
 +		lastrm->avail_in--;
 +		lastrm->total_in++;
 +	}
 +	if (lastrm->avail_in == 0 && action == ARCHIVE_Z_FINISH) {
 +		__archive_ppmd7_functions.Ppmd7z_RangeEnc_FlushData(
 +			&(strm->range_enc));
 +		strm->stat = 1;
 +		/* Return EOF if there are no remaining bytes. */
 +		if (strm->buff_bytes == 0)
 +			return (ARCHIVE_EOF);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
 +{
 +	struct ppmd_stream *strm;
 +
++	(void)a; /* UNUSED */
++
 +	strm = (struct ppmd_stream *)lastrm->real_stream;
 +	__archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context, &g_szalloc);
 +	free(strm->buff);
 +	free(strm);
 +	lastrm->real_stream = NULL;
 +	lastrm->valid = 0;
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Universal compressor initializer.
 + */
 +static int
 +_7z_compression_init_encoder(struct archive_write *a, unsigned compression,
 +    int compression_level)
 +{
 +	struct _7zip *zip;
 +	int r;
 +
 +	zip = (struct _7zip *)a->format_data;
 +	switch (compression) {
 +	case _7Z_DEFLATE:
 +		r = compression_init_encoder_deflate(
 +		    &(a->archive), &(zip->stream),
 +		    compression_level, 0);
 +		break;
 +	case _7Z_BZIP2:
 +		r = compression_init_encoder_bzip2(
 +		    &(a->archive), &(zip->stream),
 +		    compression_level);
 +		break;
 +	case _7Z_LZMA1:
 +		r = compression_init_encoder_lzma1(
 +		    &(a->archive), &(zip->stream),
 +		    compression_level);
 +		break;
 +	case _7Z_LZMA2:
 +		r = compression_init_encoder_lzma2(
 +		    &(a->archive), &(zip->stream),
 +		    compression_level);
 +		break;
 +	case _7Z_PPMD:
 +		r = compression_init_encoder_ppmd(
 +		    &(a->archive), &(zip->stream),
 +		    PPMD7_DEFAULT_ORDER, PPMD7_DEFAULT_MEM_SIZE);
 +		break;
 +	case _7Z_COPY:
 +	default:
 +		r = compression_init_encoder_copy(
 +		    &(a->archive), &(zip->stream));
 +		break;
 +	}
 +	if (r == ARCHIVE_OK) {
 +		zip->stream.total_in = 0;
 +		zip->stream.next_out = zip->wbuff;
 +		zip->stream.avail_out = sizeof(zip->wbuff);
 +		zip->stream.total_out = 0;
 +	}
 +
 +	return (r);
 +}
 +
 +static int
 +compression_code(struct archive *a, struct la_zstream *lastrm,
 +    enum la_zaction action)
 +{
 +	if (lastrm->valid)
 +		return (lastrm->code(a, lastrm, action));
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_end(struct archive *a, struct la_zstream *lastrm)
 +{
 +	if (lastrm->valid) {
 +		lastrm->prop_size = 0;
 +		free(lastrm->props);
 +		lastrm->props = NULL;
 +		return (lastrm->end(a, lastrm));
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +
diff --cc Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c
index 0b9aaf9,0000000..e722625
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c
@@@ -1,8114 -1,0 +1,8148 @@@
 +/*-
-  * Copyright (c) 2009-2011 Michihiro NAKAJIMA
++ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "archive_platform.h"
 +
 +#ifdef HAVE_SYS_TYPES_H
 +#include <sys/types.h>
 +#endif
 +#ifdef HAVE_SYS_UTSNAME_H
 +#include <sys/utsname.h>
 +#endif
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_LIMITS_H
 +#include <limits.h>
 +#endif
 +#include <stdio.h>
 +#include <stdarg.h>
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#include <time.h>
 +#ifdef HAVE_UNISTD_H
 +#include <unistd.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_private.h"
 +#include "archive_rb.h"
 +#include "archive_write_private.h"
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +#define getuid()			0
 +#define getgid()			0
 +#endif
 +
 +/*#define DEBUG 1*/
 +#ifdef DEBUG
 +/* To compare to the ISO image file made by mkisofs. */
 +#define COMPAT_MKISOFS		1
 +#endif
 +
 +#define LOGICAL_BLOCK_BITS			11
 +#define LOGICAL_BLOCK_SIZE			2048
 +#define PATH_TABLE_BLOCK_SIZE			4096
 +
 +#define SYSTEM_AREA_BLOCK			16
 +#define PRIMARY_VOLUME_DESCRIPTOR_BLOCK 	1
 +#define SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK 	1
 +#define BOOT_RECORD_DESCRIPTOR_BLOCK	 	1
 +#define VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK	1
 +#define NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK	1
 +#define RRIP_ER_BLOCK				1
 +#define PADDING_BLOCK				150
 +
 +#define FD_1_2M_SIZE		(1024 * 1200)
 +#define FD_1_44M_SIZE		(1024 * 1440)
 +#define FD_2_88M_SIZE		(1024 * 2880)
 +#define MULTI_EXTENT_SIZE	(ARCHIVE_LITERAL_LL(1) << 32)	/* 4Gi bytes. */
 +#define MAX_DEPTH		8
 +#define RR_CE_SIZE		28		/* SUSP "CE" extension size */
 +
 +#define FILE_FLAG_EXISTENCE	0x01
 +#define FILE_FLAG_DIRECTORY	0x02
 +#define FILE_FLAG_ASSOCIATED	0x04
 +#define FILE_FLAG_RECORD	0x08
 +#define FILE_FLAG_PROTECTION	0x10
 +#define FILE_FLAG_MULTI_EXTENT	0x80
 +
 +static const char rrip_identifier[] =
 +	"RRIP_1991A";
 +static const char rrip_descriptor[] =
 +	"THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR "
 +	"POSIX FILE SYSTEM SEMANTICS";
 +static const char rrip_source[] =
 +	"PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  "
 +	"SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR "
 +	"CONTACT INFORMATION.";
 +#define RRIP_ER_ID_SIZE		(sizeof(rrip_identifier)-1)
 +#define RRIP_ER_DSC_SIZE	(sizeof(rrip_descriptor)-1)
 +#define RRIP_ER_SRC_SIZE	(sizeof(rrip_source)-1)
 +#define RRIP_ER_SIZE		(8 + RRIP_ER_ID_SIZE + \
 +				RRIP_ER_DSC_SIZE + RRIP_ER_SRC_SIZE)
 +
 +static const unsigned char zisofs_magic[8] = {
 +	0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07
 +};
 +
 +#define ZF_HEADER_SIZE	16	/* zisofs header size. */
 +#define ZF_LOG2_BS	15	/* log2 block size; 32K bytes. */
 +#define ZF_BLOCK_SIZE	(1UL << ZF_LOG2_BS)
 +
 +/*
 + * Manage extra records.
 + */
 +struct extr_rec {
 +	int		 location;
 +	int		 offset;
 +	unsigned char	 buf[LOGICAL_BLOCK_SIZE];
 +	struct extr_rec	*next;
 +};
 +
 +struct ctl_extr_rec {
 +	int		 use_extr;
 +	unsigned char	*bp;
 +	struct isoent	*isoent;
 +	unsigned char	*ce_ptr;
 +	int		 cur_len;
 +	int		 dr_len;
 +	int		 limit;
 +	int		 extr_off;
 +	int		 extr_loc;
 +};
 +#define DR_SAFETY	RR_CE_SIZE
 +#define DR_LIMIT	(254 - DR_SAFETY)
 +
 +/*
 + * The relation of struct isofile and isoent and archive_entry.
 + *
 + * Primary volume tree  --> struct isoent
 + *                                |
 + *                                v
 + *                          struct isofile --> archive_entry
 + *                                ^
 + *                                |
 + * Joliet volume tree   --> struct isoent
 + *
 + * struct isoent has specific information for volume.
 + */
 +
 +struct isofile {
 +	/* Used for managing struct isofile list. */
 +	struct isofile		*allnext;
 +	struct isofile		*datanext;
 +	/* Used for managing a hardlined struct isofile list. */
 +	struct isofile		*hlnext;
 +	struct isofile		*hardlink_target;
 +
 +	struct archive_entry	*entry;
 +
 +	/*
 +	 * Used for making a directory tree.
 +	 */
 +	struct archive_string	 parentdir;
 +	struct archive_string	 basename;
 +	struct archive_string	 basename_utf16;
 +	struct archive_string	 symlink;
 +	int			 dircnt;	/* The number of elements of
 +						 * its parent directory */
 +
 +	/*
 +	 * Used for a Directory Record.
 +	 */
 +	struct content {
 +		int64_t		 offset_of_temp;
 +		int64_t		 size;
 +		int		 blocks;
 +		uint32_t 	 location;
 +		/*
 +		 * One extent equals one content.
 +		 * If this entry has multi extent, `next' variable points
 +		 * next content data.
 +		 */
 +		struct content	*next;		/* next content	*/
 +	} content, *cur_content;
 +	int			 write_content;
 +
 +	enum {
 +		NO = 0,
 +		BOOT_CATALOG,
 +		BOOT_IMAGE
 +	} boot;
 +
 +	/*
 +	 * Used for a zisofs.
 +	 */
 +	struct {
 +		unsigned char	 header_size;
 +		unsigned char	 log2_bs;
 +		uint32_t	 uncompressed_size;
 +	} zisofs;
 +};
 +
 +struct isoent {
 +	/* Keep `rbnode' at the first member of struct isoent. */
 +	struct archive_rb_node	 rbnode;
 +
 +	struct isofile		*file;
 +
 +	struct isoent		*parent;
 +	/* A list of children.(use chnext) */
 +	struct {
 +		struct isoent	*first;
 +		struct isoent	**last;
 +		int		 cnt;
 +	}			 children;
 +	struct archive_rb_tree	 rbtree;
 +
 +	/* A list of sub directories.(use drnext) */
 +	struct {
 +		struct isoent	*first;
 +		struct isoent	**last;
 +		int		 cnt;
 +	}			 subdirs;
 +	/* A sorted list of sub directories. */
 +	struct isoent		**children_sorted;
 +	/* Used for managing struct isoent list. */
 +	struct isoent		*chnext;
 +	struct isoent		*drnext;
 +	struct isoent		*ptnext;
 +
 +	/*
 +	 * Used for making a Directory Record.
 +	 */
 +	int			 dir_number;
 +	struct {
 +		int		 vd;
 +		int		 self;
 +		int		 parent;
 +		int		 normal;
 +	}			 dr_len;
 +	uint32_t 		 dir_location;
 +	int			 dir_block;
 +
 +	/*
 +	 * Identifier:
 +	 *   on primary, ISO9660 file/directory name.
 +	 *   on joliet, UCS2 file/directory name.
 +	 * ext_off   : offset of identifier extension.
 +	 * ext_len   : length of identifier extension.
 +	 * id_len    : byte size of identifier.
 +	 *   on primary, this is ext_off + ext_len + version length.
 +	 *   on joliet, this is ext_off + ext_len.
 +	 * mb_len    : length of multibyte-character of identifier.
 +	 *   on primary, mb_len and id_len are always the same.
 +	 *   on joliet, mb_len and id_len are different.
 +	 */
 +	char			*identifier;
 +	int			 ext_off;
 +	int			 ext_len;
 +	int			 id_len;
 +	int			 mb_len;
 +
 +	/*
 +	 * Used for making a Rockridge extension.
 +	 * This is a part of Directory Records.
 +	 */
 +	struct isoent		*rr_parent;
 +	struct isoent		*rr_child;
 +
 +	/* Extra Record.(which we call in this source file)
 +	 * A maximum size of the Directory Record is 254.
 +	 * so, if generated RRIP data of a file cannot into a Directory
 +	 * Record because of its size, that surplus data relocate this
 +	 * Extra Record.
 +	 */
 +	struct {
 +		struct extr_rec	*first;
 +		struct extr_rec	**last;
 +		struct extr_rec	*current;
 +	}			 extr_rec_list;
 +
 +	int			 virtual:1;
 +	/* If set to one, this file type is a directory.
 +	 * A convenience flag to be used as
 +	 * "archive_entry_filetype(isoent->file->entry) == AE_IFDIR".
 +	 */
 +	int			 dir:1;
 +};
 +
 +struct hardlink {
 +	struct archive_rb_node	 rbnode;
 +	int			 nlink;
 +	struct {
 +		struct isofile	*first;
 +		struct isofile	**last;
 +	}			 file_list;
 +};
 +
 +/*
 + * ISO writer options
 + */
 +struct iso_option {
 +	/*
 +	 * Usage  : abstract-file=<value>
 +	 * Type   : string, max 37 bytes
 +	 * Default: Not specified
 +	 * COMPAT : mkisofs -abstract <value>
 +	 *
 +	 * Specifies Abstract Filename.
 +	 * This file shall be described in the Root Directory
 +	 * and containing a abstract statement.
 +	 */
 +	unsigned int	 abstract_file:1;
 +#define OPT_ABSTRACT_FILE_DEFAULT	0	/* Not specified */
 +#define ABSTRACT_FILE_SIZE		37
 +
 +	/*
 +	 * Usage  : application-id=<value>
 +	 * Type   : string, max 128 bytes
 +	 * Default: Not specified
 +	 * COMPAT : mkisofs -A/-appid <value>.
 +	 *
 +	 * Specifies Application Identifier.
 +	 * If the first byte is set to '_'(5F), the remaining
 +	 * bytes of this option shall specify an identifier
 +	 * for a file containing the identification of the
 +	 * application.
 +	 * This file shall be described in the Root Directory.
 +	 */
 +	unsigned int	 application_id:1;
 +#define OPT_APPLICATION_ID_DEFAULT	0	/* Use default identifier */
 +#define APPLICATION_IDENTIFIER_SIZE	128
 +
 +	/*
 +	 * Usage : !allow-vernum
 +	 * Type  : boolean
 +	 * Default: Enabled
 +	 *	  : Violates the ISO9660 standard if disable.
 +	 * COMPAT: mkisofs -N
 +	 *
 +	 * Allow filenames to use version numbers.
 +	 */
 +	unsigned int	 allow_vernum:1;
 +#define OPT_ALLOW_VERNUM_DEFAULT	1	/* Enabled */
 +
 +	/*
 +	 * Usage  : biblio-file=<value>
 +	 * Type   : string, max 37 bytes
 +	 * Default: Not specified
 +	 * COMPAT : mkisofs -biblio <value>
 +	 *
 +	 * Specifies Bibliographic Filename.
 +	 * This file shall be described in the Root Directory
 +	 * and containing bibliographic records.
 +	 */
 +	unsigned int	 biblio_file:1;
 +#define OPT_BIBLIO_FILE_DEFAULT		0	/* Not specified */
 +#define BIBLIO_FILE_SIZE		37
 +
 +	/*
 +	 * Usage  : boot=<value>
 +	 * Type   : string
 +	 * Default: Not specified
 +	 * COMPAT : mkisofs -b/-eltorito-boot <value>
 +	 *
 +	 * Specifies "El Torito" boot image file to make
 +	 * a bootable CD.
 +	 */
 +	unsigned int	 boot:1;
 +#define OPT_BOOT_DEFAULT		0	/* Not specified */
 +
 +	/*
 +	 * Usage  : boot-catalog=<value>
 +	 * Type   : string
 +	 * Default: "boot.catalog"
 +	 * COMPAT : mkisofs -c/-eltorito-catalog <value>
 +	 *
 +	 * Specifies a fullpath of El Torito boot catalog.
 +	 */
 +	unsigned int	 boot_catalog:1;
 +#define OPT_BOOT_CATALOG_DEFAULT	0	/* Not specified */
 +
 +	/*
 +	 * Usage  : boot-info-table
 +	 * Type   : boolean
 +	 * Default: Disabled
 +	 * COMPAT : mkisofs -boot-info-table
 +	 *
 +	 * Modify the boot image file specified by `boot'
 +	 * option; ISO writer stores boot file information
 +	 * into the boot file in ISO image at offset 8
 +	 * through offset 64.
 +	 */
 +	unsigned int	 boot_info_table:1;
 +#define OPT_BOOT_INFO_TABLE_DEFAULT	0	/* Disabled */
 +
 +	/*
 +	 * Usage  : boot-load-seg=<value>
 +	 * Type   : hexadecimal
 +	 * Default: Not specified
 +	 * COMPAT : mkisofs -boot-load-seg <value>
 +	 *
 +	 * Specifies a load segment for boot image.
 +	 * This is used with no-emulation mode.
 +	 */
 +	unsigned int	 boot_load_seg:1;
 +#define OPT_BOOT_LOAD_SEG_DEFAULT	0	/* Not specified */
 +
 +	/*
 +	 * Usage  : boot-load-size=<value>
 +	 * Type   : decimal
 +	 * Default: Not specified
 +	 * COMPAT : mkisofs -boot-load-size <value>
 +	 *
 +	 * Specifies a sector count for boot image.
 +	 * This is used with no-emulation mode.
 +	 */
 +	unsigned int	 boot_load_size:1;
 +#define OPT_BOOT_LOAD_SIZE_DEFAULT	0	/* Not specified */
 +
 +	/*
 +	 * Usage  : boot-type=<boot-media-type>
 +	 *        : 'no-emulation' : 'no emulation' image
 +	 *        :           'fd' : floppy disk image
 +	 *        :    'hard-disk' : hard disk image
 +	 * Type   : string
 +	 * Default: Auto detect
 +	 *        : We check a size of boot image;
 +	 *        : If ths size is just 1.22M/1.44M/2.88M,
 +	 *        : we assume boot_type is 'fd';
 +	 *        : otherwise boot_type is 'no-emulation'.
 +	 * COMPAT :
 +	 *    boot=no-emulation
 +	 *	mkisofs -no-emul-boot
 +	 *    boot=fd
 +	 *	This is a default on the mkisofs.
 +	 *    boot=hard-disk
 +	 *	mkisofs -hard-disk-boot
 +	 *
 +	 * Specifies a type of "El Torito" boot image.
 +	 */
 +	unsigned int	 boot_type:2;
 +#define OPT_BOOT_TYPE_AUTO		0	/* auto detect		  */
 +#define OPT_BOOT_TYPE_NO_EMU		1	/* ``no emulation'' image */
 +#define OPT_BOOT_TYPE_FD		2	/* floppy disk image	  */
 +#define OPT_BOOT_TYPE_HARD_DISK		3	/* hard disk image	  */
 +#define OPT_BOOT_TYPE_DEFAULT		OPT_BOOT_TYPE_AUTO
 +
 +	/*
 +	 * Usage  : compression-level=<value>
 +	 * Type   : decimal
 +	 * Default: Not specified
 +	 * COMPAT : NONE
 +	 *
 +	 * Specifies compression level for option zisofs=direct.
 +	 */
 +	unsigned int	 compression_level:1;
 +#define OPT_COMPRESSION_LEVEL_DEFAULT	0	/* Not specified */
 +
 +	/*
 +	 * Usage  : copyright-file=<value>
 +	 * Type   : string, max 37 bytes
 +	 * Default: Not specified
 +	 * COMPAT : mkisofs -copyright <value>
 +	 *
 +	 * Specifies Copyright Filename.
 +	 * This file shall be described in the Root Directory
 +	 * and containing a copyright statement.
 +	 */
 +	unsigned int	 copyright_file:1;
 +#define OPT_COPYRIGHT_FILE_DEFAULT	0	/* Not specified */
 +#define COPYRIGHT_FILE_SIZE		37
 +
 +	/*
 +	 * Usage  : gid=<value>
 +	 * Type   : decimal
 +	 * Default: Not specified
 +	 * COMPAT : mkisofs -gid <value>
 +	 *
 +	 * Specifies a group id to rewrite the group id of all files.
 +	 */
 +	unsigned int	 gid:1;
 +#define OPT_GID_DEFAULT			0	/* Not specified */
 +
 +	/*
 +	 * Usage  : iso-level=[1234]
 +	 * Type   : decimal
 +	 * Default: 1
 +	 * COMPAT : mkisofs -iso-level <value>
 +	 *
 +	 * Specifies ISO9600 Level.
 +	 * Level 1: [DEFAULT]
 +	 *   - limits each file size less than 4Gi bytes;
 +	 *   - a File Name shall not contain more than eight
 +	 *     d-characters or eight d1-characters;
 +	 *   - a File Name Extension shall not contain more than
 +	 *     three d-characters or three d1-characters;
 +	 *   - a Directory Identifier shall not contain more
 +	 *     than eight d-characters or eight d1-characters.
 +	 * Level 2:
 +	 *   - limits each file size less than 4Giga bytes;
 +	 *   - a File Name shall not contain more than thirty
 +	 *     d-characters or thirty d1-characters;
 +	 *   - a File Name Extension shall not contain more than
 +	 *     thirty d-characters or thirty d1-characters;
 +	 *   - a Directory Identifier shall not contain more
 +	 *     than thirty-one d-characters or thirty-one
 +	 *     d1-characters.
 +	 * Level 3:
 +	 *   - no limit of file size; use multi extent.
 +	 * Level 4:
 +	 *   - this level 4 simulates mkisofs option
 +	 *     '-iso-level 4';
 +	 *   - crate a enhanced volume as mkisofs doing;
 +	 *   - allow a File Name to have leading dot;
 +	 *   - allow a File Name to have all ASCII letters;
 +	 *   - allow a File Name to have multiple dots;
 +	 *   - allow more then 8 depths of directory trees;
 +	 *   - disable a version number to a File Name;
 +	 *   - disable a forced period to the tail of a File Name;
 +	 *   - the maxinum length of files and directories is raised to 193.
 +	 *     if rockridge option is disabled, raised to 207.
 +	 */
 +	unsigned int	 iso_level:3;
 +#define OPT_ISO_LEVEL_DEFAULT		1	/* ISO Level 1 */
 +
 +	/*
 +	 * Usage  : joliet[=long]
 +	 *        : !joliet
 +	 *        :   Do not generate Joliet Volume and Records.
 +	 *        : joliet [DEFAULT]
 +	 *        :   Generates Joliet Volume and Directory Records.
 +	 *        :   [COMPAT: mkisofs -J/-joliet]
 +	 *        : joliet=long
 +	 *        :   The joliet filenames are up to 103 Unicode
 +	 *        :   characters.
 +	 *        :   This option breaks the Joliet specification.
 +	 *        :   [COMPAT: mkisofs -J -joliet-long]
 +	 * Type   : boolean/string
 +	 * Default: Enabled
 +	 * COMPAT : mkisofs -J / -joliet-long
 +	 *
 +	 * Generates Joliet Volume and Directory Records.
 +	 */
 +	unsigned int	 joliet:2;
 +#define OPT_JOLIET_DISABLE		0	/* Not generate Joliet Records. */
 +#define OPT_JOLIET_ENABLE		1	/* Generate Joliet Records.  */
 +#define OPT_JOLIET_LONGNAME		2	/* Use long joliet filenames.*/
 +#define OPT_JOLIET_DEFAULT		OPT_JOLIET_ENABLE
 +
 +	/*
 +	 * Usage  : !limit-depth
 +	 * Type   : boolean
 +	 * Default: Enabled
 +	 *	  : Violates the ISO9660 standard if disable.
 +	 * COMPAT : mkisofs -D/-disable-deep-relocation
 +	 *
 +	 * The number of levels in hierarchy cannot exceed eight.
 +	 */
 +	unsigned int	 limit_depth:1;
 +#define OPT_LIMIT_DEPTH_DEFAULT		1	/* Enabled */
 +
 +	/*
 +	 * Usage  : !limit-dirs
 +	 * Type   : boolean
 +	 * Default: Enabled
 +	 *	  : Violates the ISO9660 standard if disable.
 +	 * COMPAT : mkisofs -no-limit-pathtables
 +	 *
 +	 * Limits the number of directories less than 65536 due
 +	 * to the size of the Parent Directory Number of Path
 +	 * Table.
 +	 */
 +	unsigned int	 limit_dirs:1;
 +#define OPT_LIMIT_DIRS_DEFAULT		1	/* Enabled */
 +
 +	/*
 +	 * Usage  : !pad
 +	 * Type   : boolean
 +	 * Default: Enabled
 +	 * COMPAT : -pad/-no-pad
 +	 *
 +	 * Pads the end of the ISO image by null of 300Ki bytes.
 +	 */
 +	unsigned int	 pad:1;
 +#define OPT_PAD_DEFAULT			1	/* Enabled */
 +
 +	/*
 +	 * Usage  : publisher=<value>
 +	 * Type   : string, max 128 bytes
 +	 * Default: Not specified
 +	 * COMPAT : mkisofs -publisher <value>
 +	 *
 +	 * Specifies Publisher Identifier.
 +	 * If the first byte is set to '_'(5F), the remaining
 +	 * bytes of this option shall specify an identifier
 +	 * for a file containing the identification of the user.
 +	 * This file shall be described in the Root Directory.
 +	 */
 +	unsigned int	 publisher:1;
 +#define OPT_PUBLISHER_DEFAULT		0	/* Not specified */
 +#define PUBLISHER_IDENTIFIER_SIZE	128
 +
 +	/*
 +	 * Usage  : rockridge
 +	 *        : !rockridge
 +	 *        :    disable to generate SUSP and RR records.
 +	 *        : rockridge
 +	 *        :    the same as 'rockridge=useful'.
 +	 *        : rockridge=strict
 +	 *        :    generate SUSP and RR records.
 +	 *        :    [COMPAT: mkisofs -R]
 +	 *        : rockridge=useful [DEFAULT]
 +	 *        :    generate SUSP and RR records.
 +	 *        :    [COMPAT: mkisofs -r]
 +	 *        :    NOTE  Our rockridge=useful option does not set a zero
 +	 *        :          to uid and gid, you should use application
 +	 *        :          option such as --gid,--gname,--uid and --uname
 +	 *        :          badtar options instead.
 +	 * Type   : boolean/string
 +	 * Default: Enabled as rockridge=useful
 +	 * COMPAT : mkisofs -r / -R
 +	 *
 +	 * Generates SUSP and RR records.
 +	 */
 +	unsigned int	 rr:2;
 +#define OPT_RR_DISABLED			0
 +#define OPT_RR_STRICT			1
 +#define OPT_RR_USEFUL			2
 +#define OPT_RR_DEFAULT			OPT_RR_USEFUL
 +
 +	/*
 +	 * Usage  : volume-id=<value>
 +	 * Type   : string, max 32 bytes
 +	 * Default: Not specified
 +	 * COMPAT : mkisofs -V <value>
 +	 *
 +	 * Specifies Volume Identifier.
 +	 */
 +	unsigned int	 volume_id:1;
 +#define OPT_VOLUME_ID_DEFAULT		0	/* Use default identifier */
 +#define VOLUME_IDENTIFIER_SIZE		32
 +
 +	/*
 +	 * Usage  : !zisofs [DEFAULT] 
 +	 *        :    Disable to generate RRIP 'ZF' extension.
 +	 *        : zisofs
 +	 *        :    Make files zisofs file and generate RRIP 'ZF'
 + 	 *        :    extension. So you do not need mkzftree utility
 +	 *        :    for making zisofs.
 +	 *        :    When the file size is less than one Logical Block
 +	 *        :    size, that file will not zisofs'ed since it does
 +	 *        :    reduece an ISO-image size.
 +	 *        :
 +	 *        :    When you specify option 'boot=<boot-image>', that
 +	 *        :    'boot-image' file won't be converted to zisofs file.
 +	 * Type   : boolean
 +	 * Default: Disabled
 +	 *
 +	 * Generates RRIP 'ZF' System Use Entry.
 +	 */
 +	unsigned int	 zisofs:1;
 +#define OPT_ZISOFS_DISABLED		0
 +#define OPT_ZISOFS_DIRECT		1
 +#define OPT_ZISOFS_DEFAULT		OPT_ZISOFS_DISABLED
 +
 +};
 +
 +struct iso9660 {
 +	/* The creation time of ISO image. */
 +	time_t			 birth_time;
 +	/* A file stream of a temporary file, which file contents
 +	 * save to until ISO iamge can be created. */
 +	int			 temp_fd;
 +
 +	struct isofile		*cur_file;
 +	struct isoent		*cur_dirent;
 +	struct archive_string	 cur_dirstr;
 +	uint64_t		 bytes_remaining;
 +	int			 need_multi_extent;
 +
 +	/* Temporary string buffer for Joliet extension. */ 
 +	struct archive_string	 utf16be;
 +	struct archive_string	 mbs;
 +
 +	struct archive_string_conv *sconv_to_utf16be;
 +	struct archive_string_conv *sconv_from_utf16be;
 +
 +	/* A list of all of struct isofile entries. */
 +	struct {
 +		struct isofile	*first;
 +		struct isofile	**last;
 +	}			 all_file_list;
 +
 +	/* A list of struct isofile entries which have its
 +	 * contents and are not a directory, a hardlined file
 +	 * and a symlink file. */
 +	struct {
 +		struct isofile	*first;
 +		struct isofile	**last;
 +	}			 data_file_list;
 +
 +	/* Used for managing to find hardlinking files. */
 +	struct archive_rb_tree	 hardlink_rbtree;
 +
 +	/* Used for making the Path Table Record. */
 +	struct vdd {
 +		/* the root of entry tree. */
 +		struct isoent	*rootent;
 +		enum vdd_type {
 +			VDD_PRIMARY,
 +			VDD_JOLIET,
 +			VDD_ENHANCED
 +		} vdd_type;
 +
 +		struct path_table {
 +			struct isoent		*first;
 +			struct isoent		**last;
 +			struct isoent		**sorted;
 +			int			 cnt;
 +		} *pathtbl;
 +		int				 max_depth;
 +
 +		int		 path_table_block;
 +		int		 path_table_size;
 +		int		 location_type_L_path_table;
 +		int		 location_type_M_path_table;
 +		int		 total_dir_block;
 +	} primary, joliet;
 +
 +	/* Used for making a Volume Descriptor. */
 +	int			 volume_space_size;
 +	int			 volume_sequence_number;
 +	int			 total_file_block;
 +	struct archive_string	 volume_identifier;
 +	struct archive_string	 publisher_identifier;
 +	struct archive_string	 data_preparer_identifier;
 +	struct archive_string	 application_identifier;
 +	struct archive_string	 copyright_file_identifier;
 +	struct archive_string	 abstract_file_identifier;
 +	struct archive_string	 bibliographic_file_identifier;
 +
 +	/* Used for making rockridge extensions. */
 +	int			 location_rrip_er;
 +
 +	/* Used for making zisofs. */
 +	struct {
 +		int		 detect_magic:1;
 +		int		 making:1;
 +		int		 allzero:1;
 +		unsigned char	 magic_buffer[64];
 +		int		 magic_cnt;
 +
 +#ifdef HAVE_ZLIB_H
 +		/*
 +		 * Copy a compressed file to iso9660.zisofs.temp_fd
 +		 * and also copy a uncompressed file(original file) to
 +		 * iso9660.temp_fd . If the number of logical block
 +		 * of the compressed file is less than the number of
 +		 * logical block of the uncompressed file, use it and
 +		 * remove the copy of the uncompressed file.
 +		 * but if not, we use uncompressed file and remove
 +		 * the copy of the compressed file.
 +		 */
 +		uint32_t	*block_pointers;
 +		size_t		 block_pointers_allocated;
 +		int		 block_pointers_cnt;
 +		int		 block_pointers_idx;
 +		int64_t		 total_size;
 +		int64_t		 block_offset;
 +
 +		z_stream	 stream;
 +		int		 stream_valid;
 +		int64_t		 remaining;
 +		int		 compression_level;
 +#endif
 +	} zisofs;
 +
 +	struct isoent		*directories_too_deep;
 +	int			 dircnt_max;
 +
 +	/* Write buffer. */
 +#define wb_buffmax()	(LOGICAL_BLOCK_SIZE * 32)
 +#define wb_remaining(a)	(((struct iso9660 *)(a)->format_data)->wbuff_remaining)
 +#define wb_offset(a)	(((struct iso9660 *)(a)->format_data)->wbuff_offset \
 +		+ wb_buffmax() - wb_remaining(a))
 +	unsigned char		 wbuff[LOGICAL_BLOCK_SIZE * 32];
 +	size_t			 wbuff_remaining;
 +	enum {
 +		WB_TO_STREAM,
 +		WB_TO_TEMP
 +	} 			 wbuff_type;
 +	int64_t			 wbuff_offset;
 +	int64_t			 wbuff_written;
 +	int64_t			 wbuff_tail;
 +
 +	/* 'El Torito' boot data. */
 +	struct {
 +		/* boot catalog file */
 +		struct archive_string	 catalog_filename;
 +		struct isoent		*catalog;
 +		/* boot image file */
 +		struct archive_string	 boot_filename;
 +		struct isoent		*boot;
 +
 +		unsigned char		 platform_id;
 +#define BOOT_PLATFORM_X86	0
 +#define BOOT_PLATFORM_PPC	1
 +#define BOOT_PLATFORM_MAC	2
 +		struct archive_string	 id;
 +		unsigned char		 media_type;
 +#define BOOT_MEDIA_NO_EMULATION		0
 +#define BOOT_MEDIA_1_2M_DISKETTE	1
 +#define BOOT_MEDIA_1_44M_DISKETTE	2
 +#define BOOT_MEDIA_2_88M_DISKETTE	3
 +#define BOOT_MEDIA_HARD_DISK		4
 +		unsigned char		 system_type;
 +		uint16_t		 boot_load_seg;
 +		uint16_t		 boot_load_size;
 +#define BOOT_LOAD_SIZE		4
 +	} el_torito;
 +
 +	struct iso_option	 opt;
 +};
 +
 +/*
 + * Types of Volume Descriptor
 + */
 +enum VD_type {
 +	VDT_BOOT_RECORD=0,	/* Boot Record Volume Descriptor 	*/
 +	VDT_PRIMARY=1,		/* Primary Volume Descriptor		*/
 +	VDT_SUPPLEMENTARY=2,	/* Supplementary Volume Descriptor	*/
 +	VDT_TERMINATOR=255	/* Volume Descriptor Set Terminator	*/
 +};
 +
 +/*
 + * Types of Directory Record
 + */
 +enum dir_rec_type {
 +	DIR_REC_VD,		/* Stored in Volume Descriptor.	*/
 +	DIR_REC_SELF,		/* Stored as Current Directory.	*/
 +	DIR_REC_PARENT,		/* Stored as Parent Directory.	*/
 +	DIR_REC_NORMAL 		/* Stored as Child.		*/
 +};
 +
 +/*
 + * Kinds of Volume Descriptor Character
 + */
 +enum vdc {
 +	VDC_STD,
 +	VDC_LOWERCASE,
 +	VDC_UCS2,
 +	VDC_UCS2_DIRECT
 +};
 +
 +/*
 + * IDentifier Resolver.
 + * Used for resolving duplicated filenames.
 + */
 +struct idr {
 +	struct idrent {
 +		struct archive_rb_node	rbnode;
 +		/* Used in wait_list. */
 +		struct idrent		*wnext;
 +		struct idrent		*avail;
 +
 +		struct isoent		*isoent;
 +		int			 weight;
 +		int			 noff;
 +		int			 rename_num;
 +	} *idrent_pool;
 +
 +	struct archive_rb_tree		 rbtree;
 +
 +	struct {
 +		struct idrent		*first;
 +		struct idrent		**last;
 +	} wait_list;
 +
 +	int				 pool_size;
 +	int				 pool_idx;
 +	int				 num_size;
 +	int				 null_size;
 +
 +	char				 char_map[0x80];
 +};
 +
 +enum char_type {
 +	A_CHAR,
 +	D_CHAR
 +};
 +
 +
 +static int	iso9660_options(struct archive_write *,
 +		    const char *, const char *);
 +static int	iso9660_write_header(struct archive_write *,
 +		    struct archive_entry *);
 +static ssize_t	iso9660_write_data(struct archive_write *,
 +		    const void *, size_t);
 +static int	iso9660_finish_entry(struct archive_write *);
 +static int	iso9660_close(struct archive_write *);
 +static int	iso9660_free(struct archive_write *);
 +
 +static void	get_system_identitier(char *, size_t);
 +static void	set_str(unsigned char *, const char *, size_t, char,
 +		    const char *);
 +static inline int joliet_allowed_char(unsigned char, unsigned char);
 +static int	set_str_utf16be(struct archive_write *, unsigned char *,
 +			const char *, size_t, uint16_t, enum vdc);
 +static int	set_str_a_characters_bp(struct archive_write *,
 +			unsigned char *, int, int, const char *, enum vdc);
 +static int	set_str_d_characters_bp(struct archive_write *,
 +			unsigned char *, int, int, const char *, enum  vdc);
 +static void	set_VD_bp(unsigned char *, enum VD_type, unsigned char);
 +static inline void set_unused_field_bp(unsigned char *, int, int);
 +
 +static unsigned char *extra_open_record(unsigned char *, int,
 +		    struct isoent *, struct ctl_extr_rec *);
 +static void	extra_close_record(struct ctl_extr_rec *, int);
 +static unsigned char * extra_next_record(struct ctl_extr_rec *, int);
 +static unsigned char *extra_get_record(struct isoent *, int *, int *, int *);
 +static void	extra_tell_used_size(struct ctl_extr_rec *, int);
 +static int	extra_setup_location(struct isoent *, int);
 +static int	set_directory_record_rr(unsigned char *, int,
 +		    struct isoent *, struct iso9660 *, enum dir_rec_type);
 +static int	set_directory_record(unsigned char *, size_t,
 +		    struct isoent *, struct iso9660 *, enum dir_rec_type,
 +		    enum vdd_type);
 +static inline int get_dir_rec_size(struct iso9660 *, struct isoent *,
 +		    enum dir_rec_type, enum vdd_type);
 +static inline unsigned char *wb_buffptr(struct archive_write *);
 +static int	wb_write_out(struct archive_write *);
 +static int	wb_consume(struct archive_write *, size_t);
 +#ifdef HAVE_ZLIB_H
 +static int	wb_set_offset(struct archive_write *, int64_t);
 +#endif
 +static int	write_null(struct archive_write *, size_t);
 +static int	write_VD_terminator(struct archive_write *);
 +static int	set_file_identifier(unsigned char *, int, int, enum vdc,
 +		    struct archive_write *, struct vdd *,
 +		    struct archive_string *, const char *, int,
 +		    enum char_type);
 +static int	write_VD(struct archive_write *, struct vdd *);
 +static int	write_VD_boot_record(struct archive_write *);
 +static int	write_information_block(struct archive_write *);
 +static int	write_path_table(struct archive_write *, int,
 +		    struct vdd *);
 +static int	write_directory_descriptors(struct archive_write *,
 +		    struct vdd *);
 +static int	write_file_descriptors(struct archive_write *);
 +static int	write_rr_ER(struct archive_write *);
 +static void	calculate_path_table_size(struct vdd *);
 +
 +static void	isofile_init_entry_list(struct iso9660 *);
 +static void	isofile_add_entry(struct iso9660 *, struct isofile *);
 +static void	isofile_free_all_entries(struct iso9660 *);
 +static void	isofile_init_entry_data_file_list(struct iso9660 *);
 +static void	isofile_add_data_file(struct iso9660 *, struct isofile *);
 +static struct isofile * isofile_new(struct archive_write *,
 +		    struct archive_entry *);
 +static void	isofile_free(struct isofile *);
 +static int	isofile_gen_utility_names(struct archive_write *,
 +		    struct isofile *);
 +static int	isofile_register_hardlink(struct archive_write *,
 +		    struct isofile *);
 +static void	isofile_connect_hardlink_files(struct iso9660 *);
 +static void	isofile_init_hardlinks(struct iso9660 *);
 +static void	isofile_free_hardlinks(struct iso9660 *);
 +
 +static struct isoent *isoent_new(struct isofile *);
 +static int	isoent_clone_tree(struct archive_write *,
 +		    struct isoent **, struct isoent *);
 +static void	_isoent_free(struct isoent *isoent);
 +static void	isoent_free_all(struct isoent *);
 +static struct isoent * isoent_create_virtual_dir(struct archive_write *,
 +		    struct iso9660 *, const char *);
 +static int	isoent_cmp_node(const struct archive_rb_node *,
 +		    const struct archive_rb_node *);
 +static int	isoent_cmp_key(const struct archive_rb_node *,
 +		    const void *);
 +static int	isoent_add_child_head(struct isoent *, struct isoent *);
 +static int	isoent_add_child_tail(struct isoent *, struct isoent *);
 +static void	isoent_remove_child(struct isoent *, struct isoent *);
 +static void	isoent_setup_directory_location(struct iso9660 *,
 +		    int, struct vdd *);
 +static void	isoent_setup_file_location(struct iso9660 *, int);
- static int	get_path_component(char *, int, const char *);
++static int	get_path_component(char *, size_t, const char *);
 +static int	isoent_tree(struct archive_write *, struct isoent **);
 +static struct isoent *isoent_find_child(struct isoent *, const char *);
 +static struct isoent *isoent_find_entry(struct isoent *, const char *);
 +static void	idr_relaxed_filenames(char *);
 +static void	idr_init(struct iso9660 *, struct vdd *, struct idr *);
 +static void	idr_cleanup(struct idr *);
 +static int	idr_ensure_poolsize(struct archive_write *, struct idr *,
 +		    int);
 +static int	idr_start(struct archive_write *, struct idr *,
 +		    int, int, int, int, const struct archive_rb_tree_ops *);
 +static void	idr_register(struct idr *, struct isoent *, int,
 +		    int);
 +static void	idr_extend_identifier(struct idrent *, int, int);
 +static void	idr_resolve(struct idr *, void (*)(unsigned char *, int));
 +static void	idr_set_num(unsigned char *, int);
 +static void	idr_set_num_beutf16(unsigned char *, int);
 +static int	isoent_gen_iso9660_identifier(struct archive_write *,
 +		    struct isoent *, struct idr *);
 +static int	isoent_gen_joliet_identifier(struct archive_write *,
 +		    struct isoent *, struct idr *);
 +static int	isoent_cmp_iso9660_identifier(const struct isoent *,
 +		    const struct isoent *);
 +static int	isoent_cmp_node_iso9660(const struct archive_rb_node *,
 +		    const struct archive_rb_node *);
 +static int	isoent_cmp_key_iso9660(const struct archive_rb_node *,
 +		    const void *);
 +static int	isoent_cmp_joliet_identifier(const struct isoent *,
 +		    const struct isoent *);
 +static int	isoent_cmp_node_joliet(const struct archive_rb_node *,
 +		    const struct archive_rb_node *);
 +static int	isoent_cmp_key_joliet(const struct archive_rb_node *,
 +		    const void *);
 +static inline void path_table_add_entry(struct path_table *, struct isoent *);
 +static inline struct isoent * path_table_last_entry(struct path_table *);
 +static int	isoent_make_path_table(struct archive_write *);
 +static int	isoent_find_out_boot_file(struct archive_write *,
 +		    struct isoent *);
 +static int	isoent_create_boot_catalog(struct archive_write *,
 +		    struct isoent *);
 +static size_t	fd_boot_image_size(int);
 +static int	make_boot_catalog(struct archive_write *);
 +static int	setup_boot_information(struct archive_write *);
 +
 +static int	zisofs_init(struct archive_write *, struct isofile *);
 +static void	zisofs_detect_magic(struct archive_write *,
 +		    const void *, size_t);
 +static int	zisofs_write_to_temp(struct archive_write *,
 +		    const void *, size_t);
 +static int	zisofs_finish_entry(struct archive_write *);
 +static int	zisofs_rewind_boot_file(struct archive_write *);
 +static int	zisofs_free(struct archive_write *);
 +
 +int
 +archive_write_set_format_iso9660(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct iso9660 *iso9660;
 +
 +	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_set_format_iso9660");
 +
 +	/* If another format was already registered, unregister it. */
 +	if (a->format_free != NULL)
 +		(a->format_free)(a);
 +
 +	iso9660 = calloc(1, sizeof(*iso9660));
 +	if (iso9660 == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate iso9660 data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	iso9660->birth_time = 0;
 +	iso9660->temp_fd = -1;
 +	iso9660->cur_file = NULL;
 +	iso9660->primary.max_depth = 0;
 +	iso9660->primary.vdd_type = VDD_PRIMARY;
 +	iso9660->primary.pathtbl = NULL;
 +	iso9660->joliet.rootent = NULL;
 +	iso9660->joliet.max_depth = 0;
 +	iso9660->joliet.vdd_type = VDD_JOLIET;
 +	iso9660->joliet.pathtbl = NULL;
 +	isofile_init_entry_list(iso9660);
 +	isofile_init_entry_data_file_list(iso9660);
 +	isofile_init_hardlinks(iso9660);
 +	iso9660->directories_too_deep = NULL;
 +	iso9660->dircnt_max = 1;
 +	iso9660->wbuff_remaining = wb_buffmax();
 +	iso9660->wbuff_type = WB_TO_TEMP;
 +	iso9660->wbuff_offset = 0;
 +	iso9660->wbuff_written = 0;
 +	iso9660->wbuff_tail = 0;
 +	archive_string_init(&(iso9660->utf16be));
 +	archive_string_init(&(iso9660->mbs));
 +
 +	/*
 +	 * Init Identifiers used for PVD and SVD.
 +	 */
 +	archive_string_init(&(iso9660->volume_identifier));
 +	archive_strcpy(&(iso9660->volume_identifier), "CDROM");
 +	archive_string_init(&(iso9660->publisher_identifier));
 +	archive_string_init(&(iso9660->data_preparer_identifier));
 +	archive_string_init(&(iso9660->application_identifier));
 +	archive_strcpy(&(iso9660->application_identifier),
 +	    archive_version_string());
 +	archive_string_init(&(iso9660->copyright_file_identifier));
 +	archive_string_init(&(iso9660->abstract_file_identifier));
 +	archive_string_init(&(iso9660->bibliographic_file_identifier));
 +
 +	/*
 +	 * Init El Torito bootable CD variables.
 +	 */
 +	archive_string_init(&(iso9660->el_torito.catalog_filename));
 +	iso9660->el_torito.catalog = NULL;
 +	/* Set default file name of boot catalog  */
 +	archive_strcpy(&(iso9660->el_torito.catalog_filename),
 +	    "boot.catalog");
 +	archive_string_init(&(iso9660->el_torito.boot_filename));
 +	iso9660->el_torito.boot = NULL;
 +	iso9660->el_torito.platform_id = BOOT_PLATFORM_X86;
 +	archive_string_init(&(iso9660->el_torito.id));
 +	iso9660->el_torito.boot_load_seg = 0;
 +	iso9660->el_torito.boot_load_size = BOOT_LOAD_SIZE;
 +
 +	/*
 +	 * Init zisofs variables.
 +	 */
 +#ifdef HAVE_ZLIB_H
 +	iso9660->zisofs.block_pointers = NULL;
 +	iso9660->zisofs.block_pointers_allocated = 0;
 +	iso9660->zisofs.stream_valid = 0;
 +	iso9660->zisofs.compression_level = 9;
 +	memset(&(iso9660->zisofs.stream), 0,
 +	    sizeof(iso9660->zisofs.stream));
 +#endif
 +
 +	/*
 +	 * Set default value of iso9660 options.
 +	 */
 +	iso9660->opt.abstract_file = OPT_ABSTRACT_FILE_DEFAULT;
 +	iso9660->opt.application_id = OPT_APPLICATION_ID_DEFAULT;
 +	iso9660->opt.allow_vernum = OPT_ALLOW_VERNUM_DEFAULT;
 +	iso9660->opt.biblio_file = OPT_BIBLIO_FILE_DEFAULT;
 +	iso9660->opt.boot = OPT_BOOT_DEFAULT;
 +	iso9660->opt.boot_catalog = OPT_BOOT_CATALOG_DEFAULT;
 +	iso9660->opt.boot_info_table = OPT_BOOT_INFO_TABLE_DEFAULT;
 +	iso9660->opt.boot_load_seg = OPT_BOOT_LOAD_SEG_DEFAULT;
 +	iso9660->opt.boot_load_size = OPT_BOOT_LOAD_SIZE_DEFAULT;
 +	iso9660->opt.boot_type = OPT_BOOT_TYPE_DEFAULT;
 +	iso9660->opt.compression_level = OPT_COMPRESSION_LEVEL_DEFAULT;
 +	iso9660->opt.copyright_file = OPT_COPYRIGHT_FILE_DEFAULT;
 +	iso9660->opt.iso_level = OPT_ISO_LEVEL_DEFAULT;
 +	iso9660->opt.joliet = OPT_JOLIET_DEFAULT;
 +	iso9660->opt.limit_depth = OPT_LIMIT_DEPTH_DEFAULT;
 +	iso9660->opt.limit_dirs = OPT_LIMIT_DIRS_DEFAULT;
 +	iso9660->opt.pad = OPT_PAD_DEFAULT;
 +	iso9660->opt.publisher = OPT_PUBLISHER_DEFAULT;
 +	iso9660->opt.rr = OPT_RR_DEFAULT;
 +	iso9660->opt.volume_id = OPT_VOLUME_ID_DEFAULT;
 +	iso9660->opt.zisofs = OPT_ZISOFS_DEFAULT;
 +
 +	/* Create the root directory. */
 +	iso9660->primary.rootent =
 +	    isoent_create_virtual_dir(a, iso9660, "");
 +	if (iso9660->primary.rootent == NULL) {
 +		free(iso9660);
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	iso9660->primary.rootent->parent = iso9660->primary.rootent;
 +	iso9660->cur_dirent = iso9660->primary.rootent;
 +	archive_string_init(&(iso9660->cur_dirstr));
 +	archive_string_ensure(&(iso9660->cur_dirstr), 1);
 +	iso9660->cur_dirstr.s[0] = 0;
 +	iso9660->sconv_to_utf16be = NULL;
 +	iso9660->sconv_from_utf16be = NULL;
 +
 +	a->format_data = iso9660;
 +	a->format_name = "iso9660";
 +	a->format_options = iso9660_options;
 +	a->format_write_header = iso9660_write_header;
 +	a->format_write_data = iso9660_write_data;
 +	a->format_finish_entry = iso9660_finish_entry;
 +	a->format_close = iso9660_close;
 +	a->format_free = iso9660_free;
 +	a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
 +	a->archive.archive_format_name = "ISO9660";
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +get_str_opt(struct archive_write *a, struct archive_string *s,
 +    size_t maxsize, const char *key, const char *value)
 +{
 +
 +	if (strlen(value) > maxsize) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Value is longer than %zu characters "
 +		    "for option ``%s''", maxsize, key);
 +		return (ARCHIVE_FATAL);
 +	}
 +	archive_strcpy(s, value);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +get_num_opt(struct archive_write *a, int *num, int high, int low,
 +    const char *key, const char *value)
 +{
 +	const char *p = value;
 +	int data = 0;
 +	int neg = 0;
 +
 +	if (p == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid value(empty) for option ``%s''", key);
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (*p == '-') {
 +		neg = 1;
 +		p++;
 +	}
 +	while (*p) {
 +		if (*p >= '0' && *p <= '9')
 +			data = data * 10 + *p - '0';
 +		else {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Invalid value for option ``%s''", key);
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (data > high) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Invalid value(over %d) for "
 +			    "option ``%s''", high, key);
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (data < low) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Invalid value(under %d) for "
 +			    "option ``%s''", low, key);
 +			return (ARCHIVE_FATAL);
 +		}
 +		p++;
 +	}
 +	if (neg)
 +		data *= -1;
 +	*num = data;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +iso9660_options(struct archive_write *a, const char *key, const char *value)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	const char *p;
 +	int r;
 +
 +	switch (key[0]) {
 +	case 'a':
 +		if (strcmp(key, "abstract-file") == 0) {
 +			r = get_str_opt(a,
 +			    &(iso9660->abstract_file_identifier),
 +			    ABSTRACT_FILE_SIZE, key, value);
 +			iso9660->opt.abstract_file = r == ARCHIVE_OK;
 +			return (r);
 +		}
 +		if (strcmp(key, "application-id") == 0) {
 +			r = get_str_opt(a,
 +			    &(iso9660->application_identifier),
 +			    APPLICATION_IDENTIFIER_SIZE, key, value);
 +			iso9660->opt.application_id = r == ARCHIVE_OK;
 +			return (r);
 +		}
 +		if (strcmp(key, "allow-vernum") == 0) {
 +			iso9660->opt.allow_vernum = value != NULL;
 +			return (ARCHIVE_OK);
 +		}
 +		break;
 +	case 'b':
 +		if (strcmp(key, "biblio-file") == 0) {
 +			r = get_str_opt(a,
 +			    &(iso9660->bibliographic_file_identifier),
 +			    BIBLIO_FILE_SIZE, key, value);
 +			iso9660->opt.biblio_file = r == ARCHIVE_OK;
 +			return (r);
 +		}
 +		if (strcmp(key, "boot") == 0) {
 +			if (value == NULL)
 +				iso9660->opt.boot = 0;
 +			else {
 +				iso9660->opt.boot = 1;
 +				archive_strcpy(
 +				    &(iso9660->el_torito.boot_filename),
 +				    value);
 +			}
 +			return (ARCHIVE_OK);
 +		}
 +		if (strcmp(key, "boot-catalog") == 0) {
 +			r = get_str_opt(a,
 +			    &(iso9660->el_torito.catalog_filename),
 +			    1024, key, value);
 +			iso9660->opt.boot_catalog = r == ARCHIVE_OK;
 +			return (r);
 +		}
 +		if (strcmp(key, "boot-info-table") == 0) {
 +			iso9660->opt.boot_info_table = value != NULL;
 +			return (ARCHIVE_OK);
 +		}
 +		if (strcmp(key, "boot-load-seg") == 0) {
 +			uint32_t seg;
 +
 +			iso9660->opt.boot_load_seg = 0;
 +			if (value == NULL)
 +				goto invalid_value;
 +			seg = 0;
 +			p = value;
 +			if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
 +				p += 2;
 +			while (*p) {
 +				if (seg)
 +					seg <<= 4;
 +				if (*p >= 'A' && *p <= 'F')
 +					seg += *p - 'A' + 0x0a;
 +				else if (*p >= 'a' && *p <= 'f')
 +					seg += *p - 'a' + 0x0a;
 +				else if (*p >= '0' && *p <= '9')
 +					seg += *p - '0';
 +				else
 +					goto invalid_value;
 +				if (seg > 0xffff) {
 +					archive_set_error(&a->archive,
 +					    ARCHIVE_ERRNO_MISC,
 +					    "Invalid value(over 0xffff) for "
 +					    "option ``%s''", key);
 +					return (ARCHIVE_FATAL);
 +				}
 +				p++;
 +			}
 +			iso9660->el_torito.boot_load_seg = (uint16_t)seg;
 +			iso9660->opt.boot_load_seg = 1;
 +			return (ARCHIVE_OK);
 +		}
 +		if (strcmp(key, "boot-load-size") == 0) {
 +			int num = 0;
 +			r = get_num_opt(a, &num, 0xffff, 1, key, value);
 +			iso9660->opt.boot_load_size = r == ARCHIVE_OK;
 +			if (r != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			iso9660->el_torito.boot_load_size = (uint16_t)num;
 +			return (ARCHIVE_OK);
 +		}
 +		if (strcmp(key, "boot-type") == 0) {
 +			if (value == NULL)
 +				goto invalid_value;
 +			if (strcmp(value, "no-emulation") == 0)
 +				iso9660->opt.boot_type = OPT_BOOT_TYPE_NO_EMU;
 +			else if (strcmp(value, "fd") == 0)
 +				iso9660->opt.boot_type = OPT_BOOT_TYPE_FD;
 +			else if (strcmp(value, "hard-disk") == 0)
 +				iso9660->opt.boot_type = OPT_BOOT_TYPE_HARD_DISK;
 +			else
 +				goto invalid_value;
 +			return (ARCHIVE_OK);
 +		}
 +		break;
 +	case 'c':
 +		if (strcmp(key, "compression-level") == 0) {
 +#ifdef HAVE_ZLIB_H
 +			if (value == NULL ||
 +			    !(value[0] >= '0' && value[0] <= '9') ||
 +			    value[1] != '\0')
 +				goto invalid_value;
 +                	iso9660->zisofs.compression_level = value[0] - '0';
 +			iso9660->opt.compression_level = 1;
 +                	return (ARCHIVE_OK);
 +#else
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Option ``%s'' "
 +			    "is not supported on this platform.", key);
 +			return (ARCHIVE_FATAL);
 +#endif
 +		}
 +		if (strcmp(key, "copyright-file") == 0) {
 +			r = get_str_opt(a,
 +			    &(iso9660->copyright_file_identifier),
 +			    COPYRIGHT_FILE_SIZE, key, value);
 +			iso9660->opt.copyright_file = r == ARCHIVE_OK;
 +			return (r);
 +		}
 +#ifdef DEBUG
 +		/* Specifies Volume creation date and time;
 +		 * year(4),month(2),day(2),hour(2),minute(2),second(2).
 +		 * e.g. "20090929033757"
 +		 */
 +		if (strcmp(key, "creation") == 0) {
 +			struct tm tm;
 +			char buf[5];
 +
 +			p = value;
 +			if (p == NULL || strlen(p) < 14)
 +				goto invalid_value;
 +			memset(&tm, 0, sizeof(tm));
 +			memcpy(buf, p, 4); buf[4] = '\0'; p += 4;
 +			tm.tm_year = strtol(buf, NULL, 10) - 1900;
 +			memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
 +			tm.tm_mon = strtol(buf, NULL, 10) - 1;
 +			memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
 +			tm.tm_mday = strtol(buf, NULL, 10);
 +			memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
 +			tm.tm_hour = strtol(buf, NULL, 10);
 +			memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
 +			tm.tm_min = strtol(buf, NULL, 10);
 +			memcpy(buf, p, 2); buf[2] = '\0';
 +			tm.tm_sec = strtol(buf, NULL, 10);
 +			iso9660->birth_time = mktime(&tm);
 +			return (ARCHIVE_OK);
 +		}
 +#endif
 +		break;
 +	case 'i':
 +		if (strcmp(key, "iso-level") == 0) {
 +			if (value != NULL && value[1] == '\0' &&
 +			    (value[0] >= '1' && value[0] <= '4')) {
 +				iso9660->opt.iso_level = value[0]-'0';
 +				return (ARCHIVE_OK);
 +			}
 +			goto invalid_value;
 +		}
 +		break;
 +	case 'j':
 +		if (strcmp(key, "joliet") == 0) {
 +			if (value == NULL)
 +				iso9660->opt.joliet = OPT_JOLIET_DISABLE;
 +			else if (strcmp(value, "1") == 0)
 +				iso9660->opt.joliet = OPT_JOLIET_ENABLE;
 +			else if (strcmp(value, "long") == 0)
 +				iso9660->opt.joliet = OPT_JOLIET_LONGNAME;
 +			else
 +				goto invalid_value;
 +			return (ARCHIVE_OK);
 +		}
 +		break;
 +	case 'l':
 +		if (strcmp(key, "limit-depth") == 0) {
 +			iso9660->opt.limit_depth = value != NULL;
 +			return (ARCHIVE_OK);
 +		}
 +		if (strcmp(key, "limit-dirs") == 0) {
 +			iso9660->opt.limit_dirs = value != NULL;
 +			return (ARCHIVE_OK);
 +		}
 +		break;
 +	case 'p':
 +		if (strcmp(key, "pad") == 0) {
 +			iso9660->opt.pad = value != NULL;
 +			return (ARCHIVE_OK);
 +		}
 +		if (strcmp(key, "publisher") == 0) {
 +			r = get_str_opt(a,
 +			    &(iso9660->publisher_identifier),
 +			    PUBLISHER_IDENTIFIER_SIZE, key, value);
 +			iso9660->opt.publisher = r == ARCHIVE_OK;
 +			return (r);
 +		}
 +		break;
 +	case 'r':
 +		if (strcmp(key, "rockridge") == 0 ||
 +		    strcmp(key, "Rockridge") == 0) {
 +			if (value == NULL)
 +				iso9660->opt.rr = OPT_RR_DISABLED;
 +			else if (strcmp(value, "1") == 0)
 +				iso9660->opt.rr = OPT_RR_USEFUL;
 +			else if (strcmp(value, "strict") == 0)
 +				iso9660->opt.rr = OPT_RR_STRICT;
 +			else if (strcmp(value, "useful") == 0)
 +				iso9660->opt.rr = OPT_RR_USEFUL;
 +			else
 +				goto invalid_value;
 +			return (ARCHIVE_OK);
 +		}
 +		break;
 +	case 'v':
 +		if (strcmp(key, "volume-id") == 0) {
 +			r = get_str_opt(a, &(iso9660->volume_identifier),
 +			    VOLUME_IDENTIFIER_SIZE, key, value);
 +			iso9660->opt.volume_id = r == ARCHIVE_OK;
 +			return (r);
 +		}
 +		break;
 +	case 'z':
 +		if (strcmp(key, "zisofs") == 0) {
 +			if (value == NULL)
 +				iso9660->opt.zisofs = OPT_ZISOFS_DISABLED;
 +			else {
 +#ifdef HAVE_ZLIB_H
 +				iso9660->opt.zisofs = OPT_ZISOFS_DIRECT;
 +#else
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "``zisofs'' "
 +				    "is not supported on this platform.");
 +				return (ARCHIVE_FATAL);
 +#endif
 +			}
 +			return (ARCHIVE_OK);
 +		}
 +		break;
 +	}
 +
++	/* Note: The "warn" return is just to inform the options
++	 * supervisor that we didn't handle it.  It will generate
++	 * a suitable error if no one used this option. */
++	return (ARCHIVE_WARN);
++
 +invalid_value:
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +	    "Invalid value for option ``%s''", key);
 +	return (ARCHIVE_FAILED);
 +}
 +
 +static int
 +iso9660_write_header(struct archive_write *a, struct archive_entry *entry)
 +{
 +	struct iso9660 *iso9660;
 +	struct isofile *file;
 +	struct isoent *isoent;
 +	int r, ret = ARCHIVE_OK;
 +
 +	iso9660 = a->format_data;
 +
 +	iso9660->cur_file = NULL;
 +	iso9660->bytes_remaining = 0;
 +	iso9660->need_multi_extent = 0;
 +	if (archive_entry_filetype(entry) == AE_IFLNK
 +	    && iso9660->opt.rr == OPT_RR_DISABLED) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Ignore symlink file.");
 +		iso9660->cur_file = NULL;
 +		return (ARCHIVE_WARN);
 +	}
 +	if (archive_entry_filetype(entry) == AE_IFREG &&
 +	    archive_entry_size(entry) >= MULTI_EXTENT_SIZE) {
 +		if (iso9660->opt.iso_level < 3) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Ignore over %lld bytes file. "
 +			    "This file too large.",
 +			    MULTI_EXTENT_SIZE);
 +				iso9660->cur_file = NULL;
 +			return (ARCHIVE_WARN);
 +		}
 +		iso9660->need_multi_extent = 1;
 +	}
 +
 +	file = isofile_new(a, entry);
 +	if (file == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	r = isofile_gen_utility_names(a, file);
 +	if (r < ARCHIVE_WARN) {
 +		isofile_free(file);
 +		return (r);
 +	}
 +	else if (r < ret)
 +		ret = r;
 +
 +	/*
 +	 * Ignore a path which looks like the top of directory name
 +	 * since we have already made the root directory of an ISO image.
 +	 */
 +	if (archive_strlen(&(file->parentdir)) == 0 &&
 +	    archive_strlen(&(file->basename)) == 0) {
 +		isofile_free(file);
 +		return (r);
 +	}
 +
 +	isofile_add_entry(iso9660, file);
 +	isoent = isoent_new(file);
 +	if (isoent == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (isoent->file->dircnt > iso9660->dircnt_max)
 +		iso9660->dircnt_max = isoent->file->dircnt;
 +
 +	/* Add the current file into tree */
 +	r = isoent_tree(a, &isoent);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +
 +	/* If there is the same file in tree and
 +	 * the current file is older than the file in tree.
 +	 * So we don't need the current file data anymore. */
 +	if (isoent->file != file)
 +		return (ARCHIVE_OK);
 +
 +	/* Non regular files contents are unneeded to be saved to
 +	 * temporary files. */
 +	if (archive_entry_filetype(file->entry) != AE_IFREG)
 +		return (ret);
 +
 +	/*
 +	 * Set the current file to cur_file to read its contents.
 +	 */
 +	iso9660->cur_file = file;
 +
 +	if (archive_entry_nlink(file->entry) > 1) {
 +		r = isofile_register_hardlink(a, file);
 +		if (r != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Prepare to save the contents of the file.
 +	 */
 +	if (iso9660->temp_fd < 0) {
 +		iso9660->temp_fd = __archive_mktemp(NULL);
 +		if (iso9660->temp_fd < 0) {
 +			archive_set_error(&a->archive, errno,
 +			    "Couldn't create temporary file");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	/* Save an offset of current file in temporary file. */
 +	file->content.offset_of_temp = wb_offset(a);
 +	file->cur_content = &(file->content);
 +	r = zisofs_init(a, file);
 +	if (r < ret)
 +		ret = r;
 +	iso9660->bytes_remaining =  archive_entry_size(file->entry);
 +
 +	return (ret);
 +}
 +
 +static int
 +write_to_temp(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	ssize_t written;
 +	const unsigned char *b;
 +
 +	b = (const unsigned char *)buff;
 +	while (s) {
 +		written = write(iso9660->temp_fd, b, s);
 +		if (written < 0) {
 +			archive_set_error(&a->archive, errno,
 +			    "Can't write to temporary file");
 +			return (ARCHIVE_FATAL);
 +		}
 +		s -= written;
 +		b += written;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +wb_write_to_temp(struct archive_write *a, const void *buff, size_t s)
 +{
 +	const char *xp = buff;
 +	size_t xs = s;
 +
 +	/*
 +	 * If a written data size is big enough to use system-call
 +	 * and there is no waiting data, this calls write_to_temp() in
 +	 * order to reduce a extra memory copy.
 +	 */
 +	if (wb_remaining(a) == wb_buffmax() && s > (1024 * 16)) {
 +		struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
 +		xs = s % LOGICAL_BLOCK_SIZE;
 +		iso9660->wbuff_offset += s - xs;
 +		if (write_to_temp(a, buff, s - xs) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		if (xs == 0)
 +			return (ARCHIVE_OK);
 +		xp += s - xs;
 +	}
 +
 +	while (xs) {
 +		size_t size = xs;
 +		if (size > wb_remaining(a))
 +			size = wb_remaining(a);
 +		memcpy(wb_buffptr(a), xp, size);
 +		if (wb_consume(a, size) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		xs -= size;
 +		xp += size;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +wb_write_padding_to_temp(struct archive_write *a, int64_t csize)
 +{
 +	size_t ns;
 +	int ret;
 +
- 	ns = csize % LOGICAL_BLOCK_SIZE;
++	ns = (size_t)(csize % LOGICAL_BLOCK_SIZE);
 +	if (ns != 0)
 +		ret = write_null(a, LOGICAL_BLOCK_SIZE - ns);
 +	else
 +		ret = ARCHIVE_OK;
 +	return (ret);
 +}
 +
 +static ssize_t
 +write_iso9660_data(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	size_t ws;
 +
 +	if (iso9660->temp_fd < 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Couldn't create temporary file");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	ws = s;
 +	if (iso9660->need_multi_extent &&
 +	    (iso9660->cur_file->cur_content->size + ws) >=
 +	      (MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE)) {
 +		struct content *con;
 +		size_t ts;
 +
- 		ts = MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE -
- 		    iso9660->cur_file->cur_content->size;
++		ts = (size_t)(MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE -
++		    iso9660->cur_file->cur_content->size);
 +
 +		if (iso9660->zisofs.detect_magic)
 +			zisofs_detect_magic(a, buff, ts);
 +
 +		if (iso9660->zisofs.making) {
 +			if (zisofs_write_to_temp(a, buff, ts) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		} else {
 +			if (wb_write_to_temp(a, buff, ts) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			iso9660->cur_file->cur_content->size += ts;
 +		}
 +
 +		/* Write padding. */
 +		if (wb_write_padding_to_temp(a,
 +		    iso9660->cur_file->cur_content->size) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +
 +		/* Compute the logical block number. */
- 		iso9660->cur_file->cur_content->blocks =
- 		    (iso9660->cur_file->cur_content->size
- 		     + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS;
++		iso9660->cur_file->cur_content->blocks = (int)
++		    ((iso9660->cur_file->cur_content->size
++		     + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
 +
 +		/*
 +		 * Make next extent.
 +		 */
 +		ws -= ts;
 +		buff = (const void *)(((const unsigned char *)buff) + ts);
 +		/* Make a content for next extent. */
 +		con = calloc(1, sizeof(*con));
 +		if (con == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate content data");
 +			return (ARCHIVE_FATAL);
 +		}
 +		con->offset_of_temp = wb_offset(a);
 +		iso9660->cur_file->cur_content->next = con;
 +		iso9660->cur_file->cur_content = con;
 +#ifdef HAVE_ZLIB_H
 +		iso9660->zisofs.block_offset = 0;
 +#endif
 +	}
 +
 +	if (iso9660->zisofs.detect_magic)
 +		zisofs_detect_magic(a, buff, ws);
 +
 +	if (iso9660->zisofs.making) {
 +		if (zisofs_write_to_temp(a, buff, ws) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	} else {
 +		if (wb_write_to_temp(a, buff, ws) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		iso9660->cur_file->cur_content->size += ws;
 +	}
 +
 +	return (s);
 +}
 +
 +static ssize_t
 +iso9660_write_data(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	ssize_t r;
 +
 +	if (iso9660->cur_file == NULL)
 +		return (0);
 +	if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
 +		return (0);
 +	if (s > iso9660->bytes_remaining)
- 		s = iso9660->bytes_remaining;
++		s = (size_t)iso9660->bytes_remaining;
 +	if (s == 0)
 +		return (0);
 +
 +	r = write_iso9660_data(a, buff, s);
 +	if (r > 0)
 +		iso9660->bytes_remaining -= r;
 +	return (r);
 +}
 +
 +static int
 +iso9660_finish_entry(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +
 +	if (iso9660->cur_file == NULL)
 +		return (ARCHIVE_OK);
 +	if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
 +		return (ARCHIVE_OK);
 +	if (iso9660->cur_file->content.size == 0)
 +		return (ARCHIVE_OK);
 +
 +	/* If there are unwritten data, write null data instead. */
 +	while (iso9660->bytes_remaining > 0) {
 +		size_t s;
 +
 +		s = (iso9660->bytes_remaining > a->null_length)?
 +		    a->null_length: (size_t)iso9660->bytes_remaining;
 +		if (write_iso9660_data(a, a->nulls, s) < 0)
 +			return (ARCHIVE_FATAL);
 +		iso9660->bytes_remaining -= s;
 +	}
 +
 +	if (iso9660->zisofs.making && zisofs_finish_entry(a) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Write padding. */
 +	if (wb_write_padding_to_temp(a, iso9660->cur_file->cur_content->size)
 +	    != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Compute the logical block number. */
- 	iso9660->cur_file->cur_content->blocks =
- 	    (iso9660->cur_file->cur_content->size
- 	     + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS;
++	iso9660->cur_file->cur_content->blocks = (int)
++	    ((iso9660->cur_file->cur_content->size
++	     + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
 +
 +	/* Add the current file to data file list. */
 +	isofile_add_data_file(iso9660, iso9660->cur_file);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +iso9660_close(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660;
 +	int ret, blocks;
 +
 +	iso9660 = a->format_data;
 +
 +	/*
- 	 * Write remaining data out to the temprary file.
++	 * Write remaining data out to the temporary file.
 +	 */
 +	if (wb_remaining(a) > 0) {
 +		ret = wb_write_out(a);
 +		if (ret < 0)
 +			return (ret);
 +	}
 +
 +	/*
 +	 * Preparations...
 +	 */
 +#ifdef DEBUG
 +	if (iso9660->birth_time == 0)
 +#endif
 +		time(&(iso9660->birth_time));
 +
 +	/*
 +	 * Prepare a bootable ISO image.
 +	 */
 +	if (iso9660->opt.boot) {
 +		/* Find out the boot file entry. */
 +		ret = isoent_find_out_boot_file(a, iso9660->primary.rootent);
 +		if (ret < 0)
 +			return (ret);
 +		/* Reconvert the boot file from zisofs'ed form to
 +		 * plain form. */
 +		ret = zisofs_rewind_boot_file(a);
 +		if (ret < 0)
 +			return (ret);
- 		/* Write remaining data out to the temprary file. */
++		/* Write remaining data out to the temporary file. */
 +		if (wb_remaining(a) > 0) {
 +			ret = wb_write_out(a);
 +			if (ret < 0)
 +				return (ret);
 +		}
 +		/* Create the boot catalog. */
 +		ret = isoent_create_boot_catalog(a, iso9660->primary.rootent);
 +		if (ret < 0)
 +			return (ret);
 +	}
 +
 +	/*
 +	 * Prepare joliet extensions.
 +	 */
 +	if (iso9660->opt.joliet) {
 +		/* Make a new tree for joliet. */
 +		ret = isoent_clone_tree(a, &(iso9660->joliet.rootent),
 +		    iso9660->primary.rootent);
 +		if (ret < 0)
 +			return (ret);
 +		/* Make sure we have UTF-16BE convertors.
 +		 * if there is no file entry, convertors are still
 +		 * uninitilized. */
 +		if (iso9660->sconv_to_utf16be == NULL) {
 +			iso9660->sconv_to_utf16be =
 +			    archive_string_conversion_to_charset(
 +				&(a->archive), "UTF-16BE", 1);
 +			if (iso9660->sconv_to_utf16be == NULL)
 +				/* Couldn't allocate memory */
 +				return (ARCHIVE_FATAL);
 +			iso9660->sconv_from_utf16be =
 +			    archive_string_conversion_from_charset(
 +				&(a->archive), "UTF-16BE", 1);
 +			if (iso9660->sconv_from_utf16be == NULL)
 +				/* Couldn't allocate memory */
 +				return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	/*
 +	 * Make Path Tables.
 +	 */
 +	ret = isoent_make_path_table(a);
 +	if (ret < 0)
 +		return (ret);
 +
 +	/*
 +	 * Calculate a total volume size and setup all locations of
 +	 * contents of an iso9660 image.
 +	 */
 +	blocks = SYSTEM_AREA_BLOCK
 +		+ PRIMARY_VOLUME_DESCRIPTOR_BLOCK
 +		+ VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK
 +		+ NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
 +	if (iso9660->opt.boot)
 +		blocks += BOOT_RECORD_DESCRIPTOR_BLOCK;
 +	if (iso9660->opt.joliet)
 +		blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;
 +	if (iso9660->opt.iso_level == 4)
 +		blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;
 +
 +	/* Setup the locations of Path Table. */
 +	iso9660->primary.location_type_L_path_table = blocks;
 +	blocks += iso9660->primary.path_table_block;
 +	iso9660->primary.location_type_M_path_table = blocks;
 +	blocks += iso9660->primary.path_table_block;
 +	if (iso9660->opt.joliet) {
 +		iso9660->joliet.location_type_L_path_table = blocks;
 +		blocks += iso9660->joliet.path_table_block;
 +		iso9660->joliet.location_type_M_path_table = blocks;
 +		blocks += iso9660->joliet.path_table_block;
 +	}
 +
 +	/* Setup the locations of directories. */
 +	isoent_setup_directory_location(iso9660, blocks,
 +	    &(iso9660->primary));
 +	blocks += iso9660->primary.total_dir_block;
 +	if (iso9660->opt.joliet) {
 +		isoent_setup_directory_location(iso9660, blocks,
 +		    &(iso9660->joliet));
 +		blocks += iso9660->joliet.total_dir_block;
 +	}
 +
 +	if (iso9660->opt.rr) {
 +		iso9660->location_rrip_er = blocks;
 +		blocks += RRIP_ER_BLOCK;
 +	}
 +
 +	/* Setup the locations of all file contents. */
 + 	isoent_setup_file_location(iso9660, blocks);
 +	blocks += iso9660->total_file_block;
 +	if (iso9660->opt.boot && iso9660->opt.boot_info_table) {
 +		ret = setup_boot_information(a);
 +		if (ret < 0)
 +			return (ret);
 +	}
 +
 +	/* Now we have a total volume size. */
 +	iso9660->volume_space_size = blocks;
 +	if (iso9660->opt.pad)
 +		iso9660->volume_space_size += PADDING_BLOCK;
 +	iso9660->volume_sequence_number = 1;
 +
 +
 +	/*
 +	 * Write an ISO 9660 image.
 +	 */
 +
 +	/* Switc to start using wbuff as file buffer. */
 +	iso9660->wbuff_remaining = wb_buffmax();
 +	iso9660->wbuff_type = WB_TO_STREAM;
 +	iso9660->wbuff_offset = 0;
 +	iso9660->wbuff_written = 0;
 +	iso9660->wbuff_tail = 0;
 +
 +	/* Write The System Area */
 +	ret = write_null(a, SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE);
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Write Primary Volume Descriptor */
 +	ret = write_VD(a, &(iso9660->primary));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	if (iso9660->opt.boot) {
 +		/* Write Boot Record Volume Descriptor */
 +		ret = write_VD_boot_record(a);
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	if (iso9660->opt.iso_level == 4) {
 +		/* Write Enhanced Volume Descriptor */
 +		iso9660->primary.vdd_type = VDD_ENHANCED;
 +		ret = write_VD(a, &(iso9660->primary));
 +		iso9660->primary.vdd_type = VDD_PRIMARY;
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	if (iso9660->opt.joliet) {
 +		ret = write_VD(a, &(iso9660->joliet));
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Write Volume Descriptor Set Terminator */
 +	ret = write_VD_terminator(a);
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Write Non-ISO File System Information */
 +	ret = write_information_block(a);
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Write Type L Path Table */
 +	ret = write_path_table(a, 0, &(iso9660->primary));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Write Type M Path Table */
 +	ret = write_path_table(a, 1, &(iso9660->primary));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	if (iso9660->opt.joliet) {
 +		/* Write Type L Path Table */
 +		ret = write_path_table(a, 0, &(iso9660->joliet));
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +
 +		/* Write Type M Path Table */
 +		ret = write_path_table(a, 1, &(iso9660->joliet));
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Write Directory Descriptors */
 +	ret = write_directory_descriptors(a, &(iso9660->primary));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	if (iso9660->opt.joliet) {
 +		ret = write_directory_descriptors(a, &(iso9660->joliet));
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	if (iso9660->opt.rr) {
 +		/* Write Rockridge ER(Extensions Reference) */
 +		ret = write_rr_ER(a);
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Write File Descriptors */
 +	ret = write_file_descriptors(a);
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Write Padding  */
 +	if (iso9660->opt.pad) {
 +		ret = write_null(a, PADDING_BLOCK * LOGICAL_BLOCK_SIZE);
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	if (iso9660->directories_too_deep != NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "%s: Directories too deep.",
 +		    archive_entry_pathname(
 +			iso9660->directories_too_deep->file->entry));
 +		return (ARCHIVE_WARN);
 +	}
 +
 +	/* Write remaining data out. */
 +	ret = wb_write_out(a);
 +
 +	return (ret);
 +}
 +
 +static int
 +iso9660_free(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660;
 +	int i, ret;
 +
 +	iso9660 = a->format_data;
 +
 +	/* Close the temporary file. */
 +	if (iso9660->temp_fd >= 0)
 +		close(iso9660->temp_fd);
 +
 +	/* Free some stuff for zisofs operations. */
 +	ret = zisofs_free(a);
 +
 +	/* Remove directory entries in tree which includes file entries. */
 +	isoent_free_all(iso9660->primary.rootent);
 +	for (i = 0; i < iso9660->primary.max_depth; i++)
 +		free(iso9660->primary.pathtbl[i].sorted);
 +	free(iso9660->primary.pathtbl);
 +
 +	if (iso9660->opt.joliet) {
 +		isoent_free_all(iso9660->joliet.rootent);
 +		for (i = 0; i < iso9660->joliet.max_depth; i++)
 +			free(iso9660->joliet.pathtbl[i].sorted);
 +		free(iso9660->joliet.pathtbl);
 +	}
 +
 +	/* Remove isofile entries. */
 +	isofile_free_all_entries(iso9660);
 +	isofile_free_hardlinks(iso9660);
 +
 +	archive_string_free(&(iso9660->cur_dirstr));
 +	archive_string_free(&(iso9660->volume_identifier));
 +	archive_string_free(&(iso9660->publisher_identifier));
 +	archive_string_free(&(iso9660->data_preparer_identifier));
 +	archive_string_free(&(iso9660->application_identifier));
 +	archive_string_free(&(iso9660->copyright_file_identifier));
 +	archive_string_free(&(iso9660->abstract_file_identifier));
 +	archive_string_free(&(iso9660->bibliographic_file_identifier));
 +	archive_string_free(&(iso9660->el_torito.catalog_filename));
 +	archive_string_free(&(iso9660->el_torito.boot_filename));
 +	archive_string_free(&(iso9660->el_torito.id));
 +	archive_string_free(&(iso9660->utf16be));
 +	archive_string_free(&(iso9660->mbs));
 +
 +	free(iso9660);
 +	a->format_data = NULL;
 +
 +	return (ret);
 +}
 +
 +/*
 + * Get the System Identifier
 + */
 +static void
 +get_system_identitier(char *system_id, size_t size)
 +{
 +#if defined(HAVE_SYS_UTSNAME_H)
 +	struct utsname u;
 +
 +	uname(&u);
 +	strncpy(system_id, u.sysname, size-1);
 +	system_id[size-1] = '\0';
 +#elif defined(_WIN32) && !defined(__CYGWIN__)
 +	strncpy(system_id, "Windows", size-1);
 +	system_id[size-1] = '\0';
 +#else
 +#error no way to get the system identifier on your platform.
 +#endif
 +}
 +
 +static void
 +set_str(unsigned char *p, const char *s, size_t l, char f, const char *map)
 +{
 +	unsigned char c;
 +
 +	if (s == NULL)
 +		s = "";
 +	while ((c = *s++) != 0 && l > 0) {
 +		if (c >= 0x80 || map[c] == 0)
 +		 {
 +			/* illegal character */
 +			if (c >= 'a' && c <= 'z') {
 +				/* convert c from a-z to A-Z */
 +				c -= 0x20;
 +			} else
 +				c = 0x5f;
 +		}
 +		*p++ = c;
 +		l--;
 +	}
 +	/* If l isn't zero, fill p buffer by the character
 +	 * which indicated by f. */
 +	if (l > 0)
 +		memset(p , f, l);
 +}
 +
 +static inline int
 +joliet_allowed_char(unsigned char high, unsigned char low)
 +{
 +	int utf16 = (high << 8) | low;
 +
 +	if (utf16 <= 0x001F)
 +		return (0);
 +
 +	switch (utf16) {
 +	case 0x002A: /* '*' */
 +	case 0x002F: /* '/' */
 +	case 0x003A: /* ':' */
 +	case 0x003B: /* ';' */
 +	case 0x003F: /* '?' */
 +	case 0x005C: /* '\' */
 +		return (0);/* Not allowed. */
 +	}
 +	return (1);
 +}
 +
 +static int
 +set_str_utf16be(struct archive_write *a, unsigned char *p, const char *s,
 +    size_t l, uint16_t uf, enum vdc vdc)
 +{
 +	size_t size, i;
 +	int onepad;
 +
 +	if (s == NULL)
 +		s = "";
 +	if (l & 0x01) {
 +		onepad = 1;
 +		l &= ~1;
 +	} else
 +		onepad = 0;
 +	if (vdc == VDC_UCS2) {
 +		struct iso9660 *iso9660 = a->format_data;
- 		if (archive_strncpy_in_locale(&iso9660->utf16be, s, strlen(s),
++		if (archive_strncpy_l(&iso9660->utf16be, s, strlen(s),
 +		    iso9660->sconv_to_utf16be) != 0 && errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for UTF-16BE");
 +			return (ARCHIVE_FATAL);
 +		}
 +		size = iso9660->utf16be.length;
 +		if (size > l)
 +			size = l;
 +		memcpy(p, iso9660->utf16be.s, size);
 +	} else {
 +		const uint16_t *u16 = (const uint16_t *)s;
 +
 +		size = 0;
 +		while (*u16++)
 +			size += 2;
 +		if (size > l)
 +			size = l;
 +		memcpy(p, s, size);
 +	}
 +	for (i = 0; i < size; i += 2, p += 2) {
 +		if (!joliet_allowed_char(p[0], p[1]))
 +			archive_be16enc(p, 0x005F);/* '_' */
 +	}
 +	l -= size;
 +	while (l > 0) {
 +		archive_be16enc(p, uf);
 +		p += 2;
 +		l -= 2;
 +	}
 +	if (onepad)
 +		*p = 0;
 +	return (ARCHIVE_OK);
 +}
 +
 +static const char a_characters_map[0x80] = {
 +/*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
 +    1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */
 +    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */
 +    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
 +    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */
 +};
 +
 +static const char a1_characters_map[0x80] = {
 +/*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
 +    1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */
 +    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */
 +    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
 +    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
 +    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */
 +    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */
 +};
 +
 +static const char d_characters_map[0x80] = {
 +/*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */
 +    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */
 +    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
 +    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */
 +};
 +
 +static const char d1_characters_map[0x80] = {
 +/*  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F          */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
 +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */
 +    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */
 +    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
 +    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
 +    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */
 +    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */
 +};
 +
 +static int
 +set_str_a_characters_bp(struct archive_write *a, unsigned char *bp,
 +    int from, int to, const char *s, enum vdc vdc)
 +{
 +	int r;
 +
 +	switch (vdc) {
 +	case VDC_STD:
 +		set_str(bp+from, s, to - from + 1, 0x20,
 +		    a_characters_map);
 +		r = ARCHIVE_OK;
 +		break;
 +	case VDC_LOWERCASE:
 +		set_str(bp+from, s, to - from + 1, 0x20,
 +		    a1_characters_map);
 +		r = ARCHIVE_OK;
 +		break;
 +	case VDC_UCS2:
 +	case VDC_UCS2_DIRECT:
 +		r = set_str_utf16be(a, bp+from, s, to - from + 1,
 +		    0x0020, vdc);
 +		break;
 +	default:
 +		r = ARCHIVE_FATAL;
 +	}
 +	return (r);
 +}
 +
 +static int
 +set_str_d_characters_bp(struct archive_write *a, unsigned char *bp,
 +    int from, int to, const char *s, enum  vdc vdc)
 +{
 +	int r;
 +
 +	switch (vdc) {
 +	case VDC_STD:
 +		set_str(bp+from, s, to - from + 1, 0x20,
 +		    d_characters_map);
 +		r = ARCHIVE_OK;
 +		break;
 +	case VDC_LOWERCASE:
 +		set_str(bp+from, s, to - from + 1, 0x20,
 +		    d1_characters_map);
 +		r = ARCHIVE_OK;
 +		break;
 +	case VDC_UCS2:
 +	case VDC_UCS2_DIRECT:
 +		r = set_str_utf16be(a, bp+from, s, to - from + 1,
 +		    0x0020, vdc);
 +		break;
 +	default:
 +		r = ARCHIVE_FATAL;
 +	}
 +	return (r);
 +}
 +
 +static void
 +set_VD_bp(unsigned char *bp, enum VD_type type, unsigned char ver)
 +{
 +
 +	/* Volume Descriptor Type */
 +	bp[1] = (unsigned char)type;
 +	/* Standard Identifier */
 +	memcpy(bp + 2, "CD001", 5);
 +	/* Volume Descriptor Version */
 +	bp[7] = ver;
 +}
 +
 +static inline void
 +set_unused_field_bp(unsigned char *bp, int from, int to)
 +{
 +	memset(bp + from, 0, to - from + 1);
 +}
 +
 +/*
 + * 8-bit unsigned numerical values.
 + * ISO9660 Standard 7.1.1
 + */
 +static inline void
 +set_num_711(unsigned char *p, unsigned char value)
 +{
 +	*p = value;
 +}
 +
 +/*
 + * 8-bit signed numerical values.
 + * ISO9660 Standard 7.1.2
 + */
 +static inline void
 +set_num_712(unsigned char *p, char value)
 +{
 +	*((char *)p) = value;
 +}
 +
 +/*
 + * Least significant byte first.
 + * ISO9660 Standard 7.2.1
 + */
 +static inline void
 +set_num_721(unsigned char *p, uint16_t value)
 +{
 +	archive_le16enc(p, value);
 +}
 +
 +/*
 + * Most significant byte first.
 + * ISO9660 Standard 7.2.2
 + */
 +static inline void
 +set_num_722(unsigned char *p, uint16_t value)
 +{
 +	archive_be16enc(p, value);
 +}
 +
 +/*
 + * Both-byte orders.
 + * ISO9660 Standard 7.2.3
 + */
 +static void
 +set_num_723(unsigned char *p, uint16_t value)
 +{
 +	archive_le16enc(p, value);
 +	archive_be16enc(p+2, value);
 +}
 +
 +/*
 + * Least significant byte first.
 + * ISO9660 Standard 7.3.1
 + */
 +static inline void
 +set_num_731(unsigned char *p, uint32_t value)
 +{
 +	archive_le32enc(p, value);
 +}
 +
 +/*
 + * Most significant byte first.
 + * ISO9660 Standard 7.3.2
 + */
 +static inline void
 +set_num_732(unsigned char *p, uint32_t value)
 +{
 +	archive_be32enc(p, value);
 +}
 +
 +/*
 + * Both-byte orders.
 + * ISO9660 Standard 7.3.3
 + */
 +static inline void
 +set_num_733(unsigned char *p, uint32_t value)
 +{
 +	archive_le32enc(p, value);
 +	archive_be32enc(p+4, value);
 +}
 +
 +static void
 +set_digit(unsigned char *p, size_t s, int value)
 +{
 +
 +	while (s--) {
 +		p[s] = '0' + (value % 10);
 +		value /= 10;
 +	}
 +}
 +
 +#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
 +#define get_gmoffset(tm)	((tm)->tm_gmtoff)
 +#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
 +#define get_gmoffset(tm)	((tm)->__tm_gmtoff)
 +#else
 +static long
 +get_gmoffset(struct tm *tm)
 +{
 +	long offset;
 +
 +#if defined(HAVE__GET_TIMEZONE)
 +	_get_timezone(&offset);
 +#elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
 +	offset = _timezone;
 +#else
 +	offset = timezone;
 +#endif
 +	offset *= -1;
 +	if (tm->tm_isdst)
 +		offset += 3600;
 +	return (offset);
 +}
 +#endif
 +
 +static void
 +get_tmfromtime(struct tm *tm, time_t *t)
 +{
 +#if HAVE_LOCALTIME_R
 +	tzset();
 +	localtime_r(t, tm);
 +#elif HAVE__LOCALTIME64_S
 +	_localtime64_s(tm, t);
 +#else
 +	memcpy(tm, localtime(t), sizeof(*tm));
 +#endif
 +}
 +
 +/*
 + * Date and Time Format.
 + * ISO9660 Standard 8.4.26.1
 + */
 +static void
 +set_date_time(unsigned char *p, time_t t)
 +{
 +	struct tm tm;
 +
 +	get_tmfromtime(&tm, &t);
 +	set_digit(p, 4, tm.tm_year + 1900);
 +	set_digit(p+4, 2, tm.tm_mon + 1);
 +	set_digit(p+6, 2, tm.tm_mday);
 +	set_digit(p+8, 2, tm.tm_hour);
 +	set_digit(p+10, 2, tm.tm_min);
 +	set_digit(p+12, 2, tm.tm_sec);
 +	set_digit(p+14, 2, 0);
- 	set_num_712(p+16, get_gmoffset(&tm)/(60*15));
++	set_num_712(p+16, (char)(get_gmoffset(&tm)/(60*15)));
 +}
 +
 +static void
 +set_date_time_null(unsigned char *p)
 +{
 +	memset(p, '0', 16);
 +	p[16] = 0;
 +}
 +
 +static void
 +set_time_915(unsigned char *p, time_t t)
 +{
 +	struct tm tm;
 +
 +	get_tmfromtime(&tm, &t);
 +	set_num_711(p+0, tm.tm_year);
 +	set_num_711(p+1, tm.tm_mon+1);
 +	set_num_711(p+2, tm.tm_mday);
 +	set_num_711(p+3, tm.tm_hour);
 +	set_num_711(p+4, tm.tm_min);
 +	set_num_711(p+5, tm.tm_sec);
- 	set_num_712(p+6, get_gmoffset(&tm)/(60*15));
++	set_num_712(p+6, (char)(get_gmoffset(&tm)/(60*15)));
 +}
 +
 +
 +/*
 + * Write SUSP "CE" System Use Entry.
 + */
 +static int
 +set_SUSP_CE(unsigned char *p, int location, int offset, int size)
 +{
 +	unsigned char *bp = p -1;
 +	/*  Extend the System Use Area
 +	 *   "CE" Format:
 +	 *               len  ver
 +	 *    +----+----+----+----+-----------+-----------+
 +	 *    | 'C'| 'E'| 1C | 01 | LOCATION1 | LOCATION2 |
 +	 *    +----+----+----+----+-----------+-----------+
 +	 *    0    1    2    3    4          12          20
 +	 *    +-----------+
 +	 *    | LOCATION3 |
 +	 *    +-----------+
 +	 *   20          28
 +	 *   LOCATION1 : Location of Continuation of System Use Area.
 +	 *   LOCATION2 : Offset to Start of Continuation.
 +	 *   LOCATION3 : Length of the Continuation.
 +	 */
 +
 +	bp[1] = 'C';
 +	bp[2] = 'E';
 +	bp[3] = RR_CE_SIZE;	/* length	*/
 +	bp[4] = 1;		/* version	*/
 +	set_num_733(bp+5, location);
 +	set_num_733(bp+13, offset);
 +	set_num_733(bp+21, size);
 +	return (RR_CE_SIZE);
 +}
 +
 +/*
 + * The functions, which names are beginning with extra_, are used to
 + * control extra records.
 + * The maximum size of a Directory Record is 254. When a filename is
 + * very long, all of RRIP data of a file won't stored to the Directory
 + * Record and so remaining RRIP data store to an extra record instead.
 + */
 +static unsigned char *
 +extra_open_record(unsigned char *bp, int dr_len, struct isoent *isoent,
 +    struct ctl_extr_rec *ctl)
 +{
 +	ctl->bp = bp;
 +	if (bp != NULL)
 +		bp += dr_len;
 +	ctl->use_extr = 0;
 +	ctl->isoent = isoent;
 +	ctl->ce_ptr = NULL;
 +	ctl->cur_len = ctl->dr_len = dr_len;
 +	ctl->limit = DR_LIMIT;
 +
 +	return (bp);
 +}
 +
 +static void
 +extra_close_record(struct ctl_extr_rec *ctl, int ce_size)
 +{
 +	int padding = 0;
 +
 +	if (ce_size > 0)
 +		extra_tell_used_size(ctl, ce_size);
 +	/* Padding. */
 +	if (ctl->cur_len & 0x01) {
 +		ctl->cur_len++;
 +		if (ctl->bp != NULL)
 +			ctl->bp[ctl->cur_len] = 0;
 +		padding = 1;
 +	}
 +	if (ctl->use_extr) {
 +		if (ctl->ce_ptr != NULL)
 +			set_SUSP_CE(ctl->ce_ptr, ctl->extr_loc,
 +			    ctl->extr_off, ctl->cur_len - padding);
 +	} else
 +		ctl->dr_len = ctl->cur_len;
 +}
 +
 +#define extra_space(ctl)	((ctl)->limit - (ctl)->cur_len)
 +
 +static unsigned char *
 +extra_next_record(struct ctl_extr_rec *ctl, int length)
 +{
 +	int cur_len = ctl->cur_len;/* save cur_len */
 +
 +	/* Close the current extra record or Directory Record. */
 +	extra_close_record(ctl, RR_CE_SIZE);
 +
 +	/* Get a next extra record. */
 +	ctl->use_extr = 1;
 +	if (ctl->bp != NULL) {
 +		/* Storing data into an extra record. */
 +		unsigned char *p;
 +
 +		/* Save the pointer where a CE extension will be
 +		 * stored to. */
 +		ctl->ce_ptr = &ctl->bp[cur_len+1];
 +		p = extra_get_record(ctl->isoent,
 +		    &ctl->limit, &ctl->extr_off, &ctl->extr_loc);
 +		ctl->bp = p - 1;/* the base of bp offset is 1. */
 +	} else
 +		/* Calculating the size of an extra record. */
 +		(void)extra_get_record(ctl->isoent,
 +		    &ctl->limit, NULL, NULL);
 +	ctl->cur_len = 0;
 +	/* Check if an extra record is almost full.
 +	 * If so, get a next one. */
 +	if (extra_space(ctl) < length)
 +		(void)extra_next_record(ctl, length);
 +
 +	return (ctl->bp);
 +}
 +
 +static inline struct extr_rec *
 +extra_last_record(struct isoent *isoent)
 +{
 +	if (isoent->extr_rec_list.first == NULL)
 +		return (NULL);
 +	return ((struct extr_rec *)(void *)
 +		((char *)(isoent->extr_rec_list.last)
 +		    - offsetof(struct extr_rec, next)));
 +}
 +
 +static unsigned char *
 +extra_get_record(struct isoent *isoent, int *space, int *off, int *loc)
 +{
 +	struct extr_rec *rec;
 +
 +	isoent = isoent->parent;
 +	if (off != NULL) {
 +		/* Storing data into an extra record. */
 +		rec = isoent->extr_rec_list.current;
 +		if (DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset)
 +			rec = rec->next;
 +	} else {
 +		/* Calculating the size of an extra record. */
 +		rec = extra_last_record(isoent);
 +		if (rec == NULL ||
 +		    DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset) {
 +			rec = malloc(sizeof(*rec));
 +			if (rec == NULL)
 +				return (NULL);
 +			rec->location = 0;
 +			rec->offset = 0;
 +			/* Insert `rec` into the tail of isoent->extr_rec_list */
 +			rec->next = NULL;
 +			*isoent->extr_rec_list.last = rec;
 +			isoent->extr_rec_list.last = &(rec->next);
 +		}
 +	}
 +	*space = LOGICAL_BLOCK_SIZE - rec->offset - DR_SAFETY;
 +	if (*space & 0x01)
 +		*space -= 1;/* Keep padding space. */
 +	if (off != NULL)
 +		*off = rec->offset;
 +	if (loc != NULL)
 +		*loc = rec->location;
 +	isoent->extr_rec_list.current = rec;
 +
 +	return (&rec->buf[rec->offset]);
 +}
 +
 +static void
 +extra_tell_used_size(struct ctl_extr_rec *ctl, int size)
 +{
 +	struct isoent *isoent;
 +	struct extr_rec *rec;
 +
 +	if (ctl->use_extr) {
 +		isoent = ctl->isoent->parent;
 +		rec = isoent->extr_rec_list.current;
 +		if (rec != NULL)
 +			rec->offset += size;
 +	}
 +	ctl->cur_len += size;
 +}
 +
 +static int
 +extra_setup_location(struct isoent *isoent, int location)
 +{
 +	struct extr_rec *rec;
 +	int cnt;
 +
 +	cnt = 0;
 +	rec = isoent->extr_rec_list.first;
 +	isoent->extr_rec_list.current = rec;
 +	while (rec) {
 +		cnt++;
 +		rec->location = location++;
 +		rec->offset = 0;
 +		rec = rec->next;
 +	}
 +	return (cnt);
 +}
 +
 +/*
 + * Create the RRIP entries.
 + */
 +static int
 +set_directory_record_rr(unsigned char *bp, int dr_len,
 +    struct isoent *isoent, struct iso9660 *iso9660, enum dir_rec_type t)
 +{
 +	/* Flags(BP 5) of the Rockridge "RR" System Use Field */
 +	unsigned char rr_flag;
 +#define RR_USE_PX	0x01
 +#define RR_USE_PN	0x02
 +#define RR_USE_SL	0x04
 +#define RR_USE_NM	0x08
 +#define RR_USE_CL	0x10
 +#define RR_USE_PL	0x20
 +#define RR_USE_RE	0x40
 +#define RR_USE_TF	0x80
 +	int length;
 +	struct ctl_extr_rec ctl;
 +	struct isoent *rr_parent, *pxent;
 +	struct isofile *file;
 +
 +	bp = extra_open_record(bp, dr_len, isoent, &ctl);
 +
 +	if (t == DIR_REC_PARENT) {
 +		rr_parent = isoent->rr_parent;
 +		pxent = isoent->parent;
 +		if (rr_parent != NULL)
 +			isoent = rr_parent;
 +		else
 +			isoent = isoent->parent;
 +	} else {
 +		rr_parent = NULL;
 +		pxent = isoent;
 +	}
 +	file = isoent->file;
 +
 +	if (t != DIR_REC_NORMAL) {
 +		rr_flag = RR_USE_PX | RR_USE_TF;
 +		if (rr_parent != NULL)
 +			rr_flag |= RR_USE_PL;
 +	} else {
 +		rr_flag = RR_USE_PX | RR_USE_NM | RR_USE_TF;
 +		if (archive_entry_filetype(file->entry) == AE_IFLNK)
 +			rr_flag |= RR_USE_SL;
 +		if (isoent->rr_parent != NULL)
 +			rr_flag |= RR_USE_RE;
 +		if (isoent->rr_child != NULL)
 +			rr_flag |= RR_USE_CL;
 +		if (archive_entry_filetype(file->entry) == AE_IFCHR ||
 +		    archive_entry_filetype(file->entry) == AE_IFBLK)
 +			rr_flag |= RR_USE_PN;
 +#ifdef COMPAT_MKISOFS
 +		/*
 +		 * mkisofs 2.01.01a63 records "RE" extension to
 +		 * the entry of "rr_moved" directory.
 +		 * I don't understand this behavior.
 +		 */
 +		if (isoent->virtual &&
 +		    isoent->parent == iso9660->primary.rootent &&
 +		    strcmp(isoent->file->basename.s, "rr_moved") == 0)
 +			rr_flag |= RR_USE_RE;
 +#endif
 +	}
 +
 +	/* Write "SP" System Use Entry. */
 +	if (t == DIR_REC_SELF && isoent == isoent->parent) {
 +		length = 7;
 +		if (bp != NULL) {
 +			bp[1] = 'S';
 +			bp[2] = 'P';
 +			bp[3] = length;
 +			bp[4] = 1;	/* version	*/
 +			bp[5] = 0xBE;  /* Check Byte	*/
 +			bp[6] = 0xEF;  /* Check Byte	*/
 +			bp[7] = 0;
 +			bp += length;
 +		}
 +		extra_tell_used_size(&ctl, length);
 +	}
 +
 +	/* Write "RR" System Use Entry. */
 +	length = 5;
 +	if (extra_space(&ctl) < length)
 +		bp = extra_next_record(&ctl, length);
 +	if (bp != NULL) {
 +		bp[1] = 'R';
 +		bp[2] = 'R';
 +		bp[3] = length;
 +		bp[4] = 1;	/* version */
 +		bp[5] = rr_flag;
 +		bp += length;
 +	}
 +	extra_tell_used_size(&ctl, length);
 +
 +	/* Write "NM" System Use Entry. */
 +	if (rr_flag & RR_USE_NM) {
 +		/*
 +		 *   "NM" Format:
 +		 *     e.g. a basename is 'foo'
 +		 *               len  ver  flg
 +		 *    +----+----+----+----+----+----+----+----+
 +		 *    | 'N'| 'M'| 08 | 01 | 00 | 'f'| 'o'| 'o'|
 +		 *    +----+----+----+----+----+----+----+----+
 +		 *    <----------------- len ----------------->
 +		 */
 +		size_t nmlen = file->basename.length;
 +		const char *nm = file->basename.s;
 +		size_t nmmax;
 +
 +		if (extra_space(&ctl) < 6)
 +			bp = extra_next_record(&ctl, 6);
 +		if (bp != NULL) {
 +			bp[1] = 'N';
 +			bp[2] = 'M';
 +			bp[4] = 1;	    /* version	*/
 +		}
 +		nmmax = extra_space(&ctl);
 +		if (nmmax > 0xff)
 +			nmmax = 0xff;
 +		while (nmlen + 5 > nmmax) {
- 			length = nmmax;
++			length = (int)nmmax;
 +			if (bp != NULL) {
 +				bp[3] = length;
 +				bp[5] = 0x01;/* Alternate Name continues
 +					       * in next "NM" field */
 +				memcpy(bp+6, nm, length - 5);
 +				bp += length;
 +			}
 +			nmlen -= length - 5;
 +			nm += length - 5;
 +			extra_tell_used_size(&ctl, length);
 +			if (extra_space(&ctl) < 6) {
 +				bp = extra_next_record(&ctl, 6);
 +				nmmax = extra_space(&ctl);
 +				if (nmmax > 0xff)
 +					nmmax = 0xff;
 +			}
 +			if (bp != NULL) {
 +				bp[1] = 'N';
 +				bp[2] = 'M';
 +				bp[4] = 1;    /* version */
 +			}
 +		}
- 		length = 5 + nmlen;
++		length = 5 + (int)nmlen;
 +		if (bp != NULL) {
 +			bp[3] = length;
 +			bp[5] = 0;
 +			memcpy(bp+6, nm, nmlen);
 +			bp += length;
 +		}
 +		extra_tell_used_size(&ctl, length);
 +	}
 +
 +	/* Write "PX" System Use Entry. */
 +	if (rr_flag & RR_USE_PX) {
 +		/*
 +		 *   "PX" Format:
 +		 *               len  ver
 +		 *    +----+----+----+----+-----------+-----------+
 +		 *    | 'P'| 'X'| 2C | 01 | FILE MODE |   LINKS   |
 +		 *    +----+----+----+----+-----------+-----------+
 +		 *    0    1    2    3    4          12          20
 +		 *    +-----------+-----------+------------------+
 +		 *    |  USER ID  | GROUP ID  |FILE SERIAL NUMBER|
 +		 *    +-----------+-----------+------------------+
 +		 *   20          28          36                 44
 +		 */
 +		length = 44;
 +		if (extra_space(&ctl) < length)
 +			bp = extra_next_record(&ctl, length);
 +		if (bp != NULL) {
 +			mode_t mode;
- 			uid_t uid;
- 			gid_t gid;
++			int64_t uid;
++			int64_t gid;
 +
 +			mode = archive_entry_mode(file->entry);
 +			uid = archive_entry_uid(file->entry);
 +			gid = archive_entry_gid(file->entry);
 +			if (iso9660->opt.rr == OPT_RR_USEFUL) {
 +				/*
 +				 * This action is simular mkisofs -r option
 +				 * but our rockridge=useful option does not
 +				 * set a zero to uid and gid.
 +				 */
 +				/* set all read bit ON */
 +				mode |= 0444;
 +#if !defined(_WIN32) && !defined(__CYGWIN__)
 +				if (mode & 0111)
 +#endif
 +					/* set all exec bit ON */
 +					mode |= 0111;
 +				/* clear all write bits. */
 +				mode &= ~0222;
 +				/* clear setuid,setgid,sticky bits. */
 +				mode &= ~07000;
 +			}
 +
 +			bp[1] = 'P';
 +			bp[2] = 'X';
 +			bp[3] = length;
 +			bp[4] = 1;	/* version	*/
 +			/* file mode */
 +			set_num_733(bp+5, mode);
 +			/* file links (stat.st_nlink) */
 +			set_num_733(bp+13,
 +			    archive_entry_nlink(file->entry));
- 			set_num_733(bp+21, uid);
- 			set_num_733(bp+29, gid);
++			set_num_733(bp+21, (uint32_t)uid);
++			set_num_733(bp+29, (uint32_t)gid);
 +			/* File Serial Number */
 +			if (pxent->dir)
 +				set_num_733(bp+37, pxent->dir_location);
 +			else if (file->hardlink_target != NULL)
 +				set_num_733(bp+37,
 +				    file->hardlink_target->cur_content->location);
 +			else
 +				set_num_733(bp+37,
 +				    file->cur_content->location);
 +			bp += length;
 +		}
 +		extra_tell_used_size(&ctl, length);
 +	}
 +
 +	/* Write "SL" System Use Entry. */
 +	if (rr_flag & RR_USE_SL) {
 +		/*
 +		 *   "SL" Format:
 +		 *     e.g. a symbolic name is 'foo/bar'
 +		 *               len  ver  flg
 +		 *    +----+----+----+----+----+------------+
 +		 *    | 'S'| 'L'| 0F | 01 | 00 | components |
 +		 *    +----+----+----+----+----+-----+------+
 +		 *    0    1    2    3    4    5  ...|...  15
 +		 *    <----------------- len --------+------>
 +		 *    components :                   |
 +		 *     cflg clen                     |
 +		 *    +----+----+----+----+----+     |
 +		 *    | 00 | 03 | 'f'| 'o'| 'o'| <---+
 +		 *    +----+----+----+----+----+     |
 +		 *    5    6    7    8    9   10     |
 +		 *     cflg clen                     |
 +		 *    +----+----+----+----+----+     |
 +		 *    | 00 | 03 | 'b'| 'a'| 'r'| <---+
 +		 *    +----+----+----+----+----+
 +		 *   10   11   12   13   14   15
 +		 *
 +	 	 *    - cflg : flag of componet
 +		 *    - clen : length of componet
 +		 */
 +		const char *sl;
 +		char sl_last;
 +
 +		if (extra_space(&ctl) < 7)
 +			bp = extra_next_record(&ctl, 7);
 +		sl = file->symlink.s;
 +		sl_last = '\0';
 +		if (bp != NULL) {
 +			bp[1] = 'S';
 +			bp[2] = 'L';
 +			bp[4] = 1;	/* version	*/
 +		}
 +		for (;;) {
 +			unsigned char *nc, *cf,  *cl, cldmy = 0;
 +			int sllen, slmax;
 +
 +			slmax = extra_space(&ctl);
 +			if (slmax > 0xff)
 +				slmax = 0xff;
 +			if (bp != NULL)
 +				nc = &bp[6];
 +			else
 +				nc = NULL;
 +			cf = cl = NULL;
 +			sllen = 0;
 +			while (*sl && sllen + 11 < slmax) {
 +				if (sl_last == '\0' && sl[0] == '/') {
 +					/*
 +					 *     flg  len
 +					 *    +----+----+
 +					 *    | 08 | 00 | ROOT component.
 +					 *    +----+----+ ("/")
 +					 *
 +				 	 * Root component has to appear
 +				 	 * at the first component only.
 +					 */
 +					if (nc != NULL) {
 +						cf = nc++;
 +						*cf = 0x08; /* ROOT */
 +						*nc++ = 0;
 +					}
 +					sllen += 2;
 +					sl++;
 +					sl_last = '/';
 +					cl = NULL;
 +					continue;
 +				}
 +				if (((sl_last == '\0' || sl_last == '/') &&
 +				      sl[0] == '.' && sl[1] == '.' &&
 +				     (sl[2] == '/' || sl[2] == '\0')) ||
 +				    (sl[0] == '/' &&
 +				      sl[1] == '.' && sl[2] == '.' &&
 +				     (sl[3] == '/' || sl[3] == '\0'))) {
 +					/*
 +					 *     flg  len
 +					 *    +----+----+
 +					 *    | 04 | 00 | PARENT component.
 +					 *    +----+----+ ("..")
 +					 */
 +					if (nc != NULL) {
 +						cf = nc++;
 +						*cf = 0x04; /* PARENT */
 +						*nc++ = 0;
 +					}
 +					sllen += 2;
 +					if (sl[0] == '/')
 +						sl += 3;/* skip "/.." */
 +					else
 +						sl += 2;/* skip ".." */
 +					sl_last = '.';
 +					cl = NULL;
 +					continue;
 +				}
 +				if (((sl_last == '\0' || sl_last == '/') &&
 +				      sl[0] == '.' &&
 +				     (sl[1] == '/' || sl[1] == '\0')) ||
 +				    (sl[0] == '/' && sl[1] == '.' &&
 +				     (sl[2] == '/' || sl[2] == '\0'))) {
 +					/*
 +					 *     flg  len
 +					 *    +----+----+
 +					 *    | 02 | 00 | CURREENT component.
 +					 *    +----+----+ (".")
 +					 */
 +					if (nc != NULL) {
 +						cf = nc++;
 +						*cf = 0x02; /* CURRENT */
 +						*nc++ = 0;
 +					}
 +					sllen += 2;
 +					if (sl[0] == '/')
 +						sl += 2;/* skip "/." */
 +					else
 +						sl ++;  /* skip "." */
 +					sl_last = '.';
 +					cl = NULL;
 +					continue;
 +				}
 +				if (sl[0] == '/' || cl == NULL) {
 +					if (nc != NULL) {
 +						cf = nc++;
 +						*cf = 0;
 +						cl = nc++;
 +						*cl = 0;
 +					} else
 +						cl = &cldmy;
 +					sllen += 2;
 +					if (sl[0] == '/') {
 +						sl_last = *sl++;
 +						continue;
 +					}
 +				}
 +				sl_last = *sl++;
 +				if (nc != NULL) {
 +					*nc++ = sl_last;
 +					(*cl) ++;
 +				}
 +				sllen++;
 +			}
 +			if (*sl) {
 +				length = 5 + sllen;
 +				if (bp != NULL) {
 +					/*
 +					 * Mark flg as CONTINUE component.
 +					 */
 +					*cf |= 0x01;
 +					/*
 +					 *               len  ver  flg
 +					 *    +----+----+----+----+----+-
 +					 *    | 'S'| 'L'| XX | 01 | 01 |
 +					 *    +----+----+----+----+----+-
 +					 *                           ^
 +					 *           continues in next "SL"
 +					 */
 +					bp[3] = length;
 +					bp[5] = 0x01;/* This Symbolic Link
 +						      * continues in next
 +						      * "SL" field */
 +					bp += length;
 +				}
 +				extra_tell_used_size(&ctl, length);
 +				if (extra_space(&ctl) < 11)
 +					bp = extra_next_record(&ctl, 11);
 +				if (bp != NULL) {
 +					/* Next 'SL' */
 +					bp[1] = 'S';
 +					bp[2] = 'L';
 +					bp[4] = 1;    /* version */
 +				}
 +			} else {
 +				length = 5 + sllen;
 +				if (bp != NULL) {
 +					bp[3] = length;
 +					bp[5] = 0;
 +					bp += length;
 +				}
 +				extra_tell_used_size(&ctl, length);
 +				break;
 +			}
 +		}
 +	}
 +
 +	/* Write "TF" System Use Entry. */
 +	if (rr_flag & RR_USE_TF) {
 +		/*
 +		 *   "TF" Format:
 +		 *               len  ver
 +		 *    +----+----+----+----+-----+-------------+
 +		 *    | 'T'| 'F'| XX | 01 |FLAGS| TIME STAMPS |
 +		 *    +----+----+----+----+-----+-------------+
 +		 *    0    1    2    3    4     5            XX
 +		 *    TIME STAMPS : ISO 9660 Standard 9.1.5.
 +		 *                  If TF_LONG_FORM FLAGS is set,
 +		 *                  use ISO9660 Standard 8.4.26.1.
 +		 */
 +#define TF_CREATION	0x01	/* Creation time recorded		*/
 +#define TF_MODIFY	0x02	/* Modification time recorded		*/
 +#define TF_ACCESS	0x04	/* Last Access time recorded		*/
 +#define TF_ATTRIBUTES	0x08	/* Last Attribute Change time recorded  */
 +#define TF_BACKUP	0x10	/* Last Backup time recorded		*/
 +#define TF_EXPIRATION	0x20	/* Expiration time recorded		*/
 +#define TF_EFFECTIVE	0x40	/* Effective time recorded		*/
 +#define TF_LONG_FORM	0x80	/* ISO 9660 17-byte time format used	*/
 +		unsigned char tf_flags;
 +
 +		length = 5;
 +		tf_flags = 0;
 +#ifndef COMPAT_MKISOFS
 +		if (archive_entry_birthtime_is_set(file->entry) &&
 +		    archive_entry_birthtime(file->entry) <=
 +		    archive_entry_mtime(file->entry)) {
 +			length += 7;
 +			tf_flags |= TF_CREATION;
 +		}
 +#endif
 +		if (archive_entry_mtime_is_set(file->entry)) {
 +			length += 7;
 +			tf_flags |= TF_MODIFY;
 +		}
 +		if (archive_entry_atime_is_set(file->entry)) {
 +			length += 7;
 +			tf_flags |= TF_ACCESS;
 +		}
 +		if (archive_entry_ctime_is_set(file->entry)) {
 +			length += 7;
 +			tf_flags |= TF_ATTRIBUTES;
 +		}
 +		if (extra_space(&ctl) < length)
 +			bp = extra_next_record(&ctl, length);
 +		if (bp != NULL) {
 +			bp[1] = 'T';
 +			bp[2] = 'F';
 +			bp[3] = length;
 +			bp[4] = 1;	/* version	*/
 +			bp[5] = tf_flags;
 +			bp += 5;
 +			/* Creation time */
 +			if (tf_flags & TF_CREATION) {
 +				set_time_915(bp+1,
 +				    archive_entry_birthtime(file->entry));
 +				bp += 7;
 +			}
 +			/* Modification time */
 +			if (tf_flags & TF_MODIFY) {
 +				set_time_915(bp+1,
 +				    archive_entry_mtime(file->entry));
 +				bp += 7;
 +			}
 +			/* Last Access time */
 +			if (tf_flags & TF_ACCESS) {
 +				set_time_915(bp+1,
 +				    archive_entry_atime(file->entry));
 +				bp += 7;
 +			}
 +			/* Last Attribute Change time */
 +			if (tf_flags & TF_ATTRIBUTES) {
 +				set_time_915(bp+1,
 +				    archive_entry_ctime(file->entry));
 +				bp += 7;
 +			}
 +		}
 +		extra_tell_used_size(&ctl, length);
 +	}
 +
 +	/* Write "RE" System Use Entry. */
 +	if (rr_flag & RR_USE_RE) {
 +		/*
 +		 *   "RE" Format:
 +		 *               len  ver
 +		 *    +----+----+----+----+
 +		 *    | 'R'| 'E'| 04 | 01 |
 +		 *    +----+----+----+----+
 +		 *    0    1    2    3    4
 +		 */
 +		length = 4;
 +		if (extra_space(&ctl) < length)
 +			bp = extra_next_record(&ctl, length);
 +		if (bp != NULL) {
 +			bp[1] = 'R';
 +			bp[2] = 'E';
 +			bp[3] = length;
 +			bp[4] = 1;	/* version	*/
 +			bp += length;
 +		}
 +		extra_tell_used_size(&ctl, length);
 +	}
 +
 +	/* Write "PL" System Use Entry. */
 +	if (rr_flag & RR_USE_PL) {
 +		/*
 +		 *   "PL" Format:
 +		 *               len  ver
 +		 *    +----+----+----+----+------------+
 +		 *    | 'P'| 'L'| 0C | 01 | *LOCATION  |
 +		 *    +----+----+----+----+------------+
 +		 *    0    1    2    3    4           12
 +		 *    *LOCATION: location of parent directory
 +		 */
 +		length = 12;
 +		if (extra_space(&ctl) < length)
 +			bp = extra_next_record(&ctl, length);
 +		if (bp != NULL) {
 +			bp[1] = 'P';
 +			bp[2] = 'L';
 +			bp[3] = length;
 +			bp[4] = 1;	/* version	*/
 +			set_num_733(bp + 5,
 +			    rr_parent->dir_location);
 +			bp += length;
 +		}
 +		extra_tell_used_size(&ctl, length);
 +	}
 +
 +	/* Write "CL" System Use Entry. */
 +	if (rr_flag & RR_USE_CL) {
 +		/*
 +		 *   "CL" Format:
 +		 *               len  ver
 +		 *    +----+----+----+----+------------+
 +		 *    | 'C'| 'L'| 0C | 01 | *LOCATION  |
 +		 *    +----+----+----+----+------------+
 +		 *    0    1    2    3    4           12
 +		 *    *LOCATION: location of child directory
 +		 */
 +		length = 12;
 +		if (extra_space(&ctl) < length)
 +			bp = extra_next_record(&ctl, length);
 +		if (bp != NULL) {
 +			bp[1] = 'C';
 +			bp[2] = 'L';
 +			bp[3] = length;
 +			bp[4] = 1;	/* version	*/
 +			set_num_733(bp + 5,
 +			    isoent->rr_child->dir_location);
 +			bp += length;
 +		}
 +		extra_tell_used_size(&ctl, length);
 +	}
 +
 +	/* Write "PN" System Use Entry. */
 +	if (rr_flag & RR_USE_PN) {
 +		/*
 +		 *   "PN" Format:
 +		 *               len  ver
 +		 *    +----+----+----+----+------------+------------+
 +		 *    | 'P'| 'N'| 14 | 01 | dev_t high | dev_t low  |
 +		 *    +----+----+----+----+------------+------------+
 +		 *    0    1    2    3    4           12           20
 +		 */
 +		length = 20;
 +		if (extra_space(&ctl) < length)
 +			bp = extra_next_record(&ctl, length);
 +		if (bp != NULL) {
 +			uint64_t dev;
 +
 +			bp[1] = 'P';
 +			bp[2] = 'N';
 +			bp[3] = length;
 +			bp[4] = 1;	/* version	*/
 +			dev = (uint64_t)archive_entry_rdev(file->entry);
- 			set_num_733(bp + 5, dev >> 32);
- 			set_num_733(bp + 13, dev & 0xFFFFFFFF);
++			set_num_733(bp + 5, (uint32_t)(dev >> 32));
++			set_num_733(bp + 13, (uint32_t)(dev & 0xFFFFFFFF));
 +			bp += length;
 +		}
 +		extra_tell_used_size(&ctl, length);
 +	}
 +
 +	/* Write "ZF" System Use Entry. */
 +	if (file->zisofs.header_size) {
 +		/*
 +		 *   "ZF" Format:
 +		 *               len  ver
 +		 *    +----+----+----+----+----+----+-------------+
 +		 *    | 'Z'| 'F'| 10 | 01 | 'p'| 'z'| Header Size |
 +		 *    +----+----+----+----+----+----+-------------+
 +		 *    0    1    2    3    4    5    6             7
 +		 *    +--------------------+-------------------+
 +		 *    | Log2 of block Size | Uncompressed Size |
 +		 *    +--------------------+-------------------+
 +		 *    7                    8                   16
 +		 */
 +		length = 16;
 +		if (extra_space(&ctl) < length)
 +			bp = extra_next_record(&ctl, length);
 +		if (bp != NULL) {
 +			bp[1] = 'Z';
 +			bp[2] = 'F';
 +			bp[3] = length;
 +			bp[4] = 1;	/* version	*/
 +			bp[5] = 'p';
 +			bp[6] = 'z';
 +			bp[7] = file->zisofs.header_size;
 +			bp[8] = file->zisofs.log2_bs;
 +			set_num_733(bp + 9, file->zisofs.uncompressed_size);
 +			bp += length;
 +		}
 +		extra_tell_used_size(&ctl, length);
 +	}
 +
 +	/* Write "CE" System Use Entry. */
 +	if (t == DIR_REC_SELF && isoent == isoent->parent) {
 +		length = RR_CE_SIZE;
 +		if (bp != NULL)
 +			set_SUSP_CE(bp+1, iso9660->location_rrip_er,
 +			    0, RRIP_ER_SIZE);
 +		extra_tell_used_size(&ctl, length);
 +	}
 +
 +	extra_close_record(&ctl, 0);
 +
 +	return (ctl.dr_len);
 +}
 +
 +/*
 + * Write data of a Directory Record or calculate writing bytes itself.
 + * If parameter `p' is NULL, calculates the size of writing data, which
 + * a Directory Record needs to write, then it saved and return
 + * the calculated size.
 + * Parameter `n' is a remaining size of buffer. when parameter `p' is
 + * not NULL, check whether that `n' is not less than the saved size.
 + * if that `n' is small, return zero.
 + *
 + * This format of the Directory Record is according to
 + * ISO9660 Standard 9.1
 + */
 +static int
 +set_directory_record(unsigned char *p, size_t n, struct isoent *isoent,
 +    struct iso9660 *iso9660, enum dir_rec_type t,
 +    enum vdd_type vdd_type)
 +{
 +	unsigned char *bp;
 +	size_t dr_len;
 +	size_t fi_len;
 +
 +	if (p != NULL) {
 +		/*
 +		 * Check whether a write buffer size is less than the
 +		 * saved size which is needed to write this Directory
 +		 * Record.
 +		 */
 +		switch (t) {
 +		case DIR_REC_VD:
 +			dr_len = isoent->dr_len.vd; break;
 +		case DIR_REC_SELF:
 +			dr_len = isoent->dr_len.self; break;
 +		case DIR_REC_PARENT:
 +			dr_len = isoent->dr_len.parent; break;
 +		case DIR_REC_NORMAL:
 +		default:
 +			dr_len = isoent->dr_len.normal; break;
 +		}
 +		if (dr_len > n)
 +			return (0);/* Needs more buffer size. */
 +	}
 +
 +	if (t == DIR_REC_NORMAL && isoent->identifier != NULL)
 +		fi_len = isoent->id_len;
 +	else
 +		fi_len = 1;
 +
 +	if (p != NULL) {
 +		struct isoent *xisoent;
 +		struct isofile *file;
 +		unsigned char flag;
 +
 +		if (t == DIR_REC_PARENT)
 +			xisoent = isoent->parent;
 +		else
 +			xisoent = isoent;
 +		file = isoent->file;
 +		if (file->hardlink_target != NULL)
 +			file = file->hardlink_target;
 +		/* Make a file flag. */
 +		if (xisoent->dir)
 +			flag = FILE_FLAG_DIRECTORY;
 +		else {
 +			if (file->cur_content->next != NULL)
 +				flag = FILE_FLAG_MULTI_EXTENT;
 +			else
 +				flag = 0;
 +		}
 +
 +		bp = p -1;
 +		/* Extended Attribute Record Length */
 +		set_num_711(bp+2, 0);
 +		/* Location of Extent */
 +		if (xisoent->dir)
 +			set_num_733(bp+3, xisoent->dir_location);
 +		else
 +			set_num_733(bp+3, file->cur_content->location);
 +		/* Data Length */
 +		if (xisoent->dir)
 +			set_num_733(bp+11,
 +			    xisoent->dir_block * LOGICAL_BLOCK_SIZE);
 +		else
- 			set_num_733(bp+11, file->cur_content->size);
++			set_num_733(bp+11, (uint32_t)file->cur_content->size);
 +		/* Recording Date and Time */
 +		/* NOTE:
 +		 *  If a file type is symbolic link, you are seeing this
 +		 *  field value is different from a value mkisofs makes.
 +		 *  libarchive uses lstat to get this one, but it
 +		 *  seems mkisofs uses stat to get.
 +		 */
 +		set_time_915(bp+19,
 +		    archive_entry_mtime(xisoent->file->entry));
 +		/* File Flags */
 +		bp[26] = flag;
 +		/* File Unit Size */
 +		set_num_711(bp+27, 0);
 +		/* Interleave Gap Size */
 +		set_num_711(bp+28, 0);
 +		/* Volume Sequence Number */
 +		set_num_723(bp+29, iso9660->volume_sequence_number);
 +		/* Length of File Identifier */
- 		set_num_711(bp+33, fi_len);
++		set_num_711(bp+33, (unsigned char)fi_len);
 +		/* File Identifier */
 +		switch (t) {
 +		case DIR_REC_VD:
 +		case DIR_REC_SELF:
 +			set_num_711(bp+34, 0);
 +			break;
 +		case DIR_REC_PARENT:
 +			set_num_711(bp+34, 1);
 +			break;
 +		case DIR_REC_NORMAL:
 +			if (isoent->identifier != NULL)
 +				memcpy(bp+34, isoent->identifier, fi_len);
 +			else
 +				set_num_711(bp+34, 0);
 +			break;
 +		}
 +	} else
 +		bp = NULL;
 +	dr_len = 33 + fi_len;
 +	/* Padding Field */
 +	if (dr_len & 0x01) {
 +		dr_len ++;
 +		if (p != NULL)
 +			bp[dr_len] = 0;
 +	}
 +
 +	/* Volume Descriptor does not record extension. */
 +	if (t == DIR_REC_VD) {
 +		if (p != NULL)
 +			/* Length of Directory Record */
- 			set_num_711(p, dr_len);
++			set_num_711(p, (unsigned char)dr_len);
 +		else
- 			isoent->dr_len.vd = dr_len;
- 		return (dr_len);
++			isoent->dr_len.vd = (int)dr_len;
++		return ((int)dr_len);
 +	}
 +
 +	/* Rockridge */
 +	if (iso9660->opt.rr && vdd_type != VDD_JOLIET)
- 		dr_len = set_directory_record_rr(bp, dr_len,
++		dr_len = set_directory_record_rr(bp, (int)dr_len,
 +		    isoent, iso9660, t);
 +
 +	if (p != NULL)
 +		/* Length of Directory Record */
- 		set_num_711(p, dr_len);
++		set_num_711(p, (unsigned char)dr_len);
 +	else {
 +		/*
 +		 * Save the size which is needed to write this
 +		 * Directory Record.
 +		 */
 +		switch (t) {
 +		case DIR_REC_VD:
 +			/* This case does not come, but compiler
 +			 * complains that DIR_REC_VD not handled
 +			 *  in switch ....  */
 +			break;
 +		case DIR_REC_SELF:
- 			isoent->dr_len.self = dr_len; break;
++			isoent->dr_len.self = (int)dr_len; break;
 +		case DIR_REC_PARENT:
- 			isoent->dr_len.parent = dr_len; break;
++			isoent->dr_len.parent = (int)dr_len; break;
 +		case DIR_REC_NORMAL:
- 			isoent->dr_len.normal = dr_len; break;
++			isoent->dr_len.normal = (int)dr_len; break;
 +		}
 +	}
 +
- 	return (dr_len);
++	return ((int)dr_len);
 +}
 +
 +/*
 + * Calculate the size of a directory record.
 + */
 +static inline int
 +get_dir_rec_size(struct iso9660 *iso9660, struct isoent *isoent,
 +    enum dir_rec_type t, enum vdd_type vdd_type)
 +{
 +
 +	return (set_directory_record(NULL, SIZE_MAX,
 +	    isoent, iso9660, t, vdd_type));
 +}
 +
 +/*
 + * Manage to write ISO-image data with wbuff to reduce calling
 + * __archive_write_output() for performance.
 + */
 +
 +
 +static inline unsigned char *
 +wb_buffptr(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
 +
 +	return (&(iso9660->wbuff[sizeof(iso9660->wbuff)
 +		- iso9660->wbuff_remaining]));
 +}
 +
 +static int
 +wb_write_out(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
 +	size_t wsize, nw;
 +	int r;
 +
 +	wsize = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
 +	nw = wsize % LOGICAL_BLOCK_SIZE;
 +	if (iso9660->wbuff_type == WB_TO_STREAM)
 +		r = __archive_write_output(a, iso9660->wbuff, wsize - nw);
 +	else
 +		r = write_to_temp(a, iso9660->wbuff, wsize - nw);
 +	/* Increase the offset. */
 +	iso9660->wbuff_offset += wsize - nw;
 +	if (iso9660->wbuff_offset > iso9660->wbuff_written)
 +		iso9660->wbuff_written = iso9660->wbuff_offset;
 +	iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
 +	if (nw) {
 +		iso9660->wbuff_remaining -= nw;
 +		memmove(iso9660->wbuff, iso9660->wbuff + wsize - nw, nw);
 +	}
 +	return (r);
 +}
 +
 +static int
 +wb_consume(struct archive_write *a, size_t size)
 +{
 +	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
 +
 +	if (size > iso9660->wbuff_remaining ||
 +	    iso9660->wbuff_remaining == 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Internal Programing error: iso9660:wb_consume()"
 +		    " size=%jd, wbuff_remaining=%jd",
 +		    (intmax_t)size, (intmax_t)iso9660->wbuff_remaining);
 +		return (ARCHIVE_FATAL);
 +	}
 +	iso9660->wbuff_remaining -= size;
 +	if (iso9660->wbuff_remaining < LOGICAL_BLOCK_SIZE)
 +		return (wb_write_out(a));
 +	return (ARCHIVE_OK);
 +}
 +
 +#ifdef HAVE_ZLIB_H
 +
 +static int
 +wb_set_offset(struct archive_write *a, int64_t off)
 +{
 +	struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
 +	int64_t used, ext_bytes;
 +
 +	if (iso9660->wbuff_type != WB_TO_TEMP) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Internal Programing error: iso9660:wb_set_offset()");
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	used = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
 +	if (iso9660->wbuff_offset + used > iso9660->wbuff_tail)
 +		iso9660->wbuff_tail = iso9660->wbuff_offset + used;
 +	if (iso9660->wbuff_offset < iso9660->wbuff_written) {
 +		if (used > 0 &&
- 		    write_to_temp(a, iso9660->wbuff, used) != ARCHIVE_OK)
++		    write_to_temp(a, iso9660->wbuff, (size_t)used) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		iso9660->wbuff_offset = iso9660->wbuff_written;
 +		lseek(iso9660->temp_fd, iso9660->wbuff_offset, SEEK_SET);
 +		iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
 +		used = 0;
 +	}
 +	if (off < iso9660->wbuff_offset) {
 +		/*
 +		 * Write out waiting data.
 +		 */
 +		if (used > 0) {
 +			if (wb_write_out(a) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		}
 +		lseek(iso9660->temp_fd, off, SEEK_SET);
 +		iso9660->wbuff_offset = off;
 +		iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
 +	} else if (off <= iso9660->wbuff_tail) {
- 		iso9660->wbuff_remaining =
- 		    sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset);
++		iso9660->wbuff_remaining = (size_t)
++		    (sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset));
 +	} else {
 +		ext_bytes = off - iso9660->wbuff_tail;
- 		iso9660->wbuff_remaining = sizeof(iso9660->wbuff)
- 		   - (iso9660->wbuff_tail - iso9660->wbuff_offset);
- 		while (ext_bytes >= iso9660->wbuff_remaining) {
++		iso9660->wbuff_remaining = (size_t)(sizeof(iso9660->wbuff)
++		   - (iso9660->wbuff_tail - iso9660->wbuff_offset));
++		while (ext_bytes >= (int64_t)iso9660->wbuff_remaining) {
 +			if (write_null(a, (size_t)iso9660->wbuff_remaining)
 +			    != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			ext_bytes -= iso9660->wbuff_remaining;
 +		}
 +		if (ext_bytes > 0) {
 +			if (write_null(a, (size_t)ext_bytes) != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +		}
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +#endif /* HAVE_ZLIB_H */
 +
 +static int
 +write_null(struct archive_write *a, size_t size)
 +{
 +	size_t remaining;
 +	unsigned char *p, *old;
 +	int r;
 +
 +	remaining = wb_remaining(a);
 +	p = wb_buffptr(a);
 +	if (size <= remaining) {
 +		memset(p, 0, size);
 +		return (wb_consume(a, size));
 +	}
 +	memset(p, 0, remaining);
 +	r = wb_consume(a, remaining);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	size -= remaining;
 +	old = p;
 +	p = wb_buffptr(a);
 +	memset(p, 0, old - p);
 +	remaining = wb_remaining(a);
 +	while (size) {
 +		size_t wsize = size;
 +
 +		if (wsize > remaining)
 +			wsize = remaining;
 +		r = wb_consume(a, wsize);
 +		if (r != ARCHIVE_OK)
 +			return (r);
 +		size -= wsize;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Write Volume Descriptor Set Terminator
 + */
 +static int
 +write_VD_terminator(struct archive_write *a)
 +{
 +	unsigned char *bp;
 +
 +	bp = wb_buffptr(a) -1;
 +	set_VD_bp(bp, VDT_TERMINATOR, 1);
 +	set_unused_field_bp(bp, 8, LOGICAL_BLOCK_SIZE);
 +
 +	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
 +}
 +
 +static int
 +set_file_identifier(unsigned char *bp, int from, int to, enum vdc vdc,
 +    struct archive_write *a, struct vdd *vdd, struct archive_string *id,
 +    const char *label, int leading_under, enum char_type char_type)
 +{
 +	char identifier[256];
 +	struct isoent *isoent;
 +	const char *ids;
 +	size_t len;
 +	int r;
 +
 +	if (id->length > 0 && leading_under && id->s[0] != '_') {
 +		if (char_type == A_CHAR)
 +			r = set_str_a_characters_bp(a, bp, from, to, id->s, vdc);
 +		else
 +			r = set_str_d_characters_bp(a, bp, from, to, id->s, vdc);
 +	} else if (id->length > 0) {
 +		ids = id->s;
 +		if (leading_under)
 +			ids++;
 +		isoent = isoent_find_entry(vdd->rootent, ids);
 +		if (isoent == NULL) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Not Found %s `%s'.",
 +			    label, ids);
 +			return (ARCHIVE_FATAL);
 +		}
 +		len = isoent->ext_off + isoent->ext_len;
 +		if (vdd->vdd_type == VDD_JOLIET) {
 +			if (len > sizeof(identifier)-2)
 +				len = sizeof(identifier)-2;
 +		} else {
 +			if (len > sizeof(identifier)-1)
 +				len = sizeof(identifier)-1;
 +		}
 +		memcpy(identifier, isoent->identifier, len);
 +		identifier[len] = '\0';
 +		if (vdd->vdd_type == VDD_JOLIET) {
 +			identifier[len+1] = 0;
 +			vdc = VDC_UCS2_DIRECT;
 +		}
 +		if (char_type == A_CHAR)
 +			r = set_str_a_characters_bp(a, bp, from, to,
 +			    identifier, vdc);
 +		else
 +			r = set_str_d_characters_bp(a, bp, from, to,
 +			    identifier, vdc);
 +	} else {
 +		if (char_type == A_CHAR)
 +			r = set_str_a_characters_bp(a, bp, from, to, NULL, vdc);
 +		else
 +			r = set_str_d_characters_bp(a, bp, from, to, NULL, vdc);
 +	}
 +	return (r);
 +}
 +
 +/*
 + * Write Primary/Supplementary Volume Descriptor
 + */
 +static int
 +write_VD(struct archive_write *a, struct vdd *vdd)
 +{
 +	struct iso9660 *iso9660;
 +	unsigned char *bp;
 +	uint16_t volume_set_size = 1;
 +	char identifier[256];
 +	enum VD_type vdt;
 +	enum vdc vdc;
 +	unsigned char vd_ver, fst_ver;
 +	int r;
 +
 +	iso9660 = a->format_data;
 +	switch (vdd->vdd_type) {
 +	case VDD_JOLIET:
 +		vdt = VDT_SUPPLEMENTARY;
 +		vd_ver = fst_ver = 1;
 +		vdc = VDC_UCS2;
 +		break;
 +	case VDD_ENHANCED:
 +		vdt = VDT_SUPPLEMENTARY;
 +		vd_ver = fst_ver = 2;
 +		vdc = VDC_LOWERCASE;
 +		break;
 +	case VDD_PRIMARY:
 +	default:
 +		vdt = VDT_PRIMARY;
 +		vd_ver = fst_ver = 1;
 +#ifdef COMPAT_MKISOFS
 +		vdc = VDC_LOWERCASE;
 +#else
 +		vdc = VDC_STD;
 +#endif
 +		break;
 +	}
 +
 +	bp = wb_buffptr(a) -1;
 +	/* Volume Descriptor Type */
 +	set_VD_bp(bp, vdt, vd_ver);
 +	/* Unused Field */
 +	set_unused_field_bp(bp, 8, 8);
 +	/* System Identifier */
 +	get_system_identitier(identifier, sizeof(identifier));
 +	r = set_str_a_characters_bp(a, bp, 9, 40, identifier, vdc);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Volume Identifier */
 +	r = set_str_d_characters_bp(a, bp, 41, 72,
 +	    iso9660->volume_identifier.s, vdc);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Unused Field */
 +	set_unused_field_bp(bp, 73, 80);
 +	/* Volume Space Size */
 +	set_num_733(bp+81, iso9660->volume_space_size);
 +	if (vdd->vdd_type == VDD_JOLIET) {
 +		/* Escape Sequences */
 +		bp[89] = 0x25;/* UCS-2 Level 3 */
 +		bp[90] = 0x2F;
 +		bp[91] = 0x45;
 +		memset(bp + 92, 0, 120 - 92 + 1);
 +	} else {
 +		/* Unused Field */
 +		set_unused_field_bp(bp, 89, 120);
 +	}
 +	/* Volume Set Size */
 +	set_num_723(bp+121, volume_set_size);
 +	/* Volume Sequence Number */
 +	set_num_723(bp+125, iso9660->volume_sequence_number);
 +	/* Logical Block Size */
 +	set_num_723(bp+129, LOGICAL_BLOCK_SIZE);
 +	/* Path Table Size */
 +	set_num_733(bp+133, vdd->path_table_size);
 +	/* Location of Occurrence of Type L Path Table */
 +	set_num_731(bp+141, vdd->location_type_L_path_table);
 +	/* Location of Optional Occurrence of Type L Path Table */
 +	set_num_731(bp+145, 0);
 +	/* Location of Occurrence of Type M Path Table */
 +	set_num_732(bp+149, vdd->location_type_M_path_table);
 +	/* Location of Optional Occurrence of Type M Path Table */
 +	set_num_732(bp+153, 0);
 +	/* Directory Record for Root Directory(BP 157 to 190) */
 +	set_directory_record(bp+157, 190-157+1, vdd->rootent,
 +	    iso9660, DIR_REC_VD, vdd->vdd_type);
 +	/* Volume Set Identifier */
 +	r = set_str_d_characters_bp(a, bp, 191, 318, "", vdc);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Publisher Identifier */
 +	r = set_file_identifier(bp, 319, 446, vdc, a, vdd,
 +	    &(iso9660->publisher_identifier),
 +	    "Publisher File", 1, A_CHAR);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Data Preparer Identifier */
 +	r = set_file_identifier(bp, 447, 574, vdc, a, vdd,
 +	    &(iso9660->data_preparer_identifier),
 +	    "Data Preparer File", 1, A_CHAR);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Application Identifier */
 +	r = set_file_identifier(bp, 575, 702, vdc, a, vdd,
 +	    &(iso9660->application_identifier),
 +	    "Application File", 1, A_CHAR);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Copyright File Identifier */
 +	r = set_file_identifier(bp, 703, 739, vdc, a, vdd,
 +	    &(iso9660->copyright_file_identifier),
 +	    "Copyright File", 0, D_CHAR);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Abstract File Identifier */
 +	r = set_file_identifier(bp, 740, 776, vdc, a, vdd,
 +	    &(iso9660->abstract_file_identifier),
 +	    "Abstract File", 0, D_CHAR);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Bibliongraphic File Identifier */
 +	r = set_file_identifier(bp, 777, 813, vdc, a, vdd,
 +	    &(iso9660->bibliographic_file_identifier),
 +	    "Bibliongraphic File", 0, D_CHAR);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* Volume Creation Date and Time */
 +	set_date_time(bp+814, iso9660->birth_time);
 +	/* Volume Modification Date and Time */
 +	set_date_time(bp+831, iso9660->birth_time);
 +	/* Volume Expiration Date and Time(obsolete) */
 +	set_date_time_null(bp+848);
 +	/* Volume Effective Date and Time */
 +	set_date_time(bp+865, iso9660->birth_time);
 +	/* File Structure Version */
 +	bp[882] = fst_ver;
 +	/* Reserved */
 +	bp[883] = 0;
 +	/* Application Use */
 +	memset(bp + 884, 0x20, 1395 - 884 + 1);
 +	/* Reserved */
 +	set_unused_field_bp(bp, 1396, LOGICAL_BLOCK_SIZE);
 +
 +	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
 +}
 +
 +/*
 + * Write Boot Record Volume Descriptor
 + */
 +static int
 +write_VD_boot_record(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660;
 +	unsigned char *bp;
 +
 +	iso9660 = a->format_data;
 +	bp = wb_buffptr(a) -1;
 +	/* Volume Descriptor Type */
 +	set_VD_bp(bp, VDT_BOOT_RECORD, 1);
 +	/* Boot System Identifier */
 +	memcpy(bp+8, "EL TORITO SPECIFICATION", 23);
 +	set_unused_field_bp(bp, 8+23, 39);
 +	/* Unused */
 +	set_unused_field_bp(bp, 40, 71);
 +	/* Absolute pointer to first sector of Boot Catalog */
 +	set_num_731(bp+72,
 +	    iso9660->el_torito.catalog->file->content.location);
 +	/* Unused */
 +	set_unused_field_bp(bp, 76, LOGICAL_BLOCK_SIZE);
 +
 +	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
 +}
 +
 +enum keytype {
 +	KEY_FLG,
 +	KEY_STR,
 +	KEY_INT,
 +	KEY_HEX
 +};
 +static void
 +set_option_info(struct archive_string *info, int *opt, const char *key,
 +    enum keytype type,  ...)
 +{
 +	va_list ap;
 +	char prefix;
 +	const char *s;
 +	int d;
 +
 +	prefix = (*opt==0)? ' ':',';
 +	va_start(ap, type);
 +	switch (type) {
 +	case KEY_FLG:
 +		d = va_arg(ap, int);
 +		archive_string_sprintf(info, "%c%s%s",
 +		    prefix, (d == 0)?"!":"", key);
 +		break;
 +	case KEY_STR:
 +		s = va_arg(ap, const char *);
 +		archive_string_sprintf(info, "%c%s=%s",
 +		    prefix, key, s);
 +		break;
 +	case KEY_INT:
 +		d = va_arg(ap, int);
 +		archive_string_sprintf(info, "%c%s=%d",
 +		    prefix, key, d);
 +		break;
 +	case KEY_HEX:
 +		d = va_arg(ap, int);
 +		archive_string_sprintf(info, "%c%s=%x",
 +		    prefix, key, d);
 +		break;
 +	}
 +	va_end(ap);
 +
 +	*opt = 1;
 +}
 +
 +/*
 + * Make Non-ISO File System Information
 + */
 +static int
 +write_information_block(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660;
 +	char buf[128];
 +	const char *v;
 +	int opt, r;
 +	struct archive_string info;
 +	size_t info_size = LOGICAL_BLOCK_SIZE *
 +			       NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
 +
 +	iso9660 = (struct iso9660 *)a->format_data;
 +	if (info_size > wb_remaining(a)) {
 +		r = wb_write_out(a);
 +		if (r != ARCHIVE_OK)
 +			return (r);
 +	}
 +	archive_string_init(&info);
 +	if (archive_string_ensure(&info, info_size) == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	memset(info.s, 0, info_size);
 +	opt = 0;
 +#if defined(HAVE__CTIME64_S)
 +	_ctime64_s(buf, sizeof(buf), &(iso9660->birth_time));
 +#elif defined(HAVE_CTIME_R)
 +	ctime_r(&(iso9660->birth_time), buf);
 +#else
 +	strncpy(buf, ctime(&(iso9660->birth_time)), sizeof(buf)-1);
 +	buf[sizeof(buf)-1] = '\0';
 +#endif
 +	archive_string_sprintf(&info,
 +	    "INFO %s%s", buf, archive_version_string());
 +	if (iso9660->opt.abstract_file != OPT_ABSTRACT_FILE_DEFAULT)
 +		set_option_info(&info, &opt, "abstract-file",
 +		    KEY_STR, iso9660->abstract_file_identifier.s);
 +	if (iso9660->opt.application_id != OPT_APPLICATION_ID_DEFAULT)
 +		set_option_info(&info, &opt, "application-id",
 +		    KEY_STR, iso9660->application_identifier.s);
 +	if (iso9660->opt.allow_vernum != OPT_ALLOW_VERNUM_DEFAULT)
 +		set_option_info(&info, &opt, "allow-vernum",
 +		    KEY_FLG, iso9660->opt.allow_vernum);
 +	if (iso9660->opt.biblio_file != OPT_BIBLIO_FILE_DEFAULT)
 +		set_option_info(&info, &opt, "biblio-file",
 +		    KEY_STR, iso9660->bibliographic_file_identifier.s);
 +	if (iso9660->opt.boot != OPT_BOOT_DEFAULT)
 +		set_option_info(&info, &opt, "boot",
 +		    KEY_STR, iso9660->el_torito.boot_filename.s);
 +	if (iso9660->opt.boot_catalog != OPT_BOOT_CATALOG_DEFAULT)
 +		set_option_info(&info, &opt, "boot-catalog",
 +		    KEY_STR, iso9660->el_torito.catalog_filename.s);
 +	if (iso9660->opt.boot_info_table != OPT_BOOT_INFO_TABLE_DEFAULT)
 +		set_option_info(&info, &opt, "boot-info-table",
 +		    KEY_FLG, iso9660->opt.boot_info_table);
 +	if (iso9660->opt.boot_load_seg != OPT_BOOT_LOAD_SEG_DEFAULT)
 +		set_option_info(&info, &opt, "boot-load-seg",
 +		    KEY_HEX, iso9660->el_torito.boot_load_seg);
 +	if (iso9660->opt.boot_load_size != OPT_BOOT_LOAD_SIZE_DEFAULT)
 +		set_option_info(&info, &opt, "boot-load-size",
 +		    KEY_INT, iso9660->el_torito.boot_load_size);
 +	if (iso9660->opt.boot_type != OPT_BOOT_TYPE_DEFAULT) {
 +		v = "no-emulation";
 +		if (iso9660->opt.boot_type == OPT_BOOT_TYPE_FD)
 +			v = "fd";
 +		if (iso9660->opt.boot_type == OPT_BOOT_TYPE_HARD_DISK)
 +			v = "hard-disk";
 +		set_option_info(&info, &opt, "boot-type",
 +		    KEY_STR, v);
 +	}
 +#ifdef HAVE_ZLIB_H
 +	if (iso9660->opt.compression_level != OPT_COMPRESSION_LEVEL_DEFAULT)
 +		set_option_info(&info, &opt, "compression-level",
 +		    KEY_INT, iso9660->zisofs.compression_level);
 +#endif
 +	if (iso9660->opt.copyright_file != OPT_COPYRIGHT_FILE_DEFAULT)
 +		set_option_info(&info, &opt, "copyright-file",
 +		    KEY_STR, iso9660->copyright_file_identifier.s);
 +	if (iso9660->opt.iso_level != OPT_ISO_LEVEL_DEFAULT)
 +		set_option_info(&info, &opt, "iso-level",
 +		    KEY_INT, iso9660->opt.iso_level);
 +	if (iso9660->opt.joliet != OPT_JOLIET_DEFAULT) {
 +		if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
 +			set_option_info(&info, &opt, "joliet",
 +			    KEY_STR, "long");
 +		else
 +			set_option_info(&info, &opt, "joliet",
 +			    KEY_FLG, iso9660->opt.joliet);
 +	}
 +	if (iso9660->opt.limit_depth != OPT_LIMIT_DEPTH_DEFAULT)
 +		set_option_info(&info, &opt, "limit-depth",
 +		    KEY_FLG, iso9660->opt.limit_depth);
 +	if (iso9660->opt.limit_dirs != OPT_LIMIT_DIRS_DEFAULT)
 +		set_option_info(&info, &opt, "limit-dirs",
 +		    KEY_FLG, iso9660->opt.limit_dirs);
 +	if (iso9660->opt.pad != OPT_PAD_DEFAULT)
 +		set_option_info(&info, &opt, "pad",
 +		    KEY_FLG, iso9660->opt.pad);
 +	if (iso9660->opt.publisher != OPT_PUBLISHER_DEFAULT)
 +		set_option_info(&info, &opt, "publisher",
 +		    KEY_STR, iso9660->publisher_identifier.s);
 +	if (iso9660->opt.rr != OPT_RR_DEFAULT) {
 +		if (iso9660->opt.rr == OPT_RR_DISABLED)
 +			set_option_info(&info, &opt, "rockridge",
 +			    KEY_FLG, iso9660->opt.rr);
 +		else if (iso9660->opt.rr == OPT_RR_STRICT)
 +			set_option_info(&info, &opt, "rockridge",
 +			    KEY_STR, "strict");
 +		else if (iso9660->opt.rr == OPT_RR_USEFUL)
 +			set_option_info(&info, &opt, "rockridge",
 +			    KEY_STR, "useful");
 +	}
 +	if (iso9660->opt.volume_id != OPT_VOLUME_ID_DEFAULT)
 +		set_option_info(&info, &opt, "volume-id",
 +		    KEY_STR, iso9660->volume_identifier.s);
 +	if (iso9660->opt.zisofs != OPT_ZISOFS_DEFAULT)
 +		set_option_info(&info, &opt, "zisofs",
 +		    KEY_FLG, iso9660->opt.zisofs);
 +
 +	memcpy(wb_buffptr(a), info.s, info_size);
 +	archive_string_free(&info);
 +	return (wb_consume(a, info_size));
 +}
 +
 +static int
 +write_rr_ER(struct archive_write *a)
 +{
 +	unsigned char *p;
 +
 +	p = wb_buffptr(a);
 +
 +	memset(p, 0, LOGICAL_BLOCK_SIZE);
 +	p[0] = 'E';
 +	p[1] = 'R';
 +	p[3] = 0x01;
 +	p[2] = RRIP_ER_SIZE;
 +	p[4] = RRIP_ER_ID_SIZE;
 +	p[5] = RRIP_ER_DSC_SIZE;
 +	p[6] = RRIP_ER_SRC_SIZE;
 +	p[7] = 0x01;
 +	memcpy(&p[8], rrip_identifier, p[4]);
 +	memcpy(&p[8+p[4]], rrip_descriptor, p[5]);
 +	memcpy(&p[8+p[4]+p[5]], rrip_source, p[6]);
 +
 +	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
 +}
 +
 +static void
 +calculate_path_table_size(struct vdd *vdd)
 +{
 +	int depth, size;
 +	struct path_table *pt;
 +
 +	pt = vdd->pathtbl;
 +	size = 0;
 +	for (depth = 0; depth < vdd->max_depth; depth++) {
 +		struct isoent **ptbl;
 +		int i, cnt;
 +
 +		if ((cnt = pt[depth].cnt) == 0)
 +			break;
 +
 +		ptbl = pt[depth].sorted;
 +		for (i = 0; i < cnt; i++) {
 +			int len;
 +
 +			if (ptbl[i]->identifier == NULL)
 +				len = 1; /* root directory */
 +			else
 +				len = ptbl[i]->id_len;
 +			if (len & 0x01)
 +				len++; /* Padding Field */
 +			size += 8 + len;
 +		}
 +	}
 +	vdd->path_table_size = size;
 +	vdd->path_table_block =
 +	    ((size + PATH_TABLE_BLOCK_SIZE -1) /
 +	    PATH_TABLE_BLOCK_SIZE) *
 +	    (PATH_TABLE_BLOCK_SIZE / LOGICAL_BLOCK_SIZE);
 +}
 +
 +static int
 +_write_path_table(struct archive_write *a, int type_m, int depth,
 +    struct vdd *vdd)
 +{
 +	unsigned char *bp, *wb;
 +	struct isoent **ptbl;
 +	size_t wbremaining;
 +	int i, r, wsize;
 +
 +	if (vdd->pathtbl[depth].cnt == 0)
 +		return (0);
 +
 +	wsize = 0;
 +	wb = wb_buffptr(a);
 +	wbremaining = wb_remaining(a);
 +	bp = wb - 1;
 +	ptbl = vdd->pathtbl[depth].sorted;
 +	for (i = 0; i < vdd->pathtbl[depth].cnt; i++) {
 +		struct isoent *np;
 +		size_t len;
 +
 +		np = ptbl[i];
 +		if (np->identifier == NULL)
 +			len = 1; /* root directory */
 +		else
 +			len = np->id_len;
 +		if (wbremaining - ((bp+1) - wb) < (len + 1 + 8)) {
 +			r = wb_consume(a, (bp+1) - wb);
 +			if (r < 0)
 +				return (r);
 +			wb = wb_buffptr(a);
 +			wbremaining = wb_remaining(a);
 +			bp = wb -1;
 +		}
 +		/* Length of Directory Identifier */
- 		set_num_711(bp+1, len);
++		set_num_711(bp+1, (unsigned char)len);
 +		/* Extended Attribute Record Length */
 +		set_num_711(bp+2, 0);
 +		/* Location of Extent */
 +		if (type_m)
 +			set_num_732(bp+3, np->dir_location);
 +		else
 +			set_num_731(bp+3, np->dir_location);
 +		/* Parent Directory Number */
 +		if (type_m)
 +			set_num_722(bp+7, np->parent->dir_number);
 +		else
 +			set_num_721(bp+7, np->parent->dir_number);
 +		/* Directory Identifier */
 +		if (np->identifier == NULL)
 +			bp[9] = 0;
 +		else
 +			memcpy(&bp[9], np->identifier, len);
 +		if (len & 0x01) {
 +			/* Padding Field */
 +			bp[9+len] = 0;
 +			len++;
 +		}
- 		wsize += 8 + len;
++		wsize += 8 + (int)len;
 +		bp += 8 + len;
 +	}
 +	if ((bp + 1) > wb) {
 +		r = wb_consume(a, (bp+1)-wb);
 +		if (r < 0)
 +			return (r);
 +	}
 +	return (wsize);
 +}
 +
 +static int
 +write_path_table(struct archive_write *a, int type_m, struct vdd *vdd)
 +{
 +	int depth, r;
 +	size_t path_table_size;
 +
 +	r = ARCHIVE_OK;
 +	path_table_size = 0;
 +	for (depth = 0; depth < vdd->max_depth; depth++) {
 +		r = _write_path_table(a, type_m, depth, vdd);
 +		if (r < 0)
 +			return (r);
 +		path_table_size += r;
 +	}
 +
 +	/* Write padding data. */
 +	path_table_size = path_table_size % PATH_TABLE_BLOCK_SIZE;
 +	if (path_table_size > 0)
 +		r = write_null(a, PATH_TABLE_BLOCK_SIZE - path_table_size);
 +	return (r);
 +}
 +
 +static int
 +calculate_directory_descriptors(struct iso9660 *iso9660, struct vdd *vdd,
 +    struct isoent *isoent, int depth)
 +{
 +	struct isoent **enttbl;
 +	int bs, block, i;
 +
 +	block = 1;
 +	bs = get_dir_rec_size(iso9660, isoent, DIR_REC_SELF, vdd->vdd_type);
 +	bs += get_dir_rec_size(iso9660, isoent, DIR_REC_PARENT, vdd->vdd_type);
 +
 +	if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
 +	    !iso9660->opt.rr && depth + 1 >= vdd->max_depth))
 +		return (block);
 +
 +	enttbl = isoent->children_sorted;
 +	for (i = 0; i < isoent->children.cnt; i++) {
 +		struct isoent *np = enttbl[i];
 +		struct isofile *file;
 +
 +		file = np->file;
 +		if (file->hardlink_target != NULL)
 +			file = file->hardlink_target;
 +		file->cur_content = &(file->content);
 +		do {
 +			int dr_l;
 +
 +			dr_l = get_dir_rec_size(iso9660, np, DIR_REC_NORMAL,
 +			    vdd->vdd_type);
 +			if ((bs + dr_l) > LOGICAL_BLOCK_SIZE) {
 +				block ++;
 +				bs = dr_l;
 +			} else
 +				bs += dr_l;
 +			file->cur_content = file->cur_content->next;
 +		} while (file->cur_content != NULL);
 +	}
 +	return (block);
 +}
 +
 +static int
 +_write_directory_descriptors(struct archive_write *a, struct vdd *vdd,
 +    struct isoent *isoent, int depth)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isoent **enttbl;
 +	unsigned char *p, *wb;
 +	int i, r;
 +	int dr_l;
 +
 +	p = wb = wb_buffptr(a);
 +#define WD_REMAINING	(LOGICAL_BLOCK_SIZE - (p - wb))
 +	p += set_directory_record(p, WD_REMAINING, isoent,
 +	    iso9660, DIR_REC_SELF, vdd->vdd_type);
 +	p += set_directory_record(p, WD_REMAINING, isoent,
 +	    iso9660, DIR_REC_PARENT, vdd->vdd_type);
 +
 +	if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
 +	    !iso9660->opt.rr && depth + 1 >= vdd->max_depth)) {
 +		memset(p, 0, WD_REMAINING);
 +		return (wb_consume(a, LOGICAL_BLOCK_SIZE));
 +	}
 +
 +	enttbl = isoent->children_sorted;
 +	for (i = 0; i < isoent->children.cnt; i++) {
 +		struct isoent *np = enttbl[i];
 +		struct isofile *file = np->file;
 +
 +		if (file->hardlink_target != NULL)
 +			file = file->hardlink_target;
 +		file->cur_content = &(file->content);
 +		do {
 +			dr_l = set_directory_record(p, WD_REMAINING,
 +			    np, iso9660, DIR_REC_NORMAL,
 +			    vdd->vdd_type);
 +			if (dr_l == 0) {
 +				memset(p, 0, WD_REMAINING);
 +				r = wb_consume(a, LOGICAL_BLOCK_SIZE);
 +				if (r < 0)
 +					return (r);
 +				p = wb = wb_buffptr(a);
 +				dr_l = set_directory_record(p,
 +				    WD_REMAINING, np, iso9660,
 +				    DIR_REC_NORMAL, vdd->vdd_type);
 +			}
 +			p += dr_l;
 +			file->cur_content = file->cur_content->next;
 +		} while (file->cur_content != NULL);
 +	}
 +	memset(p, 0, WD_REMAINING);
 +	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
 +}
 +
 +static int
 +write_directory_descriptors(struct archive_write *a, struct vdd *vdd)
 +{
 +	struct isoent *np;
 +	int depth, r;
 +
 +	depth = 0;
 +	np = vdd->rootent;
 +	do {
 +		struct extr_rec *extr;
 +
 +		r = _write_directory_descriptors(a, vdd, np, depth);
 +		if (r < 0)
 +			return (r);
 +		if (vdd->vdd_type != VDD_JOLIET) {
 +			/*
 +			 * This extract record is used by SUSP,RRIP.
 +			 * Not for joliet.
 +			 */
 +			for (extr = np->extr_rec_list.first;
 +			    extr != NULL;
 +			    extr = extr->next) {
 +				unsigned char *wb;
 +
 +				wb = wb_buffptr(a);
 +				memcpy(wb, extr->buf, extr->offset);
 +				memset(wb + extr->offset, 0,
 +				    LOGICAL_BLOCK_SIZE - extr->offset);
 +				r = wb_consume(a, LOGICAL_BLOCK_SIZE);
 +				if (r < 0)
 +					return (r);
 +			}
 +		}
 +
 +		if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
 +			/* Enter to sub directories. */
 +			np = np->subdirs.first;
 +			depth++;
 +			continue;
 +		}
 +		while (np != np->parent) {
 +			if (np->drnext == NULL) {
 +				/* Return to the parent directory. */
 +				np = np->parent;
 +				depth--;
 +			} else {
 +				np = np->drnext;
 +				break;
 +			}
 +		}
 +	} while (np != np->parent);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Read file contents from the temporary file, and write it.
 + */
 +static int
 +write_file_contents(struct archive_write *a, int64_t offset, int64_t size)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	int r;
 +
 +	lseek(iso9660->temp_fd, offset, SEEK_SET);
 +
 +	while (size) {
 +		size_t rsize;
 +		ssize_t rs;
 +		unsigned char *wb;
 +
 +		wb = wb_buffptr(a);
 +		rsize = wb_remaining(a);
 +		if (rsize > (size_t)size)
 +			rsize = (size_t)size;
 +		rs = read(iso9660->temp_fd, wb, rsize);
 +		if (rs <= 0) {
 +			archive_set_error(&a->archive, errno,
 +			    "Can't read temporary file(%jd)", (intmax_t)rs);
 +			return (ARCHIVE_FATAL);
 +		}
 +		size -= rs;
 +		r = wb_consume(a, rs);
 +		if (r < 0)
 +			return (r);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +write_file_descriptors(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isofile *file;
 +	int64_t blocks, offset;
 +	int r;
 +
 +	blocks = 0;
 +	offset = 0;
 +
 +	/* Make the boot catalog contents, and write it. */
 +	if (iso9660->el_torito.catalog != NULL) {
 +		r = make_boot_catalog(a);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Write the boot file contents. */
 +	if (iso9660->el_torito.boot != NULL) {
- 		struct isofile *file = iso9660->el_torito.boot->file;
- 
++		file = iso9660->el_torito.boot->file;
 +		blocks = file->content.blocks;
 +		offset = file->content.offset_of_temp;
 +		if (offset != 0) {
 +			r = write_file_contents(a, offset,
 +			    blocks << LOGICAL_BLOCK_BITS);
 +			if (r < 0)
 +				return (r);
 +			blocks = 0;
 +			offset = 0;
 +		}
 +	}
 +
 +	/* Write out all file contents. */
 +	for (file = iso9660->data_file_list.first;
 +	    file != NULL; file = file->datanext) {
 +
 +		if (!file->write_content)
 +			continue;
 +
 +		if ((offset + (blocks << LOGICAL_BLOCK_BITS)) <
 +		     file->content.offset_of_temp) {
 +			if (blocks > 0) {
 +				r = write_file_contents(a, offset,
 +				    blocks << LOGICAL_BLOCK_BITS);
 +				if (r < 0)
 +					return (r);
 +			}
 +			blocks = 0;
 +			offset = file->content.offset_of_temp;
 +		}
 +
 +		file->cur_content = &(file->content);
 +		do {
 +			blocks += file->cur_content->blocks;
 +			/* Next fragument */
 +			file->cur_content = file->cur_content->next;
 +		} while (file->cur_content != NULL);
 +	}
 +
 +	/* Flush out remaining blocks. */
 +	if (blocks > 0) {
 +		r = write_file_contents(a, offset,
 +		    blocks << LOGICAL_BLOCK_BITS);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +isofile_init_entry_list(struct iso9660 *iso9660)
 +{
 +	iso9660->all_file_list.first = NULL;
 +	iso9660->all_file_list.last = &(iso9660->all_file_list.first);
 +}
 +
 +static void
 +isofile_add_entry(struct iso9660 *iso9660, struct isofile *file)
 +{
 +	file->allnext = NULL;
 +	*iso9660->all_file_list.last = file;
 +	iso9660->all_file_list.last = &(file->allnext);
 +}
 +
 +static void
 +isofile_free_all_entries(struct iso9660 *iso9660)
 +{
 +	struct isofile *file, *file_next;
 +
 +	file = iso9660->all_file_list.first;
 +	while (file != NULL) {
 +		file_next = file->allnext;
 +		isofile_free(file);
 +		file = file_next;
 +	}
 +}
 +
 +static void
 +isofile_init_entry_data_file_list(struct iso9660 *iso9660)
 +{
 +	iso9660->data_file_list.first = NULL;
 +	iso9660->data_file_list.last = &(iso9660->data_file_list.first);
 +}
 +
 +static void
 +isofile_add_data_file(struct iso9660 *iso9660, struct isofile *file)
 +{
 +	file->datanext = NULL;
 +	*iso9660->data_file_list.last = file;
 +	iso9660->data_file_list.last = &(file->datanext);
 +}
 +
 +
 +static struct isofile *
 +isofile_new(struct archive_write *a, struct archive_entry *entry)
 +{
 +	struct isofile *file;
 +
 +	file = calloc(1, sizeof(*file));
 +	if (file == NULL)
 +		return (NULL);
 +
 +	if (entry != NULL)
 +		file->entry = archive_entry_clone(entry);
 +	else
 +		file->entry = archive_entry_new2(&a->archive);
 +	if (file->entry == NULL) {
 +		free(file);
 +		return (NULL);
 +	}
 +	archive_string_init(&(file->parentdir));
 +	archive_string_init(&(file->basename));
 +	archive_string_init(&(file->basename_utf16));
 +	archive_string_init(&(file->symlink));
 +	file->cur_content = &(file->content);
 +
 +	return (file);
 +}
 +
 +static void
 +isofile_free(struct isofile *file)
 +{
 +	struct content *con, *tmp;
 +
 +	con = file->content.next;
 +	while (con != NULL) {
 +		tmp = con;
 +		con = con->next;
 +		free(tmp);
 +	}
 +	archive_entry_free(file->entry);
 +	archive_string_free(&(file->parentdir));
 +	archive_string_free(&(file->basename));
 +	archive_string_free(&(file->basename_utf16));
 +	archive_string_free(&(file->symlink));
 +	free(file);
 +}
 +
 +#if defined(_WIN32) || defined(__CYGWIN__)
 +static int
 +cleanup_backslash_1(char *p)
 +{
 +	int mb, dos;
 +
 +	mb = dos = 0;
 +	while (*p) {
 +		if (*(unsigned char *)p > 127)
 +			mb = 1;
 +		if (*p == '\\') {
 +			/* If we have not met any multi-byte characters,
 +			 * we can replace '\' with '/'. */
 +			if (!mb)
 +				*p = '/';
 +			dos = 1;
 +		}
 +		p++;
 +	}
 +	if (!mb || !dos)
 +		return (0);
 +	return (-1);
 +}
 +
 +static void
 +cleanup_backslash_2(wchar_t *p)
 +{
 +
 +	/* Convert a path-separator from '\' to  '/' */
 +	while (*p != L'\0') {
 +		if (*p == L'\\')
 +			*p = L'/';
 +		p++;
 +	}
 +}
 +#endif
 +
 +/*
 + * Generate a parent directory name and a base name from a pathname.
 + */
 +static int
 +isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
 +{
 +	struct iso9660 *iso9660;
 +	const char *pathname;
 +	char *p, *dirname, *slash;
 +	size_t len;
 +	int ret = ARCHIVE_OK;
 +
 +	iso9660 = a->format_data;
 +
 +	archive_string_empty(&(file->parentdir));
 +	archive_string_empty(&(file->basename));
 +	archive_string_empty(&(file->basename_utf16));
 +	archive_string_empty(&(file->symlink));
 +
 +	pathname =  archive_entry_pathname(file->entry);
 +	if (pathname == NULL || pathname[0] == '\0') {/* virtual root */
 +		file->dircnt = 0;
 +		return (ret);
 +	}
 +
 +	/*
 +	 * Make a UTF-16BE basename if Joliet extension enabled.
 +	 */
 +	if (iso9660->opt.joliet) {
 +		const char *u16, *ulast;
 +		size_t u16len, ulen_last;
 +
 +		if (iso9660->sconv_to_utf16be == NULL) {
 +			iso9660->sconv_to_utf16be =
 +			    archive_string_conversion_to_charset(
 +				&(a->archive), "UTF-16BE", 1);
 +			if (iso9660->sconv_to_utf16be == NULL)
 +				/* Couldn't allocate memory */
 +				return (ARCHIVE_FATAL);
 +			iso9660->sconv_from_utf16be =
 +			    archive_string_conversion_from_charset(
 +				&(a->archive), "UTF-16BE", 1);
 +			if (iso9660->sconv_from_utf16be == NULL)
 +				/* Couldn't allocate memory */
 +				return (ARCHIVE_FATAL);
 +		}
 +
 +		/*
 +		 * Converte a filename to UTF-16BE.
 +		 */
 +		if (0 > archive_entry_pathname_l(file->entry, &u16, &u16len,
 +		    iso9660->sconv_to_utf16be)) {
 +			if (errno == ENOMEM) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "Can't allocate memory for UTF-16BE");
 +				return (ARCHIVE_FATAL);
 +			}
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "A filename cannot be converted to UTF-16BE;"
 +			    "You should disable making Joliet extension");
 +			ret = ARCHIVE_WARN;
 +		}
 +
 +		/*
 +		 * Make sure a path separator is not in the last;
 +		 * Remove trailing '/'.
 +		 */
 +		while (u16len >= 2) {
 +#if defined(_WIN32) || defined(__CYGWIN__)
 +			if (u16[u16len-2] == 0 &&
 +			    (u16[u16len-1] == '/' || u16[u16len-1] == '\\'))
 +#else
 +			if (u16[u16len-2] == 0 && u16[u16len-1] == '/')
 +#endif
 +			{
 +				u16len -= 2;
 +			} else
 +				break;
 +		}
 +
 +		/*
 +		 * Find a basename in UTF-16BE.
 +		 */
 +		ulast = u16;
 +		u16len >>= 1;
 +		ulen_last = u16len;
 +		while (u16len > 0) {
 +#if defined(_WIN32) || defined(__CYGWIN__)
 +			if (u16[0] == 0 && (u16[1] == '/' || u16[1] == '\\'))
 +#else
 +			if (u16[0] == 0 && u16[1] == '/')
 +#endif
 +			{
 +				ulast = u16 + 2;
 +				ulen_last = u16len -1;
 +			}
 +			u16 += 2;
 +			u16len --;
 +		}
 +		ulen_last <<= 1;
 +		if (archive_string_ensure(&(file->basename_utf16),
 +		    ulen_last) == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for UTF-16BE");
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		/*
 +		 * Set UTF-16BE basename.
 +		 */
 +		memcpy(file->basename_utf16.s, ulast, ulen_last);
 +		file->basename_utf16.length = ulen_last;
 +	}
 +
 +	archive_strcpy(&(file->parentdir), pathname);
 +#if defined(_WIN32) || defined(__CYGWIN__)
 +	/*
 +	 * Convert a path-separator from '\' to  '/'
 +	 */
 +	if (cleanup_backslash_1(file->parentdir.s) != 0) {
 +		const wchar_t *wp = archive_entry_pathname_w(file->entry);
 +		struct archive_wstring ws;
 +
 +		if (wp != NULL) {
++			int r;
 +			archive_string_init(&ws);
 +			archive_wstrcpy(&ws, wp);
 +			cleanup_backslash_2(ws.s);
 +			archive_string_empty(&(file->parentdir));
- 			archive_string_append_from_wcs(&(file->parentdir),
++			r = archive_string_append_from_wcs(&(file->parentdir),
 +			    ws.s, ws.length);
 +			archive_wstring_free(&ws);
++			if (r < 0 && errno == ENOMEM) {
++				archive_set_error(&a->archive, ENOMEM,
++				    "Can't allocate memory");
++				return (ARCHIVE_FATAL);
++			}
 +		}
 +	}
 +#endif
 +
 +	len = file->parentdir.length;
 +	p = dirname = file->parentdir.s;
 +
 +	/*
 +	 * Remove leading '/', '../' and './' elements
 +	 */
 +	while (*p) {
 +		if (p[0] == '/') {
 +			p++;
 +			len--;
 +		} else if (p[0] != '.')
 +			break;
 +		else if (p[1] == '.' && p[2] == '/') {
 +			p += 3;
 +			len -= 3;
 +		} else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
 +			p += 2;
 +			len -= 2;
 +		} else if (p[1] == '\0') {
 +			p++;
 +			len--;
 +		} else
 +			break;
 +	}
 +	if (p != dirname) {
 +		memmove(dirname, p, len+1);
 +		p = dirname;
 +	}
 +	/*
 +	 * Remove "/","/." and "/.." elements from tail.
 +	 */
 +	while (len > 0) {
 +		size_t ll = len;
 +
 +		if (len > 0 && p[len-1] == '/') {
 +			p[len-1] = '\0';
 +			len--;
 +		}
 +		if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
 +			p[len-2] = '\0';
 +			len -= 2;
 +		}
 +		if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
 +		    p[len-1] == '.') {
 +			p[len-3] = '\0';
 +			len -= 3;
 +		}
 +		if (ll == len)
 +			break;
 +	}
 +	while (*p) {
 +		if (p[0] == '/') {
 +			if (p[1] == '/')
 +				/* Convert '//' --> '/' */
 +				strcpy(p, p+1);
 +			else if (p[1] == '.' && p[2] == '/')
 +				/* Convert '/./' --> '/' */
 +				strcpy(p, p+2);
 +			else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
 +				/* Convert 'dir/dir1/../dir2/'
 +				 *     --> 'dir/dir2/'
 +				 */
 +				char *rp = p -1;
 +				while (rp >= dirname) {
 +					if (*rp == '/')
 +						break;
 +					--rp;
 +				}
 +				if (rp > dirname) {
 +					strcpy(rp, p+3);
 +					p = rp;
 +				} else {
 +					strcpy(dirname, p+4);
 +					p = dirname;
 +				}
 +			} else
 +				p++;
 +		} else
 +			p++;
 +	}
 +	p = dirname;
 +	len = strlen(p);
 +
 +	if (archive_entry_filetype(file->entry) == AE_IFLNK) {
 +		/* Convert symlink name too. */
 +		pathname = archive_entry_symlink(file->entry);
 +		archive_strcpy(&(file->symlink),  pathname);
 +#if defined(_WIN32) || defined(__CYGWIN__)
 +		/*
 +		 * Convert a path-separator from '\' to  '/'
 +		 */
 +		if (archive_strlen(&(file->symlink)) > 0 &&
 +		    cleanup_backslash_1(file->symlink.s) != 0) {
 +			const wchar_t *wp =
 +			    archive_entry_symlink_w(file->entry);
 +			struct archive_wstring ws;
 +
 +			if (wp != NULL) {
++				int r;
 +				archive_string_init(&ws);
 +				archive_wstrcpy(&ws, wp);
 +				cleanup_backslash_2(ws.s);
 +				archive_string_empty(&(file->symlink));
- 				archive_string_append_from_wcs(
++				r = archive_string_append_from_wcs(
 +				    &(file->symlink),
 +				    ws.s, ws.length);
 +				archive_wstring_free(&ws);
++				if (r < 0 && errno == ENOMEM) {
++					archive_set_error(&a->archive, ENOMEM,
++					    "Can't allocate memory");
++					return (ARCHIVE_FATAL);
++				}
 +			}
 +		}
 +#endif
 +	}
 +	/*
 +	 * - Count up directory elements.
 +	 * - Find out the position which points the last position of
 +	 *   path separator('/').
 +	 */
 +	slash = NULL;
 +	file->dircnt = 0;
 +	for (; *p != '\0'; p++)
 +		if (*p == '/') {
 +			slash = p;
 +			file->dircnt++;
 +		}
 +	if (slash == NULL) {
 +		/* The pathname doesn't have a parent directory. */
 +		file->parentdir.length = len;
 +		archive_string_copy(&(file->basename), &(file->parentdir));
 +		archive_string_empty(&(file->parentdir));
 +		*file->parentdir.s = '\0';
 +		return (ret);
 +	}
 +
 +	/* Make a basename from dirname and slash */
 +	*slash  = '\0';
 +	file->parentdir.length = slash - dirname;
 +	archive_strcpy(&(file->basename),  slash + 1);
 +	if (archive_entry_filetype(file->entry) == AE_IFDIR)
 +		file->dircnt ++;
 +	return (ret);
 +}
 +
 +/*
 + * Register a entry to get a hardlink target.
 + */
 +static int
 +isofile_register_hardlink(struct archive_write *a, struct isofile *file)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct hardlink *hl;
 +	const char *pathname;
 +
 +	archive_entry_set_nlink(file->entry, 1);
 +	pathname = archive_entry_hardlink(file->entry);
 +	if (pathname == NULL) {
 +		/* This `file` is a hardlink target. */
 +		hl = malloc(sizeof(*hl));
 +		if (hl == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		hl->nlink = 1;
 +		/* A hardlink target must be the first position. */
 +		file->hlnext = NULL;
 +		hl->file_list.first = file;
 +		hl->file_list.last = &(file->hlnext);
 +		__archive_rb_tree_insert_node(&(iso9660->hardlink_rbtree),
 +		    (struct archive_rb_node *)hl);
 +	} else {
 +		hl = (struct hardlink *)__archive_rb_tree_find_node(
 +		    &(iso9660->hardlink_rbtree), pathname);
 +		if (hl != NULL) {
 +			/* Insert `file` entry into the tail. */
 +			file->hlnext = NULL;
 +			*hl->file_list.last = file;
 +			hl->file_list.last = &(file->hlnext);
 +			hl->nlink++;
 +		}
 +		archive_entry_unset_size(file->entry);
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Hardlinked files have to have the same location of extent.
 + * We have to find out hardlink target entries for the entries
 + * which have a hardlink target name.
 + */
 +static void
 +isofile_connect_hardlink_files(struct iso9660 *iso9660)
 +{
 +	struct archive_rb_node *n;
 +	struct hardlink *hl;
 +	struct isofile *target, *nf;
 +
 +	ARCHIVE_RB_TREE_FOREACH(n, &(iso9660->hardlink_rbtree)) {
 +		hl = (struct hardlink *)n;
 +
 +		/* The first entry must be a hardlink target. */
 +		target = hl->file_list.first;
 +		archive_entry_set_nlink(target->entry, hl->nlink);
 +		/* Set a hardlink target to reference entries. */
 +		for (nf = target->hlnext;
 +		    nf != NULL; nf = nf->hlnext) {
 +			nf->hardlink_target = target;
 +			archive_entry_set_nlink(nf->entry, hl->nlink);
 +		}
 +	}
 +}
 +
 +static int
 +isofile_hd_cmp_node(const struct archive_rb_node *n1,
 +    const struct archive_rb_node *n2)
 +{
 +	const struct hardlink *h1 = (const struct hardlink *)n1;
 +	const struct hardlink *h2 = (const struct hardlink *)n2;
 +
 +	return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
 +		       archive_entry_pathname(h2->file_list.first->entry)));
 +}
 +
 +static int
 +isofile_hd_cmp_key(const struct archive_rb_node *n, const void *key)
 +{
 +	const struct hardlink *h = (const struct hardlink *)n;
 +
 +	return (strcmp(archive_entry_pathname(h->file_list.first->entry),
 +		       (const char *)key));
 +}
 +
 +static void
 +isofile_init_hardlinks(struct iso9660 *iso9660)
 +{
 +	static const struct archive_rb_tree_ops rb_ops = {
 +		isofile_hd_cmp_node, isofile_hd_cmp_key,
 +	};
 +
 +	__archive_rb_tree_init(&(iso9660->hardlink_rbtree), &rb_ops);
 +}
 +
 +static void
 +isofile_free_hardlinks(struct iso9660 *iso9660)
 +{
 +	struct archive_rb_node *n, *next;
 +
 +	for (n = ARCHIVE_RB_TREE_MIN(&(iso9660->hardlink_rbtree)); n;) {
 +		next = __archive_rb_tree_iterate(&(iso9660->hardlink_rbtree),
 +		    n, ARCHIVE_RB_DIR_RIGHT);
 +		free(n);
 +		n = next;
 +	}
 +}
 +
 +static struct isoent *
 +isoent_new(struct isofile *file)
 +{
 +	struct isoent *isoent;
 +	static const struct archive_rb_tree_ops rb_ops = {
 +		isoent_cmp_node, isoent_cmp_key,
 +	};
 +
 +	isoent = calloc(1, sizeof(*isoent));
 +	if (isoent == NULL)
 +		return (NULL);
 +	isoent->file = file;
 +	isoent->children.first = NULL;
 +	isoent->children.last = &(isoent->children.first);
 +	__archive_rb_tree_init(&(isoent->rbtree), &rb_ops);
 +	isoent->subdirs.first = NULL;
 +	isoent->subdirs.last = &(isoent->subdirs.first);
 +	isoent->extr_rec_list.first = NULL;
 +	isoent->extr_rec_list.last = &(isoent->extr_rec_list.first);
 +	isoent->extr_rec_list.current = NULL;
 +	if (archive_entry_filetype(file->entry) == AE_IFDIR)
 +		isoent->dir = 1;
 +
 +	return (isoent);
 +}
 +
 +static inline struct isoent *
 +isoent_clone(struct isoent *src)
 +{
 +	return (isoent_new(src->file));
 +}
 +
 +static void
 +_isoent_free(struct isoent *isoent)
 +{
 +	struct extr_rec *er, *er_next;
 +
 +	free(isoent->children_sorted);
 +	free(isoent->identifier);
 +	er = isoent->extr_rec_list.first;
 +	while (er != NULL) {
 +		er_next = er->next;
 +		free(er);
 +		er = er_next;
 +	}
 +	free(isoent);
 +}
 +
 +static void
 +isoent_free_all(struct isoent *isoent)
 +{
 +	struct isoent *np, *np_temp;
 +
 +	if (isoent == NULL)
 +		return;
 +	np = isoent;
 +	for (;;) {
 +		if (np->dir) {
 +			if (np->children.first != NULL) {
 +				/* Enter to sub directories. */
 +				np = np->children.first;
 +				continue;
 +			}
 +		}
 +		for (;;) {
 +			np_temp = np;
 +			if (np->chnext == NULL) {
 +				/* Return to the parent directory. */
 +				np = np->parent;
 +				_isoent_free(np_temp);
 +				if (np == np_temp)
 +					return;
 +			} else {
 +				np = np->chnext;
 +				_isoent_free(np_temp);
 +				break;
 +			}
 +		}
 +	}
 +}
 +
 +static struct isoent *
 +isoent_create_virtual_dir(struct archive_write *a, struct iso9660 *iso9660, const char *pathname)
 +{
 +	struct isofile *file;
 +	struct isoent *isoent;
 +
 +	file = isofile_new(a, NULL);
 +	if (file == NULL)
 +		return (NULL);
 +	archive_entry_set_pathname(file->entry, pathname);
 +	archive_entry_unset_mtime(file->entry);
 +	archive_entry_unset_atime(file->entry);
 +	archive_entry_unset_ctime(file->entry);
 +	archive_entry_set_uid(file->entry, getuid());
 +	archive_entry_set_gid(file->entry, getgid());
 +	archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
 +	archive_entry_set_nlink(file->entry, 2);
 +	if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
 +		isofile_free(file);
 +		return (NULL);
 +	}
 +	isofile_add_entry(iso9660, file);
 +
 +	isoent = isoent_new(file);
 +	if (isoent == NULL)
 +		return (NULL);
 +	isoent->dir = 1;
 +	isoent->virtual = 1;
 +
 +	return (isoent);
 +}
 +
 +static int
 +isoent_cmp_node(const struct archive_rb_node *n1,
 +    const struct archive_rb_node *n2)
 +{
 +	const struct isoent *e1 = (const struct isoent *)n1;
 +	const struct isoent *e2 = (const struct isoent *)n2;
 +
 +	return (strcmp(e1->file->basename.s, e2->file->basename.s));
 +}
 +
 +static int
 +isoent_cmp_key(const struct archive_rb_node *n, const void *key)
 +{
 +	const struct isoent *e = (const struct isoent *)n;
 +
 +	return (strcmp(e->file->basename.s, (const char *)key));
 +}
 +
 +static int
 +isoent_add_child_head(struct isoent *parent, struct isoent *child)
 +{
 +
 +	if (!__archive_rb_tree_insert_node(
 +	    &(parent->rbtree), (struct archive_rb_node *)child))
 +		return (0);
 +	if ((child->chnext = parent->children.first) == NULL)
 +		parent->children.last = &(child->chnext);
 +	parent->children.first = child;
 +	parent->children.cnt++;
 +	child->parent = parent;
 +
 +	/* Add a child to a sub-directory chain */
 +	if (child->dir) {
 +		if ((child->drnext = parent->subdirs.first) == NULL)
 +			parent->subdirs.last = &(child->drnext);
 +		parent->subdirs.first = child;
 +		parent->subdirs.cnt++;
 +		child->parent = parent;
 +	} else
 +		child->drnext = NULL;
 +	return (1);
 +}
 +
 +static int
 +isoent_add_child_tail(struct isoent *parent, struct isoent *child)
 +{
 +
 +	if (!__archive_rb_tree_insert_node(
 +	    &(parent->rbtree), (struct archive_rb_node *)child))
 +		return (0);
 +	child->chnext = NULL;
 +	*parent->children.last = child;
 +	parent->children.last = &(child->chnext);
 +	parent->children.cnt++;
 +	child->parent = parent;
 +
 +	/* Add a child to a sub-directory chain */
 +	child->drnext = NULL;
 +	if (child->dir) {
 +		*parent->subdirs.last = child;
 +		parent->subdirs.last = &(child->drnext);
 +		parent->subdirs.cnt++;
 +		child->parent = parent;
 +	}
 +	return (1);
 +}
 +
 +static void
 +isoent_remove_child(struct isoent *parent, struct isoent *child)
 +{
 +	struct isoent *ent;
 +
 +	/* Remove a child entry from children chain. */
 +	ent = parent->children.first;
 +	while (ent->chnext != child)
 +		ent = ent->chnext;
 +	if ((ent->chnext = ent->chnext->chnext) == NULL)
 +		parent->children.last = &(ent->chnext);
 +	parent->children.cnt--;
 +
 +	if (child->dir) {
 +		/* Remove a child entry from sub-directory chain. */
 +		ent = parent->subdirs.first;
 +		while (ent->drnext != child)
 +			ent = ent->drnext;
 +		if ((ent->drnext = ent->drnext->drnext) == NULL)
 +			parent->subdirs.last = &(ent->drnext);
 +		parent->subdirs.cnt--;
 +	}
 +
 +	__archive_rb_tree_remove_node(&(parent->rbtree),
 +	    (struct archive_rb_node *)child);
 +}
 +
 +static int
 +isoent_clone_tree(struct archive_write *a, struct isoent **nroot,
 +    struct isoent *root)
 +{
 +	struct isoent *np, *xroot, *newent;
 +
 +	np = root;
 +	xroot = NULL;
 +	do {
 +		newent = isoent_clone(np);
 +		if (newent == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (xroot == NULL) {
 +			*nroot = xroot = newent;
 +			newent->parent = xroot;
 +		} else
 +			isoent_add_child_tail(xroot, newent);
 +		if (np->dir && np->children.first != NULL) {
 +			/* Enter to sub directories. */
 +			np = np->children.first;
 +			xroot = newent;
 +			continue;
 +		}
 +		while (np != np->parent) {
 +			if (np->chnext == NULL) {
 +				/* Return to the parent directory. */
 +				np = np->parent;
 +				xroot = xroot->parent;
 +			} else {
 +				np = np->chnext;
 +				break;
 +			}
 +		}
 +	} while (np != np->parent);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Setup directory locations.
 + */
 +static void
 +isoent_setup_directory_location(struct iso9660 *iso9660, int location,
 +    struct vdd *vdd)
 +{
 +	struct isoent *np;
 +	int depth;
 +
 +	vdd->total_dir_block = 0;
 +	depth = 0;
 +	np = vdd->rootent;
 +	do {
 +		int block;
 +
 +		np->dir_block = calculate_directory_descriptors(
 +		    iso9660, vdd, np, depth);
 +		vdd->total_dir_block += np->dir_block;
 +		np->dir_location = location;
 +		location += np->dir_block;
 +		block = extra_setup_location(np, location);
 +		vdd->total_dir_block += block;
 +		location += block;
 +
 +		if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
 +			/* Enter to sub directories. */
 +			np = np->subdirs.first;
 +			depth++;
 +			continue;
 +		}
 +		while (np != np->parent) {
 +			if (np->drnext == NULL) {
 +				/* Return to the parent directory. */
 +				np = np->parent;
 +				depth--;
 +			} else {
 +				np = np->drnext;
 +				break;
 +			}
 +		}
 +	} while (np != np->parent);
 +}
 +
 +static void
 +_isoent_file_location(struct iso9660 *iso9660, struct isoent *isoent,
 +    int *symlocation)
 +{
 +	struct isoent **children;
 +	int n;
 +
 +	if (isoent->children.cnt == 0)
 +		return;
 +
 +	children = isoent->children_sorted;
 +	for (n = 0; n < isoent->children.cnt; n++) {
 +		struct isoent *np;
 +		struct isofile *file;
 +
 +		np = children[n];
 +		if (np->dir)
 +			continue;
 +		if (np == iso9660->el_torito.boot)
 +			continue;
 +		file = np->file;
 +		if (file->boot || file->hardlink_target != NULL)
 +			continue;
 +		if (archive_entry_filetype(file->entry) == AE_IFLNK ||
 +		    file->content.size == 0) {
 +			/*
 +			 * Do not point a valid location.
 +			 * Make sure entry is not hardlink file.
 +			 */
 +			file->content.location = (*symlocation)--;
 +			continue;
 +		}
 +
 +		file->write_content = 1;
 +	}
 +}
 +
 +/*
 + * Setup file locations.
 + */
 +static void
 +isoent_setup_file_location(struct iso9660 *iso9660, int location)
 +{
 +	struct isoent *isoent;
 +	struct isoent *np;
 +	struct isofile *file;
 +	size_t size;
 +	int block;
 +	int depth;
 +	int joliet;
 +	int symlocation;
 +	int total_block;
 +
 +	iso9660->total_file_block = 0;
 +	if ((isoent = iso9660->el_torito.catalog) != NULL) {
 +		isoent->file->content.location = location;
- 		block = (archive_entry_size(isoent->file->entry) +
- 		    LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS;
++		block = (int)((archive_entry_size(isoent->file->entry) +
++		    LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
 +		location += block;
 +		iso9660->total_file_block += block;
 +	}
 +	if ((isoent = iso9660->el_torito.boot) != NULL) {
 +		isoent->file->content.location = location;
 +		size = fd_boot_image_size(iso9660->el_torito.media_type);
 +		if (size == 0)
- 			size = archive_entry_size(isoent->file->entry);
- 		block = (size + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS;
++			size = (size_t)archive_entry_size(isoent->file->entry);
++		block = ((int)size + LOGICAL_BLOCK_SIZE -1)
++		    >> LOGICAL_BLOCK_BITS;
 +		location += block;
 +		iso9660->total_file_block += block;
 +		isoent->file->content.blocks = block;
 +	}
 +
 +	depth = 0;
 +	symlocation = -16;
 +	if (!iso9660->opt.rr && iso9660->opt.joliet) {
 +		joliet = 1;
 +		np = iso9660->joliet.rootent;
 +	} else {
 +		joliet = 0;
 +		np = iso9660->primary.rootent;
 +	}
 +	do {
 +		_isoent_file_location(iso9660, np, &symlocation);
 +
 +		if (np->subdirs.first != NULL &&
 +		    (joliet ||
 +		    ((iso9660->opt.rr == OPT_RR_DISABLED &&
 +		      depth + 2 < iso9660->primary.max_depth) ||
 +		     (iso9660->opt.rr &&
 +		      depth + 1 < iso9660->primary.max_depth)))) {
 +			/* Enter to sub directories. */
 +			np = np->subdirs.first;
 +			depth++;
 +			continue;
 +		}
 +		while (np != np->parent) {
 +			if (np->drnext == NULL) {
 +				/* Return to the parent directory. */
 +				np = np->parent;
 +				depth--;
 +			} else {
 +				np = np->drnext;
 +				break;
 +			}
 +		}
 +	} while (np != np->parent);
 +
 +	total_block = 0;
 +	for (file = iso9660->data_file_list.first;
 +	    file != NULL; file = file->datanext) {
 +
 +		if (!file->write_content)
 +			continue;
 +
 +		file->cur_content = &(file->content);
 +		do {
 +			file->cur_content->location = location;
 +			location += file->cur_content->blocks;
 +			total_block += file->cur_content->blocks;
 +			/* Next fragument */
 +			file->cur_content = file->cur_content->next;
 +		} while (file->cur_content != NULL);
 +	}
 +	iso9660->total_file_block += total_block;
 +}
 +
 +static int
- get_path_component(char *name, int n, const char *fn)
++get_path_component(char *name, size_t n, const char *fn)
 +{
 +	char *p;
- 	int l;
++	size_t l;
 +
 +	p = strchr(fn, '/');
 +	if (p == NULL) {
 +		if ((l = strlen(fn)) == 0)
 +			return (0);
 +	} else
 +		l = p - fn;
 +	if (l > n -1)
 +		return (-1);
 +	memcpy(name, fn, l);
 +	name[l] = '\0';
 +
- 	return (l);
++	return ((int)l);
 +}
 +
 +/*
 + * Add a new entry into the tree.
 + */
 +static int
 +isoent_tree(struct archive_write *a, struct isoent **isoentpp)
 +{
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +	char name[_MAX_FNAME];/* Included null terminator size. */
 +#elif defined(NAME_MAX) && NAME_MAX >= 255
 +	char name[NAME_MAX+1];
 +#else
 +	char name[256];
 +#endif
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isoent *dent, *isoent, *np;
 +	struct isofile *f1, *f2;
 +	const char *fn, *p;
 +	int l;
 +
 +	isoent = *isoentpp;
 +	dent = iso9660->primary.rootent;
 +	if (isoent->file->parentdir.length > 0)
 +		fn = p = isoent->file->parentdir.s;
 +	else
 +		fn = p = "";
 +
 +	/*
 +	 * If the path of the parent directory of `isoent' entry is
 +	 * the same as the path of `cur_dirent', add isoent to
 +	 * `cur_dirent'.
 +	 */
 +	if (archive_strlen(&(iso9660->cur_dirstr))
 +	      == archive_strlen(&(isoent->file->parentdir)) &&
 +	    strcmp(iso9660->cur_dirstr.s, fn) == 0) {
 +		if (!isoent_add_child_tail(iso9660->cur_dirent, isoent)) {
 +			np = (struct isoent *)__archive_rb_tree_find_node(
 +			    &(iso9660->cur_dirent->rbtree),
 +			    isoent->file->basename.s);
 +			goto same_entry;
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +
 +	for (;;) {
 +		l = get_path_component(name, sizeof(name), fn);
 +		if (l == 0) {
 +			np = NULL;
 +			break;
 +		}
 +		if (l < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "A name buffer is too small");
 +			_isoent_free(isoent);
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		np = isoent_find_child(dent, name);
 +		if (np == NULL || fn[0] == '\0')
 +			break;
 +
 +		/* Find next subdirectory. */
 +		if (!np->dir) {
 +			/* NOT Directory! */
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "`%s' is not directory, we cannot insert `%s' ",
 +			    archive_entry_pathname(np->file->entry),
 +			    archive_entry_pathname(isoent->file->entry));
 +			_isoent_free(isoent);
 +			*isoentpp = NULL;
 +			return (ARCHIVE_FAILED);
 +		}
 +		fn += l;
 +		if (fn[0] == '/')
 +			fn++;
 +		dent = np;
 +	}
 +	if (np == NULL) {
 +		/*
 +		 * Create virtual parent directories.
 +		 */
 +		while (fn[0] != '\0') {
 +			struct isoent *vp;
 +			struct archive_string as;
 +
 +			archive_string_init(&as);
 +			archive_strncat(&as, p, fn - p + l);
 +			if (as.s[as.length-1] == '/') {
 +				as.s[as.length-1] = '\0';
 +				as.length--;
 +			}
 +			vp = isoent_create_virtual_dir(a, iso9660, as.s);
 +			if (vp == NULL) {
 +				archive_string_free(&as);
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "Can't allocate memory");
 +				_isoent_free(isoent);
 +				*isoentpp = NULL;
 +				return (ARCHIVE_FATAL);
 +			}
 +			archive_string_free(&as);
 +
 +			if (vp->file->dircnt > iso9660->dircnt_max)
 +				iso9660->dircnt_max = vp->file->dircnt;
 +			isoent_add_child_tail(dent, vp);
 +			np = vp;
 +
 +			fn += l;
 +			if (fn[0] == '/')
 +				fn++;
 +			l = get_path_component(name, sizeof(name), fn);
 +			if (l < 0) {
 +				archive_string_free(&as);
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "A name buffer is too small");
 +				_isoent_free(isoent);
 +				*isoentpp = NULL;
 +				return (ARCHIVE_FATAL);
 +			}
 +			dent = np;
 +		}
 +
 +		/* Found out the parent directory where isoent can be
 +		 * inserted. */
 +		iso9660->cur_dirent = dent;
 +		archive_string_empty(&(iso9660->cur_dirstr));
 +		archive_string_ensure(&(iso9660->cur_dirstr),
 +		    archive_strlen(&(dent->file->parentdir)) +
 +		    archive_strlen(&(dent->file->basename)) + 2);
 +		if (archive_strlen(&(dent->file->parentdir)) +
 +		    archive_strlen(&(dent->file->basename)) == 0)
 +			iso9660->cur_dirstr.s[0] = 0;
 +		else {
 +			if (archive_strlen(&(dent->file->parentdir)) > 0) {
 +				archive_string_copy(&(iso9660->cur_dirstr),
 +				    &(dent->file->parentdir));
 +				archive_strappend_char(&(iso9660->cur_dirstr), '/');
 +			}
 +			archive_string_concat(&(iso9660->cur_dirstr),
 +			    &(dent->file->basename));
 +		}
 +
 +		if (!isoent_add_child_tail(dent, isoent)) {
 +			np = (struct isoent *)__archive_rb_tree_find_node(
 +			    &(dent->rbtree), isoent->file->basename.s);
 +			goto same_entry;
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +
 +same_entry:
 +	/*
 +	 * We have already has the entry the filename of which is
 +	 * the same.
 +	 */
 +	f1 = np->file;
 +	f2 = isoent->file;
 +
 +	/* If the file type of entries is different,
 +	 * we cannot handle it. */
 +	if (archive_entry_filetype(f1->entry) !=
 +	    archive_entry_filetype(f2->entry)) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Found duplicate entries `%s' and its file type is "
 +		    "different",
 +		    archive_entry_pathname(f1->entry));
 +		_isoent_free(isoent);
 +		*isoentpp = NULL;
 +		return (ARCHIVE_FAILED);
 +	}
 +
 +	/* Swap file entries. */
 +	np->file = f2;
 +	isoent->file = f1;
 +	np->virtual = 0;
 +
 +	_isoent_free(isoent);
 +	*isoentpp = np;
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Find a entry from `isoent'
 + */
 +static struct isoent *
 +isoent_find_child(struct isoent *isoent, const char *child_name)
 +{
 +	struct isoent *np;
 +
 +	np = (struct isoent *)__archive_rb_tree_find_node(
 +	    &(isoent->rbtree), child_name);
 +	return (np);
 +}
 +
 +/*
 + * Find a entry full-path of which is specified by `fn' parameter,
 + * in the tree.
 + */
 +static struct isoent *
 +isoent_find_entry(struct isoent *rootent, const char *fn)
 +{
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +	char name[_MAX_FNAME];/* Included null terminator size. */
 +#elif defined(NAME_MAX) && NAME_MAX >= 255
 +	char name[NAME_MAX+1];
 +#else
 +	char name[256];
 +#endif
 +	struct isoent *isoent, *np;
 +	int l;
 +
 +	isoent = rootent;
 +	np = NULL;
 +	for (;;) {
 +		l = get_path_component(name, sizeof(name), fn);
 +		if (l == 0)
 +			break;
 +		fn += l;
 +		if (fn[0] == '/')
 +			fn++;
 +
 +		np = isoent_find_child(isoent, name);
 +		if (np == NULL)
 +			break;
 +		if (fn[0] == '\0')
 +			break;/* We found out the entry */
 +
 +		/* Try sub directory. */
 +		isoent = np;
 +		np = NULL;
 +		if (!isoent->dir)
 +			break;/* Not directory */
 +	}
 +
 +	return (np);
 +}
 +
 +/*
 + * Following idr_* functions are used for resolving duplicated filenames
 + * and unreceivable filenames to generate ISO9660/Joliet Identifiers.
 + */
 +
 +static void
 +idr_relaxed_filenames(char *map)
 +{
 +	int i;
 +
 +	for (i = 0x21; i <= 0x2F; i++)
 +		map[i] = 1;
 +	for (i = 0x3A; i <= 0x41; i++)
 +		map[i] = 1;
 +	for (i = 0x5B; i <= 0x5E; i++)
 +		map[i] = 1;
 +	map[0x60] = 1;
 +	for (i = 0x7B; i <= 0x7E; i++)
 +		map[i] = 1;
 +}
 +
 +static void
 +idr_init(struct iso9660 *iso9660, struct vdd *vdd, struct idr *idr)
 +{
 +
 +	idr->idrent_pool = NULL;
 +	idr->pool_size = 0;
 +	if (vdd->vdd_type != VDD_JOLIET) {
 +		if (iso9660->opt.iso_level <= 3) {
 +			memcpy(idr->char_map, d_characters_map,
 +			    sizeof(idr->char_map));
 +		} else {
 +			memcpy(idr->char_map, d1_characters_map,
 +			    sizeof(idr->char_map));
 +			idr_relaxed_filenames(idr->char_map);
 +		}
 +	}
 +}
 +
 +static void
 +idr_cleanup(struct idr *idr)
 +{
 +	free(idr->idrent_pool);
 +}
 +
 +static int
 +idr_ensure_poolsize(struct archive_write *a, struct idr *idr,
 +    int cnt)
 +{
 +
 +	if (idr->pool_size < cnt) {
++		void *p;
 +		const int bk = (1 << 7) - 1;
 +		int psize;
 +
 +		psize = (cnt + bk) & ~bk;
- 		idr->idrent_pool = realloc(idr->idrent_pool,
- 		    sizeof(struct idrent) * psize);
- 		if (idr->idrent_pool == NULL) {
++		p = realloc(idr->idrent_pool, sizeof(struct idrent) * psize);
++		if (p == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory");
 +			return (ARCHIVE_FATAL);
 +		}
++		idr->idrent_pool = (struct idrent *)p;
 +		idr->pool_size = psize;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +idr_start(struct archive_write *a, struct idr *idr, int cnt, int ffmax,
 +    int num_size, int null_size, const struct archive_rb_tree_ops *rbt_ops)
 +{
 +	int r;
 +
 +	(void)ffmax; /* UNUSED */
 +
 +	r = idr_ensure_poolsize(a, idr, cnt);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	__archive_rb_tree_init(&(idr->rbtree), rbt_ops);
 +	idr->wait_list.first = NULL;
 +	idr->wait_list.last = &(idr->wait_list.first);
 +	idr->pool_idx = 0;
 +	idr->num_size = num_size;
 +	idr->null_size = null_size;
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +idr_register(struct idr *idr, struct isoent *isoent, int weight, int noff)
 +{
 +	struct idrent *idrent, *n;
 +
 +	idrent = &(idr->idrent_pool[idr->pool_idx++]);
 +	idrent->wnext = idrent->avail = NULL;
 +	idrent->isoent = isoent;
 +	idrent->weight = weight;
 +	idrent->noff = noff;
 +	idrent->rename_num = 0;
 +
 +	if (!__archive_rb_tree_insert_node(&(idr->rbtree), &(idrent->rbnode))) {
 +		n = (struct idrent *)__archive_rb_tree_find_node(
 +		    &(idr->rbtree), idrent->isoent);
 +		if (n != NULL) {
 +			/* this `idrent' needs to rename. */
 +			idrent->avail = n;
 +			*idr->wait_list.last = idrent;
 +			idr->wait_list.last = &(idrent->wnext);
 +		}
 +	}
 +}
 +
 +static void
 +idr_extend_identifier(struct idrent *wnp, int numsize, int nullsize)
 +{
 +	unsigned char *p;
 +	int wnp_ext_off;
 +
 +	wnp_ext_off = wnp->isoent->ext_off;
 +	if (wnp->noff + numsize != wnp_ext_off) {
 +		p = (unsigned char *)wnp->isoent->identifier;
 +		/* Extend the filename; foo.c --> foo___.c */
 +		memmove(p + wnp->noff + numsize, p + wnp_ext_off,
 +		    wnp->isoent->ext_len + nullsize);
 +		wnp->isoent->ext_off = wnp_ext_off = wnp->noff + numsize;
 +		wnp->isoent->id_len = wnp_ext_off + wnp->isoent->ext_len;
 +	}
 +}
 +
 +static void
 +idr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))
 +{
 +	struct idrent *n;
 +	unsigned char *p;
 +
 +	for (n = idr->wait_list.first; n != NULL; n = n->wnext) {
 +		idr_extend_identifier(n, idr->num_size, idr->null_size);
 +		p = (unsigned char *)n->isoent->identifier + n->noff;
 +		do {
 +			fsetnum(p, n->avail->rename_num++);
 +		} while (!__archive_rb_tree_insert_node(
 +		    &(idr->rbtree), &(n->rbnode)));
 +	}
 +}
 +
 +static void
 +idr_set_num(unsigned char *p, int num)
 +{
 +	static const char xdig[] = {
 +		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 +		'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
 +		'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
 +		'U', 'V', 'W', 'X', 'Y', 'Z'
 +	};
 +
 +	num %= sizeof(xdig) * sizeof(xdig) * sizeof(xdig);
 +	p[0] = xdig[(num / (sizeof(xdig) * sizeof(xdig)))];
 +	num %= sizeof(xdig) * sizeof(xdig);
 +	p[1] = xdig[ (num / sizeof(xdig))];
 +	num %= sizeof(xdig);
 +	p[2] = xdig[num];
 +}
 +
 +static void
 +idr_set_num_beutf16(unsigned char *p, int num)
 +{
 +	static const uint16_t xdig[] = {
 +		0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
 +		0x0036, 0x0037, 0x0038, 0x0039,
 +		0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046,
 +		0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C,
 +		0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052,
 +		0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
 +		0x0059, 0x005A
 +	};
 +#define XDIG_CNT	(sizeof(xdig)/sizeof(xdig[0]))
 +
 +	num %= XDIG_CNT * XDIG_CNT * XDIG_CNT;
 +	archive_be16enc(p, xdig[(num / (XDIG_CNT * XDIG_CNT))]);
 +	num %= XDIG_CNT * XDIG_CNT;
 +	archive_be16enc(p+2, xdig[ (num / XDIG_CNT)]);
 +	num %= XDIG_CNT;
 +	archive_be16enc(p+4, xdig[num]);
 +}
 +
 +/*
 + * Generate ISO9660 Identifier.
 + */
 +static int
 +isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
 +    struct idr *idr)
 +{
 +	struct iso9660 *iso9660;
 +	struct isoent *np;
 +	char *p;
 +	int l, r;
 +	const char *char_map;
 +	char allow_ldots, allow_multidot, allow_period, allow_vernum;
 +	int fnmax, ffmax, dnmax;
 +	static const struct archive_rb_tree_ops rb_ops = {
 +		isoent_cmp_node_iso9660, isoent_cmp_key_iso9660
 +	};
 +
 +	if (isoent->children.cnt == 0)
 +		return (0);
 +
 +	iso9660 = a->format_data;
 +	char_map = idr->char_map;
 +	if (iso9660->opt.iso_level <= 3) {
 +		allow_ldots = 0;
 +		allow_multidot = 0;
 +		allow_period = 1;
 +		allow_vernum = iso9660->opt.allow_vernum;
 +		if (iso9660->opt.iso_level == 1) {
 +			fnmax = 8;
 +			ffmax = 12;/* fnmax + '.' + 3 */
 +			dnmax = 8;
 +		} else {
 +			fnmax = 30;
 +			ffmax = 31;
 +			dnmax = 31;
 +		}
 +	} else {
 +		allow_ldots = allow_multidot = 1;
 +		allow_period = allow_vernum = 0;
 +		if (iso9660->opt.rr)
 +			/*
 +			 * MDR : The maximum size of Directory Record(254).
 +			 * DRL : A Directory Record Length(33).
 +			 * CE  : A size of SUSP CE System Use Entry(28).
 +			 * MDR - DRL - CE = 254 - 33 - 28 = 193.
 +			 */
 +			fnmax = ffmax = dnmax = 193;
 +		else
 +			/*
 +			 * XA  : CD-ROM XA System Use Extension
 +			 *       Information(14).
 +			 * MDR - DRL - XA = 254 - 33 -14 = 207.
 +			 */
 +			fnmax = ffmax = dnmax = 207;
 +	}
 +
 +	r = idr_start(a, idr, isoent->children.cnt, ffmax, 3, 1, &rb_ops);
 +	if (r < 0)
 +		return (r);
 +
 +	for (np = isoent->children.first; np != NULL; np = np->chnext) {
 +		char *dot, *xdot;
 +		int ext_off, noff, weight;
 +
- 		l = np->file->basename.length;
++		l = (int)np->file->basename.length;
 +		p = malloc(l+31+2+1);
 +		if (p == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		memcpy(p, np->file->basename.s, l);
 +		p[l] = '\0';
 +		np->identifier = p;
 +
 +		dot = xdot = NULL;
 +		if (!allow_ldots) {
 +			/*
 +			 * If there is a '.' character at the first byte,
 +			 * it has to be replaced by '_' character.
 +			 */
 +			if (*p == '.')
 +				*p++ = '_';
 +		}
 +		for (;*p; p++) {
 +			if (*p & 0x80) {
 +				*p = '_';
 +				continue;
 +			}
 +			if (char_map[(unsigned char)*p]) {
 +				/* if iso-level is '4', a character '.' is
 +				 * allowed by char_map. */
 +				if (*p == '.') {
 +					xdot = dot;
 +					dot = p;
 +				}
 +				continue;
 +			}
 +			if (*p >= 'a' && *p <= 'z') {
 +				*p -= 'a' - 'A';
 +				continue;
 +			}
 +			if (*p == '.') {
 +				xdot = dot;
 +				dot = p;
 +				if (allow_multidot)
 +					continue;
 +			}
 +			*p = '_';
 +		}
 +		p = np->identifier;
 +		weight = -1;
 +		if (dot == NULL) {
 +			int nammax;
 +
 +			if (np->dir)
 +				nammax = dnmax;
 +			else
 +				nammax = fnmax;
 +
 +			if (l > nammax) {
 +				p[nammax] = '\0';
 +				weight = nammax;
 +				ext_off = nammax;
 +			} else
 +				ext_off = l;
 +		} else {
 +			*dot = '.';
- 			ext_off = dot - p;
++			ext_off = (int)(dot - p);
 +
 +			if (iso9660->opt.iso_level == 1) {
 +				if (dot - p <= 8) {
 +					if (strlen(dot) > 4) {
 +						/* A length of a file extension
 +						 * must be less than 4 */
 +						dot[4] = '\0';
 +						weight = 0;
 +					}
 +				} else {
 +					p[8] = dot[0];
 +					p[9] = dot[1];
 +					p[10] = dot[2];
 +					p[11] = dot[3];
 +					p[12] = '\0';
 +					weight = 8;
 +					ext_off = 8;
 +				}
 +			} else if (np->dir) {
 +				if (l > dnmax) {
 +					p[dnmax] = '\0';
 +					weight = dnmax;
 +					if (ext_off > dnmax)
 +						ext_off = dnmax;
 +				}
 +			} else if (l > ffmax) {
- 				int extlen = strlen(dot);
++				int extlen = (int)strlen(dot);
 +				int xdoff;
 +
 +				if (xdot != NULL)
- 					xdoff = xdot - p;
++					xdoff = (int)(xdot - p);
 +				else
 +					xdoff = 0;
 +
 +				if (extlen > 1 && xdoff < fnmax-1) {
 +					int off;
 +
 +					if (extlen > ffmax)
 +						extlen = ffmax;
 +					off = ffmax - extlen;
 +					if (off == 0) {
 +						/* A dot('.')  character
 +						 * does't place to the first
 +						 * byte of identifier. */
 +						off ++;
 +						extlen --;
 +					}
 +					memmove(p+off, dot, extlen);
 +					p[ffmax] = '\0';
 +					ext_off = off;
 +					weight = off;
 +#ifdef COMPAT_MKISOFS
 +				} else if (xdoff >= fnmax-1) {
 +					/* Simulate a bug(?) of mkisofs. */
 +					p[fnmax-1] = '\0';
 +					ext_off = fnmax-1;
 +					weight = fnmax-1;
 +#endif
 +				} else {
 +					p[fnmax] = '\0';
 +					ext_off = fnmax;
 +					weight = fnmax;
 +				}
 +			}
 +		}
 +		/* Save an offset of a file name extension to sort files. */
 +		np->ext_off = ext_off;
- 		np->ext_len = strlen(&p[ext_off]);
++		np->ext_len = (int)strlen(&p[ext_off]);
 +		np->id_len = l = ext_off + np->ext_len;
 +
 +		/* Make an offset of the number which is used to be set
 +		 * hexadecimal number to avoid duplicate identififier. */
 +		if (iso9660->opt.iso_level == 1) {
 +			if (ext_off >= 5)
 +				noff = 5;
 +			else
 +				noff = ext_off;
 +		} else {
 +			if (l == ffmax)
 +				noff = ext_off - 3;
 +			else if (l == ffmax-1)
 +				noff = ext_off - 2;
 +			else if (l == ffmax-2)
 +				noff = ext_off - 1;
 +			else
 +				noff = ext_off;
 +		}
 +		/* Register entry to the identifier resolver. */
 +		idr_register(idr, np, weight, noff);
 +	}
 +
 +	/* Resolve duplicate identifier. */
 +	idr_resolve(idr, idr_set_num);
 +
 +	/* Add a period and a version number to identifiers. */
 +	for (np = isoent->children.first; np != NULL; np = np->chnext) {
 +		if (!np->dir && np->rr_child == NULL) {
 +			p = np->identifier + np->ext_off + np->ext_len;
 +			if (np->ext_len == 0 && allow_period) {
 +				*p++ = '.';
 +				np->ext_len = 1;
 +			}
 +			if (np->ext_len == 1 && !allow_period) {
 +				*--p = '\0';
 +				np->ext_len = 0;
 +			}
 +			np->id_len = np->ext_off + np->ext_len;
 +			if (allow_vernum) {
 +				*p++ = ';';
 +				*p++ = '1';
 +				np->id_len += 2;
 +			}
 +			*p = '\0';
 +		} else
 +			np->id_len = np->ext_off + np->ext_len;
 +		np->mb_len = np->id_len;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Generate Joliet Identifier.
 + */
 +static int
 +isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
 +    struct idr *idr)
 +{
 +	struct iso9660 *iso9660;
 +	struct isoent *np;
 +	unsigned char *p;
 +	size_t l;
 +	int r;
 +	int ffmax, parent_len;
 +	static const struct archive_rb_tree_ops rb_ops = {
 +		isoent_cmp_node_joliet, isoent_cmp_key_joliet
 +	};
 +
 +	if (isoent->children.cnt == 0)
 +		return (0);
 +
 +	iso9660 = a->format_data;
 +	if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
 +		ffmax = 206;
 +	else
 +		ffmax = 128;
 +
 +	r = idr_start(a, idr, isoent->children.cnt, ffmax, 6, 2, &rb_ops);
 +	if (r < 0)
 +		return (r);
 +
 +	parent_len = 1;
 +	for (np = isoent; np->parent != np; np = np->parent)
 +		parent_len += np->mb_len + 1;
 +
 +	for (np = isoent->children.first; np != NULL; np = np->chnext) {
 +		unsigned char *dot;
 +		int ext_off, noff, weight;
 +		size_t lt;
 +
 +		if ((int)(l = np->file->basename_utf16.length) > ffmax)
 +			l = ffmax;
 +
 +		p = malloc((l+1)*2);
 +		if (p == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		memcpy(p, np->file->basename_utf16.s, l);
 +		p[l] = 0;
 +		p[l+1] = 0;
 +
 +		np->identifier = (char *)p;
 +		lt = l;
 +		dot = p + l;
 +		weight = 0;
 +		while (lt > 0) {
 +			if (!joliet_allowed_char(p[0], p[1]))
 +				archive_be16enc(p, 0x005F); /* '_' */
 +			else if (p[0] == 0 && p[1] == 0x2E) /* '.' */
 +				dot = p;
 +			p += 2;
 +			lt -= 2;
 +		}
- 		ext_off = dot - (unsigned char *)np->identifier;
++		ext_off = (int)(dot - (unsigned char *)np->identifier);
 +		np->ext_off = ext_off;
- 		np->ext_len = l - ext_off;
- 		np->id_len = l;
++		np->ext_len = (int)l - ext_off;
++		np->id_len = (int)l;
 +
 +		/*
 +		 * Get a length of MBS of a full-pathname.
 +		 */
 +		if ((int)np->file->basename_utf16.length > ffmax) {
- 			archive_strncpy_in_locale(&iso9660->mbs,
++			if (archive_strncpy_l(&iso9660->mbs,
 +			    (const char *)np->identifier, l,
- 			    iso9660->sconv_from_utf16be);
- 			np->mb_len = iso9660->mbs.length;
++				iso9660->sconv_from_utf16be) != 0 &&
++			    errno == ENOMEM) {
++				archive_set_error(&a->archive, errno,
++				    "No memory");
++				return (ARCHIVE_FATAL);
++			}
++			np->mb_len = (int)iso9660->mbs.length;
 +			if (np->mb_len != (int)np->file->basename.length)
 +				weight = np->mb_len;
 +		} else
- 			np->mb_len = np->file->basename.length;
++			np->mb_len = (int)np->file->basename.length;
 +
 +		/* If a length of full-pathname is longer than 240 bytes,
 +		 * it violates Joliet extensions regulation. */
 +		if (parent_len + np->mb_len > 240) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "The regulation of Joliet extensions;"
- 			    " A lenght of a full-pathname of `%s' is "
++			    " A length of a full-pathname of `%s' is "
 +			    "longer than 240 bytes, (p=%d, b=%d)",
 +			    archive_entry_pathname(np->file->entry),
 +			    (int)parent_len, (int)np->mb_len);
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		/* Make an offset of the number which is used to be set
- 		 * hexadecimal number to avoid duplicate identififier. */
++		 * hexadecimal number to avoid duplicate identifier. */
 +		if ((int)l == ffmax)
 +			noff = ext_off - 6;
 +		else if ((int)l == ffmax-2)
 +			noff = ext_off - 4;
 +		else if ((int)l == ffmax-4)
 +			noff = ext_off - 2;
 +		else
 +			noff = ext_off;
 +		/* Register entry to the identifier resolver. */
 +		idr_register(idr, np, weight, noff);
 +	}
 +
 +	/* Resolve duplicate identifier with Joliet Volume. */
 +	idr_resolve(idr, idr_set_num_beutf16);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
-  * This comparing rule is acording to ISO9660 Standard 9.3
++ * This comparing rule is according to ISO9660 Standard 9.3
 + */
 +static int
 +isoent_cmp_iso9660_identifier(const struct isoent *p1, const struct isoent *p2)
 +{
 +	const char *s1, *s2;
 +	int cmp;
 +	int l;
 +
 +	s1 = p1->identifier;
 +	s2 = p2->identifier;
 +
 +	/* Compare File Name */
 +	l = p1->ext_off;
 +	if (l > p2->ext_off)
 +		l = p2->ext_off;
 +	cmp = memcmp(s1, s2, l);
 +	if (cmp != 0)
 +		return (cmp);
 +	if (p1->ext_off < p2->ext_off) {
 +		s2 += l;
 +		l = p2->ext_off - p1->ext_off;
 +		while (l--)
 +			if (0x20 != *s2++)
 +				return (0x20
 +				    - *(const unsigned char *)(s2 - 1));
 +	} else if (p1->ext_off > p2->ext_off) {
 +		s1 += l;
 +		l = p1->ext_off - p2->ext_off;
 +		while (l--)
 +			if (0x20 != *s1++)
 +				return (*(const unsigned char *)(s1 - 1)
 +				    - 0x20);
 +	}
 +	/* Compare File Name Extension */
 +	if (p1->ext_len == 0 && p2->ext_len == 0)
 +		return (0);
 +	if (p1->ext_len == 1 && p2->ext_len == 1)
 +		return (0);
 +	if (p1->ext_len <= 1)
 +		return (-1);
 +	if (p2->ext_len <= 1)
 +		return (1);
 +	l = p1->ext_len;
 +	if (l > p2->ext_len)
 +		l = p2->ext_len;
 +	s1 = p1->identifier + p1->ext_off;
 +	s2 = p2->identifier + p2->ext_off;
 +	if (l > 1) {
 +		cmp = memcmp(s1, s2, l);
 +		if (cmp != 0)
 +			return (cmp);
 +	}
 +	if (p1->ext_len < p2->ext_len) {
 +		s2 += l;
 +		l = p2->ext_len - p1->ext_len;
 +		while (l--)
 +			if (0x20 != *s2++)
 +				return (0x20
 +				    - *(const unsigned char *)(s2 - 1));
- 	} else if (p1->ext_len < p2->ext_len) {
++	} else if (p1->ext_len > p2->ext_len) {
 +		s1 += l;
 +		l = p1->ext_len - p2->ext_len;
 +		while (l--)
 +			if (0x20 != *s1++)
 +				return (*(const unsigned char *)(s1 - 1)
 +				    - 0x20);
 +	}
 +	/* Compare File Version Number */
 +	/* No operation. The File Version Number is always one. */
 +
 +	return (cmp);
 +}
 +
 +static int
 +isoent_cmp_node_iso9660(const struct archive_rb_node *n1,
 +    const struct archive_rb_node *n2)
 +{
 +	const struct idrent *e1 = (const struct idrent *)n1;
 +	const struct idrent *e2 = (const struct idrent *)n2;
 +
 +	return (isoent_cmp_iso9660_identifier(e2->isoent, e1->isoent));
 +}
 +
 +static int
 +isoent_cmp_key_iso9660(const struct archive_rb_node *node, const void *key)
 +{
 +	const struct isoent *isoent = (const struct isoent *)key;
 +	const struct idrent *idrent = (const struct idrent *)node;
 +
 +	return (isoent_cmp_iso9660_identifier(isoent, idrent->isoent));
 +}
 +
 +static int
 +isoent_cmp_joliet_identifier(const struct isoent *p1, const struct isoent *p2)
 +{
 +	const unsigned char *s1, *s2;
 +	int cmp;
 +	int l;
 +
 +	s1 = (const unsigned char *)p1->identifier;
 +	s2 = (const unsigned char *)p2->identifier;
 +
 +	/* Compare File Name */
 +	l = p1->ext_off;
 +	if (l > p2->ext_off)
 +		l = p2->ext_off;
 +	cmp = memcmp(s1, s2, l);
 +	if (cmp != 0)
 +		return (cmp);
 +	if (p1->ext_off < p2->ext_off) {
 +		s2 += l;
 +		l = p2->ext_off - p1->ext_off;
 +		while (l--)
 +			if (0 != *s2++)
 +				return (- *(const unsigned char *)(s2 - 1));
 +	} else if (p1->ext_off > p2->ext_off) {
 +		s1 += l;
 +		l = p1->ext_off - p2->ext_off;
 +		while (l--)
 +			if (0 != *s1++)
 +				return (*(const unsigned char *)(s1 - 1));
 +	}
 +	/* Compare File Name Extension */
 +	if (p1->ext_len == 0 && p2->ext_len == 0)
 +		return (0);
 +	if (p1->ext_len == 2 && p2->ext_len == 2)
 +		return (0);
 +	if (p1->ext_len <= 2)
 +		return (-1);
 +	if (p2->ext_len <= 2)
 +		return (1);
 +	l = p1->ext_len;
 +	if (l > p2->ext_len)
 +		l = p2->ext_len;
 +	s1 = (unsigned char *)(p1->identifier + p1->ext_off);
 +	s2 = (unsigned char *)(p2->identifier + p2->ext_off);
 +	if (l > 1) {
 +		cmp = memcmp(s1, s2, l);
 +		if (cmp != 0)
 +			return (cmp);
 +	}
 +	if (p1->ext_len < p2->ext_len) {
 +		s2 += l;
 +		l = p2->ext_len - p1->ext_len;
 +		while (l--)
 +			if (0 != *s2++)
 +				return (- *(const unsigned char *)(s2 - 1));
- 	} else if (p1->ext_len < p2->ext_len) {
++	} else if (p1->ext_len > p2->ext_len) {
 +		s1 += l;
 +		l = p1->ext_len - p2->ext_len;
 +		while (l--)
 +			if (0 != *s1++)
 +				return (*(const unsigned char *)(s1 - 1));
 +	}
 +	/* Compare File Version Number */
 +	/* No operation. The File Version Number is always one. */
 +
 +	return (cmp);
 +}
 +
 +static int
 +isoent_cmp_node_joliet(const struct archive_rb_node *n1,
 +    const struct archive_rb_node *n2)
 +{
 +	const struct idrent *e1 = (const struct idrent *)n1;
 +	const struct idrent *e2 = (const struct idrent *)n2;
 +
 +	return (isoent_cmp_joliet_identifier(e2->isoent, e1->isoent));
 +}
 +
 +static int
 +isoent_cmp_key_joliet(const struct archive_rb_node *node, const void *key)
 +{
 +	const struct isoent *isoent = (const struct isoent *)key;
 +	const struct idrent *idrent = (const struct idrent *)node;
 +
 +	return (isoent_cmp_joliet_identifier(isoent, idrent->isoent));
 +}
 +
 +static int
 +isoent_make_sorted_files(struct archive_write *a, struct isoent *isoent,
 +    struct idr *idr)
 +{
 +	struct archive_rb_node *rn;
 +	struct isoent **children;
 +
 +	children = malloc(isoent->children.cnt * sizeof(struct isoent *));
 +	if (children == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	isoent->children_sorted = children;
 +
 +	ARCHIVE_RB_TREE_FOREACH(rn, &(idr->rbtree)) {
 +		struct idrent *idrent = (struct idrent *)rn;
 +		*children ++ = idrent->isoent;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * - Generate ISO9660 and Joliet identifiers from basenames.
 + * - Sort files by each directory.
 + */
 +static int
 +isoent_traverse_tree(struct archive_write *a, struct vdd* vdd)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isoent *np;
 +	struct idr idr;
 +	int depth;
 +	int r;
- 	int (*genid)(struct archive_write *a, struct isoent *isoent,
- 	    struct idr *idr);
++	int (*genid)(struct archive_write *, struct isoent *, struct idr *);
 +
 +	idr_init(iso9660, vdd, &idr);
 +	np = vdd->rootent;
 +	depth = 0;
 +	if (vdd->vdd_type == VDD_JOLIET)
 +		genid = isoent_gen_joliet_identifier;
 +	else
 +		genid = isoent_gen_iso9660_identifier;
 +	do {
 +		if (np->virtual &&
 +		    !archive_entry_mtime_is_set(np->file->entry)) {
 +			/* Set properly times to virtual directory */
 +			archive_entry_set_mtime(np->file->entry,
 +			    iso9660->birth_time, 0);
 +			archive_entry_set_atime(np->file->entry,
 +			    iso9660->birth_time, 0);
 +			archive_entry_set_ctime(np->file->entry,
 +			    iso9660->birth_time, 0);
 +		}
 +		if (np->children.first != NULL) {
 +			if (vdd->vdd_type != VDD_JOLIET &&
 +			    !iso9660->opt.rr && depth + 1 >= vdd->max_depth) {
 +				if (np->children.cnt > 0)
 +					iso9660->directories_too_deep = np;
 +			} else {
 +				/* Generate Identifier */
 +				r = genid(a, np, &idr);
 +				if (r < 0)
 +					goto exit_traverse_tree;
 +				r = isoent_make_sorted_files(a, np, &idr);
 +				if (r < 0)
 +					goto exit_traverse_tree;
 +
 +				if (np->subdirs.first != NULL &&
 +				    depth + 1 < vdd->max_depth) {
 +					/* Enter to sub directories. */
 +					np = np->subdirs.first;
 +					depth++;
 +					continue;
 +				}
 +			}
 +		}
 +		while (np != np->parent) {
 +			if (np->drnext == NULL) {
 +				/* Return to the parent directory. */
 +				np = np->parent;
 +				depth--;
 +			} else {
 +				np = np->drnext;
 +				break;
 +			}
 +		}
 +	} while (np != np->parent);
 +
 +	r = ARCHIVE_OK;
 +exit_traverse_tree:
 +	idr_cleanup(&idr);
 +
 +	return (r);
 +}
 +
 +/*
 + * Collect directory entries into path_table by a directory depth.
 + */
 +static int
 +isoent_collect_dirs(struct vdd *vdd, struct isoent *rootent, int depth)
 +{
 +	struct isoent *np;
 +
 +	if (rootent == NULL)
 +		rootent = vdd->rootent;
 +	np = rootent;
 +	do {
 +		/* Register current directory to pathtable. */
 +		path_table_add_entry(&(vdd->pathtbl[depth]), np);
 +
 +		if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
 +			/* Enter to sub directories. */
 +			np = np->subdirs.first;
 +			depth++;
 +			continue;
 +		}
 +		while (np != rootent) {
 +			if (np->drnext == NULL) {
 +				/* Return to the parent directory. */
 +				np = np->parent;
 +				depth--;
 +			} else {
 +				np = np->drnext;
 +				break;
 +			}
 +		}
 +	} while (np != rootent);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * The entry whose number of levels in a directory hierarchy is
 + * large than eight relocate to rr_move directory.
 + */
 +static int
 +isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,
 +    struct isoent *curent, struct isoent **newent)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isoent *rrmoved, *mvent, *np;
 +
 +	if ((rrmoved = *rr_moved) == NULL) {
 +		struct isoent *rootent = iso9660->primary.rootent;
 +		/* There isn't rr_move entry.
 +		 * Create rr_move entry and insert it into the root entry.
 +		 */
 +		rrmoved = isoent_create_virtual_dir(a, iso9660, "rr_moved");
 +		if (rrmoved == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		/* Add "rr_moved" entry to the root entry. */
 +		isoent_add_child_head(rootent, rrmoved);
 +		archive_entry_set_nlink(rootent->file->entry,
 +		    archive_entry_nlink(rootent->file->entry) + 1);
 +		/* Register "rr_moved" entry to second level pathtable. */
 +		path_table_add_entry(&(iso9660->primary.pathtbl[1]), rrmoved);
 +		/* Save rr_moved. */
 +		*rr_moved = rrmoved;
 +	}
 +	/*
 +	 * Make a clone of curent which is going to be relocated
 +	 * to rr_moved.
 +	 */
 +	mvent = isoent_clone(curent);
 +	if (mvent == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	/* linking..  and use for creating "CL", "PL" and "RE" */
 +	mvent->rr_parent = curent->parent;
 +	curent->rr_child = mvent;
 +	/*
 +	 * Move subdirectories from the curent to mvent
 +	 */
 +	if (curent->children.first != NULL) {
 +		*mvent->children.last = curent->children.first;
 +		mvent->children.last = curent->children.last;
 +	}
 +	for (np = mvent->children.first; np != NULL; np = np->chnext)
 +		np->parent = mvent;
 +	mvent->children.cnt = curent->children.cnt;
 +	curent->children.cnt = 0;
 +	curent->children.first = NULL;
 +	curent->children.last = &curent->children.first;
 +
 +	if (curent->subdirs.first != NULL) {
 +		*mvent->subdirs.last = curent->subdirs.first;
 +		mvent->subdirs.last = curent->subdirs.last;
 +	}
 +	mvent->subdirs.cnt = curent->subdirs.cnt;
 +	curent->subdirs.cnt = 0;
 +	curent->subdirs.first = NULL;
 +	curent->subdirs.last = &curent->subdirs.first;
 +
 +	/*
 +	 * The mvent becomes a child of the rr_moved entry.
 +	 */
 +	isoent_add_child_tail(rrmoved, mvent);
 +	archive_entry_set_nlink(rrmoved->file->entry,
 +	    archive_entry_nlink(rrmoved->file->entry) + 1);
 +	/*
 +	 * This entry which relocated to the rr_moved directory
 +	 * has to set the flag as a file.
 +	 * See also RRIP 4.1.5.1 Description of the "CL" System Use Entry.
 +	 */
 +	curent->dir = 0;
 +
 +	*newent = mvent;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +isoent_rr_move(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct path_table *pt;
 +	struct isoent *rootent, *rr_moved;
 +	struct isoent *np, *last;
 +	int r;
 +
 +	pt = &(iso9660->primary.pathtbl[MAX_DEPTH-1]);
 +	/* Theare aren't level 8 directories reaching a deepr level. */
 +	if (pt->cnt == 0)
 +		return (ARCHIVE_OK);
 +
 +	rootent = iso9660->primary.rootent;
 +	/* If "rr_moved" directory is already existing,
 +	 * we have to use it. */
 +	rr_moved = isoent_find_child(rootent, "rr_moved");
 +	if (rr_moved != NULL &&
 +	    rr_moved != rootent->children.first) {
 +		/*
 +		 * It's necessary that rr_move is the first entry
 +		 * of the root.
 +		 */
 +		/* Remove "rr_moved" entry from children chain. */
 +		isoent_remove_child(rootent, rr_moved);
 +
 +		/* Add "rr_moved" entry into the head of children chain. */
 +		isoent_add_child_head(rootent, rr_moved);
 +	}
 +
 +	/*
 +	 * Check level 8 path_table.
 +	 * If find out sub directory entries, that entries move to rr_move.
 +	 */
 +	np = pt->first;
 +	while (np != NULL) {
 +		last = path_table_last_entry(pt);
 +		for (; np != NULL; np = np->ptnext) {
 +			struct isoent *mvent;
 +			struct isoent *newent;
 +
 +			if (!np->dir)
 +				continue;
 +			for (mvent = np->subdirs.first;
 +			    mvent != NULL; mvent = mvent->drnext) {
 +				r = isoent_rr_move_dir(a, &rr_moved,
 +				    mvent, &newent);
 +				if (r < 0)
 +					return (r);
 +				isoent_collect_dirs(&(iso9660->primary),
 +				    newent, 2);
 +			}
 +		}
 +		/* If new entries are added to level 8 path_talbe,
 +		 * its sub directory entries move to rr_move too.
 +		 */
 +		np = last->ptnext;
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * This comparing rule is according to ISO9660 Standard 6.9.1
 + */
 +static int
 +_compare_path_table(const void *v1, const void *v2)
 +{
 +	const struct isoent *p1, *p2;
 +	const char *s1, *s2;
 +	int cmp, l;
 +
 +	p1 = *((const struct isoent **)(uintptr_t)v1);
 +	p2 = *((const struct isoent **)(uintptr_t)v2);
 +
 +	/* Compare parent directory number */
 +	cmp = p1->parent->dir_number - p2->parent->dir_number;
 +	if (cmp != 0)
 +		return (cmp);
 +
 +	/* Compare indetifier */
 +	s1 = p1->identifier;
 +	s2 = p2->identifier;
 +	l = p1->ext_off;
 +	if (l > p2->ext_off)
 +		l = p2->ext_off;
 +	cmp = strncmp(s1, s2, l);
 +	if (cmp != 0)
 +		return (cmp);
 +	if (p1->ext_off < p2->ext_off) {
 +		s2 += l;
 +		l = p2->ext_off - p1->ext_off;
 +		while (l--)
 +			if (0x20 != *s2++)
 +				return (0x20
 +				    - *(const unsigned char *)(s2 - 1));
 +	} else if (p1->ext_off > p2->ext_off) {
 +		s1 += l;
 +		l = p1->ext_off - p2->ext_off;
 +		while (l--)
 +			if (0x20 != *s1++)
 +				return (*(const unsigned char *)(s1 - 1)
 +				    - 0x20);
 +	}
 +	return (0);
 +}
 +
 +static int
 +_compare_path_table_joliet(const void *v1, const void *v2)
 +{
 +	const struct isoent *p1, *p2;
 +	const unsigned char *s1, *s2;
 +	int cmp, l;
 +
 +	p1 = *((const struct isoent **)(uintptr_t)v1);
 +	p2 = *((const struct isoent **)(uintptr_t)v2);
 +
 +	/* Compare parent directory number */
 +	cmp = p1->parent->dir_number - p2->parent->dir_number;
 +	if (cmp != 0)
 +		return (cmp);
 +
 +	/* Compare indetifier */
 +	s1 = (const unsigned char *)p1->identifier;
 +	s2 = (const unsigned char *)p2->identifier;
 +	l = p1->ext_off;
 +	if (l > p2->ext_off)
 +		l = p2->ext_off;
 +	cmp = memcmp(s1, s2, l);
 +	if (cmp != 0)
 +		return (cmp);
 +	if (p1->ext_off < p2->ext_off) {
 +		s2 += l;
 +		l = p2->ext_off - p1->ext_off;
 +		while (l--)
 +			if (0 != *s2++)
 +				return (- *(const unsigned char *)(s2 - 1));
 +	} else if (p1->ext_off > p2->ext_off) {
 +		s1 += l;
 +		l = p1->ext_off - p2->ext_off;
 +		while (l--)
 +			if (0 != *s1++)
 +				return (*(const unsigned char *)(s1 - 1));
 +	}
 +	return (0);
 +}
 +
 +static inline void
 +path_table_add_entry(struct path_table *pathtbl, struct isoent *ent)
 +{
 +	ent->ptnext = NULL;
 +	*pathtbl->last = ent;
 +	pathtbl->last = &(ent->ptnext);
 +	pathtbl->cnt ++;
 +}
 +
 +static inline struct isoent *
 +path_table_last_entry(struct path_table *pathtbl)
 +{
 +	if (pathtbl->first == NULL)
 +		return (NULL);
 +	return (((struct isoent *)(void *)
 +		((char *)(pathtbl->last) - offsetof(struct isoent, ptnext))));
 +}
 +
 +/*
 + * Sort directory entries in path_table
 + * and assign directory number to each entries.
 + */
 +static int
 +isoent_make_path_table_2(struct archive_write *a, struct vdd *vdd,
 +    int depth, int *dir_number)
 +{
 +	struct isoent *np;
 +	struct isoent **enttbl;
 +	struct path_table *pt;
 +	int i;
 +
 +	pt = &vdd->pathtbl[depth];
 +	if (pt->cnt == 0) {
 +		pt->sorted = NULL;
 +		return (ARCHIVE_OK);
 +	}
 +	enttbl = malloc(pt->cnt * sizeof(struct isoent *));
 +	if (enttbl == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	pt->sorted = enttbl;
 +	for (np = pt->first; np != NULL; np = np->ptnext)
 +		*enttbl ++ = np;
 +	enttbl = pt->sorted;
 +
 +	switch (vdd->vdd_type) {
 +	case VDD_PRIMARY:
 +	case VDD_ENHANCED:
++#ifdef __COMPAR_FN_T
++		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
++		    (__compar_fn_t)_compare_path_table);
++#else
 +		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
 +		    _compare_path_table);
++#endif
 +		break;
 +	case VDD_JOLIET:
++#ifdef __COMPAR_FN_T
++		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
++		    (__compar_fn_t)_compare_path_table_joliet);
++#else
 +		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
 +		    _compare_path_table_joliet);
++#endif
 +		break;
 +	}
 +	for (i = 0; i < pt->cnt; i++)
 +		enttbl[i]->dir_number = (*dir_number)++;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +isoent_alloc_path_table(struct archive_write *a, struct vdd *vdd,
 +    int max_depth)
 +{
 +	int i;
 +
 +	vdd->max_depth = max_depth;
 +	vdd->pathtbl = malloc(sizeof(*vdd->pathtbl) * vdd->max_depth);
 +	if (vdd->pathtbl == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	for (i = 0; i < vdd->max_depth; i++) {
 +		vdd->pathtbl[i].first = NULL;
 +		vdd->pathtbl[i].last = &(vdd->pathtbl[i].first);
 +		vdd->pathtbl[i].sorted = NULL;
 +		vdd->pathtbl[i].cnt = 0;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Make Path Tables
 + */
 +static int
 +isoent_make_path_table(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	int depth, r;
 +	int dir_number;
 +
 +	/*
 +	 * Init Path Table.
 +	 */
 +	if (iso9660->dircnt_max >= MAX_DEPTH &&
 +	    (!iso9660->opt.limit_depth || iso9660->opt.iso_level == 4))
 +		r = isoent_alloc_path_table(a, &(iso9660->primary),
 +		    iso9660->dircnt_max + 1);
 +	else
 +		/* The number of levels in the hierarchy cannot exceed
 +		 * eight. */
 +		r = isoent_alloc_path_table(a, &(iso9660->primary),
 +		    MAX_DEPTH);
 +	if (r < 0)
 +		return (r);
 +	if (iso9660->opt.joliet) {
 +		r = isoent_alloc_path_table(a, &(iso9660->joliet),
 +		    iso9660->dircnt_max + 1);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Step 0.
 +	 * - Collect directories for primary and joliet.
 +	 */
 +	isoent_collect_dirs(&(iso9660->primary), NULL, 0);
 +	if (iso9660->opt.joliet)
 +		isoent_collect_dirs(&(iso9660->joliet), NULL, 0);
 +	/*
 +	 * Rockridge; move deeper depth directories to rr_moved.
 +	 */
 +	if (iso9660->opt.rr) {
 +		r = isoent_rr_move(a);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 + 	/* Update nlink. */
 +	isofile_connect_hardlink_files(iso9660);
 +
 +	/* Step 1.
 +	 * - Renew a value of the depth of that directories.
 +	 * - Resolve hardlinks.
 + 	 * - Convert pathnames to ISO9660 name or UCS2(joliet).
 +	 * - Sort files by each directory.
 +	 */
 +	r = isoent_traverse_tree(a, &(iso9660->primary));
 +	if (r < 0)
 +		return (r);
 +	if (iso9660->opt.joliet) {
 +		r = isoent_traverse_tree(a, &(iso9660->joliet));
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/* Step 2.
 +	 * - Sort directories.
 +	 * - Assign all directory number.
 +	 */
 +	dir_number = 1;
 +	for (depth = 0; depth < iso9660->primary.max_depth; depth++) {
 +		r = isoent_make_path_table_2(a, &(iso9660->primary),
 +		    depth, &dir_number);
 +		if (r < 0)
 +			return (r);
 +	}
 +	if (iso9660->opt.joliet) {
 +		dir_number = 1;
 +		for (depth = 0; depth < iso9660->joliet.max_depth; depth++) {
 +			r = isoent_make_path_table_2(a, &(iso9660->joliet),
 +			    depth, &dir_number);
 +			if (r < 0)
 +				return (r);
 +		}
 +	}
 +	if (iso9660->opt.limit_dirs && dir_number > 0xffff) {
 +		/*
 +		 * Maximum number of directories is 65535(0xffff)
 +		 * doe to size(16bit) of Parent Directory Number of
 +		 * the Path Table.
 +		 * See also ISO9660 Standard 9.4.
 +		 */
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Too many directories(%d) over 65535.", dir_number);
 +		return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Get the size of the Path Table. */
 +	calculate_path_table_size(&(iso9660->primary));
 +	if (iso9660->opt.joliet)
 +		calculate_path_table_size(&(iso9660->joliet));
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +isoent_find_out_boot_file(struct archive_write *a, struct isoent *rootent)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +
 +	/* Find a isoent of the boot file. */
 +	iso9660->el_torito.boot = isoent_find_entry(rootent,
 +	    iso9660->el_torito.boot_filename.s);
 +	if (iso9660->el_torito.boot == NULL) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Can't find the boot image file ``%s''",
 +		    iso9660->el_torito.boot_filename.s);
 +		return (ARCHIVE_FATAL);
 +	}
 +	iso9660->el_torito.boot->file->boot = BOOT_IMAGE;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +isoent_create_boot_catalog(struct archive_write *a, struct isoent *rootent)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isofile *file;
 +	struct isoent *isoent;
 +	struct archive_entry *entry;
 +
 +	(void)rootent; /* UNUSED */
 +	/*
 +	 * Create the entry which is the "boot.catalog" file.
 +	 */
 +	file = isofile_new(a, NULL);
 +	if (file == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	archive_entry_set_pathname(file->entry,
 +	    iso9660->el_torito.catalog_filename.s);
 +	archive_entry_set_size(file->entry, LOGICAL_BLOCK_SIZE);
 +	archive_entry_set_mtime(file->entry, iso9660->birth_time, 0);
 +	archive_entry_set_atime(file->entry, iso9660->birth_time, 0);
 +	archive_entry_set_ctime(file->entry, iso9660->birth_time, 0);
 +	archive_entry_set_uid(file->entry, getuid());
 +	archive_entry_set_gid(file->entry, getgid());
 +	archive_entry_set_mode(file->entry, AE_IFREG | 0444);
 +	archive_entry_set_nlink(file->entry, 1);
 +
 +	if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
 +		isofile_free(file);
 +		return (ARCHIVE_FATAL);
 +	}
 +	file->boot = BOOT_CATALOG;
 +	file->content.size = LOGICAL_BLOCK_SIZE;
 +	isofile_add_entry(iso9660, file);
 +
 +	isoent = isoent_new(file);
 +	if (isoent == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	isoent->virtual = 1;
 +
 +	/* Add the "boot.catalog" entry into tree */
 +	if (isoent_tree(a, &isoent) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	iso9660->el_torito.catalog = isoent;
 +	/*
 +	 * Get a boot medai type.
 +	 */
 +	switch (iso9660->opt.boot_type) {
 +	default:
 +	case OPT_BOOT_TYPE_AUTO:
 +		/* Try detecting a media type of the boot image. */
 +		entry = iso9660->el_torito.boot->file->entry;
 +		if (archive_entry_size(entry) == FD_1_2M_SIZE)
 +			iso9660->el_torito.media_type =
 +			    BOOT_MEDIA_1_2M_DISKETTE;
 +		else if (archive_entry_size(entry) == FD_1_44M_SIZE)
 +			iso9660->el_torito.media_type =
 +			    BOOT_MEDIA_1_44M_DISKETTE;
 +		else if (archive_entry_size(entry) == FD_2_88M_SIZE)
 +			iso9660->el_torito.media_type =
 +			    BOOT_MEDIA_2_88M_DISKETTE;
 +		else
 +			/* We cannot decide whether the boot image is
 +			 * hard-disk. */
 +			iso9660->el_torito.media_type =
 +			    BOOT_MEDIA_NO_EMULATION;
 +		break;
 +	case OPT_BOOT_TYPE_NO_EMU:
 +		iso9660->el_torito.media_type = BOOT_MEDIA_NO_EMULATION;
 +		break;
 +	case OPT_BOOT_TYPE_HARD_DISK:
 +		iso9660->el_torito.media_type = BOOT_MEDIA_HARD_DISK;
 +		break;
 +	case OPT_BOOT_TYPE_FD:
 +		entry = iso9660->el_torito.boot->file->entry;
 +		if (archive_entry_size(entry) <= FD_1_2M_SIZE)
 +			iso9660->el_torito.media_type =
 +			    BOOT_MEDIA_1_2M_DISKETTE;
 +		else if (archive_entry_size(entry) <= FD_1_44M_SIZE)
 +			iso9660->el_torito.media_type =
 +			    BOOT_MEDIA_1_44M_DISKETTE;
 +		else if (archive_entry_size(entry) <= FD_2_88M_SIZE)
 +			iso9660->el_torito.media_type =
 +			    BOOT_MEDIA_2_88M_DISKETTE;
 +		else {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Boot image file(``%s'') size is too big "
 +			    "for fd type.",
 +			    iso9660->el_torito.boot_filename.s);
 +			return (ARCHIVE_FATAL);
 +		}
 +		break;
 +	}
 +
 +	/*
 +	 * Get a system type.
 +	 * TODO: `El Torito' specification says "A copy of byte 5 from the
 +	 *       Partition Table found in the boot image".
 +	 */
 +	iso9660->el_torito.system_type = 0;
 +
 +	/*
 +	 * Get an ID.
 +	 */
 +	if (iso9660->opt.publisher)
 +		archive_string_copy(&(iso9660->el_torito.id),
 +		    &(iso9660->publisher_identifier));
 +
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * If a media type is floppy, return its image size.
 + * otherwise return 0.
 + */
 +static size_t
 +fd_boot_image_size(int media_type)
 +{
 +	switch (media_type) {
 +	case BOOT_MEDIA_1_2M_DISKETTE:
 +		return (FD_1_2M_SIZE);
 +	case BOOT_MEDIA_1_44M_DISKETTE:
 +		return (FD_1_44M_SIZE);
 +	case BOOT_MEDIA_2_88M_DISKETTE:
 +		return (FD_2_88M_SIZE);
 +	default:
 +		return (0);
 +	}
 +}
 +
 +/*
 + * Make a boot catalog image data.
 + */
 +static int
 +make_boot_catalog(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	unsigned char *block;
 +	unsigned char *p;
 +	uint16_t sum, *wp;
 +
 +	block = wb_buffptr(a);
 +	memset(block, 0, LOGICAL_BLOCK_SIZE);
 +	p = block;
 +	/*
 +	 * Validation Entry
 +	 */
 +	/* Header ID */
 +	p[0] = 1;
 +	/* Platform ID */
 +	p[1] = iso9660->el_torito.platform_id;
 +	/* Reserved */
 +	p[2] = p[3] = 0;
 +	/* ID */
 +	if (archive_strlen(&(iso9660->el_torito.id)) > 0)
 +		strncpy((char *)p+4, iso9660->el_torito.id.s, 23);
 +	p[27] = 0;
 +	/* Checksum */
 +	p[28] = p[29] = 0;
 +	/* Key */
 +	p[30] = 0x55;
 +	p[31] = 0xAA;
 +
 +	sum = 0;
 +	wp = (uint16_t *)block;
 +	while (wp < (uint16_t *)&block[32])
 +		sum += archive_le16dec(wp++);
 +	set_num_721(&block[28], (~sum) + 1);
 +
 +	/*
 +	 * Initial/Default Entry
 +	 */
 +	p = &block[32];
 +	/* Boot Indicator */
 +	p[0] = 0x88;
 +	/* Boot media type */
 +	p[1] = iso9660->el_torito.media_type;
 +	/* Load Segment */
 +	if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
 +		set_num_721(&p[2], iso9660->el_torito.boot_load_seg);
 +	else
 +		set_num_721(&p[2], 0);
 +	/* System Type */
 +	p[4] = iso9660->el_torito.system_type;
 +	/* Unused */
 +	p[5] = 0;
 +	/* Sector Count */
 +	if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
 +		set_num_721(&p[6], iso9660->el_torito.boot_load_size);
 +	else
 +		set_num_721(&p[6], 1);
 +	/* Load RBA */
 +	set_num_731(&p[8],
 +	    iso9660->el_torito.boot->file->content.location);
 +	/* Unused */
 +	memset(&p[12], 0, 20);
 +
 +	return (wb_consume(a, LOGICAL_BLOCK_SIZE));
 +}
 +
 +static int
 +setup_boot_information(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isoent *np;
 +	int64_t size;
 +	uint32_t sum;
 +	unsigned char buff[4096];
 +
 +	np = iso9660->el_torito.boot;
 +	lseek(iso9660->temp_fd,
 +	    np->file->content.offset_of_temp + 64, SEEK_SET);
 +	size = archive_entry_size(np->file->entry) - 64;
 +	if (size <= 0) {
 +		archive_set_error(&a->archive, errno,
 +		    "Boot file(%jd) is too small", (intmax_t)size + 64);
 +		return (ARCHIVE_FATAL);
 +	}
 +	sum = 0;
 +	while (size > 0) {
 +		size_t rsize;
 +		ssize_t i, rs;
 +
- 		if (size > sizeof(buff))
++		if (size > (int64_t)sizeof(buff))
 +			rsize = sizeof(buff);
 +		else
 +			rsize = (size_t)size;
 +
 +		rs = read(iso9660->temp_fd, buff, rsize);
 +		if (rs <= 0) {
 +			archive_set_error(&a->archive, errno,
 +			    "Can't read temporary file(%jd)",
 +			    (intmax_t)rs);
 +			return (ARCHIVE_FATAL);
 +		}
 +		for (i = 0; i < rs; i += 4)
 +			sum += archive_le32dec(buff + i);
 +		size -= rs;
 +	}
 +	/* Set the location of Primary Volume Descriptor. */
 +	set_num_731(buff, SYSTEM_AREA_BLOCK);
 +	/* Set the location of the boot file. */
 +	set_num_731(buff+4, np->file->content.location);
 +	/* Set the size of the boot file. */
 +	size = fd_boot_image_size(iso9660->el_torito.media_type);
 +	if (size == 0)
 +		size = archive_entry_size(np->file->entry);
 +	set_num_731(buff+8, (uint32_t)size);
 +	/* Set the sum of the boot file. */
 +	set_num_731(buff+12, sum);
 +	/* Clear reserved bytes. */
 +	memset(buff+16, 0, 40);
 +
 +	/* Overwrite the boot file. */
 +	lseek(iso9660->temp_fd,
 +	    np->file->content.offset_of_temp + 8, SEEK_SET);
 +	return (write_to_temp(a, buff, 56));
 +}
 +
 +#ifdef HAVE_ZLIB_H
 +
 +static int
 +zisofs_init_zstream(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	int r;
 +
 +	iso9660->zisofs.stream.next_in = NULL;
 +	iso9660->zisofs.stream.avail_in = 0;
 +	iso9660->zisofs.stream.total_in = 0;
 +	iso9660->zisofs.stream.total_out = 0;
 +	if (iso9660->zisofs.stream_valid)
 +		r = deflateReset(&(iso9660->zisofs.stream));
 +	else {
 +		r = deflateInit(&(iso9660->zisofs.stream),
 +		    iso9660->zisofs.compression_level);
 +		iso9660->zisofs.stream_valid = 1;
 +	}
 +	switch (r) {
 +	case Z_OK:
 +		break;
 +	default:
 +	case Z_STREAM_ERROR:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing "
 +		    "compression library: invalid setup parameter");
 +		return (ARCHIVE_FATAL);
 +	case Z_MEM_ERROR:
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Internal error initializing "
 +		    "compression library");
 +		return (ARCHIVE_FATAL);
 +	case Z_VERSION_ERROR:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing "
 +		    "compression library: invalid library version");
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +#endif /* HAVE_ZLIB_H */
 +
 +static int
 +zisofs_init(struct archive_write *a,  struct isofile *file)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +#ifdef HAVE_ZLIB_H
 +	uint64_t tsize;
- 	size_t ceil, bpsize;
++	size_t _ceil, bpsize;
 +	int r;
 +#endif
 +
 +	iso9660->zisofs.detect_magic = 0;
 +	iso9660->zisofs.making = 0;
 +
 +	if (!iso9660->opt.rr || !iso9660->opt.zisofs)
 +		return (ARCHIVE_OK);
 +
 +	if (archive_entry_size(file->entry) >= 24 &&
 +	    archive_entry_size(file->entry) < MULTI_EXTENT_SIZE) {
 +		/* Acceptable file size for zisofs. */
 +		iso9660->zisofs.detect_magic = 1;
 +		iso9660->zisofs.magic_cnt = 0;
 +	}
 +	if (!iso9660->zisofs.detect_magic)
 +		return (ARCHIVE_OK);
 +
 +#ifdef HAVE_ZLIB_H
 +	/* The number of Logical Blocks which uncompressed data
 +	 * will use in iso-image file is the same as the number of
 +	 * Logical Blocks which zisofs(compressed) data will use
 +	 * in ISO-image file. It won't reduce iso-image file size. */
 +	if (archive_entry_size(file->entry) <= LOGICAL_BLOCK_SIZE)
 +		return (ARCHIVE_OK);
 +
 +	/* Initialize compression library */
 +	r = zisofs_init_zstream(a);
 +	if (r != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Mark file->zisofs to create RRIP 'ZF' Use Entry. */
 +	file->zisofs.header_size = ZF_HEADER_SIZE >> 2;
 +	file->zisofs.log2_bs = ZF_LOG2_BS;
- 	file->zisofs.uncompressed_size = archive_entry_size(file->entry);
++	file->zisofs.uncompressed_size =
++		(uint32_t)archive_entry_size(file->entry);
 +
 +	/* Calculate a size of Block Pointers of zisofs. */
- 	ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)
++	_ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)
 +		>> file->zisofs.log2_bs;
- 	iso9660->zisofs.block_pointers_cnt = ceil + 1;
++	iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1;
 +	iso9660->zisofs.block_pointers_idx = 0;
 +
 +	/* Ensure a buffer size used for Block Pointers */
 +	bpsize = iso9660->zisofs.block_pointers_cnt *
 +	    sizeof(iso9660->zisofs.block_pointers[0]);
 +	if (iso9660->zisofs.block_pointers_allocated < bpsize) {
 +		free(iso9660->zisofs.block_pointers);
 +		iso9660->zisofs.block_pointers = malloc(bpsize);
 +		if (iso9660->zisofs.block_pointers == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate data");
 +			return (ARCHIVE_FATAL);
 +		}
 +		iso9660->zisofs.block_pointers_allocated = bpsize;
 +	}
 +
 +	/*
 +	 * Skip zisofs header and Block Pointers, which we will write
 +	 * after all compressed data of a file written to the temporary
 +	 * file.
 +	 */
 +	tsize = ZF_HEADER_SIZE + bpsize;
- 	if (write_null(a, tsize) != ARCHIVE_OK)
++	if (write_null(a, (size_t)tsize) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/*
 +	 * Initialize some variables to make zisofs.
 +	 */
- 	archive_le32enc(&(iso9660->zisofs.block_pointers[0]), tsize);
++	archive_le32enc(&(iso9660->zisofs.block_pointers[0]),
++		(uint32_t)tsize);
 +	iso9660->zisofs.remaining = file->zisofs.uncompressed_size;
 +	iso9660->zisofs.making = 1;
 +	iso9660->zisofs.allzero = 1;
 +	iso9660->zisofs.block_offset = tsize;
 +	iso9660->zisofs.total_size = tsize;
 +	iso9660->cur_file->cur_content->size = tsize;
 +#endif
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isofile *file = iso9660->cur_file;
 +	const unsigned char *p, *endp;
 +	const unsigned char *magic_buff;
 +	uint32_t uncompressed_size;
 +	unsigned char header_size;
 +	unsigned char log2_bs;
- 	size_t ceil, doff;
++	size_t _ceil, doff;
 +	uint32_t bst, bed;
 +	int magic_max;
 +	int64_t entry_size;
 +
 +	entry_size = archive_entry_size(file->entry);
- 	if (sizeof(iso9660->zisofs.magic_buffer) > entry_size)
- 		magic_max = entry_size;
++	if ((int64_t)sizeof(iso9660->zisofs.magic_buffer) > entry_size)
++		magic_max = (int)entry_size;
 +	else
 +		magic_max = sizeof(iso9660->zisofs.magic_buffer);
 +
 +	if (iso9660->zisofs.magic_cnt == 0 && s >= (size_t)magic_max)
 +		/* It's unnecessary we copy buffer. */
 +		magic_buff = buff;
 +	else {
 +		if (iso9660->zisofs.magic_cnt < magic_max) {
 +			size_t l;
 +
 +			l = sizeof(iso9660->zisofs.magic_buffer)
 +			    - iso9660->zisofs.magic_cnt;
 +			if (l > s)
 +				l = s;
 +			memcpy(iso9660->zisofs.magic_buffer
 +			    + iso9660->zisofs.magic_cnt, buff, l);
- 			iso9660->zisofs.magic_cnt += l;
++			iso9660->zisofs.magic_cnt += (int)l;
 +			if (iso9660->zisofs.magic_cnt < magic_max)
 +				return;
 +		}
 +		magic_buff = iso9660->zisofs.magic_buffer;
 +	}
 +	iso9660->zisofs.detect_magic = 0;
 +	p = magic_buff;
 +
 +	/* Check the magic code of zisofs. */
 +	if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
 +		/* This is not zisofs file which made by mkzftree. */
 +		return;
 +	p += sizeof(zisofs_magic);
 +
 +	/* Read a zisofs header. */
 +	uncompressed_size = archive_le32dec(p);
 +	header_size = p[4];
 +	log2_bs = p[5];
 +	if (uncompressed_size < 24 || header_size != 4 ||
 +	    log2_bs > 30 || log2_bs < 7)
 +		return;/* Invalid or not supported header. */
 +
 +	/* Calculate a size of Block Pointers of zisofs. */
- 	ceil = (uncompressed_size +
++	_ceil = (uncompressed_size +
 +	        (ARCHIVE_LITERAL_LL(1) << log2_bs) -1) >> log2_bs;
- 	doff = (ceil + 1) * 4 + 16;
- 	if (entry_size < doff)
++	doff = (_ceil + 1) * 4 + 16;
++	if (entry_size < (int64_t)doff)
 +		return;/* Invalid data. */
 +
 +	/* Check every Block Pointer has valid value. */
 +	p = magic_buff + 16;
 +	endp = magic_buff + magic_max;
- 	while (ceil && p + 8 <= endp) {
++	while (_ceil && p + 8 <= endp) {
 +		bst = archive_le32dec(p);
 +		if (bst != doff)
 +			return;/* Invalid data. */
 +		p += 4;
 +		bed = archive_le32dec(p);
 +		if (bed < bst || bed > entry_size)
 +			return;/* Invalid data. */
 +		doff += bed - bst;
- 		ceil--;
++		_ceil--;
 +	}
 +
 +	file->zisofs.uncompressed_size = uncompressed_size;
 +	file->zisofs.header_size = header_size;
 +	file->zisofs.log2_bs = log2_bs;
 +
 +	/* Disable making a zisofs image. */
 +	iso9660->zisofs.making = 0;
 +}
 +
 +#ifdef HAVE_ZLIB_H
 +
 +/*
 + * Compress data and write it to a temporary file.
 + */
 +static int
 +zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isofile *file = iso9660->cur_file;
 +	const unsigned char *b;
 +	z_stream *zstrm;
 +	size_t avail, csize;
 +	int flush, r;
 +
 +	zstrm = &(iso9660->zisofs.stream);
 +	zstrm->next_out = wb_buffptr(a);
- 	zstrm->avail_out = wb_remaining(a);
++	zstrm->avail_out = (uInt)wb_remaining(a);
 +	b = (const unsigned char *)buff;
 +	do {
 +		avail = ZF_BLOCK_SIZE - zstrm->total_in;
 +		if (s < avail) {
 +			avail = s;
 +			flush = Z_NO_FLUSH;
 +		} else
 +			flush = Z_FINISH;
 +		iso9660->zisofs.remaining -= avail;
 +		if (iso9660->zisofs.remaining <= 0)
 +			flush = Z_FINISH;
 +
 +		zstrm->next_in = (Bytef *)(uintptr_t)(const void *)b;
- 		zstrm->avail_in = avail;
++		zstrm->avail_in = (uInt)avail;
 +
 +		/*
 +		 * Check if current data block are all zero.
 +		 */
 +		if (iso9660->zisofs.allzero) {
 +			const unsigned char *nonzero = b;
 +			const unsigned char *nonzeroend = b + avail;
 +
 +			while (nonzero < nonzeroend)
 +				if (*nonzero++) {
 +					iso9660->zisofs.allzero = 0;
 +					break;
 +				}
 +		}
 +		b += avail;
 +		s -= avail;
 +
 +		/*
 +		 * If current data block are all zero, we do not use
 +		 * compressed data.
 +		 */
 +		if (flush == Z_FINISH && iso9660->zisofs.allzero &&
 +		    avail + zstrm->total_in == ZF_BLOCK_SIZE) {
 +			if (iso9660->zisofs.block_offset !=
 +			    file->cur_content->size) {
 +				int64_t diff;
 +
 +				r = wb_set_offset(a,
 +				    file->cur_content->offset_of_temp +
 +				        iso9660->zisofs.block_offset);
 +				if (r != ARCHIVE_OK)
 +					return (r);
 +				diff = file->cur_content->size -
 +				    iso9660->zisofs.block_offset;
 +				file->cur_content->size -= diff;
 +				iso9660->zisofs.total_size -= diff;
 +			}
 +			zstrm->avail_in = 0;
 +		}
 +
 +		/*
 +		 * Compress file data.
 +		 */
 +		while (zstrm->avail_in > 0) {
 +			csize = zstrm->total_out;
 +			r = deflate(zstrm, flush);
 +			switch (r) {
 +			case Z_OK:
 +			case Z_STREAM_END:
 +				csize = zstrm->total_out - csize;
 +				if (wb_consume(a, csize) != ARCHIVE_OK)
 +					return (ARCHIVE_FATAL);
 +				iso9660->zisofs.total_size += csize;
 +				iso9660->cur_file->cur_content->size += csize;
 +				zstrm->next_out = wb_buffptr(a);
- 				zstrm->avail_out = wb_remaining(a);
++				zstrm->avail_out = (uInt)wb_remaining(a);
 +				break;
 +			default:
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "Compression failed:"
 +				    " deflate() call returned status %d",
 +				    r);
 +				return (ARCHIVE_FATAL);
 +			}
 +		}
 +
 +		if (flush == Z_FINISH) {
 +			/*
 +			 * Save the information of one zisofs block.
 +			 */
 +			iso9660->zisofs.block_pointers_idx ++;
 +			archive_le32enc(&(iso9660->zisofs.block_pointers[
 +			    iso9660->zisofs.block_pointers_idx]),
- 				iso9660->zisofs.total_size);
++				(uint32_t)iso9660->zisofs.total_size);
 +			r = zisofs_init_zstream(a);
 +			if (r != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			iso9660->zisofs.allzero = 1;
 +			iso9660->zisofs.block_offset = file->cur_content->size;
 +		}
 +	} while (s);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +zisofs_finish_entry(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isofile *file = iso9660->cur_file;
 +	unsigned char buff[16];
 +	size_t s;
 +	int64_t tail;
 +
 +	/* Direct temp file stream to zisofs temp file stream. */
 +	archive_entry_set_size(file->entry, iso9660->zisofs.total_size);
 +
 +	/*
 +	 * Save a file pointer which points the end of current zisofs data.
 +	 */
 +	tail = wb_offset(a);
 +
 +	/*
 +	 * Make a header.
 +	 *
 +	 * +-----------------+----------------+-----------------+
 +	 * | Header 16 bytes | Block Pointers | Compressed data |
 +	 * +-----------------+----------------+-----------------+
 +	 * 0                16               +X
 +	 * Block Pointers :
 +	 *   4 * (((Uncompressed file size + block_size -1) / block_size) + 1)
 +	 *
 +	 * Write zisofs header.
 +	 *    Magic number
 +	 * +----+----+----+----+----+----+----+----+
 +	 * | 37 | E4 | 53 | 96 | C9 | DB | D6 | 07 |
 +	 * +----+----+----+----+----+----+----+----+
 +	 * 0    1    2    3    4    5    6    7    8
 +	 *
 +	 * +------------------------+------------------+
 +	 * | Uncompressed file size | header_size >> 2 |
 +	 * +------------------------+------------------+
 +	 * 8                       12                 13
 +	 *
 +	 * +-----------------+----------------+
 +	 * | log2 block_size | Reserved(0000) |
 +	 * +-----------------+----------------+
 +	 * 13               14               16
 +	 */
 +	memcpy(buff, zisofs_magic, 8);
 +	set_num_731(buff+8, file->zisofs.uncompressed_size);
 +	buff[12] = file->zisofs.header_size;
 +	buff[13] = file->zisofs.log2_bs;
 +	buff[14] = buff[15] = 0;/* Reserved */
 +
 +	/* Move to the right position to write the header. */
 +	wb_set_offset(a, file->content.offset_of_temp);
 +
 +	/* Write the header. */
 +	if (wb_write_to_temp(a, buff, 16) != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/*
 +	 * Write zisofs Block Pointers.
 +	 */
 +	s = iso9660->zisofs.block_pointers_cnt *
 +	    sizeof(iso9660->zisofs.block_pointers[0]);
 +	if (wb_write_to_temp(a, iso9660->zisofs.block_pointers, s)
 +	    != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +
 +	/* Set a file pointer back to the end of the temporary file. */
 +	wb_set_offset(a, tail);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +zisofs_free(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	int ret = ARCHIVE_OK;
 +
 +	free(iso9660->zisofs.block_pointers);
 +	if (iso9660->zisofs.stream_valid &&
 +	    deflateEnd(&(iso9660->zisofs.stream)) != Z_OK) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		ret = ARCHIVE_FATAL;
 +	}
 +	iso9660->zisofs.block_pointers = NULL;
 +	iso9660->zisofs.stream_valid = 0;
 +	return (ret);
 +}
 +
 +struct zisofs_extract {
 +	int		 pz_log2_bs; /* Log2 of block size */
 +	uint64_t	 pz_uncompressed_size;
 +	size_t		 uncompressed_buffer_size;
 +
 +	int		 initialized:1;
 +	int		 header_passed:1;
 +
 +	uint32_t	 pz_offset;
 +	unsigned char	*block_pointers;
 +	size_t		 block_pointers_size;
 +	size_t		 block_pointers_avail;
 +	size_t		 block_off;
 +	uint32_t	 block_avail;
 +
 +	z_stream	 stream;
 +	int		 stream_valid;
 +};
 +
 +static ssize_t
 +zisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs,
 +    const unsigned char *p, size_t bytes)
 +{
 +	size_t avail = bytes;
- 	size_t ceil, xsize;
++	size_t _ceil, xsize;
 +
 +	/* Allocate block pointers buffer. */
- 	ceil = (zisofs->pz_uncompressed_size +
++	_ceil = (size_t)((zisofs->pz_uncompressed_size +
 +		(((int64_t)1) << zisofs->pz_log2_bs) - 1)
- 		>> zisofs->pz_log2_bs;
- 	xsize = (ceil + 1) * 4;
++		>> zisofs->pz_log2_bs);
++	xsize = (_ceil + 1) * 4;
 +	if (zisofs->block_pointers == NULL) {
 +		size_t alloc = ((xsize >> 10) + 1) << 10;
 +		zisofs->block_pointers = malloc(alloc);
 +		if (zisofs->block_pointers == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "No memory for zisofs decompression");
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +	zisofs->block_pointers_size = xsize;
 +
 +	/* Allocate uncompressed data buffer. */
- 	zisofs->uncompressed_buffer_size = 1UL << zisofs->pz_log2_bs;
++	zisofs->uncompressed_buffer_size = (size_t)1UL << zisofs->pz_log2_bs;
 +
 +	/*
 +	 * Read the file header, and check the magic code of zisofs.
 +	 */
 +	if (!zisofs->header_passed) {
 +		int err = 0;
 +		if (avail < 16) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs file body");
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
 +			err = 1;
 +		else if (archive_le32dec(p + 8) != zisofs->pz_uncompressed_size)
 +			err = 1;
 +		else if (p[12] != 4 || p[13] != zisofs->pz_log2_bs)
 +			err = 1;
 +		if (err) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs file body");
 +			return (ARCHIVE_FATAL);
 +		}
 +		avail -= 16;
 +		p += 16;
 +		zisofs->header_passed = 1;
 +	}
 +
 +	/*
 +	 * Read block pointers.
 +	 */
 +	if (zisofs->header_passed &&
 +	    zisofs->block_pointers_avail < zisofs->block_pointers_size) {
 +		xsize = zisofs->block_pointers_size
 +		    - zisofs->block_pointers_avail;
 +		if (avail < xsize)
 +			xsize = avail;
 +		memcpy(zisofs->block_pointers
 +		    + zisofs->block_pointers_avail, p, xsize);
 +		zisofs->block_pointers_avail += xsize;
 +		avail -= xsize;
 +	    	if (zisofs->block_pointers_avail
 +		    == zisofs->block_pointers_size) {
 +			/* We've got all block pointers and initialize
 +			 * related variables.	*/
 +			zisofs->block_off = 0;
 +			zisofs->block_avail = 0;
 +			/* Complete a initialization */
 +			zisofs->initialized = 1;
 +		}
 +	}
 +	return ((ssize_t)avail);
 +}
 +
 +static ssize_t
 +zisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs,
 +    const unsigned char *p, size_t bytes)
 +{
 +	size_t avail;
 +	int r;
 +
 +	if (!zisofs->initialized) {
 +		ssize_t rs = zisofs_extract_init(a, zisofs, p, bytes);
 +		if (rs < 0)
 +			return (rs);
 +		if (!zisofs->initialized) {
 +			/* We need more data. */
- 			zisofs->pz_offset += bytes;
++			zisofs->pz_offset += (uint32_t)bytes;
 +			return (bytes);
 +		}
 +		avail = rs;
 +		p += bytes - avail;
 +	} else
 +		avail = bytes;
 +
 +	/*
 +	 * Get block offsets from block pointers.
 +	 */
 +	if (zisofs->block_avail == 0) {
 +		uint32_t bst, bed;
 +
 +		if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {
 +			/* There isn't a pair of offsets. */
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs block pointers");
 +			return (ARCHIVE_FATAL);
 +		}
 +		bst = archive_le32dec(
 +		    zisofs->block_pointers + zisofs->block_off);
 +		if (bst != zisofs->pz_offset + (bytes - avail)) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs block pointers(cannot seek)");
 +			return (ARCHIVE_FATAL);
 +		}
 +		bed = archive_le32dec(
 +		    zisofs->block_pointers + zisofs->block_off + 4);
 +		if (bed < bst) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Illegal zisofs block pointers");
 +			return (ARCHIVE_FATAL);
 +		}
 +		zisofs->block_avail = bed - bst;
 +		zisofs->block_off += 4;
 +
 +		/* Initialize compression library for new block. */
 +		if (zisofs->stream_valid)
 +			r = inflateReset(&zisofs->stream);
 +		else
 +			r = inflateInit(&zisofs->stream);
 +		if (r != Z_OK) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "Can't initialize zisofs decompression.");
 +			return (ARCHIVE_FATAL);
 +		}
 +		zisofs->stream_valid = 1;
 +		zisofs->stream.total_in = 0;
 +		zisofs->stream.total_out = 0;
 +	}
 +
 +	/*
 +	 * Make uncompressed data.
 +	 */
 +	if (zisofs->block_avail == 0) {
 +		/*
 +		 * It's basically 32K bytes NUL data.
 +		 */
 +		unsigned char *wb;
 +		size_t size, wsize;
 +
 +		size = zisofs->uncompressed_buffer_size;
 +		while (size) {
 +			wb = wb_buffptr(a);
 +			if (size > wb_remaining(a))
 +				wsize = wb_remaining(a);
 +			else
 +				wsize = size;
 +			memset(wb, 0, wsize);
 +			r = wb_consume(a, wsize);
 +			if (r < 0)
 +				return (r);
 +			size -= wsize;
 +		}
 +	} else {
 +		zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;
 +		if (avail > zisofs->block_avail)
 +			zisofs->stream.avail_in = zisofs->block_avail;
 +		else
- 			zisofs->stream.avail_in = avail;
++			zisofs->stream.avail_in = (uInt)avail;
 +		zisofs->stream.next_out = wb_buffptr(a);
- 		zisofs->stream.avail_out = wb_remaining(a);
++		zisofs->stream.avail_out = (uInt)wb_remaining(a);
 +
 +		r = inflate(&zisofs->stream, 0);
 +		switch (r) {
 +		case Z_OK: /* Decompressor made some progress.*/
 +		case Z_STREAM_END: /* Found end of stream. */
 +			break;
 +		default:
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "zisofs decompression failed (%d)", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		avail -= zisofs->stream.next_in - p;
- 		zisofs->block_avail -= zisofs->stream.next_in - p;
++		zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);
 +		r = wb_consume(a, wb_remaining(a) - zisofs->stream.avail_out);
 +		if (r < 0)
 +			return (r);
 +	}
- 	zisofs->pz_offset += bytes;
++	zisofs->pz_offset += (uint32_t)bytes;
 +	return (bytes - avail);
 +}
 +
 +static int
 +zisofs_rewind_boot_file(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +	struct isofile *file;
 +	unsigned char *rbuff;
 +	ssize_t r;
 +	size_t remaining, rbuff_size;
 +	struct zisofs_extract zext;
 +	int64_t read_offset, write_offset, new_offset;
 +	int fd, ret = ARCHIVE_OK;
 +
 +	file = iso9660->el_torito.boot->file;
 +	/*
 +	 * There is nothing to do if this boot file does not have
 +	 * zisofs header.
 +	 */
 +	if (file->zisofs.header_size == 0)
 +		return (ARCHIVE_OK);
 +
 +	/*
 +	 * Uncompress the zisofs'ed file contents.
 +	 */
 +	memset(&zext, 0, sizeof(zext));
 +	zext.pz_uncompressed_size = file->zisofs.uncompressed_size;
 +	zext.pz_log2_bs = file->zisofs.log2_bs;
 +
 +	fd = iso9660->temp_fd;
 +	new_offset = wb_offset(a);
 +	read_offset = file->content.offset_of_temp;
- 	remaining = file->content.size;
++	remaining = (size_t)file->content.size;
 +	if (remaining > 1024 * 32)
 +		rbuff_size = 1024 * 32;
 +	else
 +		rbuff_size = remaining;
 +
 +	rbuff = malloc(rbuff_size);
 +	if (rbuff == NULL) {
 +		archive_set_error(&a->archive, ENOMEM, "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	while (remaining) {
 +		size_t rsize;
 +		ssize_t rs;
 +
 +		/* Get the current file pointer. */
 +		write_offset = lseek(fd, 0, SEEK_CUR);
 +
 +		/* Change the file pointer to read. */
 +		lseek(fd, read_offset, SEEK_SET);
 +
 +		rsize = rbuff_size;
 +		if (rsize > remaining)
 +			rsize = remaining;
 +		rs = read(iso9660->temp_fd, rbuff, rsize);
 +		if (rs <= 0) {
 +			archive_set_error(&a->archive, errno,
 +			    "Can't read temporary file(%jd)", (intmax_t)rs);
 +			ret = ARCHIVE_FATAL;
 +			break;
 +		}
 +		remaining -= rs;
 +		read_offset += rs;
 +
 +		/* Put the file pointer back to write. */
 +		lseek(fd, write_offset, SEEK_SET);
 +
 +		r = zisofs_extract(a, &zext, rbuff, rs);
 +		if (r < 0) {
 +			ret = (int)r;
 +			break;
 +		}
 +	}
 +
 +	if (ret == ARCHIVE_OK) {
 +		/*
 +		 * Change the boot file content from zisofs'ed data
 +		 * to plain data.
 +		 */
 +		file->content.offset_of_temp = new_offset;
 +		file->content.size = file->zisofs.uncompressed_size;
 +		archive_entry_set_size(file->entry, file->content.size);
 +		/* Set to be no zisofs. */
 +		file->zisofs.header_size = 0;
 +		file->zisofs.log2_bs = 0;
 +		file->zisofs.uncompressed_size = 0;
 +		r = wb_write_padding_to_temp(a, file->content.size);
 +		if (r < 0)
 +			ret = ARCHIVE_FATAL;
 +	}
 +
 +	/*
 +	 * Free the resource we used in this function only.
 +	 */
 +	free(rbuff);
 +	free(zext.block_pointers);
 +	if (zext.stream_valid && inflateEnd(&(zext.stream)) != Z_OK) {
 +        	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		ret = ARCHIVE_FATAL;
 +	}
 +
 +	return (ret);
 +}
 +
 +#else
 +
 +static int
 +zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
 +{
 +	(void)buff; /* UNUSED */
 +	(void)s; /* UNUSED */
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Programing error");
 +	return (ARCHIVE_FATAL);
 +}
 +
 +static int
 +zisofs_rewind_boot_file(struct archive_write *a)
 +{
 +	struct iso9660 *iso9660 = a->format_data;
 +
 +	if (iso9660->el_torito.boot->file->zisofs.header_size != 0) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "We cannot extract the zisofs imaged boot file;"
 +		    " this may not boot in being zisofs imaged");
 +		return (ARCHIVE_FAILED);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +zisofs_finish_entry(struct archive_write *a)
 +{
 +	(void)a; /* UNUSED */
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +zisofs_free(struct archive_write *a)
 +{
 +	(void)a; /* UNUSED */
 +	return (ARCHIVE_OK);
 +}
 +
 +#endif /* HAVE_ZLIB_H */
 +
diff --cc Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c
index 4515157,0000000..a4ce7ee
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c
@@@ -1,3171 -1,0 +1,3181 @@@
 +/*-
-  * Copyright (c) 2010-2011 Michihiro NAKAJIMA
++ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD$");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_LIMITS_H
 +#include <limits.h>
 +#endif
 +#include <stdlib.h>
 +#if HAVE_LIBXML_XMLWRITER_H
 +#include <libxml/xmlwriter.h>
 +#endif
 +#ifdef HAVE_BZLIB_H
 +#include <cm_bzlib.h>
 +#endif
 +#if HAVE_LZMA_H
 +#include <lzma.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_crypto_private.h"
 +#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_private.h"
 +#include "archive_rb.h"
 +#include "archive_string.h"
 +#include "archive_write_private.h"
 +
 +/*
 + * Differences to xar utility.
 + * - Subdocument is not supported yet.
 + * - ACL is not supported yet.
 + * - When writing an XML element <link type="<file-type>">, <file-type>
 + *   which is a file type a symbolic link is referencing is always marked
 + *   as "broken". Xar utility uses stat(2) to get the file type, but, in
 + *   libarcive format writer, we should not use it; if it is needed, we
 + *   should get about it at archive_read_disk.c.
 + * - It is possible to appear both <flags> and <ext2> elements.
 + *   Xar utility generates <flags> on BSD platform and <ext2> on Linux
 + *   platform.
 + *
 + */
 +
 +#if !(defined(HAVE_LIBXML_XMLWRITER_H) && defined(LIBXML_VERSION) &&\
 +	LIBXML_VERSION >= 20703) ||\
 +	!defined(HAVE_ZLIB_H) || \
 +	!defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
 +/*
 + * xar needs several external libraries.
 + *   o libxml2
 + *   o openssl or MD5/SHA1 hash function
 + *   o zlib
 + *   o bzlib2 (option)
 + *   o liblzma (option)
 + */
 +int
 +archive_write_set_format_xar(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +
 +	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +	    "Xar not supported on this platform");
 +	return (ARCHIVE_WARN);
 +}
 +
 +#else	/* Support xar format */
 +
 +/*#define DEBUG_PRINT_TOC		1 */
 +
++#define BAD_CAST_CONST (const xmlChar *)
++
 +#define HEADER_MAGIC	0x78617221
 +#define HEADER_SIZE	28
 +#define HEADER_VERSION	1
 +
 +enum sumalg {
 +	CKSUM_NONE = 0,
 +	CKSUM_SHA1 = 1,
 +	CKSUM_MD5 = 2
 +};
 +
 +#define MD5_SIZE	16
 +#define SHA1_SIZE	20
 +#define MAX_SUM_SIZE	20
 +#define MD5_NAME	"md5"
 +#define SHA1_NAME	"sha1"
 + 
 +enum enctype {
 +	NONE,
 +	GZIP,
 +	BZIP2,
 +	LZMA,
 +	XZ,
 +};
 +
 +struct chksumwork {
 +	enum sumalg		 alg;
 +#ifdef ARCHIVE_HAS_MD5
 +	archive_md5_ctx		 md5ctx;
 +#endif
 +#ifdef ARCHIVE_HAS_SHA1
 +	archive_sha1_ctx	 sha1ctx;
 +#endif
 +};
 +
 +enum la_zaction {
 +	ARCHIVE_Z_FINISH,
 +	ARCHIVE_Z_RUN
 +};
 +
 +/*
 + * Universal zstream.
 + */
 +struct la_zstream {
 +	const unsigned char	*next_in;
 +	size_t			 avail_in;
 +	uint64_t		 total_in;
 +
 +	unsigned char		*next_out;
 +	size_t			 avail_out;
 +	uint64_t		 total_out;
 +
 +	int			 valid;
 +	void			*real_stream;
 +	int			 (*code) (struct archive *a,
 +				    struct la_zstream *lastrm,
 +				    enum la_zaction action);
 +	int			 (*end)(struct archive *a,
 +				    struct la_zstream *lastrm);
 +};
 +
 +struct chksumval {
 +	enum sumalg		 alg;
 +	size_t			 len;
 +	unsigned char		 val[MAX_SUM_SIZE];
 +};
 +
 +struct heap_data {
 +	int			 id;
 +	struct heap_data	*next;
 +	uint64_t		 temp_offset;
 +	uint64_t		 length;	/* archived size.	*/
 +	uint64_t		 size;		/* extracted size.	*/
 +	enum enctype		 compression;
 +	struct chksumval	 a_sum;		/* archived checksum.	*/
 +	struct chksumval	 e_sum;		/* extracted checksum.	*/
 +};
 +
 +struct file {
 +	struct archive_rb_node	 rbnode;
 +
 +	int			 id;
 +	struct archive_entry	*entry;
 +
 +	struct archive_rb_tree	 rbtree;
 +	struct file		*next;
 +	struct file		*chnext;
 +	struct file		*hlnext;
 +	/* For hardlinked files.
 +	 * Use only when archive_entry_nlink() > 1 */
 +	struct file		*hardlink_target;
 +	struct file		*parent;	/* parent directory entry */
 +	/*
 +	 * To manage sub directory files.
 +	 * We use 'chnext' a menber of struct file to chain.
 +	 */
 +	struct {
 +		struct file	*first;
 +		struct file	**last;
 +	}			 children;
 +
 +	/* For making a directory tree. */
 +        struct archive_string    parentdir;
 +        struct archive_string    basename;
 +        struct archive_string    symlink;
 +
 +	int			 ea_idx;
 +	struct {
 +		struct heap_data *first;
 +		struct heap_data **last;
 +	}			 xattr;
 +	struct heap_data	 data;
 +        struct archive_string    script;
 +
 +	int			 virtual:1;
 +	int			 dir:1;
 +};
 +
 +struct hardlink {
 +	struct archive_rb_node	 rbnode;
 +	int			 nlink;
 +	struct {
 +		struct file	*first;
 +		struct file	**last;
 +	}			 file_list;
 +};
 +
 +struct xar {
 +	int			 temp_fd;
 +	uint64_t		 temp_offset;
 +
 +	int			 file_idx;
 +	struct file		*root;
 +	struct file		*cur_dirent;
 +	struct archive_string	 cur_dirstr;
 +	struct file		*cur_file;
 +	uint64_t		 bytes_remaining;
 +	struct archive_string	 tstr;
 +	struct archive_string	 vstr;
 +
 +	enum sumalg		 opt_toc_sumalg;
 +	enum sumalg		 opt_sumalg;
 +	enum enctype		 opt_compression;
 +	int			 opt_compression_level;
 +
 +	struct chksumwork	 a_sumwrk;	/* archived checksum.	*/
 +	struct chksumwork	 e_sumwrk;	/* extracted checksum.	*/
 +	struct la_zstream	 stream;
 +	struct archive_string_conv *sconv;
 +	/*
 +	 * Compressed data buffer.
 +	 */
 +	unsigned char		 wbuff[1024 * 64];
 +	size_t			 wbuff_remaining;
 +
 +	struct heap_data	 toc;
 +	/*
 +	 * The list of all file entries is used to manage struct file
 +	 * objects.
 +	 * We use 'next' a menber of struct file to chain.
 +	 */
 +	struct {
 +		struct file	*first;
 +		struct file	**last;
 +	}			 file_list;
 +	/*
 +	 * The list of hard-linked file entries.
 +	 * We use 'hlnext' a menber of struct file to chain.
 +	 */
 +	struct archive_rb_tree	 hardlink_rbtree;
 +};
 +
 +static int	xar_options(struct archive_write *,
 +		    const char *, const char *);
 +static int	xar_write_header(struct archive_write *,
 +		    struct archive_entry *);
 +static ssize_t	xar_write_data(struct archive_write *,
 +		    const void *, size_t);
 +static int	xar_finish_entry(struct archive_write *);
 +static int	xar_close(struct archive_write *);
 +static int	xar_free(struct archive_write *);
 +
 +static struct file *file_new(struct archive_write *a, struct archive_entry *);
 +static void	file_free(struct file *);
 +static struct file *file_create_virtual_dir(struct archive_write *a, struct xar *,
 +		    const char *);
 +static int	file_add_child_tail(struct file *, struct file *);
 +static struct file *file_find_child(struct file *, const char *);
 +static int	file_gen_utility_names(struct archive_write *,
 +		    struct file *);
 +static int	get_path_component(char *, int, const char *);
 +static int	file_tree(struct archive_write *, struct file **);
 +static void	file_register(struct xar *, struct file *);
 +static void	file_init_register(struct xar *);
 +static void	file_free_register(struct xar *);
 +static int	file_register_hardlink(struct archive_write *,
 +		    struct file *);
 +static void	file_connect_hardlink_files(struct xar *);
 +static void	file_init_hardlinks(struct xar *);
 +static void	file_free_hardlinks(struct xar *);
 +
 +static void	checksum_init(struct chksumwork *, enum sumalg);
 +static void	checksum_update(struct chksumwork *, const void *, size_t);
 +static void	checksum_final(struct chksumwork *, struct chksumval *);
 +static int	compression_init_encoder_gzip(struct archive *,
 +		    struct la_zstream *, int, int);
 +static int	compression_code_gzip(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_gzip(struct archive *, struct la_zstream *);
 +static int	compression_init_encoder_bzip2(struct archive *,
 +		    struct la_zstream *, int);
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +static int	compression_code_bzip2(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_bzip2(struct archive *, struct la_zstream *);
 +#endif
 +static int	compression_init_encoder_lzma(struct archive *,
 +		    struct la_zstream *, int);
 +static int	compression_init_encoder_xz(struct archive *,
 +		    struct la_zstream *, int);
 +#if defined(HAVE_LZMA_H)
 +static int	compression_code_lzma(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end_lzma(struct archive *, struct la_zstream *);
 +#endif
 +static int	xar_compression_init_encoder(struct archive_write *);
 +static int	compression_code(struct archive *,
 +		    struct la_zstream *, enum la_zaction);
 +static int	compression_end(struct archive *,
 +		    struct la_zstream *);
 +static int	save_xattrs(struct archive_write *, struct file *);
 +static int	getalgsize(enum sumalg);
 +static const char *getalgname(enum sumalg);
 +
 +int
 +archive_write_set_format_xar(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct xar *xar;
 +
 +	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_set_format_xar");
 +
 +	/* If another format was already registered, unregister it. */
 +	if (a->format_free != NULL)
 +		(a->format_free)(a);
 +
 +	xar = calloc(1, sizeof(*xar));
 +	if (xar == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate xar data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	xar->temp_fd = -1;
 +	file_init_register(xar);
 +	file_init_hardlinks(xar);
 +	archive_string_init(&(xar->tstr));
 +	archive_string_init(&(xar->vstr));
 +
 +	/*
 +	 * Create the root directory.
 +	 */
 +	xar->root = file_create_virtual_dir(a, xar, "");
 +	if (xar->root == NULL) {
 +		free(xar);
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate xar data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	xar->root->parent = xar->root;
 +	file_register(xar, xar->root);
 +	xar->cur_dirent = xar->root;
 +	archive_string_init(&(xar->cur_dirstr));
 +	archive_string_ensure(&(xar->cur_dirstr), 1);
 +	xar->cur_dirstr.s[0] = 0;
 +
 +	/*
 +	 * Initialize option.
 +	 */
 +	/* Set default checksum type. */
 +	xar->opt_toc_sumalg = CKSUM_SHA1;
 +	xar->opt_sumalg = CKSUM_SHA1;
 +	/* Set default compression type and level. */
 +	xar->opt_compression = GZIP;
 +	xar->opt_compression_level = 6;
 +
 +	a->format_data = xar;
 +
 +	a->format_name = "xar";
 +	a->format_options = xar_options;
 +	a->format_write_header = xar_write_header;
 +	a->format_write_data = xar_write_data;
 +	a->format_finish_entry = xar_finish_entry;
 +	a->format_close = xar_close;
 +	a->format_free = xar_free;
 +	a->archive.archive_format = ARCHIVE_FORMAT_XAR;
 +	a->archive.archive_format_name = "xar";
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xar_options(struct archive_write *a, const char *key, const char *value)
 +{
 +	struct xar *xar;
 +
 +	xar = (struct xar *)a->format_data;
 +
 +	if (strcmp(key, "checksum") == 0) {
 +		if (value == NULL)
 +			xar->opt_sumalg = CKSUM_NONE;
 +		else if (strcmp(value, "sha1") == 0)
 +			xar->opt_sumalg = CKSUM_SHA1;
 +		else if (strcmp(value, "md5") == 0)
 +			xar->opt_sumalg = CKSUM_MD5;
 +		else {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Unknown checksum name: `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +	if (strcmp(key, "compression") == 0) {
 +		const char *name = NULL;
 +
 +		if (value == NULL)
 +			xar->opt_compression = NONE;
 +		else if (strcmp(value, "gzip") == 0)
 +			xar->opt_compression = GZIP;
 +		else if (strcmp(value, "bzip2") == 0)
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +			xar->opt_compression = BZIP2;
 +#else
 +			name = "bzip2";
 +#endif
 +		else if (strcmp(value, "lzma") == 0)
 +#if HAVE_LZMA_H
 +			xar->opt_compression = LZMA;
 +#else
 +			name = "lzma";
 +#endif
 +		else if (strcmp(value, "xz") == 0)
 +#if HAVE_LZMA_H
 +			xar->opt_compression = XZ;
 +#else
 +			name = "xz";
 +#endif
 +		else {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Unknown compression name: `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		if (name != NULL) {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "`%s' compression not supported "
 +			    "on this platform",
 +			    name);
 +			return (ARCHIVE_FAILED);
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +	if (strcmp(key, "compression-level") == 0) {
 +		if (value == NULL ||
 +		    !(value[0] >= '0' && value[0] <= '9') ||
 +		    value[1] != '\0') {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
- 			    "Illeagal value `%s'",
++			    "Illegal value `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		xar->opt_compression_level = value[0] - '0';
 +		return (ARCHIVE_OK);
 +	}
 +	if (strcmp(key, "toc-checksum") == 0) {
 +		if (value == NULL)
 +			xar->opt_toc_sumalg = CKSUM_NONE;
 +		else if (strcmp(value, "sha1") == 0)
 +			xar->opt_toc_sumalg = CKSUM_SHA1;
 +		else if (strcmp(value, "md5") == 0)
 +			xar->opt_toc_sumalg = CKSUM_MD5;
 +		else {
 +			archive_set_error(&(a->archive),
 +			    ARCHIVE_ERRNO_MISC,
 +			    "Unknown checksum name: `%s'",
 +			    value);
 +			return (ARCHIVE_FAILED);
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +
- 	return (ARCHIVE_FAILED);
++	/* Note: The "warn" return is just to inform the options
++	 * supervisor that we didn't handle it.  It will generate
++	 * a suitable error if no one used this option. */
++	return (ARCHIVE_WARN);
 +}
 +
 +static int
 +xar_write_header(struct archive_write *a, struct archive_entry *entry)
 +{
 +	struct xar *xar;
 +	struct file *file;
 +	struct archive_entry *file_entry;
 +	int r, r2;
 +
 +	xar = (struct xar *)a->format_data;
 +	xar->cur_file = NULL;
 +	xar->bytes_remaining = 0;
 +
 +	if (xar->sconv == NULL) {
 +		xar->sconv = archive_string_conversion_to_charset(
 +		    &a->archive, "UTF-8", 1);
 +		if (xar->sconv == NULL)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	file = file_new(a, entry);
 +	if (file == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	r2 = file_gen_utility_names(a, file);
 +	if (r2 < ARCHIVE_WARN)
 +		return (r2);
 +
 +	/*
 +	 * Ignore a path which looks like the top of directory name
 +	 * since we have already made the root directory of an Xar archive.
 +	 */
 +	if (archive_strlen(&(file->parentdir)) == 0 &&
 +	    archive_strlen(&(file->basename)) == 0) {
 +		file_free(file);
 +		return (r2);
 +	}
 +
 +	/* Add entry into tree */
 +	file_entry = file->entry;
 +	r = file_tree(a, &file);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/* There is the same file in tree and
 +	 * the current file is older than the file in tree.
 +	 * So we don't need the current file data anymore. */
 +	if (file->entry != file_entry)
 +		return (r2);
 +	if (file->id == 0)
 +		file_register(xar, file);
 +
 +	/* A virtual file, which is a directory, does not have
 +	 * any contents and we won't store it into a archive
 +	 * file other than its name. */
 +	if (file->virtual)
 +		return (r2);
 +
 +	/*
 +	 * Prepare to save the contents of the file.
 +	 */
 +	if (xar->temp_fd == -1) {
 +		int algsize;
 +		xar->temp_offset = 0;
 +		xar->temp_fd = __archive_mktemp(NULL);
 +		if (xar->temp_fd < 0) {
 +			archive_set_error(&a->archive, errno,
 +			    "Couldn't create temporary file");
 +			return (ARCHIVE_FATAL);
 +		}
 +		algsize = getalgsize(xar->opt_toc_sumalg);
 +		if (algsize > 0) {
 +			if (lseek(xar->temp_fd, algsize, SEEK_SET) < 0) {
 +				archive_set_error(&(a->archive), errno,
 +				    "lseek failed");
 +				return (ARCHIVE_FATAL);
 +			}
 +			xar->temp_offset = algsize;
 +		}
 +	}
 +
 +	if (archive_entry_hardlink(file->entry) == NULL) {
 +		r = save_xattrs(a, file);
 +		if (r != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/* Non regular files contents are unneeded to be saved to
 +	 * a temporary file. */
 +	if (archive_entry_filetype(file->entry) != AE_IFREG)
 +		return (r2);
 +
 +	/*
 +	 * Set the current file to cur_file to read its contents.
 +	 */
 +	xar->cur_file = file;
 +
 +	if (archive_entry_nlink(file->entry) > 1) {
 +		r = file_register_hardlink(a, file);
 +		if (r != ARCHIVE_OK)
 +			return (r);
 +		if (archive_entry_hardlink(file->entry) != NULL) {
 +			archive_entry_unset_size(file->entry);
 +			return (r2);
 +		}
 +	}
 +
 +	/* Save a offset of current file in temporary file. */
 +	file->data.temp_offset = xar->temp_offset;
 +	file->data.size = archive_entry_size(file->entry);
 +	file->data.compression = xar->opt_compression;
 +	xar->bytes_remaining = archive_entry_size(file->entry);
 +	checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
 +	checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
 +	r = xar_compression_init_encoder(a);
 +
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	else
 +		return (r2);
 +}
 +
 +static int
 +write_to_temp(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct xar *xar;
- 	unsigned char *p;
++	const unsigned char *p;
 +	ssize_t ws;
 +
 +	xar = (struct xar *)a->format_data;
- 	p = (unsigned char *)buff;
++	p = (const unsigned char *)buff;
 +	while (s) {
 +		ws = write(xar->temp_fd, p, s);
 +		if (ws < 0) {
 +			archive_set_error(&(a->archive), errno,
 +			    "fwrite function failed");
 +			return (ARCHIVE_FATAL);
 +		}
 +		s -= ws;
 +		p += ws;
 +		xar->temp_offset += ws;
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static ssize_t
 +xar_write_data(struct archive_write *a, const void *buff, size_t s)
 +{
 +	struct xar *xar;
 +	enum la_zaction run;
 +	size_t size, rsize;
 +	int r;
 +
 +	xar = (struct xar *)a->format_data;
 +
 +	if (s > xar->bytes_remaining)
- 		s = xar->bytes_remaining;
++		s = (size_t)xar->bytes_remaining;
 +	if (s == 0 || xar->cur_file == NULL)
 +		return (0);
 +	if (xar->cur_file->data.compression == NONE) {
 +		checksum_update(&(xar->e_sumwrk), buff, s);
 +		checksum_update(&(xar->a_sumwrk), buff, s);
 +		size = rsize = s;
 +	} else {
 +		xar->stream.next_in = (const unsigned char *)buff;
 +		xar->stream.avail_in = s;
 +		if (xar->bytes_remaining > s)
 +			run = ARCHIVE_Z_RUN;
 +		else
 +			run = ARCHIVE_Z_FINISH;
 +		/* Compress file data. */
 +		r = compression_code(&(a->archive), &(xar->stream), run);
 +		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
 +			return (ARCHIVE_FATAL);
 +		rsize = s - xar->stream.avail_in;
 +		checksum_update(&(xar->e_sumwrk), buff, rsize);
 +		size = sizeof(xar->wbuff) - xar->stream.avail_out;
 +		checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
 +	}
 +#if !defined(_WIN32) || defined(__CYGWIN__)
 +	if (xar->bytes_remaining ==
- 	    archive_entry_size(xar->cur_file->entry)) {
++	    (uint64_t)archive_entry_size(xar->cur_file->entry)) {
 +		/*
 +		 * Get the path of a shell script if so.
 +		 */
 +		const unsigned char *b = (const unsigned char *)buff;
 +
 +		archive_string_empty(&(xar->cur_file->script));
 +		if (rsize > 2 && b[0] == '#' && b[1] == '!') {
 +			size_t i, end, off;
 +
 +			off = 2;
 +			if (b[off] == ' ')
 +				off++;
 +#ifdef PATH_MAX
 +			if ((rsize - off) > PATH_MAX)
 +				end = off + PATH_MAX;
 +			else
 +#endif
 +				end = rsize;
 +			/* Find the end of a script path. */
 +			for (i = off; i < end && b[i] != '\0' &&
 +			    b[i] != '\n' && b[i] != '\r' &&
 +			    b[i] != ' ' && b[i] != '\t'; i++)
 +				;
 +			archive_strncpy(&(xar->cur_file->script), b + off,
 +			    i - off);
 +		}
 +	}
 +#endif
 +
 +	if (xar->cur_file->data.compression == NONE) {
 +		if (write_to_temp(a, buff, size) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	} else {
 +		if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +	xar->bytes_remaining -= rsize;
 +	xar->cur_file->data.length += size;
 +
 +	return (rsize);
 +}
 +
 +static int
 +xar_finish_entry(struct archive_write *a)
 +{
 +	struct xar *xar;
 +	struct file *file;
 +	size_t s;
 +	ssize_t w;
 +
 +	xar = (struct xar *)a->format_data;
 +	if (xar->cur_file == NULL)
 +		return (ARCHIVE_OK);
 +
 +	while (xar->bytes_remaining > 0) {
- 		s = xar->bytes_remaining;
++		s = (size_t)xar->bytes_remaining;
 +		if (s > a->null_length)
 +			s = a->null_length;
 +		w = xar_write_data(a, a->nulls, s);
 +		if (w > 0)
 +			xar->bytes_remaining -= w;
 +		else
 +			return (w);
 +	}
 +	file = xar->cur_file;
 +	checksum_final(&(xar->e_sumwrk), &(file->data.e_sum));
 +	checksum_final(&(xar->a_sumwrk), &(file->data.a_sum));
 +	xar->cur_file = NULL;
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, const char *value,
 +	const char *attrkey, const char *attrvalue)
 +{
 +	int r;
 +
- 	r = xmlTextWriterStartElement(writer, BAD_CAST(key));
++	r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterStartElement() failed: %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (attrkey != NULL && attrvalue != NULL) {
 +		r = xmlTextWriterWriteAttribute(writer,
- 		    BAD_CAST(attrkey), BAD_CAST(attrvalue));
++		    BAD_CAST_CONST(attrkey), BAD_CAST_CONST(attrvalue));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteAttribute() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +	if (value != NULL) {
- 		r = xmlTextWriterWriteString(writer, BAD_CAST(value));
++		r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteString() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +	r = xmlTextWriterEndElement(writer);
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterEndElement() failed: %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, const char *value)
 +{
 +	int r;
 +
 +	if (value == NULL)
 +		return (ARCHIVE_OK);
 +	
- 	r = xmlTextWriterStartElement(writer, BAD_CAST(key));
++	r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterStartElement() failed: %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +	if (value != NULL) {
- 		r = xmlTextWriterWriteString(writer, BAD_CAST(value));
++		r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteString() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +	r = xmlTextWriterEndElement(writer);
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterEndElement() failed: %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xmlwrite_fstring(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, const char *fmt, ...)
 +{
 +	struct xar *xar;
 +	va_list ap;
 +
 +	xar = (struct xar *)a->format_data;
 +	va_start(ap, fmt);
 +	archive_string_empty(&xar->vstr);
 +	archive_string_vsprintf(&xar->vstr, fmt, ap);
 +	va_end(ap);
 +	return (xmlwrite_string(a, writer, key, xar->vstr.s));
 +}
 +
 +static int
 +xmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, time_t t, int z)
 +{
 +	char timestr[100];
 +	struct tm tm;
 +
 +#if defined(HAVE_GMTIME_R)
 +	gmtime_r(&t, &tm);
 +#elif defined(HAVE__GMTIME64_S)
 +	_gmtime64_s(&tm, &t);
 +#else
 +	memcpy(&tm, gmtime(&t), sizeof(tm));
 +#endif
 +	memset(&timestr, 0, sizeof(timestr));
 +	/* Do not use %F and %T for portability. */
 +	strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S", &tm);
 +	if (z)
 +		strcat(timestr, "Z");
 +	return (xmlwrite_string(a, writer, key, timestr));
 +}
 +
 +static int
 +xmlwrite_mode(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, mode_t mode)
 +{
 +	char ms[5];
 +
 +	ms[0] = '0';
 +	ms[1] = '0' + ((mode >> 6) & 07);
 +	ms[2] = '0' + ((mode >> 3) & 07);
 +	ms[3] = '0' + (mode & 07);
 +	ms[4] = '\0';
 +
 +	return (xmlwrite_string(a, writer, key, ms));
 +}
 +
 +static int
 +xmlwrite_sum(struct archive_write *a, xmlTextWriterPtr writer,
 +	const char *key, struct chksumval *sum)
 +{
 +	const char *algname;
 +	int algsize;
 +	char buff[MAX_SUM_SIZE*2 + 1];
 +	char *p;
 +	unsigned char *s;
 +	int i, r;
 +
 +	if (sum->len > 0) {
 +		algname = getalgname(sum->alg);
 +		algsize = getalgsize(sum->alg);
 +		if (algname != NULL) {
 +			const char *hex = "0123456789abcdef";
 +			p = buff;
 +			s = sum->val;
 +			for (i = 0; i < algsize; i++) {
 +				*p++ = hex[(*s >> 4)];
 +				*p++ = hex[(*s & 0x0f)];
 +				s++;
 +			}
 +			*p = '\0';
 +			r = xmlwrite_string_attr(a, writer,
 +			    key, buff,
 +			    "style", algname);
 +			if (r < 0)
 +				return (ARCHIVE_FATAL);
 +		}
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xmlwrite_heap(struct archive_write *a, xmlTextWriterPtr writer,
 +	struct heap_data *heap)
 +{
 +	const char *encname;
 +	int r;
 +
 +	r = xmlwrite_fstring(a, writer, "length", "%ju", heap->length);
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = xmlwrite_fstring(a, writer, "offset", "%ju", heap->temp_offset);
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = xmlwrite_fstring(a, writer, "size", "%ju", heap->size);
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	switch (heap->compression) {
 +	case GZIP:
 +		encname = "application/x-gzip"; break;
 +	case BZIP2:
 +		encname = "application/x-bzip2"; break;
 +	case LZMA:
 +		encname = "application/x-lzma"; break;
 +	case XZ:
 +		encname = "application/x-xz"; break;
 +	default:
 +		encname = "application/octet-stream"; break;
 +	}
 +	r = xmlwrite_string_attr(a, writer, "encoding", NULL,
 +	    "style", encname);
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = xmlwrite_sum(a, writer, "archived-checksum", &(heap->a_sum));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = xmlwrite_sum(a, writer, "extracted-checksum", &(heap->e_sum));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * xar utility records fflags as following xml elements:
 + *   <flags>
 + *     <UserNoDump/>
 + *     .....
 + *   </flags>
 + * or
 + *   <ext2>
 + *     <NoDump/>
 + *     .....
 + *   </ext2>
 + * If xar is running on BSD platform, records <flags>..</flags>;
 + * if xar is running on linux platform, records <ext2>..</ext2>;
 + * otherwise does not record.
 + *
 + * Our implements records both <flags> and <ext2> if it's necessary.
 + */
 +static int
 +make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer,
 +    const char *element, const char *fflags_text)
 +{
 +	static const struct flagentry {
 +		const char	*name;
 +		const char	*xarname;
 +	}
 +	flagbsd[] = {
 +		{ "sappnd",	"SystemAppend"},
 +		{ "sappend",	"SystemAppend"},
 +		{ "arch",	"SystemArchived"},
 +		{ "archived",	"SystemArchived"},
 +		{ "schg",	"SystemImmutable"},
 +		{ "schange",	"SystemImmutable"},
 +		{ "simmutable",	"SystemImmutable"},
 +		{ "nosunlnk",	"SystemNoUnlink"},
 +		{ "nosunlink",	"SystemNoUnlink"},
 +		{ "snapshot",	"SystemSnapshot"},
 +		{ "uappnd",	"UserAppend"},
 +		{ "uappend",	"UserAppend"},
 +		{ "uchg",	"UserImmutable"},
 +		{ "uchange",	"UserImmutable"},
 +		{ "uimmutable",	"UserImmutable"},
 +		{ "nodump",	"UserNoDump"},
 +		{ "noopaque",	"UserOpaque"},
 +		{ "nouunlnk",	"UserNoUnlink"},
 +		{ "nouunlink",	"UserNoUnlink"},
 +		{ NULL, NULL}
 +	},
 +	flagext2[] = {
 +		{ "sappnd",	"AppendOnly"},
 +		{ "sappend",	"AppendOnly"},
 +		{ "schg",	"Immutable"},
 +		{ "schange",	"Immutable"},
 +		{ "simmutable",	"Immutable"},
 +		{ "nodump",	"NoDump"},
 +		{ "nouunlnk",	"Undelete"},
 +		{ "nouunlink",	"Undelete"},
 +		{ "btree",	"BTree"},
 +		{ "comperr",	"CompError"},
 +		{ "compress",	"Compress"},
 +		{ "noatime",	"NoAtime"},
 +		{ "compdirty",	"CompDirty"},
 +		{ "comprblk",	"CompBlock"},
 +		{ "dirsync",	"DirSync"},
 +		{ "hashidx",	"HashIndexed"},
 +		{ "imagic",	"iMagic"},
 +		{ "journal",	"Journaled"},
 +		{ "securedeletion",	"SecureDeletion"},
 +		{ "sync",	"Synchronous"},
 +		{ "notail",	"NoTail"},
 +		{ "topdir",	"TopDir"},
 +		{ "reserved",	"Reserved"},
 +		{ NULL, NULL}
 +	};
 +	const struct flagentry *fe, *flagentry;
 +#define FLAGENTRY_MAXSIZE ((sizeof(flagbsd)+sizeof(flagext2))/sizeof(flagbsd))
 +	const struct flagentry *avail[FLAGENTRY_MAXSIZE];
 +	const char *p;
 +	int i, n, r;
 +
 +	if (strcmp(element, "ext2") == 0)
 +		flagentry = flagext2;
 +	else
 +		flagentry = flagbsd;
 +	n = 0;
 +	p = fflags_text;
 +	do {
 +		const char *cp;
 +
 +		cp = strchr(p, ',');
 +		if (cp == NULL)
 +			cp = p + strlen(p);
 +
 +		for (fe = flagentry; fe->name != NULL; fe++) {
 +			if (fe->name[cp - p] != '\0'
 +			    || p[0] != fe->name[0])
 +				continue;
 +			if (strncmp(p, fe->name, cp - p) == 0) {
 +				avail[n++] = fe;
 +				break;
 +			}
 +		}
 +		if (*cp == ',')
 +			p = cp + 1;
 +		else
 +			p = NULL;
 +	} while (p != NULL);
 +
 +	if (n > 0) {
- 		r = xmlTextWriterStartElement(writer, BAD_CAST(element));
++		r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(element));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		for (i = 0; i < n; i++) {
 +			r = xmlwrite_string(a, writer,
 +			    avail[i]->xarname, NULL);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +		}
 +
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +make_file_entry(struct archive_write *a, xmlTextWriterPtr writer,
 +    struct file *file)
 +{
 +	struct xar *xar;
 +	const char *filetype, *filelink, *fflags;
 +	struct archive_string linkto;
 +	struct heap_data *heap;
 +	unsigned char *tmp;
 +	const char *p;
 +	size_t len;
 +	int r, r2, l, ll;
 +
 +	xar = (struct xar *)a->format_data;
 +	r2 = ARCHIVE_OK;
 +
 +	/*
 +	 * Make a file name entry, "<name>".
 +	 */
 +	l = ll = archive_strlen(&(file->basename));
 +	tmp = malloc(l);
 +	if (tmp == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate memory");
 +		return (ARCHIVE_FATAL);
 +	}
 +	r = UTF8Toisolat1(tmp, &l, BAD_CAST(file->basename.s), &ll);
 +	free(tmp);
 +	if (r < 0) {
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("name"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlTextWriterWriteAttribute(writer,
 +		    BAD_CAST("enctype"), BAD_CAST("base64"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteAttribute() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlTextWriterWriteBase64(writer, file->basename.s,
 +		    0, archive_strlen(&(file->basename)));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteBase64() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	} else {
 +		r = xmlwrite_string(a, writer, "name", file->basename.s);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a file type entry, "<type>".
 +	 */
 +	filelink = NULL;
 +	archive_string_init(&linkto);
 +	switch (archive_entry_filetype(file->entry)) {
 +	case AE_IFDIR:
 +		filetype = "directory"; break;
 +	case AE_IFLNK:
 +		filetype = "symlink"; break;
 +	case AE_IFCHR:
 +		filetype = "character special"; break;
 +	case AE_IFBLK:
 +		filetype = "block special"; break;
 +	case AE_IFSOCK:
 +		filetype = "socket"; break;
 +	case AE_IFIFO:
 +		filetype = "fifo"; break;
 +	case AE_IFREG:
 +	default:
 +		if (file->hardlink_target != NULL) {
 +			filetype = "hardlink";
 +			filelink = "link";
 +			if (file->hardlink_target == file)
 +				archive_strcpy(&linkto, "original");
 +			else
 +				archive_string_sprintf(&linkto, "%d",
 +				    file->hardlink_target->id);
 +		} else
 +			filetype = "file";
 +		break;
 +	}
 +	r = xmlwrite_string_attr(a, writer, "type", filetype,
 +	    filelink, linkto.s);
 +	archive_string_free(&linkto);
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +
 +	/*
 +	 * On a virtual directory, we record "name" and "type" only.
 +	 */
 +	if (file->virtual)
 +		return (ARCHIVE_OK);
 +
 +	switch (archive_entry_filetype(file->entry)) {
 +	case AE_IFLNK:
 +		/*
 +		 * xar utility has checked a file type, which
 +		 * a symblic-link file has referenced.
 +		 * For example:
 +		 *   <link type="directory">../ref/</link>
 +		 *   The symlink target file is "../ref/" and its
 +		 *   file type is a directory.
 +		 *
 +		 *   <link type="file">../f</link>
 +		 *   The symlink target file is "../f" and its
 +		 *   file type is a regular file.
 +		 *
 +		 * But our implemention cannot do it, and then we
 +		 * always record that a attribute "type" is "borken",
 +		 * for example:
 +		 *   <link type="broken">foo/bar</link>
 +		 *   It means "foo/bar" is not reachable.
 +		 */
 +		r = xmlwrite_string_attr(a, writer, "link",
 +		    file->symlink.s,
 +		    "type", "broken");
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +		break;
 +	case AE_IFCHR:
 +	case AE_IFBLK:
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("device"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlwrite_fstring(a, writer, "major",
 +		    "%d", archive_entry_rdevmajor(file->entry));
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +		r = xmlwrite_fstring(a, writer, "minor",
 +		    "%d", archive_entry_rdevminor(file->entry));
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		break;
 +	default:
 +		break;
 +	}
 +
 +	/*
 +	 * Make a inode entry, "<inode>".
 +	 */
 +	r = xmlwrite_fstring(a, writer, "inode",
 +	    "%jd", archive_entry_ino64(file->entry));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	if (archive_entry_dev(file->entry) != 0) {
 +		r = xmlwrite_fstring(a, writer, "deviceno",
 +		    "%d", archive_entry_dev(file->entry));
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a file mode entry, "<mode>".
 +	 */
 +	r = xmlwrite_mode(a, writer, "mode",
 +	    archive_entry_mode(file->entry));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +
 +	/*
 +	 * Make a user entry, "<uid>" and "<user>.
 +	 */
 +	r = xmlwrite_fstring(a, writer, "uid",
 +	    "%d", archive_entry_uid(file->entry));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = archive_entry_uname_l(file->entry, &p, &len, xar->sconv);
 +	if (r != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Uname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Can't translate uname '%s' to UTF-8",
 +		    archive_entry_uname(file->entry));
 +		r2 = ARCHIVE_WARN;
 +	}
 +	if (len > 0) {
 +		r = xmlwrite_string(a, writer, "user", p);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a group entry, "<gid>" and "<group>.
 +	 */
 +	r = xmlwrite_fstring(a, writer, "gid",
 +	    "%d", archive_entry_gid(file->entry));
 +	if (r < 0)
 +		return (ARCHIVE_FATAL);
 +	r = archive_entry_gname_l(file->entry, &p, &len, xar->sconv);
 +	if (r != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Gname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Can't translate gname '%s' to UTF-8",
 +		    archive_entry_gname(file->entry));
 +		r2 = ARCHIVE_WARN;
 +	}
 +	if (len > 0) {
 +		r = xmlwrite_string(a, writer, "group", p);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a ctime entry, "<ctime>".
 +	 */
 +	if (archive_entry_ctime_is_set(file->entry)) {
 +		r = xmlwrite_time(a, writer, "ctime",
 +		    archive_entry_ctime(file->entry), 1);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a mtime entry, "<mtime>".
 +	 */
 +	if (archive_entry_mtime_is_set(file->entry)) {
 +		r = xmlwrite_time(a, writer, "mtime",
 +		    archive_entry_mtime(file->entry), 1);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make a atime entry, "<atime>".
 +	 */
 +	if (archive_entry_atime_is_set(file->entry)) {
 +		r = xmlwrite_time(a, writer, "atime",
 +		    archive_entry_atime(file->entry), 1);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +	}
 +
 +	/*
 +	 * Make fflags entries, "<flags>" and "<ext2>".
 +	 */
 +	fflags = archive_entry_fflags_text(file->entry);
 +	if (fflags != NULL) {
 +		r = make_fflags_entry(a, writer, "flags", fflags);
 +		if (r < 0)
 +			return (r);
 +		r = make_fflags_entry(a, writer, "ext2", fflags);
 +		if (r < 0)
 +			return (r);
 +	}
 +
 +	/*
 +	 * Make extended attribute entries, "<ea>".
 +	 */
 +	archive_entry_xattr_reset(file->entry);
 +	for (heap = file->xattr.first; heap != NULL; heap = heap->next) {
 +		const char *name;
 +		const void *value;
 +		size_t size;
 +
 +		archive_entry_xattr_next(file->entry,
 +		    &name, &value, &size);
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("ea"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlTextWriterWriteFormatAttribute(writer,
 +		    BAD_CAST("id"), "%d", heap->id);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteAttribute() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +		r = xmlwrite_heap(a, writer, heap);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +		r = xmlwrite_string(a, writer, "name", name);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	/*
 +	 * Make a file data entry, "<data>".
 +	 */
 +	if (file->data.length > 0) {
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("data"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		r = xmlwrite_heap(a, writer, &(file->data));
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	if (archive_strlen(&file->script) > 0) {
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("content"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		r = xmlwrite_string(a, writer,
 +		    "interpreter", file->script.s);
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +
 +		r = xmlwrite_string(a, writer, "type", "script");
 +		if (r < 0)
 +			return (ARCHIVE_FATAL);
 +
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			return (ARCHIVE_FATAL);
 +		}
 +	}
 +
 +	return (r2);
 +}
 +
 +/*
 + * Make the TOC
 + */
 +static int
 +make_toc(struct archive_write *a)
 +{
 +	struct xar *xar;
 +	struct file *np;
 +	xmlBufferPtr bp;
 +	xmlTextWriterPtr writer;
 +	int algsize;
 +	int r, ret;
 +
 +	xar = (struct xar *)a->format_data;
 +
 +	ret = ARCHIVE_FATAL;
 +
 +	/*
 +	 * Initialize xml writer.
 +	 */
 +	writer = NULL;
 +	bp = xmlBufferCreate();
 +	if (bp == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "xmlBufferCreate() "
 +		    "couldn't create xml buffer");
 +		goto exit_toc;
 +	}
 +	writer = xmlNewTextWriterMemory(bp, 0);
 +	if (writer == NULL) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlNewTextWriterMemory() "
 +		    "couldn't create xml writer");
 +		goto exit_toc;
 +	}
 +	r = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterStartDocument() failed: %d", r);
 +		goto exit_toc;
 +	}
 +	r = xmlTextWriterSetIndent(writer, 4);
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterSetIndent() failed: %d", r);
 +		goto exit_toc;
 +	}
 +
 +	/*
 +	 * Start recoding TOC
 +	 */
 +	r = xmlTextWriterStartElement(writer, BAD_CAST("xar"));
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterStartElement() failed: %d", r);
 +		goto exit_toc;
 +	}
 +	r = xmlTextWriterStartElement(writer, BAD_CAST("toc"));
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterStartDocument() failed: %d", r);
 +		goto exit_toc;
 +	}
 +
 +	/*
 +	 * Record the creation time of the archive file.
 +	 */
 +	r = xmlwrite_time(a, writer, "creation-time", time(NULL), 0);
 +	if (r < 0)
 +		goto exit_toc;
 +
 +	/*
 +	 * Record the checksum value of TOC
 +	 */
 +	algsize = getalgsize(xar->opt_toc_sumalg);
 +	if (algsize) {
 +		/*
 +		 * Record TOC checksum
 +		 */
 +		r = xmlTextWriterStartElement(writer, BAD_CAST("checksum"));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterStartElement() failed: %d", r);
 +			goto exit_toc;
 +		}
 +		r = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"),
- 		    BAD_CAST(getalgname(xar->opt_toc_sumalg)));
++		    BAD_CAST_CONST(getalgname(xar->opt_toc_sumalg)));
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterWriteAttribute() failed: %d", r);
 +			goto exit_toc;
 +		}
 +
 +		/*
 +		 * Record the offset of the value of checksum of TOC
 +		 */
 +		r = xmlwrite_string(a, writer, "offset", "0");
 +		if (r < 0)
 +			goto exit_toc;
 +
 +		/*
 +		 * Record the size of the value of checksum of TOC
 +		 */
 +		r = xmlwrite_fstring(a, writer, "size", "%d", algsize);
 +		if (r < 0)
 +			goto exit_toc;
 +
 +		r = xmlTextWriterEndElement(writer);
 +		if (r < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "xmlTextWriterEndElement() failed: %d", r);
 +			goto exit_toc;
 +		}
 +	}
 +
 +	np = xar->root;
 +	do {
 +		if (np != np->parent) {
 +			r = make_file_entry(a, writer, np);
 +			if (r != ARCHIVE_OK)
 +				goto exit_toc;
 +		}
 +
 +		if (np->dir && np->children.first != NULL) {
 +			/* Enter to sub directories. */
 +			np = np->children.first;
 +			r = xmlTextWriterStartElement(writer,
 +			    BAD_CAST("file"));
 +			if (r < 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "xmlTextWriterStartElement() "
 +				    "failed: %d", r);
 +				goto exit_toc;
 +			}
 +			r = xmlTextWriterWriteFormatAttribute(
 +			    writer, BAD_CAST("id"), "%d", np->id);
 +			if (r < 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "xmlTextWriterWriteAttribute() "
 +				    "failed: %d", r);
 +				goto exit_toc;
 +			}
 +			continue;
 +		}
 +		while (np != np->parent) {
 +			r = xmlTextWriterEndElement(writer);
 +			if (r < 0) {
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "xmlTextWriterEndElement() "
 +				    "failed: %d", r);
 +				goto exit_toc;
 +			}
 +			if (np->chnext == NULL) {
 +				/* Return to the parent directory. */
 +				np = np->parent;
 +			} else {
 +				np = np->chnext;
 +				r = xmlTextWriterStartElement(writer,
 +				    BAD_CAST("file"));
 +				if (r < 0) {
 +					archive_set_error(&a->archive,
 +					    ARCHIVE_ERRNO_MISC,
 +					    "xmlTextWriterStartElement() "
 +					    "failed: %d", r);
 +					goto exit_toc;
 +				}
 +				r = xmlTextWriterWriteFormatAttribute(
 +				    writer, BAD_CAST("id"), "%d", np->id);
 +				if (r < 0) {
 +					archive_set_error(&a->archive,
 +					    ARCHIVE_ERRNO_MISC,
 +					    "xmlTextWriterWriteAttribute() "
 +					    "failed: %d", r);
 +					goto exit_toc;
 +				}
 +				break;
 +			}
 +		}
 +	} while (np != np->parent);
 +
 +	r = xmlTextWriterEndDocument(writer);
 +	if (r < 0) {
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_MISC,
 +		    "xmlTextWriterEndDocument() failed: %d", r);
 +		goto exit_toc;
 +	}
 +#if DEBUG_PRINT_TOC
 +	fprintf(stderr, "\n---TOC-- %d bytes --\n%s\n",
 +	    strlen((const char *)bp->content), bp->content);
 +#endif
 +
 +	/*
 +	 * Compress the TOC and calculate the sum of the TOC.
 +	 */
 +	xar->toc.temp_offset = xar->temp_offset;
 +	xar->toc.size = bp->use;
 +	checksum_init(&(xar->a_sumwrk), xar->opt_toc_sumalg);
 +
 +	r = compression_init_encoder_gzip(&(a->archive),
 +	    &(xar->stream), 6, 1);
 +	if (r != ARCHIVE_OK)
 +		goto exit_toc;
 +	xar->stream.next_in = bp->content;
 +	xar->stream.avail_in = bp->use;
 +	xar->stream.total_in = 0;
 +	xar->stream.next_out = xar->wbuff;
 +	xar->stream.avail_out = sizeof(xar->wbuff);
 +	xar->stream.total_out = 0;
 +	for (;;) {
 +		size_t size;
 +
 +		r = compression_code(&(a->archive),
 +		    &(xar->stream), ARCHIVE_Z_FINISH);
 +		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
 +			goto exit_toc;
 +		size = sizeof(xar->wbuff) - xar->stream.avail_out;
 +		checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
 +		if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
 +			goto exit_toc;
 +		if (r == ARCHIVE_EOF)
 +			break;
 +		xar->stream.next_out = xar->wbuff;
 +		xar->stream.avail_out = sizeof(xar->wbuff);
 +	}
 +	r = compression_end(&(a->archive), &(xar->stream));
 +	if (r != ARCHIVE_OK)
 +		goto exit_toc;
 +	xar->toc.length = xar->stream.total_out;
 +	xar->toc.compression = GZIP;
 +	checksum_final(&(xar->a_sumwrk), &(xar->toc.a_sum));
 +
 +	ret = ARCHIVE_OK;
 +exit_toc:
 +	if (writer)
 +		xmlFreeTextWriter(writer);
 +	if (bp)
 +		xmlBufferFree(bp);
 +
 +	return (ret);
 +}
 +
 +static int
 +flush_wbuff(struct archive_write *a)
 +{
 +	struct xar *xar;
 +	int r;
 +	size_t s;
 +
 +	xar = (struct xar *)a->format_data;
 +	s = sizeof(xar->wbuff) - xar->wbuff_remaining;
 +	r = __archive_write_output(a, xar->wbuff, s);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	xar->wbuff_remaining = sizeof(xar->wbuff);
 +	return (r);
 +}
 +
 +static int
 +copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
 +{
 +	struct xar *xar;
 +	int r;
 +
 +	xar = (struct xar *)a->format_data;
 +	if (lseek(xar->temp_fd, offset, SEEK_SET) < 0) {
 +		archive_set_error(&(a->archive), errno, "lseek failed");
 +		return (ARCHIVE_FATAL);
 +	}
 +	while (length) {
 +		size_t rsize;
 +		ssize_t rs;
 +		unsigned char *wb;
 +
 +		if (length > xar->wbuff_remaining)
 +			rsize = xar->wbuff_remaining;
 +		else
 +			rsize = (size_t)length;
 +		wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
 +		rs = read(xar->temp_fd, wb, rsize);
 +		if (rs < 0) {
 +			archive_set_error(&(a->archive), errno,
 +			    "Can't read temporary file(%jd)",
 +			    (intmax_t)rs);
 +			return (ARCHIVE_FATAL);
 +		}
 +		if (rs == 0) {
 +			archive_set_error(&(a->archive), 0,
 +			    "Truncated xar archive");
 +			return (ARCHIVE_FATAL);
 +		}
 +		xar->wbuff_remaining -= rs;
 +		length -= rs;
 +		if (xar->wbuff_remaining == 0) {
 +			r = flush_wbuff(a);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +		}
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +xar_close(struct archive_write *a)
 +{
 +	struct xar *xar;
 +	unsigned char *wb;
 +	uint64_t length;
 +	int r;
 +
 +	xar = (struct xar *)a->format_data;
 +
 +	/* Empty! */
 +	if (xar->root->children.first == NULL)
 +		return (ARCHIVE_OK);
 +
 +	/* Save the length of all file extended attributes and contents. */
 +	length = xar->temp_offset;
 +
 +	/* Connect hardlinked files */
 +	file_connect_hardlink_files(xar);
 +
 +	/* Make the TOC */
 +	r = make_toc(a);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	/*
 +	 * Make the xar header on wbuff(write buffer).
 +	 */
 +	wb = xar->wbuff;
 +	xar->wbuff_remaining = sizeof(xar->wbuff);
 +	archive_be32enc(&wb[0], HEADER_MAGIC);
 +	archive_be16enc(&wb[4], HEADER_SIZE);
 +	archive_be16enc(&wb[6], HEADER_VERSION);
 +	archive_be64enc(&wb[8], xar->toc.length);
 +	archive_be64enc(&wb[16], xar->toc.size);
 +	archive_be32enc(&wb[24], xar->toc.a_sum.alg);
 +	xar->wbuff_remaining -= HEADER_SIZE;
 +
 +	/*
 +	 * Write the TOC
 +	 */
 +	r = copy_out(a, xar->toc.temp_offset, xar->toc.length);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +
 +	/* Write the checksum value of the TOC. */
 +	if (xar->toc.a_sum.len) {
 +		if (xar->wbuff_remaining < xar->toc.a_sum.len) {
 +			r = flush_wbuff(a);
 +			if (r != ARCHIVE_OK)
 +				return (r);
 +		}
 +		wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
 +		memcpy(wb, xar->toc.a_sum.val, xar->toc.a_sum.len);
 +		xar->wbuff_remaining -= xar->toc.a_sum.len;
 +	}
 +
 +	/*
 +	 * Write all file extended attributes and contents.
 +	 */
 +	r = copy_out(a, xar->toc.a_sum.len, length);
 +	if (r != ARCHIVE_OK)
 +		return (r);
 +	r = flush_wbuff(a);
 +	return (r);
 +}
 +
 +static int
 +xar_free(struct archive_write *a)
 +{
 +	struct xar *xar;
 +
 +	xar = (struct xar *)a->format_data;
 +	archive_string_free(&(xar->cur_dirstr));
 +	archive_string_free(&(xar->tstr));
 +	archive_string_free(&(xar->vstr));
 +	file_free_hardlinks(xar);
 +	file_free_register(xar);
 +	compression_end(&(a->archive), &(xar->stream));
 +	free(xar);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +file_cmp_node(const struct archive_rb_node *n1,
 +    const struct archive_rb_node *n2)
 +{
- 	struct file *f1 = (struct file *)n1;
- 	struct file *f2 = (struct file *)n2;
++	const struct file *f1 = (const struct file *)n1;
++	const struct file *f2 = (const struct file *)n2;
 +
 +	return (strcmp(f1->basename.s, f2->basename.s));
 +}
 +        
 +static int
 +file_cmp_key(const struct archive_rb_node *n, const void *key)
 +{
- 	struct file *f = (struct file *)n;
++	const struct file *f = (const struct file *)n;
 +
 +	return (strcmp(f->basename.s, (const char *)key));
 +}
 +
 +static struct file *
 +file_new(struct archive_write *a, struct archive_entry *entry)
 +{
 +	struct file *file;
 +	static const struct archive_rb_tree_ops rb_ops = {
 +		file_cmp_node, file_cmp_key
 +	};
 +
 +	file = calloc(1, sizeof(*file));
 +	if (file == NULL)
 +		return (NULL);
 +
 +	if (entry != NULL)
 +		file->entry = archive_entry_clone(entry);
 +	else
 +		file->entry = archive_entry_new2(&a->archive);
 +	if (file->entry == NULL) {
 +		free(file);
 +		return (NULL);
 +	}
 +	__archive_rb_tree_init(&(file->rbtree), &rb_ops);
 +	file->children.first = NULL;
 +	file->children.last = &(file->children.first);
 +	file->xattr.first = NULL;
 +	file->xattr.last = &(file->xattr.first);
 +	archive_string_init(&(file->parentdir));
 +	archive_string_init(&(file->basename));
 +	archive_string_init(&(file->symlink));
 +	archive_string_init(&(file->script));
 +	if (entry != NULL && archive_entry_filetype(entry) == AE_IFDIR)
 +		file->dir = 1;
 +
 +	return (file);
 +}
 +
 +static void
 +file_free(struct file *file)
 +{
 +	struct heap_data *heap, *next_heap;
 +
 +	heap = file->xattr.first;
 +	while (heap != NULL) {
 +		next_heap = heap->next;
 +		free(heap);
 +		heap = next_heap;
 +	}
 +	archive_string_free(&(file->parentdir));
 +	archive_string_free(&(file->basename));
 +	archive_string_free(&(file->symlink));
 +	archive_string_free(&(file->script));
 +	free(file);
 +}
 +
 +static struct file *
 +file_create_virtual_dir(struct archive_write *a, struct xar *xar,
 +    const char *pathname)
 +{
 +	struct file *file;
 +
++	(void)xar; /* UNUSED */
++
 +	file = file_new(a, NULL);
 +	if (file == NULL)
 +		return (NULL);
 +	archive_entry_set_pathname(file->entry, pathname);
 +	archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
 +
 +	file->dir = 1;
 +	file->virtual = 1;
 +
 +	return (file);
 +}
 +
 +static int
 +file_add_child_tail(struct file *parent, struct file *child)
 +{
 +	if (!__archive_rb_tree_insert_node(
 +	    &(parent->rbtree), (struct archive_rb_node *)child))
 +		return (0);
 +	child->chnext = NULL;
 +	*parent->children.last = child;
 +	parent->children.last = &(child->chnext);
 +	child->parent = parent;
 +	return (1);
 +}
 +
 +/*
 + * Find a entry from `parent'
 + */
 +static struct file *
 +file_find_child(struct file *parent, const char *child_name)
 +{
 +	struct file *np;
 +
 +	np = (struct file *)__archive_rb_tree_find_node(
 +	    &(parent->rbtree), child_name);
 +	return (np);
 +}
 +
 +#if defined(_WIN32) || defined(__CYGWIN__)
 +static void
 +cleanup_backslash(char *utf8, size_t len)
 +{
 +
 +	/* Convert a path-separator from '\' to  '/' */
 +	while (*utf8 != '\0' && len) {
 +		if (*utf8 == '\\')
 +			*utf8 = '/';
 +		++utf8;
 +		--len;
 +	}
 +}
 +#else
 +#define cleanup_backslash(p, len)	/* nop */
 +#endif
 +
 +/*
 + * Generate a parent directory name and a base name from a pathname.
 + */
 +static int
 +file_gen_utility_names(struct archive_write *a, struct file *file)
 +{
 +	struct xar *xar;
 +	const char *pp;
 +	char *p, *dirname, *slash;
 +	size_t len;
 +	int r = ARCHIVE_OK;
 +
 +	xar = (struct xar *)a->format_data;
 +	archive_string_empty(&(file->parentdir));
 +	archive_string_empty(&(file->basename));
 +	archive_string_empty(&(file->symlink));
 +
 +	if (file->parent == file)/* virtual root */
 +		return (ARCHIVE_OK);
 +
 +	if (archive_entry_pathname_l(file->entry, &pp, &len, xar->sconv)
 +	    != 0) {
 +		if (errno == ENOMEM) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for Pathname");
 +			return (ARCHIVE_FATAL);
 +		}
 +		archive_set_error(&a->archive,
 +		    ARCHIVE_ERRNO_FILE_FORMAT,
 +		    "Can't translate pathname '%s' to UTF-8",
 +		    archive_entry_pathname(file->entry));
 +		r = ARCHIVE_WARN;
 +	}
 +	archive_strncpy(&(file->parentdir), pp, len);
 +	len = file->parentdir.length;
 +	p = dirname = file->parentdir.s;
 +	/*
 +	 * Convert a path-separator from '\' to  '/'
 +	 */
 +	cleanup_backslash(p, len);
 +
 +	/*
 +	 * Remove leading '/', '../' and './' elements
 +	 */
 +	while (*p) {
 +		if (p[0] == '/') {
 +			p++;
 +			len--;
 +		} else if (p[0] != '.')
 +			break;
 +		else if (p[1] == '.' && p[2] == '/') {
 +			p += 3;
 +			len -= 3;
 +		} else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
 +			p += 2;
 +			len -= 2;
 +		} else if (p[1] == '\0') {
 +			p++;
 +			len--;
 +		} else
 +			break;
 +	}
 +	if (p != dirname) {
 +		memmove(dirname, p, len+1);
 +		p = dirname;
 +	}
 +	/*
 +	 * Remove "/","/." and "/.." elements from tail.
 +	 */
 +	while (len > 0) {
 +		size_t ll = len;
 +
 +		if (len > 0 && p[len-1] == '/') {
 +			p[len-1] = '\0';
 +			len--;
 +		}
 +		if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
 +			p[len-2] = '\0';
 +			len -= 2;
 +		}
 +		if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
 +		    p[len-1] == '.') {
 +			p[len-3] = '\0';
 +			len -= 3;
 +		}
 +		if (ll == len)
 +			break;
 +	}
 +	while (*p) {
 +		if (p[0] == '/') {
 +			if (p[1] == '/')
 +				/* Convert '//' --> '/' */
 +				strcpy(p, p+1);
 +			else if (p[1] == '.' && p[2] == '/')
 +				/* Convert '/./' --> '/' */
 +				strcpy(p, p+2);
 +			else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
 +				/* Convert 'dir/dir1/../dir2/'
 +				 *     --> 'dir/dir2/'
 +				 */
 +				char *rp = p -1;
 +				while (rp >= dirname) {
 +					if (*rp == '/')
 +						break;
 +					--rp;
 +				}
 +				if (rp > dirname) {
 +					strcpy(rp, p+3);
 +					p = rp;
 +				} else {
 +					strcpy(dirname, p+4);
 +					p = dirname;
 +				}
 +			} else
 +				p++;
 +		} else
 +			p++;
 +	}
 +	p = dirname;
 +	len = strlen(p);
 +
 +	if (archive_entry_filetype(file->entry) == AE_IFLNK) {
 +		size_t len2;
 +		/* Convert symlink name too. */
 +		if (archive_entry_symlink_l(file->entry, &pp, &len2,
 +		    xar->sconv) != 0) {
 +			if (errno == ENOMEM) {
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "Can't allocate memory for Linkname");
 +				return (ARCHIVE_FATAL);
 +			}
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
 +			    "Can't translate symlink '%s' to UTF-8",
 +			    archive_entry_symlink(file->entry));
 +			r = ARCHIVE_WARN;
 +		}
 +		archive_strncpy(&(file->symlink), pp, len2);
 +		cleanup_backslash(file->symlink.s, file->symlink.length);
 +	}
 +	/*
 +	 * - Count up directory elements.
 +	 * - Find out the position which points the last position of
 +	 *   path separator('/').
 +	 */
 +	slash = NULL;
 +	for (; *p != '\0'; p++)
 +		if (*p == '/')
 +			slash = p;
 +	if (slash == NULL) {
 +		/* The pathname doesn't have a parent directory. */
 +		file->parentdir.length = len;
 +		archive_string_copy(&(file->basename), &(file->parentdir));
 +		archive_string_empty(&(file->parentdir));
 +		file->parentdir.s = '\0';
 +		return (r);
 +	}
 +
 +	/* Make a basename from dirname and slash */
 +	*slash  = '\0';
 +	file->parentdir.length = slash - dirname;
 +	archive_strcpy(&(file->basename),  slash + 1);
 +	return (r);
 +}
 +
 +static int
 +get_path_component(char *name, int n, const char *fn)
 +{
 +	char *p;
 +	int l;
 +
 +	p = strchr(fn, '/');
 +	if (p == NULL) {
 +		if ((l = strlen(fn)) == 0)
 +			return (0);
 +	} else
 +		l = p - fn;
 +	if (l > n -1)
 +		return (-1);
 +	memcpy(name, fn, l);
 +	name[l] = '\0';
 +
 +	return (l);
 +}
 +
 +/*
 + * Add a new entry into the tree.
 + */
 +static int
 +file_tree(struct archive_write *a, struct file **filepp)
 +{
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +	char name[_MAX_FNAME];/* Included null terminator size. */
 +#elif defined(NAME_MAX) && NAME_MAX >= 255
 +	char name[NAME_MAX+1];
 +#else
 +	char name[256];
 +#endif
 +	struct xar *xar = (struct xar *)a->format_data;
 +	struct file *dent, *file, *np;
 +	struct archive_entry *ent;
 +	const char *fn, *p;
 +	int l;
 +
 +	file = *filepp;
 +	dent = xar->root;
 +	if (file->parentdir.length > 0)
 +		fn = p = file->parentdir.s;
 +	else
 +		fn = p = "";
 +
 +	/*
 +	 * If the path of the parent directory of `file' entry is
 +	 * the same as the path of `cur_dirent', add isoent to
 +	 * `cur_dirent'.
 +	 */
 +	if (archive_strlen(&(xar->cur_dirstr))
 +	      == archive_strlen(&(file->parentdir)) &&
 +	    strcmp(xar->cur_dirstr.s, fn) == 0) {
 +		if (!file_add_child_tail(xar->cur_dirent, file)) {
 +			np = (struct file *)__archive_rb_tree_find_node(
 +			    &(xar->cur_dirent->rbtree),
 +			    file->basename.s);
 +			goto same_entry;
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +
 +	for (;;) {
 +		l = get_path_component(name, sizeof(name), fn);
 +		if (l == 0) {
 +			np = NULL;
 +			break;
 +		}
 +		if (l < 0) {
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "A name buffer is too small");
 +			file_free(file);
 +			*filepp = NULL;
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		np = file_find_child(dent, name);
 +		if (np == NULL || fn[0] == '\0')
 +			break;
 +
 +		/* Find next subdirectory. */
 +		if (!np->dir) {
 +			/* NOT Directory! */
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_MISC,
 +			    "`%s' is not directory, we cannot insert `%s' ",
 +			    archive_entry_pathname(np->entry),
 +			    archive_entry_pathname(file->entry));
 +			file_free(file);
 +			*filepp = NULL;
 +			return (ARCHIVE_FAILED);
 +		}
 +		fn += l;
 +		if (fn[0] == '/')
 +			fn++;
 +		dent = np;
 +	}
 +	if (np == NULL) {
 +		/*
 +		 * Create virtual parent directories.
 +		 */
 +		while (fn[0] != '\0') {
 +			struct file *vp;
 +			struct archive_string as;
 +
 +			archive_string_init(&as);
 +			archive_strncat(&as, p, fn - p + l);
 +			if (as.s[as.length-1] == '/') {
 +				as.s[as.length-1] = '\0';
 +				as.length--;
 +			}
 +			vp = file_create_virtual_dir(a, xar, as.s);
 +			if (vp == NULL) {
 +				archive_string_free(&as);
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "Can't allocate memory");
 +				file_free(file);
 +				*filepp = NULL;
 +				return (ARCHIVE_FATAL);
 +			}
 +			archive_string_free(&as);
 +			if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED)
 +				return (ARCHIVE_FATAL);
 +			file_add_child_tail(dent, vp);
 +			file_register(xar, vp);
 +			np = vp;
 +
 +			fn += l;
 +			if (fn[0] == '/')
 +				fn++;
 +			l = get_path_component(name, sizeof(name), fn);
 +			if (l < 0) {
 +				archive_string_free(&as);
 +				archive_set_error(&a->archive,
 +				    ARCHIVE_ERRNO_MISC,
 +				    "A name buffer is too small");
 +				file_free(file);
 +				*filepp = NULL;
 +				return (ARCHIVE_FATAL);
 +			}
 +			dent = np;
 +		}
 +
 +		/* Found out the parent directory where isoent can be
 +		 * inserted. */
 +		xar->cur_dirent = dent;
 +		archive_string_empty(&(xar->cur_dirstr));
 +		archive_string_ensure(&(xar->cur_dirstr),
 +		    archive_strlen(&(dent->parentdir)) +
 +		    archive_strlen(&(dent->basename)) + 2);
 +		if (archive_strlen(&(dent->parentdir)) +
 +		    archive_strlen(&(dent->basename)) == 0)
 +			xar->cur_dirstr.s[0] = 0;
 +		else {
 +			if (archive_strlen(&(dent->parentdir)) > 0) {
 +				archive_string_copy(&(xar->cur_dirstr),
 +				    &(dent->parentdir));
 +				archive_strappend_char(&(xar->cur_dirstr), '/');
 +			}
 +			archive_string_concat(&(xar->cur_dirstr),
 +			    &(dent->basename));
 +		}
 +
 +		if (!file_add_child_tail(dent, file)) {
 +			np = (struct file *)__archive_rb_tree_find_node(
 +			    &(dent->rbtree), file->basename.s);
 +			goto same_entry;
 +		}
 +		return (ARCHIVE_OK);
 +	}
 +
 +same_entry:
 +	/*
 +	 * We have already has the entry the filename of which is
 +	 * the same.
 +	 */
 +	if (archive_entry_filetype(np->entry) !=
 +	    archive_entry_filetype(file->entry)) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Found duplicate entries `%s' and its file type is "
 +		    "different",
 +		    archive_entry_pathname(np->entry));
 +		file_free(file);
 +		*filepp = NULL;
 +		return (ARCHIVE_FAILED);
 +	}
 +
 +	/* Swap files. */
 +	ent = np->entry;
 +	np->entry = file->entry;
 +	file->entry = ent;
 +	np->virtual = 0;
 +
 +	file_free(file);
 +	*filepp = np;
 +	return (ARCHIVE_OK);
 +}
 +
 +static void
 +file_register(struct xar *xar, struct file *file)
 +{
 +	file->id = xar->file_idx++;
 +        file->next = NULL;
 +        *xar->file_list.last = file;
 +        xar->file_list.last = &(file->next);
 +}
 +
 +static void
 +file_init_register(struct xar *xar)
 +{
 +	xar->file_list.first = NULL;
 +	xar->file_list.last = &(xar->file_list.first);
 +}
 +
 +static void
 +file_free_register(struct xar *xar)
 +{
 +	struct file *file, *file_next;
 +
 +	file = xar->file_list.first;
 +	while (file != NULL) {
 +		file_next = file->next;
 +		file_free(file);
 +		file = file_next;
 +	}
 +}
 +
 +/*
 + * Register entry to get a hardlink target.
 + */
 +static int
 +file_register_hardlink(struct archive_write *a, struct file *file)
 +{
 +	struct xar *xar = (struct xar *)a->format_data;
 +	struct hardlink *hl;
 +	const char *pathname;
 +
 +	archive_entry_set_nlink(file->entry, 1);
 +	pathname = archive_entry_hardlink(file->entry);
 +	if (pathname == NULL) {
 +		/* This `file` is a hardlink target. */
 +		hl = malloc(sizeof(*hl));
 +		if (hl == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory");
 +			return (ARCHIVE_FATAL);
 +		}
 +		hl->nlink = 1;
 +		/* A hardlink target must be the first position. */
 +		file->hlnext = NULL;
 +		hl->file_list.first = file;
 +		hl->file_list.last = &(file->hlnext);
 +		__archive_rb_tree_insert_node(&(xar->hardlink_rbtree),
 +		    (struct archive_rb_node *)hl);
 +	} else {
 +		hl = (struct hardlink *)__archive_rb_tree_find_node(
 +		    &(xar->hardlink_rbtree), pathname);
 +		if (hl != NULL) {
 +			/* Insert `file` entry into the tail. */
 +			file->hlnext = NULL;
 +			*hl->file_list.last = file;
 +			hl->file_list.last = &(file->hlnext);
 +			hl->nlink++;
 +		}
 +		archive_entry_unset_size(file->entry);
 +	}
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +/*
 + * Hardlinked files have to have the same location of extent.
 + * We have to find out hardlink target entries for entries which
 + * have a hardlink target name.
 + */
 +static void
 +file_connect_hardlink_files(struct xar *xar)
 +{
 +	struct archive_rb_node *n;
 +	struct hardlink *hl;
 +	struct file *target, *nf;
 +
 +	ARCHIVE_RB_TREE_FOREACH(n, &(xar->hardlink_rbtree)) {
 +		hl = (struct hardlink *)n;
 +
 +		/* The first entry must be a hardlink target. */
 +		target = hl->file_list.first;
 +		archive_entry_set_nlink(target->entry, hl->nlink);
 +		if (hl->nlink > 1)
 +			/* It means this file is a hardlink
 +			 * targe itself. */
 +			target->hardlink_target = target;
 +		for (nf = target->hlnext;
 +		    nf != NULL; nf = nf->hlnext) {
 +			nf->hardlink_target = target;
 +			archive_entry_set_nlink(nf->entry, hl->nlink);
 +		}
 +	}
 +}
 +
 +static int
 +file_hd_cmp_node(const struct archive_rb_node *n1,
 +    const struct archive_rb_node *n2)
 +{
- 	struct hardlink *h1 = (struct hardlink *)n1;
- 	struct hardlink *h2 = (struct hardlink *)n2;
++	const struct hardlink *h1 = (const struct hardlink *)n1;
++	const struct hardlink *h2 = (const struct hardlink *)n2;
 +
 +	return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
 +		       archive_entry_pathname(h2->file_list.first->entry)));
 +}
 +
 +static int
 +file_hd_cmp_key(const struct archive_rb_node *n, const void *key)
 +{
- 	struct hardlink *h = (struct hardlink *)n;
++	const struct hardlink *h = (const struct hardlink *)n;
 +
 +	return (strcmp(archive_entry_pathname(h->file_list.first->entry),
 +		       (const char *)key));
 +}
 +
 +
 +static void
 +file_init_hardlinks(struct xar *xar)
 +{
 +	static const struct archive_rb_tree_ops rb_ops = {
 +		file_hd_cmp_node, file_hd_cmp_key,
 +	};
 + 
 +	__archive_rb_tree_init(&(xar->hardlink_rbtree), &rb_ops);
 +}
 +
 +static void
 +file_free_hardlinks(struct xar *xar)
 +{
 +	struct archive_rb_node *n, *next;
 +
 +	for (n = ARCHIVE_RB_TREE_MIN(&(xar->hardlink_rbtree)); n;) {
 +		next = __archive_rb_tree_iterate(&(xar->hardlink_rbtree),
 +		    n, ARCHIVE_RB_DIR_RIGHT);
 +		free(n);
 +		n = next;
 +	}
 +}
 +
 +static void
 +checksum_init(struct chksumwork *sumwrk, enum sumalg sum_alg)
 +{
 +	sumwrk->alg = sum_alg;
 +	switch (sum_alg) {
 +	case CKSUM_NONE:
 +		break;
 +	case CKSUM_SHA1:
 +		archive_sha1_init(&(sumwrk->sha1ctx));
 +		break;
 +	case CKSUM_MD5:
 +		archive_md5_init(&(sumwrk->md5ctx));
 +		break;
 +	}
 +}
 +
 +static void
 +checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
 +{
 +
 +	switch (sumwrk->alg) {
 +	case CKSUM_NONE:
 +		break;
 +	case CKSUM_SHA1:
 +		archive_sha1_update(&(sumwrk->sha1ctx), buff, size);
 +		break;
 +	case CKSUM_MD5:
 +		archive_md5_update(&(sumwrk->md5ctx), buff, size);
 +		break;
 +	}
 +}
 +
 +static void
 +checksum_final(struct chksumwork *sumwrk, struct chksumval *sumval)
 +{
 +
 +	switch (sumwrk->alg) {
 +	case CKSUM_NONE:
 +		sumval->len = 0;
 +		break;
 +	case CKSUM_SHA1:
 +		archive_sha1_final(&(sumwrk->sha1ctx), sumval->val);
 +		sumval->len = SHA1_SIZE;
 +		break;
 +	case CKSUM_MD5:
 +		archive_md5_final(&(sumwrk->md5ctx), sumval->val);
 +		sumval->len = MD5_SIZE;
 +		break;
 +	}
 +	sumval->alg = sumwrk->alg;
 +}
 +
 +#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
 +static int
 +compression_unsupported_encoder(struct archive *a,
 +    struct la_zstream *lastrm, const char *name)
 +{
 +
 +	archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +	    "%s compression not supported on this platform", name);
 +	lastrm->valid = 0;
 +	lastrm->real_stream = NULL;
 +	return (ARCHIVE_FAILED);
 +}
 +#endif
 +
 +static int
 +compression_init_encoder_gzip(struct archive *a,
 +    struct la_zstream *lastrm, int level, int withheader)
 +{
 +	z_stream *strm;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for gzip stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	/* zlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
- 	strm->total_in = lastrm->total_in;
++	strm->total_in = (uLong)lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
- 	strm->total_out = lastrm->total_out;
++	strm->total_out = (uLong)lastrm->total_out;
 +	if (deflateInit2(strm, level, Z_DEFLATED,
 +	    (withheader)?15:-15,
 +	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lastrm->real_stream = strm;
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_gzip;
 +	lastrm->end = compression_end_gzip;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_gzip(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	z_stream *strm;
 +	int r;
 +
 +	strm = (z_stream *)lastrm->real_stream;
 +	/* zlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
- 	strm->total_in = lastrm->total_in;
++	strm->total_in = (uLong)lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
- 	strm->total_out = lastrm->total_out;
++	strm->total_out = (uLong)lastrm->total_out;
 +	r = deflate(strm,
 +	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
 +	lastrm->next_in = strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in = strm->total_in;
 +	lastrm->next_out = strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out = strm->total_out;
 +	switch (r) {
 +	case Z_OK:
 +		return (ARCHIVE_OK);
 +	case Z_STREAM_END:
 +		return (ARCHIVE_EOF);
 +	default:
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "GZip compression failed:"
 +		    " deflate() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_gzip(struct archive *a, struct la_zstream *lastrm)
 +{
 +	z_stream *strm;
 +	int r;
 +
 +	strm = (z_stream *)lastrm->real_stream;
 +	r = deflateEnd(strm);
 +	free(strm);
 +	lastrm->real_stream = NULL;
 +	lastrm->valid = 0;
 +	if (r != Z_OK) {
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 +static int
 +compression_init_encoder_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	bz_stream *strm;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for bzip2 stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	/* bzlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
 +	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
 +	strm->next_out = (char *)lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
 +	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
 +	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lastrm->real_stream = strm;
 +	lastrm->valid = 1;
 +	lastrm->code = compression_code_bzip2;
 +	lastrm->end = compression_end_bzip2;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_code_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	bz_stream *strm;
 +	int r;
 +
 +	strm = (bz_stream *)lastrm->real_stream;
 +	/* bzlib.h is not const-correct, so we need this one bit
 +	 * of ugly hackery to convert a const * pointer to
 +	 * a non-const pointer. */
 +	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
 +	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
 +	strm->next_out = (char *)lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
 +	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
 +	r = BZ2_bzCompress(strm,
 +	    (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
 +	lastrm->next_in = (const unsigned char *)strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in =
 +	    (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
 +	    + (uint64_t)(uint32_t)strm->total_in_lo32;
 +	lastrm->next_out = (unsigned char *)strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out =
 +	    (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
 +	    + (uint64_t)(uint32_t)strm->total_out_lo32;
 +	switch (r) {
 +	case BZ_RUN_OK:     /* Non-finishing */
 +	case BZ_FINISH_OK:  /* Finishing: There's more work to do */
 +		return (ARCHIVE_OK);
 +	case BZ_STREAM_END: /* Finishing: all done */
 +		/* Only occurs in finishing case */
 +		return (ARCHIVE_EOF);
 +	default:
 +		/* Any other return value indicates an error */
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Bzip2 compression failed:"
 +		    " BZ2_bzCompress() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
 +{
 +	bz_stream *strm;
 +	int r;
 +
 +	strm = (bz_stream *)lastrm->real_stream;
 +	r = BZ2_bzCompressEnd(strm);
 +	free(strm);
 +	lastrm->real_stream = NULL;
 +	lastrm->valid = 0;
 +	if (r != BZ_OK) {
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Failed to clean up compressor");
 +		return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +#else
 +static int
 +compression_init_encoder_bzip2(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "bzip2"));
 +}
 +#endif
 +
 +#if defined(HAVE_LZMA_H)
 +static int
 +compression_init_encoder_lzma(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
 +	lzma_stream *strm;
 +	lzma_options_lzma lzma_opt;
 +	int r;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	if (lzma_lzma_preset(&lzma_opt, level)) {
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	strm = calloc(1, sizeof(*strm));
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for lzma stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	*strm = lzma_init_data;
 +	r = lzma_alone_encoder(strm, &lzma_opt);
 +	switch (r) {
 +	case LZMA_OK:
 +		lastrm->real_stream = strm;
 +		lastrm->valid = 1;
 +		lastrm->code = compression_code_lzma;
 +		lastrm->end = compression_end_lzma;
 +		r = ARCHIVE_OK;
 +		break;
 +	case LZMA_MEM_ERROR:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library: "
 +		    "Cannot allocate memory");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +        default:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    "It's a bug in liblzma");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +	}
 +	return (r);
 +}
 +
 +static int
 +compression_init_encoder_xz(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +	static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
 +	lzma_stream *strm;
 +	lzma_filter *lzmafilters;
 +	lzma_options_lzma lzma_opt;
 +	int r;
 +
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
 +	if (strm == NULL) {
 +		archive_set_error(a, ENOMEM,
 +		    "Can't allocate memory for xz stream");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lzmafilters = (lzma_filter *)(strm+1);
 +	if (level > 6)
 +		level = 6;
 +	if (lzma_lzma_preset(&lzma_opt, level)) {
++		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library");
 +		return (ARCHIVE_FATAL);
 +	}
 +	lzmafilters[0].id = LZMA_FILTER_LZMA2;
 +	lzmafilters[0].options = &lzma_opt;
 +	lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
 +
 +	*strm = lzma_init_data;
 +	r = lzma_stream_encoder(strm, lzmafilters, LZMA_CHECK_CRC64);
 +	switch (r) {
 +	case LZMA_OK:
 +		lastrm->real_stream = strm;
 +		lastrm->valid = 1;
 +		lastrm->code = compression_code_lzma;
 +		lastrm->end = compression_end_lzma;
 +		r = ARCHIVE_OK;
 +		break;
 +	case LZMA_MEM_ERROR:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ENOMEM,
 +		    "Internal error initializing compression library: "
 +		    "Cannot allocate memory");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +        default:
 +		free(strm);
 +		lastrm->real_stream = NULL;
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "Internal error initializing compression library: "
 +		    "It's a bug in liblzma");
 +		r =  ARCHIVE_FATAL;
 +		break;
 +	}
 +	return (r);
 +}
 +
 +static int
 +compression_code_lzma(struct archive *a,
 +    struct la_zstream *lastrm, enum la_zaction action)
 +{
 +	lzma_stream *strm;
 +	int r;
 +
 +	strm = (lzma_stream *)lastrm->real_stream;
 +	strm->next_in = lastrm->next_in;
 +	strm->avail_in = lastrm->avail_in;
 +	strm->total_in = lastrm->total_in;
 +	strm->next_out = lastrm->next_out;
 +	strm->avail_out = lastrm->avail_out;
 +	strm->total_out = lastrm->total_out;
 +	r = lzma_code(strm,
 +	    (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
 +	lastrm->next_in = strm->next_in;
 +	lastrm->avail_in = strm->avail_in;
 +	lastrm->total_in = strm->total_in;
 +	lastrm->next_out = strm->next_out;
 +	lastrm->avail_out = strm->avail_out;
 +	lastrm->total_out = strm->total_out;
 +	switch (r) {
 +	case LZMA_OK:
 +		/* Non-finishing case */
 +		return (ARCHIVE_OK);
 +	case LZMA_STREAM_END:
 +		/* This return can only occur in finishing case. */
 +		return (ARCHIVE_EOF);
 +	case LZMA_MEMLIMIT_ERROR:
 +		archive_set_error(a, ENOMEM,
 +		    "lzma compression error:"
 +		    " %ju MiB would have been needed",
 +		    (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
 +			/ (1024 * 1024)));
 +		return (ARCHIVE_FATAL);
 +	default:
 +		/* Any other return value indicates an error */
 +		archive_set_error(a, ARCHIVE_ERRNO_MISC,
 +		    "lzma compression failed:"
 +		    " lzma_code() call returned status %d", r);
 +		return (ARCHIVE_FATAL);
 +	}
 +}
 +
 +static int
 +compression_end_lzma(struct archive *a, struct la_zstream *lastrm)
 +{
 +	lzma_stream *strm;
 +
 +	(void)a; /* UNUSED */
 +	strm = (lzma_stream *)lastrm->real_stream;
 +	lzma_end(strm);
 +	free(strm);
 +	lastrm->valid = 0;
 +	lastrm->real_stream = NULL;
 +	return (ARCHIVE_OK);
 +}
 +#else
 +static int
 +compression_init_encoder_lzma(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "lzma"));
 +}
 +static int
 +compression_init_encoder_xz(struct archive *a,
 +    struct la_zstream *lastrm, int level)
 +{
 +
 +	(void) level; /* UNUSED */
 +	if (lastrm->valid)
 +		compression_end(a, lastrm);
 +	return (compression_unsupported_encoder(a, lastrm, "xz"));
 +}
 +#endif
 +
 +static int
 +xar_compression_init_encoder(struct archive_write *a)
 +{
 +	struct xar *xar;
 +	int r;
 +
 +	xar = (struct xar *)a->format_data;
 +	switch (xar->opt_compression) {
 +	case GZIP:
 +		r = compression_init_encoder_gzip(
 +		    &(a->archive), &(xar->stream),
 +		    xar->opt_compression_level, 1);
 +		break;
 +	case BZIP2:
 +		r = compression_init_encoder_bzip2(
 +		    &(a->archive), &(xar->stream),
 +		    xar->opt_compression_level);
 +		break;
 +	case LZMA:
 +		r = compression_init_encoder_lzma(
 +		    &(a->archive), &(xar->stream),
 +		    xar->opt_compression_level);
 +		break;
 +	case XZ:
 +		r = compression_init_encoder_xz(
 +		    &(a->archive), &(xar->stream),
 +		    xar->opt_compression_level);
 +		break;
 +	default:
 +		r = ARCHIVE_OK;
 +		break;
 +	}
 +	if (r == ARCHIVE_OK) {
 +		xar->stream.total_in = 0;
 +		xar->stream.next_out = xar->wbuff;
 +		xar->stream.avail_out = sizeof(xar->wbuff);
 +		xar->stream.total_out = 0;
 +	}
 +
 +	return (r);
 +}
 +
 +static int
 +compression_code(struct archive *a, struct la_zstream *lastrm,
 +    enum la_zaction action)
 +{
 +	if (lastrm->valid)
 +		return (lastrm->code(a, lastrm, action));
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +compression_end(struct archive *a, struct la_zstream *lastrm)
 +{
 +	if (lastrm->valid)
 +		return (lastrm->end(a, lastrm));
 +	return (ARCHIVE_OK);
 +}
 +
 +
 +static int
 +save_xattrs(struct archive_write *a, struct file *file)
 +{
 +	struct xar *xar;
 +	const char *name;
 +	const void *value;
 +	struct heap_data *heap;
 +	size_t size;
 +	int count, r;
 +
 +	xar = (struct xar *)a->format_data;
 +	count = archive_entry_xattr_reset(file->entry);
 +	if (count == 0)
 +		return (ARCHIVE_OK);
 +	while (count--) {
 +		archive_entry_xattr_next(file->entry,
 +		    &name, &value, &size);
 +		checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
 +		checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
 +
 +		heap = calloc(1, sizeof(*heap));
 +		if (heap == NULL) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't allocate memory for xattr");
 +			return (ARCHIVE_FATAL);
 +		}
 +		heap->id = file->ea_idx++;
 +		heap->temp_offset = xar->temp_offset;
 +		heap->size = size;/* save a extracted size */
 +		heap->compression = xar->opt_compression;
 +		/* Get a extracted sumcheck value. */
 +		checksum_update(&(xar->e_sumwrk), value, size);
 +		checksum_final(&(xar->e_sumwrk), &(heap->e_sum));
 +
 +		/*
 +		 * Not compression to xattr is simple way.
 +		 */
 +		if (heap->compression == NONE) {
 +			checksum_update(&(xar->a_sumwrk), value, size);
 +			checksum_final(&(xar->a_sumwrk), &(heap->a_sum));
 +			if (write_to_temp(a, value, size)
- 			    != ARCHIVE_OK)
++			    != ARCHIVE_OK) {
++				free(heap);
 +				return (ARCHIVE_FATAL);
++			}
 +			heap->length = size;
 +			/* Add heap to the tail of file->xattr. */
 +			heap->next = NULL;
 +			*file->xattr.last = heap;
 +			file->xattr.last = &(heap->next);
 +			/* Next xattr */
 +			continue;
 +		}
 +
 +		/*
 +		 * Init compression library.
 +		 */
 +		r = xar_compression_init_encoder(a);
 +		if (r != ARCHIVE_OK) {
 +			free(heap);
 +			return (ARCHIVE_FATAL);
 +		}
 +
 +		xar->stream.next_in = (const unsigned char *)value;
 +		xar->stream.avail_in = size;
 +		for (;;) {
 +			r = compression_code(&(a->archive),
 +			    &(xar->stream), ARCHIVE_Z_FINISH);
 +			if (r != ARCHIVE_OK && r != ARCHIVE_EOF) {
 +				free(heap);
 +				return (ARCHIVE_FATAL);
 +			}
 +			size = sizeof(xar->wbuff) - xar->stream.avail_out;
 +			checksum_update(&(xar->a_sumwrk),
 +			    xar->wbuff, size);
 +			if (write_to_temp(a, xar->wbuff, size)
 +			    != ARCHIVE_OK)
 +				return (ARCHIVE_FATAL);
 +			if (r == ARCHIVE_OK) {
 +				xar->stream.next_out = xar->wbuff;
 +				xar->stream.avail_out = sizeof(xar->wbuff);
 +			} else {
 +				checksum_final(&(xar->a_sumwrk),
 +				    &(heap->a_sum));
 +				heap->length = xar->stream.total_out;
 +				/* Add heap to the tail of file->xattr. */
 +				heap->next = NULL;
 +				*file->xattr.last = heap;
 +				file->xattr.last = &(heap->next);
 +				break;
 +			}
 +		}
 +		/* Clean up compression library. */
 +		r = compression_end(&(a->archive), &(xar->stream));
 +		if (r != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +	}
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +getalgsize(enum sumalg sumalg)
 +{
 +	switch (sumalg) {
 +	default:
 +	case CKSUM_NONE:
 +		return (0);
 +	case CKSUM_SHA1:
 +		return (SHA1_SIZE);
 +	case CKSUM_MD5:
 +		return (MD5_SIZE);
 +	}
 +}
 +
 +static const char *
 +getalgname(enum sumalg sumalg)
 +{
 +	switch (sumalg) {
 +	default:
 +	case CKSUM_NONE:
 +		return (NULL);
 +	case CKSUM_SHA1:
 +		return (SHA1_NAME);
 +	case CKSUM_MD5:
 +		return (MD5_NAME);
 +	}
 +}
 +
 +#endif /* Support xar format */
 +
diff --cc Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c
index 11fbd45,0000000..5a9f114
mode 100644,000000..100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c
@@@ -1,820 -1,0 +1,930 @@@
 +/*-
 + * Copyright (c) 2008 Anselm Strauss
 + * Copyright (c) 2009 Joerg Sonnenberger
-  * Copyright (c) 2011 Michihiro NAKAJIMA
++ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +/*
 + * Development supported by Google Summer of Code 2008.
 + */
 +
 +/*
 + * The current implementation is very limited:
 + *
 + *   - No encryption support.
 + *   - No ZIP64 support.
 + *   - No support for splitting and spanning.
 + *   - Only supports regular file and folder entries.
 + *
 + * Note that generally data in ZIP files is little-endian encoded,
 + * with some exceptions.
 + *
 + * TODO: Since Libarchive is generally 64bit oriented, but this implementation
 + * does not yet support sizes exceeding 32bit, it is highly fragile for
 + * big archives. This should change when ZIP64 is finally implemented, otherwise
 + * some serious checking has to be done.
 + *
 + */
 +
 +#include "archive_platform.h"
 +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_zip.c 201168 2009-12-29 06:15:32Z kientzle $");
 +
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_LANGINFO_H
 +#include <langinfo.h>
 +#endif
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#ifdef HAVE_ZLIB_H
 +#include <cm_zlib.h>
 +#endif
 +
 +#include "archive.h"
 +#include "archive_endian.h"
 +#include "archive_entry.h"
 +#include "archive_entry_locale.h"
 +#include "archive_private.h"
 +#include "archive_write_private.h"
 +
 +#ifndef HAVE_ZLIB_H
 +#include "archive_crc32.h"
 +#endif
 +
 +#define ZIP_SIGNATURE_LOCAL_FILE_HEADER 0x04034b50
 +#define ZIP_SIGNATURE_DATA_DESCRIPTOR 0x08074b50
 +#define ZIP_SIGNATURE_FILE_HEADER 0x02014b50
 +#define ZIP_SIGNATURE_CENTRAL_DIRECTORY_END 0x06054b50
 +#define ZIP_SIGNATURE_EXTRA_TIMESTAMP 0x5455
 +#define ZIP_SIGNATURE_EXTRA_NEW_UNIX 0x7875
 +#define ZIP_VERSION_EXTRACT 0x0014 /* ZIP version 2.0 is needed. */
 +#define ZIP_VERSION_BY 0x0314 /* Made by UNIX, using ZIP version 2.0. */
 +#define ZIP_FLAGS 0x08 /* Flagging bit 3 (count from 0) for using data descriptor. */
 +#define ZIP_FLAGS_UTF8_NAME	(1 << 11)
 +
 +enum compression {
 +	COMPRESSION_STORE = 0
 +#ifdef HAVE_ZLIB_H
 +	,
 +	COMPRESSION_DEFLATE = 8
 +#endif
 +};
 +
 +static ssize_t archive_write_zip_data(struct archive_write *,
 +		   const void *buff, size_t s);
 +static int archive_write_zip_close(struct archive_write *);
 +static int archive_write_zip_free(struct archive_write *);
 +static int archive_write_zip_finish_entry(struct archive_write *);
 +static int archive_write_zip_header(struct archive_write *,
 +	      struct archive_entry *);
 +static int archive_write_zip_options(struct archive_write *,
 +	      const char *, const char *);
 +static unsigned int dos_time(const time_t);
 +static size_t path_length(struct archive_entry *);
 +static int write_path(struct archive_entry *, struct archive_write *);
 +
- struct zip_local_file_header {
- 	char signature[4];
- 	char version[2];
- 	char flags[2];
- 	char compression[2];
- 	char timedate[4];
- 	char crc32[4];
- 	char compressed_size[4];
- 	char uncompressed_size[4];
- 	char filename_length[2];
- 	char extra_length[2];
- };
- 
- struct zip_file_header {
- 	char signature[4];
- 	char version_by[2];
- 	char version_extract[2];
- 	char flags[2];
- 	char compression[2];
- 	char timedate[4];
- 	char crc32[4];
- 	char compressed_size[4];
- 	char uncompressed_size[4];
- 	char filename_length[2];
- 	char extra_length[2];
- 	char comment_length[2];
- 	char disk_number[2];
- 	char attributes_internal[2];
- 	char attributes_external[4];
- 	char offset[4];
- };
- 
- struct zip_data_descriptor {
- 	char signature[4]; /* Not mandatory, but recommended by specification. */
- 	char crc32[4];
- 	char compressed_size[4];
- 	char uncompressed_size[4];
- };
- 
- struct zip_extra_data_local {
- 	char time_id[2];
- 	char time_size[2];
- 	char time_flag[1];
- 	char mtime[4];
- 	char atime[4];
- 	char ctime[4];
- 	char unix_id[2];
- 	char unix_size[2];
- 	char unix_version;
- 	char unix_uid_size;
- 	char unix_uid[4];
- 	char unix_gid_size;
- 	char unix_gid[4];
- };
- 
- struct zip_extra_data_central {
- 	char time_id[2];
- 	char time_size[2];
- 	char time_flag[1];
- 	char mtime[4];
- 	char unix_id[2];
- 	char unix_size[2];
- };
++#define LOCAL_FILE_HEADER_SIGNATURE		0
++#define LOCAL_FILE_HEADER_VERSION		4
++#define LOCAL_FILE_HEADER_FLAGS			6
++#define LOCAL_FILE_HEADER_COMPRESSION		8
++#define LOCAL_FILE_HEADER_TIMEDATE		10
++#define LOCAL_FILE_HEADER_CRC32			14
++#define LOCAL_FILE_HEADER_COMPRESSED_SIZE	18
++#define LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE	22
++#define LOCAL_FILE_HEADER_FILENAME_LENGTH	26
++#define LOCAL_FILE_HEADER_EXTRA_LENGTH		28
++#define SIZE_LOCAL_FILE_HEADER			30
++
++#define FILE_HEADER_SIGNATURE			0
++#define FILE_HEADER_VERSION_BY			4
++#define FILE_HEADER_VERSION_EXTRACT		6
++#define FILE_HEADER_FLAGS			8
++#define FILE_HEADER_COMPRESSION			10
++#define FILE_HEADER_TIMEDATE			12
++#define FILE_HEADER_CRC32			16
++#define FILE_HEADER_COMPRESSED_SIZE		20
++#define FILE_HEADER_UNCOMPRESSED_SIZE		24
++#define FILE_HEADER_FILENAME_LENGTH		28
++#define FILE_HEADER_EXTRA_LENGTH		30
++#define FILE_HEADER_COMMENT_LENGTH		32
++#define FILE_HEADER_DISK_NUMBER			34
++#define FILE_HEADER_ATTRIBUTES_INTERNAL		36
++#define FILE_HEADER_ATTRIBUTES_EXTERNAL		38
++#define FILE_HEADER_OFFSET			42
++#define SIZE_FILE_HEADER			46
++
++	/* Not mandatory, but recommended by specification. */
++#define DATA_DESCRIPTOR_SIGNATURE		0
++#define DATA_DESCRIPTOR_CRC32			4
++#define DATA_DESCRIPTOR_COMPRESSED_SIZE		8
++#define DATA_DESCRIPTOR_UNCOMPRESSED_SIZE	12
++#define SIZE_DATA_DESCRIPTOR			16
++
++#define EXTRA_DATA_LOCAL_TIME_ID		0
++#define EXTRA_DATA_LOCAL_TIME_SIZE		2
++#define EXTRA_DATA_LOCAL_TIME_FLAG		4
++#define EXTRA_DATA_LOCAL_MTIME			5
++#define EXTRA_DATA_LOCAL_ATIME			9
++#define EXTRA_DATA_LOCAL_CTIME			13
++#define EXTRA_DATA_LOCAL_UNIX_ID		17
++#define EXTRA_DATA_LOCAL_UNIX_SIZE		19
++#define EXTRA_DATA_LOCAL_UNIX_VERSION		21
++#define EXTRA_DATA_LOCAL_UNIX_UID_SIZE		22
++#define EXTRA_DATA_LOCAL_UNIX_UID		23
++#define EXTRA_DATA_LOCAL_UNIX_GID_SIZE		27
++#define EXTRA_DATA_LOCAL_UNIX_GID		28
++#define SIZE_EXTRA_DATA_LOCAL			32
++
++#define EXTRA_DATA_CENTRAL_TIME_ID		0
++#define EXTRA_DATA_CENTRAL_TIME_SIZE		2
++#define EXTRA_DATA_CENTRAL_TIME_FLAG		4
++#define EXTRA_DATA_CENTRAL_MTIME		5
++#define EXTRA_DATA_CENTRAL_UNIX_ID		9
++#define EXTRA_DATA_CENTRAL_UNIX_SIZE		11
++#define SIZE_EXTRA_DATA_CENTRAL			13
++
++#define CENTRAL_DIRECTORY_END_SIGNATURE		0
++#define CENTRAL_DIRECTORY_END_DISK		4
++#define CENTRAL_DIRECTORY_END_START_DISK	6
++#define CENTRAL_DIRECTORY_END_ENTRIES_DISK	8
++#define CENTRAL_DIRECTORY_END_ENTRIES		10
++#define CENTRAL_DIRECTORY_END_SIZE		12
++#define CENTRAL_DIRECTORY_END_OFFSET		16
++#define CENTRAL_DIRECTORY_END_COMMENT_LENGTH	20
++#define SIZE_CENTRAL_DIRECTORY_END		22
 +
 +struct zip_file_header_link {
 +	struct zip_file_header_link *next;
 +	struct archive_entry *entry;
 +	int64_t offset;
 +	unsigned long crc32;
 +	int64_t compressed_size;
 +	enum compression compression;
 +	int flags;
 +};
 +
 +struct zip {
- 	struct zip_data_descriptor data_descriptor;
++	uint8_t data_descriptor[SIZE_DATA_DESCRIPTOR];
 +	struct zip_file_header_link *central_directory;
 +	struct zip_file_header_link *central_directory_end;
 +	int64_t offset;
 +	int64_t written_bytes;
 +	int64_t remaining_data_bytes;
 +	enum compression compression;
 +	int flags;
 +	struct archive_string_conv *opt_sconv;
 +	struct archive_string_conv *sconv_default;
 +	int	init_default_conversion;
 +
 +#ifdef HAVE_ZLIB_H
 +	z_stream stream;
 +	size_t len_buf;
 +	unsigned char *buf;
 +#endif
 +};
 +
- struct zip_central_directory_end {
- 	char signature[4];
- 	char disk[2];
- 	char start_disk[2];
- 	char entries_disk[2];
- 	char entries[2];
- 	char size[4];
- 	char offset[4];
- 	char comment_length[2];
- };
- 
 +static int
 +archive_write_zip_options(struct archive_write *a, const char *key,
 +    const char *val)
 +{
 +	struct zip *zip = a->format_data;
 +	int ret = ARCHIVE_FAILED;
 +
 +	if (strcmp(key, "compression") == 0) {
 +		if (val == NULL || val[0] == 0) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "%s: compression option needs a compression name",
 +			    a->format_name);
 +		} else if (strcmp(val, "deflate") == 0) {
 +#ifdef HAVE_ZLIB_H
 +			zip->compression = COMPRESSION_DEFLATE;
 +			ret = ARCHIVE_OK;
 +#else
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "deflate compression not supported");
 +#endif
 +		} else if (strcmp(val, "store") == 0) {
 +			zip->compression = COMPRESSION_STORE;
 +			ret = ARCHIVE_OK;
 +		}
++		return (ret);
 +	} else if (strcmp(key, "hdrcharset")  == 0) {
 +		if (val == NULL || val[0] == 0) {
 +			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +			    "%s: hdrcharset option needs a character-set name",
 +			    a->format_name);
 +		} else {
 +			zip->opt_sconv = archive_string_conversion_to_charset(
 +			    &a->archive, val, 0);
 +			if (zip->opt_sconv != NULL)
 +				ret = ARCHIVE_OK;
 +			else
 +				ret = ARCHIVE_FATAL;
 +		}
- 	} else
++		return (ret);
++	}
++
++	/* Note: The "warn" return is just to inform the options
++	 * supervisor that we didn't handle it.  It will generate
++	 * a suitable error if no one used this option. */
++	return (ARCHIVE_WARN);
++}
++
++int
++archive_write_zip_set_compression_deflate(struct archive *_a)
++{
++	struct archive_write *a = (struct archive_write *)_a;
++	int ret = ARCHIVE_FAILED;
++	
++	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
++		ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER,
++		"archive_write_zip_set_compression_deflate");
++	if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {
++		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++		"Can only use archive_write_zip_set_compression_deflate"
++		" with zip format");
++		ret = ARCHIVE_FATAL;
++	} else {
++#ifdef HAVE_ZLIB_H
++		struct zip *zip = a->format_data;
++		zip->compression = COMPRESSION_DEFLATE;
++		ret = ARCHIVE_OK;
++#else
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- 		    "%s: unknown keyword ``%s''", a->format_name, key);
++			"deflate compression not supported");
++#endif
++	}
++	return (ret);
++}
++
++int
++archive_write_zip_set_compression_store(struct archive *_a)
++{
++	struct archive_write *a = (struct archive_write *)_a;
++	struct zip *zip = a->format_data;
++	int ret = ARCHIVE_FAILED;
++	
++	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
++		ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER,
++		"archive_write_zip_set_compression_deflate");
++	if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {
++		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++			"Can only use archive_write_zip_set_compression_store"
++			" with zip format");
++		ret = ARCHIVE_FATAL;
++	} else {
++		zip->compression = COMPRESSION_STORE;
++		ret = ARCHIVE_OK;
++	}
 +	return (ret);
 +}
 +
 +int
 +archive_write_set_format_zip(struct archive *_a)
 +{
 +	struct archive_write *a = (struct archive_write *)_a;
 +	struct zip *zip;
 +
 +	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
 +	    ARCHIVE_STATE_NEW, "archive_write_set_format_zip");
 +
 +	/* If another format was already registered, unregister it. */
 +	if (a->format_free != NULL)
 +		(a->format_free)(a);
 +
 +	zip = (struct zip *) calloc(1, sizeof(*zip));
 +	if (zip == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate zip data");
 +		return (ARCHIVE_FATAL);
 +	}
 +	zip->central_directory = NULL;
 +	zip->central_directory_end = NULL;
 +	zip->offset = 0;
 +	zip->written_bytes = 0;
 +	zip->remaining_data_bytes = 0;
 +
 +#ifdef HAVE_ZLIB_H
 +	zip->compression = COMPRESSION_DEFLATE;
 +	zip->len_buf = 65536;
 +	zip->buf = malloc(zip->len_buf);
 +	if (zip->buf == NULL) {
++		free(zip);
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate compression buffer");
 +		return (ARCHIVE_FATAL);
 +	}
 +#else
 +	zip->compression = COMPRESSION_STORE;
 +#endif
 +
 +	a->format_data = zip;
 +	a->format_name = "zip";
 +	a->format_options = archive_write_zip_options;
 +	a->format_write_header = archive_write_zip_header;
 +	a->format_write_data = archive_write_zip_data;
 +	a->format_finish_entry = archive_write_zip_finish_entry;
 +	a->format_close = archive_write_zip_close;
 +	a->format_free = archive_write_zip_free;
 +	a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
 +	a->archive.archive_format_name = "ZIP";
 +
- 	archive_le32enc(&zip->data_descriptor.signature,
++	archive_le32enc(&zip->data_descriptor[DATA_DESCRIPTOR_SIGNATURE],
 +	    ZIP_SIGNATURE_DATA_DESCRIPTOR);
 +
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +is_all_ascii(const char *p)
 +{
 +	const unsigned char *pp = (const unsigned char *)p;
 +
 +	while (*pp) {
 +		if (*pp++ > 127)
 +			return (0);
 +	}
 +	return (1);
 +}
 +
 +static int
 +archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 +{
 +	struct zip *zip;
- 	struct zip_local_file_header h;
- 	struct zip_extra_data_local e;
- 	struct zip_data_descriptor *d;
++	uint8_t h[SIZE_LOCAL_FILE_HEADER];
++	uint8_t e[SIZE_EXTRA_DATA_LOCAL];
++	uint8_t *d;
 +	struct zip_file_header_link *l;
 +	struct archive_string_conv *sconv;
 +	int ret, ret2 = ARCHIVE_OK;
 +	int64_t size;
 +	mode_t type;
 +
 +	/* Entries other than a regular file or a folder are skipped. */
 +	type = archive_entry_filetype(entry);
 +	if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) {
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Filetype not supported");
 +		return ARCHIVE_FAILED;
- 	}; 
++	};
 +
 +	/* Directory entries should have a size of 0. */
 +	if (type == AE_IFDIR)
 +		archive_entry_set_size(entry, 0);
 +
 +	zip = a->format_data;
 +	/* Setup default conversion. */
 +	if (zip->opt_sconv == NULL && !zip->init_default_conversion) {
 +		zip->sconv_default =
 +		    archive_string_default_conversion_for_write(&(a->archive));
 +		zip->init_default_conversion = 1;
 +	}
 +
 +	if (zip->flags == 0) {
 +		/* Initialize the general purpose flags. */
 +		zip->flags = ZIP_FLAGS;
 +		if (zip->opt_sconv != NULL) {
 +			if (strcmp(archive_string_conversion_charset_name(
 +			    zip->opt_sconv), "UTF-8") == 0)
 +				zip->flags |= ZIP_FLAGS_UTF8_NAME;
 +#if HAVE_NL_LANGINFO
 +		} else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
 +			zip->flags |= ZIP_FLAGS_UTF8_NAME;
 +#endif
 +		}
 +	}
- 	d = &zip->data_descriptor;
++	d = zip->data_descriptor;
 +	size = archive_entry_size(entry);
 +	zip->remaining_data_bytes = size;
 +
 +	/* Append archive entry to the central directory data. */
 +	l = (struct zip_file_header_link *) malloc(sizeof(*l));
 +	if (l == NULL) {
 +		archive_set_error(&a->archive, ENOMEM,
 +		    "Can't allocate zip header data");
 +		return (ARCHIVE_FATAL);
 +	}
++#if defined(_WIN32) && !defined(__CYGWIN__)
++	/* Make sure the path separators in pahtname, hardlink and symlink
++	 * are all slash '/', not the Windows path separator '\'. */
++	l->entry = __la_win_entry_in_posix_pathseparator(entry);
++	if (l->entry == entry)
++		l->entry = archive_entry_clone(entry);
++#else
 +	l->entry = archive_entry_clone(entry);
++#endif
++	if (l->entry == NULL) {
++		archive_set_error(&a->archive, ENOMEM,
++		    "Can't allocate zip header data");
++		free(l);
++		return (ARCHIVE_FATAL);
++	}
 +	l->flags = zip->flags;
 +	if (zip->opt_sconv != NULL)
 +		sconv = zip->opt_sconv;
 +	else
 +		sconv = zip->sconv_default;
 +	if (sconv != NULL) {
 +		const char *p;
 +		size_t len;
 +
 +		if (archive_entry_pathname_l(entry, &p, &len, sconv) != 0) {
 +			if (errno == ENOMEM) {
++				archive_entry_free(l->entry);
++				free(l);
 +				archive_set_error(&a->archive, ENOMEM,
 +				    "Can't allocate memory for Pathname");
 +				return (ARCHIVE_FATAL);
 +			}
 +			archive_set_error(&a->archive,
 +			    ARCHIVE_ERRNO_FILE_FORMAT,
- 			    "Can't translate pathname '%s' to %s",
++			    "Can't translate Pathname '%s' to %s",
 +			    archive_entry_pathname(entry),
 +			    archive_string_conversion_charset_name(sconv));
 +			ret2 = ARCHIVE_WARN;
 +		}
 +		if (len > 0)
 +			archive_entry_set_pathname(l->entry, p);
++
++		/*
++		 * Although there is no character-set regulation for Symlink,
++		 * it is suitable to convert a character-set of Symlinke to
++		 * what those of the Pathname has been converted to.
++		 */
++		if (type == AE_IFLNK) {
++			if (archive_entry_symlink_l(entry, &p, &len, sconv)) {
++				if (errno == ENOMEM) {
++					archive_entry_free(l->entry);
++					free(l);
++					archive_set_error(&a->archive, ENOMEM,
++					    "Can't allocate memory "
++					    " for Symlink");
++					return (ARCHIVE_FATAL);
++				}
++				/*
++				 * Even if the strng conversion failed,
++				 * we should not report the error since
++				 * thre is no regulation for.
++				 */
++			} else if (len > 0)
++				archive_entry_set_symlink(l->entry, p);
++		}
 +	}
- 	/* If all character of a filename is ASCII, Reset UTF-8 Name flag. */
++	/* If all characters in a filename are ASCII, Reset UTF-8 Name flag. */
 +	if ((l->flags & ZIP_FLAGS_UTF8_NAME) != 0 &&
 +	    is_all_ascii(archive_entry_pathname(l->entry)))
 +		l->flags &= ~ZIP_FLAGS_UTF8_NAME;
 +
 +	/* Initialize the CRC variable and potentially the local crc32(). */
 +	l->crc32 = crc32(0, NULL, 0);
 +	if (type == AE_IFLNK) {
 +		const char *p = archive_entry_symlink(l->entry);
 +		if (p != NULL)
 +			size = strlen(p);
 +		else
 +			size = 0;
 +		zip->remaining_data_bytes = 0;
 +		archive_entry_set_size(l->entry, size);
 +		l->compression = COMPRESSION_STORE;
 +		l->compressed_size = size;
 +	} else {
 +		l->compression = zip->compression;
 +		l->compressed_size = 0;
 +	}
 +	l->next = NULL;
 +	if (zip->central_directory == NULL) {
 +		zip->central_directory = l;
 +	} else {
 +		zip->central_directory_end->next = l;
 +	}
 +	zip->central_directory_end = l;
 +
 +	/* Store the offset of this header for later use in central
 +	 * directory. */
 +	l->offset = zip->written_bytes;
 +
- 	memset(&h, 0, sizeof(h));
- 	archive_le32enc(&h.signature, ZIP_SIGNATURE_LOCAL_FILE_HEADER);
- 	archive_le16enc(&h.version, ZIP_VERSION_EXTRACT);
- 	archive_le16enc(&h.flags, l->flags);
- 	archive_le16enc(&h.compression, l->compression);
- 	archive_le32enc(&h.timedate, dos_time(archive_entry_mtime(entry)));
- 	archive_le16enc(&h.filename_length, (uint16_t)path_length(l->entry));
++	memset(h, 0, sizeof(h));
++	archive_le32enc(&h[LOCAL_FILE_HEADER_SIGNATURE],
++		ZIP_SIGNATURE_LOCAL_FILE_HEADER);
++	archive_le16enc(&h[LOCAL_FILE_HEADER_VERSION], ZIP_VERSION_EXTRACT);
++	archive_le16enc(&h[LOCAL_FILE_HEADER_FLAGS], l->flags);
++	archive_le16enc(&h[LOCAL_FILE_HEADER_COMPRESSION], l->compression);
++	archive_le32enc(&h[LOCAL_FILE_HEADER_TIMEDATE],
++		dos_time(archive_entry_mtime(entry)));
++	archive_le16enc(&h[LOCAL_FILE_HEADER_FILENAME_LENGTH],
++		(uint16_t)path_length(l->entry));
 +
 +	switch (l->compression) {
 +	case COMPRESSION_STORE:
 +		/* Setting compressed and uncompressed sizes even when
 +		 * specification says to set to zero when using data
 +		 * descriptors. Otherwise the end of the data for an
 +		 * entry is rather difficult to find. */
- 		archive_le32enc(&h.compressed_size, size);
- 		archive_le32enc(&h.uncompressed_size, size);
++		archive_le32enc(&h[LOCAL_FILE_HEADER_COMPRESSED_SIZE],
++		    (uint32_t)size);
++		archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
++		    (uint32_t)size);
 +		break;
 +#ifdef HAVE_ZLIB_H
 +	case COMPRESSION_DEFLATE:
- 		archive_le32enc(&h.uncompressed_size, size);
++		archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
++		    (uint32_t)size);
 +
 +		zip->stream.zalloc = Z_NULL;
 +		zip->stream.zfree = Z_NULL;
 +		zip->stream.opaque = Z_NULL;
 +		zip->stream.next_out = zip->buf;
- 		zip->stream.avail_out = zip->len_buf;
++		zip->stream.avail_out = (uInt)zip->len_buf;
 +		if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION,
 +		    Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
 +			archive_set_error(&a->archive, ENOMEM,
 +			    "Can't init deflate compressor");
 +			return (ARCHIVE_FATAL);
 +		}
 +		break;
 +#endif
 +	}
 +
 +	/* Formatting extra data. */
- 	archive_le16enc(&h.extra_length, sizeof(e));
- 	archive_le16enc(&e.time_id, ZIP_SIGNATURE_EXTRA_TIMESTAMP);
- 	archive_le16enc(&e.time_size, sizeof(e.time_flag) +
- 	    sizeof(e.mtime) + sizeof(e.atime) + sizeof(e.ctime));
- 	e.time_flag[0] = 0x07;
- 	archive_le32enc(&e.mtime, archive_entry_mtime(entry));
- 	archive_le32enc(&e.atime, archive_entry_atime(entry));
- 	archive_le32enc(&e.ctime, archive_entry_ctime(entry));
- 
- 	archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_NEW_UNIX);
- 	archive_le16enc(&e.unix_size, sizeof(e.unix_version) +
- 	    sizeof(e.unix_uid_size) + sizeof(e.unix_uid) +
- 	    sizeof(e.unix_gid_size) + sizeof(e.unix_gid));
- 	e.unix_version = 1;
- 	e.unix_uid_size = 4;
- 	archive_le32enc(&e.unix_uid, archive_entry_uid(entry));
- 	e.unix_gid_size = 4;
- 	archive_le32enc(&e.unix_gid, archive_entry_gid(entry));
- 
- 	archive_le32enc(&d->uncompressed_size, size);
- 
- 	ret = __archive_write_output(a, &h, sizeof(h));
++	archive_le16enc(&h[LOCAL_FILE_HEADER_EXTRA_LENGTH], sizeof(e));
++	archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_ID],
++		ZIP_SIGNATURE_EXTRA_TIMESTAMP);
++	archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_SIZE], 1 + 4 * 3);
++	e[EXTRA_DATA_LOCAL_TIME_FLAG] = 0x07;
++	archive_le32enc(&e[EXTRA_DATA_LOCAL_MTIME],
++	    (uint32_t)archive_entry_mtime(entry));
++	archive_le32enc(&e[EXTRA_DATA_LOCAL_ATIME],
++	    (uint32_t)archive_entry_atime(entry));
++	archive_le32enc(&e[EXTRA_DATA_LOCAL_CTIME],
++	    (uint32_t)archive_entry_ctime(entry));
++
++	archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_ID],
++		ZIP_SIGNATURE_EXTRA_NEW_UNIX);
++	archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_SIZE], 1 + (1 + 4) * 2);
++	e[EXTRA_DATA_LOCAL_UNIX_VERSION] = 1;
++	e[EXTRA_DATA_LOCAL_UNIX_UID_SIZE] = 4;
++	archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_UID],
++		(uint32_t)archive_entry_uid(entry));
++	e[EXTRA_DATA_LOCAL_UNIX_GID_SIZE] = 4;
++	archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_GID],
++		(uint32_t)archive_entry_gid(entry));
++
++	archive_le32enc(&d[DATA_DESCRIPTOR_UNCOMPRESSED_SIZE],
++	    (uint32_t)size);
++
++	ret = __archive_write_output(a, h, sizeof(h));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	zip->written_bytes += sizeof(h);
 +
 +	ret = write_path(l->entry, a);
 +	if (ret <= ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	zip->written_bytes += ret;
 +
- 	ret = __archive_write_output(a, &e, sizeof(e));
++	ret = __archive_write_output(a, e, sizeof(e));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	zip->written_bytes += sizeof(e);
 +
 +	if (type == AE_IFLNK) {
 +		const unsigned char *p;
 +
 +		p = (const unsigned char *)archive_entry_symlink(l->entry);
- 		ret = __archive_write_output(a, p, size);
++		ret = __archive_write_output(a, p, (size_t)size);
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		zip->written_bytes += size;
- 		l->crc32 = crc32(l->crc32, p, size);
++		l->crc32 = crc32(l->crc32, p, (unsigned)size);
 +	}
 +
 +	if (ret2 != ARCHIVE_OK)
 +		return (ret2);
 +	return (ARCHIVE_OK);
 +}
 +
 +static ssize_t
 +archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
 +{
 +	int ret;
 +	struct zip *zip = a->format_data;
 +	struct zip_file_header_link *l = zip->central_directory_end;
 +
 +	if ((int64_t)s > zip->remaining_data_bytes)
 +		s = (size_t)zip->remaining_data_bytes;
 +
 +	if (s == 0) return 0;
 +
 +	switch (l->compression) {
 +	case COMPRESSION_STORE:
 +		ret = __archive_write_output(a, buff, s);
 +		if (ret != ARCHIVE_OK) return (ret);
 +		zip->written_bytes += s;
 +		zip->remaining_data_bytes -= s;
 +		l->compressed_size += s;
- 		l->crc32 = crc32(l->crc32, buff, s);
++		l->crc32 = crc32(l->crc32, buff, (unsigned)s);
 +		return (s);
 +#if HAVE_ZLIB_H
 +	case COMPRESSION_DEFLATE:
 +		zip->stream.next_in = (unsigned char*)(uintptr_t)buff;
- 		zip->stream.avail_in = s;
++		zip->stream.avail_in = (uInt)s;
 +		do {
 +			ret = deflate(&zip->stream, Z_NO_FLUSH);
 +			if (ret == Z_STREAM_ERROR)
 +				return (ARCHIVE_FATAL);
 +			if (zip->stream.avail_out == 0) {
 +				ret = __archive_write_output(a, zip->buf,
 +					zip->len_buf);
 +				if (ret != ARCHIVE_OK)
 +					return (ret);
 +				l->compressed_size += zip->len_buf;
 +				zip->written_bytes += zip->len_buf;
 +				zip->stream.next_out = zip->buf;
- 				zip->stream.avail_out = zip->len_buf;
++				zip->stream.avail_out = (uInt)zip->len_buf;
 +			}
 +		} while (zip->stream.avail_in != 0);
 +		zip->remaining_data_bytes -= s;
 +		/* If we have it, use zlib's fast crc32() */
- 		l->crc32 = crc32(l->crc32, buff, s);
++		l->crc32 = crc32(l->crc32, buff, (uInt)s);
 +		return (s);
 +#endif
 +
 +	default:
 +		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 +		    "Invalid ZIP compression type");
 +		return ARCHIVE_FATAL;
 +	}
 +}
 +
 +static int
 +archive_write_zip_finish_entry(struct archive_write *a)
 +{
 +	/* Write the data descripter after file data has been written. */
 +	int ret;
 +	struct zip *zip = a->format_data;
- 	struct zip_data_descriptor *d = &zip->data_descriptor;
++	uint8_t *d = zip->data_descriptor;
 +	struct zip_file_header_link *l = zip->central_directory_end;
 +#if HAVE_ZLIB_H
 +	size_t reminder;
 +#endif
 +
 +	switch(l->compression) {
 +	case COMPRESSION_STORE:
 +		break;
 +#if HAVE_ZLIB_H
 +	case COMPRESSION_DEFLATE:
 +		for (;;) {
 +			ret = deflate(&zip->stream, Z_FINISH);
 +			if (ret == Z_STREAM_ERROR)
 +				return (ARCHIVE_FATAL);
 +			reminder = zip->len_buf - zip->stream.avail_out;
 +			ret = __archive_write_output(a, zip->buf, reminder);
 +			if (ret != ARCHIVE_OK)
 +				return (ret);
 +			l->compressed_size += reminder;
 +			zip->written_bytes += reminder;
 +			zip->stream.next_out = zip->buf;
 +			if (zip->stream.avail_out != 0)
 +				break;
- 			zip->stream.avail_out = zip->len_buf;
++			zip->stream.avail_out = (uInt)zip->len_buf;
 +		}
 +		deflateEnd(&zip->stream);
 +		break;
 +#endif
 +	}
 +
- 	archive_le32enc(&d->crc32, l->crc32);
- 	archive_le32enc(&d->compressed_size, l->compressed_size);
- 	ret = __archive_write_output(a, d, sizeof(*d));
++	archive_le32enc(&d[DATA_DESCRIPTOR_CRC32], l->crc32);
++	archive_le32enc(&d[DATA_DESCRIPTOR_COMPRESSED_SIZE],
++		(uint32_t)l->compressed_size);
++	ret = __archive_write_output(a, d, SIZE_DATA_DESCRIPTOR);
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
- 	zip->written_bytes += sizeof(*d);
++	zip->written_bytes += SIZE_DATA_DESCRIPTOR;
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_write_zip_close(struct archive_write *a)
 +{
 +	struct zip *zip;
 +	struct zip_file_header_link *l;
- 	struct zip_file_header h;
- 	struct zip_central_directory_end end;
- 	struct zip_extra_data_central e;
++	uint8_t h[SIZE_FILE_HEADER];
++	uint8_t end[SIZE_CENTRAL_DIRECTORY_END];
++	uint8_t e[SIZE_EXTRA_DATA_CENTRAL];
 +	int64_t offset_start, offset_end;
 +	int entries;
 +	int ret;
 +
 +	zip = a->format_data;
 +	l = zip->central_directory;
 +
 +	/*
 +	 * Formatting central directory file header fields that are
 +	 * fixed for all entries.
 +	 * Fields not used (and therefor 0) are:
 +	 *
 +	 *   - comment_length
 +	 *   - disk_number
 +	 *   - attributes_internal
 +	 */
- 	memset(&h, 0, sizeof(h));
- 	archive_le32enc(&h.signature, ZIP_SIGNATURE_FILE_HEADER);
- 	archive_le16enc(&h.version_by, ZIP_VERSION_BY);
- 	archive_le16enc(&h.version_extract, ZIP_VERSION_EXTRACT);
++	memset(h, 0, sizeof(h));
++	archive_le32enc(&h[FILE_HEADER_SIGNATURE], ZIP_SIGNATURE_FILE_HEADER);
++	archive_le16enc(&h[FILE_HEADER_VERSION_BY], ZIP_VERSION_BY);
++	archive_le16enc(&h[FILE_HEADER_VERSION_EXTRACT], ZIP_VERSION_EXTRACT);
 +
 +	entries = 0;
 +	offset_start = zip->written_bytes;
 +
 +	/* Formatting individual header fields per entry and
 +	 * writing each entry. */
 +	while (l != NULL) {
- 		archive_le16enc(&h.flags, l->flags);
- 		archive_le16enc(&h.compression, l->compression);
- 		archive_le32enc(&h.timedate,
++		archive_le16enc(&h[FILE_HEADER_FLAGS], l->flags);
++		archive_le16enc(&h[FILE_HEADER_COMPRESSION], l->compression);
++		archive_le32enc(&h[FILE_HEADER_TIMEDATE],
 +			dos_time(archive_entry_mtime(l->entry)));
- 		archive_le32enc(&h.crc32, l->crc32);
- 		archive_le32enc(&h.compressed_size, l->compressed_size);
- 		archive_le32enc(&h.uncompressed_size,
- 			archive_entry_size(l->entry));
- 		archive_le16enc(&h.filename_length,
++		archive_le32enc(&h[FILE_HEADER_CRC32], l->crc32);
++		archive_le32enc(&h[FILE_HEADER_COMPRESSED_SIZE],
++			(uint32_t)l->compressed_size);
++		archive_le32enc(&h[FILE_HEADER_UNCOMPRESSED_SIZE],
++			(uint32_t)archive_entry_size(l->entry));
++		archive_le16enc(&h[FILE_HEADER_FILENAME_LENGTH],
 +			(uint16_t)path_length(l->entry));
- 		archive_le16enc(&h.extra_length, sizeof(e));
- 		archive_le16enc(&h.attributes_external[2],
++		archive_le16enc(&h[FILE_HEADER_EXTRA_LENGTH], sizeof(e));
++		archive_le16enc(&h[FILE_HEADER_ATTRIBUTES_EXTERNAL+2],
 +			archive_entry_mode(l->entry));
- 		archive_le32enc(&h.offset, l->offset);
++		archive_le32enc(&h[FILE_HEADER_OFFSET], (uint32_t)l->offset);
 +
 +		/* Formatting extra data. */
- 		archive_le16enc(&e.time_id, ZIP_SIGNATURE_EXTRA_TIMESTAMP);
- 		archive_le16enc(&e.time_size,
- 			sizeof(e.mtime) + sizeof(e.time_flag));
- 		e.time_flag[0] = 0x07;
- 		archive_le32enc(&e.mtime, archive_entry_mtime(l->entry));
- 		archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_NEW_UNIX);
- 		archive_le16enc(&e.unix_size, 0x0000);
- 
- 		ret = __archive_write_output(a, &h, sizeof(h));
++		archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_ID],
++			ZIP_SIGNATURE_EXTRA_TIMESTAMP);
++		archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_SIZE], 1 + 4);
++		e[EXTRA_DATA_CENTRAL_TIME_FLAG] = 0x07;
++		archive_le32enc(&e[EXTRA_DATA_CENTRAL_MTIME],
++			(uint32_t)archive_entry_mtime(l->entry));
++		archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_ID],
++			ZIP_SIGNATURE_EXTRA_NEW_UNIX);
++		archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_SIZE], 0x0000);
++
++		ret = __archive_write_output(a, h, sizeof(h));
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		zip->written_bytes += sizeof(h);
 +
 +		ret = write_path(l->entry, a);
 +		if (ret <= ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		zip->written_bytes += ret;
 +
- 		ret = __archive_write_output(a, &e, sizeof(e));
++		ret = __archive_write_output(a, e, sizeof(e));
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		zip->written_bytes += sizeof(e);
 +
 +		l = l->next;
 +		entries++;
 +	}
 +	offset_end = zip->written_bytes;
 +
 +	/* Formatting end of central directory. */
- 	memset(&end, 0, sizeof(end));
- 	archive_le32enc(&end.signature, ZIP_SIGNATURE_CENTRAL_DIRECTORY_END);
- 	archive_le16enc(&end.entries_disk, entries);
- 	archive_le16enc(&end.entries, entries);
- 	archive_le32enc(&end.size, offset_end - offset_start);
- 	archive_le32enc(&end.offset, offset_start);
++	memset(end, 0, sizeof(end));
++	archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIGNATURE],
++		ZIP_SIGNATURE_CENTRAL_DIRECTORY_END);
++	archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES_DISK], entries);
++	archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES], entries);
++	archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIZE],
++		(uint32_t)(offset_end - offset_start));
++	archive_le32enc(&end[CENTRAL_DIRECTORY_END_OFFSET],
++		(uint32_t)offset_start);
 +
 +	/* Writing end of central directory. */
- 	ret = __archive_write_output(a, &end, sizeof(end));
++	ret = __archive_write_output(a, end, sizeof(end));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	zip->written_bytes += sizeof(end);
 +	return (ARCHIVE_OK);
 +}
 +
 +static int
 +archive_write_zip_free(struct archive_write *a)
 +{
 +	struct zip *zip;
 +	struct zip_file_header_link *l;
 +
 +	zip = a->format_data;
 +	while (zip->central_directory != NULL) {
 +	   l = zip->central_directory;
 +	   zip->central_directory = l->next;
 +	   archive_entry_free(l->entry);
 +	   free(l);
 +	}
 +#ifdef HAVE_ZLIB_H
 +	free(zip->buf);
 +#endif
 +	free(zip);
 +	a->format_data = NULL;
 +	return (ARCHIVE_OK);
 +}
 +
 +/* Convert into MSDOS-style date/time. */
 +static unsigned int
 +dos_time(const time_t unix_time)
 +{
 +	struct tm *t;
 +	unsigned int dt;
 +
 +	/* This will not preserve time when creating/extracting the archive
 +	 * on two systems with different time zones. */
 +	t = localtime(&unix_time);
 +
 +	/* MSDOS-style date/time is only between 1980-01-01 and 2107-12-31 */
 +	if (t->tm_year < 1980 - 1900)
 +		/* Set minimum date/time '1980-01-01 00:00:00'. */
 +		dt = 0x00210000U;
 +	else if (t->tm_year > 2107 - 1900)
 +		/* Set maximum date/time '2107-12-31 23:59:58'. */
 +		dt = 0xff9fbf7dU;
 +	else {
 +		dt = 0;
 +		dt += ((t->tm_year - 80) & 0x7f) << 9;
 +		dt += ((t->tm_mon + 1) & 0x0f) << 5;
 +		dt += (t->tm_mday & 0x1f);
 +		dt <<= 16;
 +		dt += (t->tm_hour & 0x1f) << 11;
 +		dt += (t->tm_min & 0x3f) << 5;
 +		dt += (t->tm_sec & 0x3e) >> 1; /* Only counting every 2 seconds. */
 +	}
 +	return dt;
 +}
 +
 +static size_t
 +path_length(struct archive_entry *entry)
 +{
 +	mode_t type;
 +	const char *path;
 +
 +	type = archive_entry_filetype(entry);
 +	path = archive_entry_pathname(entry);
 +
- 	if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
++	if (path == NULL)
++		return (0);
++	if (type == AE_IFDIR &&
++	    (path[0] == '\0' || path[strlen(path) - 1] != '/')) {
 +		return strlen(path) + 1;
 +	} else {
 +		return strlen(path);
 +	}
 +}
 +
 +static int
 +write_path(struct archive_entry *entry, struct archive_write *archive)
 +{
 +	int ret;
 +	const char *path;
 +	mode_t type;
 +	size_t written_bytes;
 +
 +	path = archive_entry_pathname(entry);
 +	type = archive_entry_filetype(entry);
 +	written_bytes = 0;
 +
 +	ret = __archive_write_output(archive, path, strlen(path));
 +	if (ret != ARCHIVE_OK)
 +		return (ARCHIVE_FATAL);
 +	written_bytes += strlen(path);
 +
 +	/* Folders are recognized by a traling slash. */
 +	if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
 +		ret = __archive_write_output(archive, "/", 1);
 +		if (ret != ARCHIVE_OK)
 +			return (ARCHIVE_FATAL);
 +		written_bytes += 1;
 +	}
 +
 +	return ((int)written_bytes);
 +}

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=35df7c8ba8854e97bd6994c4d1143f57535ed6f2
commit 35df7c8ba8854e97bd6994c4d1143f57535ed6f2
Author:     LibArchive Upstream <libarchive-discuss at googlegroups.com>
AuthorDate: Sat Feb 9 12:17:57 2013 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Fri Jul 26 15:45:29 2013 -0400

    libarchive 3.1.2 (reduced)
    
    Extract upstream libarchive using the following shell code.
    
    url=git://github.com/libarchive/libarchive.git &&
    v=3.1.2 &&
    r=19f23e19 &&
    paths="
      CMakeLists.txt
      COPYING
      CTestConfig.cmake
      build/cmake
      build/pkgconfig
      build/utils
      build/version
      libarchive/*.*
    " &&
    mkdir libarchive-$v-g$r-reduced &&
    git clone $url libarchive-git &&
    date=$(cd libarchive-git && git log -n 1 --format='%cd' $r) &&
    (cd libarchive-git && git archive --format=tar $r -- $paths) |
    (cd libarchive-$v-g$r-reduced && tar xv) &&
    fromdos libarchive-$v-g$r-reduced/build/cmake/Find*.cmake &&
    echo "g$r date: $date"

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 60672ce..2cdb9fb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,13 +1,36 @@
 #
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.6 FATAL_ERROR)
 #
 PROJECT(libarchive C)
 #
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
 SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
 if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
   set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${libarchive_BINARY_DIR}/bin)
 endif()
-SET(CMAKE_BUILD_TYPE "Release")
+#
+# Set the Build type for make based generators.
+# You can choose following types:
+#   Debug          : Debug build
+#   Release        : Release build
+#   RelWithDebInfo : Release build with Debug Info
+#   MinSizeRel     : Release Min Size build
+IF(NOT CMAKE_BUILD_TYPE)
+  SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type" FORCE)
+ENDIF(NOT CMAKE_BUILD_TYPE)
+# Set a value type to properly display CMAKE_BUILD_TYPE on GUI if the
+# value type is "UNINITIALIZED".
+GET_PROPERTY(cached_type CACHE CMAKE_BUILD_TYPE PROPERTY TYPE)
+IF("${cached_type}" STREQUAL "UNINITIALIZED")
+  SET(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING "Build Type" FORCE)
+ENDIF("${cached_type}" STREQUAL "UNINITIALIZED")
+# Check the Build Type.
+IF(NOT "${CMAKE_BUILD_TYPE}"
+       MATCHES "^(Debug|Release|RelWithDebInfo|MinSizeRel)\$")
+  MESSAGE(FATAL_ERROR
+          "Unknown keyword for CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}\n"
+          "Acceptable keywords: Debug,Release,RelWithDebInfo,MinSizeRel")
+ENDIF(NOT "${CMAKE_BUILD_TYPE}"
+          MATCHES "^(Debug|Release|RelWithDebInfo|MinSizeRel)\$")
 
 # On MacOS, prefer MacPorts libraries to system libraries.
 # I haven't come up with a compelling argument for this to be conditional.
@@ -40,20 +63,80 @@ SET(LIBARCHIVE_VERSION_STRING  "${VERSION}")
 # libarchive 2.8 == interface version 10 = 2 + 8
 # libarchive 2.9 == interface version 11 = 2 + 9
 # libarchive 3.0 == interface version 12
-# libarchive 3.x == interface version 12 + x
-math(EXPR INTERFACE_VERSION  "12 + ${_minor}")
+# libarchive 3.1 == interface version 13
+math(EXPR INTERFACE_VERSION  "13 + ${_minor}")
 
 # Set SOVERSION == Interface version
 # ?? Should there be more here ??
 SET(SOVERSION "${INTERFACE_VERSION}")
 
+# Enalbe CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE() macros
+# saving and restoring the state of the variables.
+INCLUDE(CMakePushCheckState)
+
+# Initialize the state of the variables. This initialization is not
+# necessary but this shows you what value the variables initially have.
+SET(CMAKE_REQUIRED_DEFINITIONS)
+SET(CMAKE_REQUIRED_INCLUDES)
+SET(CMAKE_REQUIRED_LIBRARIES)
+SET(CMAKE_REQUIRED_FLAGS)
+
 # Especially for early development, we want to be a little
 # aggressive about diagnosing build problems; this can get
 # relaxed somewhat in final shipping versions.
 IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
-  ADD_DEFINITIONS(-Wall)
-  SET(CMAKE_REQUIRED_FLAGS "-Wall")
+  SET(CMAKE_REQUIRED_FLAGS "-Wall -Wformat -Wformat-security")
+  #################################################################
+  # Set compile flags for all build types.
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wformat -Wformat-security")
+  #################################################################
+  # Set compile flags for debug build.
+  # This is added into CMAKE_C_FLAGS when CMAKE_BUILD_TYPE is "Debug"
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror -Wextra -Wunused")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wshadow")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wmissing-prototypes")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wcast-qual")
 ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
+IF (MSVC)
+  #################################################################
+  # Set compile flags for debug build.
+  # This is added into CMAKE_C_FLAGS when CMAKE_BUILD_TYPE is "Debug"
+  # Enable level 4 C4061: The enumerate has no associated handler in a switch
+  #                       statement.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4061")
+  # Enable level 4 C4254: A larger bit field was assigned to a smaller bit
+  #                       field.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4254")
+  # Enable level 4 C4295: An array was initialized but the last character in
+  #                       the array is not a null; accessing the array may
+  #                       produce unexpected results.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4295")
+  # Enable level 4 C4296: An unsigned variable was used in a comparison
+  #                       operation with zero.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4296")
+  # Enable level 4 C4389: An operation involved signed and unsigned variables.
+  #                       This could result in a loss of data.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4389")
+  # Enable level 4 C4505: The given function is local and not referenced in
+  #                       the body of the module; therefore, the function is
+  #                       dead code.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4505")
+  # Enable level 4 C4514: The optimizer removed an inline function that is not
+  #                       called.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4514")
+  # Enable level 4 C4702: Unreachable code.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4702")
+  # Enable level 4 C4706: The test value in a conditional expression was the
+  #                       result of an assignment.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4706")
+  # /WX option is the same as gcc's -Werror option.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /WX")
+  # /Oi option enables built-in functions.
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Oi")
+  #################################################################
+  # Set compile flags for release build.
+  SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi")
+ENDIF (MSVC)
 
 # Enable CTest/CDash support
 include(CTest)
@@ -68,19 +151,55 @@ OPTION(ENABLE_XATTR "Enable extended attribute support" ON)
 OPTION(ENABLE_ACL "Enable ACL support" ON)
 OPTION(ENABLE_ICONV "Enable iconv support" ON)
 OPTION(ENABLE_TEST "Enable unit and regression tests" ON)
+SET(POSIX_REGEX_LIB "AUTO" CACHE STRING "Choose what library should provide POSIX regular expression support")
+SET(ENABLE_SAFESEH "AUTO" CACHE STRING "Enable use of /SAFESEH linker flag (MSVC only)")
+SET(WINDOWS_VERSION "" CACHE STRING "Set Windows version to use (Windows only)")
 
 IF(ENABLE_TEST)
 	ENABLE_TESTING()
 ENDIF(ENABLE_TEST)
 
 IF(WIN32)
-  SET(_WIN32_WINNT 0x0500 CACHE INTERNAL "Setting _WIN32_WINNT to 0x0500 for Windows 2000 APIs")
-  SET(WINVER 0x0500 CACHE INTERNAL "Setting WINVER to 0x0500 for Windows 2000 APIs")
+  IF(WINDOWS_VERSION STREQUAL "WIN8")
+    SET(WINVER 0x0602)
+  ELSEIF(WINDOWS_VERSION STREQUAL "WIN7")
+    SET(WINVER 0x0601)
+  ELSEIF(WINDOWS_VERSION STREQUAL "WS08")
+    SET(WINVER 0x0600)
+  ELSEIF(WINDOWS_VERSION STREQUAL "VISTA")
+    SET(WINVER 0x0600)
+  ELSEIF(WINDOWS_VERSION STREQUAL "WS03")
+    SET(WINVER 0x0502)
+  ELSEIF(WINDOWS_VERSION STREQUAL "WINXP")
+    SET(WINVER 0x0501)
+  ELSE(WINDOWS_VERSION STREQUAL "WIN8")
+    # The default is to use Windows 2000 API.
+    SET(WINVER 0x0500)
+  ENDIF(WINDOWS_VERSION STREQUAL "WIN8")
+  SET(_WIN32_WINNT ${WINVER})
 ENDIF(WIN32)
 
+IF(MSVC)
+  IF(ENABLE_SAFESEH STREQUAL "YES")
+    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH")
+    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH")
+    SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH")
+	SET(CMAKE_REQUIRED_LINKER_FLAGS "/SAFESEH")
+  ELSEIF(ENABLE_SAFESEH STREQUAL "NO")
+    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
+    SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO")
+    SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /SAFESEH:NO")
+	SET(CMAKE_REQUIRED_LINKER_FLAGS "/SAFESEH:NO")
+  ENDIF(ENABLE_SAFESEH STREQUAL "YES")
+ENDIF(MSVC)
+
+IF("${CMAKE_C_PLATFORM_ID}" MATCHES "^(HP-UX)$")
+  ADD_DEFINITIONS(-D_XOPEN_SOURCE=500) # Ask wchar.h for mbstate_t
+ENDIF()
+
 #
-INCLUDE(CheckCSourceCompiles)
-INCLUDE(CheckCSourceRuns)
+INCLUDE(LibarchiveCheckCSourceCompiles)
+INCLUDE(LibarchiveCheckCSourceRuns)
 INCLUDE(CheckFileOffsetBits)
 INCLUDE(CheckFuncs)
 INCLUDE(CheckHeaderDirent)
@@ -125,7 +244,38 @@ MACRO (INSTALL_MAN __mans)
     INSTALL(FILES ${_man} DESTINATION "share/man/man${_mansect}")
   ENDFOREACH (_man)
 ENDMACRO (INSTALL_MAN __mans)
-
+#
+# Find out what macro is needed to use libraries on Windows.
+#
+MACRO (TRY_MACRO_FOR_LIBRARY INCLUDES LIBRARIES
+       TRY_TYPE SAMPLE_SOURCE MACRO_LIST)
+  IF(WIN32 AND NOT CYGWIN)
+    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
+    SET(CMAKE_REQUIRED_INCLUDES ${INCLUDES})
+    SET(CMAKE_REQUIRED_LIBRARIES ${LIBRARIES})
+    FOREACH(VAR ${MACRO_LIST})
+      # Clear ${VAR} from CACHE If the libraries which ${VAR} was
+      # checked with are changed.
+      SET(VAR_WITH_LIB "${VAR}_WITH_LIB")
+      GET_PROPERTY(PREV_VAR_WITH_LIB VARIABLE PROPERTY ${VAR_WITH_LIB})
+      IF(NOT "${PREV_VAR_WITH_LIB}" STREQUAL "${LIBRARIES}")
+        UNSET(${VAR} CACHE)
+      ENDIF(NOT "${PREV_VAR_WITH_LIB}" STREQUAL "${LIBRARIES}")
+      # Check if the library can be used with the macro.
+      IF("${TRY_TYPE}" MATCHES "COMPILES")
+        LIBARCHIVE_CHECK_C_SOURCE_COMPILES("${SAMPLE_SOURCE}" ${VAR})
+      ELSEIF("${TRY_TYPE}" MATCHES "RUNS")
+        LIBARCHIVE_CHECK_C_SOURCE_RUNS("${SAMPLE_SOURCE}" ${VAR})
+      ELSE("${TRY_TYPE}" MATCHES "COMPILES")
+        MESSAGE(FATAL_ERROR "UNKNOWN KEYWORD \"${TRY_TYPE}\" FOR TRY_TYPE")
+      ENDIF("${TRY_TYPE}" MATCHES "COMPILES")
+      # Save the libraries which ${VAR} is checked with.
+      SET(${VAR_WITH_LIB} "${LIBRARIES}" CACHE INTERNAL
+          "Macro ${VAR} is checked with")
+    ENDFOREACH(VAR)
+    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
+  ENDIF(WIN32 AND NOT CYGWIN)
+ENDMACRO (TRY_MACRO_FOR_LIBRARY)
 #
 # Check compress/decompress libraries
 #
@@ -172,11 +322,27 @@ IF(ZLIB_FOUND)
   INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${ZLIB_LIBRARIES})
   IF(WIN32 AND NOT CYGWIN)
-    SET(CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIR})
-    SET(CMAKE_REQUIRED_LIBRARIES ${ZLIB_LIBRARIES})
-    CHECK_C_SOURCE_Runs(
-      "#ifndef ZLIB_WINAPI\n#define ZLIB_WINAPI\n#endif\n#include <zlib.h>\nint main() {uLong f = zlibCompileFlags(); return (f&(1U<<10))?0:-1; }"
+    #
+    # Test if ZLIB_WINAPI macro is needed to use.
+    #
+    TRY_MACRO_FOR_LIBRARY(
+      "${ZLIB_INCLUDE_DIR}" "${ZLIB_LIBRARIES}"
+      RUNS
+      "#include <zlib.h>\nint main() {uLong f = zlibCompileFlags(); return (f&(1U<<10))?0:-1; }"
       ZLIB_WINAPI)
+    IF(ZLIB_WINAPI)
+      ADD_DEFINITIONS(-DZLIB_WINAPI)
+    ELSE(ZLIB_WINAPI)
+      # Test if a macro is needed for the library.
+      TRY_MACRO_FOR_LIBRARY(
+        "${ZLIB_INCLUDE_DIR}" "${ZLIB_LIBRARIES}"
+        COMPILES
+        "#include <zlib.h>\nint main() {return zlibVersion()?1:0; }"
+        "ZLIB_DLL;WITHOUT_ZLIB_DLL")
+      IF(ZLIB_DLL)
+        ADD_DEFINITIONS(-DZLIB_DLL)
+      ENDIF(ZLIB_DLL)
+    ENDIF(ZLIB_WINAPI)
   ENDIF(WIN32 AND NOT CYGWIN)
 ENDIF(ZLIB_FOUND)
 MARK_AS_ADVANCED(CLEAR ZLIB_INCLUDE_DIR)
@@ -190,9 +356,20 @@ IF(BZIP2_FOUND)
   SET(HAVE_BZLIB_H 1)
   INCLUDE_DIRECTORIES(${BZIP2_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${BZIP2_LIBRARIES})
+  # Test if a macro is needed for the library.
+  TRY_MACRO_FOR_LIBRARY(
+    "${BZIP2_INCLUDE_DIR}" "${BZIP2_LIBRARIES}"
+    COMPILES
+    "#include <bzlib.h>\nint main() {return BZ2_bzlibVersion()?1:0; }"
+    "USE_BZIP2_DLL;USE_BZIP2_STATIC")
+  IF(USE_BZIP2_DLL)
+    ADD_DEFINITIONS(-DUSE_BZIP2_DLL)
+  ELSEIF(USE_BZIP2_STATIC)
+    ADD_DEFINITIONS(-DUSE_BZIP2_STATIC)
+  ENDIF(USE_BZIP2_DLL)
 ENDIF(BZIP2_FOUND)
 MARK_AS_ADVANCED(CLEAR BZIP2_INCLUDE_DIR)
-MARK_AS_ADVANCED(CLEAR BZIP2_LIBRARY)
+MARK_AS_ADVANCED(CLEAR BZIP2_LIBRARIES)
 #
 # Find LZMA
 #
@@ -202,12 +379,45 @@ IF(LZMA_FOUND)
   SET(HAVE_LZMA_H 1)
   INCLUDE_DIRECTORIES(${LZMA_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${LZMA_LIBRARIES})
+  # Test if a macro is needed for the library.
+  TRY_MACRO_FOR_LIBRARY(
+    "${LZMA_INCLUDE_DIR}" "${LZMA_LIBRARIES}"
+    COMPILES
+    "#include <lzma.h>\nint main() {return (int)lzma_version_number(); }"
+    "WITHOUT_LZMA_API_STATIC;LZMA_API_STATIC")
+  IF(NOT WITHOUT_LZMA_API_STATIC AND LZMA_API_STATIC)
+    ADD_DEFINITIONS(-DLZMA_API_STATIC)
+  ENDIF(NOT WITHOUT_LZMA_API_STATIC AND LZMA_API_STATIC)
 ELSEIF(LZMADEC_FOUND)
   SET(HAVE_LIBLZMADEC 1)
   SET(HAVE_LZMADEC_H 1)
   INCLUDE_DIRECTORIES(${LZMADEC_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${LZMADEC_LIBRARIES})
 ENDIF(LZMA_FOUND)
+#
+# Find LZO2
+#
+IF (LZO2_INCLUDE_DIR)
+  # Already in cache, be silent
+  SET(LZO2_FIND_QUIETLY TRUE)
+ENDIF (LZO2_INCLUDE_DIR)
+
+FIND_PATH(LZO2_INCLUDE_DIR lzo/lzoconf.h)
+FIND_LIBRARY(LZO2_LIBRARY NAMES lzo2 liblzo2)
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZO2 DEFAULT_MSG LZO2_LIBRARY LZO2_INCLUDE_DIR)
+IF(LZO2_FOUND)
+  SET(HAVE_LIBLZO2 1)
+  SET(HAVE_LZO_LZOCONF_H 1)
+  SET(HAVE_LZO_LZO1X_H 1)
+  INCLUDE_DIRECTORIES(${LZO2_INCLUDE_DIR})
+  LIST(APPEND ADDITIONAL_LIBS ${LZO2_LIBRARY})
+  #
+  # TODO: test for static library.
+  #
+ENDIF(LZO2_FOUND)
+MARK_AS_ADVANCED(CLEAR LZO2_INCLUDE_DIR)
+MARK_AS_ADVANCED(CLEAR LZO2_LIBRARY)
 
 #
 # Check headers
@@ -234,7 +444,7 @@ LA_CHECK_INCLUDE_FILE("dlfcn.h" HAVE_DLFCN_H)
 LA_CHECK_INCLUDE_FILE("errno.h" HAVE_ERRNO_H)
 LA_CHECK_INCLUDE_FILE("ext2fs/ext2_fs.h" HAVE_EXT2FS_EXT2_FS_H)
 
-CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
 #include <ext2fs/ext2_fs.h>
 int main(void) { return EXT2_IOC_GETFLAGS; }" HAVE_WORKING_EXT2_IOC_GETFLAGS)
 
@@ -244,6 +454,7 @@ LA_CHECK_INCLUDE_FILE("inttypes.h" HAVE_INTTYPES_H)
 LA_CHECK_INCLUDE_FILE("io.h" HAVE_IO_H)
 LA_CHECK_INCLUDE_FILE("langinfo.h" HAVE_LANGINFO_H)
 LA_CHECK_INCLUDE_FILE("limits.h" HAVE_LIMITS_H)
+LA_CHECK_INCLUDE_FILE("linux/types.h" HAVE_LINUX_TYPES_H)
 LA_CHECK_INCLUDE_FILE("linux/fiemap.h" HAVE_LINUX_FIEMAP_H)
 LA_CHECK_INCLUDE_FILE("linux/fs.h" HAVE_LINUX_FS_H)
 LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H)
@@ -255,6 +466,7 @@ LA_CHECK_INCLUDE_FILE("process.h" HAVE_PROCESS_H)
 LA_CHECK_INCLUDE_FILE("pwd.h" HAVE_PWD_H)
 LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
 LA_CHECK_INCLUDE_FILE("signal.h" HAVE_SIGNAL_H)
+LA_CHECK_INCLUDE_FILE("spawn.h" HAVE_SPAWN_H)
 LA_CHECK_INCLUDE_FILE("stdarg.h" HAVE_STDARG_H)
 LA_CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H)
 LA_CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H)
@@ -295,7 +507,7 @@ FOREACH (it ${_HEADER})
    SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
 ENDFOREACH (it)
 
-CHECK_C_SOURCE_COMPILES(
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
   "#define __EXTENSIONS__ 1
    ${_INCLUDE_FILES}
    int main() { return 0;}"
@@ -305,14 +517,17 @@ CHECK_C_SOURCE_COMPILES(
 # Find Nettle
 #
 IF(ENABLE_NETTLE)
-  CHECK_LIBRARY_EXISTS(nettle "nettle_sha1_digest" "" NETTLE_FOUND)
+  FIND_PACKAGE(Nettle)
   IF(NETTLE_FOUND)
-    SET(CMAKE_REQUIRED_LIBRARIES "nettle")
-    FIND_LIBRARY(NETTLE_LIBRARY NAMES nettle)
-    LIST(APPEND ADDITIONAL_LIBS ${NETTLE_LIBRARY})
-  ELSE(NETTLE_FOUND)
-    SET(ENABLE_NETTLE OFF)
+    SET(HAVE_LIBNETTLE 1)
+    SET(HAVE_NETTLE_MD5_H 1)
+    SET(HAVE_NETTLE_RIPEMD160_H 1)
+    SET(HAVE_NETTLE_SHA_H 1)
+    INCLUDE_DIRECTORIES(${NETTLE_INCLUDE_DIR})
+    LIST(APPEND ADDITIONAL_LIBS ${NETTLE_LIBRARIES})
   ENDIF(NETTLE_FOUND)
+  MARK_AS_ADVANCED(CLEAR NETTLE_INCLUDE_DIR)
+  MARK_AS_ADVANCED(CLEAR NETTLE_LIBRARIES)
 ENDIF(ENABLE_NETTLE)
 
 #
@@ -326,12 +541,16 @@ ELSE()
 ENDIF()
 
 # FreeBSD libmd
-CHECK_LIBRARY_EXISTS(md "MD5Init" "" LIBMD_FOUND)
-IF(LIBMD_FOUND)
-  SET(CMAKE_REQUIRED_LIBRARIES "md")
-  FIND_LIBRARY(LIBMD_LIBRARY NAMES md)
-  LIST(APPEND ADDITIONAL_LIBS ${LIBMD_LIBRARY})
-ENDIF(LIBMD_FOUND)
+IF(NOT OPENSSL_FOUND)
+  CHECK_LIBRARY_EXISTS(md "MD5Init" "" LIBMD_FOUND)
+  IF(LIBMD_FOUND)
+    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
+    SET(CMAKE_REQUIRED_LIBRARIES "md")
+    FIND_LIBRARY(LIBMD_LIBRARY NAMES md)
+    LIST(APPEND ADDITIONAL_LIBS ${LIBMD_LIBRARY})
+    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
+  ENDIF(LIBMD_FOUND)
+ENDIF(NOT OPENSSL_FOUND)
 
 #
 # How to prove that CRYPTO functions, which have several names on various
@@ -339,13 +558,8 @@ ENDIF(LIBMD_FOUND)
 # required libraries.
 #
 MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
-    IF(HAVE_SYS_TYPES_H)
-        SET(CRYPTO_HEADER_CONFIG "#define HAVE_SYS_TYPES_H 1\n")
-    ELSE(HAVE_SYS_TYPES_H)
-        SET(CRYPTO_HEADER_CONFIG "")
-    ENDIF(HAVE_SYS_TYPES_H)
-
     FOREACH(ALGORITHM ${ALGORITHMS})
+      IF(NOT ARCHIVE_CRYPTO_${ALGORITHM})
       STRING(TOLOWER "${ALGORITHM}" lower_algorithm)
       STRING(TOUPPER "${ALGORITHM}" algorithm)
       IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND NOT OPENSSL_FOUND)
@@ -358,7 +572,7 @@ MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
         # Probe the local implementation for whether this
 	# crypto implementation is available on this platform.
 	SET(TRY_CRYPTO_REQUIRED_INCLUDES
-	  "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_CURRENT_SOURCE_DIR}/libarchive;${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
+	  "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive;${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
 	SET(TRY_CRYPTO_REQUIRED_LIBS)
 	IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 	    SET(TRY_CRYPTO_REQUIRED_INCLUDES
@@ -366,6 +580,8 @@ MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 	    SET(TRY_CRYPTO_REQUIRED_LIBS
 	        "-DLINK_LIBRARIES:STRING=${OPENSSL_LIBRARIES}")
 	ELSEIF("${IMPLEMENTATION}" MATCHES "^NETTLE$" AND NETTLE_FOUND)
+	    SET(TRY_CRYPTO_REQUIRED_INCLUDES
+	      "${TRY_CRYPTO_REQUIRED_INCLUDES};${NETTLE_INCLUDE_DIR}")
 	    SET(TRY_CRYPTO_REQUIRED_LIBS
 	        "-DLINK_LIBRARIES:STRING=${NETTLE_LIBRARY}")
 	ELSEIF("${IMPLEMENTATION}" MATCHES "^LIBMD$" AND LIBMD_FOUND)
@@ -373,10 +589,15 @@ MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 	        "-DLINK_LIBRARIES:STRING=${LIBMD_LIBRARY}")
 	ENDIF("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
 
+    CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h)
+	FILE(READ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h"
+	     CONFDEFS_H)
 	FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/libarchive/archive_crypto.c"
 	     ARCHIVE_CRYPTO_C)
 
-	SET(SOURCE "
+	SET(SOURCE "${CONFDEFS_H}
+
 #define ARCHIVE_${algorithm}_COMPILE_TEST
 #define ARCHIVE_CRYPTO_${algorithm}_${IMPLEMENTATION}
 #define PLATFORM_CONFIG_H \"check_crypto_md.h\"
@@ -386,10 +607,10 @@ ${ARCHIVE_CRYPTO_C}
 int
 main(int argc, char **argv)
 {
-  archive_${lower_crypto}_ctx ctx;
-  archive_${lower_crypto}_init(&ctx);
-  archive_${lower_crypto}_update(&ctx, *argv, argc);
-  archive_${lower_crypto}_final(&ctx, NULL);
+  archive_${lower_algorithm}_ctx ctx;
+  archive_${lower_algorithm}_init(&ctx);
+  archive_${lower_algorithm}_update(&ctx, *argv, argc);
+  archive_${lower_algorithm}_final(&ctx, NULL);
   return 0;
 }
 ")
@@ -398,10 +619,16 @@ main(int argc, char **argv)
 	FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c" "${SOURCE}")
 	MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}")
 
+    IF(CMAKE_REQUIRED_LINKER_FLAGS)
+      SET(CHECK_CRYPTO_ADD_LINKER_FLAGS
+        "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
+    ELSE(CMAKE_REQUIRED_LINKER_FLAGS)
+      SET(CHECK_CRYPTO_ADD_LINKER_FLAGS)
+    ENDIF(CMAKE_REQUIRED_LINKER_FLAGS)
 	TRY_COMPILE(ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}
 	  ${CMAKE_BINARY_DIR}
 	  ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c
-	  CMAKE_FLAGS
+	  CMAKE_FLAGS ${CHECK_CRYPTO_ADD_LINKER_FLAGS}
 	   "${TRY_CRYPTO_REQUIRED_LIBS}"
 	   "${TRY_CRYPTO_REQUIRED_INCLUDES}"
 	  OUTPUT_VARIABLE OUTPUT)
@@ -409,6 +636,7 @@ main(int argc, char **argv)
 	# Inform user whether or not we found it; if not, log why we didn't.
         IF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
           MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} -- found")
+		  SET(ARCHIVE_CRYPTO_${ALGORITHM} 1)
         ELSE (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
           MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION} -- not found")
           FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
@@ -427,6 +655,7 @@ main(int argc, char **argv)
 	   LIST(REMOVE_DUPLICATES ADDITIONAL_LIBS)
         ENDIF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
       ENDIF (ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION})
+      ENDIF(NOT ARCHIVE_CRYPTO_${ALGORITHM})
     ENDFOREACH(ALGORITHM ${ALGORITHMS})
 ENDMACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 
@@ -442,6 +671,7 @@ ENDMACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
 MACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
   IF(WIN32 AND NOT CYGWIN)
     FOREACH(CRYPTO ${CRYPTO_LIST})
+      IF(NOT ARCHIVE_CRYPTO_${CRYPTO})
       IF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 	STRING(TOUPPER "${CRYPTO}" crypto)
 	SET(ALGID "")
@@ -461,9 +691,14 @@ MACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 	    SET(ALGID "CALG_SHA_512")
 	ENDIF ("${CRYPTO}" MATCHES "^SHA512$")
 
-	SET(SOURCE "#define ${crypto}_COMPILE_TEST
-#define _WIN32_WINNT ${_WIN32_WINNT}
-#define WINVER ${WINVER}
+    CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h)
+	FILE(READ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h"
+	     CONFDEFS_H)
+
+	SET(SOURCE "${CONFDEFS_H}
+
+#define ${crypto}_COMPILE_TEST
 #include <windows.h>
 #include <wincrypt.h>
 
@@ -478,15 +713,22 @@ main(int argc, char **argv)
 	FILE(WRITE "${SOURCE_FILE}" "${SOURCE}")
 	MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN")
 
+    IF(CMAKE_REQUIRED_LINKER_FLAGS)
+      SET(CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS
+        "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
+    ELSE(CMAKE_REQUIRED_LINKER_FLAGS)
+      SET(CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS)
+    ENDIF(CMAKE_REQUIRED_LINKER_FLAGS)
 	TRY_COMPILE(ARCHIVE_CRYPTO_${CRYPTO}_WIN
 	  ${CMAKE_BINARY_DIR}
 	  ${SOURCE_FILE}
-	  CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_CURRENT_SOURCE_DIR}/libarchive"
+	  CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive" ${CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS}
 	  OUTPUT_VARIABLE OUTPUT)
 
 	IF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 	    MESSAGE(STATUS
 	        "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- found")
+		SET(ARCHIVE_CRYPTO_${CRYPTO} 1)
 	ELSE (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 	    MESSAGE(STATUS
 	         "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- not found")
@@ -498,6 +740,7 @@ main(int argc, char **argv)
 	ENDIF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
 
       ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
+      ENDIF(NOT ARCHIVE_CRYPTO_${CRYPTO})
     ENDFOREACH(CRYPTO)
   ENDIF(WIN32 AND NOT CYGWIN)
 ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
@@ -511,7 +754,21 @@ ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 #
 MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
   IF(NOT HAVE_ICONV)
-    CHECK_C_SOURCE_COMPILES(
+    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
+    IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
+      #
+      # During checking iconv proto type, we should use -Werror to avoid the
+      # success of iconv detection with a warnig which success is a miss
+      # detection. So this needs for all build mode(even it's a release mode).
+      #
+      SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
+    ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
+    IF (MSVC)
+      # NOTE: /WX option is the same as gcc's -Werror option.
+      SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /WX")
+    ENDIF (MSVC)
+    #
+    LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
       "#include <stdlib.h>
        #include <iconv.h>
        int main() {
@@ -526,10 +783,12 @@ MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
       SET(HAVE_ICONV true)
       SET(ICONV_CONST ${TRY_ICONV_CONST})
     ENDIF(HAVE_ICONV_${LIB}_${TRY_ICONV_CONST})
+    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
   ENDIF(NOT HAVE_ICONV)
 ENDMACRO(CHECK_ICONV TRY_ICONV_CONST)
 
 IF(ENABLE_ICONV)
+  CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
   FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
   IF(ICONV_INCLUDE_DIR)
     #SET(INCLUDES ${INCLUDES} "iconv.h")
@@ -540,9 +799,30 @@ IF(ENABLE_ICONV)
     CHECK_ICONV("libc" "")
 
     # If iconv isn't in libc and we have a libiconv, try that.
-    FIND_LIBRARY(LIBICONV_PATH iconv)
+    FIND_LIBRARY(LIBICONV_PATH NAMES iconv libiconv)
     IF(NOT HAVE_ICONV AND LIBICONV_PATH)
       LIST(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBICONV_PATH})
+      # Test if a macro is needed for the library.
+      TRY_MACRO_FOR_LIBRARY(
+        "${ICONV_INCLUDE_DIR}" "${LIBICONV_PATH}"
+        COMPILES
+        "#include <iconv.h>\nint main() {return iconv_close((iconv_t)0);}"
+        "WITHOUT_LIBICONV_STATIC;LIBICONV_STATIC")
+      IF(NOT WITHOUT_LIBICONV_STATIC AND LIBICONV_STATIC)
+        ADD_DEFINITIONS(-DLIBICONV_STATIC)
+      ENDIF(NOT WITHOUT_LIBICONV_STATIC AND LIBICONV_STATIC)
+      #
+      # Set up CMAKE_REQUIRED_* for CHECK_ICONV
+      #
+      SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
+      SET(CMAKE_REQUIRED_LIBRARIES ${LIBICONV_PATH})
+      IF(LIBICONV_STATIC)
+        # LIBICONV_STATIC is necessary for the success of CHECK_ICONV
+        # on Windows.
+        SET(CMAKE_REQUIRED_DEFINITIONS "-DLIBICONV_STATIC")
+      ELSE(LIBICONV_STATIC)
+        SET(CMAKE_REQUIRED_DEFINITIONS)
+      ENDIF(LIBICONV_STATIC)
       CHECK_ICONV("libiconv" "const")
       CHECK_ICONV("libiconv" "")
       IF (HAVE_ICONV)
@@ -554,19 +834,36 @@ IF(ENABLE_ICONV)
   # Find locale_charset() for libiconv.
   #
   IF(LIBICONV_PATH)
+    SET(CMAKE_REQUIRED_DEFINITIONS)
+    SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
+    SET(CMAKE_REQUIRED_LIBRARIES)
     CHECK_INCLUDE_FILES("localcharset.h" HAVE_LOCALCHARSET_H)
-    CHECK_FUNCTION_EXISTS_GLIBC(locale_charset HAVE_LOCALE_CHARSET)
-    IF(NOT HAVE_LOCALE_CHARSET)
-      FIND_LIBRARY(LIBCHARSET_PATH charset)
-      IF(LIBCHARSET_PATH)
-        SET(CMAKE_REQUIRED_LIBRARIES ${LIBCHARSET_PATH})
+    FIND_LIBRARY(LIBCHARSET_PATH NAMES charset libcharset)
+    IF(LIBCHARSET_PATH)
+      SET(CMAKE_REQUIRED_LIBRARIES ${LIBCHARSET_PATH})
+      IF(WIN32 AND NOT CYGWIN)
+        # Test if a macro is needed for the library.
+        TRY_MACRO_FOR_LIBRARY(
+          "${ICONV_INCLUDE_DIR}" "${LIBCHARSET_PATH}"
+          COMPILES
+          "#include <localcharset.h>\nint main() {return locale_charset()?1:0;}"
+          "WITHOUT_LIBCHARSET_STATIC;LIBCHARSET_STATIC")
+        IF(NOT WITHOUT_LIBCHARSET_STATIC AND LIBCHARSET_STATIC)
+          ADD_DEFINITIONS(-DLIBCHARSET_STATIC)
+        ENDIF(NOT WITHOUT_LIBCHARSET_STATIC AND LIBCHARSET_STATIC)
+        IF(WITHOUT_LIBCHARSET_STATIC OR LIBCHARSET_STATIC)
+          SET(HAVE_LOCALE_CHARSET ON CACHE INTERNAL
+              "Have function locale_charset")
+        ENDIF(WITHOUT_LIBCHARSET_STATIC OR LIBCHARSET_STATIC)
+      ELSE(WIN32 AND NOT CYGWIN)
         CHECK_FUNCTION_EXISTS_GLIBC(locale_charset HAVE_LOCALE_CHARSET)
-        IF(HAVE_LOCALE_CHARSET)
-          LIST(APPEND ADDITIONAL_LIBS ${LIBCHARSET_PATH})
-        ENDIF(HAVE_LOCALE_CHARSET)
-      ENDIF(LIBCHARSET_PATH)
-    ENDIF(NOT HAVE_LOCALE_CHARSET)
+      ENDIF(WIN32 AND NOT CYGWIN)
+      IF(HAVE_LOCALE_CHARSET)
+        LIST(APPEND ADDITIONAL_LIBS ${LIBCHARSET_PATH})
+      ENDIF(HAVE_LOCALE_CHARSET)
+    ENDIF(LIBCHARSET_PATH)
   ENDIF(LIBICONV_PATH)
+  CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
 ELSE(ENABLE_ICONV)
   # Make sure ICONV variables are not in CACHE after ENABLE_ICONV disabled
   # (once enabled).
@@ -578,6 +875,10 @@ ELSE(ENABLE_ICONV)
   UNSET(HAVE_ICONV_libiconv_const CACHE)
   UNSET(ICONV_INCLUDE_DIR CACHE)
   UNSET(LIBICONV_PATH CACHE)
+  UNSET(LIBICONV_DLL CACHE)
+  UNSET(LIBICONV_STATIC CACHE)
+  UNSET(LIBCHARSET_DLL CACHE)
+  UNSET(LIBCHARSET_STATIC CACHE)
 ENDIF(ENABLE_ICONV)
 
 #
@@ -585,6 +886,7 @@ ENDIF(ENABLE_ICONV)
 #
 FIND_PACKAGE(LibXml2)
 IF(LIBXML2_FOUND)
+  CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
   INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})
   LIST(APPEND ADDITIONAL_LIBS ${LIBXML2_LIBRARIES})
   SET(HAVE_LIBXML2 1)
@@ -592,30 +894,150 @@ IF(LIBXML2_FOUND)
   SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR})
   CHECK_INCLUDE_FILES("libxml/xmlreader.h" HAVE_LIBXML_XMLREADER_H)
   CHECK_INCLUDE_FILES("libxml/xmlwriter.h" HAVE_LIBXML_XMLWRITER_H)
-  SET(CMAKE_REQUIRED_INCLUDES "")
+  # Test if a macro is needed for the library.
+  TRY_MACRO_FOR_LIBRARY(
+    "${ICONV_INCLUDE_DIR};${LIBXML2_INCLUDE_DIR}"
+    "ws2_32.lib;${ZLIB_LIBRARIES};${LIBICONV_PATH};${LIBXML2_LIBRARIES}"
+    COMPILES
+    "#include <stddef.h>\n#include <libxml/xmlreader.h>\nint main() {return xmlTextReaderRead((xmlTextReaderPtr)(void *)0);}"
+    "WITHOUT_LIBXML_STATIC;LIBXML_STATIC")
+  IF(NOT WITHOUT_LIBXML_STATIC AND LIBXML_STATIC)
+    ADD_DEFINITIONS(-DLIBXML_STATIC)
+  ENDIF(NOT WITHOUT_LIBXML_STATIC AND LIBXML_STATIC)
+  CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
 ELSE(LIBXML2_FOUND)
   #
   # Find Expat
   #
   FIND_PACKAGE(EXPAT)
   IF(EXPAT_FOUND)
+    CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
     INCLUDE_DIRECTORIES(${EXPAT_INCLUDE_DIR})
     LIST(APPEND ADDITIONAL_LIBS ${EXPAT_LIBRARIES})
     SET(HAVE_LIBEXPAT 1)
     LA_CHECK_INCLUDE_FILE("expat.h" HAVE_EXPAT_H)
+    CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
   ENDIF(EXPAT_FOUND)
 ENDIF(LIBXML2_FOUND)
+MARK_AS_ADVANCED(CLEAR LIBXML2_INCLUDE_DIR)
+MARK_AS_ADVANCED(CLEAR LIBXML2_LIBRARIES)
+
+#
+# POSIX Regular Expression support
+#
+IF(POSIX_REGEX_LIB MATCHES "^(AUTO|LIBC|LIBREGEX)$")
+  #
+  # If PCREPOSIX is not found or not requested, try using regex
+  # from libc or libregex
+  #
+  FIND_PATH(REGEX_INCLUDE_DIR regex.h)
+  IF(REGEX_INCLUDE_DIR)
+    CHECK_FUNCTION_EXISTS_GLIBC(regcomp HAVE_REGCOMP_LIBC)
+    #
+    # If libc does not provide regex, find libregex.
+    #
+    IF(NOT HAVE_REGCOMP_LIBC)
+      CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
+      FIND_LIBRARY(REGEX_LIBRARY regex)
+      IF(REGEX_LIBRARY)
+        SET(CMAKE_REQUIRED_LIBRARIES ${REGEX_LIBRARY})
+        CHECK_FUNCTION_EXISTS_GLIBC(regcomp HAVE_REGCOMP_LIBREGEX)
+        IF(HAVE_REGCOMP_LIBREGEX)
+          LIST(APPEND ADDITIONAL_LIBS ${REGEX_LIBRARY})
+          #
+          # If regex.h is not found, retry looking for regex.h at
+          # REGEX_INCLUDE_DIR
+          #
+          IF(NOT HAVE_REGEX_H)
+            UNSET(HAVE_REGEX_H CACHE)
+            INCLUDE_DIRECTORIES(${REGEX_INCLUDE_DIR})
+            SET(CMAKE_REQUIRED_INCLUDES ${REGEX_INCLUDE_DIR})
+            LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
+          ENDIF(NOT HAVE_REGEX_H)
+          # Test if a macro is needed for the library.
+          TRY_MACRO_FOR_LIBRARY(
+            "${REGEX_INCLUDE_DIR}" "${REGEX_LIBRARY}"
+            COMPILES
+            "#include <stddef.h>\n#include <regex.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
+            "USE_REGEX_DLL;USE_REGEX_STATIC")
+          IF(USE_REGEX_DLL)
+            ADD_DEFINITIONS(-DUSE_REGEX_DLL)
+          ELSEIF(USE_REGEX_STATIC)
+            ADD_DEFINITIONS(-DUSE_REGEX_STATIC)
+          ENDIF(USE_REGEX_DLL)
+        ENDIF(HAVE_REGCOMP_LIBREGEX)
+      ENDIF(REGEX_LIBRARY)
+      CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
+    ENDIF(NOT HAVE_REGCOMP_LIBC)
+  ENDIF(REGEX_INCLUDE_DIR)
+  IF(HAVE_REGCOMP_LIBC OR HAVE_REGCOMP_LIBREGEX)
+    SET(FOUND_POSIX_REGEX_LIB 1)
+  ENDIF(HAVE_REGCOMP_LIBC OR HAVE_REGCOMP_LIBREGEX)
+ENDIF(POSIX_REGEX_LIB MATCHES "^(AUTO|LIBC|LIBREGEX)$")
+
+IF(NOT FOUND_POSIX_REGEX_LIB AND POSIX_REGEX_LIB MATCHES "^(AUTO|LIBPCREPOSIX)$")
+  #
+  # If requested, try finding library for PCREPOSIX
+  #
+  FIND_PACKAGE(LibGCC)
+  FIND_PACKAGE(PCREPOSIX)
+  IF(PCREPOSIX_FOUND)
+    INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIR})
+    LIST(APPEND ADDITIONAL_LIBS ${PCREPOSIX_LIBRARIES})
+    # Test if a macro is needed for the library.
+    TRY_MACRO_FOR_LIBRARY(
+      "${PCRE_INCLUDE_DIR}" "${PCREPOSIX_LIBRARIES}"
+      COMPILES
+      "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
+      "WITHOUT_PCRE_STATIC;PCRE_STATIC")
+    IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+      ADD_DEFINITIONS(-DPCRE_STATIC)
+	ELSEIF(NOT WITHOUT_PCRE_STATIC AND NOT PCRE_STATIC AND PCRE_FOUND)
+	  # Determine if pcre static libraries are to be used.
+      LIST(APPEND ADDITIONAL_LIBS ${PCRE_LIBRARIES})
+      SET(TMP_LIBRARIES ${PCREPOSIX_LIBRARIES} ${PCRE_LIBRARIES})
+      MESSAGE(STATUS "trying again with -lpcre included")
+      TRY_MACRO_FOR_LIBRARY(
+        "${PCRE_INCLUDE_DIR}" "${TMP_LIBRARIES}"
+        COMPILES
+        "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
+        "WITHOUT_PCRE_STATIC;PCRE_STATIC")
+      IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+        ADD_DEFINITIONS(-DPCRE_STATIC)
+      ELSEIF(NOT WITHOUT_PCRE_STATIC AND NOT PCRE_STATIC AND MSVC AND LIBGCC_FOUND)
+        # When doing a Visual Studio build using pcre static libraries
+        # built using the mingw toolchain, -lgcc is needed to resolve
+        # ___chkstk_ms.
+        MESSAGE(STATUS "Visual Studio build detected, trying again with -lgcc included")
+        LIST(APPEND ADDITIONAL_LIBS ${LIBGCC_LIBRARIES})
+        SET(TMP_LIBRARIES ${PCREPOSIX_LIBRARIES} ${PCRE_LIBRARIES} ${LIBGCC_LIBRARIES})
+          TRY_MACRO_FOR_LIBRARY(
+            "${PCRE_INCLUDE_DIR}" "${TMP_LIBRARIES}"
+            COMPILES
+            "#include <pcreposix.h>\nint main() {regex_t r;return regcomp(&r, \"\", 0);}"
+            "WITHOUT_PCRE_STATIC;PCRE_STATIC")
+          IF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+            ADD_DEFINITIONS(-DPCRE_STATIC)
+          ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+      ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+    ENDIF(NOT WITHOUT_PCRE_STATIC AND PCRE_STATIC)
+  ENDIF(PCREPOSIX_FOUND)
+  MARK_AS_ADVANCED(CLEAR PCRE_INCLUDE_DIR)
+  MARK_AS_ADVANCED(CLEAR PCREPOSIX_LIBRARIES)
+  MARK_AS_ADVANCED(CLEAR PCRE_LIBRARIES)
+  MARK_AS_ADVANCED(CLEAR LIBGCC_LIBRARIES)
+ENDIF(NOT FOUND_POSIX_REGEX_LIB AND POSIX_REGEX_LIB MATCHES "^(AUTO|LIBPCREPOSIX)$")
 
 #
 # Check functions
 #
+CMAKE_PUSH_CHECK_STATE()	# Save the state of the variables
 IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
   #
   # During checking functions, we should use -fno-builtin to avoid the
   # failure of function detection which failure is an error "conflicting
   # types for built-in function" caused by using -Werror option.
   #
-  SET(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
   SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-builtin")
 ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
 CHECK_SYMBOL_EXISTS(_CrtSetReportMode "crtdbg.h" HAVE__CrtSetReportMode)
@@ -623,6 +1045,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS)
 CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
 CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
 CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R)
+CHECK_FUNCTION_EXISTS_GLIBC(dirfd HAVE_DIRFD)
 CHECK_FUNCTION_EXISTS_GLIBC(fchdir HAVE_FCHDIR)
 CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS)
 CHECK_FUNCTION_EXISTS_GLIBC(fchmod HAVE_FCHMOD)
@@ -654,7 +1077,6 @@ CHECK_FUNCTION_EXISTS_GLIBC(localtime_r HAVE_LOCALTIME_R)
 CHECK_FUNCTION_EXISTS_GLIBC(lstat HAVE_LSTAT)
 CHECK_FUNCTION_EXISTS_GLIBC(lutimes HAVE_LUTIMES)
 CHECK_FUNCTION_EXISTS_GLIBC(mbrtowc HAVE_MBRTOWC)
-CHECK_FUNCTION_EXISTS_GLIBC(mbsnrtowcs HAVE_MBSNRTOWCS)
 CHECK_FUNCTION_EXISTS_GLIBC(memmove HAVE_MEMMOVE)
 CHECK_FUNCTION_EXISTS_GLIBC(mkdir HAVE_MKDIR)
 CHECK_FUNCTION_EXISTS_GLIBC(mkfifo HAVE_MKFIFO)
@@ -664,6 +1086,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(nl_langinfo HAVE_NL_LANGINFO)
 CHECK_FUNCTION_EXISTS_GLIBC(openat HAVE_OPENAT)
 CHECK_FUNCTION_EXISTS_GLIBC(pipe HAVE_PIPE)
 CHECK_FUNCTION_EXISTS_GLIBC(poll HAVE_POLL)
+CHECK_FUNCTION_EXISTS_GLIBC(posix_spawnp HAVE_POSIX_SPAWNP)
 CHECK_FUNCTION_EXISTS_GLIBC(readlink HAVE_READLINK)
 CHECK_FUNCTION_EXISTS_GLIBC(select HAVE_SELECT)
 CHECK_FUNCTION_EXISTS_GLIBC(setenv HAVE_SETENV)
@@ -688,7 +1111,6 @@ CHECK_FUNCTION_EXISTS_GLIBC(wcrtomb HAVE_WCRTOMB)
 CHECK_FUNCTION_EXISTS_GLIBC(wcscmp HAVE_WCSCMP)
 CHECK_FUNCTION_EXISTS_GLIBC(wcscpy HAVE_WCSCPY)
 CHECK_FUNCTION_EXISTS_GLIBC(wcslen HAVE_WCSLEN)
-CHECK_FUNCTION_EXISTS_GLIBC(wcsnrtombs HAVE_WCSNRTOMBS)
 CHECK_FUNCTION_EXISTS_GLIBC(wctomb HAVE_WCTOMB)
 CHECK_FUNCTION_EXISTS_GLIBC(_ctime64_s HAVE__CTIME64_S)
 CHECK_FUNCTION_EXISTS_GLIBC(_fseeki64 HAVE__FSEEKI64)
@@ -705,21 +1127,18 @@ CHECK_FUNCTION_EXISTS(vprintf HAVE_VPRINTF)
 CHECK_FUNCTION_EXISTS(wmemcmp HAVE_WMEMCMP)
 CHECK_FUNCTION_EXISTS(wmemcpy HAVE_WMEMCPY)
 
-# Restore CMAKE_REQUIRED_FLAGS
-IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
-  SET(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS})
-ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
+CMAKE_POP_CHECK_STATE()	# Restore the state of the variables
 
 # Make sure we have the POSIX version of readdir_r, not the
 # older 2-argument version.
-CHECK_C_SOURCE_COMPILES(
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
   "#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}"
   HAVE_READDIR_R)
 
 
 # Only detect readlinkat() if we also have AT_FDCWD in unistd.h.
 # NOTE: linux requires fcntl.h for AT_FDCWD.
-CHECK_C_SOURCE_COMPILES(
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
   "#include <fcntl.h>\n#include <unistd.h>\nint main() {char buf[10]; return readlinkat(AT_FDCWD, \"\", buf, 0);}"
   HAVE_READLINKAT)
 
@@ -728,10 +1147,10 @@ CHECK_C_SOURCE_COMPILES(
 # of interest and verify that the result can be linked.
 # CHECK_FUNCTION_EXISTS doesn't accept a header argument,
 # CHECK_SYMBOL_EXISTS doesn't test linkage.
-CHECK_C_SOURCE_COMPILES(
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
   "#include <sys/mkdev.h>\nint main() { return major(256); }"
   MAJOR_IN_MKDEV)
-CHECK_C_SOURCE_COMPILES(
+LIBARCHIVE_CHECK_C_SOURCE_COMPILES(
   "#include <sys/sysmacros.h>\nint main() { return major(256); }"
   MAJOR_IN_SYSMACROS)
 
@@ -795,6 +1214,12 @@ CHECK_STRUCT_MEMBER("struct stat" st_blksize
 # Check for st_flags in struct stat (BSD fflags)
 CHECK_STRUCT_MEMBER("struct stat" st_flags
     "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_FLAGS)
+
+IF(HAVE_SYS_STATVFS_H)
+  CHECK_STRUCT_MEMBER("struct statvfs" f_iosize
+    "sys/types.h;sys/statvfs.h" HAVE_STRUCT_STATVFS_F_IOSIZE)
+ENDIF()
+
 #
 #
 CHECK_STRUCT_MEMBER("struct tm" tm_sec
@@ -1021,6 +1446,8 @@ IF(ENABLE_ACL)
   CHECK_FUNCTION_EXISTS(acl_get_perm_np HAVE_ACL_GET_PERM_NP)
   CHECK_FUNCTION_EXISTS(acl_get_link HAVE_ACL_GET_LINK)
   CHECK_FUNCTION_EXISTS(acl_get_link_np HAVE_ACL_GET_LINK_NP)
+  CHECK_FUNCTION_EXISTS(acl_is_trivial_np HAVE_ACL_IS_TRIVIAL_NP)
+  CHECK_FUNCTION_EXISTS(acl_set_link_np HAVE_ACL_SET_LINK_NP)
 
   # MacOS has an acl.h that isn't POSIX.  It can be detected by
   # checking for ACL_USER
@@ -1089,11 +1516,6 @@ IF(MSVC)
   ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
 ENDIF(MSVC)
 
-# We need CoreServices on Mac OS.
-IF(APPLE)
-  LIST(APPEND ADDITIONAL_LIBS "-framework CoreServices")
-ENDIF(APPLE)
-
 IF(ENABLE_TEST)
   ADD_CUSTOM_TARGET(run_all_tests)
 ENDIF(ENABLE_TEST)
diff --git a/build/cmake/CheckFileOffsetBits.cmake b/build/cmake/CheckFileOffsetBits.cmake
index 4132b38..b347c93 100644
--- a/build/cmake/CheckFileOffsetBits.cmake
+++ b/build/cmake/CheckFileOffsetBits.cmake
@@ -19,7 +19,7 @@ GET_FILENAME_COMPONENT(_selfdir_CheckFileOffsetBits
 
 MACRO (CHECK_FILE_OFFSET_BITS)
   IF(NOT DEFINED _FILE_OFFSET_BITS)
-    MESSAGE(STATUS "Cheking _FILE_OFFSET_BITS for large files")
+    MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files")
     TRY_COMPILE(__WITHOUT_FILE_OFFSET_BITS_64
       ${CMAKE_CURRENT_BINARY_DIR}
       ${_selfdir_CheckFileOffsetBits}/CheckFileOffsetBits.c
@@ -33,10 +33,10 @@ MACRO (CHECK_FILE_OFFSET_BITS)
 
     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")
+      MESSAGE(STATUS "Checking _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")
+      MESSAGE(STATUS "Checking _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)
 
diff --git a/build/cmake/FindLibGCC.cmake b/build/cmake/FindLibGCC.cmake
new file mode 100644
index 0000000..7985f2b
--- /dev/null
+++ b/build/cmake/FindLibGCC.cmake
@@ -0,0 +1,22 @@
+# - Find libgcc
+# Find the libgcc library.
+#
+#  LIBGCC_LIBRARIES      - List of libraries when using libgcc
+#  LIBGCC_FOUND          - True if libgcc found.
+
+IF (LIBGCC_LIBRARY)
+  # Already in cache, be silent
+  SET(LIBGCC_FIND_QUIETLY TRUE)
+ENDIF (LIBGCC_LIBRARY)
+
+FIND_LIBRARY(LIBGCC_LIBRARY NAMES gcc libgcc)
+
+# handle the QUIETLY and REQUIRED arguments and set LIBGCC_FOUND to TRUE if 
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBGCC DEFAULT_MSG LIBGCC_LIBRARY)
+
+IF(LIBGCC_FOUND)
+  SET(LIBGCC_LIBRARIES ${LIBGCC_LIBRARY})
+  SET(HAVE_LIBGCC 1)
+ENDIF(LIBGCC_FOUND)
diff --git a/build/cmake/FindNettle.cmake b/build/cmake/FindNettle.cmake
new file mode 100644
index 0000000..1f66610
--- /dev/null
+++ b/build/cmake/FindNettle.cmake
@@ -0,0 +1,23 @@
+# - Find Nettle
+# Find the Nettle include directory and library
+#
+#  NETTLE_INCLUDE_DIR    - where to find <nettle/sha.h>, etc.
+#  NETTLE_LIBRARIES      - List of libraries when using libnettle.
+#  NETTLE_FOUND          - True if libnettle found.
+
+IF (NETTLE_INCLUDE_DIR)
+  # Already in cache, be silent
+  SET(NETTLE_FIND_QUIETLY TRUE)
+ENDIF (NETTLE_INCLUDE_DIR)
+
+FIND_PATH(NETTLE_INCLUDE_DIR nettle/md5.h nettle/ripemd160.h nettle/sha.h)
+FIND_LIBRARY(NETTLE_LIBRARY NAMES nettle libnettle)
+
+# handle the QUIETLY and REQUIRED arguments and set NETTLE_FOUND to TRUE if 
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(NETTLE DEFAULT_MSG NETTLE_LIBRARY NETTLE_INCLUDE_DIR)
+
+IF(NETTLE_FOUND)
+  SET(NETTLE_LIBRARIES ${NETTLE_LIBRARY})
+ENDIF(NETTLE_FOUND)
diff --git a/build/cmake/FindPCREPOSIX.cmake b/build/cmake/FindPCREPOSIX.cmake
new file mode 100644
index 0000000..7cc40ec
--- /dev/null
+++ b/build/cmake/FindPCREPOSIX.cmake
@@ -0,0 +1,34 @@
+# - Find pcreposix
+# Find the native PCRE and PCREPOSIX include and libraries
+#
+#  PCRE_INCLUDE_DIR    - where to find pcreposix.h, etc.
+#  PCREPOSIX_LIBRARIES - List of libraries when using libpcreposix.
+#  PCRE_LIBRARIES      - List of libraries when using libpcre.
+#  PCREPOSIX_FOUND     - True if libpcreposix found.
+#  PCRE_FOUND          - True if libpcre found.
+
+IF (PCRE_INCLUDE_DIR)
+  # Already in cache, be silent
+  SET(PCRE_FIND_QUIETLY TRUE)
+ENDIF (PCRE_INCLUDE_DIR)
+
+FIND_PATH(PCRE_INCLUDE_DIR pcreposix.h)
+FIND_LIBRARY(PCREPOSIX_LIBRARY NAMES pcreposix libpcreposix)
+FIND_LIBRARY(PCRE_LIBRARY NAMES pcre libpcre)
+
+# handle the QUIETLY and REQUIRED arguments and set PCREPOSIX_FOUND to TRUE if 
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCREPOSIX DEFAULT_MSG PCREPOSIX_LIBRARY PCRE_INCLUDE_DIR)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY)
+
+IF(PCREPOSIX_FOUND)
+  SET(PCREPOSIX_LIBRARIES ${PCREPOSIX_LIBRARY})
+  SET(HAVE_LIBPCREPOSIX 1)
+  SET(HAVE_PCREPOSIX_H 1)
+ENDIF(PCREPOSIX_FOUND)
+
+IF(PCRE_FOUND)
+  SET(PCRE_LIBRARIES ${PCRE_LIBRARY})
+  SET(HAVE_LIBPCRE 1)
+ENDIF(PCRE_FOUND)
diff --git a/build/cmake/LibarchiveCheckCSourceCompiles.cmake b/build/cmake/LibarchiveCheckCSourceCompiles.cmake
new file mode 100644
index 0000000..6b6f593
--- /dev/null
+++ b/build/cmake/LibarchiveCheckCSourceCompiles.cmake
@@ -0,0 +1,106 @@
+# - Check if given C source compiles and links into an executable
+# CHECK_C_SOURCE_COMPILES(<code> <var> [FAIL_REGEX <fail-regex>])
+#  <code>       - source code to try to compile, must define 'main'
+#  <var>        - variable to store whether the source code compiled
+#  <fail-regex> - fail if test output matches this regex
+# 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
+#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+#=============================================================================
+# Copyright 2005-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+#
+# Extra arguments added by libarchive
+# CMAKE_REQUIRED_LINKER_FLAGS = string of linker command line flags
+#
+
+include(CMakeExpandImportedTargets)
+
+
+macro(LIBARCHIVE_CHECK_C_SOURCE_COMPILES SOURCE VAR)
+  if("${VAR}" MATCHES "^${VAR}$")
+    set(_FAIL_REGEX)
+    set(_key)
+    foreach(arg ${ARGN})
+      if("${arg}" MATCHES "^(FAIL_REGEX)$")
+        set(_key "${arg}")
+      elseif(_key)
+        list(APPEND _${_key} "${arg}")
+      else()
+        message(FATAL_ERROR "Unknown argument:\n  ${arg}\n")
+      endif()
+    endforeach()
+    set(MACRO_CHECK_FUNCTION_DEFINITIONS
+      "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
+    if(CMAKE_REQUIRED_LIBRARIES)
+      # this one translates potentially used imported library targets to their files on disk
+      CMAKE_EXPAND_IMPORTED_TARGETS(_ADJUSTED_CMAKE_REQUIRED_LIBRARIES  LIBRARIES  ${CMAKE_REQUIRED_LIBRARIES} CONFIGURATION "${CMAKE_TRY_COMPILE_CONFIGURATION}")
+      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES
+        "-DLINK_LIBRARIES:STRING=${_ADJUSTED_CMAKE_REQUIRED_LIBRARIES}")
+    else()
+      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
+    endif()
+    if(CMAKE_REQUIRED_INCLUDES)
+      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES
+        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+    else()
+      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
+    endif()
+	if(CMAKE_REQUIRED_LINKER_FLAGS)
+	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS
+	    "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
+	else()
+	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS)
+	endif()
+    file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
+      "${SOURCE}\n")
+
+    message(STATUS "Performing Test ${VAR}")
+    try_compile(${VAR}
+      ${CMAKE_BINARY_DIR}
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
+      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} ${CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS}
+      "${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
+      "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
+      OUTPUT_VARIABLE OUTPUT)
+
+    foreach(_regex ${_FAIL_REGEX})
+      if("${OUTPUT}" MATCHES "${_regex}")
+        set(${VAR} 0)
+      endif()
+    endforeach()
+
+    if(${VAR})
+      set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
+      message(STATUS "Performing Test ${VAR} - Success")
+      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+        "Performing C SOURCE FILE Test ${VAR} succeded with the following output:\n"
+        "${OUTPUT}\n"
+        "Source file was:\n${SOURCE}\n")
+    else()
+      message(STATUS "Performing Test ${VAR} - Failed")
+      set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
+      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+        "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n"
+        "${OUTPUT}\n"
+        "Source file was:\n${SOURCE}\n")
+    endif()
+  endif()
+endmacro()
+
diff --git a/build/cmake/LibarchiveCheckCSourceRuns.cmake b/build/cmake/LibarchiveCheckCSourceRuns.cmake
new file mode 100644
index 0000000..498f522
--- /dev/null
+++ b/build/cmake/LibarchiveCheckCSourceRuns.cmake
@@ -0,0 +1,102 @@
+# - Check if the given C source code compiles and runs.
+# CHECK_C_SOURCE_RUNS(<code> <var>)
+#  <code>   - source code to try to compile
+#  <var>    - variable to store the result
+#             (1 for success, empty for failure)
+# 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
+#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+#=============================================================================
+# Copyright 2006-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+#
+# Extra arguments added by libarchive
+# CMAKE_REQUIRED_LINKER_FLAGS = string of linker command line flags
+#
+
+include(CMakeExpandImportedTargets)
+
+
+macro(LIBARCHIVE_CHECK_C_SOURCE_RUNS SOURCE VAR)
+  if("${VAR}" MATCHES "^${VAR}$")
+    set(MACRO_CHECK_FUNCTION_DEFINITIONS
+      "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
+    if(CMAKE_REQUIRED_LIBRARIES)
+      # this one translates potentially used imported library targets to their files on disk
+      CMAKE_EXPAND_IMPORTED_TARGETS(_ADJUSTED_CMAKE_REQUIRED_LIBRARIES  LIBRARIES  ${CMAKE_REQUIRED_LIBRARIES} CONFIGURATION "${CMAKE_TRY_COMPILE_CONFIGURATION}")
+      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES
+        "-DLINK_LIBRARIES:STRING=${_ADJUSTED_CMAKE_REQUIRED_LIBRARIES}")
+    else()
+      set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
+    endif()
+    if(CMAKE_REQUIRED_INCLUDES)
+      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES
+        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+    else()
+      set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
+    endif()
+	if(CMAKE_REQUIRED_LINKER_FLAGS)
+	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS
+	    "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
+	else()
+	  set(CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS)
+	endif()
+    file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
+      "${SOURCE}\n")
+
+    message(STATUS "Performing Test ${VAR}")
+    try_run(${VAR}_EXITCODE ${VAR}_COMPILED
+      ${CMAKE_BINARY_DIR}
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
+      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} ${CHECK_C_SOURCE_COMPILES_ADD_LINKER_FLAGS}
+      -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH}
+      "${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
+      "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
+      COMPILE_OUTPUT_VARIABLE OUTPUT)
+    # if it did not compile make the return value fail code of 1
+    if(NOT ${VAR}_COMPILED)
+      set(${VAR}_EXITCODE 1)
+    endif()
+    # if the return value was 0 then it worked
+    if("${${VAR}_EXITCODE}" EQUAL 0)
+      set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
+      message(STATUS "Performing Test ${VAR} - Success")
+      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+        "Performing C SOURCE FILE Test ${VAR} succeded with the following output:\n"
+        "${OUTPUT}\n"
+        "Return value: ${${VAR}}\n"
+        "Source file was:\n${SOURCE}\n")
+    else()
+      if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES  "FAILED_TO_RUN")
+        set(${VAR} "${${VAR}_EXITCODE}")
+      else()
+        set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
+      endif()
+
+      message(STATUS "Performing Test ${VAR} - Failed")
+      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+        "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n"
+        "${OUTPUT}\n"
+        "Return value: ${${VAR}_EXITCODE}\n"
+        "Source file was:\n${SOURCE}\n")
+
+    endif()
+  endif()
+endmacro()
+
diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in
index b169051..c04314e 100644
--- a/build/cmake/config.h.in
+++ b/build/cmake/config.h.in
@@ -390,6 +390,9 @@ typedef uint64_t uintmax_t;
    */
 #cmakedefine HAVE_DIRENT_H 1
 
+/* Define to 1 if you have the `dirfd' function. */
+#cmakedefine HAVE_DIRFD 1
+
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #cmakedefine HAVE_DLFCN_H 1
 
@@ -576,12 +579,27 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the `expat' library (-lexpat). */
 #cmakedefine HAVE_LIBEXPAT 1
 
+/* Define to 1 if you have the `gcc' library (-lgcc). */
+#cmakedefine HAVE_LIBGCC 1
+
 /* Define to 1 if you have the `lzma' library (-llzma). */
 #cmakedefine HAVE_LIBLZMA 1
 
 /* Define to 1 if you have the `lzmadec' library (-llzmadec). */
 #cmakedefine HAVE_LIBLZMADEC 1
 
+/* Define to 1 if you have the `lzo2' library (-llzo2). */
+#cmakedefine HAVE_LIBLZO2 1
+
+/* Define to 1 if you have the `nettle' library (-lnettle). */
+#cmakedefine HAVE_LIBNETTLE 1
+
+/* Define to 1 if you have the `pcre' library (-lpcre). */
+#cmakedefine HAVE_LIBPCRE 1
+
+/* Define to 1 if you have the `pcreposix' library (-lpcreposix). */
+#cmakedefine HAVE_LIBPCREPOSIX 1
+
 /* Define to 1 if you have the `xml2' library (-lxml2). */
 #cmakedefine HAVE_LIBXML2 1
 
@@ -609,6 +627,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <linux/magic.h> header file. */
 #cmakedefine HAVE_LINUX_MAGIC_H 1
 
+/* Define to 1 if you have the <linux/types.h> header file. */
+#cmakedefine HAVE_LINUX_TYPES_H 1
+
 /* Define to 1 if you have the `listea' function. */
 #cmakedefine HAVE_LISTEA 1
 
@@ -658,12 +679,15 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <lzma.h> header file. */
 #cmakedefine HAVE_LZMA_H 1
 
+/* Define to 1 if you have the <lzo/lzo1x.h> header file. */
+#cmakedefine HAVE_LZO_LZO1X_H 1
+
+/* Define to 1 if you have the <lzo/lzoconf.h> header file. */
+#cmakedefine HAVE_LZO_LZOCONF_H 1
+
 /* Define to 1 if you have the `mbrtowc' function. */
 #cmakedefine HAVE_MBRTOWC 1
 
-/* Define to 1 if you have the `mbsnrtowcs' function. */
-#cmakedefine HAVE_MBSNRTOWCS 1
-
 /* Define to 1 if you have the `memmove' function. */
 #cmakedefine HAVE_MEMMOVE 1
 
@@ -685,6 +709,15 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
 #cmakedefine HAVE_NDIR_H 1
 
+/* Define to 1 if you have the <nettle/md5.h> header file. */
+#cmakedefine HAVE_NETTLE_MD5_H 1
+
+/* Define to 1 if you have the <nettle/ripemd160.h> header file. */
+#cmakedefine HAVE_NETTLE_RIPEMD160_H 1
+
+/* Define to 1 if you have the <nettle/sha.h> header file. */
+#cmakedefine HAVE_NETTLE_SHA_H 1
+
 /* Define to 1 if you have the `nl_langinfo' function. */
 #cmakedefine HAVE_NL_LANGINFO 1
 
@@ -694,6 +727,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <paths.h> header file. */
 #cmakedefine HAVE_PATHS_H 1
 
+/* Define to 1 if you have the <pcreposix.h> header file. */
+#cmakedefine HAVE_PCREPOSIX_H 1
+
 /* Define to 1 if you have the `pipe' function. */
 #cmakedefine HAVE_PIPE 1
 
@@ -703,6 +739,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <poll.h> header file. */
 #cmakedefine HAVE_POLL_H 1
 
+/* Define to 1 if you have the `posix_spawnp' function. */
+#cmakedefine HAVE_POSIX_SPAWNP 1
+
 /* Define to 1 if you have the <process.h> header file. */
 #cmakedefine HAVE_PROCESS_H 1
 
@@ -736,6 +775,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <signal.h> header file. */
 #cmakedefine HAVE_SIGNAL_H 1
 
+/* Define to 1 if you have the <spawn.h> header file. */
+#cmakedefine HAVE_SPAWN_H 1
+
 /* Define to 1 if you have the `statfs' function. */
 #cmakedefine HAVE_STATFS 1
 
@@ -782,6 +824,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if `f_namemax' is a member of `struct statfs'. */
 #cmakedefine HAVE_STRUCT_STATFS_F_NAMEMAX 1
 
+/* Define to 1 if `f_iosize' is a member of `struct statvfs'. */
+#cmakedefine HAVE_STRUCT_STATVFS_F_IOSIZE 1
+
 /* Define to 1 if `st_birthtime' is a member of `struct stat'. */
 #cmakedefine HAVE_STRUCT_STAT_ST_BIRTHTIME 1
 
@@ -943,9 +988,6 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the `wcslen' function. */
 #cmakedefine HAVE_WCSLEN 1
 
-/* Define to 1 if you have the `wcsnrtombs' function. */
-#cmakedefine HAVE_WCSNRTOMBS 1
-
 /* Define to 1 if you have the `wctomb' function. */
 #cmakedefine HAVE_WCTOMB 1
 
diff --git a/build/utils/gen_archive_string_composition_h.sh b/build/utils/gen_archive_string_composition_h.sh
old mode 100644
new mode 100755
index 95dbe16..925de5c
--- a/build/utils/gen_archive_string_composition_h.sh
+++ b/build/utils/gen_archive_string_composition_h.sh
@@ -1,10 +1,13 @@
 #!/bin/sh
 #
-# This needs http://unicode.org/Public/UNIDATA/UnicodeData.txt
+# This needs http://unicode.org/Public/6.0.0/ucd/UnicodeData.txt
 #
 inputfile="$1"	# Expect UnicodeData.txt
 outfile=archive_string_composition.h
 pickout=/tmp/mk_unicode_composition_tbl$$.awk
+pickout2=/tmp/mk_unicode_composition_tbl2$$.awk
+#nfdtmp=/tmp/mk_unicode_decomposition_tmp$$.txt
+nfdtmp="nfdtmpx"
 #################################################################################
 #
 # Append the file header of "archive_string_composition.h"
@@ -14,7 +17,7 @@ append_copyright()
 {
 cat > ${outfile} <<CR_END
 /*-
- * Copyright (c) 2011 libarchive Project
+ * Copyright (c) 2011-2012 libarchive Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,7 +47,7 @@ cat > ${outfile} <<CR_END
 /*
  * ATTENTION!
  *  This file is generated by build/utils/gen_archive_string_composition_h.sh
- *  from http://unicode.org/Public/UNIDATA/UnicodeData.txt
+ *  from http://unicode.org/Public/6.0.0/ucd/UnicodeData.txt
  *
  *  See also http://unicode.org/report/tr15/
  */
@@ -76,6 +79,7 @@ BEGIN {
   min = "";
   max = "";
   cmd="sort | awk -F ' ' '{printf \"\\\\t{ 0x%s , 0x%s , 0x%s },\\\\n\",\$1,\$2,\$3}'"
+  nfdtbl="${nfdtmp}"
   print "static const struct unicode_composition_table u_composition_table[] = {"
 }
 END {
@@ -178,7 +182,6 @@ END {
   }
   print "};"
   print ""
-  print "#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */"
 }
 #
 #
@@ -241,7 +244,7 @@ function hextoi(hex)
 #}
 #
 # Exclusion code points specified by  
-# http://unicode.org/Public/UNIDATA/CompositionExclusions.txt
+# http://unicode.org/Public/6.0.0/ucd/CompositionExclusions.txt
 ##
 # 1. Script Specifices
 ##
@@ -404,6 +407,35 @@ function hextoi(hex)
         print "0"cp[1], "0"cp[2], "0"\$1 | cmd
     else
         print cp[1], cp[2], \$1 | cmd
+    # NFC ==> NFD table.
+    if (length(\$1) == 4)
+        print "0"\$1, "0"cp[1], "0"cp[2] >>nfdtbl
+    else
+        print \$1, cp[1], cp[2] >>nfdtbl
+}
+AWK_END
+#################################################################################
+# awk script
+#
+#################################################################################
+cat > ${pickout2} <<AWK_END
+#
+BEGIN {
+  FS = " "
+  print "struct unicode_decomposition_table {"
+  print "\tuint32_t nfc;"
+  print "\tuint32_t cp1;"
+  print "\tuint32_t cp2;"
+  print "};"
+  print ""
+  print "static const struct unicode_decomposition_table u_decomposition_table[] = {"
+}
+END {
+  print "};"
+  print ""
+}
+{
+printf "\t{ 0x%s , 0x%s , 0x%s },\n", \$1, \$2, \$3;
 }
 AWK_END
 #################################################################################
@@ -413,6 +445,11 @@ AWK_END
 #################################################################################
 append_copyright
 awk -f ${pickout} ${inputfile} >> ${outfile}
+awk -f ${pickout2} ${nfdtmp} >> ${outfile}
+echo "#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */" >> ${outfile}
+echo "" >> ${outfile}
 #
 # Remove awk the script.
 rm ${pickout}
+rm ${pickout2}
+rm ${nfdtmp}
diff --git a/build/version b/build/version
index ee575c8..937b126 100644
--- a/build/version
+++ b/build/version
@@ -1 +1 @@
-3000002
+3001002
diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt
index a801fb2..ecb0409 100644
--- a/libarchive/CMakeLists.txt
+++ b/libarchive/CMakeLists.txt
@@ -15,6 +15,9 @@ SET(include_HEADERS
 SET(libarchive_SOURCES
   archive_acl.c
   archive_check_magic.c
+  archive_cmdline.c
+  archive_cmdline_private.h
+  archive_crc32.h
   archive_crypto.c
   archive_crypto_private.h
   archive_endian.h
@@ -28,8 +31,12 @@ SET(libarchive_SOURCES
   archive_entry_stat.c
   archive_entry_strmode.c
   archive_entry_xattr.c
+  archive_getdate.c
+  archive_match.c
   archive_options.c
   archive_options_private.h
+  archive_pathmatch.c
+  archive_pathmatch.h
   archive_platform.h
   archive_ppmd_private.h
   archive_ppmd7.c
@@ -38,6 +45,7 @@ SET(libarchive_SOURCES
   archive_rb.c
   archive_rb.h
   archive_read.c
+  archive_read_append_filter.c
   archive_read_data_into_fd.c
   archive_read_disk_entry_from_file.c
   archive_read_disk_posix.c
@@ -49,11 +57,15 @@ SET(libarchive_SOURCES
   archive_read_open_filename.c
   archive_read_open_memory.c
   archive_read_private.h
+  archive_read_set_format.c
   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_grzip.c
+  archive_read_support_filter_lrzip.c
+  archive_read_support_filter_lzop.c
   archive_read_support_filter_none.c
   archive_read_support_filter_program.c
   archive_read_support_filter_rpm.c
@@ -81,6 +93,7 @@ SET(libarchive_SOURCES
   archive_util.c
   archive_virtual.c
   archive_write.c
+  archive_write_disk_acl.c
   archive_write_disk_posix.c
   archive_write_disk_private.h
   archive_write_disk_set_standard_lookup.c
@@ -89,11 +102,18 @@ SET(libarchive_SOURCES
   archive_write_open_file.c
   archive_write_open_filename.c
   archive_write_open_memory.c
+  archive_write_add_filter.c
+  archive_write_add_filter_b64encode.c
+  archive_write_add_filter_by_name.c
   archive_write_add_filter_bzip2.c
   archive_write_add_filter_compress.c
+  archive_write_add_filter_grzip.c
   archive_write_add_filter_gzip.c
+  archive_write_add_filter_lrzip.c
+  archive_write_add_filter_lzop.c
   archive_write_add_filter_none.c
   archive_write_add_filter_program.c
+  archive_write_add_filter_uuencode.c
   archive_write_add_filter_xz.c
   archive_write_set_format.c
   archive_write_set_format_7zip.c
@@ -107,10 +127,11 @@ SET(libarchive_SOURCES
   archive_write_set_format_pax.c
   archive_write_set_format_shar.c
   archive_write_set_format_ustar.c
+  archive_write_set_format_v7tar.c
   archive_write_set_format_xar.c
   archive_write_set_format_zip.c
   archive_write_set_options.c
-  filter_fork.c
+  filter_fork_posix.c
   filter_fork.h
 )
 
diff --git a/libarchive/archive.h b/libarchive/archive.h
index 13cbe79..f56bc38 100644
--- a/libarchive/archive.h
+++ b/libarchive/archive.h
@@ -56,23 +56,14 @@
 # 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 */
+# include <unistd.h>  /* ssize_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
 
 /*
@@ -106,6 +97,12 @@
 #define	__LA_PRINTF(fmtarg, firstvararg)	/* nothing */
 #endif
 
+#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
+# define __LA_DEPRECATED __attribute__((deprecated))
+#else
+# define __LA_DEPRECATED
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -127,13 +124,13 @@ extern "C" {
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define	ARCHIVE_VERSION_NUMBER 3000002
+#define	ARCHIVE_VERSION_NUMBER 3001002
 __LA_DECL int		archive_version_number(void);
 
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define	ARCHIVE_VERSION_STRING "libarchive 3.0.2"
+#define	ARCHIVE_VERSION_STRING "libarchive 3.1.2"
 __LA_DECL const char *	archive_version_string(void);
 
 /* Declare our basic types. */
@@ -203,6 +200,13 @@ typedef int	archive_open_callback(struct archive *, void *_client_data);
 
 typedef int	archive_close_callback(struct archive *, void *_client_data);
 
+/* Switches from one client data object to the next/prev client data object.
+ * This is useful for reading from different data blocks such as a set of files
+ * that make up one large file.
+ */
+typedef int archive_switch_callback(struct archive *, void *_client_data1,
+			    void *_client_data2);
+
 /*
  * Codes to identify various stream filters.
  */
@@ -216,6 +220,9 @@ typedef int	archive_close_callback(struct archive *, void *_client_data);
 #define	ARCHIVE_FILTER_UU	7
 #define	ARCHIVE_FILTER_RPM	8
 #define	ARCHIVE_FILTER_LZIP	9
+#define	ARCHIVE_FILTER_LRZIP	10
+#define	ARCHIVE_FILTER_LZOP	11
+#define	ARCHIVE_FILTER_GRZIP	12
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
 #define	ARCHIVE_COMPRESSION_NONE	ARCHIVE_FILTER_NONE
@@ -228,6 +235,7 @@ typedef int	archive_close_callback(struct archive *, void *_client_data);
 #define	ARCHIVE_COMPRESSION_UU		ARCHIVE_FILTER_UU
 #define	ARCHIVE_COMPRESSION_RPM		ARCHIVE_FILTER_RPM
 #define	ARCHIVE_COMPRESSION_LZIP	ARCHIVE_FILTER_LZIP
+#define	ARCHIVE_COMPRESSION_LRZIP	ARCHIVE_FILTER_LRZIP
 #endif
 
 /*
@@ -300,37 +308,49 @@ __LA_DECL struct archive	*archive_read_new(void);
  */
 
 #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_all(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_bzip2(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_compress(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_gzip(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_lzip(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_lzma(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_none(struct archive *)
+		__LA_DEPRECATED;
 __LA_DECL int archive_read_support_compression_program(struct archive *,
-		     const char *command);
+		     const char *command) __LA_DEPRECATED;
 __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 *);
+		 const void * /* match */, size_t) __LA_DEPRECATED;
+
+__LA_DECL int archive_read_support_compression_rpm(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_uu(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_xz(struct archive *)
+		__LA_DEPRECATED;
 #endif
 
 __LA_DECL int archive_read_support_filter_all(struct archive *);
 __LA_DECL int archive_read_support_filter_bzip2(struct archive *);
 __LA_DECL int archive_read_support_filter_compress(struct archive *);
 __LA_DECL int archive_read_support_filter_gzip(struct archive *);
+__LA_DECL int archive_read_support_filter_grzip(struct archive *);
+__LA_DECL int archive_read_support_filter_lrzip(struct archive *);
 __LA_DECL int archive_read_support_filter_lzip(struct archive *);
 __LA_DECL int archive_read_support_filter_lzma(struct archive *);
+__LA_DECL int archive_read_support_filter_lzop(struct archive *);
 __LA_DECL int archive_read_support_filter_none(struct archive *);
 __LA_DECL int archive_read_support_filter_program(struct archive *,
 		     const char *command);
 __LA_DECL int archive_read_support_filter_program_signature
-		(struct archive *, const char *,
+		(struct archive *, const char * /* cmd */,
 				    const void * /* match */, size_t);
-
 __LA_DECL int archive_read_support_filter_rpm(struct archive *);
 __LA_DECL int archive_read_support_filter_uu(struct archive *);
 __LA_DECL int archive_read_support_filter_xz(struct archive *);
@@ -352,6 +372,17 @@ __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 *);
 
+/* Functions to manually set the format and filters to be used. This is
+ * useful to bypass the bidding process when the format and filters to use
+ * is known in advance.
+ */
+__LA_DECL int archive_read_set_format(struct archive *, int);
+__LA_DECL int archive_read_append_filter(struct archive *, int);
+__LA_DECL int archive_read_append_filter_program(struct archive *,
+    const char *);
+__LA_DECL int archive_read_append_filter_program_signature
+    (struct archive *, const char *, const void * /* match */, size_t);
+
 /* Set various callbacks. */
 __LA_DECL int archive_read_set_open_callback(struct archive *,
     archive_open_callback *);
@@ -363,8 +394,23 @@ __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. */
+/* Callback used to switch between one data object to the next */
+__LA_DECL int archive_read_set_switch_callback(struct archive *,
+    archive_switch_callback *);
+
+/* This sets the first data object. */
 __LA_DECL int archive_read_set_callback_data(struct archive *, void *);
+/* This sets data object at specified index */
+__LA_DECL int archive_read_set_callback_data2(struct archive *, void *,
+    unsigned int);
+/* This adds a data object at the specified index. */
+__LA_DECL int archive_read_add_callback_data(struct archive *, void *,
+    unsigned int);
+/* This appends a data object to the end of list */
+__LA_DECL int archive_read_append_callback_data(struct archive *, void *);
+/* This prepends a data object to the beginning of list */
+__LA_DECL int archive_read_prepend_callback_data(struct archive *, void *);
+
 /* Opening freezes the callbacks. */
 __LA_DECL int archive_read_open1(struct archive *);
 
@@ -384,11 +430,15 @@ __LA_DECL int archive_read_open2(struct archive *, void *_client_data,
 /* Use this if you know the filename.  Note: NULL indicates stdin. */
 __LA_DECL int archive_read_open_filename(struct archive *,
 		     const char *_filename, size_t _block_size);
+/* Use this for reading multivolume files by filenames.
+ * NOTE: Must be NULL terminated. Sorting is NOT done. */
+__LA_DECL int archive_read_open_filenames(struct archive *,
+		     const char **_filenames, size_t _block_size);
 __LA_DECL int archive_read_open_filename_w(struct archive *,
 		     const wchar_t *_filename, size_t _block_size);
 /* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
 __LA_DECL int archive_read_open_file(struct archive *,
-		     const char *_filename, size_t _block_size);
+		     const char *_filename, size_t _block_size) __LA_DEPRECATED;
 /* Read an archive that's stored in memory. */
 __LA_DECL int archive_read_open_memory(struct archive *,
 		     void * buff, size_t size);
@@ -420,6 +470,9 @@ __LA_DECL __LA_INT64_T		 archive_read_header_position(struct archive *);
 __LA_DECL __LA_SSIZE_T		 archive_read_data(struct archive *,
 				    void *, size_t);
 
+/* Seek within the body of an entry.  Similar to lseek(2). */
+__LA_DECL __LA_INT64_T archive_seek_data(struct archive *, __LA_INT64_T, int);
+
 /*
  * A zero-copy version of archive_read_data that also exposes the file offset
  * of each returned block.  Note that the client has no way to specify
@@ -503,6 +556,12 @@ __LA_DECL int archive_read_set_options(struct archive *_a,
 /* Default: Do not restore Mac extended metadata. */
 /* This has no effect except on Mac OS. */
 #define	ARCHIVE_EXTRACT_MAC_METADATA		(0x2000)
+/* Default: Use HFS+ compression if it was compressed. */
+/* This has no effect except on Mac OS v10.6 or later. */
+#define	ARCHIVE_EXTRACT_NO_HFS_COMPRESSION	(0x4000)
+/* Default: Do not use HFS+ compression if it was not compressed. */
+/* This has no effect except on Mac OS v10.6 or later. */
+#define	ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED	(0x8000)
 
 __LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
 		     int flags);
@@ -523,7 +582,7 @@ __LA_DECL int		 archive_read_close(struct archive *);
 __LA_DECL int		 archive_read_free(struct archive *);
 #if ARCHIVE_VERSION_NUMBER < 4000000
 /* Synonym for archive_read_free() for backwards compatibility. */
-__LA_DECL int		 archive_read_finish(struct archive *);
+__LA_DECL int		 archive_read_finish(struct archive *) __LA_DEPRECATED;
 #endif
 
 /*-
@@ -556,25 +615,41 @@ __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_bzip2(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_compress(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_gzip(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_lzip(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_lzma(struct archive *)
+		__LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_none(struct archive *)
+		__LA_DEPRECATED;
 __LA_DECL int archive_write_set_compression_program(struct archive *,
-		     const char *cmd);
-__LA_DECL int archive_write_set_compression_xz(struct archive *);
+		     const char *cmd) __LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_xz(struct archive *)
+		__LA_DEPRECATED;
 #endif
 
+/* A convenience function to set the filter based on the code. */
+__LA_DECL int archive_write_add_filter(struct archive *, int filter_code);
+__LA_DECL int archive_write_add_filter_by_name(struct archive *,
+		     const char *name);
+__LA_DECL int archive_write_add_filter_b64encode(struct archive *);
 __LA_DECL int archive_write_add_filter_bzip2(struct archive *);
 __LA_DECL int archive_write_add_filter_compress(struct archive *);
+__LA_DECL int archive_write_add_filter_grzip(struct archive *);
 __LA_DECL int archive_write_add_filter_gzip(struct archive *);
+__LA_DECL int archive_write_add_filter_lrzip(struct archive *);
 __LA_DECL int archive_write_add_filter_lzip(struct archive *);
 __LA_DECL int archive_write_add_filter_lzma(struct archive *);
+__LA_DECL int archive_write_add_filter_lzop(struct archive *);
 __LA_DECL int archive_write_add_filter_none(struct archive *);
 __LA_DECL int archive_write_add_filter_program(struct archive *,
 		     const char *cmd);
+__LA_DECL int archive_write_add_filter_uuencode(struct archive *);
 __LA_DECL int archive_write_add_filter_xz(struct archive *);
 
 
@@ -591,14 +666,18 @@ __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 *);
+__LA_DECL int archive_write_set_format_mtree_classic(struct archive *);
 /* TODO: int archive_write_set_format_old_tar(struct archive *); */
 __LA_DECL int archive_write_set_format_pax(struct archive *);
 __LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
 __LA_DECL int archive_write_set_format_shar(struct archive *);
 __LA_DECL int archive_write_set_format_shar_dump(struct archive *);
 __LA_DECL int archive_write_set_format_ustar(struct archive *);
+__LA_DECL int archive_write_set_format_v7tar(struct archive *);
 __LA_DECL int archive_write_set_format_xar(struct archive *);
 __LA_DECL int archive_write_set_format_zip(struct archive *);
+__LA_DECL int archive_write_zip_set_compression_deflate(struct archive *);
+__LA_DECL int archive_write_zip_set_compression_store(struct archive *);
 __LA_DECL int archive_write_open(struct archive *, void *,
 		     archive_open_callback *, archive_write_callback *,
 		     archive_close_callback *);
@@ -607,7 +686,8 @@ __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 *, const char *_file)
+		__LA_DEPRECATED;
 __LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
 /* _buffSize is the size of the buffer, _used refers to a variable that
  * will be updated after each write into the buffer. */
@@ -629,12 +709,16 @@ __LA_DECL __LA_SSIZE_T	 archive_write_data_block(struct archive *,
 
 __LA_DECL int		 archive_write_finish_entry(struct archive *);
 __LA_DECL int		 archive_write_close(struct archive *);
+/* Marks the archive as FATAL so that a subsequent free() operation
+ * won't try to close() cleanly.  Provides a fast abort capability
+ * when the client discovers that things have gone wrong. */
+__LA_DECL int            archive_write_fail(struct archive *);
 /* This can fail if the archive wasn't already closed, in which case
  * archive_write_free() will implicitly call archive_write_close(). */
 __LA_DECL int		 archive_write_free(struct archive *);
 #if ARCHIVE_VERSION_NUMBER < 4000000
 /* Synonym for archive_write_free() for backwards compatibility. */
-__LA_DECL int		 archive_write_finish(struct archive *);
+__LA_DECL int		 archive_write_finish(struct archive *) __LA_DEPRECATED;
 #endif
 
 /*
@@ -758,11 +842,42 @@ __LA_DECL int	archive_read_disk_open_w(struct archive *, const wchar_t *);
  * traversal.
  */
 __LA_DECL int	archive_read_disk_descend(struct archive *);
+__LA_DECL int	archive_read_disk_can_descend(struct archive *);
 __LA_DECL int	archive_read_disk_current_filesystem(struct archive *);
 __LA_DECL int	archive_read_disk_current_filesystem_is_synthetic(struct archive *);
 __LA_DECL int	archive_read_disk_current_filesystem_is_remote(struct archive *);
 /* Request that the access time of the entry visited by travesal be restored. */
 __LA_DECL int  archive_read_disk_set_atime_restored(struct archive *);
+/*
+ * Set behavior. The "flags" argument selects optional behavior.
+ */
+/* Request that the access time of the entry visited by travesal be restored.
+ * This is the same as archive_read_disk_set_atime_restored. */
+#define	ARCHIVE_READDISK_RESTORE_ATIME		(0x0001)
+/* Default: Do not skip an entry which has nodump flags. */
+#define	ARCHIVE_READDISK_HONOR_NODUMP		(0x0002)
+/* Default: Skip a mac resource fork file whose prefix is "._" because of
+ * using copyfile. */
+#define	ARCHIVE_READDISK_MAC_COPYFILE		(0x0004)
+/* Default: Do not traverse mount points. */
+#define	ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS	(0x0008)
+
+__LA_DECL int  archive_read_disk_set_behavior(struct archive *,
+		    int flags);
+
+/*
+ * Set archive_match object that will be used in archive_read_disk to
+ * know whether an entry should be skipped. The callback function
+ * _excluded_func will be invoked when an entry is skipped by the result
+ * of archive_match.
+ */
+__LA_DECL int	archive_read_disk_set_matching(struct archive *,
+		    struct archive *_matching, void (*_excluded_func)
+		    (struct archive *, void *, struct archive_entry *),
+		    void *_client_data);
+__LA_DECL int	archive_read_disk_set_metadata_filter_callback(struct archive *,
+		    int (*_metadata_filter_func)(struct archive *, void *,
+		    	struct archive_entry *), void *_client_data);
 
 /*
  * Accessor functions to read/set various information in
@@ -782,13 +897,17 @@ __LA_DECL const char *	 archive_filter_name(struct archive *, int);
 /* These don't properly handle multiple filters, so are deprecated and
  * will eventually be removed. */
 /* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */
-__LA_DECL __LA_INT64_T	 archive_position_compressed(struct archive *);
+__LA_DECL __LA_INT64_T	 archive_position_compressed(struct archive *)
+				__LA_DEPRECATED;
 /* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */
-__LA_DECL __LA_INT64_T	 archive_position_uncompressed(struct archive *);
+__LA_DECL __LA_INT64_T	 archive_position_uncompressed(struct archive *)
+				__LA_DEPRECATED;
 /* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
-__LA_DECL const char	*archive_compression_name(struct archive *);
+__LA_DECL const char	*archive_compression_name(struct archive *)
+				__LA_DEPRECATED;
 /* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */
-__LA_DECL int		 archive_compression(struct archive *);
+__LA_DECL int		 archive_compression(struct archive *)
+				__LA_DEPRECATED;
 #endif
 
 __LA_DECL int		 archive_errno(struct archive *);
@@ -802,14 +921,116 @@ __LA_DECL void		 archive_copy_error(struct archive *dest,
 			    struct archive *src);
 __LA_DECL int		 archive_file_count(struct archive *);
 
+/*
+ * ARCHIVE_MATCH API
+ */
+__LA_DECL struct archive *archive_match_new(void);
+__LA_DECL int	archive_match_free(struct archive *);
+
+/*
+ * Test if archive_entry is excluded.
+ * This is a convenience function. This is the same as calling all
+ * archive_match_path_excluded, archive_match_time_excluded
+ * and archive_match_owner_excluded.
+ */
+__LA_DECL int	archive_match_excluded(struct archive *,
+		    struct archive_entry *);
+
+/*
+ * Test if pathname is excluded. The conditions are set by following functions.
+ */
+__LA_DECL int	archive_match_path_excluded(struct archive *,
+		    struct archive_entry *);
+/* Add exclusion pathname pattern. */
+__LA_DECL int	archive_match_exclude_pattern(struct archive *, const char *);
+__LA_DECL int	archive_match_exclude_pattern_w(struct archive *,
+		    const wchar_t *);
+/* Add exclusion pathname pattern from file. */
+__LA_DECL int	archive_match_exclude_pattern_from_file(struct archive *,
+		    const char *, int _nullSeparator);
+__LA_DECL int	archive_match_exclude_pattern_from_file_w(struct archive *,
+		    const wchar_t *, int _nullSeparator);
+/* Add inclusion pathname pattern. */
+__LA_DECL int	archive_match_include_pattern(struct archive *, const char *);
+__LA_DECL int	archive_match_include_pattern_w(struct archive *,
+		    const wchar_t *);
+/* Add inclusion pathname pattern from file. */
+__LA_DECL int	archive_match_include_pattern_from_file(struct archive *,
+		    const char *, int _nullSeparator);
+__LA_DECL int	archive_match_include_pattern_from_file_w(struct archive *,
+		    const wchar_t *, int _nullSeparator);
+/*
+ * How to get statistic information for inclusion patterns.
+ */
+/* Return the amount number of unmatched inclusion patterns. */
+__LA_DECL int	archive_match_path_unmatched_inclusions(struct archive *);
+/* Return the pattern of unmatched inclusion with ARCHIVE_OK.
+ * Return ARCHIVE_EOF if there is no inclusion pattern. */
+__LA_DECL int	archive_match_path_unmatched_inclusions_next(
+		    struct archive *, const char **);
+__LA_DECL int	archive_match_path_unmatched_inclusions_next_w(
+		    struct archive *, const wchar_t **);
+
+/*
+ * Test if a file is excluded by its time stamp.
+ * The conditions are set by following functions.
+ */
+__LA_DECL int	archive_match_time_excluded(struct archive *,
+		    struct archive_entry *);
+
+/*
+ * Flags to tell a matching type of time stamps. These are used for
+ * following functinos.
+ */
+/* Time flag: mtime to be tested. */
+#define ARCHIVE_MATCH_MTIME	(0x0100)
+/* Time flag: ctime to be tested. */
+#define ARCHIVE_MATCH_CTIME	(0x0200)
+/* Comparison flag: Match the time if it is newer than. */
+#define ARCHIVE_MATCH_NEWER	(0x0001)
+/* Comparison flag: Match the time if it is older than. */
+#define ARCHIVE_MATCH_OLDER	(0x0002)
+/* Comparison flag: Match the time if it is equal to. */
+#define ARCHIVE_MATCH_EQUAL	(0x0010)
+/* Set inclusion time. */
+__LA_DECL int	archive_match_include_time(struct archive *, int _flag,
+		    time_t _sec, long _nsec);
+/* Set inclusion time by a date string. */
+__LA_DECL int	archive_match_include_date(struct archive *, int _flag,
+		    const char *_datestr);
+__LA_DECL int	archive_match_include_date_w(struct archive *, int _flag,
+		    const wchar_t *_datestr);
+/* Set inclusion time by a particluar file. */
+__LA_DECL int	archive_match_include_file_time(struct archive *,
+		    int _flag, const char *_pathname);
+__LA_DECL int	archive_match_include_file_time_w(struct archive *,
+		    int _flag, const wchar_t *_pathname);
+/* Add exclusion entry. */
+__LA_DECL int	archive_match_exclude_entry(struct archive *,
+		    int _flag, struct archive_entry *);
+
+/*
+ * Test if a file is excluded by its uid ,gid, uname or gname.
+ * The conditions are set by following functions.
+ */
+__LA_DECL int	archive_match_owner_excluded(struct archive *,
+		    struct archive_entry *);
+/* Add inclusion uid, gid, uname and gname. */
+__LA_DECL int	archive_match_include_uid(struct archive *, __LA_INT64_T);
+__LA_DECL int	archive_match_include_gid(struct archive *, __LA_INT64_T);
+__LA_DECL int	archive_match_include_uname(struct archive *, const char *);
+__LA_DECL int	archive_match_include_uname_w(struct archive *,
+		    const wchar_t *);
+__LA_DECL int	archive_match_include_gname(struct archive *, const char *);
+__LA_DECL int	archive_match_include_gname_w(struct archive *,
+		    const wchar_t *);
+
 #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 */
diff --git a/libarchive/archive_acl.c b/libarchive/archive_acl.c
index 4747a4c..bf4b610 100644
--- a/libarchive/archive_acl.c
+++ b/libarchive/archive_acl.c
@@ -52,6 +52,9 @@ static int	acl_special(struct archive_acl *acl,
 		    int type, int permset, int tag);
 static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl,
 		    int type, int permset, int tag, int id);
+static int	archive_acl_add_entry_len_l(struct archive_acl *acl,
+		    int type, int permset, int tag, int id, const char *name,
+		    size_t len, struct archive_string_conv *sc);
 static int	isint_w(const wchar_t *start, const wchar_t *end, int *result);
 static int	ismode_w(const wchar_t *start, const wchar_t *end, int *result);
 static void	next_field_w(const wchar_t **wp, const wchar_t **start,
@@ -65,7 +68,7 @@ static int	isint(const char *start, const char *end, int *result);
 static int	ismode(const char *start, const char *end, int *result);
 static void	next_field(const char **p, const char **start,
 		    const char **end, char *sep);
-static int	prefix(const char *start, const char *end,
+static int	prefix_c(const char *start, const char *end,
 		    const char *test);
 static void	append_entry(char **p, const char *prefix, int tag,
 		    const char *name, int perm, int id);
@@ -152,7 +155,7 @@ archive_acl_add_entry_w_len(struct archive_acl *acl,
 	return ARCHIVE_OK;
 }
 
-int
+static int
 archive_acl_add_entry_len_l(struct archive_acl *acl,
     int type, int permset, int tag, int id, const char *name, size_t len,
     struct archive_string_conv *sc)
@@ -419,8 +422,11 @@ archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int
 	*permset = acl->acl_p->permset;
 	*tag = acl->acl_p->tag;
 	*id = acl->acl_p->id;
-	if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0)
+	if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) {
+		if (errno == ENOMEM)
+			return (ARCHIVE_FATAL);
 		*name = NULL;
+	}
 	acl->acl_p = acl->acl_p->next;
 	return (ARCHIVE_OK);
 }
@@ -438,7 +444,7 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
 	const wchar_t *prefix;
 	wchar_t separator;
 	struct archive_acl_entry *ap;
-	int id;
+	int id, r;
 	wchar_t *wp;
 
 	if (acl->acl_text_w != NULL) {
@@ -458,9 +464,11 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
 				length += 8; /* "default:" */
 			length += 5; /* tag name */
 			length += 1; /* colon */
-			if (archive_mstring_get_wcs(a, &ap->name, &wname) == 0 &&
-			    wname != NULL)
+			r = archive_mstring_get_wcs(a, &ap->name, &wname);
+			if (r == 0 && wname != NULL)
 				length += wcslen(wname);
+			else if (r < 0 && errno == ENOMEM)
+				return (NULL);
 			else
 				length += sizeof(uid_t) * 3 + 1;
 			length ++; /* colon */
@@ -484,7 +492,7 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
 	/* Now, allocate the string and actually populate it. */
 	wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
 	if (wp == NULL)
-		__archive_errx(1, "No memory to generate the text version of the ACL");
+		return (NULL);
 	count = 0;
 	if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
 		append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
@@ -499,16 +507,19 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
 
 		ap = acl->acl_head;
 		while (ap != NULL) {
-			if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 &&
-				archive_mstring_get_wcs(a, &ap->name, &wname) == 0) {
-				*wp++ = separator;
-				if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
-					id = ap->id;
-				else
-					id = -1;
-				append_entry_w(&wp, NULL, ap->tag, wname,
-				    ap->permset, id);
-				count++;
+			if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+				r = archive_mstring_get_wcs(a, &ap->name, &wname);
+				if (r == 0) {
+					*wp++ = separator;
+					if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+						id = ap->id;
+					else
+						id = -1;
+					append_entry_w(&wp, NULL, ap->tag, wname,
+					    ap->permset, id);
+					count++;
+				} else if (r < 0 && errno == ENOMEM)
+					return (NULL);
 			}
 			ap = ap->next;
 		}
@@ -523,17 +534,20 @@ archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
 		ap = acl->acl_head;
 		count = 0;
 		while (ap != NULL) {
-			if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 &&
-				archive_mstring_get_wcs(a, &ap->name, &wname) == 0) {
-				if (count > 0)
-					*wp++ = separator;
-				if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
-					id = ap->id;
-				else
-					id = -1;
-				append_entry_w(&wp, prefix, ap->tag,
-				    wname, ap->permset, id);
-				count ++;
+			if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
+				r = archive_mstring_get_wcs(a, &ap->name, &wname);
+				if (r == 0) {
+					if (count > 0)
+						*wp++ = separator;
+					if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+						id = ap->id;
+					else
+						id = -1;
+					append_entry_w(&wp, prefix, ap->tag,
+					    wname, ap->permset, id);
+					count ++;
+				} else if (r < 0 && errno == ENOMEM)
+					return (NULL);
 			}
 			ap = ap->next;
 		}
@@ -672,7 +686,7 @@ archive_acl_text_l(struct archive_acl *acl, int flags,
 	/* Now, allocate the string and actually populate it. */
 	p = acl->acl_text = (char *)malloc(length);
 	if (p == NULL)
-		__archive_errx(1, "No memory to generate the text version of the ACL");
+		return (-1);
 	count = 0;
 	if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
 		append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
@@ -1088,7 +1102,7 @@ archive_acl_parse_l(struct archive_acl *acl,
 			type = default_type;
 
 		name.start = name.end = NULL;
-		if (prefix(field[0].start, field[0].end, "user")) {
+		if (prefix_c(field[0].start, field[0].end, "user")) {
 			if (!ismode(field[2].start, field[2].end, &permset))
 				return (ARCHIVE_WARN);
 			if (id != -1 || field[1].start < field[1].end) {
@@ -1096,7 +1110,7 @@ archive_acl_parse_l(struct archive_acl *acl,
 				name = field[1];
 			} else
 				tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
-		} else if (prefix(field[0].start, field[0].end, "group")) {
+		} else if (prefix_c(field[0].start, field[0].end, "group")) {
 			if (!ismode(field[2].start, field[2].end, &permset))
 				return (ARCHIVE_WARN);
 			if (id != -1 || field[1].start < field[1].end) {
@@ -1104,7 +1118,7 @@ archive_acl_parse_l(struct archive_acl *acl,
 				name = field[1];
 			} else
 				tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
-		} else if (prefix(field[0].start, field[0].end, "other")) {
+		} else if (prefix_c(field[0].start, field[0].end, "other")) {
 			if (fields == 2
 			    && field[1].start < field[1].end
 			    && ismode(field[1].start, field[1].end, &permset)) {
@@ -1117,7 +1131,7 @@ archive_acl_parse_l(struct archive_acl *acl,
 			} else
 				return (ARCHIVE_WARN);
 			tag = ARCHIVE_ENTRY_ACL_OTHER;
-		} else if (prefix(field[0].start, field[0].end, "mask")) {
+		} else if (prefix_c(field[0].start, field[0].end, "mask")) {
 			if (fields == 2
 			    && field[1].start < field[1].end
 			    && ismode(field[1].start, field[1].end, &permset)) {
@@ -1246,7 +1260,7 @@ next_field(const char **p, const char **start,
  * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
  */
 static int
-prefix(const char *start, const char *end, const char *test)
+prefix_c(const char *start, const char *end, const char *test)
 {
 	if (start == end)
 		return (0);
diff --git a/libarchive/archive_check_magic.c b/libarchive/archive_check_magic.c
index 9122955..c695e58 100644
--- a/libarchive/archive_check_magic.c
+++ b/libarchive/archive_check_magic.c
@@ -94,6 +94,7 @@ archive_handle_type_name(unsigned m)
 	case ARCHIVE_READ_MAGIC:	return ("archive_read");
 	case ARCHIVE_WRITE_DISK_MAGIC:	return ("archive_write_disk");
 	case ARCHIVE_READ_DISK_MAGIC:	return ("archive_read_disk");
+	case ARCHIVE_MATCH_MAGIC:	return ("archive_match");
 	default:			return NULL;
 	}
 }
diff --git a/libarchive/archive_cmdline.c b/libarchive/archive_cmdline.c
new file mode 100644
index 0000000..7d3bac5
--- /dev/null
+++ b/libarchive/archive_cmdline.c
@@ -0,0 +1,227 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_STRING_H
+#  include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_cmdline_private.h"
+#include "archive_string.h"
+
+static int cmdline_set_path(struct archive_cmdline *, const char *);
+static int cmdline_add_arg(struct archive_cmdline *, const char *);
+
+static ssize_t
+extract_quotation(struct archive_string *as, const char *p)
+{
+	const char *s;
+
+	for (s = p + 1; *s;) {
+		if (*s == '\\') {
+			if (s[1] != '\0') {
+				archive_strappend_char(as, s[1]);
+				s += 2;
+			} else
+				s++;
+		} else if (*s == '"')
+			break;
+		else {
+			archive_strappend_char(as, s[0]);
+			s++;
+		}
+	}
+	if (*s != '"')
+		return (ARCHIVE_FAILED);/* Invalid sequence. */
+	return ((ssize_t)(s + 1 - p));
+}
+
+static ssize_t
+get_argument(struct archive_string *as, const char *p)
+{
+	const char *s = p;
+
+	archive_string_empty(as);
+
+	/* Skip beginning space characters. */
+	while (*s != '\0' && *s == ' ')
+		s++;
+	/* Copy non-space characters. */
+	while (*s != '\0' && *s != ' ') {
+		if (*s == '\\') {
+			if (s[1] != '\0') {
+				archive_strappend_char(as, s[1]);
+				s += 2;
+			} else {
+				s++;/* Ignore this character.*/
+				break;
+			}
+		} else if (*s == '"') {
+			ssize_t q = extract_quotation(as, s);
+			if (q < 0)
+				return (ARCHIVE_FAILED);/* Invalid sequence. */
+			s += q;
+		} else {
+			archive_strappend_char(as, s[0]);
+			s++;
+		}
+	}
+	return ((ssize_t)(s - p));
+}
+
+/*
+ * Set up command line arguments.
+ * Returns ARChIVE_OK if everything okey.
+ * Returns ARChIVE_FAILED if there is a lack of the `"' terminator or an
+ * empty command line.
+ * Returns ARChIVE_FATAL if no memory.
+ */
+int
+__archive_cmdline_parse(struct archive_cmdline *data, const char *cmd)
+{
+	struct archive_string as;
+	const char *p;
+	ssize_t al;
+	int r;
+
+	archive_string_init(&as);
+
+	/* Get first argument as a command path. */
+	al = get_argument(&as, cmd);
+	if (al < 0) {
+		r = ARCHIVE_FAILED;/* Invalid sequence. */
+		goto exit_function;
+	}
+	if (archive_strlen(&as) == 0) {
+		r = ARCHIVE_FAILED;/* An empty command path. */
+		goto exit_function;
+	}
+	r = cmdline_set_path(data, as.s);
+	if (r != ARCHIVE_OK)
+		goto exit_function;
+	p = strrchr(as.s, '/');
+	if (p == NULL)
+		p = as.s;
+	else
+		p++;
+	r = cmdline_add_arg(data, p);
+	if (r != ARCHIVE_OK)
+		goto exit_function;
+	cmd += al;
+
+	for (;;) {
+		al = get_argument(&as, cmd);
+		if (al < 0) {
+			r = ARCHIVE_FAILED;/* Invalid sequence. */
+			goto exit_function;
+		}
+		if (al == 0)
+			break;
+		cmd += al;
+		if (archive_strlen(&as) == 0 && *cmd == '\0')
+			break;
+		r = cmdline_add_arg(data, as.s);
+		if (r != ARCHIVE_OK)
+			goto exit_function;
+	}
+	r = ARCHIVE_OK;
+exit_function:
+	archive_string_free(&as);
+	return (r);
+}
+
+/*
+ * Set the program path.
+ */
+static int
+cmdline_set_path(struct archive_cmdline *data, const char *path)
+{
+	char *newptr;
+
+	newptr = realloc(data->path, strlen(path) + 1);
+	if (newptr == NULL)
+		return (ARCHIVE_FATAL);
+	data->path = newptr;
+	strcpy(data->path, path);
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Add a argument for the program.
+ */
+static int
+cmdline_add_arg(struct archive_cmdline *data, const char *arg)
+{
+	char **newargv;
+
+	if (data->path == NULL)
+		return (ARCHIVE_FAILED);
+
+	newargv = realloc(data->argv, (data->argc + 2) * sizeof(char *));
+	if (newargv == NULL)
+		return (ARCHIVE_FATAL);
+	data->argv = newargv;
+	data->argv[data->argc] = strdup(arg);
+	if (data->argv[data->argc] == NULL)
+		return (ARCHIVE_FATAL);
+	/* Set the terminator of argv. */
+	data->argv[++data->argc] = NULL;
+	return (ARCHIVE_OK);
+}
+
+struct archive_cmdline *
+__archive_cmdline_allocate(void)
+{
+	return (struct archive_cmdline *)
+		calloc(1, sizeof(struct archive_cmdline));
+}
+
+/*
+ * Release the resources.
+ */
+int
+__archive_cmdline_free(struct archive_cmdline *data)
+{
+
+	if (data) {
+		free(data->path);
+		if (data->argv != NULL) {
+			int i;
+			for (i = 0; data->argv[i] != NULL; i++)
+				free(data->argv[i]);
+			free(data->argv);
+		}
+		free(data);
+	}
+	return (ARCHIVE_OK);
+}
+
diff --git a/libarchive/filter_fork.h b/libarchive/archive_cmdline_private.h
similarity index 75%
copy from libarchive/filter_fork.h
copy to libarchive/archive_cmdline_private.h
index 453d032..4e409e8 100644
--- a/libarchive/filter_fork.h
+++ b/libarchive/archive_cmdline_private.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2007 Joerg Sonnenberger
+ * Copyright (c) 2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -22,20 +22,26 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: head/lib/libarchive/filter_fork.h 201087 2009-12-28 02:18:26Z kientzle $
+ * $FreeBSD$
  */
 
 #ifndef __LIBARCHIVE_BUILD
+#ifndef __LIBARCHIVE_TEST
 #error This header is only to be used internally to libarchive.
 #endif
+#endif
 
-#ifndef FILTER_FORK_H
-#define FILTER_FORK_H
+#ifndef ARCHIVE_CMDLINE_PRIVATE_H
+#define ARCHIVE_CMDLINE_PRIVATE_H
 
-pid_t
-__archive_create_child(const char *path, int *child_stdin, int *child_stdout);
+struct archive_cmdline {
+        char            *path;
+        char            **argv;
+        int              argc;
+};
 
-void
-__archive_check_child(int in, int out);
+struct archive_cmdline *__archive_cmdline_allocate(void);
+int __archive_cmdline_parse(struct archive_cmdline *, const char *);
+int __archive_cmdline_free(struct archive_cmdline *);
 
 #endif
diff --git a/libarchive/archive_crypto.c b/libarchive/archive_crypto.c
index 2caf571..85aba3a 100644
--- a/libarchive/archive_crypto.c
+++ b/libarchive/archive_crypto.c
@@ -90,7 +90,7 @@ win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
 static int
 win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
 {
-	DWORD siglen = bufsize;
+	DWORD siglen = (DWORD)bufsize;
 
 	if (!ctx->valid)
 		return (ARCHIVE_FAILED);
@@ -1222,8 +1222,10 @@ __archive_stub_sha512final(archive_sha512_ctx *ctx, void *md)
  * 2. libc2
  * 3. libc3
  * 4. libSystem
- * 5. OpenSSL
- * 6. Windows API
+ * 5. Nettle
+ * 6. OpenSSL
+ * 7. libmd
+ * 8. Windows API
  */
 const struct archive_crypto __archive_crypto =
 {
diff --git a/libarchive/archive_endian.h b/libarchive/archive_endian.h
index edc90ee..68123b0 100644
--- a/libarchive/archive_endian.h
+++ b/libarchive/archive_endian.h
@@ -126,8 +126,8 @@ archive_be64enc(void *pp, uint64_t u)
 {
 	unsigned char *p = (unsigned char *)pp;
 
-	archive_be32enc(p, u >> 32);
-	archive_be32enc(p + 4, u & 0xffffffff);
+	archive_be32enc(p, (uint32_t)(u >> 32));
+	archive_be32enc(p + 4, (uint32_t)(u & 0xffffffff));
 }
 
 static inline void
@@ -155,8 +155,8 @@ archive_le64enc(void *pp, uint64_t u)
 {
 	unsigned char *p = (unsigned char *)pp;
 
-	archive_le32enc(p, u & 0xffffffff);
-	archive_le32enc(p + 4, u >> 32);
+	archive_le32enc(p, (uint32_t)(u & 0xffffffff));
+	archive_le32enc(p + 4, (uint32_t)(u >> 32));
 }
 
 #endif
diff --git a/libarchive/archive_entry.3 b/libarchive/archive_entry.3
index 10e3c34..f77f385 100644
--- a/libarchive/archive_entry.3
+++ b/libarchive/archive_entry.3
@@ -23,9 +23,9 @@
 .\" 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 $
+.\" $FreeBSD$
 .\"
-.Dd Feburary 22, 2010
+.Dd Feburary 2, 2012
 .Dt ARCHIVE_ENTRY 3
 .Os
 .Sh NAME
@@ -34,6 +34,8 @@
 .Nm archive_entry_free ,
 .Nm archive_entry_new ,
 .Nd functions for managing archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive_entry.h
 .Ft "struct archive_entry *"
diff --git a/libarchive/archive_entry.c b/libarchive/archive_entry.c
index cbdda8a..386e51d 100644
--- a/libarchive/archive_entry.c
+++ b/libarchive/archive_entry.c
@@ -375,8 +375,11 @@ archive_entry_fflags_text(struct archive_entry *entry)
 	char *p;
 
 	if (archive_mstring_get_mbs(entry->archive,
-	    &entry->ae_fflags_text, &f) == 0 && f != NULL)
-		return (f);
+	    &entry->ae_fflags_text, &f) == 0) {
+		if (f != NULL)
+			return (f);
+	} else if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 
 	if (entry->ae_fflags_set == 0  &&  entry->ae_fflags_clear == 0)
 		return (NULL);
@@ -390,6 +393,8 @@ archive_entry_fflags_text(struct archive_entry *entry)
 	if (archive_mstring_get_mbs(entry->archive,
 	    &entry->ae_fflags_text, &f) == 0)
 		return (f);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -405,6 +410,8 @@ archive_entry_gname(struct archive_entry *entry)
 	const char *p;
 	if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -414,6 +421,8 @@ archive_entry_gname_w(struct archive_entry *entry)
 	const wchar_t *p;
 	if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -428,9 +437,13 @@ const char *
 archive_entry_hardlink(struct archive_entry *entry)
 {
 	const char *p;
-	if ((entry->ae_set & AE_SET_HARDLINK) && archive_mstring_get_mbs(
+	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
+		return (NULL);
+	if (archive_mstring_get_mbs(
 	    entry->archive, &entry->ae_hardlink, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -438,9 +451,13 @@ const wchar_t *
 archive_entry_hardlink_w(struct archive_entry *entry)
 {
 	const wchar_t *p;
-	if ((entry->ae_set & AE_SET_HARDLINK) && archive_mstring_get_wcs(
+	if ((entry->ae_set & AE_SET_HARDLINK) == 0)
+		return (NULL);
+	if (archive_mstring_get_wcs(
 	    entry->archive, &entry->ae_hardlink, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -511,6 +528,8 @@ archive_entry_pathname(struct archive_entry *entry)
 	if (archive_mstring_get_mbs(
 	    entry->archive, &entry->ae_pathname, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -521,6 +540,8 @@ archive_entry_pathname_w(struct archive_entry *entry)
 	if (archive_mstring_get_wcs(
 	    entry->archive, &entry->ae_pathname, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -584,6 +605,8 @@ archive_entry_sourcepath(struct archive_entry *entry)
 	if (archive_mstring_get_mbs(
 	    entry->archive, &entry->ae_sourcepath, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -601,9 +624,13 @@ const char *
 archive_entry_symlink(struct archive_entry *entry)
 {
 	const char *p;
-	if ((entry->ae_set & AE_SET_SYMLINK) && archive_mstring_get_mbs(
+	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
+		return (NULL);
+	if (archive_mstring_get_mbs(
 	    entry->archive, &entry->ae_symlink, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -611,9 +638,13 @@ const wchar_t *
 archive_entry_symlink_w(struct archive_entry *entry)
 {
 	const wchar_t *p;
-	if ((entry->ae_set & AE_SET_SYMLINK) && archive_mstring_get_wcs(
+	if ((entry->ae_set & AE_SET_SYMLINK) == 0)
+		return (NULL);
+	if (archive_mstring_get_wcs(
 	    entry->archive, &entry->ae_symlink, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -641,6 +672,8 @@ archive_entry_uname(struct archive_entry *entry)
 	const char *p;
 	if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -650,6 +683,8 @@ archive_entry_uname_w(struct archive_entry *entry)
 	const wchar_t *p;
 	if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)
 		return (p);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (NULL);
 }
 
@@ -730,6 +765,8 @@ archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)
 	if (archive_mstring_update_utf8(entry->archive,
 	    &entry->ae_gname, name) == 0)
 		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (0);
 }
 
@@ -796,6 +833,8 @@ archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *targ
 	if (archive_mstring_update_utf8(entry->archive,
 	    &entry->ae_hardlink, target) == 0)
 		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (0);
 }
 
@@ -932,7 +971,11 @@ archive_entry_update_link_utf8(struct archive_entry *entry, const char *target)
 	else
 		r = archive_mstring_update_utf8(entry->archive,
 		    &entry->ae_hardlink, target);
-	return ((r == 0)? 1: 0);
+	if (r == 0)
+		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
+	return (0);
 }
 
 int
@@ -1005,6 +1048,8 @@ archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name
 	if (archive_mstring_update_utf8(entry->archive,
 	    &entry->ae_pathname, name) == 0)
 		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (0);
 }
 
@@ -1115,6 +1160,8 @@ archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkn
 	if (archive_mstring_update_utf8(entry->archive,
 	    &entry->ae_symlink, linkname) == 0)
 		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (0);
 }
 
@@ -1164,6 +1211,8 @@ archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
 	if (archive_mstring_update_utf8(entry->archive,
 	    &entry->ae_uname, name) == 0)
 		return (1);
+	if (errno == ENOMEM)
+		__archive_errx(1, "No memory");
 	return (0);
 }
 
@@ -1269,7 +1318,12 @@ int
 archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
     int *permset, int *tag, int *id, const char **name)
 {
-	return archive_acl_next(entry->archive, &entry->acl, want_type, type, permset, tag, id, name);
+	int r;
+	r = archive_acl_next(entry->archive, &entry->acl, want_type, type,
+		permset, tag, id, name);
+	if (r == ARCHIVE_FATAL && errno == ENOMEM)
+		__archive_errx(1, "No memory");
+	return (r);
 }
 
 /*
@@ -1279,7 +1333,11 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
 const wchar_t *
 archive_entry_acl_text_w(struct archive_entry *entry, int flags)
 {
-	return archive_acl_text_w(entry->archive, &entry->acl, flags);
+	const wchar_t *r;
+	r = archive_acl_text_w(entry->archive, &entry->acl, flags);
+	if (r == NULL && errno == ENOMEM)
+		__archive_errx(1, "No memory");
+	return (r);
 }
 
 const char *
@@ -1288,7 +1346,7 @@ archive_entry_acl_text(struct archive_entry *entry, int flags)
 	const char *p;
 	if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0
 	    && errno == ENOMEM)
-		return (NULL);
+		__archive_errx(1, "No memory");
 	return (p);
 }
 
@@ -1391,6 +1449,9 @@ static struct flag {
 	{ "nouunlnk",	L"nouunlnk",		UF_NOUNLINK,	0 },
 	{ "nouunlink",	L"nouunlink",		UF_NOUNLINK,	0 },
 #endif
+#ifdef UF_COMPRESSED
+	{ "nocompressed",L"nocompressed",	UF_COMPRESSED,	0 },
+#endif
 #ifdef EXT2_UNRM_FL
         { "nouunlink",	L"nouunlink",		EXT2_UNRM_FL,	0},
 #endif
diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h
index 533dc7f..a905065 100644
--- a/libarchive/archive_entry.h
+++ b/libarchive/archive_entry.h
@@ -29,7 +29,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define	ARCHIVE_VERSION_NUMBER 3000002
+#define	ARCHIVE_VERSION_NUMBER 3001002
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
@@ -47,21 +47,9 @@
 #include <windows.h>
 #endif
 
-/* Get appropriate definitions of standard POSIX-style types. */
-/* These should match the types used in 'struct stat' */
+/* Get a suitable 64-bit integer type. */
 #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
+# define	__LA_INT64_T	__int64
 #else
 #include <unistd.h>
 # if defined(_SCO_DS)
@@ -69,17 +57,17 @@
 # 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
-
+/* Get a suitable definition for mode_t */
+#if ARCHIVE_VERSION_NUMBER >= 3999000
+/* Switch to plain 'int' for libarchive 4.0.  It's less broken than 'mode_t' */
+# define	__LA_MODE_T	int
+#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__)
+# define	__LA_MODE_T	unsigned short
+#else
+# define	__LA_MODE_T	mode_t
+#endif
 
 /*
  * On Windows, define LIBARCHIVE_STATIC if you're building or using a
@@ -149,14 +137,18 @@ struct archive_entry;
  * 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
+/*
+ * In libarchive 4.0, we can drop the casts here.
+ * They're needed to work around Borland C's broken mode_t.
+ */
+#define AE_IFMT		((__LA_MODE_T)0170000)
+#define AE_IFREG	((__LA_MODE_T)0100000)
+#define AE_IFLNK	((__LA_MODE_T)0120000)
+#define AE_IFSOCK	((__LA_MODE_T)0140000)
+#define AE_IFCHR	((__LA_MODE_T)0020000)
+#define AE_IFBLK	((__LA_MODE_T)0060000)
+#define AE_IFDIR	((__LA_MODE_T)0040000)
+#define AE_IFIFO	((__LA_MODE_T)0010000)
 
 /*
  * Basic object manipulation
@@ -321,7 +313,10 @@ __LA_DECL int	archive_entry_update_uname_utf8(struct archive_entry *, const char
  * manipulate archives on systems different than the ones they were
  * created on.
  *
- * TODO: On Linux, provide both stat32 and stat64 versions of these functions.
+ * TODO: On Linux and other LFS systems, provide both stat32 and
+ * stat64 versions of these functions and all of the macro glue so
+ * that archive_entry_stat is magically defined to
+ * archive_entry_stat32 or archive_entry_stat64 as appropriate.
  */
 __LA_DECL const struct stat	*archive_entry_stat(struct archive_entry *);
 __LA_DECL void	archive_entry_copy_stat(struct archive_entry *, const struct stat *);
diff --git a/libarchive/archive_entry_acl.3 b/libarchive/archive_entry_acl.3
index 93906e7..f5c3377 100644
--- a/libarchive/archive_entry_acl.3
+++ b/libarchive/archive_entry_acl.3
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd February 21, 2010
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY_ACL 3
 .Os
 .Sh NAME
@@ -35,6 +35,8 @@
 .Nm archive_entry_acl_reset ,
 .Nm archive_entry_acl_text_w
 .Nd functions for manipulating Access Control Lists in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive_entry.h
 .Ft void
@@ -132,7 +134,7 @@ All files have an access ACL
 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.
+which controls the initial access ACL for newly created directory entries.
 .Pp
 .Fn archive_entry_acl_add_entry
 and
diff --git a/libarchive/archive_entry_copy_bhfi.c b/libarchive/archive_entry_copy_bhfi.c
index 7a4bc9c..77bf38e 100644
--- a/libarchive/archive_entry_copy_bhfi.c
+++ b/libarchive/archive_entry_copy_bhfi.c
@@ -34,7 +34,7 @@ __FBSDID("$FreeBSD$");
 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 
 __inline static void
-fileTimeToUtc(const FILETIME *filetime, time_t *time, long *ns)
+fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns)
 {
 	ULARGE_INTEGER utc;
 
@@ -42,10 +42,10 @@ fileTimeToUtc(const FILETIME *filetime, time_t *time, long *ns)
 	utc.LowPart  = filetime->dwLowDateTime;
 	if (utc.QuadPart >= EPOC_TIME) {
 		utc.QuadPart -= EPOC_TIME;
-		*time = (time_t)(utc.QuadPart / 10000000);	/* milli seconds base */
+		*t = (time_t)(utc.QuadPart / 10000000);	/* milli seconds base */
 		*ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
 	} else {
-		*time = 0;
+		*t = 0;
 		*ns = 0;
 	}
 }
diff --git a/libarchive/archive_entry_link_resolver.c b/libarchive/archive_entry_link_resolver.c
index a18144d..c7d5949 100644
--- a/libarchive/archive_entry_link_resolver.c
+++ b/libarchive/archive_entry_link_resolver.c
@@ -244,6 +244,9 @@ archive_entry_linkify(struct archive_entry_linkresolver *res,
 			 * for future use.
 			 */
 			le = insert_entry(res, *e);
+			if (le == NULL)
+				/* XXX We should return an error code XXX */
+				return;
 			le->entry = *e;
 			*e = NULL;
 		}
@@ -362,7 +365,7 @@ insert_entry(struct archive_entry_linkresolver *res,
 	if (res->number_entries > res->number_buckets * 2)
 		grow_hash(res);
 
-	hash = archive_entry_dev(entry) ^ archive_entry_ino64(entry);
+	hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry));
 	bucket = hash & (res->number_buckets - 1);
 
 	/* If we could allocate the entry, record it. */
diff --git a/libarchive/archive_entry_linkify.3 b/libarchive/archive_entry_linkify.3
index a34b095..8c19fdd 100644
--- a/libarchive/archive_entry_linkify.3
+++ b/libarchive/archive_entry_linkify.3
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd February 20, 2010
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY_LINKIFY 3
 .Os
 .Sh NAME
@@ -33,7 +33,7 @@
 .Nm archive_entry_linkify
 .Nd hardlink resolver functions
 .Sh LIBRARY
-.Lb libarchive
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive_entry.h
 .Ft struct archive_entry_linkresolver *
diff --git a/libarchive/archive_entry_paths.3 b/libarchive/archive_entry_paths.3
index 621f655..51c8b8c 100644
--- a/libarchive/archive_entry_paths.3
+++ b/libarchive/archive_entry_paths.3
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd February 22, 2010
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY_PATHS 3
 .Os
 .Sh NAME
@@ -51,6 +51,8 @@
 .Nm archive_entry_copy_symlink_w ,
 .Nm archve_entry_update_symlink_utf8
 .Nd functions for manipulating path names in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive_entry.h
 .Ft const char *
diff --git a/libarchive/archive_entry_perms.3 b/libarchive/archive_entry_perms.3
index 164af97..5b7b5d9 100644
--- a/libarchive/archive_entry_perms.3
+++ b/libarchive/archive_entry_perms.3
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd February 22, 2010
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY_PERMS 3
 .Os
 .Sh NAME
@@ -52,6 +52,8 @@
 .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 LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive_entry.h
 .Ft gid_t
diff --git a/libarchive/archive_entry_stat.3 b/libarchive/archive_entry_stat.3
index 36a7efb..84a4ea1 100644
--- a/libarchive/archive_entry_stat.3
+++ b/libarchive/archive_entry_stat.3
@@ -22,8 +22,8 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd May 12, 2008
-.Dt ARCHIVE_ENTRY 3
+.Dd February 2, 2012
+.Dt ARCHIVE_ENTRY_STAT 3
 .Os
 .Sh NAME
 .Nm archive_entry_stat ,
@@ -56,6 +56,8 @@
 .Nm archive_entry_rdevminor ,
 .Nm archive_entry_set_rdevminor ,
 .Nd accessor functions for manipulating archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive_entry.h
 .Ft const struct stat *
diff --git a/libarchive/archive_entry_stat.c b/libarchive/archive_entry_stat.c
index d5ed1cb..71a407b 100644
--- a/libarchive/archive_entry_stat.c
+++ b/libarchive/archive_entry_stat.c
@@ -70,12 +70,12 @@ archive_entry_stat(struct archive_entry *entry)
 	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_gid = (gid_t)archive_entry_gid(entry);
+	st->st_uid = (uid_t)archive_entry_uid(entry);
+	st->st_ino = (ino_t)archive_entry_ino64(entry);
 	st->st_nlink = archive_entry_nlink(entry);
 	st->st_rdev = archive_entry_rdev(entry);
-	st->st_size = archive_entry_size(entry);
+	st->st_size = (off_t)archive_entry_size(entry);
 	st->st_mode = archive_entry_mode(entry);
 
 	/*
@@ -110,7 +110,7 @@ archive_entry_stat(struct archive_entry *entry)
 	/*
 	 * 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.
+	 * will allow us to support both variants interchangeably.
 	 */
 	entry->stat_valid = 1;
 
diff --git a/libarchive/archive_entry_time.3 b/libarchive/archive_entry_time.3
index 85a8209..17c658a 100644
--- a/libarchive/archive_entry_time.3
+++ b/libarchive/archive_entry_time.3
@@ -23,9 +23,9 @@
 .\" 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 $
+.\" $FreeBSD$
 .\"
-.Dd February 21, 2010
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY_TIME 3
 .Os
 .Sh NAME
@@ -50,6 +50,8 @@
 .Nm archive_entry_set_mtime ,
 .Nm archive_entry_unset_mtime ,
 .Nd functions for manipulating times in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive_entry.h
 .Ft time_t
diff --git a/libarchive/archive_getdate.c b/libarchive/archive_getdate.c
new file mode 100644
index 0000000..f8b5a28
--- /dev/null
+++ b/libarchive/archive_getdate.c
@@ -0,0 +1,1037 @@
+/*
+ * This code is in the public domain and has no copyright.
+ *
+ * This is a plain C recursive-descent translation of an old
+ * public-domain YACC grammar that has been used for parsing dates in
+ * very many open-source projects.
+ *
+ * Since the original authors were generous enough to donate their
+ * work to the public domain, I feel compelled to match their
+ * generosity.
+ *
+ * Tim Kientzle, February 2009.
+ */
+
+/*
+ * Header comment from original getdate.y:
+ */
+
+/*
+**  Originally written by Steven M. Bellovin <smb at research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz at bbn.com> and Jim Berets <jberets at bbn.com> in August, 1990;
+**
+**  This grammar has 10 shift/reduce conflicts.
+**
+**  This code is in the public domain and has no copyright.
+*/
+
+#ifdef __FreeBSD__
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/* This file defines a single public function. */
+time_t __archive_get_date(time_t now, char *);
+
+/* Basic time units. */
+#define	EPOCH		1970
+#define	MINUTE		(60L)
+#define	HOUR		(60L * MINUTE)
+#define	DAY		(24L * HOUR)
+
+/* Daylight-savings mode:  on, off, or not yet known. */
+enum DSTMODE { DSTon, DSToff, DSTmaybe };
+/* Meridian:  am or pm. */
+enum { tAM, tPM };
+/* Token types returned by nexttoken() */
+enum { tAGO = 260, tDAY, tDAYZONE, tAMPM, tMONTH, tMONTH_UNIT, tSEC_UNIT,
+       tUNUMBER, tZONE, tDST };
+struct token { int token; time_t value; };
+
+/*
+ * Parser state.
+ */
+struct gdstate {
+	struct token *tokenp; /* Pointer to next token. */
+	/* HaveXxxx counts how many of this kind of phrase we've seen;
+	 * it's a fatal error to have more than one time, zone, day,
+	 * or date phrase. */
+	int	HaveYear;
+	int	HaveMonth;
+	int	HaveDay;
+	int	HaveWeekDay; /* Day of week */
+	int	HaveTime; /* Hour/minute/second */
+	int	HaveZone; /* timezone and/or DST info */
+	int	HaveRel; /* time offset; we can have more than one */
+	/* Absolute time values. */
+	time_t	Timezone;  /* Seconds offset from GMT */
+	time_t	Day;
+	time_t	Hour;
+	time_t	Minutes;
+	time_t	Month;
+	time_t	Seconds;
+	time_t	Year;
+	/* DST selection */
+	enum DSTMODE	DSTmode;
+	/* Day of week accounting, e.g., "3rd Tuesday" */
+	time_t	DayOrdinal; /* "3" in "3rd Tuesday" */
+	time_t	DayNumber; /* "Tuesday" in "3rd Tuesday" */
+	/* Relative time values: hour/day/week offsets are measured in
+	 * seconds, month/year are counted in months. */
+	time_t	RelMonth;
+	time_t	RelSeconds;
+};
+
+/*
+ * A series of functions that recognize certain common time phrases.
+ * Each function returns 1 if it managed to make sense of some of the
+ * tokens, zero otherwise.
+ */
+
+/*
+ *  hour:minute or hour:minute:second with optional AM, PM, or numeric
+ *  timezone offset
+ */
+static int
+timephrase(struct gdstate *gds)
+{
+	if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == ':'
+	    && gds->tokenp[2].token == tUNUMBER
+	    && gds->tokenp[3].token == ':'
+	    && gds->tokenp[4].token == tUNUMBER) {
+		/* "12:14:18" or "22:08:07" */
+		++gds->HaveTime;
+		gds->Hour = gds->tokenp[0].value;
+		gds->Minutes = gds->tokenp[2].value;
+		gds->Seconds = gds->tokenp[4].value;
+		gds->tokenp += 5;
+	}
+	else if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == ':'
+	    && gds->tokenp[2].token == tUNUMBER) {
+		/* "12:14" or "22:08" */
+		++gds->HaveTime;
+		gds->Hour = gds->tokenp[0].value;
+		gds->Minutes = gds->tokenp[2].value;
+		gds->Seconds = 0;
+		gds->tokenp += 3;
+	}
+	else if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == tAMPM) {
+		/* "7" is a time if it's followed by "am" or "pm" */
+		++gds->HaveTime;
+		gds->Hour = gds->tokenp[0].value;
+		gds->Minutes = gds->Seconds = 0;
+		/* We'll handle the AM/PM below. */
+		gds->tokenp += 1;
+	} else {
+		/* We can't handle this. */
+		return 0;
+	}
+
+	if (gds->tokenp[0].token == tAMPM) {
+		/* "7:12pm", "12:20:13am" */
+		if (gds->Hour == 12)
+			gds->Hour = 0;
+		if (gds->tokenp[0].value == tPM)
+			gds->Hour += 12;
+		gds->tokenp += 1;
+	}
+	if (gds->tokenp[0].token == '+'
+	    && gds->tokenp[1].token == tUNUMBER) {
+		/* "7:14+0700" */
+		gds->HaveZone++;
+		gds->DSTmode = DSToff;
+		gds->Timezone = - ((gds->tokenp[1].value / 100) * HOUR
+		    + (gds->tokenp[1].value % 100) * MINUTE);
+		gds->tokenp += 2;
+	}
+	if (gds->tokenp[0].token == '-'
+	    && gds->tokenp[1].token == tUNUMBER) {
+		/* "19:14:12-0530" */
+		gds->HaveZone++;
+		gds->DSTmode = DSToff;
+		gds->Timezone = + ((gds->tokenp[1].value / 100) * HOUR
+		    + (gds->tokenp[1].value % 100) * MINUTE);
+		gds->tokenp += 2;
+	}
+	return 1;
+}
+
+/*
+ * Timezone name, possibly including DST.
+ */
+static int
+zonephrase(struct gdstate *gds)
+{
+	if (gds->tokenp[0].token == tZONE
+	    && gds->tokenp[1].token == tDST) {
+		gds->HaveZone++;
+		gds->Timezone = gds->tokenp[0].value;
+		gds->DSTmode = DSTon;
+		gds->tokenp += 1;
+		return 1;
+	}
+
+	if (gds->tokenp[0].token == tZONE) {
+		gds->HaveZone++;
+		gds->Timezone = gds->tokenp[0].value;
+		gds->DSTmode = DSToff;
+		gds->tokenp += 1;
+		return 1;
+	}
+
+	if (gds->tokenp[0].token == tDAYZONE) {
+		gds->HaveZone++;
+		gds->Timezone = gds->tokenp[0].value;
+		gds->DSTmode = DSTon;
+		gds->tokenp += 1;
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Year/month/day in various combinations.
+ */
+static int
+datephrase(struct gdstate *gds)
+{
+	if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == '/'
+	    && gds->tokenp[2].token == tUNUMBER
+	    && gds->tokenp[3].token == '/'
+	    && gds->tokenp[4].token == tUNUMBER) {
+		gds->HaveYear++;
+		gds->HaveMonth++;
+		gds->HaveDay++;
+		if (gds->tokenp[0].value >= 13) {
+			/* First number is big:  2004/01/29, 99/02/17 */
+			gds->Year = gds->tokenp[0].value;
+			gds->Month = gds->tokenp[2].value;
+			gds->Day = gds->tokenp[4].value;
+		} else if ((gds->tokenp[4].value >= 13)
+		    || (gds->tokenp[2].value >= 13)) {
+			/* Last number is big:  01/07/98 */
+			/* Middle number is big:  01/29/04 */
+			gds->Month = gds->tokenp[0].value;
+			gds->Day = gds->tokenp[2].value;
+			gds->Year = gds->tokenp[4].value;
+		} else {
+			/* No significant clues: 02/03/04 */
+			gds->Month = gds->tokenp[0].value;
+			gds->Day = gds->tokenp[2].value;
+			gds->Year = gds->tokenp[4].value;
+		}
+		gds->tokenp += 5;
+		return 1;
+	}
+
+	if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == '/'
+	    && gds->tokenp[2].token == tUNUMBER) {
+		/* "1/15" */
+		gds->HaveMonth++;
+		gds->HaveDay++;
+		gds->Month = gds->tokenp[0].value;
+		gds->Day = gds->tokenp[2].value;
+		gds->tokenp += 3;
+		return 1;
+	}
+
+	if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == '-'
+	    && gds->tokenp[2].token == tUNUMBER
+	    && gds->tokenp[3].token == '-'
+	    && gds->tokenp[4].token == tUNUMBER) {
+		/* ISO 8601 format.  yyyy-mm-dd.  */
+		gds->HaveYear++;
+		gds->HaveMonth++;
+		gds->HaveDay++;
+		gds->Year = gds->tokenp[0].value;
+		gds->Month = gds->tokenp[2].value;
+		gds->Day = gds->tokenp[4].value;
+		gds->tokenp += 5;
+		return 1;
+	}
+
+	if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == '-'
+	    && gds->tokenp[2].token == tMONTH
+	    && gds->tokenp[3].token == '-'
+	    && gds->tokenp[4].token == tUNUMBER) {
+		gds->HaveYear++;
+		gds->HaveMonth++;
+		gds->HaveDay++;
+		if (gds->tokenp[0].value > 31) {
+			/* e.g. 1992-Jun-17 */
+			gds->Year = gds->tokenp[0].value;
+			gds->Month = gds->tokenp[2].value;
+			gds->Day = gds->tokenp[4].value;
+		} else {
+			/* e.g. 17-JUN-1992.  */
+			gds->Day = gds->tokenp[0].value;
+			gds->Month = gds->tokenp[2].value;
+			gds->Year = gds->tokenp[4].value;
+		}
+		gds->tokenp += 5;
+		return 1;
+	}
+
+	if (gds->tokenp[0].token == tMONTH
+	    && gds->tokenp[1].token == tUNUMBER
+	    && gds->tokenp[2].token == ','
+	    && gds->tokenp[3].token == tUNUMBER) {
+		/* "June 17, 2001" */
+		gds->HaveYear++;
+		gds->HaveMonth++;
+		gds->HaveDay++;
+		gds->Month = gds->tokenp[0].value;
+		gds->Day = gds->tokenp[1].value;
+		gds->Year = gds->tokenp[3].value;
+		gds->tokenp += 4;
+		return 1;
+	}
+
+	if (gds->tokenp[0].token == tMONTH
+	    && gds->tokenp[1].token == tUNUMBER) {
+		/* "May 3" */
+		gds->HaveMonth++;
+		gds->HaveDay++;
+		gds->Month = gds->tokenp[0].value;
+		gds->Day = gds->tokenp[1].value;
+		gds->tokenp += 2;
+		return 1;
+	}
+
+	if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == tMONTH
+	    && gds->tokenp[2].token == tUNUMBER) {
+		/* "12 Sept 1997" */
+		gds->HaveYear++;
+		gds->HaveMonth++;
+		gds->HaveDay++;
+		gds->Day = gds->tokenp[0].value;
+		gds->Month = gds->tokenp[1].value;
+		gds->Year = gds->tokenp[2].value;
+		gds->tokenp += 3;
+		return 1;
+	}
+
+	if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == tMONTH) {
+		/* "12 Sept" */
+		gds->HaveMonth++;
+		gds->HaveDay++;
+		gds->Day = gds->tokenp[0].value;
+		gds->Month = gds->tokenp[1].value;
+		gds->tokenp += 2;
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Relative time phrase: "tomorrow", "yesterday", "+1 hour", etc.
+ */
+static int
+relunitphrase(struct gdstate *gds)
+{
+	if (gds->tokenp[0].token == '-'
+	    && gds->tokenp[1].token == tUNUMBER
+	    && gds->tokenp[2].token == tSEC_UNIT) {
+		/* "-3 hours" */
+		gds->HaveRel++;
+		gds->RelSeconds -= gds->tokenp[1].value * gds->tokenp[2].value;
+		gds->tokenp += 3;
+		return 1;
+	}
+	if (gds->tokenp[0].token == '+'
+	    && gds->tokenp[1].token == tUNUMBER
+	    && gds->tokenp[2].token == tSEC_UNIT) {
+		/* "+1 minute" */
+		gds->HaveRel++;
+		gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value;
+		gds->tokenp += 3;
+		return 1;
+	}
+	if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == tSEC_UNIT) {
+		/* "1 day" */
+		gds->HaveRel++;
+		gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value;
+		gds->tokenp += 3;
+		return 1;
+	}
+	if (gds->tokenp[0].token == '-'
+	    && gds->tokenp[1].token == tUNUMBER
+	    && gds->tokenp[2].token == tMONTH_UNIT) {
+		/* "-3 months" */
+		gds->HaveRel++;
+		gds->RelMonth -= gds->tokenp[1].value * gds->tokenp[2].value;
+		gds->tokenp += 3;
+		return 1;
+	}
+	if (gds->tokenp[0].token == '+'
+	    && gds->tokenp[1].token == tUNUMBER
+	    && gds->tokenp[2].token == tMONTH_UNIT) {
+		/* "+5 years" */
+		gds->HaveRel++;
+		gds->RelMonth += gds->tokenp[1].value * gds->tokenp[2].value;
+		gds->tokenp += 3;
+		return 1;
+	}
+	if (gds->tokenp[0].token == tUNUMBER
+	    && gds->tokenp[1].token == tMONTH_UNIT) {
+		/* "2 years" */
+		gds->HaveRel++;
+		gds->RelMonth += gds->tokenp[0].value * gds->tokenp[1].value;
+		gds->tokenp += 2;
+		return 1;
+	}
+	if (gds->tokenp[0].token == tSEC_UNIT) {
+		/* "now", "tomorrow" */
+		gds->HaveRel++;
+		gds->RelSeconds += gds->tokenp[0].value;
+		++gds->tokenp;
+		return 1;
+	}
+	if (gds->tokenp[0].token == tMONTH_UNIT) {
+		/* "month" */
+		gds->HaveRel++;
+		gds->RelMonth += gds->tokenp[0].value;
+		gds->tokenp += 1;
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Day of the week specification.
+ */
+static int
+dayphrase(struct gdstate *gds)
+{
+	if (gds->tokenp[0].token == tDAY) {
+		/* "tues", "wednesday," */
+		gds->HaveWeekDay++;
+		gds->DayOrdinal = 1;
+		gds->DayNumber = gds->tokenp[0].value;
+		gds->tokenp += 1;
+		if (gds->tokenp[0].token == ',')
+			gds->tokenp += 1;
+		return 1;
+	}
+	if (gds->tokenp[0].token == tUNUMBER
+		&& gds->tokenp[1].token == tDAY) {
+		/* "second tues" "3 wed" */
+		gds->HaveWeekDay++;
+		gds->DayOrdinal = gds->tokenp[0].value;
+		gds->DayNumber = gds->tokenp[1].value;
+		gds->tokenp += 2;
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Try to match a phrase using one of the above functions.
+ * This layer also deals with a couple of generic issues.
+ */
+static int
+phrase(struct gdstate *gds)
+{
+	if (timephrase(gds))
+		return 1;
+	if (zonephrase(gds))
+		return 1;
+	if (datephrase(gds))
+		return 1;
+	if (dayphrase(gds))
+		return 1;
+	if (relunitphrase(gds)) {
+		if (gds->tokenp[0].token == tAGO) {
+			gds->RelSeconds = -gds->RelSeconds;
+			gds->RelMonth = -gds->RelMonth;
+			gds->tokenp += 1;
+		}
+		return 1;
+	}
+
+	/* Bare numbers sometimes have meaning. */
+	if (gds->tokenp[0].token == tUNUMBER) {
+		if (gds->HaveTime && !gds->HaveYear && !gds->HaveRel) {
+			gds->HaveYear++;
+			gds->Year = gds->tokenp[0].value;
+			gds->tokenp += 1;
+			return 1;
+		}
+
+		if(gds->tokenp[0].value > 10000) {
+			/* "20040301" */
+			gds->HaveYear++;
+			gds->HaveMonth++;
+			gds->HaveDay++;
+			gds->Day= (gds->tokenp[0].value)%100;
+			gds->Month= (gds->tokenp[0].value/100)%100;
+			gds->Year = gds->tokenp[0].value/10000;
+			gds->tokenp += 1;
+			return 1;
+		}
+
+		if (gds->tokenp[0].value < 24) {
+			gds->HaveTime++;
+			gds->Hour = gds->tokenp[0].value;
+			gds->Minutes = 0;
+			gds->Seconds = 0;
+			gds->tokenp += 1;
+			return 1;
+		}
+
+		if ((gds->tokenp[0].value / 100 < 24)
+		    && (gds->tokenp[0].value % 100 < 60)) {
+			/* "513" is same as "5:13" */
+			gds->Hour = gds->tokenp[0].value / 100;
+			gds->Minutes = gds->tokenp[0].value % 100;
+			gds->Seconds = 0;
+			gds->tokenp += 1;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * A dictionary of time words.
+ */
+static struct LEXICON {
+	size_t		abbrev;
+	const char	*name;
+	int		type;
+	time_t		value;
+} const TimeWords[] = {
+	/* am/pm */
+	{ 0, "am",		tAMPM,	tAM },
+	{ 0, "pm",		tAMPM,	tPM },
+
+	/* Month names. */
+	{ 3, "january",		tMONTH,  1 },
+	{ 3, "february",	tMONTH,  2 },
+	{ 3, "march",		tMONTH,  3 },
+	{ 3, "april",		tMONTH,  4 },
+	{ 3, "may",		tMONTH,  5 },
+	{ 3, "june",		tMONTH,  6 },
+	{ 3, "july",		tMONTH,  7 },
+	{ 3, "august",		tMONTH,  8 },
+	{ 3, "september",	tMONTH,  9 },
+	{ 3, "october",		tMONTH, 10 },
+	{ 3, "november",	tMONTH, 11 },
+	{ 3, "december",	tMONTH, 12 },
+
+	/* Days of the week. */
+	{ 2, "sunday",		tDAY, 0 },
+	{ 3, "monday",		tDAY, 1 },
+	{ 2, "tuesday",		tDAY, 2 },
+	{ 3, "wednesday",	tDAY, 3 },
+	{ 2, "thursday",	tDAY, 4 },
+	{ 2, "friday",		tDAY, 5 },
+	{ 2, "saturday",	tDAY, 6 },
+
+	/* Timezones: Offsets are in seconds. */
+	{ 0, "gmt",  tZONE,     0*HOUR }, /* Greenwich Mean */
+	{ 0, "ut",   tZONE,     0*HOUR }, /* Universal (Coordinated) */
+	{ 0, "utc",  tZONE,     0*HOUR },
+	{ 0, "wet",  tZONE,     0*HOUR }, /* Western European */
+	{ 0, "bst",  tDAYZONE,  0*HOUR }, /* British Summer */
+	{ 0, "wat",  tZONE,     1*HOUR }, /* West Africa */
+	{ 0, "at",   tZONE,     2*HOUR }, /* Azores */
+	/* { 0, "bst", tZONE, 3*HOUR }, */ /* Brazil Standard: Conflict */
+	/* { 0, "gst", tZONE, 3*HOUR }, */ /* Greenland Standard: Conflict*/
+	{ 0, "nft",  tZONE,     3*HOUR+30*MINUTE }, /* Newfoundland */
+	{ 0, "nst",  tZONE,     3*HOUR+30*MINUTE }, /* Newfoundland Standard */
+	{ 0, "ndt",  tDAYZONE,  3*HOUR+30*MINUTE }, /* Newfoundland Daylight */
+	{ 0, "ast",  tZONE,     4*HOUR }, /* Atlantic Standard */
+	{ 0, "adt",  tDAYZONE,  4*HOUR }, /* Atlantic Daylight */
+	{ 0, "est",  tZONE,     5*HOUR }, /* Eastern Standard */
+	{ 0, "edt",  tDAYZONE,  5*HOUR }, /* Eastern Daylight */
+	{ 0, "cst",  tZONE,     6*HOUR }, /* Central Standard */
+	{ 0, "cdt",  tDAYZONE,  6*HOUR }, /* Central Daylight */
+	{ 0, "mst",  tZONE,     7*HOUR }, /* Mountain Standard */
+	{ 0, "mdt",  tDAYZONE,  7*HOUR }, /* Mountain Daylight */
+	{ 0, "pst",  tZONE,     8*HOUR }, /* Pacific Standard */
+	{ 0, "pdt",  tDAYZONE,  8*HOUR }, /* Pacific Daylight */
+	{ 0, "yst",  tZONE,     9*HOUR }, /* Yukon Standard */
+	{ 0, "ydt",  tDAYZONE,  9*HOUR }, /* Yukon Daylight */
+	{ 0, "hst",  tZONE,     10*HOUR }, /* Hawaii Standard */
+	{ 0, "hdt",  tDAYZONE,  10*HOUR }, /* Hawaii Daylight */
+	{ 0, "cat",  tZONE,     10*HOUR }, /* Central Alaska */
+	{ 0, "ahst", tZONE,     10*HOUR }, /* Alaska-Hawaii Standard */
+	{ 0, "nt",   tZONE,     11*HOUR }, /* Nome */
+	{ 0, "idlw", tZONE,     12*HOUR }, /* Intl Date Line West */
+	{ 0, "cet",  tZONE,     -1*HOUR }, /* Central European */
+	{ 0, "met",  tZONE,     -1*HOUR }, /* Middle European */
+	{ 0, "mewt", tZONE,     -1*HOUR }, /* Middle European Winter */
+	{ 0, "mest", tDAYZONE,  -1*HOUR }, /* Middle European Summer */
+	{ 0, "swt",  tZONE,     -1*HOUR }, /* Swedish Winter */
+	{ 0, "sst",  tDAYZONE,  -1*HOUR }, /* Swedish Summer */
+	{ 0, "fwt",  tZONE,     -1*HOUR }, /* French Winter */
+	{ 0, "fst",  tDAYZONE,  -1*HOUR }, /* French Summer */
+	{ 0, "eet",  tZONE,     -2*HOUR }, /* Eastern Eur, USSR Zone 1 */
+	{ 0, "bt",   tZONE,     -3*HOUR }, /* Baghdad, USSR Zone 2 */
+	{ 0, "it",   tZONE,     -3*HOUR-30*MINUTE },/* Iran */
+	{ 0, "zp4",  tZONE,     -4*HOUR }, /* USSR Zone 3 */
+	{ 0, "zp5",  tZONE,     -5*HOUR }, /* USSR Zone 4 */
+	{ 0, "ist",  tZONE,     -5*HOUR-30*MINUTE },/* Indian Standard */
+	{ 0, "zp6",  tZONE,     -6*HOUR }, /* USSR Zone 5 */
+	/* { 0, "nst",  tZONE, -6.5*HOUR }, */ /* North Sumatra: Conflict */
+	/* { 0, "sst", tZONE, -7*HOUR }, */ /* So Sumatra, USSR 6: Conflict */
+	{ 0, "wast", tZONE,     -7*HOUR }, /* West Australian Standard */
+	{ 0, "wadt", tDAYZONE,  -7*HOUR }, /* West Australian Daylight */
+	{ 0, "jt",   tZONE,     -7*HOUR-30*MINUTE },/* Java (3pm in Cronusland!)*/
+	{ 0, "cct",  tZONE,     -8*HOUR }, /* China Coast, USSR Zone 7 */
+	{ 0, "jst",  tZONE,     -9*HOUR }, /* Japan Std, USSR Zone 8 */
+	{ 0, "cast", tZONE,     -9*HOUR-30*MINUTE },/* Ctrl Australian Std */
+	{ 0, "cadt", tDAYZONE,  -9*HOUR-30*MINUTE },/* Ctrl Australian Daylt */
+	{ 0, "east", tZONE,     -10*HOUR }, /* Eastern Australian Std */
+	{ 0, "eadt", tDAYZONE,  -10*HOUR }, /* Eastern Australian Daylt */
+	{ 0, "gst",  tZONE,     -10*HOUR }, /* Guam Std, USSR Zone 9 */
+	{ 0, "nzt",  tZONE,     -12*HOUR }, /* New Zealand */
+	{ 0, "nzst", tZONE,     -12*HOUR }, /* New Zealand Standard */
+	{ 0, "nzdt", tDAYZONE,  -12*HOUR }, /* New Zealand Daylight */
+	{ 0, "idle", tZONE,     -12*HOUR }, /* Intl Date Line East */
+
+	{ 0, "dst",  tDST,		0 },
+
+	/* Time units. */
+	{ 4, "years",		tMONTH_UNIT,	12 },
+	{ 5, "months",		tMONTH_UNIT,	1 },
+	{ 9, "fortnights",	tSEC_UNIT,	14 * DAY },
+	{ 4, "weeks",		tSEC_UNIT,	7 * DAY },
+	{ 3, "days",		tSEC_UNIT,	DAY },
+	{ 4, "hours",		tSEC_UNIT,	HOUR },
+	{ 3, "minutes",		tSEC_UNIT,	MINUTE },
+	{ 3, "seconds",		tSEC_UNIT,	1 },
+
+	/* Relative-time words. */
+	{ 0, "tomorrow",	tSEC_UNIT,	DAY },
+	{ 0, "yesterday",	tSEC_UNIT,	-DAY },
+	{ 0, "today",		tSEC_UNIT,	0 },
+	{ 0, "now",		tSEC_UNIT,	0 },
+	{ 0, "last",		tUNUMBER,	-1 },
+	{ 0, "this",		tSEC_UNIT,	0 },
+	{ 0, "next",		tUNUMBER,	2 },
+	{ 0, "first",		tUNUMBER,	1 },
+	{ 0, "1st",		tUNUMBER,	1 },
+/*	{ 0, "second",		tUNUMBER,	2 }, */
+	{ 0, "2nd",		tUNUMBER,	2 },
+	{ 0, "third",		tUNUMBER,	3 },
+	{ 0, "3rd",		tUNUMBER,	3 },
+	{ 0, "fourth",		tUNUMBER,	4 },
+	{ 0, "4th",		tUNUMBER,	4 },
+	{ 0, "fifth",		tUNUMBER,	5 },
+	{ 0, "5th",		tUNUMBER,	5 },
+	{ 0, "sixth",		tUNUMBER,	6 },
+	{ 0, "seventh",		tUNUMBER,	7 },
+	{ 0, "eighth",		tUNUMBER,	8 },
+	{ 0, "ninth",		tUNUMBER,	9 },
+	{ 0, "tenth",		tUNUMBER,	10 },
+	{ 0, "eleventh",	tUNUMBER,	11 },
+	{ 0, "twelfth",		tUNUMBER,	12 },
+	{ 0, "ago",		tAGO,		1 },
+
+	/* Military timezones. */
+	{ 0, "a",	tZONE,	1*HOUR },
+	{ 0, "b",	tZONE,	2*HOUR },
+	{ 0, "c",	tZONE,	3*HOUR },
+	{ 0, "d",	tZONE,	4*HOUR },
+	{ 0, "e",	tZONE,	5*HOUR },
+	{ 0, "f",	tZONE,	6*HOUR },
+	{ 0, "g",	tZONE,	7*HOUR },
+	{ 0, "h",	tZONE,	8*HOUR },
+	{ 0, "i",	tZONE,	9*HOUR },
+	{ 0, "k",	tZONE,	10*HOUR },
+	{ 0, "l",	tZONE,	11*HOUR },
+	{ 0, "m",	tZONE,	12*HOUR },
+	{ 0, "n",	tZONE,	-1*HOUR },
+	{ 0, "o",	tZONE,	-2*HOUR },
+	{ 0, "p",	tZONE,	-3*HOUR },
+	{ 0, "q",	tZONE,	-4*HOUR },
+	{ 0, "r",	tZONE,	-5*HOUR },
+	{ 0, "s",	tZONE,	-6*HOUR },
+	{ 0, "t",	tZONE,	-7*HOUR },
+	{ 0, "u",	tZONE,	-8*HOUR },
+	{ 0, "v",	tZONE,	-9*HOUR },
+	{ 0, "w",	tZONE,	-10*HOUR },
+	{ 0, "x",	tZONE,	-11*HOUR },
+	{ 0, "y",	tZONE,	-12*HOUR },
+	{ 0, "z",	tZONE,	0*HOUR },
+
+	/* End of table. */
+	{ 0, NULL,	0,	0 }
+};
+
+/*
+ * Year is either:
+ *  = A number from 0 to 99, which means a year from 1970 to 2069, or
+ *  = The actual year (>=100).
+ */
+static time_t
+Convert(time_t Month, time_t Day, time_t Year,
+	time_t Hours, time_t Minutes, time_t Seconds,
+	time_t Timezone, enum DSTMODE DSTmode)
+{
+	static int DaysInMonth[12] = {
+		31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+	};
+	time_t	Julian;
+	int	i;
+
+	if (Year < 69)
+		Year += 2000;
+	else if (Year < 100)
+		Year += 1900;
+	DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+	    ? 29 : 28;
+	/* Checking for 2038 bogusly assumes that time_t is 32 bits.  But
+	   I'm too lazy to try to check for time_t overflow in another way.  */
+	if (Year < EPOCH || Year > 2038
+	    || Month < 1 || Month > 12
+	    /* Lint fluff:  "conversion from long may lose accuracy" */
+	    || Day < 1 || Day > DaysInMonth[(int)--Month]
+	    || Hours < 0 || Hours > 23
+	    || Minutes < 0 || Minutes > 59
+	    || Seconds < 0 || Seconds > 59)
+		return -1;
+
+	Julian = Day - 1;
+	for (i = 0; i < Month; i++)
+		Julian += DaysInMonth[i];
+	for (i = EPOCH; i < Year; i++)
+		Julian += 365 + (i % 4 == 0);
+	Julian *= DAY;
+	Julian += Timezone;
+	Julian += Hours * HOUR + Minutes * MINUTE + Seconds;
+	if (DSTmode == DSTon
+	    || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+		Julian -= HOUR;
+	return Julian;
+}
+
+
+static time_t
+DSTcorrect(time_t Start, time_t Future)
+{
+	time_t	StartDay;
+	time_t	FutureDay;
+
+	StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+	FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+	return (Future - Start) + (StartDay - FutureDay) * HOUR;
+}
+
+
+static time_t
+RelativeDate(time_t Start, time_t zone, int dstmode,
+    time_t DayOrdinal, time_t DayNumber)
+{
+	struct tm	*tm;
+	time_t	t, now;
+
+	t = Start - zone;
+	tm = gmtime(&t);
+	now = Start;
+	now += DAY * ((DayNumber - tm->tm_wday + 7) % 7);
+	now += 7 * DAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+	if (dstmode == DSTmaybe)
+		return DSTcorrect(Start, now);
+	return now - Start;
+}
+
+
+static time_t
+RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)
+{
+	struct tm	*tm;
+	time_t	Month;
+	time_t	Year;
+
+	if (RelMonth == 0)
+		return 0;
+	tm = localtime(&Start);
+	Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
+	Year = Month / 12;
+	Month = Month % 12 + 1;
+	return DSTcorrect(Start,
+	    Convert(Month, (time_t)tm->tm_mday, Year,
+		(time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+		Timezone, DSTmaybe));
+}
+
+/*
+ * Tokenizer.
+ */
+static int
+nexttoken(char **in, time_t *value)
+{
+	char	c;
+	char	buff[64];
+
+	for ( ; ; ) {
+		while (isspace((unsigned char)**in))
+			++*in;
+
+		/* Skip parenthesized comments. */
+		if (**in == '(') {
+			int Count = 0;
+			do {
+				c = *(*in)++;
+				if (c == '\0')
+					return c;
+				if (c == '(')
+					Count++;
+				else if (c == ')')
+					Count--;
+			} while (Count > 0);
+			continue;
+		}
+
+		/* Try the next token in the word table first. */
+		/* This allows us to match "2nd", for example. */
+		{
+			char *src = *in;
+			const struct LEXICON *tp;
+			unsigned i = 0;
+
+			/* Force to lowercase and strip '.' characters. */
+			while (*src != '\0'
+			    && (isalnum((unsigned char)*src) || *src == '.')
+			    && i < sizeof(buff)-1) {
+				if (*src != '.') {
+					if (isupper((unsigned char)*src))
+						buff[i++] = tolower((unsigned char)*src);
+					else
+						buff[i++] = *src;
+				}
+				src++;
+			}
+			buff[i] = '\0';
+
+			/*
+			 * Find the first match.  If the word can be
+			 * abbreviated, make sure we match at least
+			 * the minimum abbreviation.
+			 */
+			for (tp = TimeWords; tp->name; tp++) {
+				size_t abbrev = tp->abbrev;
+				if (abbrev == 0)
+					abbrev = strlen(tp->name);
+				if (strlen(buff) >= abbrev
+				    && strncmp(tp->name, buff, strlen(buff))
+				    	== 0) {
+					/* Skip over token. */
+					*in = src;
+					/* Return the match. */
+					*value = tp->value;
+					return tp->type;
+				}
+			}
+		}
+
+		/*
+		 * Not in the word table, maybe it's a number.  Note:
+		 * Because '-' and '+' have other special meanings, I
+		 * don't deal with signed numbers here.
+		 */
+		if (isdigit((unsigned char)(c = **in))) {
+			for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )
+				*value = 10 * *value + c - '0';
+			(*in)--;
+			return (tUNUMBER);
+		}
+
+		return *(*in)++;
+	}
+}
+
+#define	TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static long
+difftm (struct tm *a, struct tm *b)
+{
+	int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+	int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+	int days = (
+		/* difference in day of year */
+		a->tm_yday - b->tm_yday
+		/* + intervening leap days */
+		+  ((ay >> 2) - (by >> 2))
+		-  (ay/100 - by/100)
+		+  ((ay/100 >> 2) - (by/100 >> 2))
+		/* + difference in years * 365 */
+		+  (long)(ay-by) * 365
+		);
+	return (days * DAY + (a->tm_hour - b->tm_hour) * HOUR
+	    + (a->tm_min - b->tm_min) * MINUTE
+	    + (a->tm_sec - b->tm_sec));
+}
+
+/*
+ *
+ * The public function.
+ *
+ * TODO: tokens[] array should be dynamically sized.
+ */
+time_t
+__archive_get_date(time_t now, char *p)
+{
+	struct token	tokens[256];
+	struct gdstate	_gds;
+	struct token	*lasttoken;
+	struct gdstate	*gds;
+	struct tm	local, *tm;
+	struct tm	gmt, *gmt_ptr;
+	time_t		Start;
+	time_t		tod;
+	long		tzone;
+
+	/* Clear out the parsed token array. */
+	memset(tokens, 0, sizeof(tokens));
+	/* Initialize the parser state. */
+	memset(&_gds, 0, sizeof(_gds));
+	gds = &_gds;
+
+	/* Look up the current time. */
+	memset(&local, 0, sizeof(local));
+	tm = localtime (&now);
+	if (tm == NULL)
+		return -1;
+	local = *tm;
+
+	/* Look up UTC if we can and use that to determine the current
+	 * timezone offset. */
+	memset(&gmt, 0, sizeof(gmt));
+	gmt_ptr = gmtime (&now);
+	if (gmt_ptr != NULL) {
+		/* Copy, in case localtime and gmtime use the same buffer. */
+		gmt = *gmt_ptr;
+	}
+	if (gmt_ptr != NULL)
+		tzone = difftm (&gmt, &local);
+	else
+		/* This system doesn't understand timezones; fake it. */
+		tzone = 0;
+	if(local.tm_isdst)
+		tzone += HOUR;
+
+	/* Tokenize the input string. */
+	lasttoken = tokens;
+	while ((lasttoken->token = nexttoken(&p, &lasttoken->value)) != 0) {
+		++lasttoken;
+		if (lasttoken > tokens + 255)
+			return -1;
+	}
+	gds->tokenp = tokens;
+
+	/* Match phrases until we run out of input tokens. */
+	while (gds->tokenp < lasttoken) {
+		if (!phrase(gds))
+			return -1;
+	}
+
+	/* Use current local timezone if none was specified. */
+	if (!gds->HaveZone) {
+		gds->Timezone = tzone;
+		gds->DSTmode = DSTmaybe;
+	}
+
+	/* If a timezone was specified, use that for generating the default
+	 * time components instead of the local timezone. */
+	if (gds->HaveZone && gmt_ptr != NULL) {
+		now -= gds->Timezone;
+		gmt_ptr = gmtime (&now);
+		if (gmt_ptr != NULL)
+			local = *gmt_ptr;
+		now += gds->Timezone;
+	}
+
+	if (!gds->HaveYear)
+		gds->Year = local.tm_year + 1900;
+	if (!gds->HaveMonth)
+		gds->Month = local.tm_mon + 1;
+	if (!gds->HaveDay)
+		gds->Day = local.tm_mday;
+	/* Note: No default for hour/min/sec; a specifier that just
+	 * gives date always refers to 00:00 on that date. */
+
+	/* If we saw more than one time, timezone, weekday, year, month,
+	 * or day, then give up. */
+	if (gds->HaveTime > 1 || gds->HaveZone > 1 || gds->HaveWeekDay > 1
+	    || gds->HaveYear > 1 || gds->HaveMonth > 1 || gds->HaveDay > 1)
+		return -1;
+
+	/* Compute an absolute time based on whatever absolute information
+	 * we collected. */
+	if (gds->HaveYear || gds->HaveMonth || gds->HaveDay
+	    || gds->HaveTime || gds->HaveWeekDay) {
+		Start = Convert(gds->Month, gds->Day, gds->Year,
+		    gds->Hour, gds->Minutes, gds->Seconds,
+		    gds->Timezone, gds->DSTmode);
+		if (Start < 0)
+			return -1;
+	} else {
+		Start = now;
+		if (!gds->HaveRel)
+			Start -= local.tm_hour * HOUR + local.tm_min * MINUTE
+			    + local.tm_sec;
+	}
+
+	/* Add the relative offset. */
+	Start += gds->RelSeconds;
+	Start += RelativeMonth(Start, gds->Timezone, gds->RelMonth);
+
+	/* Adjust for day-of-week offsets. */
+	if (gds->HaveWeekDay
+	    && !(gds->HaveYear || gds->HaveMonth || gds->HaveDay)) {
+		tod = RelativeDate(Start, gds->Timezone,
+		    gds->DSTmode, gds->DayOrdinal, gds->DayNumber);
+		Start += tod;
+	}
+
+	/* -1 is an error indicator, so return 0 instead of -1 if
+	 * that's the actual time. */
+	return Start == -1 ? 0 : Start;
+}
+
+
+#if	defined(TEST)
+
+/* ARGSUSED */
+int
+main(int argc, char **argv)
+{
+    time_t	d;
+
+    while (*++argv != NULL) {
+	    (void)printf("Input: %s\n", *argv);
+	    d = get_date(*argv);
+	    if (d == -1)
+		    (void)printf("Bad format - couldn't convert.\n");
+	    else
+		    (void)printf("Output: %s\n", ctime(&d));
+    }
+    exit(0);
+    /* NOTREACHED */
+}
+#endif	/* defined(TEST) */
diff --git a/libarchive/archive_match.c b/libarchive/archive_match.c
new file mode 100644
index 0000000..6b6be9c
--- /dev/null
+++ b/libarchive/archive_match.c
@@ -0,0 +1,1841 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_entry.h"
+#include "archive_pathmatch.h"
+#include "archive_rb.h"
+#include "archive_string.h"
+
+struct match {
+	struct match		*next;
+	int			 matches;
+	struct archive_mstring	 pattern;
+};
+
+struct match_list {
+	struct match		*first;
+	struct match		**last;
+	int			 count;
+	int			 unmatched_count;
+	struct match		*unmatched_next;
+	int			 unmatched_eof;
+};
+
+struct match_file {
+	struct archive_rb_node	 node;
+	struct match_file	*next;
+	struct archive_mstring	 pathname;
+	int			 flag;
+	time_t			 mtime_sec;
+	long			 mtime_nsec;
+	time_t			 ctime_sec;
+	long			 ctime_nsec;
+};
+
+struct entry_list {
+	struct match_file	*first;
+	struct match_file	**last;
+	int			 count;
+};
+
+struct id_array {
+	size_t			 size;/* Allocated size */
+	size_t			 count;
+	int64_t			*ids;
+};
+
+#define PATTERN_IS_SET		1
+#define TIME_IS_SET		2
+#define ID_IS_SET		4
+
+struct archive_match {
+	struct archive		 archive;
+
+	/* exclusion/inclusion set flag. */
+	int			 setflag;
+
+	/*
+	 * Matching filename patterns.
+	 */
+	struct match_list	 exclusions;
+	struct match_list	 inclusions;
+
+	/*
+	 * Matching time stamps.
+	 */
+	time_t			 now;
+	int			 newer_mtime_filter;
+	time_t			 newer_mtime_sec;
+	long			 newer_mtime_nsec;
+	int			 newer_ctime_filter;
+	time_t			 newer_ctime_sec;
+	long			 newer_ctime_nsec;
+	int			 older_mtime_filter;
+	time_t			 older_mtime_sec;
+	long			 older_mtime_nsec;
+	int			 older_ctime_filter;
+	time_t			 older_ctime_sec;
+	long			 older_ctime_nsec;
+	/*
+	 * Matching time stamps with its filename.
+	 */
+	struct archive_rb_tree	 exclusion_tree;
+	struct entry_list 	 exclusion_entry_list;
+
+	/*
+	 * Matching file owners.
+	 */
+	struct id_array 	 inclusion_uids;
+	struct id_array 	 inclusion_gids;
+	struct match_list	 inclusion_unames;
+	struct match_list	 inclusion_gnames;
+};
+
+static int	add_pattern_from_file(struct archive_match *,
+		    struct match_list *, int, const void *, int);
+static int	add_entry(struct archive_match *, int,
+		    struct archive_entry *);
+static int	add_owner_id(struct archive_match *, struct id_array *,
+		    int64_t);
+static int	add_owner_name(struct archive_match *, struct match_list *,
+		    int, const void *);
+static int	add_pattern_mbs(struct archive_match *, struct match_list *,
+		    const char *);
+static int	add_pattern_wcs(struct archive_match *, struct match_list *,
+		    const wchar_t *);
+static int	cmp_key_mbs(const struct archive_rb_node *, const void *);
+static int	cmp_key_wcs(const struct archive_rb_node *, const void *);
+static int	cmp_node_mbs(const struct archive_rb_node *,
+		    const struct archive_rb_node *);
+static int	cmp_node_wcs(const struct archive_rb_node *,
+		    const struct archive_rb_node *);
+static void	entry_list_add(struct entry_list *, struct match_file *);
+static void	entry_list_free(struct entry_list *);
+static void	entry_list_init(struct entry_list *);
+static int	error_nomem(struct archive_match *);
+static void	match_list_add(struct match_list *, struct match *);
+static void	match_list_free(struct match_list *);
+static void	match_list_init(struct match_list *);
+static int	match_list_unmatched_inclusions_next(struct archive_match *,
+		    struct match_list *, int, const void **);
+static int	match_owner_id(struct id_array *, int64_t);
+#if !defined(_WIN32) || defined(__CYGWIN__)
+static int	match_owner_name_mbs(struct archive_match *,
+		    struct match_list *, const char *);
+#else
+static int	match_owner_name_wcs(struct archive_match *,
+		    struct match_list *, const wchar_t *);
+#endif
+static int	match_path_exclusion(struct archive_match *,
+		    struct match *, int, const void *);
+static int	match_path_inclusion(struct archive_match *,
+		    struct match *, int, const void *);
+static int	owner_excluded(struct archive_match *,
+		    struct archive_entry *);
+static int	path_excluded(struct archive_match *, int, const void *);
+static int	set_timefilter(struct archive_match *, int, time_t, long,
+		    time_t, long);
+static int	set_timefilter_pathname_mbs(struct archive_match *,
+		    int, const char *);
+static int	set_timefilter_pathname_wcs(struct archive_match *,
+		    int, const wchar_t *);
+static int	set_timefilter_date(struct archive_match *, int, const char *);
+static int	set_timefilter_date_w(struct archive_match *, int,
+		    const wchar_t *);
+static int	time_excluded(struct archive_match *,
+		    struct archive_entry *);
+static int	validate_time_flag(struct archive *, int, const char *);
+
+time_t __archive_get_date(time_t now, const char *);
+#define get_date __archive_get_date
+
+static const struct archive_rb_tree_ops rb_ops_mbs = {
+	cmp_node_mbs, cmp_key_mbs
+};
+
+static const struct archive_rb_tree_ops rb_ops_wcs = {
+	cmp_node_wcs, cmp_key_wcs
+};
+
+/*
+ * The matching logic here needs to be re-thought.  I started out to
+ * try to mimic gtar's matching logic, but it's not entirely
+ * consistent.  In particular 'tar -t' and 'tar -x' interpret patterns
+ * on the command line as anchored, but --exclude doesn't.
+ */
+
+static int
+error_nomem(struct archive_match *a)
+{
+	archive_set_error(&(a->archive), ENOMEM, "No memory");
+	a->archive.state = ARCHIVE_STATE_FATAL;
+	return (ARCHIVE_FATAL);
+}
+
+/*
+ * Create an ARCHIVE_MATCH object.
+ */
+struct archive *
+archive_match_new(void)
+{
+	struct archive_match *a;
+
+	a = (struct archive_match *)calloc(1, sizeof(*a));
+	if (a == NULL)
+		return (NULL);
+	a->archive.magic = ARCHIVE_MATCH_MAGIC;
+	a->archive.state = ARCHIVE_STATE_NEW;
+	match_list_init(&(a->inclusions));
+	match_list_init(&(a->exclusions));
+	__archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs);
+	entry_list_init(&(a->exclusion_entry_list));
+	match_list_init(&(a->inclusion_unames));
+	match_list_init(&(a->inclusion_gnames));
+	time(&a->now);
+	return (&(a->archive));
+}
+
+/*
+ * Free an ARCHIVE_MATCH object.
+ */
+int
+archive_match_free(struct archive *_a)
+{
+	struct archive_match *a;
+
+	if (_a == NULL)
+		return (ARCHIVE_OK);
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free");
+	a = (struct archive_match *)_a;
+	match_list_free(&(a->inclusions));
+	match_list_free(&(a->exclusions));
+	entry_list_free(&(a->exclusion_entry_list));
+	free(a->inclusion_uids.ids);
+	free(a->inclusion_gids.ids);
+	match_list_free(&(a->inclusion_unames));
+	match_list_free(&(a->inclusion_gnames));
+	free(a);
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Convenience function to perform all exclusion tests.
+ *
+ * Returns 1 if archive entry is excluded.
+ * Returns 0 if archive entry is not excluded.
+ * Returns <0 if something error happened.
+ */
+int
+archive_match_excluded(struct archive *_a, struct archive_entry *entry)
+{
+	struct archive_match *a;
+	int r;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_excluded_ae");
+
+	a = (struct archive_match *)_a;
+	if (entry == NULL) {
+		archive_set_error(&(a->archive), EINVAL, "entry is NULL");
+		return (ARCHIVE_FAILED);
+	}
+
+	r = 0;
+	if (a->setflag & PATTERN_IS_SET) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+		r = path_excluded(a, 0, archive_entry_pathname_w(entry));
+#else
+		r = path_excluded(a, 1, archive_entry_pathname(entry));
+#endif
+		if (r != 0)
+			return (r);
+	}
+
+	if (a->setflag & TIME_IS_SET) {
+		r = time_excluded(a, entry);
+		if (r != 0)
+			return (r);
+	}
+
+	if (a->setflag & ID_IS_SET)
+		r = owner_excluded(a, entry);
+	return (r);
+}
+
+/*
+ * Utility functions to manage exclusion/inclusion patterns
+ */
+
+int
+archive_match_exclude_pattern(struct archive *_a, const char *pattern)
+{
+	struct archive_match *a;
+	int r;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_exclude_pattern");
+	a = (struct archive_match *)_a;
+
+	if (pattern == NULL || *pattern == '\0') {
+		archive_set_error(&(a->archive), EINVAL, "pattern is empty");
+		return (ARCHIVE_FAILED);
+	}
+	if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
+		return (r);
+	return (ARCHIVE_OK);
+}
+
+int
+archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern)
+{
+	struct archive_match *a;
+	int r;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w");
+	a = (struct archive_match *)_a;
+
+	if (pattern == NULL || *pattern == L'\0') {
+		archive_set_error(&(a->archive), EINVAL, "pattern is empty");
+		return (ARCHIVE_FAILED);
+	}
+	if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
+		return (r);
+	return (ARCHIVE_OK);
+}
+
+int
+archive_match_exclude_pattern_from_file(struct archive *_a,
+    const char *pathname, int nullSeparator)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file");
+	a = (struct archive_match *)_a;
+
+	return add_pattern_from_file(a, &(a->exclusions), 1, pathname,
+		nullSeparator);
+}
+
+int
+archive_match_exclude_pattern_from_file_w(struct archive *_a,
+    const wchar_t *pathname, int nullSeparator)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w");
+	a = (struct archive_match *)_a;
+
+	return add_pattern_from_file(a, &(a->exclusions), 0, pathname,
+		nullSeparator);
+}
+
+int
+archive_match_include_pattern(struct archive *_a, const char *pattern)
+{
+	struct archive_match *a;
+	int r;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_include_pattern");
+	a = (struct archive_match *)_a;
+
+	if (pattern == NULL || *pattern == '\0') {
+		archive_set_error(&(a->archive), EINVAL, "pattern is empty");
+		return (ARCHIVE_FAILED);
+	}
+	if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
+		return (r);
+	return (ARCHIVE_OK);
+}
+
+int
+archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern)
+{
+	struct archive_match *a;
+	int r;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_include_pattern_w");
+	a = (struct archive_match *)_a;
+
+	if (pattern == NULL || *pattern == L'\0') {
+		archive_set_error(&(a->archive), EINVAL, "pattern is empty");
+		return (ARCHIVE_FAILED);
+	}
+	if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
+		return (r);
+	return (ARCHIVE_OK);
+}
+
+int
+archive_match_include_pattern_from_file(struct archive *_a,
+    const char *pathname, int nullSeparator)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file");
+	a = (struct archive_match *)_a;
+
+	return add_pattern_from_file(a, &(a->inclusions), 1, pathname,
+		nullSeparator);
+}
+
+int
+archive_match_include_pattern_from_file_w(struct archive *_a,
+    const wchar_t *pathname, int nullSeparator)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w");
+	a = (struct archive_match *)_a;
+
+	return add_pattern_from_file(a, &(a->inclusions), 0, pathname,
+		nullSeparator);
+}
+
+/*
+ * Test functions for pathname patterns.
+ *
+ * Returns 1 if archive entry is excluded.
+ * Returns 0 if archive entry is not excluded.
+ * Returns <0 if something error happened.
+ */
+int
+archive_match_path_excluded(struct archive *_a,
+    struct archive_entry *entry)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_path_excluded");
+
+	a = (struct archive_match *)_a;
+	if (entry == NULL) {
+		archive_set_error(&(a->archive), EINVAL, "entry is NULL");
+		return (ARCHIVE_FAILED);
+	}
+
+	/* If we don't have exclusion/inclusion pattern set at all,
+	 * the entry is always not excluded. */
+	if ((a->setflag & PATTERN_IS_SET) == 0)
+		return (0);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	return (path_excluded(a, 0, archive_entry_pathname_w(entry)));
+#else
+	return (path_excluded(a, 1, archive_entry_pathname(entry)));
+#endif
+}
+
+/*
+ * Utilty functions to get statistic information for inclusion patterns.
+ */
+int
+archive_match_path_unmatched_inclusions(struct archive *_a)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions");
+	a = (struct archive_match *)_a;
+
+	return (a->inclusions.unmatched_count);
+}
+
+int
+archive_match_path_unmatched_inclusions_next(struct archive *_a,
+    const char **_p)
+{
+	struct archive_match *a;
+	const void *v;
+	int r;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next");
+	a = (struct archive_match *)_a;
+
+	r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v);
+	*_p = (const char *)v;
+	return (r);
+}
+
+int
+archive_match_path_unmatched_inclusions_next_w(struct archive *_a,
+    const wchar_t **_p)
+{
+	struct archive_match *a;
+	const void *v;
+	int r;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w");
+	a = (struct archive_match *)_a;
+
+	r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v);
+	*_p = (const wchar_t *)v;
+	return (r);
+}
+
+/*
+ * Add inclusion/exclusion patterns.
+ */
+static int
+add_pattern_mbs(struct archive_match *a, struct match_list *list,
+    const char *pattern)
+{
+	struct match *match;
+	size_t len;
+
+	match = calloc(1, sizeof(*match));
+	if (match == NULL)
+		return (error_nomem(a));
+	/* Both "foo/" and "foo" should match "foo/bar". */
+	len = strlen(pattern);
+	if (len && pattern[len - 1] == '/')
+		--len;
+	archive_mstring_copy_mbs_len(&(match->pattern), pattern, len);
+	match_list_add(list, match);
+	a->setflag |= PATTERN_IS_SET;
+	return (ARCHIVE_OK);
+}
+
+static int
+add_pattern_wcs(struct archive_match *a, struct match_list *list,
+    const wchar_t *pattern)
+{
+	struct match *match;
+	size_t len;
+
+	match = calloc(1, sizeof(*match));
+	if (match == NULL)
+		return (error_nomem(a));
+	/* Both "foo/" and "foo" should match "foo/bar". */
+	len = wcslen(pattern);
+	if (len && pattern[len - 1] == L'/')
+		--len;
+	archive_mstring_copy_wcs_len(&(match->pattern), pattern, len);
+	match_list_add(list, match);
+	a->setflag |= PATTERN_IS_SET;
+	return (ARCHIVE_OK);
+}
+
+static int
+add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
+    int mbs, const void *pathname, int nullSeparator)
+{
+	struct archive *ar;
+	struct archive_entry *ae;
+	struct archive_string as;
+	const void *buff;
+	size_t size;
+	int64_t offset;
+	int r;
+
+	ar = archive_read_new(); 
+	if (ar == NULL) {
+		archive_set_error(&(a->archive), ENOMEM, "No memory");
+		return (ARCHIVE_FATAL);
+	}
+	r = archive_read_support_format_raw(ar);
+	if (r != ARCHIVE_OK) {
+		archive_copy_error(&(a->archive), ar);
+		archive_read_free(ar);
+		return (r);
+	}
+	if (mbs)
+		r = archive_read_open_filename(ar, pathname, 512*20);
+	else
+		r = archive_read_open_filename_w(ar, pathname, 512*20);
+	if (r != ARCHIVE_OK) {
+		archive_copy_error(&(a->archive), ar);
+		archive_read_free(ar);
+		return (r);
+	}
+	r = archive_read_next_header(ar, &ae);
+	if (r != ARCHIVE_OK) {
+		archive_copy_error(&(a->archive), ar);
+		archive_read_free(ar);
+		return (r);
+	}
+
+	archive_string_init(&as);
+
+	while ((r = archive_read_data_block(ar, &buff, &size, &offset))
+	    == ARCHIVE_OK) {
+		const char *b = (const char *)buff;
+
+		while (size) {
+			const char *s = (const char *)b;
+			size_t length = 0;
+			int found_separator = 0;
+
+			while (length < size) {
+				if (nullSeparator) {
+					if (*b == '\0') {
+						found_separator = 1;
+						break;
+					}
+				} else {
+			            	if (*b == 0x0d || *b == 0x0a) {
+						found_separator = 1;
+						break;
+					}
+				}
+				b++;
+				length++;
+			}
+			if (!found_separator) {
+				archive_strncat(&as, s, length);
+				/* Read next data block. */
+				break;
+			}
+			b++;
+			size -= length + 1;
+			archive_strncat(&as, s, length);
+
+			/* If the line is not empty, add the pattern. */
+			if (archive_strlen(&as) > 0) {
+				/* Add pattern. */
+				r = add_pattern_mbs(a, mlist, as.s);
+				if (r != ARCHIVE_OK) {
+					archive_read_free(ar);
+					archive_string_free(&as);
+					return (r);
+				}
+				archive_string_empty(&as);
+			}
+		}
+	}
+
+	/* If something error happend, report it immediately. */ 
+	if (r < ARCHIVE_OK) {
+		archive_copy_error(&(a->archive), ar);
+		archive_read_free(ar);
+		archive_string_free(&as);
+		return (r);
+	}
+
+	/* If the line is not empty, add the pattern. */
+	if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) {
+		/* Add pattern. */
+		r = add_pattern_mbs(a, mlist, as.s);
+		if (r != ARCHIVE_OK) {
+			archive_read_free(ar);
+			archive_string_free(&as);
+			return (r);
+		}
+	}
+	archive_read_free(ar);
+	archive_string_free(&as);
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Test if pathname is excluded by inclusion/exclusion patterns.
+ */
+static int
+path_excluded(struct archive_match *a, int mbs, const void *pathname)
+{
+	struct match *match;
+	struct match *matched;
+	int r;
+
+	if (a == NULL)
+		return (0);
+
+	/* Mark off any unmatched inclusions. */
+	/* In particular, if a filename does appear in the archive and
+	 * is explicitly included and excluded, then we don't report
+	 * it as missing even though we don't extract it.
+	 */
+	matched = NULL;
+	for (match = a->inclusions.first; match != NULL;
+	    match = match->next){
+		if (match->matches == 0 &&
+		    (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
+			if (r < 0)
+				return (r);
+			a->inclusions.unmatched_count--;
+			match->matches++;
+			matched = match;
+		}
+	}
+
+	/* Exclusions take priority */
+	for (match = a->exclusions.first; match != NULL;
+	    match = match->next){
+		r = match_path_exclusion(a, match, mbs, pathname);
+		if (r)
+			return (r);
+	}
+
+	/* It's not excluded and we found an inclusion above, so it's
+	 * included. */
+	if (matched != NULL)
+		return (0);
+
+
+	/* We didn't find an unmatched inclusion, check the remaining ones. */
+	for (match = a->inclusions.first; match != NULL;
+	    match = match->next){
+		/* We looked at previously-unmatched inclusions already. */
+		if (match->matches > 0 &&
+		    (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
+			if (r < 0)
+				return (r);
+			match->matches++;
+			return (0);
+		}
+	}
+
+	/* If there were inclusions, default is to exclude. */
+	if (a->inclusions.first != NULL)
+	    return (1);
+
+	/* No explicit inclusions, default is to match. */
+	return (0);
+}
+
+/*
+ * This is a little odd, but it matches the default behavior of
+ * gtar.  In particular, 'a*b' will match 'foo/a1111/222b/bar'
+ *
+ */
+static int
+match_path_exclusion(struct archive_match *a, struct match *m,
+    int mbs, const void *pn)
+{
+	int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END;
+	int r;
+
+	if (mbs) {
+		const char *p;
+		r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
+		if (r == 0)
+			return (archive_pathmatch(p, (const char *)pn, flag));
+	} else {
+		const wchar_t *p;
+		r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
+		if (r == 0)
+			return (archive_pathmatch_w(p, (const wchar_t *)pn,
+				flag));
+	}
+	if (errno == ENOMEM)
+		return (error_nomem(a));
+	return (0);
+}
+
+/*
+ * Again, mimic gtar:  inclusions are always anchored (have to match
+ * the beginning of the path) even though exclusions are not anchored.
+ */
+static int
+match_path_inclusion(struct archive_match *a, struct match *m,
+    int mbs, const void *pn)
+{
+	int flag = PATHMATCH_NO_ANCHOR_END;
+	int r;
+
+	if (mbs) {
+		const char *p;
+		r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
+		if (r == 0)
+			return (archive_pathmatch(p, (const char *)pn, flag));
+	} else {
+		const wchar_t *p;
+		r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
+		if (r == 0)
+			return (archive_pathmatch_w(p, (const wchar_t *)pn,
+				flag));
+	}
+	if (errno == ENOMEM)
+		return (error_nomem(a));
+	return (0);
+}
+
+static void
+match_list_init(struct match_list *list)
+{
+	list->first = NULL;
+	list->last = &(list->first);
+	list->count = 0;
+}
+
+static void
+match_list_free(struct match_list *list)
+{
+	struct match *p, *q;
+
+	for (p = list->first; p != NULL; ) {
+		q = p;
+		p = p->next;
+		archive_mstring_clean(&(q->pattern));
+		free(q);
+	}
+}
+
+static void
+match_list_add(struct match_list *list, struct match *m)
+{
+	*list->last = m;
+	list->last = &(m->next);
+	list->count++;
+	list->unmatched_count++;
+}
+
+static int
+match_list_unmatched_inclusions_next(struct archive_match *a,
+    struct match_list *list, int mbs, const void **vp)
+{
+	struct match *m;
+
+	*vp = NULL;
+	if (list->unmatched_eof) {
+		list->unmatched_eof = 0;
+		return (ARCHIVE_EOF);
+	}
+	if (list->unmatched_next == NULL) {
+		if (list->unmatched_count == 0)
+			return (ARCHIVE_EOF);
+		list->unmatched_next = list->first;
+	}
+
+	for (m = list->unmatched_next; m != NULL; m = m->next) {
+		int r;
+
+		if (m->matches)
+			continue;
+		if (mbs) {
+			const char *p;
+			r = archive_mstring_get_mbs(&(a->archive),
+				&(m->pattern), &p);
+			if (r < 0 && errno == ENOMEM)
+				return (error_nomem(a));
+			if (p == NULL)
+				p = "";
+			*vp = p;
+		} else {
+			const wchar_t *p;
+			r = archive_mstring_get_wcs(&(a->archive),
+				&(m->pattern), &p);
+			if (r < 0 && errno == ENOMEM)
+				return (error_nomem(a));
+			if (p == NULL)
+				p = L"";
+			*vp = p;
+		}
+		list->unmatched_next = m->next;
+		if (list->unmatched_next == NULL)
+			/* To return EOF next time. */
+			list->unmatched_eof = 1;
+		return (ARCHIVE_OK);
+	}
+	list->unmatched_next = NULL;
+	return (ARCHIVE_EOF);
+}
+
+/*
+ * Utility functions to manage inclusion timestamps.
+ */
+int
+archive_match_include_time(struct archive *_a, int flag, time_t sec,
+    long nsec)
+{
+	int r;
+
+	r = validate_time_flag(_a, flag, "archive_match_include_time");
+	if (r != ARCHIVE_OK)
+		return (r);
+	return set_timefilter((struct archive_match *)_a, flag,
+			sec, nsec, sec, nsec);
+}
+
+int
+archive_match_include_date(struct archive *_a, int flag,
+    const char *datestr)
+{
+	int r;
+
+	r = validate_time_flag(_a, flag, "archive_match_include_date");
+	if (r != ARCHIVE_OK)
+		return (r);
+	return set_timefilter_date((struct archive_match *)_a, flag, datestr);
+}
+
+int
+archive_match_include_date_w(struct archive *_a, int flag,
+    const wchar_t *datestr)
+{
+	int r;
+
+	r = validate_time_flag(_a, flag, "archive_match_include_date_w");
+	if (r != ARCHIVE_OK)
+		return (r);
+
+	return set_timefilter_date_w((struct archive_match *)_a, flag, datestr);
+}
+
+int
+archive_match_include_file_time(struct archive *_a, int flag,
+    const char *pathname)
+{
+	int r;
+
+	r = validate_time_flag(_a, flag, "archive_match_include_file_time");
+	if (r != ARCHIVE_OK)
+		return (r);
+	return set_timefilter_pathname_mbs((struct archive_match *)_a,
+			flag, pathname);
+}
+
+int
+archive_match_include_file_time_w(struct archive *_a, int flag,
+    const wchar_t *pathname)
+{
+	int r;
+
+	r = validate_time_flag(_a, flag, "archive_match_include_file_time_w");
+	if (r != ARCHIVE_OK)
+		return (r);
+	return set_timefilter_pathname_wcs((struct archive_match *)_a,
+			flag, pathname);
+}
+
+int
+archive_match_exclude_entry(struct archive *_a, int flag,
+    struct archive_entry *entry)
+{
+	struct archive_match *a;
+	int r;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_time_include_entry");
+	a = (struct archive_match *)_a;
+
+	if (entry == NULL) {
+		archive_set_error(&(a->archive), EINVAL, "entry is NULL");
+		return (ARCHIVE_FAILED);
+	}
+	r = validate_time_flag(_a, flag, "archive_match_exclude_entry");
+	if (r != ARCHIVE_OK)
+		return (r);
+	return (add_entry(a, flag, entry));
+}
+
+/*
+ * Test function for time stamps.
+ *
+ * Returns 1 if archive entry is excluded.
+ * Returns 0 if archive entry is not excluded.
+ * Returns <0 if something error happened.
+ */
+int
+archive_match_time_excluded(struct archive *_a,
+    struct archive_entry *entry)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae");
+
+	a = (struct archive_match *)_a;
+	if (entry == NULL) {
+		archive_set_error(&(a->archive), EINVAL, "entry is NULL");
+		return (ARCHIVE_FAILED);
+	}
+
+	/* If we don't have inclusion time set at all, the entry is always
+	 * not excluded. */
+	if ((a->setflag & TIME_IS_SET) == 0)
+		return (0);
+	return (time_excluded(a, entry));
+}
+
+static int
+validate_time_flag(struct archive *_a, int flag, const char *_fn)
+{
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, _fn);
+
+	/* Check a type of time. */
+	if (flag &
+	   ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) {
+		archive_set_error(_a, EINVAL, "Invalid time flag");
+		return (ARCHIVE_FAILED);
+	}
+	if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) {
+		archive_set_error(_a, EINVAL, "No time flag");
+		return (ARCHIVE_FAILED);
+	}
+
+	/* Check a type of comparison. */
+	if (flag &
+	   ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
+			| ARCHIVE_MATCH_EQUAL)) & 0x00ff)) {
+		archive_set_error(_a, EINVAL, "Invalid comparison flag");
+		return (ARCHIVE_FAILED);
+	}
+	if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
+	    | ARCHIVE_MATCH_EQUAL)) == 0) {
+		archive_set_error(_a, EINVAL, "No comparison flag");
+		return (ARCHIVE_FAILED);
+	}
+
+	return (ARCHIVE_OK);
+}
+
+#define JUST_EQUAL(t) (((t) &  (ARCHIVE_MATCH_EQUAL |\
+	ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL)
+static int
+set_timefilter(struct archive_match *a, int timetype,
+    time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec)
+{
+	if (timetype & ARCHIVE_MATCH_MTIME) {
+		if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
+			a->newer_mtime_filter = timetype;
+			a->newer_mtime_sec = mtime_sec;
+			a->newer_mtime_nsec = mtime_nsec;
+			a->setflag |= TIME_IS_SET;
+		}
+		if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
+			a->older_mtime_filter = timetype;
+			a->older_mtime_sec = mtime_sec;
+			a->older_mtime_nsec = mtime_nsec;
+			a->setflag |= TIME_IS_SET;
+		}
+	}
+	if (timetype & ARCHIVE_MATCH_CTIME) {
+		if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
+			a->newer_ctime_filter = timetype;
+			a->newer_ctime_sec = ctime_sec;
+			a->newer_ctime_nsec = ctime_nsec;
+			a->setflag |= TIME_IS_SET;
+		}
+		if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
+			a->older_ctime_filter = timetype;
+			a->older_ctime_sec = ctime_sec;
+			a->older_ctime_nsec = ctime_nsec;
+			a->setflag |= TIME_IS_SET;
+		}
+	}
+	return (ARCHIVE_OK);
+}
+
+static int
+set_timefilter_date(struct archive_match *a, int timetype, const char *datestr)
+{
+	time_t t;
+
+	if (datestr == NULL || *datestr == '\0') {
+		archive_set_error(&(a->archive), EINVAL, "date is empty");
+		return (ARCHIVE_FAILED);
+	}
+	t = get_date(a->now, datestr);
+	if (t == (time_t)-1) {
+		archive_set_error(&(a->archive), EINVAL, "invalid date string");
+		return (ARCHIVE_FAILED);
+	}
+	return set_timefilter(a, timetype, t, 0, t, 0);
+}
+
+static int
+set_timefilter_date_w(struct archive_match *a, int timetype,
+    const wchar_t *datestr)
+{
+	struct archive_string as;
+	time_t t;
+
+	if (datestr == NULL || *datestr == L'\0') {
+		archive_set_error(&(a->archive), EINVAL, "date is empty");
+		return (ARCHIVE_FAILED);
+	}
+
+	archive_string_init(&as);
+	if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) {
+		archive_string_free(&as);
+		if (errno == ENOMEM)
+			return (error_nomem(a));
+		archive_set_error(&(a->archive), -1,
+		    "Failed to convert WCS to MBS");
+		return (ARCHIVE_FAILED);
+	}
+	t = get_date(a->now, as.s);
+	archive_string_free(&as);
+	if (t == (time_t)-1) {
+		archive_set_error(&(a->archive), EINVAL, "invalid date string");
+		return (ARCHIVE_FAILED);
+	}
+	return set_timefilter(a, timetype, t, 0, t, 0);
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
+static int
+set_timefilter_find_data(struct archive_match *a, int timetype,
+    DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime,
+    DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime)
+{
+	ULARGE_INTEGER utc;
+	time_t ctime_sec, mtime_sec;
+	long ctime_ns, mtime_ns;
+
+	utc.HighPart = ftCreationTime_dwHighDateTime;
+	utc.LowPart = ftCreationTime_dwLowDateTime;
+	if (utc.QuadPart >= EPOC_TIME) {
+		utc.QuadPart -= EPOC_TIME;
+		ctime_sec = (time_t)(utc.QuadPart / 10000000);
+		ctime_ns = (long)(utc.QuadPart % 10000000) * 100;
+	} else {
+		ctime_sec = 0;
+		ctime_ns = 0;
+	}
+	utc.HighPart = ftLastWriteTime_dwHighDateTime;
+	utc.LowPart = ftLastWriteTime_dwLowDateTime;
+	if (utc.QuadPart >= EPOC_TIME) {
+		utc.QuadPart -= EPOC_TIME;
+		mtime_sec = (time_t)(utc.QuadPart / 10000000);
+		mtime_ns = (long)(utc.QuadPart % 10000000) * 100;
+	} else {
+		mtime_sec = 0;
+		mtime_ns = 0;
+	}
+	return set_timefilter(a, timetype,
+			mtime_sec, mtime_ns, ctime_sec, ctime_ns);
+}
+
+static int
+set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
+    const char *path)
+{
+	/* NOTE: stat() on Windows cannot handle nano seconds. */
+	HANDLE h;
+	WIN32_FIND_DATA d;
+
+	if (path == NULL || *path == '\0') {
+		archive_set_error(&(a->archive), EINVAL, "pathname is empty");
+		return (ARCHIVE_FAILED);
+	}
+	h = FindFirstFileA(path, &d);
+	if (h == INVALID_HANDLE_VALUE) {
+		la_dosmaperr(GetLastError());
+		archive_set_error(&(a->archive), errno,
+		    "Failed to FindFirstFileA");
+		return (ARCHIVE_FAILED);
+	}
+	FindClose(h);
+	return set_timefilter_find_data(a, timetype,
+	    d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
+	    d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
+}
+
+static int
+set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
+    const wchar_t *path)
+{
+	HANDLE h;
+	WIN32_FIND_DATAW d;
+
+	if (path == NULL || *path == L'\0') {
+		archive_set_error(&(a->archive), EINVAL, "pathname is empty");
+		return (ARCHIVE_FAILED);
+	}
+	h = FindFirstFileW(path, &d);
+	if (h == INVALID_HANDLE_VALUE) {
+		la_dosmaperr(GetLastError());
+		archive_set_error(&(a->archive), errno,
+		    "Failed to FindFirstFile");
+		return (ARCHIVE_FAILED);
+	}
+	FindClose(h);
+	return set_timefilter_find_data(a, timetype,
+	    d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
+	    d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
+}
+
+#else /* _WIN32 && !__CYGWIN__ */
+
+static int
+set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st)
+{
+	struct archive_entry *ae;
+	time_t ctime_sec, mtime_sec;
+	long ctime_ns, mtime_ns;
+
+	ae = archive_entry_new();
+	if (ae == NULL)
+		return (error_nomem(a));
+	archive_entry_copy_stat(ae, st);
+	ctime_sec = archive_entry_ctime(ae);
+	ctime_ns = archive_entry_ctime_nsec(ae);
+	mtime_sec = archive_entry_mtime(ae);
+	mtime_ns = archive_entry_mtime_nsec(ae);
+	archive_entry_free(ae);
+	return set_timefilter(a, timetype, mtime_sec, mtime_ns,
+			ctime_sec, ctime_ns);
+}
+
+static int
+set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
+    const char *path)
+{
+	struct stat st;
+
+	if (path == NULL || *path == '\0') {
+		archive_set_error(&(a->archive), EINVAL, "pathname is empty");
+		return (ARCHIVE_FAILED);
+	}
+	if (stat(path, &st) != 0) {
+		archive_set_error(&(a->archive), errno, "Failed to stat()");
+		return (ARCHIVE_FAILED);
+	}
+	return (set_timefilter_stat(a, timetype, &st));
+}
+
+static int
+set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
+    const wchar_t *path)
+{
+	struct archive_string as;
+	int r;
+
+	if (path == NULL || *path == L'\0') {
+		archive_set_error(&(a->archive), EINVAL, "pathname is empty");
+		return (ARCHIVE_FAILED);
+	}
+
+	/* Convert WCS filename to MBS filename. */
+	archive_string_init(&as);
+	if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) {
+		archive_string_free(&as);
+		if (errno == ENOMEM)
+			return (error_nomem(a));
+		archive_set_error(&(a->archive), -1,
+		    "Failed to convert WCS to MBS");
+		return (ARCHIVE_FAILED);
+	}
+
+	r = set_timefilter_pathname_mbs(a, timetype, as.s);
+	archive_string_free(&as);
+
+	return (r);
+}
+#endif /* _WIN32 && !__CYGWIN__ */
+
+/*
+ * Call back funtions for archive_rb.
+ */
+static int
+cmp_node_mbs(const struct archive_rb_node *n1,
+    const struct archive_rb_node *n2)
+{
+	struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
+	struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
+	const char *p1, *p2;
+
+	archive_mstring_get_mbs(NULL, &(f1->pathname), &p1);
+	archive_mstring_get_mbs(NULL, &(f2->pathname), &p2);
+	if (p1 == NULL)
+		return (1);
+	if (p2 == NULL)
+		return (-1);
+	return (strcmp(p1, p2));
+}
+        
+static int
+cmp_key_mbs(const struct archive_rb_node *n, const void *key)
+{
+	struct match_file *f = (struct match_file *)(uintptr_t)n;
+	const char *p;
+
+	archive_mstring_get_mbs(NULL, &(f->pathname), &p);
+	if (p == NULL)
+		return (-1);
+	return (strcmp(p, (const char *)key));
+}
+
+static int
+cmp_node_wcs(const struct archive_rb_node *n1,
+    const struct archive_rb_node *n2)
+{
+	struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
+	struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
+	const wchar_t *p1, *p2;
+
+	archive_mstring_get_wcs(NULL, &(f1->pathname), &p1);
+	archive_mstring_get_wcs(NULL, &(f2->pathname), &p2);
+	if (p1 == NULL)
+		return (1);
+	if (p2 == NULL)
+		return (-1);
+	return (wcscmp(p1, p2));
+}
+        
+static int
+cmp_key_wcs(const struct archive_rb_node *n, const void *key)
+{
+	struct match_file *f = (struct match_file *)(uintptr_t)n;
+	const wchar_t *p;
+
+	archive_mstring_get_wcs(NULL, &(f->pathname), &p);
+	if (p == NULL)
+		return (-1);
+	return (wcscmp(p, (const wchar_t *)key));
+}
+
+static void
+entry_list_init(struct entry_list *list)
+{
+	list->first = NULL;
+	list->last = &(list->first);
+	list->count = 0;
+}
+
+static void
+entry_list_free(struct entry_list *list)
+{
+	struct match_file *p, *q;
+
+	for (p = list->first; p != NULL; ) {
+		q = p;
+		p = p->next;
+		archive_mstring_clean(&(q->pathname));
+		free(q);
+	}
+}
+
+static void
+entry_list_add(struct entry_list *list, struct match_file *file)
+{
+	*list->last = file;
+	list->last = &(file->next);
+	list->count++;
+}
+
+static int
+add_entry(struct archive_match *a, int flag,
+    struct archive_entry *entry)
+{
+	struct match_file *f;
+	const void *pathname;
+	int r;
+
+	f = calloc(1, sizeof(*f));
+	if (f == NULL)
+		return (error_nomem(a));
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	pathname = archive_entry_pathname_w(entry);
+	if (pathname == NULL) {
+		free(f);
+		archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
+		return (ARCHIVE_FAILED);
+	}
+	archive_mstring_copy_wcs(&(f->pathname), pathname);
+	a->exclusion_tree.rbt_ops = &rb_ops_wcs;
+#else
+	(void)rb_ops_wcs;
+	pathname = archive_entry_pathname(entry);
+	if (pathname == NULL) {
+		free(f);
+		archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
+		return (ARCHIVE_FAILED);
+	}
+	archive_mstring_copy_mbs(&(f->pathname), pathname);
+	a->exclusion_tree.rbt_ops = &rb_ops_mbs;
+#endif
+	f->flag = flag;
+	f->mtime_sec = archive_entry_mtime(entry);
+	f->mtime_nsec = archive_entry_mtime_nsec(entry);
+	f->ctime_sec = archive_entry_ctime(entry);
+	f->ctime_nsec = archive_entry_ctime_nsec(entry);
+	r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node));
+	if (!r) {
+		struct match_file *f2;
+
+		/* Get the duplicated file. */
+		f2 = (struct match_file *)__archive_rb_tree_find_node(
+			&(a->exclusion_tree), pathname);
+
+		/*
+		 * We always overwrite comparison condision.
+		 * If you do not want to overwrite it, you should not
+		 * call archive_match_exclude_entry(). We cannot know
+		 * what behavior you really expect since overwriting
+		 * condition might be different with the flag.
+		 */
+		if (f2 != NULL) {
+			f2->flag = f->flag;
+			f2->mtime_sec = f->mtime_sec;
+			f2->mtime_nsec = f->mtime_nsec;
+			f2->ctime_sec = f->ctime_sec;
+			f2->ctime_nsec = f->ctime_nsec;
+		}
+		/* Release the duplicated file. */
+		archive_mstring_clean(&(f->pathname));
+		free(f);
+		return (ARCHIVE_OK);
+	}
+	entry_list_add(&(a->exclusion_entry_list), f);
+	a->setflag |= TIME_IS_SET;
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Test if entry is excluded by its timestamp.
+ */
+static int
+time_excluded(struct archive_match *a, struct archive_entry *entry)
+{
+	struct match_file *f;
+	const void *pathname;
+	time_t sec;
+	long nsec;
+
+	/*
+	 * If this file/dir is excluded by a time comparison, skip it.
+	 */
+	if (a->newer_ctime_filter) {
+		/* If ctime is not set, use mtime instead. */
+		if (archive_entry_ctime_is_set(entry))
+			sec = archive_entry_ctime(entry);
+		else
+			sec = archive_entry_mtime(entry);
+		if (sec < a->newer_ctime_sec)
+			return (1); /* Too old, skip it. */
+		if (sec == a->newer_ctime_sec) {
+			if (archive_entry_ctime_is_set(entry))
+				nsec = archive_entry_ctime_nsec(entry);
+			else
+				nsec = archive_entry_mtime_nsec(entry);
+			if (nsec < a->newer_ctime_nsec)
+				return (1); /* Too old, skip it. */
+			if (nsec == a->newer_ctime_nsec &&
+			    (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL)
+			      == 0)
+				return (1); /* Equal, skip it. */
+		}
+	}
+	if (a->older_ctime_filter) {
+		/* If ctime is not set, use mtime instead. */
+		if (archive_entry_ctime_is_set(entry))
+			sec = archive_entry_ctime(entry);
+		else
+			sec = archive_entry_mtime(entry);
+		if (sec > a->older_ctime_sec)
+			return (1); /* Too new, skip it. */
+		if (sec == a->older_ctime_sec) {
+			if (archive_entry_ctime_is_set(entry))
+				nsec = archive_entry_ctime_nsec(entry);
+			else
+				nsec = archive_entry_mtime_nsec(entry);
+			if (nsec > a->older_ctime_nsec)
+				return (1); /* Too new, skip it. */
+			if (nsec == a->older_ctime_nsec &&
+			    (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL)
+			      == 0)
+				return (1); /* Eeual, skip it. */
+		}
+	}
+	if (a->newer_mtime_filter) {
+		sec = archive_entry_mtime(entry);
+		if (sec < a->newer_mtime_sec)
+			return (1); /* Too old, skip it. */
+		if (sec == a->newer_mtime_sec) {
+			nsec = archive_entry_mtime_nsec(entry);
+			if (nsec < a->newer_mtime_nsec)
+				return (1); /* Too old, skip it. */
+			if (nsec == a->newer_mtime_nsec &&
+			    (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL)
+			       == 0)
+				return (1); /* Equal, skip it. */
+		}
+	}
+	if (a->older_mtime_filter) {
+		sec = archive_entry_mtime(entry);
+		if (sec > a->older_mtime_sec)
+			return (1); /* Too new, skip it. */
+		nsec = archive_entry_mtime_nsec(entry);
+		if (sec == a->older_mtime_sec) {
+			if (nsec > a->older_mtime_nsec)
+				return (1); /* Too new, skip it. */
+			if (nsec == a->older_mtime_nsec &&
+			    (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL)
+			       == 0)
+				return (1); /* Equal, skip it. */
+		}
+	}
+
+	/* If there is no excluson list, include the file. */
+	if (a->exclusion_entry_list.count == 0)
+		return (0);
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	pathname = archive_entry_pathname_w(entry);
+	a->exclusion_tree.rbt_ops = &rb_ops_wcs;
+#else
+	(void)rb_ops_wcs;
+	pathname = archive_entry_pathname(entry);
+	a->exclusion_tree.rbt_ops = &rb_ops_mbs;
+#endif
+	if (pathname == NULL)
+		return (0);
+
+	f = (struct match_file *)__archive_rb_tree_find_node(
+		&(a->exclusion_tree), pathname);
+	/* If the file wasn't rejected, include it. */
+	if (f == NULL)
+		return (0);
+
+	if (f->flag & ARCHIVE_MATCH_CTIME) {
+		sec = archive_entry_ctime(entry);
+		if (f->ctime_sec > sec) {
+			if (f->flag & ARCHIVE_MATCH_OLDER)
+				return (1);
+		} else if (f->ctime_sec < sec) {
+			if (f->flag & ARCHIVE_MATCH_NEWER)
+				return (1);
+		} else {
+			nsec = archive_entry_ctime_nsec(entry);
+			if (f->ctime_nsec > nsec) {
+				if (f->flag & ARCHIVE_MATCH_OLDER)
+					return (1);
+			} else if (f->ctime_nsec < nsec) {
+				if (f->flag & ARCHIVE_MATCH_NEWER)
+					return (1);
+			} else if (f->flag & ARCHIVE_MATCH_EQUAL)
+				return (1);
+		}
+	}
+	if (f->flag & ARCHIVE_MATCH_MTIME) {
+		sec = archive_entry_mtime(entry);
+		if (f->mtime_sec > sec) {
+			if (f->flag & ARCHIVE_MATCH_OLDER)
+				return (1);
+		} else if (f->mtime_sec < sec) {
+			if (f->flag & ARCHIVE_MATCH_NEWER)
+				return (1);
+		} else {
+			nsec = archive_entry_mtime_nsec(entry);
+			if (f->mtime_nsec > nsec) {
+				if (f->flag & ARCHIVE_MATCH_OLDER)
+					return (1);
+			} else if (f->mtime_nsec < nsec) {
+				if (f->flag & ARCHIVE_MATCH_NEWER)
+					return (1);
+			} else if (f->flag & ARCHIVE_MATCH_EQUAL)
+				return (1);
+		}
+	}
+	return (0);
+}
+
+/*
+ * Utility functions to manage inclusion owners
+ */
+
+int
+archive_match_include_uid(struct archive *_a, int64_t uid)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_include_uid");
+	a = (struct archive_match *)_a;
+	return (add_owner_id(a, &(a->inclusion_uids), uid));
+}
+
+int
+archive_match_include_gid(struct archive *_a, int64_t gid)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_include_gid");
+	a = (struct archive_match *)_a;
+	return (add_owner_id(a, &(a->inclusion_gids), gid));
+}
+
+int
+archive_match_include_uname(struct archive *_a, const char *uname)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_include_uname");
+	a = (struct archive_match *)_a;
+	return (add_owner_name(a, &(a->inclusion_unames), 1, uname));
+}
+
+int
+archive_match_include_uname_w(struct archive *_a, const wchar_t *uname)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_include_uname_w");
+	a = (struct archive_match *)_a;
+	return (add_owner_name(a, &(a->inclusion_unames), 0, uname));
+}
+
+int
+archive_match_include_gname(struct archive *_a, const char *gname)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_include_gname");
+	a = (struct archive_match *)_a;
+	return (add_owner_name(a, &(a->inclusion_gnames), 1, gname));
+}
+
+int
+archive_match_include_gname_w(struct archive *_a, const wchar_t *gname)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_include_gname_w");
+	a = (struct archive_match *)_a;
+	return (add_owner_name(a, &(a->inclusion_gnames), 0, gname));
+}
+
+/*
+ * Test function for owner(uid, gid, uname, gname).
+ *
+ * Returns 1 if archive entry is excluded.
+ * Returns 0 if archive entry is not excluded.
+ * Returns <0 if something error happened.
+ */
+int
+archive_match_owner_excluded(struct archive *_a,
+    struct archive_entry *entry)
+{
+	struct archive_match *a;
+
+	archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae");
+
+	a = (struct archive_match *)_a;
+	if (entry == NULL) {
+		archive_set_error(&(a->archive), EINVAL, "entry is NULL");
+		return (ARCHIVE_FAILED);
+	}
+
+	/* If we don't have inclusion id set at all, the entry is always
+	 * not excluded. */
+	if ((a->setflag & ID_IS_SET) == 0)
+		return (0);
+	return (owner_excluded(a, entry));
+}
+
+static int
+add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
+{
+	unsigned i;
+
+	if (ids->count + 1 >= ids->size) {
+		void *p;
+
+		if (ids->size == 0)
+			ids->size = 8;
+		else
+			ids->size *= 2;
+		p = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
+		if (p == NULL)
+			return (error_nomem(a));
+		ids->ids = (int64_t *)p;
+	}
+
+	/* Find an insert point. */
+	for (i = 0; i < ids->count; i++) {
+		if (ids->ids[i] >= id)
+			break;
+	}
+
+	/* Add oowner id. */
+	if (i == ids->count)
+		ids->ids[ids->count++] = id;
+	else if (ids->ids[i] != id) {
+		memmove(&(ids->ids[i+1]), &(ids->ids[i]),
+		    (ids->count - i) * sizeof(ids->ids[0]));
+		ids->ids[i] = id;
+		ids->count++;
+	}
+	a->setflag |= ID_IS_SET;
+	return (ARCHIVE_OK);
+}
+
+static int
+match_owner_id(struct id_array *ids, int64_t id)
+{
+	unsigned b, m, t;
+
+	t = 0;
+	b = (unsigned)ids->count;
+	while (t < b) {
+		m = (t + b)>>1;
+		if (ids->ids[m] == id)
+			return (1);
+		if (ids->ids[m] < id)
+			t = m + 1;
+		else
+			b = m;
+	}
+	return (0);
+}
+
+static int
+add_owner_name(struct archive_match *a, struct match_list *list,
+    int mbs, const void *name)
+{
+	struct match *match;
+
+	match = calloc(1, sizeof(*match));
+	if (match == NULL)
+		return (error_nomem(a));
+	if (mbs)
+		archive_mstring_copy_mbs(&(match->pattern), name);
+	else
+		archive_mstring_copy_wcs(&(match->pattern), name);
+	match_list_add(list, match);
+	a->setflag |= ID_IS_SET;
+	return (ARCHIVE_OK);
+}
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+static int
+match_owner_name_mbs(struct archive_match *a, struct match_list *list,
+    const char *name)
+{
+	struct match *m;
+	const char *p;
+
+	if (name == NULL || *name == '\0')
+		return (0);
+	for (m = list->first; m; m = m->next) {
+		if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p)
+		    < 0 && errno == ENOMEM)
+			return (error_nomem(a));
+		if (p != NULL && strcmp(p, name) == 0) {
+			m->matches++;
+			return (1);
+		}
+	}
+	return (0);
+}
+#else
+static int
+match_owner_name_wcs(struct archive_match *a, struct match_list *list,
+    const wchar_t *name)
+{
+	struct match *m;
+	const wchar_t *p;
+
+	if (name == NULL || *name == L'\0')
+		return (0);
+	for (m = list->first; m; m = m->next) {
+		if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p)
+		    < 0 && errno == ENOMEM)
+			return (error_nomem(a));
+		if (p != NULL && wcscmp(p, name) == 0) {
+			m->matches++;
+			return (1);
+		}
+	}
+	return (0);
+}
+#endif
+
+/*
+ * Test if entry is excluded by uid, gid, uname or gname.
+ */
+static int
+owner_excluded(struct archive_match *a, struct archive_entry *entry)
+{
+	int r;
+
+	if (a->inclusion_uids.count) {
+		if (!match_owner_id(&(a->inclusion_uids),
+		    archive_entry_uid(entry)))
+			return (1);
+	}
+
+	if (a->inclusion_gids.count) {
+		if (!match_owner_id(&(a->inclusion_gids),
+		    archive_entry_gid(entry)))
+			return (1);
+	}
+
+	if (a->inclusion_unames.count) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+		r = match_owner_name_wcs(a, &(a->inclusion_unames),
+			archive_entry_uname_w(entry));
+#else
+		r = match_owner_name_mbs(a, &(a->inclusion_unames),
+			archive_entry_uname(entry));
+#endif
+		if (!r)
+			return (1);
+		else if (r < 0)
+			return (r);
+	}
+
+	if (a->inclusion_gnames.count) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+		r = match_owner_name_wcs(a, &(a->inclusion_gnames),
+			archive_entry_gname_w(entry));
+#else
+		r = match_owner_name_mbs(a, &(a->inclusion_gnames),
+			archive_entry_gname(entry));
+#endif
+		if (!r)
+			return (1);
+		else if (r < 0)
+			return (r);
+	}
+	return (0);
+}
+
diff --git a/libarchive/archive_options.c b/libarchive/archive_options.c
index 962572c..8af6239 100644
--- a/libarchive/archive_options.c
+++ b/libarchive/archive_options.c
@@ -38,6 +38,7 @@ _archive_set_option(struct archive *a,
     int magic, const char *fn, option_handler use_option)
 {
 	const char *mp, *op, *vp;
+	int r;
 
 	archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
 
@@ -47,10 +48,24 @@ _archive_set_option(struct archive *a,
 
 	if (op == NULL && vp == NULL)
 		return (ARCHIVE_OK);
-	if (op == NULL)
+	if (op == NULL) {
+		archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");
 		return (ARCHIVE_FAILED);
+	}
 
-	return use_option(a, mp, op, vp);
+	r = use_option(a, mp, op, vp);
+	if (r == ARCHIVE_WARN - 1) {
+		archive_set_error(a, ARCHIVE_ERRNO_MISC,
+		    "Unknown module name: `%s'", mp);
+		return (ARCHIVE_FAILED);
+	}
+	if (r == ARCHIVE_WARN) {
+		archive_set_error(a, ARCHIVE_ERRNO_MISC,
+		    "Undefined option: `%s%s%s%s%s%s'",
+		    vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:"");
+		return (ARCHIVE_FAILED);
+	}
+	return (r);
 }
 
 int
@@ -72,6 +87,8 @@ _archive_set_either_option(struct archive *a, const char *m, const char *o, cons
 	if (r2 == ARCHIVE_FATAL)
 		return (ARCHIVE_FATAL);
 
+	if (r2 == ARCHIVE_WARN - 1)
+		return r1;
 	return r1 > r2 ? r1 : r2;
 }
 
@@ -79,7 +96,7 @@ 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;
+	int allok = 1, anyok = 0, ignore_mod_err = 0, r;
 	char *data;
 	const char *s, *mod, *opt, *val;
 
@@ -96,12 +113,42 @@ _archive_set_options(struct archive *a, const char *options,
 		mod = opt = val = NULL;
 
 		parse_option(&s, &mod, &opt, &val);
+		if (mod == NULL && opt != NULL &&
+		    strcmp("__ignore_wrong_module_name__", opt) == 0) {
+			/* Ignore module name error */
+			if (val != NULL) {
+				ignore_mod_err = 1;
+				anyok = 1;
+			}
+			continue;
+		}
 
 		r = use_option(a, mod, opt, val);
 		if (r == ARCHIVE_FATAL) {
 			free(data);
 			return (ARCHIVE_FATAL);
 		}
+		if (r == ARCHIVE_FAILED && mod != NULL) {
+			free(data);
+			return (ARCHIVE_FAILED);
+		}
+		if (r == ARCHIVE_WARN - 1) {
+			if (ignore_mod_err)
+				continue;
+			/* The module name is wrong. */
+			archive_set_error(a, ARCHIVE_ERRNO_MISC,
+			    "Unknown module name: `%s'", mod);
+			free(data);
+			return (ARCHIVE_FAILED);
+		}
+		if (r == ARCHIVE_WARN) {
+			/* The option name is wrong. No-one used this. */
+			archive_set_error(a, ARCHIVE_ERRNO_MISC,
+			    "Undefined option: `%s%s%s'",
+			    mod?mod:"", mod?":":"", opt);
+			free(data);
+			return (ARCHIVE_FAILED);
+		}
 		if (r == ARCHIVE_OK)
 			anyok = 1;
 		else
diff --git a/libarchive/archive_pathmatch.c b/libarchive/archive_pathmatch.c
new file mode 100644
index 0000000..505252a
--- /dev/null
+++ b/libarchive/archive_pathmatch.c
@@ -0,0 +1,459 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_WCHAR_H
+#include <wchar.h>
+#endif
+
+#include "archive_pathmatch.h"
+
+/*
+ * Check whether a character 'c' is matched by a list specification [...]:
+ *    * Leading '!' or '^' negates the class.
+ *    * <char>-<char> is a range of characters
+ *    * \<char> removes any special meaning for <char>
+ *
+ * Some interesting boundary cases:
+ *   a-d-e is one range (a-d) followed by two single characters - and e.
+ *   \a-\d is same as a-d
+ *   a\-d is three single characters: a, d, -
+ *   Trailing - is not special (so [a-] is two characters a and -).
+ *   Initial - is not special ([a-] is same as [-a] is same as [\\-a])
+ *   This function never sees a trailing \.
+ *   [] always fails
+ *   [!] always succeeds
+ */
+static int
+pm_list(const char *start, const char *end, const char c, int flags)
+{
+	const char *p = start;
+	char rangeStart = '\0', nextRangeStart;
+	int match = 1, nomatch = 0;
+
+	/* This will be used soon... */
+	(void)flags; /* UNUSED */
+
+	/* If this is a negated class, return success for nomatch. */
+	if ((*p == '!' || *p == '^') && p < end) {
+		match = 0;
+		nomatch = 1;
+		++p;
+	}
+
+	while (p < end) {
+		nextRangeStart = '\0';
+		switch (*p) {
+		case '-':
+			/* Trailing or initial '-' is not special. */
+			if ((rangeStart == '\0') || (p == end - 1)) {
+				if (*p == c)
+					return (match);
+			} else {
+				char rangeEnd = *++p;
+				if (rangeEnd == '\\')
+					rangeEnd = *++p;
+				if ((rangeStart <= c) && (c <= rangeEnd))
+					return (match);
+			}
+			break;
+		case '\\':
+			++p;
+			/* Fall through */
+		default:
+			if (*p == c)
+				return (match);
+			nextRangeStart = *p; /* Possible start of range. */
+		}
+		rangeStart = nextRangeStart;
+		++p;
+	}
+	return (nomatch);
+}
+
+static int
+pm_list_w(const wchar_t *start, const wchar_t *end, const wchar_t c, int flags)
+{
+	const wchar_t *p = start;
+	wchar_t rangeStart = L'\0', nextRangeStart;
+	int match = 1, nomatch = 0;
+
+	/* This will be used soon... */
+	(void)flags; /* UNUSED */
+
+	/* If this is a negated class, return success for nomatch. */
+	if ((*p == L'!' || *p == L'^') && p < end) {
+		match = 0;
+		nomatch = 1;
+		++p;
+	}
+
+	while (p < end) {
+		nextRangeStart = L'\0';
+		switch (*p) {
+		case L'-':
+			/* Trailing or initial '-' is not special. */
+			if ((rangeStart == L'\0') || (p == end - 1)) {
+				if (*p == c)
+					return (match);
+			} else {
+				wchar_t rangeEnd = *++p;
+				if (rangeEnd == L'\\')
+					rangeEnd = *++p;
+				if ((rangeStart <= c) && (c <= rangeEnd))
+					return (match);
+			}
+			break;
+		case L'\\':
+			++p;
+			/* Fall through */
+		default:
+			if (*p == c)
+				return (match);
+			nextRangeStart = *p; /* Possible start of range. */
+		}
+		rangeStart = nextRangeStart;
+		++p;
+	}
+	return (nomatch);
+}
+
+/*
+ * If s is pointing to "./", ".//", "./././" or the like, skip it.
+ */
+static const char *
+pm_slashskip(const char *s) {
+	while ((*s == '/')
+	    || (s[0] == '.' && s[1] == '/')
+	    || (s[0] == '.' && s[1] == '\0'))
+		++s;
+	return (s);
+}
+
+static const wchar_t *
+pm_slashskip_w(const wchar_t *s) {
+	while ((*s == L'/')
+	    || (s[0] == L'.' && s[1] == L'/')
+	    || (s[0] == L'.' && s[1] == L'\0'))
+		++s;
+	return (s);
+}
+
+static int
+pm(const char *p, const char *s, int flags)
+{
+	const char *end;
+
+	/*
+	 * Ignore leading './', './/', '././', etc.
+	 */
+	if (s[0] == '.' && s[1] == '/')
+		s = pm_slashskip(s + 1);
+	if (p[0] == '.' && p[1] == '/')
+		p = pm_slashskip(p + 1);
+
+	for (;;) {
+		switch (*p) {
+		case '\0':
+			if (s[0] == '/') {
+				if (flags & PATHMATCH_NO_ANCHOR_END)
+					return (1);
+				/* "dir" == "dir/" == "dir/." */
+				s = pm_slashskip(s);
+			}
+			return (*s == '\0');
+		case '?':
+			/* ? always succeeds, unless we hit end of 's' */
+			if (*s == '\0')
+				return (0);
+			break;
+		case '*':
+			/* "*" == "**" == "***" ... */
+			while (*p == '*')
+				++p;
+			/* Trailing '*' always succeeds. */
+			if (*p == '\0')
+				return (1);
+			while (*s) {
+				if (archive_pathmatch(p, s, flags))
+					return (1);
+				++s;
+			}
+			return (0);
+		case '[':
+			/*
+			 * Find the end of the [...] character class,
+			 * ignoring \] that might occur within the class.
+			 */
+			end = p + 1;
+			while (*end != '\0' && *end != ']') {
+				if (*end == '\\' && end[1] != '\0')
+					++end;
+				++end;
+			}
+			if (*end == ']') {
+				/* We found [...], try to match it. */
+				if (!pm_list(p + 1, end, *s, flags))
+					return (0);
+				p = end; /* Jump to trailing ']' char. */
+				break;
+			} else
+				/* No final ']', so just match '['. */
+				if (*p != *s)
+					return (0);
+			break;
+		case '\\':
+			/* Trailing '\\' matches itself. */
+			if (p[1] == '\0') {
+				if (*s != '\\')
+					return (0);
+			} else {
+				++p;
+				if (*p != *s)
+					return (0);
+			}
+			break;
+		case '/':
+			if (*s != '/' && *s != '\0')
+				return (0);
+			/* Note: pattern "/\./" won't match "/";
+			 * pm_slashskip() correctly stops at backslash. */
+			p = pm_slashskip(p);
+			s = pm_slashskip(s);
+			if (*p == '\0' && (flags & PATHMATCH_NO_ANCHOR_END))
+				return (1);
+			--p; /* Counteract the increment below. */
+			--s;
+			break;
+		case '$':
+			/* '$' is special only at end of pattern and only
+			 * if PATHMATCH_NO_ANCHOR_END is specified. */
+			if (p[1] == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)){
+				/* "dir" == "dir/" == "dir/." */
+				return (*pm_slashskip(s) == '\0');
+			}
+			/* Otherwise, '$' is not special. */
+			/* FALL THROUGH */
+		default:
+			if (*p != *s)
+				return (0);
+			break;
+		}
+		++p;
+		++s;
+	}
+}
+
+static int
+pm_w(const wchar_t *p, const wchar_t *s, int flags)
+{
+	const wchar_t *end;
+
+	/*
+	 * Ignore leading './', './/', '././', etc.
+	 */
+	if (s[0] == L'.' && s[1] == L'/')
+		s = pm_slashskip_w(s + 1);
+	if (p[0] == L'.' && p[1] == L'/')
+		p = pm_slashskip_w(p + 1);
+
+	for (;;) {
+		switch (*p) {
+		case L'\0':
+			if (s[0] == L'/') {
+				if (flags & PATHMATCH_NO_ANCHOR_END)
+					return (1);
+				/* "dir" == "dir/" == "dir/." */
+				s = pm_slashskip_w(s);
+			}
+			return (*s == L'\0');
+		case L'?':
+			/* ? always succeeds, unless we hit end of 's' */
+			if (*s == L'\0')
+				return (0);
+			break;
+		case L'*':
+			/* "*" == "**" == "***" ... */
+			while (*p == L'*')
+				++p;
+			/* Trailing '*' always succeeds. */
+			if (*p == L'\0')
+				return (1);
+			while (*s) {
+				if (archive_pathmatch_w(p, s, flags))
+					return (1);
+				++s;
+			}
+			return (0);
+		case L'[':
+			/*
+			 * Find the end of the [...] character class,
+			 * ignoring \] that might occur within the class.
+			 */
+			end = p + 1;
+			while (*end != L'\0' && *end != L']') {
+				if (*end == L'\\' && end[1] != L'\0')
+					++end;
+				++end;
+			}
+			if (*end == L']') {
+				/* We found [...], try to match it. */
+				if (!pm_list_w(p + 1, end, *s, flags))
+					return (0);
+				p = end; /* Jump to trailing ']' char. */
+				break;
+			} else
+				/* No final ']', so just match '['. */
+				if (*p != *s)
+					return (0);
+			break;
+		case L'\\':
+			/* Trailing '\\' matches itself. */
+			if (p[1] == L'\0') {
+				if (*s != L'\\')
+					return (0);
+			} else {
+				++p;
+				if (*p != *s)
+					return (0);
+			}
+			break;
+		case L'/':
+			if (*s != L'/' && *s != L'\0')
+				return (0);
+			/* Note: pattern "/\./" won't match "/";
+			 * pm_slashskip() correctly stops at backslash. */
+			p = pm_slashskip_w(p);
+			s = pm_slashskip_w(s);
+			if (*p == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END))
+				return (1);
+			--p; /* Counteract the increment below. */
+			--s;
+			break;
+		case L'$':
+			/* '$' is special only at end of pattern and only
+			 * if PATHMATCH_NO_ANCHOR_END is specified. */
+			if (p[1] == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END)){
+				/* "dir" == "dir/" == "dir/." */
+				return (*pm_slashskip_w(s) == L'\0');
+			}
+			/* Otherwise, '$' is not special. */
+			/* FALL THROUGH */
+		default:
+			if (*p != *s)
+				return (0);
+			break;
+		}
+		++p;
+		++s;
+	}
+}
+
+/* Main entry point. */
+int
+__archive_pathmatch(const char *p, const char *s, int flags)
+{
+	/* Empty pattern only matches the empty string. */
+	if (p == NULL || *p == '\0')
+		return (s == NULL || *s == '\0');
+
+	/* Leading '^' anchors the start of the pattern. */
+	if (*p == '^') {
+		++p;
+		flags &= ~PATHMATCH_NO_ANCHOR_START;
+	}
+
+	if (*p == '/' && *s != '/')
+		return (0);
+
+	/* Certain patterns and file names anchor implicitly. */
+	if (*p == '*' || *p == '/' || *p == '/') {
+		while (*p == '/')
+			++p;
+		while (*s == '/')
+			++s;
+		return (pm(p, s, flags));
+	}
+
+	/* If start is unanchored, try to match start of each path element. */
+	if (flags & PATHMATCH_NO_ANCHOR_START) {
+		for ( ; s != NULL; s = strchr(s, '/')) {
+			if (*s == '/')
+				s++;
+			if (pm(p, s, flags))
+				return (1);
+		}
+		return (0);
+	}
+
+	/* Default: Match from beginning. */
+	return (pm(p, s, flags));
+}
+
+int
+__archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
+{
+	/* Empty pattern only matches the empty string. */
+	if (p == NULL || *p == L'\0')
+		return (s == NULL || *s == L'\0');
+
+	/* Leading '^' anchors the start of the pattern. */
+	if (*p == L'^') {
+		++p;
+		flags &= ~PATHMATCH_NO_ANCHOR_START;
+	}
+
+	if (*p == L'/' && *s != L'/')
+		return (0);
+
+	/* Certain patterns and file names anchor implicitly. */
+	if (*p == L'*' || *p == L'/' || *p == L'/') {
+		while (*p == L'/')
+			++p;
+		while (*s == L'/')
+			++s;
+		return (pm_w(p, s, flags));
+	}
+
+	/* If start is unanchored, try to match start of each path element. */
+	if (flags & PATHMATCH_NO_ANCHOR_START) {
+		for ( ; s != NULL; s = wcschr(s, L'/')) {
+			if (*s == L'/')
+				s++;
+			if (pm_w(p, s, flags))
+				return (1);
+		}
+		return (0);
+	}
+
+	/* Default: Match from beginning. */
+	return (pm_w(p, s, flags));
+}
diff --git a/libarchive/archive_write_disk_private.h b/libarchive/archive_pathmatch.h
similarity index 68%
copy from libarchive/archive_write_disk_private.h
copy to libarchive/archive_pathmatch.h
index 707c0cf..e690177 100644
--- a/libarchive/archive_write_disk_private.h
+++ b/libarchive/archive_pathmatch.h
@@ -23,16 +23,30 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: head/lib/libarchive/archive_write_disk_private.h 201086 2009-12-28 02:17:53Z kientzle $
+ * $FreeBSD$
  */
 
 #ifndef __LIBARCHIVE_BUILD
+#ifndef __LIBARCHIVE_TEST
 #error This header is only to be used internally to libarchive.
 #endif
+#endif
+
+#ifndef ARCHIVE_PATHMATCH_H
+#define ARCHIVE_PATHMATCH_H
+
+/* Don't anchor at beginning unless the pattern starts with "^" */
+#define PATHMATCH_NO_ANCHOR_START	1
+/* Don't anchor at end unless the pattern ends with "$" */
+#define PATHMATCH_NO_ANCHOR_END 	2
+
+/* Note that "^" and "$" are not special unless you set the corresponding
+ * flag above. */
 
-#ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
-#define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
+int __archive_pathmatch(const char *p, const char *s, int flags);
+int __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags);
 
-struct archive_write_disk;
+#define archive_pathmatch(p, s, f)	__archive_pathmatch(p, s, f)
+#define archive_pathmatch_w(p, s, f)	__archive_pathmatch_w(p, s, f)
 
 #endif
diff --git a/libarchive/archive_ppmd7.c b/libarchive/archive_ppmd7.c
index b2e8c3a..fe0b031 100644
--- a/libarchive/archive_ppmd7.c
+++ b/libarchive/archive_ppmd7.c
@@ -415,7 +415,7 @@ static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)
     upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
   }
 
-  do
+  while (numPs != 0)
   {
     /* Create Child */
     CTX_PTR c1; /* = AllocContext(p); */
@@ -435,7 +435,6 @@ static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)
     SetSuccessor(ps[--numPs], REF(c1));
     c = c1;
   }
-  while (numPs != 0);
   
   return c;
 }
@@ -778,7 +777,7 @@ static void Range_Normalize(CPpmd7z_RangeDec *p)
       if(p->Range >= p->Bottom)
         break;
       else
-        p->Range = -p->Low & (p->Bottom - 1);
+        p->Range = ((uint32_t)(-(int32_t)p->Low)) & (p->Bottom - 1);
     }
     p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
     p->Range <<= 8;
@@ -991,7 +990,7 @@ static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)
     p->Cache = (Byte)((UInt32)p->Low >> 24);
   }
   p->CacheSize++;
-  p->Low = (UInt32)p->Low << 8;
+  p->Low = ((UInt32)p->Low << 8) & 0xFFFFFFFF;
 }
 
 static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total)
diff --git a/libarchive/archive_ppmd_private.h b/libarchive/archive_ppmd_private.h
index 2666768..e78bde5 100644
--- a/libarchive/archive_ppmd_private.h
+++ b/libarchive/archive_ppmd_private.h
@@ -152,7 +152,7 @@ typedef
   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; }}
+  { unsigned j; for (j = 0; j < 256 / sizeof(p[0]); j += 8) { \
+  p[j+7] = p[j+6] = p[j+5] = p[j+4] = p[j+3] = p[j+2] = p[j+1] = p[j+0] = ~(size_t)0; }}
 
 #endif
diff --git a/libarchive/archive_private.h b/libarchive/archive_private.h
index 9941e96..30d472f 100644
--- a/libarchive/archive_private.h
+++ b/libarchive/archive_private.h
@@ -50,6 +50,7 @@
 #define	ARCHIVE_READ_MAGIC	(0xdeb0c5U)
 #define	ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
 #define	ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U)
+#define	ARCHIVE_MATCH_MAGIC	(0xcad11c9U)
 
 #define	ARCHIVE_STATE_NEW	1U
 #define	ARCHIVE_STATE_HEADER	2U
@@ -133,6 +134,7 @@ int	__archive_check_magic(struct archive *, unsigned int magic,
 
 void	__archive_errx(int retvalue, const char *msg) __LA_DEAD;
 
+void	__archive_ensure_cloexec_flag(int fd);
 int	__archive_mktemp(const char *tmpdir);
 
 int	__archive_clean(struct archive *);
diff --git a/libarchive/archive_rb.c b/libarchive/archive_rb.c
index f8035d9..5b5da20 100644
--- a/libarchive/archive_rb.c
+++ b/libarchive/archive_rb.c
@@ -96,7 +96,7 @@ __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 **)&rbt->rbt_root) = RB_SENTINEL_NODE;
 }
 
 struct archive_rb_node *
@@ -237,6 +237,8 @@ __archive_rb_tree_reparent_nodes(
 	struct archive_rb_node * const new_father = old_child;
 	struct archive_rb_node * const new_child = old_father;
 
+	if (new_father == NULL)
+		return;
 	/*
 	 * Exchange descendant linkages.
 	 */
@@ -377,13 +379,13 @@ __archive_rb_tree_swap_prune_and_rebalance(struct archive_rb_tree *rbt,
 
 	if (standin_father == self) {
 		/*
-		 * As a child of self, any childen would be opposite of
+		 * As a child of self, any children would be opposite of
 		 * our parent.
 		 */
 		standin_son = standin->rb_nodes[standin_which];
 	} else {
 		/*
-		 * Since we aren't a child of self, any childen would be
+		 * Since we aren't a child of self, any children would be
 		 * on the same side as our parent.
 		 */
 		standin_son = standin->rb_nodes[standin_other];
@@ -410,7 +412,7 @@ __archive_rb_tree_swap_prune_and_rebalance(struct archive_rb_tree *rbt,
 		/*
 		 * 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
+		 * Otherwise remember our original father.  Also, since we are
 		 * our standin's father we only need to reparent the standin's
 		 * brother.
 		 *
@@ -466,7 +468,7 @@ __archive_rb_tree_swap_prune_and_rebalance(struct archive_rb_tree *rbt,
  *	__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.
+ * But it's more efficient to just evaluate and recolor the child.
  */
 static void
 __archive_rb_tree_prune_blackred_branch(
@@ -505,7 +507,7 @@ __archive_rb_tree_remove_node(struct archive_rb_tree *rbt,
 	 * 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:
+	 * The simplest case is a childless red node or a childless root node:
 	 *
 	 * |    T  -->    T  |    or    |  R  -->  *  |
 	 * |  s    -->  *    |
@@ -517,7 +519,7 @@ __archive_rb_tree_remove_node(struct archive_rb_tree *rbt,
 	}
 	if (!RB_TWOCHILDREN_P(self)) {
 		/*
-		 * The next simpliest case is the node we are deleting is
+		 * The next simplest case is the node we are deleting is
 		 * black and has one red child.
 		 *
 		 * |      T  -->      T  -->      T  |
@@ -552,6 +554,8 @@ __archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt,
 		unsigned int other = which ^ RB_DIR_OTHER;
 		struct archive_rb_node *brother = parent->rb_nodes[other];
 
+		if (brother == NULL)
+			return;/* The tree may be broken. */
 		/*
 		 * For cases 1, 2a, and 2b, our brother's children must
 		 * be black and our father must be black
@@ -573,6 +577,8 @@ __archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt,
 				 */
 				__archive_rb_tree_reparent_nodes(parent, other);
 				brother = parent->rb_nodes[other];
+				if (brother == NULL)
+					return;/* The tree may be broken. */
 			} else {
 				/*
 				 * Both our parent and brother are black.
@@ -656,6 +662,8 @@ __archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt,
 			 * If we had two red nephews, then after the swap,
 			 * our former father would have a red grandson. 
 			 */
+			if (brother->rb_nodes[other] == NULL)
+				return;/* The tree may be broken. */
 			RB_MARK_BLACK(brother->rb_nodes[other]);
 			__archive_rb_tree_reparent_nodes(parent, other);
 			break;		/* We're done! */
@@ -683,7 +691,7 @@ __archive_rb_tree_iterate(struct archive_rb_tree *rbt,
 	 */
 	if (RB_SENTINEL_P(self->rb_nodes[direction])) {
 		while (!RB_ROOT_P(rbt, self)) {
-			if (other == RB_POSITION(self))
+			if (other == (unsigned int)RB_POSITION(self))
 				return RB_FATHER(self);
 			self = RB_FATHER(self);
 		}
diff --git a/libarchive/archive_read.3 b/libarchive/archive_read.3
index 5285192..a29cc1e 100644
--- a/libarchive/archive_read.3
+++ b/libarchive/archive_read.3
@@ -22,14 +22,16 @@
 .\" 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 $
+.\" $FreeBSD$
 .\"
-.Dd March 23, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ 3
 .Os
 .Sh NAME
 .Nm archive_read
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Sh DESCRIPTION
diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c
index b1d4914..048c316 100644
--- a/libarchive/archive_read.c
+++ b/libarchive/archive_read.c
@@ -57,8 +57,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:2
 
 static int	choose_filters(struct archive_read *);
 static int	choose_format(struct archive_read *);
-static void	free_filters(struct archive_read *);
-static int	close_filters(struct archive_read *);
 static struct archive_vtable *archive_read_vtable(void);
 static int64_t	_archive_filter_bytes(struct archive *, int);
 static int	_archive_filter_code(struct archive *, int);
@@ -194,14 +192,13 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
 			int64_t get, ask = request;
 			if (ask > skip_limit)
 				ask = skip_limit;
-			get = (self->archive->client.skipper)(&self->archive->archive,
-			    self->data, ask);
+			get = (self->archive->client.skipper)
+				(&self->archive->archive, self->data, ask);
 			if (get == 0)
 				return (total);
 			request -= get;
 			total += get;
 		}
-		return total;
 	} else if (self->archive->client.seeker != NULL
 		&& request > 64 * 1024) {
 		/* If the client provided a seeker but not a skipper,
@@ -216,8 +213,8 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
 		 * only do this for skips of over 64k.
 		 */
 		int64_t before = self->position;
-		int64_t after = (self->archive->client.seeker)(&self->archive->archive,
-		    self->data, request, SEEK_CUR);
+		int64_t after = (self->archive->client.seeker)
+		    (&self->archive->archive, self->data, request, SEEK_CUR);
 		if (after != before + request)
 			return ARCHIVE_FATAL;
 		return after - before;
@@ -242,14 +239,64 @@ client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)
 static int
 client_close_proxy(struct archive_read_filter *self)
 {
-	int r = ARCHIVE_OK;
+	int r = ARCHIVE_OK, r2;
+	unsigned int i;
+
+	if (self->archive->client.closer == NULL)
+		return (r);
+	for (i = 0; i < self->archive->client.nodes; i++)
+	{
+		r2 = (self->archive->client.closer)
+			((struct archive *)self->archive,
+				self->archive->client.dataset[i].data);
+		if (r > r2)
+			r = r2;
+	}
+	return (r);
+}
 
-	if (self->archive->client.closer != NULL)
-		r = (self->archive->client.closer)((struct archive *)self->archive,
-		    self->data);
+static int
+client_open_proxy(struct archive_read_filter *self)
+{
+  int r = ARCHIVE_OK;
+	if (self->archive->client.opener != NULL)
+		r = (self->archive->client.opener)(
+		    (struct archive *)self->archive, self->data);
 	return (r);
 }
 
+static int
+client_switch_proxy(struct archive_read_filter *self, unsigned int iindex)
+{
+  int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK;
+	void *data2 = NULL;
+
+	/* Don't do anything if already in the specified data node */
+	if (self->archive->client.cursor == iindex)
+		return (ARCHIVE_OK);
+
+	self->archive->client.cursor = iindex;
+	data2 = self->archive->client.dataset[self->archive->client.cursor].data;
+	if (self->archive->client.switcher != NULL)
+	{
+		r1 = r2 = (self->archive->client.switcher)
+			((struct archive *)self->archive, self->data, data2);
+		self->data = data2;
+	}
+	else
+	{
+		/* Attempt to call close and open instead */
+		if (self->archive->client.closer != NULL)
+			r1 = (self->archive->client.closer)
+				((struct archive *)self->archive, self->data);
+		self->data = data2;
+		if (self->archive->client.opener != NULL)
+			r2 = (self->archive->client.opener)
+				((struct archive *)self->archive, self->data);
+	}
+	return (r1 < r2) ? r1 : r2;
+}
+
 int
 archive_read_set_open_callback(struct archive *_a,
     archive_open_callback *client_opener)
@@ -306,21 +353,109 @@ archive_read_set_close_callback(struct archive *_a,
 }
 
 int
+archive_read_set_switch_callback(struct archive *_a,
+    archive_switch_callback *client_switcher)
+{
+	struct archive_read *a = (struct archive_read *)_a;
+	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
+	    "archive_read_set_switch_callback");
+	a->client.switcher = client_switcher;
+	return ARCHIVE_OK;
+}
+
+int
 archive_read_set_callback_data(struct archive *_a, void *client_data)
 {
+	return archive_read_set_callback_data2(_a, client_data, 0);
+}
+
+int
+archive_read_set_callback_data2(struct archive *_a, void *client_data,
+    unsigned int iindex)
+{
 	struct archive_read *a = (struct archive_read *)_a;
 	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
-	    "archive_read_set_callback_data");
-	a->client.data = client_data;
+	    "archive_read_set_callback_data2");
+
+	if (a->client.nodes == 0)
+	{
+		a->client.dataset = (struct archive_read_data_node *)
+		    calloc(1, sizeof(*a->client.dataset));
+		if (a->client.dataset == NULL)
+		{
+			archive_set_error(&a->archive, ENOMEM,
+				"No memory.");
+			return ARCHIVE_FATAL;
+		}
+		a->client.nodes = 1;
+	}
+
+	if (iindex > a->client.nodes - 1)
+	{
+		archive_set_error(&a->archive, EINVAL,
+			"Invalid index specified.");
+		return ARCHIVE_FATAL;
+	}
+	a->client.dataset[iindex].data = client_data;
+	a->client.dataset[iindex].begin_position = -1;
+	a->client.dataset[iindex].total_size = -1;
+	return ARCHIVE_OK;
+}
+
+int
+archive_read_add_callback_data(struct archive *_a, void *client_data,
+    unsigned int iindex)
+{
+	struct archive_read *a = (struct archive_read *)_a;
+	void *p;
+	unsigned int i;
+
+	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
+	    "archive_read_add_callback_data");
+	if (iindex > a->client.nodes) {
+		archive_set_error(&a->archive, EINVAL,
+			"Invalid index specified.");
+		return ARCHIVE_FATAL;
+	}
+	p = realloc(a->client.dataset, sizeof(*a->client.dataset)
+		* (++(a->client.nodes)));
+	if (p == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+			"No memory.");
+		return ARCHIVE_FATAL;
+	}
+	a->client.dataset = (struct archive_read_data_node *)p;
+	for (i = a->client.nodes - 1; i > iindex && i > 0; i--) {
+		a->client.dataset[i].data = a->client.dataset[i-1].data;
+		a->client.dataset[i].begin_position = -1;
+		a->client.dataset[i].total_size = -1;
+	}
+	a->client.dataset[iindex].data = client_data;
+	a->client.dataset[iindex].begin_position = -1;
+	a->client.dataset[iindex].total_size = -1;
 	return ARCHIVE_OK;
 }
 
 int
+archive_read_append_callback_data(struct archive *_a, void *client_data)
+{
+	struct archive_read *a = (struct archive_read *)_a;
+	return archive_read_add_callback_data(_a, client_data, a->client.nodes);
+}
+
+int
+archive_read_prepend_callback_data(struct archive *_a, void *client_data)
+{
+	return archive_read_add_callback_data(_a, client_data, 0);
+}
+
+int
 archive_read_open1(struct archive *_a)
 {
 	struct archive_read *a = (struct archive_read *)_a;
-	struct archive_read_filter *filter;
+	struct archive_read_filter *filter, *tmp;
 	int slot, e;
+	unsigned int i;
 
 	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
 	    "archive_read_open");
@@ -335,11 +470,14 @@ archive_read_open1(struct archive *_a)
 
 	/* Open data source. */
 	if (a->client.opener != NULL) {
-		e =(a->client.opener)(&a->archive, a->client.data);
+		e = (a->client.opener)(&a->archive, a->client.dataset[0].data);
 		if (e != 0) {
 			/* If the open failed, call the closer to clean up. */
-			if (a->client.closer)
-				(a->client.closer)(&a->archive, a->client.data);
+			if (a->client.closer) {
+				for (i = 0; i < a->client.nodes; i++)
+					(a->client.closer)(&a->archive,
+					    a->client.dataset[i].data);
+			}
 			return (e);
 		}
 	}
@@ -350,31 +488,51 @@ archive_read_open1(struct archive *_a)
 	filter->bidder = NULL;
 	filter->upstream = NULL;
 	filter->archive = a;
-	filter->data = a->client.data;
+	filter->data = a->client.dataset[0].data;
+	filter->open = client_open_proxy;
 	filter->read = client_read_proxy;
 	filter->skip = client_skip_proxy;
 	filter->seek = client_seek_proxy;
 	filter->close = client_close_proxy;
+	filter->sswitch = client_switch_proxy;
 	filter->name = "none";
-	filter->code = ARCHIVE_COMPRESSION_NONE;
-	a->filter = filter;
+	filter->code = ARCHIVE_FILTER_NONE;
 
-	/* Build out the input pipeline. */
-	e = choose_filters(a);
-	if (e < ARCHIVE_WARN) {
-		a->archive.state = ARCHIVE_STATE_FATAL;
-		return (ARCHIVE_FATAL);
+	a->client.dataset[0].begin_position = 0;
+	if (!a->filter || !a->bypass_filter_bidding)
+	{
+		a->filter = filter;
+		/* Build out the input pipeline. */
+		e = choose_filters(a);
+		if (e < ARCHIVE_WARN) {
+			a->archive.state = ARCHIVE_STATE_FATAL;
+			return (ARCHIVE_FATAL);
+		}
+	}
+	else
+	{
+		/* Need to add "NONE" type filter at the end of the filter chain */
+		tmp = a->filter;
+		while (tmp->upstream)
+			tmp = tmp->upstream;
+		tmp->upstream = filter;
 	}
 
-	slot = choose_format(a);
-	if (slot < 0) {
-		close_filters(a);
-		a->archive.state = ARCHIVE_STATE_FATAL;
-		return (ARCHIVE_FATAL);
+	if (!a->format)
+	{
+		slot = choose_format(a);
+		if (slot < 0) {
+			__archive_read_close_filters(a);
+			a->archive.state = ARCHIVE_STATE_FATAL;
+			return (ARCHIVE_FATAL);
+		}
+		a->format = &(a->formats[slot]);
 	}
-	a->format = &(a->formats[slot]);
 
 	a->archive.state = ARCHIVE_STATE_HEADER;
+
+	/* Ensure libarchive starts from the first node in a multivolume set */
+	client_switch_proxy(a->filter, 0);
 	return (e);
 }
 
@@ -414,8 +572,8 @@ choose_filters(struct archive_read *a)
 			/* Verify the filter by asking it for some data. */
 			__archive_read_filter_ahead(a->filter, 1, &avail);
 			if (avail < 0) {
-				close_filters(a);
-				free_filters(a);
+				__archive_read_close_filters(a);
+				__archive_read_free_filters(a);
 				return (ARCHIVE_FATAL);
 			}
 			a->archive.compression_name = a->filter->name;
@@ -433,8 +591,8 @@ choose_filters(struct archive_read *a)
 		a->filter = filter;
 		r = (best_bidder->init)(a->filter);
 		if (r != ARCHIVE_OK) {
-			close_filters(a);
-			free_filters(a);
+			__archive_read_close_filters(a);
+			__archive_read_free_filters(a);
 			return (ARCHIVE_FATAL);
 		}
 	}
@@ -502,6 +660,9 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 
 	a->read_data_output_offset = 0;
 	a->read_data_remaining = 0;
+	a->read_data_is_posix_read = 0;
+	a->read_data_requested = 0;
+	a->data_start_node = a->client.cursor;
 	/* EOF always wins; otherwise return the worst error. */
 	return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1;
 }
@@ -612,6 +773,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
 	while (s > 0) {
 		if (a->read_data_remaining == 0) {
 			read_buf = a->read_data_block;
+			a->read_data_is_posix_read = 1;
+			a->read_data_requested = s;
 			r = _archive_read_data_block(&a->archive, &read_buf,
 			    &a->read_data_remaining, &a->read_data_offset);
 			a->read_data_block = read_buf;
@@ -633,13 +796,13 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
 		}
 
 		/* Compute the amount of zero padding needed. */
-		if (a->read_data_output_offset + s <
+		if (a->read_data_output_offset + (int64_t)s <
 		    a->read_data_offset) {
 			len = s;
 		} else if (a->read_data_output_offset <
 		    a->read_data_offset) {
-			len = a->read_data_offset -
-			    a->read_data_output_offset;
+			len = (size_t)(a->read_data_offset -
+			    a->read_data_output_offset);
 		} else
 			len = 0;
 
@@ -665,6 +828,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
 			bytes_read += len;
 		}
 	}
+	a->read_data_is_posix_read = 0;
+	a->read_data_requested = 0;
 	return (bytes_read);
 }
 
@@ -699,6 +864,23 @@ archive_read_data_skip(struct archive *_a)
 	return (r);
 }
 
+int64_t
+archive_seek_data(struct archive *_a, int64_t offset, int whence)
+{
+	struct archive_read *a = (struct archive_read *)_a;
+	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
+	    "archive_seek_data_block");
+
+	if (a->format->seek_data == NULL) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+		    "Internal error: "
+		    "No format_seek_data_block function registered");
+		return (ARCHIVE_FATAL);
+	}
+
+	return (a->format->seek_data)(a, offset, whence);
+}
+
 /*
  * Read the next block of entry data from the archive.
  * This is a zero-copy interface; the client receives a pointer,
@@ -725,8 +907,8 @@ _archive_read_data_block(struct archive *_a,
 	return (a->format->read_data)(a, buff, size, offset);
 }
 
-static int
-close_filters(struct archive_read *a)
+int
+__archive_read_close_filters(struct archive_read *a)
 {
 	struct archive_read_filter *f = a->filter;
 	int r = ARCHIVE_OK;
@@ -746,8 +928,8 @@ close_filters(struct archive_read *a)
 	return r;
 }
 
-static void
-free_filters(struct archive_read *a)
+void
+__archive_read_free_filters(struct archive_read *a)
 {
 	while (a->filter != NULL) {
 		struct archive_read_filter *t = a->filter->upstream;
@@ -791,7 +973,7 @@ _archive_read_close(struct archive *_a)
 	/* TODO: Clean up the formatters. */
 
 	/* Release the filter objects. */
-	r1 = close_filters(a);
+	r1 = __archive_read_close_filters(a);
 	if (r1 < r)
 		r = r1;
 
@@ -830,7 +1012,7 @@ _archive_read_free(struct archive *_a)
 	}
 
 	/* Free the filters */
-	free_filters(a);
+	__archive_read_free_filters(a);
 
 	/* Release the bidder objects. */
 	n = sizeof(a->bidders)/sizeof(a->bidders[0]);
@@ -847,6 +1029,7 @@ _archive_read_free(struct archive *_a)
 		archive_entry_free(a->entry);
 	a->archive.magic = 0;
 	__archive_clean(&a->archive);
+	free(a->client.dataset);
 	free(a);
 	return (r);
 }
@@ -856,7 +1039,8 @@ get_filter(struct archive *_a, int n)
 {
 	struct archive_read *a = (struct archive_read *)_a;
 	struct archive_read_filter *f = a->filter;
-	/* We use n == -1 for 'the last filter', which is always the client proxy. */
+	/* We use n == -1 for 'the last filter', which is always the
+	 * client proxy. */
 	if (n == -1 && f != NULL) {
 		struct archive_read_filter *last = f;
 		f = f->upstream;
@@ -909,6 +1093,7 @@ __archive_read_register_format(struct archive_read *a,
     int (*read_header)(struct archive_read *, struct archive_entry *),
     int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
     int (*read_data_skip)(struct archive_read *),
+    int64_t (*seek_data)(struct archive_read *, int64_t, int),
     int (*cleanup)(struct archive_read *))
 {
 	int i, number_slots;
@@ -928,6 +1113,7 @@ __archive_read_register_format(struct archive_read *a,
 			a->formats[i].read_header = read_header;
 			a->formats[i].read_data = read_data;
 			a->formats[i].read_data_skip = read_data_skip;
+			a->formats[i].seek_data = seek_data;
 			a->formats[i].cleanup = cleanup;
 			a->formats[i].data = format_data;
 			a->formats[i].name = name;
@@ -1074,7 +1260,8 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 		if (filter->next > filter->buffer &&
 		    filter->next + min > filter->buffer + filter->buffer_size) {
 			if (filter->avail > 0)
-				memmove(filter->buffer, filter->next, filter->avail);
+				memmove(filter->buffer, filter->next,
+				    filter->avail);
 			filter->next = filter->buffer;
 		}
 
@@ -1089,15 +1276,26 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 			    &filter->client_buff);
 			if (bytes_read < 0) {		/* Read error. */
 				filter->client_total = filter->client_avail = 0;
-				filter->client_next = filter->client_buff = NULL;
+				filter->client_next =
+				    filter->client_buff = NULL;
 				filter->fatal = 1;
 				if (avail != NULL)
 					*avail = ARCHIVE_FATAL;
 				return (NULL);
 			}
-			if (bytes_read == 0) {	/* Premature end-of-file. */
+			if (bytes_read == 0) {
+				/* Check for another client object first */
+				if (filter->archive->client.cursor !=
+				      filter->archive->client.nodes - 1) {
+					if (client_switch_proxy(filter,
+					    filter->archive->client.cursor + 1)
+					    == ARCHIVE_OK)
+						continue;
+				}
+				/* Premature end-of-file. */
 				filter->client_total = filter->client_avail = 0;
-				filter->client_next = filter->client_buff = NULL;
+				filter->client_next =
+				    filter->client_buff = NULL;
 				filter->end_of_file = 1;
 				/* Return whatever we do have. */
 				if (avail != NULL)
@@ -1107,9 +1305,7 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 			filter->client_total = bytes_read;
 			filter->client_avail = filter->client_total;
 			filter->client_next = filter->client_buff;
-		}
-		else
-		{
+		} else {
 			/*
 			 * We can't satisfy the request from the copy
 			 * buffer or the existing client data, so we
@@ -1130,9 +1326,10 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 					t *= 2;
 					if (t <= s) { /* Integer overflow! */
 						archive_set_error(
-							&filter->archive->archive,
-							ENOMEM,
-						    "Unable to allocate copy buffer");
+						    &filter->archive->archive,
+						    ENOMEM,
+						    "Unable to allocate copy"
+						    " buffer");
 						filter->fatal = 1;
 						if (avail != NULL)
 							*avail = ARCHIVE_FATAL;
@@ -1171,8 +1368,8 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 			if (tocopy > filter->client_avail)
 				tocopy = filter->client_avail;
 
-			memcpy(filter->next + filter->avail, filter->client_next,
-			    tocopy);
+			memcpy(filter->next + filter->avail,
+			    filter->client_next, tocopy);
 			/* Remove this data from client buffer. */
 			filter->client_next += tocopy;
 			filter->client_avail -= tocopy;
@@ -1231,7 +1428,7 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
 
 	/* Use up the copy buffer first. */
 	if (filter->avail > 0) {
-		min = minimum(request, (int64_t)filter->avail);
+		min = (size_t)minimum(request, (int64_t)filter->avail);
 		filter->next += min;
 		filter->avail -= min;
 		request -= min;
@@ -1241,7 +1438,7 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
 
 	/* Then use up the client buffer. */
 	if (filter->client_avail > 0) {
-		min = minimum(request, (int64_t)filter->client_avail);
+		min = (size_t)minimum(request, (int64_t)filter->client_avail);
 		filter->client_next += min;
 		filter->client_avail -= min;
 		request -= min;
@@ -1275,6 +1472,13 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
 		}
 
 		if (bytes_read == 0) {
+			if (filter->archive->client.cursor !=
+			      filter->archive->client.nodes - 1) {
+				if (client_switch_proxy(filter,
+				    filter->archive->client.cursor + 1)
+				    == ARCHIVE_OK)
+					continue;
+			}
 			filter->client_buff = NULL;
 			filter->end_of_file = 1;
 			return (total_bytes_skipped);
@@ -1283,7 +1487,7 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
 		if (bytes_read >= request) {
 			filter->client_next =
 			    ((const char *)filter->client_buff) + request;
-			filter->client_avail = bytes_read - request;
+			filter->client_avail = (size_t)(bytes_read - request);
 			filter->client_total = bytes_read;
 			total_bytes_skipped += request;
 			filter->position += request;
@@ -1306,15 +1510,109 @@ __archive_read_seek(struct archive_read *a, int64_t offset, int whence)
 }
 
 int64_t
-__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, int whence)
+__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
+    int whence)
 {
+	struct archive_read_client *client;
 	int64_t r;
+	unsigned int cursor;
 
 	if (filter->closed || filter->fatal)
 		return (ARCHIVE_FATAL);
 	if (filter->seek == NULL)
 		return (ARCHIVE_FAILED);
-	r = filter->seek(filter, offset, whence);
+
+	client = &(filter->archive->client);
+	switch (whence) {
+	case SEEK_CUR:
+		/* Adjust the offset and use SEEK_SET instead */
+		offset += filter->position;			
+	case SEEK_SET:
+		cursor = 0;
+		while (1)
+		{
+			if (client->dataset[cursor].begin_position < 0 ||
+			    client->dataset[cursor].total_size < 0 ||
+			    client->dataset[cursor].begin_position +
+			      client->dataset[cursor].total_size - 1 > offset ||
+			    cursor + 1 >= client->nodes)
+				break;
+			r = client->dataset[cursor].begin_position +
+				client->dataset[cursor].total_size;
+			client->dataset[++cursor].begin_position = r;
+		}
+		while (1) {
+			r = client_switch_proxy(filter, cursor);
+			if (r != ARCHIVE_OK)
+				return r;
+			if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)
+				return r;
+			client->dataset[cursor].total_size = r;
+			if (client->dataset[cursor].begin_position +
+			    client->dataset[cursor].total_size - 1 > offset ||
+			    cursor + 1 >= client->nodes)
+				break;
+			r = client->dataset[cursor].begin_position +
+				client->dataset[cursor].total_size;
+			client->dataset[++cursor].begin_position = r;
+		}
+		offset -= client->dataset[cursor].begin_position;
+		if (offset < 0)
+			offset = 0;
+		else if (offset > client->dataset[cursor].total_size - 1)
+			offset = client->dataset[cursor].total_size - 1;
+		if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0)
+			return r;
+		break;
+
+	case SEEK_END:
+		cursor = 0;
+		while (1) {
+			if (client->dataset[cursor].begin_position < 0 ||
+			    client->dataset[cursor].total_size < 0 ||
+			    cursor + 1 >= client->nodes)
+				break;
+			r = client->dataset[cursor].begin_position +
+				client->dataset[cursor].total_size;
+			client->dataset[++cursor].begin_position = r;
+		}
+		while (1) {
+			r = client_switch_proxy(filter, cursor);
+			if (r != ARCHIVE_OK)
+				return r;
+			if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)
+				return r;
+			client->dataset[cursor].total_size = r;
+			r = client->dataset[cursor].begin_position +
+				client->dataset[cursor].total_size;
+			if (cursor + 1 >= client->nodes)
+				break;
+			client->dataset[++cursor].begin_position = r;
+		}
+		while (1) {
+			if (r + offset >=
+			    client->dataset[cursor].begin_position)
+				break;
+			offset += client->dataset[cursor].total_size;
+			if (cursor == 0)
+				break;
+			cursor--;
+			r = client->dataset[cursor].begin_position +
+				client->dataset[cursor].total_size;
+		}
+		offset = (r + offset) - client->dataset[cursor].begin_position;
+		if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK)
+			return r;
+		r = client_seek_proxy(filter, offset, SEEK_SET);
+		if (r < ARCHIVE_OK)
+			return r;
+		break;
+
+	default:
+		return (ARCHIVE_FATAL);
+	}
+	r += client->dataset[cursor].begin_position;
+
 	if (r >= 0) {
 		/*
 		 * Ouch.  Clearing the buffer like this hurts, especially
diff --git a/libarchive/archive_read_append_filter.c b/libarchive/archive_read_append_filter.c
new file mode 100644
index 0000000..017d7c6
--- /dev/null
+++ b/libarchive/archive_read_append_filter.c
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2003-2012 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+int
+archive_read_append_filter(struct archive *_a, int code)
+{
+  int r1, r2, number_bidders, i;
+  char str[20];
+  struct archive_read_filter_bidder *bidder;
+  struct archive_read_filter *filter;
+  struct archive_read *a = (struct archive_read *)_a;
+
+  r1 = r2 = (ARCHIVE_OK);
+  switch (code)
+  {
+    case ARCHIVE_FILTER_NONE:
+      /* No filter to add, so do nothing.
+       * NOTE: An initial "NONE" type filter is always set at the end of the
+       * filter chain.
+       */
+      r1 = (ARCHIVE_OK);
+      break;
+    case ARCHIVE_FILTER_GZIP:
+      strcpy(str, "gzip");
+      r1 = archive_read_support_filter_gzip(_a);
+      break;
+    case ARCHIVE_FILTER_BZIP2:
+      strcpy(str, "bzip2");
+      r1 = archive_read_support_filter_bzip2(_a);
+      break;
+    case ARCHIVE_FILTER_COMPRESS:
+      strcpy(str, "compress (.Z)");
+      r1 = archive_read_support_filter_compress(_a);
+      break;
+    case ARCHIVE_FILTER_PROGRAM:
+      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+          "Cannot append program filter using archive_read_append_filter");
+      return (ARCHIVE_FATAL);
+    case ARCHIVE_FILTER_LZMA:
+      strcpy(str, "lzma");
+      r1 = archive_read_support_filter_lzma(_a);
+      break;
+    case ARCHIVE_FILTER_XZ:
+      strcpy(str, "xz");
+      r1 = archive_read_support_filter_xz(_a);
+      break;
+    case ARCHIVE_FILTER_UU:
+      strcpy(str, "uu");
+      r1 = archive_read_support_filter_uu(_a);
+      break;
+    case ARCHIVE_FILTER_RPM:
+      strcpy(str, "rpm");
+      r1 = archive_read_support_filter_rpm(_a);
+      break;
+    case ARCHIVE_FILTER_LZIP:
+      strcpy(str, "lzip");
+      r1 = archive_read_support_filter_lzip(_a);
+      break;
+    case ARCHIVE_FILTER_LRZIP:
+      strcpy(str, "lrzip");
+      r1 = archive_read_support_filter_lrzip(_a);
+      break;
+    default:
+      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+          "Invalid filter code specified");
+      return (ARCHIVE_FATAL);
+  }
+
+  if (code != ARCHIVE_FILTER_NONE)
+  {
+    number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
+
+    bidder = a->bidders;
+    for (i = 0; i < number_bidders; i++, bidder++)
+    {
+      if (!bidder->name || !strcmp(bidder->name, str))
+        break;
+    }
+    if (!bidder->name || strcmp(bidder->name, str))
+    {
+      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+          "Internal error: Unable to append filter");
+      return (ARCHIVE_FATAL);
+    }
+
+    filter
+        = (struct archive_read_filter *)calloc(1, sizeof(*filter));
+    if (filter == NULL)
+    {
+      archive_set_error(&a->archive, ENOMEM, "Out of memory");
+      return (ARCHIVE_FATAL);
+    }
+    filter->bidder = bidder;
+    filter->archive = a;
+    filter->upstream = a->filter;
+    a->filter = filter;
+    r2 = (bidder->init)(a->filter);
+    if (r2 != ARCHIVE_OK) {
+      __archive_read_close_filters(a);
+      __archive_read_free_filters(a);
+      return (ARCHIVE_FATAL);
+    }
+  }
+
+  a->bypass_filter_bidding = 1;
+  return (r1 < r2) ? r1 : r2;
+}
+
+int
+archive_read_append_filter_program(struct archive *_a, const char *cmd)
+{
+  return (archive_read_append_filter_program_signature(_a, cmd, NULL, 0));
+}
+
+int
+archive_read_append_filter_program_signature(struct archive *_a,
+  const char *cmd, const void *signature, size_t signature_len)
+{
+  int r, number_bidders, i;
+  struct archive_read_filter_bidder *bidder;
+  struct archive_read_filter *filter;
+  struct archive_read *a = (struct archive_read *)_a;
+
+  if (archive_read_support_filter_program_signature(_a, cmd, signature,
+    signature_len) != (ARCHIVE_OK))
+    return (ARCHIVE_FATAL);
+
+  number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
+
+  bidder = a->bidders;
+  for (i = 0; i < number_bidders; i++, bidder++)
+  {
+    /* Program bidder name set to filter name after initialization */
+    if (bidder->data && !bidder->name)
+      break;
+  }
+  if (!bidder->data)
+  {
+    archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+        "Internal error: Unable to append program filter");
+    return (ARCHIVE_FATAL);
+  }
+
+  filter
+      = (struct archive_read_filter *)calloc(1, sizeof(*filter));
+  if (filter == NULL)
+  {
+    archive_set_error(&a->archive, ENOMEM, "Out of memory");
+    return (ARCHIVE_FATAL);
+  }
+  filter->bidder = bidder;
+  filter->archive = a;
+  filter->upstream = a->filter;
+  a->filter = filter;
+  r = (bidder->init)(a->filter);
+  if (r != ARCHIVE_OK) {
+    __archive_read_close_filters(a);
+    __archive_read_free_filters(a);
+    return (ARCHIVE_FATAL);
+  }
+  bidder->name = a->filter->name;
+
+  a->bypass_filter_bidding = 1;
+  return r;
+}
diff --git a/libarchive/archive_read_data.3 b/libarchive/archive_read_data.3
index 78d0497..bf0578c 100644
--- a/libarchive/archive_read_data.3
+++ b/libarchive/archive_read_data.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 22, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_DATA 3
 .Os
 .Sh NAME
@@ -33,6 +33,8 @@
 .Nm archive_read_data_skip ,
 .Nm archive_read_data_into_fd
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft ssize_t
diff --git a/libarchive/archive_read_data_into_fd.c b/libarchive/archive_read_data_into_fd.c
index 14f9410..b4398f1 100644
--- a/libarchive/archive_read_data_into_fd.c
+++ b/libarchive/archive_read_data_into_fd.c
@@ -64,7 +64,7 @@ pad_to(struct archive *a, int fd, int can_lseek,
 	}
 	while (target_offset > actual_offset) {
 		to_write = nulls_size;
-		if (target_offset < actual_offset + nulls_size)
+		if (target_offset < actual_offset + (int64_t)nulls_size)
 			to_write = (size_t)(target_offset - actual_offset);
 		bytes_written = write(fd, nulls, to_write);
 		if (bytes_written < 0) {
diff --git a/libarchive/archive_read_disk.3 b/libarchive/archive_read_disk.3
index 3c49bff..525dc59 100644
--- a/libarchive/archive_read_disk.3
+++ b/libarchive/archive_read_disk.3
@@ -22,9 +22,9 @@
 .\" 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 $
+.\" $FreeBSD$
 .\"
-.Dd March 10, 2009
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_DISK 3
 .Os
 .Sh NAME
@@ -42,6 +42,8 @@
 .Nm archive_read_finish ,
 .Nm archive_read_free
 .Nd functions for reading objects from disk
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft struct archive *
diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c
index 8ce88b3..e984aaa 100644
--- a/libarchive/archive_read_disk_entry_from_file.c
+++ b/libarchive/archive_read_disk_entry_from_file.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2003-2009 Tim Kientzle
- * Copyright (c) 2010 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,8 +49,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
-#ifdef HAVE_SYS_XATTR_H
+#if defined(HAVE_SYS_XATTR_H)
 #include <sys/xattr.h>
+#elif defined(HAVE_ATTR_XATTR_H)
+#include <attr/xattr.h>
 #endif
 #ifdef HAVE_SYS_EA_H
 #include <sys/ea.h>
@@ -58,9 +60,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #ifdef HAVE_ACL_LIBACL_H
 #include <acl/libacl.h>
 #endif
-#ifdef HAVE_ATTR_XATTR_H
-#include <attr/xattr.h>
-#endif
 #ifdef HAVE_COPYFILE_H
 #include <copyfile.h>
 #endif
@@ -73,6 +72,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #ifdef HAVE_LIMITS_H
 #include <limits.h>
 #endif
+#ifdef HAVE_LINUX_TYPES_H
+#include <linux/types.h>
+#endif
 #ifdef HAVE_LINUX_FIEMAP_H
 #include <linux/fiemap.h>
 #endif
@@ -101,6 +103,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #include "archive_private.h"
 #include "archive_read_disk_private.h"
 
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
+
 /*
  * Linux and FreeBSD plug this obvious hole in POSIX.1e in
  * different ways.
@@ -111,14 +117,14 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #define	ACL_GET_PERM acl_get_perm_np
 #endif
 
-static int setup_acls_posix1e(struct archive_read_disk *,
-    struct archive_entry *, int fd);
+static int setup_acls(struct archive_read_disk *,
+    struct archive_entry *, int *fd);
 static int setup_mac_metadata(struct archive_read_disk *,
-    struct archive_entry *, int fd);
+    struct archive_entry *, int *fd);
 static int setup_xattrs(struct archive_read_disk *,
-    struct archive_entry *, int fd);
+    struct archive_entry *, int *fd);
 static int setup_sparse(struct archive_read_disk *,
-    struct archive_entry *, int fd);
+    struct archive_entry *, int *fd);
 
 int
 archive_read_disk_entry_from_file(struct archive *_a,
@@ -187,11 +193,18 @@ archive_read_disk_entry_from_file(struct archive *_a,
 	 * this is an extra step, it has a nice side-effect: We get an
 	 * open file descriptor which we can use in the subsequent lookups. */
 	if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
-		if (fd < 0)
-			fd = open(path, O_RDONLY | O_NONBLOCK);
+		if (fd < 0) {
+			if (a->tree != NULL)
+				fd = a->open_on_current_dir(a->tree, path,
+					O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+			else
+				fd = open(path, O_RDONLY | O_NONBLOCK |
+						O_CLOEXEC);
+			__archive_ensure_cloexec_flag(fd);
+		}
 		if (fd >= 0) {
-			unsigned long stflags;
-			int r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
+			int stflags;
+			r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
 			if (r == 0 && stflags != 0)
 				archive_entry_set_fflags(entry, stflags, 0);
 		}
@@ -210,13 +223,21 @@ archive_read_disk_entry_from_file(struct archive *_a,
 			    "Couldn't read link data");
 			return (ARCHIVE_FAILED);
 		}
+		if (a->tree != NULL) {
 #ifdef HAVE_READLINKAT
-		if (a->entry_wd_fd >= 0)
-			lnklen = readlinkat(a->entry_wd_fd, path,
-			    linkbuffer, linkbuffer_len);
-		else
+			lnklen = readlinkat(a->tree_current_dir_fd(a->tree),
+			    path, linkbuffer, linkbuffer_len);
+#else
+			if (a->tree_enter_working_dir(a->tree) != 0) {
+				archive_set_error(&a->archive, errno,
+				    "Couldn't read link data");
+				free(linkbuffer);
+				return (ARCHIVE_FAILED);
+			}
+			lnklen = readlink(path, linkbuffer, linkbuffer_len);
 #endif /* HAVE_READLINKAT */
-		lnklen = readlink(path, linkbuffer, linkbuffer_len);
+		} else
+			lnklen = readlink(path, linkbuffer, linkbuffer_len);
 		if (lnklen < 0) {
 			archive_set_error(&a->archive, errno,
 			    "Couldn't read link data");
@@ -229,14 +250,16 @@ archive_read_disk_entry_from_file(struct archive *_a,
 	}
 #endif /* HAVE_READLINK || HAVE_READLINKAT */
 
-	r = setup_acls_posix1e(a, entry, fd);
-	r1 = setup_xattrs(a, entry, fd);
-	if (r1 < r)
-		r = r1;
-	r1 = setup_mac_metadata(a, entry, fd);
+	r = setup_acls(a, entry, &fd);
+	r1 = setup_xattrs(a, entry, &fd);
 	if (r1 < r)
 		r = r1;
-	r1 = setup_sparse(a, entry, fd);
+	if (a->enable_copyfile) {
+		r1 = setup_mac_metadata(a, entry, &fd);
+		if (r1 < r)
+			r = r1;
+	}
+	r1 = setup_sparse(a, entry, &fd);
 	if (r1 < r)
 		r = r1;
 
@@ -262,16 +285,18 @@ archive_read_disk_entry_from_file(struct archive *_a,
  */
 static int
 setup_mac_metadata(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 	int tempfd = -1;
 	int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
 	struct stat copyfile_stat;
 	int ret = ARCHIVE_OK;
-	void *buff;
+	void *buff = NULL;
 	int have_attrs;
-	const char *name, *tempdir, *tempfile = NULL;
+	const char *name, *tempdir;
+	struct archive_string tempfile;
 
+	(void)fd; /* UNUSED */
 	name = archive_entry_sourcepath(entry);
 	if (name == NULL)
 		name = archive_entry_pathname(entry);
@@ -281,6 +306,14 @@ setup_mac_metadata(struct archive_read_disk *a,
 		return (ARCHIVE_WARN);
 	}
 
+	if (a->tree != NULL) {
+		if (a->tree_enter_working_dir(a->tree) != 0) {
+			archive_set_error(&a->archive, errno,
+				    "Couldn't change dir");
+				return (ARCHIVE_FAILED);
+		}
+	}
+
 	/* Short-circuit if there's nothing to do. */
 	have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
 	if (have_attrs == -1) {
@@ -296,25 +329,28 @@ setup_mac_metadata(struct archive_read_disk *a,
 		tempdir = getenv("TMPDIR");
 	if (tempdir == NULL)
 		tempdir = _PATH_TMP;
-	tempfile = tempnam(tempdir, "tar.md.");
+	archive_string_init(&tempfile);
+	archive_strcpy(&tempfile, tempdir);
+	archive_strcat(&tempfile, "tar.md.XXXXXX");
+	tempfd = mkstemp(tempfile.s);
+	if (tempfd < 0) {
+		archive_set_error(&a->archive, errno,
+		    "Could not open extended attribute file");
+		ret = ARCHIVE_WARN;
+		goto cleanup;
+	}
+	__archive_ensure_cloexec_flag(tempfd);
 
 	/* XXX I wish copyfile() could pack directly to a memory
 	 * buffer; that would avoid the temp file here.  For that
 	 * matter, it would be nice if fcopyfile() actually worked,
 	 * that would reduce the many open/close races here. */
-	if (copyfile(name, tempfile, 0, copyfile_flags | COPYFILE_PACK)) {
+	if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) {
 		archive_set_error(&a->archive, errno,
 		    "Could not pack extended attributes");
 		ret = ARCHIVE_WARN;
 		goto cleanup;
 	}
-	tempfd = open(tempfile, O_RDONLY);
-	if (tempfd < 0) {
-		archive_set_error(&a->archive, errno,
-		    "Could not open extended attribute file");
-		ret = ARCHIVE_WARN;
-		goto cleanup;
-	}
 	if (fstat(tempfd, &copyfile_stat)) {
 		archive_set_error(&a->archive, errno,
 		    "Could not check size of extended attributes");
@@ -337,10 +373,12 @@ setup_mac_metadata(struct archive_read_disk *a,
 	archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
 
 cleanup:
-	if (tempfd >= 0)
+	if (tempfd >= 0) {
 		close(tempfd);
-	if (tempfile != NULL)
-		unlink(tempfile);
+		unlink(tempfile.s);
+	}
+	archive_string_free(&tempfile);
+	free(buff);
 	return (ret);
 }
 
@@ -351,7 +389,7 @@ cleanup:
  */
 static int
 setup_mac_metadata(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 	(void)a; /* UNUSED */
 	(void)entry; /* UNUSED */
@@ -361,16 +399,19 @@ setup_mac_metadata(struct archive_read_disk *a,
 #endif
 
 
-#ifdef HAVE_POSIX_ACL
-static void setup_acl_posix1e(struct archive_read_disk *a,
+#if defined(HAVE_POSIX_ACL) && defined(ACL_TYPE_NFS4)
+static int translate_acl(struct archive_read_disk *a,
     struct archive_entry *entry, acl_t acl, int archive_entry_acl_type);
 
 static int
-setup_acls_posix1e(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+setup_acls(struct archive_read_disk *a,
+    struct archive_entry *entry, int *fd)
 {
 	const char	*accpath;
 	acl_t		 acl;
+#if HAVE_ACL_IS_TRIVIAL_NP
+	int		r;
+#endif
 
 	accpath = archive_entry_sourcepath(entry);
 	if (accpath == NULL)
@@ -378,9 +419,38 @@ setup_acls_posix1e(struct archive_read_disk *a,
 
 	archive_entry_acl_clear(entry);
 
+	/* Try NFS4 ACL first. */
+	if (*fd >= 0)
+		acl = acl_get_fd(*fd);
+#if HAVE_ACL_GET_LINK_NP
+	else if (!a->follow_symlinks)
+		acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
+#else
+	else if ((!a->follow_symlinks)
+	    && (archive_entry_filetype(entry) == AE_IFLNK))
+		/* We can't get the ACL of a symlink, so we assume it can't
+		   have one. */
+		acl = NULL;
+#endif
+	else
+		acl = acl_get_file(accpath, ACL_TYPE_NFS4);
+#if HAVE_ACL_IS_TRIVIAL_NP
+	/* Ignore "trivial" ACLs that just mirror the file mode. */
+	acl_is_trivial_np(acl, &r);
+	if (r) {
+		acl_free(acl);
+		acl = NULL;
+	}
+#endif
+	if (acl != NULL) {
+		translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+		acl_free(acl);
+		return (ARCHIVE_OK);
+	}
+
 	/* Retrieve access ACL from file. */
-	if (fd >= 0)
-		acl = acl_get_fd(fd);
+	if (*fd >= 0)
+		acl = acl_get_fd(*fd);
 #if HAVE_ACL_GET_LINK_NP
 	else if (!a->follow_symlinks)
 		acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
@@ -394,7 +464,7 @@ setup_acls_posix1e(struct archive_read_disk *a,
 	else
 		acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
 	if (acl != NULL) {
-		setup_acl_posix1e(a, entry, acl,
+		translate_acl(a, entry, acl,
 		    ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
 		acl_free(acl);
 	}
@@ -403,7 +473,7 @@ setup_acls_posix1e(struct archive_read_disk *a,
 	if (S_ISDIR(archive_entry_mode(entry))) {
 		acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
 		if (acl != NULL) {
-			setup_acl_posix1e(a, entry, acl,
+			translate_acl(a, entry, acl,
 			    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
 			acl_free(acl);
 		}
@@ -412,69 +482,181 @@ setup_acls_posix1e(struct archive_read_disk *a,
 }
 
 /*
- * Translate POSIX.1e ACL into libarchive internal structure.
+ * Translate system ACL into libarchive internal structure.
  */
-static void
-setup_acl_posix1e(struct archive_read_disk *a,
-    struct archive_entry *entry, acl_t acl, int archive_entry_acl_type)
+
+static struct {
+        int archive_perm;
+        int platform_perm;
+} acl_perm_map[] = {
+        {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+        {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
+        {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
+        {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+        {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+        {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+        {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+        {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+        {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+        {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
+        {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
+        {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+        {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+        {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+        {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+        {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
+        {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
+        {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
+        {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+};
+
+static struct {
+        int archive_inherit;
+        int platform_inherit;
+} acl_inherit_map[] = {
+        {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+	{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+	{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
+	{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
+};
+
+static int
+translate_acl(struct archive_read_disk *a,
+    struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
 {
 	acl_tag_t	 acl_tag;
+	acl_entry_type_t acl_type;
+	acl_flagset_t	 acl_flagset;
 	acl_entry_t	 acl_entry;
 	acl_permset_t	 acl_permset;
+	int		 brand, i, r, entry_acl_type;
 	int		 s, ae_id, ae_tag, ae_perm;
 	const char	*ae_name;
 
+
+	// FreeBSD "brands" ACLs as POSIX.1e or NFSv4
+	// Make sure the "brand" on this ACL is consistent
+	// with the default_entry_acl_type bits provided.
+	acl_get_brand_np(acl, &brand);
+	switch (brand) {
+	case ACL_BRAND_POSIX:
+		switch (default_entry_acl_type) {
+		case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+		case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+			break;
+		default:
+			// XXX set warning message?
+			return ARCHIVE_FAILED;
+		}
+		break;
+	case ACL_BRAND_NFS4:
+		if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+			// XXX set warning message?
+			return ARCHIVE_FAILED;
+		}
+		break;
+	default:
+		// XXX set warning message?
+		return ARCHIVE_FAILED;
+		break;
+	}
+
+
 	s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
 	while (s == 1) {
 		ae_id = -1;
 		ae_name = NULL;
+		ae_perm = 0;
 
 		acl_get_tag_type(acl_entry, &acl_tag);
-		if (acl_tag == ACL_USER) {
+		switch (acl_tag) {
+		case ACL_USER:
 			ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
 			ae_name = archive_read_disk_uname(&a->archive, ae_id);
 			ae_tag = ARCHIVE_ENTRY_ACL_USER;
-		} else if (acl_tag == ACL_GROUP) {
+			break;
+		case ACL_GROUP:
 			ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry);
 			ae_name = archive_read_disk_gname(&a->archive, ae_id);
 			ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
-		} else if (acl_tag == ACL_MASK) {
+			break;
+		case ACL_MASK:
 			ae_tag = ARCHIVE_ENTRY_ACL_MASK;
-		} else if (acl_tag == ACL_USER_OBJ) {
+			break;
+		case ACL_USER_OBJ:
 			ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
-		} else if (acl_tag == ACL_GROUP_OBJ) {
+			break;
+		case ACL_GROUP_OBJ:
 			ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
-		} else if (acl_tag == ACL_OTHER) {
+			break;
+		case ACL_OTHER:
 			ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
-		} else {
+			break;
+		case ACL_EVERYONE:
+			ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+			break;
+		default:
 			/* Skip types that libarchive can't support. */
+			s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
 			continue;
 		}
 
-		acl_get_permset(acl_entry, &acl_permset);
-		ae_perm = 0;
+		// XXX acl type maps to allow/deny/audit/YYYY bits
+		// XXX acl_get_entry_type_np on FreeBSD returns EINVAL for
+		// non-NFSv4 ACLs
+		entry_acl_type = default_entry_acl_type;
+		r = acl_get_entry_type_np(acl_entry, &acl_type);
+		if (r == 0) {
+			switch (acl_type) {
+			case ACL_ENTRY_TYPE_ALLOW:
+				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+				break;
+			case ACL_ENTRY_TYPE_DENY:
+				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+				break;
+			case ACL_ENTRY_TYPE_AUDIT:
+				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
+				break;
+			case ACL_ENTRY_TYPE_ALARM:
+				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+				break;
+			}
+		}
+
 		/*
-		 * acl_get_perm() is spelled differently on different
-		 * platforms; see above.
+		 * Libarchive stores "flag" (NFSv4 inheritance bits)
+		 * in the ae_perm bitmap.
 		 */
-		if (ACL_GET_PERM(acl_permset, ACL_EXECUTE))
-			ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
-		if (ACL_GET_PERM(acl_permset, ACL_READ))
-			ae_perm |= ARCHIVE_ENTRY_ACL_READ;
-		if (ACL_GET_PERM(acl_permset, ACL_WRITE))
-			ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
+		acl_get_flagset_np(acl_entry, &acl_flagset);
+                for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
+			if (acl_get_flag_np(acl_flagset,
+					    acl_inherit_map[i].platform_inherit))
+				ae_perm |= acl_inherit_map[i].archive_inherit;
 
-		archive_entry_acl_add_entry(entry,
-		    archive_entry_acl_type, ae_perm, ae_tag,
-		    ae_id, ae_name);
+                }
+
+		acl_get_permset(acl_entry, &acl_permset);
+                for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
+			/*
+			 * acl_get_perm() is spelled differently on different
+			 * platforms; see above.
+			 */
+			if (ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm))
+				ae_perm |= acl_perm_map[i].archive_perm;
+		}
+
+		archive_entry_acl_add_entry(entry, entry_acl_type,
+					    ae_perm, ae_tag,
+					    ae_id, ae_name);
 
 		s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
 	}
+	return (ARCHIVE_OK);
 }
 #else
 static int
-setup_acls_posix1e(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+setup_acls(struct archive_read_disk *a,
+    struct archive_entry *entry, int *fd)
 {
 	(void)a;      /* UNUSED */
 	(void)entry;  /* UNUSED */
@@ -568,7 +750,7 @@ setup_xattr(struct archive_read_disk *a,
 
 static int
 setup_xattrs(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 	char *list, *p;
 	const char *path;
@@ -578,16 +760,30 @@ setup_xattrs(struct archive_read_disk *a,
 	if (path == NULL)
 		path = archive_entry_pathname(entry);
 
+	if (*fd < 0 && a->tree != NULL) {
+		if (a->follow_symlinks ||
+		    archive_entry_filetype(entry) != AE_IFLNK)
+			*fd = a->open_on_current_dir(a->tree, path,
+				O_RDONLY | O_NONBLOCK);
+		if (*fd < 0) {
+			if (a->tree_enter_working_dir(a->tree) != 0) {
+				archive_set_error(&a->archive, errno,
+				    "Couldn't access %s", path);
+				return (ARCHIVE_FAILED);
+			}
+		}
+	}
+
 #if HAVE_FLISTXATTR
-	if (fd >= 0)
-		list_size = flistxattr(fd, NULL, 0);
+	if (*fd >= 0)
+		list_size = flistxattr(*fd, NULL, 0);
 	else if (!a->follow_symlinks)
 		list_size = llistxattr(path, NULL, 0);
 	else
 		list_size = listxattr(path, NULL, 0);
 #elif HAVE_FLISTEA
-	if (fd >= 0)
-		list_size = flistea(fd, NULL, 0);
+	if (*fd >= 0)
+		list_size = flistea(*fd, NULL, 0);
 	else if (!a->follow_symlinks)
 		list_size = llistea(path, NULL, 0);
 	else
@@ -611,15 +807,15 @@ setup_xattrs(struct archive_read_disk *a,
 	}
 
 #if HAVE_FLISTXATTR
-	if (fd >= 0)
-		list_size = flistxattr(fd, list, list_size);
+	if (*fd >= 0)
+		list_size = flistxattr(*fd, list, list_size);
 	else if (!a->follow_symlinks)
 		list_size = llistxattr(path, list, list_size);
 	else
 		list_size = listxattr(path, list, list_size);
 #elif HAVE_FLISTEA
-	if (fd >= 0)
-		list_size = flistea(fd, list, list_size);
+	if (*fd >= 0)
+		list_size = flistea(*fd, list, list_size);
 	else if (!a->follow_symlinks)
 		list_size = llistea(path, list, list_size);
 	else
@@ -637,7 +833,7 @@ setup_xattrs(struct archive_read_disk *a,
 		if (strncmp(p, "system.", 7) == 0 ||
 				strncmp(p, "xfsroot.", 8) == 0)
 			continue;
-		setup_xattr(a, entry, p, fd);
+		setup_xattr(a, entry, p, *fd);
 	}
 
 	free(list);
@@ -698,6 +894,7 @@ setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
 		size = extattr_get_file(accpath, namespace, name, value, size);
 
 	if (size == -1) {
+		free(value);
 		archive_set_error(&a->archive, errno,
 		    "Couldn't read extended attribute");
 		return (ARCHIVE_WARN);
@@ -711,7 +908,7 @@ setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
 
 static int
 setup_xattrs(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 	char buff[512];
 	char *list, *p;
@@ -723,8 +920,22 @@ setup_xattrs(struct archive_read_disk *a,
 	if (path == NULL)
 		path = archive_entry_pathname(entry);
 
-	if (fd >= 0)
-		list_size = extattr_list_fd(fd, namespace, NULL, 0);
+	if (*fd < 0 && a->tree != NULL) {
+		if (a->follow_symlinks ||
+		    archive_entry_filetype(entry) != AE_IFLNK)
+			*fd = a->open_on_current_dir(a->tree, path,
+				O_RDONLY | O_NONBLOCK);
+		if (*fd < 0) {
+			if (a->tree_enter_working_dir(a->tree) != 0) {
+				archive_set_error(&a->archive, errno,
+				    "Couldn't access %s", path);
+				return (ARCHIVE_FAILED);
+			}
+		}
+	}
+
+	if (*fd >= 0)
+		list_size = extattr_list_fd(*fd, namespace, NULL, 0);
 	else if (!a->follow_symlinks)
 		list_size = extattr_list_link(path, namespace, NULL, 0);
 	else
@@ -746,8 +957,8 @@ setup_xattrs(struct archive_read_disk *a,
 		return (ARCHIVE_FATAL);
 	}
 
-	if (fd >= 0)
-		list_size = extattr_list_fd(fd, namespace, list, list_size);
+	if (*fd >= 0)
+		list_size = extattr_list_fd(*fd, namespace, list, list_size);
 	else if (!a->follow_symlinks)
 		list_size = extattr_list_link(path, namespace, list, list_size);
 	else
@@ -769,7 +980,7 @@ setup_xattrs(struct archive_read_disk *a,
 		name = buff + strlen(buff);
 		memcpy(name, p + 1, len);
 		name[len] = '\0';
-		setup_xattr(a, entry, namespace, name, buff, fd);
+		setup_xattr(a, entry, namespace, name, buff, *fd);
 		p += 1 + len;
 	}
 
@@ -784,7 +995,7 @@ setup_xattrs(struct archive_read_disk *a,
  */
 static int
 setup_xattrs(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 	(void)a;     /* UNUSED */
 	(void)entry; /* UNUSED */
@@ -813,14 +1024,13 @@ setup_xattrs(struct archive_read_disk *a,
 
 static int
 setup_sparse(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 	char buff[4096];
 	struct fiemap *fm;
 	struct fiemap_extent *fe;
 	int64_t size;
 	int count, do_fiemap;
-	int initial_fd = fd;
 	int exit_sts = ARCHIVE_OK;
 
 	if (archive_entry_filetype(entry) != AE_IFREG
@@ -828,20 +1038,27 @@ setup_sparse(struct archive_read_disk *a,
 	    || archive_entry_hardlink(entry) != NULL)
 		return (ARCHIVE_OK);
 
-	if (fd < 0) {
+	if (*fd < 0) {
 		const char *path;
 
 		path = archive_entry_sourcepath(entry);
 		if (path == NULL)
 			path = archive_entry_pathname(entry);
-		fd = open(path, O_RDONLY | O_NONBLOCK);
-		if (fd < 0) {
+		if (a->tree != NULL)
+			*fd = a->open_on_current_dir(a->tree, path,
+				O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+		else
+			*fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+		if (*fd < 0) {
 			archive_set_error(&a->archive, errno,
 			    "Can't open `%s'", path);
 			return (ARCHIVE_FAILED);
 		}
+		__archive_ensure_cloexec_flag(*fd);
 	}
 
+	/* Initialize buffer to avoid the error valgrind complains about. */
+	memset(buff, 0, sizeof(buff));
 	count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
 	fm = (struct fiemap *)buff;
 	fm->fm_start = 0;
@@ -853,29 +1070,22 @@ setup_sparse(struct archive_read_disk *a,
 	for (;;) {
 		int i, r;
 
-		r = ioctl(fd, FS_IOC_FIEMAP, fm); 
+		r = ioctl(*fd, FS_IOC_FIEMAP, fm); 
 		if (r < 0) {
-			/* When errno is ENOTTY, it is better we should
-			 * return ARCHIVE_OK because an earlier version
-			 *(<2.6.28) cannot perfom FS_IOC_FIEMAP.
-			 * We should also check if errno is EOPNOTSUPP,
-			 * it means "Operation not supported". */
-			if (errno != ENOTTY && errno != EOPNOTSUPP) {
-				archive_set_error(&a->archive, errno,
-				    "FIEMAP failed");
-				exit_sts = ARCHIVE_FAILED;
-			}
+			/* When something error happens, it is better we
+			 * should return ARCHIVE_OK because an earlier
+			 * version(<2.6.28) cannot perfom FS_IOC_FIEMAP. */
 			goto exit_setup_sparse;
 		}
 		if (fm->fm_mapped_extents == 0)
 			break;
 		fe = fm->fm_extents;
-		for (i = 0; i < fm->fm_mapped_extents; i++, fe++) {
+		for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {
 			if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
 				/* The fe_length of the last block does not
 				 * adjust itself to its size files. */
 				int64_t length = fe->fe_length;
-				if (fe->fe_logical + length > size)
+				if (fe->fe_logical + length > (uint64_t)size)
 					length -= fe->fe_logical + length - size;
 				if (fe->fe_logical == 0 && length == size) {
 					/* This is not sparse. */
@@ -896,8 +1106,6 @@ setup_sparse(struct archive_read_disk *a,
 			break;
 	}
 exit_setup_sparse:
-	if (initial_fd != fd)
-		close(fd);
 	return (exit_sts);
 }
 
@@ -909,10 +1117,9 @@ exit_setup_sparse:
 
 static int
 setup_sparse(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 	int64_t size;
-	int initial_fd = fd;
 	off_t initial_off; /* FreeBSD/Solaris only, so off_t okay here */
 	off_t off_s, off_e; /* FreeBSD/Solaris only, so off_t okay here */
 	int exit_sts = ARCHIVE_OK;
@@ -923,33 +1130,50 @@ setup_sparse(struct archive_read_disk *a,
 		return (ARCHIVE_OK);
 
 	/* Does filesystem support the reporting of hole ? */
-	if (fd >= 0) {
-		if (fpathconf(fd, _PC_MIN_HOLE_SIZE) <= 0)
+	if (*fd < 0 && a->tree != NULL) {
+		const char *path;
+
+		path = archive_entry_sourcepath(entry);
+		if (path == NULL)
+			path = archive_entry_pathname(entry);
+		*fd = a->open_on_current_dir(a->tree, path,
+				O_RDONLY | O_NONBLOCK);
+		if (*fd < 0) {
+			archive_set_error(&a->archive, errno,
+			    "Can't open `%s'", path);
+			return (ARCHIVE_FAILED);
+		}
+	}
+
+	if (*fd >= 0) {
+		if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
 			return (ARCHIVE_OK);
-		initial_off = lseek(fd, 0, SEEK_CUR);
+		initial_off = lseek(*fd, 0, SEEK_CUR);
 		if (initial_off != 0)
-			lseek(fd, 0, SEEK_SET);
+			lseek(*fd, 0, SEEK_SET);
 	} else {
 		const char *path;
 
 		path = archive_entry_sourcepath(entry);
 		if (path == NULL)
 			path = archive_entry_pathname(entry);
+			
 		if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
 			return (ARCHIVE_OK);
-		fd = open(path, O_RDONLY | O_NONBLOCK);
-		if (fd < 0) {
+		*fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+		if (*fd < 0) {
 			archive_set_error(&a->archive, errno,
 			    "Can't open `%s'", path);
 			return (ARCHIVE_FAILED);
 		}
+		__archive_ensure_cloexec_flag(*fd);
 		initial_off = 0;
 	}
 
 	off_s = 0;
 	size = archive_entry_size(entry);
 	while (off_s < size) {
-		off_s = lseek(fd, off_s, SEEK_DATA);
+		off_s = lseek(*fd, off_s, SEEK_DATA);
 		if (off_s == (off_t)-1) {
 			if (errno == ENXIO)
 				break;/* no more hole */
@@ -958,10 +1182,10 @@ setup_sparse(struct archive_read_disk *a,
 			exit_sts = ARCHIVE_FAILED;
 			goto exit_setup_sparse;
 		}
-		off_e = lseek(fd, off_s, SEEK_HOLE);
-		if (off_s == (off_t)-1) {
+		off_e = lseek(*fd, off_s, SEEK_HOLE);
+		if (off_e == (off_t)-1) {
 			if (errno == ENXIO) {
-				off_e = lseek(fd, 0, SEEK_END);
+				off_e = lseek(*fd, 0, SEEK_END);
 				if (off_e != (off_t)-1)
 					break;/* no more data */
 			}
@@ -977,10 +1201,7 @@ setup_sparse(struct archive_read_disk *a,
 		off_s = off_e;
 	}
 exit_setup_sparse:
-	if (initial_fd != fd)
-		close(fd);
-	else
-		lseek(fd, initial_off, SEEK_SET);
+	lseek(*fd, initial_off, SEEK_SET);
 	return (exit_sts);
 }
 
@@ -991,7 +1212,7 @@ exit_setup_sparse:
  */
 static int
 setup_sparse(struct archive_read_disk *a,
-    struct archive_entry *entry, int fd)
+    struct archive_entry *entry, int *fd)
 {
 	(void)a;     /* UNUSED */
 	(void)entry; /* UNUSED */
diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c
index b81ab30..a13dbbf 100644
--- a/libarchive/archive_read_disk_posix.c
+++ b/libarchive/archive_read_disk_posix.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2003-2009 Tim Kientzle
- * Copyright (c) 2010,2011 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,19 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_LINUX_MAGIC_H
 #include <linux/magic.h>
 #endif
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
+/*
+ * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
+ * As the include guards don't agree, the order of include is important.
+ */
+#ifdef HAVE_LINUX_EXT2_FS_H
+#include <linux/ext2_fs.h>      /* for Linux file flags */
+#endif
+#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
+#include <ext2fs/ext2_fs.h>     /* Linux file flags, broken on Cygwin */
+#endif
 #ifdef HAVE_DIRECT_H
 #include <direct.h>
 #endif
@@ -76,6 +89,9 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
 
 #include "archive.h"
 #include "archive_string.h"
@@ -89,6 +105,9 @@ __FBSDID("$FreeBSD$");
 #ifndef O_BINARY
 #define O_BINARY	0
 #endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
 
 /*-
  * This is a new directory-walking system that addresses a number
@@ -222,6 +241,7 @@ struct tree {
 	char			 symlink_mode;
 	struct filesystem	*current_filesystem;
 	struct filesystem	*filesystem_table;
+	int			 initial_filesystem_id;
 	int			 current_filesystem_id;
 	int			 max_filesystem_id;
 	int			 allocated_filesytem;
@@ -240,6 +260,7 @@ struct tree {
 #define	onWorkingDir	64 /* We are on the working dir where we are
 			    * reading directory entry at this time. */
 #define	needsRestoreTimes 128
+#define	onInitialDir	256 /* We are on the initial dir. */
 
 static int
 tree_dir_next_posix(struct tree *t);
@@ -342,6 +363,8 @@ static const char *trivial_lookup_uname(void *, int64_t uid);
 static int	setup_sparse(struct archive_read_disk *, struct archive_entry *);
 static int	close_and_restore_time(int fd, struct tree *,
 		    struct restore_time *);
+static int	open_on_current_dir(struct tree *, const char *, int);
+static int	tree_dup(int);
 
 
 static struct archive_vtable *
@@ -430,16 +453,19 @@ archive_read_disk_new(void)
 {
 	struct archive_read_disk *a;
 
-	a = (struct archive_read_disk *)malloc(sizeof(*a));
+	a = (struct archive_read_disk *)calloc(1, sizeof(*a));
 	if (a == NULL)
 		return (NULL);
-	memset(a, 0, sizeof(*a));
 	a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
 	a->archive.state = ARCHIVE_STATE_NEW;
 	a->archive.vtable = archive_read_disk_vtable();
 	a->lookup_uname = trivial_lookup_uname;
 	a->lookup_gname = trivial_lookup_gname;
-	a->entry_wd_fd = -1;
+	a->enable_copyfile = 1;
+	a->traverse_mount_points = 1;
+	a->open_on_current_dir = open_on_current_dir;
+	a->tree_current_dir_fd = tree_current_dir_fd;
+	a->tree_enter_working_dir = tree_enter_working_dir;
 	return (&a->archive);
 }
 
@@ -555,6 +581,37 @@ archive_read_disk_set_atime_restored(struct archive *_a)
 #endif
 }
 
+int
+archive_read_disk_set_behavior(struct archive *_a, int flags)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	int r = ARCHIVE_OK;
+
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
+
+	if (flags & ARCHIVE_READDISK_RESTORE_ATIME)
+		r = archive_read_disk_set_atime_restored(_a);
+	else {
+		a->restore_time = 0;
+		if (a->tree != NULL)
+			a->tree->flags &= ~needsRestoreTimes;
+	}
+	if (flags & ARCHIVE_READDISK_HONOR_NODUMP)
+		a->honor_nodump = 1;
+	else
+		a->honor_nodump = 0;
+	if (flags & ARCHIVE_READDISK_MAC_COPYFILE)
+		a->enable_copyfile = 1;
+	else
+		a->enable_copyfile = 0;
+	if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
+		a->traverse_mount_points = 0;
+	else
+		a->traverse_mount_points = 1;
+	return (r);
+}
+
 /*
  * Trivial implementations of gname/uname lookup functions.
  * These are normally overridden by the client, but these stub
@@ -664,7 +721,7 @@ _archive_read_data_block(struct archive *_a, const void **buff,
 	 * Open the current file.
 	 */
 	if (t->entry_fd < 0) {
-		int flags = O_RDONLY | O_BINARY;
+		int flags = O_RDONLY | O_BINARY | O_CLOEXEC;
 
 		/*
 		 * Eliminate or reduce cache effects if we can.
@@ -685,13 +742,9 @@ _archive_read_data_block(struct archive *_a, const void **buff,
 			flags |= O_NOATIME;
 		do {
 #endif
-#ifdef HAVE_OPENAT
-			t->entry_fd = openat(tree_current_dir_fd(t),
+			t->entry_fd = open_on_current_dir(t,
 			    tree_current_access_path(t), flags);
-#else
-			tree_enter_working_dir(t);
-			t->entry_fd = open(tree_current_access_path(t), flags);
-#endif
+			__archive_ensure_cloexec_flag(t->entry_fd);
 #if defined(O_NOATIME)
 			/*
 			 * When we did open the file with O_NOATIME flag,
@@ -733,7 +786,7 @@ _archive_read_data_block(struct archive *_a, const void **buff,
 	t->entry_buff_size = t->current_filesystem->buff_size;
 
 	buffbytes = t->entry_buff_size;
-	if (buffbytes > t->current_sparse->length)
+	if ((int64_t)buffbytes > t->current_sparse->length)
 		buffbytes = t->current_sparse->length;
 
 	/*
@@ -802,29 +855,17 @@ abort_read_data:
 }
 
 static int
-_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
+next_entry(struct archive_read_disk *a, struct tree *t,
+    struct archive_entry *entry)
 {
-	struct archive_read_disk *a = (struct archive_read_disk *)_a;
-	struct tree *t;
 	const struct stat *st; /* info to use for this entry */
 	const struct stat *lst;/* lstat() information */
-	int descend, fd = -1, r;
-
-	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
-	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
-	    "archive_read_next_header2");
+	const char *name;
+	int descend, r;
 
-	t = a->tree;
-	if (t->entry_fd >= 0) {
-		close_and_restore_time(t->entry_fd, t, &t->restore_time);
-		t->entry_fd = -1;
-	}
-#if !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR))
-	/* Restore working directory. */
-	tree_enter_working_dir(t);
-#endif
 	st = NULL;
 	lst = NULL;
+	t->descend = 0;
 	do {
 		switch (tree_next(t)) {
 		case TREE_ERROR_FATAL:
@@ -859,6 +900,38 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 		}	
 	} while (lst == NULL);
 
+#ifdef __APPLE__
+	if (a->enable_copyfile) {
+		/* If we're using copyfile(), ignore "._XXX" files. */
+		const char *bname = strrchr(tree_current_path(t), '/');
+		if (bname == NULL)
+			bname = tree_current_path(t);
+		else
+			++bname;
+		if (bname[0] == '.' && bname[1] == '_')
+			return (ARCHIVE_RETRY);
+	}
+#endif
+
+	archive_entry_copy_pathname(entry, tree_current_path(t));
+	/*
+	 * Perform path matching.
+	 */
+	if (a->matching) {
+		r = archive_match_path_excluded(a->matching, entry);
+		if (r < 0) {
+			archive_set_error(&(a->archive), errno,
+			    "Faild : %s", archive_error_string(a->matching));
+			return (r);
+		}
+		if (r) {
+			if (a->excluded_cb_func)
+				a->excluded_cb_func(&(a->archive),
+				    a->excluded_cb_data, entry);
+			return (ARCHIVE_RETRY);
+		}
+	}
+
 	/*
 	 * Distinguish 'L'/'P'/'H' symlink following.
 	 */
@@ -897,13 +970,46 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 		tree_enter_initial_dir(t);
 		return (ARCHIVE_FATAL);
 	}
+	if (t->initial_filesystem_id == -1)
+		t->initial_filesystem_id = t->current_filesystem_id;
+	if (!a->traverse_mount_points) {
+		if (t->initial_filesystem_id != t->current_filesystem_id)
+			return (ARCHIVE_RETRY);
+	}
 	t->descend = descend;
 
-	archive_entry_set_pathname(entry, tree_current_path(t));
-	archive_entry_copy_sourcepath(entry, tree_current_access_path(t));
+	/*
+	 * Honor nodump flag.
+	 * If the file is marked with nodump flag, do not return this entry.
+	 */
+	if (a->honor_nodump) {
+#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
+		if (st->st_flags & UF_NODUMP)
+			return (ARCHIVE_RETRY);
+#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) &&\
+      defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+		if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) {
+			int stflags;
+
+			t->entry_fd = open_on_current_dir(t,
+			    tree_current_access_path(t),
+			    O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+			__archive_ensure_cloexec_flag(t->entry_fd);
+			if (t->entry_fd >= 0) {
+				r = ioctl(t->entry_fd, EXT2_IOC_GETFLAGS,
+					&stflags);
+				if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0)
+					return (ARCHIVE_RETRY);
+			}
+		}
+#endif
+	}
+
 	archive_entry_copy_stat(entry, st);
 
-	/* Save the times to be restored. */
+	/* Save the times to be restored. This must be in before
+	 * calling archive_read_disk_descend() or any chance of it,
+	 * especially, invokng a callback. */
 	t->restore_time.mtime = archive_entry_mtime(entry);
 	t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry);
 	t->restore_time.atime = archive_entry_atime(entry);
@@ -911,39 +1017,102 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 	t->restore_time.filetype = archive_entry_filetype(entry);
 	t->restore_time.noatime = t->current_filesystem->noatime;
 
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
 	/*
-	 * Open the current file to freely gather its metadata anywhere in
-	 * working directory.
-	 * Note: A symbolic link file cannot be opened with O_NOFOLLOW.
+	 * Perform time matching.
 	 */
-	if (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)
-		fd = openat(tree_current_dir_fd(t), tree_current_access_path(t),
-		    O_RDONLY | O_NONBLOCK);
-	/* Restore working directory if openat() operation failed or
-	 * the file is a symbolic link. */
-	if (fd < 0)
-		tree_enter_working_dir(t);
+	if (a->matching) {
+		r = archive_match_time_excluded(a->matching, entry);
+		if (r < 0) {
+			archive_set_error(&(a->archive), errno,
+			    "Faild : %s", archive_error_string(a->matching));
+			return (r);
+		}
+		if (r) {
+			if (a->excluded_cb_func)
+				a->excluded_cb_func(&(a->archive),
+				    a->excluded_cb_data, entry);
+			return (ARCHIVE_RETRY);
+		}
+	}
 
-	/* The current direcotry fd is needed at
-	 * archive_read_disk_entry_from_file() function to read link data
-	 * with readlinkat(). */
-	a->entry_wd_fd = tree_current_dir_fd(t);
-#endif
+	/* Lookup uname/gname */
+	name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry));
+	if (name != NULL)
+		archive_entry_copy_uname(entry, name);
+	name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry));
+	if (name != NULL)
+		archive_entry_copy_gname(entry, name);
+
+	/*
+	 * Perform owner matching.
+	 */
+	if (a->matching) {
+		r = archive_match_owner_excluded(a->matching, entry);
+		if (r < 0) {
+			archive_set_error(&(a->archive), errno,
+			    "Faild : %s", archive_error_string(a->matching));
+			return (r);
+		}
+		if (r) {
+			if (a->excluded_cb_func)
+				a->excluded_cb_func(&(a->archive),
+				    a->excluded_cb_data, entry);
+			return (ARCHIVE_RETRY);
+		}
+	}
+
+	/*
+	 * Invoke a meta data filter callback.
+	 */
+	if (a->metadata_filter_func) {
+		if (!a->metadata_filter_func(&(a->archive),
+		    a->metadata_filter_data, entry))
+			return (ARCHIVE_RETRY);
+	}
 
 	/*
 	 * Populate the archive_entry with metadata from the disk.
 	 */
-	r = archive_read_disk_entry_from_file(&(a->archive), entry, fd, st);
+	archive_entry_copy_sourcepath(entry, tree_current_access_path(t));
+	r = archive_read_disk_entry_from_file(&(a->archive), entry,
+		t->entry_fd, st);
 
-	/* Close the file descriptor used for reding the current file
-	 * metadata at archive_read_disk_entry_from_file(). */
-	if (fd >= 0)
-		close(fd);
+	return (r);
+}
+
+static int
+_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	struct tree *t;
+	int r;
+
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+	    "archive_read_next_header2");
+
+	t = a->tree;
+	if (t->entry_fd >= 0) {
+		close_and_restore_time(t->entry_fd, t, &t->restore_time);
+		t->entry_fd = -1;
+	}
+
+	for (;;) {
+		r = next_entry(a, t, entry);
+		if (t->entry_fd >= 0) {
+			close(t->entry_fd);
+			t->entry_fd = -1;
+		}
+
+		if (r == ARCHIVE_RETRY) {
+			archive_entry_clear(entry);
+			continue;
+		}
+		break;
+	}
 
 	/* Return to the initial directory. */
 	tree_enter_initial_dir(t);
-	archive_entry_copy_sourcepath(entry, tree_current_path(t));
 
 	/*
 	 * EOF and FATAL are persistent at this layer.  By
@@ -956,6 +1125,8 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 		break;
 	case ARCHIVE_OK:
 	case ARCHIVE_WARN:
+		/* Overwrite the sourcepath based on the initial directory. */
+		archive_entry_copy_sourcepath(entry, tree_current_path(t));
 		t->entry_total = 0;
 		if (archive_entry_filetype(entry) == AE_IFREG) {
 			t->nlink = archive_entry_nlink(entry);
@@ -1018,6 +1189,48 @@ setup_sparse(struct archive_read_disk *a, struct archive_entry *entry)
 	return (ARCHIVE_OK);
 }
 
+int
+archive_read_disk_set_matching(struct archive *_a, struct archive *_ma,
+    void (*_excluded_func)(struct archive *, void *, struct archive_entry *),
+    void *_client_data)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_ANY, "archive_read_disk_set_matching");
+	a->matching = _ma;
+	a->excluded_cb_func = _excluded_func;
+	a->excluded_cb_data = _client_data;
+	return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_metadata_filter_callback(struct archive *_a,
+    int (*_metadata_filter_func)(struct archive *, void *,
+    struct archive_entry *), void *_client_data)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY,
+	    "archive_read_disk_set_metadata_filter_callback");
+
+	a->metadata_filter_func = _metadata_filter_func;
+	a->metadata_filter_data = _client_data;
+	return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_can_descend(struct archive *_a)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	struct tree *t = a->tree;
+
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+	    "archive_read_disk_can_descend");
+
+	return (t->visit_type == TREE_REGULAR && t->descend);
+}
+
 /*
  * Called by the client to mark the directory just returned from
  * tree_next() as needing to be visited.
@@ -1028,14 +1241,12 @@ archive_read_disk_descend(struct archive *_a)
 	struct archive_read_disk *a = (struct archive_read_disk *)_a;
 	struct tree *t = a->tree;
 
-	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
 	    "archive_read_disk_descend");
 
-	if (t->visit_type != TREE_REGULAR || !t->descend) {
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "Ignored the request descending the current object");
-		return (ARCHIVE_WARN);
-	}
+	if (t->visit_type != TREE_REGULAR || !t->descend)
+		return (ARCHIVE_OK);
 
 	if (tree_current_is_physical_dir(t)) {
 		tree_push(t, t->basename, t->current_filesystem_id,
@@ -1079,8 +1290,12 @@ archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname)
 	archive_string_init(&path);
 	if (archive_string_append_from_wcs(&path, pathname,
 	    wcslen(pathname)) != 0) {
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "Can't convert a path to a char string");
+		if (errno == ENOMEM)
+			archive_set_error(&a->archive, ENOMEM,
+			    "Can't allocate memory");
+		else
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Can't convert a path to a char string");
 		a->archive.state = ARCHIVE_STATE_FATAL;
 		ret = ARCHIVE_FATAL;
 	} else
@@ -1151,15 +1366,17 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
 	fid = t->max_filesystem_id++;
 	if (t->max_filesystem_id > t->allocated_filesytem) {
 		size_t s;
+		void *p;
 
 		s = t->max_filesystem_id * 2;
-		t->filesystem_table = realloc(t->filesystem_table,
-		    s * sizeof(*t->filesystem_table));
-		if (t->filesystem_table == NULL) {
+		p = realloc(t->filesystem_table,
+		        s * sizeof(*t->filesystem_table));
+		if (p == NULL) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate tar data");
 			return (ARCHIVE_FATAL);
 		}
+		t->filesystem_table = (struct filesystem *)p;
 		t->allocated_filesytem = s;
 	}
 	t->current_filesystem_id = fid;
@@ -1268,13 +1485,14 @@ setup_current_filesystem(struct archive_read_disk *a)
 	t->current_filesystem->synthetic = -1;
 	t->current_filesystem->remote = -1;
 	if (tree_current_is_symblic_link_target(t)) {
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#if defined(HAVE_OPENAT)
 		/*
 		 * Get file system statistics on any directory
 		 * where current is.
 		 */
 		int fd = openat(tree_current_dir_fd(t),
-		    tree_current_access_path(t), O_RDONLY);
+		    tree_current_access_path(t), O_RDONLY | O_CLOEXEC);
+		__archive_ensure_cloexec_flag(fd);
 		if (fd < 0) {
 			archive_set_error(&a->archive, errno,
 			    "openat failed");
@@ -1285,6 +1503,10 @@ setup_current_filesystem(struct archive_read_disk *a)
 			xr = get_xfer_size(t, fd, NULL);
 		close(fd);
 #else
+		if (tree_enter_working_dir(t) != 0) {
+			archive_set_error(&a->archive, errno, "fchdir failed");
+			return (ARCHIVE_FAILED);
+		}
 		r = statfs(tree_current_access_path(t), &sfs);
 		if (r == 0)
 			xr = get_xfer_size(t, -1, tree_current_access_path(t));
@@ -1334,9 +1556,13 @@ setup_current_filesystem(struct archive_read_disk *a)
 	t->current_filesystem->name_max = sfs.f_namemax;
 #else
 	/* Mac OS X does not have f_namemax in struct statfs. */
-	if (tree_current_is_symblic_link_target(t))
+	if (tree_current_is_symblic_link_target(t)) {
+		if (tree_enter_working_dir(t) != 0) {
+			archive_set_error(&a->archive, errno, "fchdir failed");
+			return (ARCHIVE_FAILED);
+		}
 		nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);
-	else
+	} else
 		nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
 	if (nm == -1)
 		t->current_filesystem->name_max = NAME_MAX;
@@ -1360,6 +1586,10 @@ setup_current_filesystem(struct archive_read_disk *a)
 	int r, xr = 0;
 
 	t->current_filesystem->synthetic = -1;
+	if (tree_enter_working_dir(t) != 0) {
+		archive_set_error(&a->archive, errno, "fchdir failed");
+		return (ARCHIVE_FAILED);
+	}
 	if (tree_current_is_symblic_link_target(t)) {
 		r = statvfs(tree_current_access_path(t), &sfs);
 		if (r == 0)
@@ -1384,17 +1614,24 @@ setup_current_filesystem(struct archive_read_disk *a)
 		 * for pathconf() function. */
 		t->current_filesystem->xfer_align = sfs.f_frsize;
 		t->current_filesystem->max_xfer_size = -1;
+#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE)
 		t->current_filesystem->min_xfer_size = sfs.f_iosize;
 		t->current_filesystem->incr_xfer_size = sfs.f_iosize;
+#else
+		t->current_filesystem->min_xfer_size = sfs.f_bsize;
+		t->current_filesystem->incr_xfer_size = sfs.f_bsize;
+#endif
 	}
 	if (sfs.f_flag & ST_LOCAL)
 		t->current_filesystem->remote = 0;
 	else
 		t->current_filesystem->remote = 1;
 
+#if defined(ST_NOATIME)
 	if (sfs.f_flag & ST_NOATIME)
 		t->current_filesystem->noatime = 1;
 	else
+#endif
 		t->current_filesystem->noatime = 0;
 
 	/* Set maximum filename length. */
@@ -1427,13 +1664,14 @@ setup_current_filesystem(struct archive_read_disk *a)
 	int r, vr = 0, xr = 0;
 
 	if (tree_current_is_symblic_link_target(t)) {
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#if defined(HAVE_OPENAT)
 		/*
 		 * Get file system statistics on any directory
 		 * where current is.
 		 */
 		int fd = openat(tree_current_dir_fd(t),
-		    tree_current_access_path(t), O_RDONLY);
+		    tree_current_access_path(t), O_RDONLY | O_CLOEXEC);
+		__archive_ensure_cloexec_flag(fd);
 		if (fd < 0) {
 			archive_set_error(&a->archive, errno,
 			    "openat failed");
@@ -1445,6 +1683,10 @@ setup_current_filesystem(struct archive_read_disk *a)
 			xr = get_xfer_size(t, fd, NULL);
 		close(fd);
 #else
+		if (tree_enter_working_dir(t) != 0) {
+			archive_set_error(&a->archive, errno, "fchdir failed");
+			return (ARCHIVE_FAILED);
+		}
 		vr = statvfs(tree_current_access_path(t), &svfs);
 		r = statfs(tree_current_access_path(t), &sfs);
 		if (r == 0)
@@ -1456,9 +1698,11 @@ setup_current_filesystem(struct archive_read_disk *a)
 		r = fstatfs(tree_current_dir_fd(t), &sfs);
 		if (r == 0)
 			xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
-#elif defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
-#error "Unexpected case. Please tell us about this error."
 #else
+		if (tree_enter_working_dir(t) != 0) {
+			archive_set_error(&a->archive, errno, "fchdir failed");
+			return (ARCHIVE_FAILED);
+		}
 		vr = statvfs(".", &svfs);
 		r = statfs(".", &sfs);
 		if (r == 0)
@@ -1529,13 +1773,14 @@ setup_current_filesystem(struct archive_read_disk *a)
 	t->current_filesystem->synthetic = -1;/* Not supported */
 	t->current_filesystem->remote = -1;/* Not supported */
 	if (tree_current_is_symblic_link_target(t)) {
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#if defined(HAVE_OPENAT)
 		/*
 		 * Get file system statistics on any directory
 		 * where current is.
 		 */
 		int fd = openat(tree_current_dir_fd(t),
-		    tree_current_access_path(t), O_RDONLY);
+		    tree_current_access_path(t), O_RDONLY | O_CLOEXEC);
+		__archive_ensure_cloexec_flag(fd);
 		if (fd < 0) {
 			archive_set_error(&a->archive, errno,
 			    "openat failed");
@@ -1546,6 +1791,10 @@ setup_current_filesystem(struct archive_read_disk *a)
 			xr = get_xfer_size(t, fd, NULL);
 		close(fd);
 #else
+		if (tree_enter_working_dir(t) != 0) {
+			archive_set_error(&a->archive, errno, "fchdir failed");
+			return (ARCHIVE_FAILED);
+		}
 		r = statvfs(tree_current_access_path(t), &sfs);
 		if (r == 0)
 			xr = get_xfer_size(t, -1, tree_current_access_path(t));
@@ -1555,9 +1804,11 @@ setup_current_filesystem(struct archive_read_disk *a)
 		r = fstatvfs(tree_current_dir_fd(t), &sfs);
 		if (r == 0)
 			xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
-#elif defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
-#error "Unexpected case. Please tell us about this error."
 #else
+		if (tree_enter_working_dir(t) != 0) {
+			archive_set_error(&a->archive, errno, "fchdir failed");
+			return (ARCHIVE_FAILED);
+		}
 		r = statvfs(".", &sfs);
 		if (r == 0)
 			xr = get_xfer_size(t, -1, ".");
@@ -1615,9 +1866,13 @@ setup_current_filesystem(struct archive_read_disk *a)
 #if defined(HAVE_READDIR_R)
 	/* Set maximum filename length. */
 #  if defined(_PC_NAME_MAX)
-	if (tree_current_is_symblic_link_target(t))
+	if (tree_current_is_symblic_link_target(t)) {
+		if (tree_enter_working_dir(t) != 0) {
+			archive_set_error(&a->archive, errno, "fchdir failed");
+			return (ARCHIVE_FAILED);
+		}
 		nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);
-	else
+	} else
 		nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
 	if (nm == -1)
 #  endif /* _PC_NAME_MAX */
@@ -1646,7 +1901,8 @@ static int
 close_and_restore_time(int fd, struct tree *t, struct restore_time *rt)
 {
 #ifndef HAVE_UTIMES
-	(void)a; /* UNUSED */
+	(void)t; /* UNUSED */
+	(void)rt; /* UNUSED */
 	return (close(fd));
 #else
 #if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__)
@@ -1697,6 +1953,40 @@ close_and_restore_time(int fd, struct tree *t, struct restore_time *rt)
 	return (0);
 }
 
+static int
+open_on_current_dir(struct tree *t, const char *path, int flags)
+{
+#ifdef HAVE_OPENAT
+	return (openat(tree_current_dir_fd(t), path, flags));
+#else
+	if (tree_enter_working_dir(t) != 0)
+		return (-1);
+	return (open(path, flags));
+#endif
+}
+
+static int
+tree_dup(int fd)
+{
+	int new_fd;
+#ifdef F_DUPFD_CLOEXEC
+	static volatile int can_dupfd_cloexec = 1;
+
+	if (can_dupfd_cloexec) {
+		new_fd = fcntl(fd, F_DUPFD_CLOEXEC);
+		if (new_fd != -1)
+			return (new_fd);
+		/* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC,
+		 * but it cannot be used. So we have to try dup(). */
+		/* We won't try F_DUPFD_CLOEXEC. */
+		can_dupfd_cloexec = 0;
+	}
+#endif /* F_DUPFD_CLOEXEC */
+	new_fd = dup(fd);
+	__archive_ensure_cloexec_flag(new_fd);
+	return (new_fd);
+}
+
 /*
  * Add a directory path to the current stack.
  */
@@ -1778,6 +2068,7 @@ static struct tree *
 tree_reopen(struct tree *t, const char *path, int restore_time)
 {
 	t->flags = (restore_time)?needsRestoreTimes:0;
+	t->flags |= onInitialDir;
 	t->visit_type = 0;
 	t->tree_errno = 0;
 	t->dirname_length = 0;
@@ -1790,25 +2081,30 @@ tree_reopen(struct tree *t, const char *path, int restore_time)
 	t->entry_fd = -1;
 	t->entry_eof = 0;
 	t->entry_remaining_bytes = 0;
+	t->initial_filesystem_id = -1;
 
 	/* First item is set up a lot like a symlink traversal. */
 	tree_push(t, path, 0, 0, 0, NULL);
 	t->stack->flags = needsFirstVisit;
 	t->maxOpenCount = t->openCount = 1;
-	t->initial_dir_fd = open(".", O_RDONLY);
-	t->working_dir_fd = dup(t->initial_dir_fd);
+	t->initial_dir_fd = open(".", O_RDONLY | O_CLOEXEC);
+	__archive_ensure_cloexec_flag(t->initial_dir_fd);
+	t->working_dir_fd = tree_dup(t->initial_dir_fd);
 	return (t);
 }
 
 static int
 tree_descent(struct tree *t)
 {
-	int r = 0;
+	int flag, new_fd, r = 0;
 
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
-	int new_fd;
 	t->dirname_length = archive_strlen(&t->path);
-	new_fd = openat(t->working_dir_fd, t->stack->name.s, O_RDONLY);
+	flag = O_RDONLY | O_CLOEXEC;
+#if defined(O_DIRECTORY)
+	flag |= O_DIRECTORY;
+#endif
+	new_fd = open_on_current_dir(t, t->stack->name.s, flag);
+	__archive_ensure_cloexec_flag(new_fd);
 	if (new_fd < 0) {
 		t->tree_errno = errno;
 		r = TREE_ERROR_DIR;
@@ -1822,30 +2118,10 @@ tree_descent(struct tree *t)
 				t->maxOpenCount = t->openCount;
 		} else
 			close(t->working_dir_fd);
+		/* Renew the current working directory. */
 		t->working_dir_fd = new_fd;
+		t->flags &= ~onWorkingDir;
 	}
-#else
-	/* If it is a link, set up fd for the ascent. */
-	if (t->stack->flags & isDirLink)
-		t->stack->symlink_parent_fd = t->working_dir_fd;
-	else {
-		close(t->working_dir_fd);
-		t->openCount--;
-	}
-	t->working_dir_fd = -1;
-	t->dirname_length = archive_strlen(&t->path);
-	if (chdir(t->stack->name.s) != 0)
-	{
-		t->tree_errno = errno;
-		r = TREE_ERROR_DIR;
-	} else {
-		t->depth++;
-		t->working_dir_fd = open(".", O_RDONLY);
-		t->openCount++;
-		if (t->openCount > t->maxOpenCount)
-			t->maxOpenCount = t->openCount;
-	}
-#endif
 	return (r);
 }
 
@@ -1856,37 +2132,23 @@ static int
 tree_ascend(struct tree *t)
 {
 	struct tree_entry *te;
-	int r = 0, prev_dir_fd;
+	int new_fd, r = 0, prev_dir_fd;
 
 	te = t->stack;
 	prev_dir_fd = t->working_dir_fd;
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
 	if (te->flags & isDirLink)
-		t->working_dir_fd = te->symlink_parent_fd;
+		new_fd = te->symlink_parent_fd;
 	else {
-		int new_fd = openat(t->working_dir_fd, "..", O_RDONLY);
-		if (new_fd < 0) {
-			t->tree_errno = errno;
-			r = TREE_ERROR_FATAL;
-		} else
-			t->working_dir_fd = new_fd;
+		new_fd = open_on_current_dir(t, "..", O_RDONLY | O_CLOEXEC);
+		__archive_ensure_cloexec_flag(new_fd);
 	}
-#else
-	if (te->flags & isDirLink) {
-		if (fchdir(te->symlink_parent_fd) != 0) {
-			t->tree_errno = errno;
-			r = TREE_ERROR_FATAL;
-		} else
-			t->working_dir_fd = te->symlink_parent_fd;
+	if (new_fd < 0) {
+		t->tree_errno = errno;
+		r = TREE_ERROR_FATAL;
 	} else {
-		if (chdir("..") != 0) {
-			t->tree_errno = errno;
-			r = TREE_ERROR_FATAL;
-		} else
-			t->working_dir_fd = open(".", O_RDONLY);
-	}
-#endif
-	if (r == 0) {
+		/* Renew the current working directory. */
+		t->working_dir_fd = new_fd;
+		t->flags &= ~onWorkingDir;
 		/* Current directory has been changed, we should
 		 * close an fd of previous working directory. */
 		close_and_restore_time(prev_dir_fd, t, &te->restore_time);
@@ -1907,10 +2169,12 @@ tree_enter_initial_dir(struct tree *t)
 {
 	int r = 0;
 
-	if (t->flags & onWorkingDir) {
+	if ((t->flags & onInitialDir) == 0) {
 		r = fchdir(t->initial_dir_fd);
-		if (r == 0)
+		if (r == 0) {
 			t->flags &= ~onWorkingDir;
+			t->flags |= onInitialDir;
+		}
 	}
 	return (r);
 }
@@ -1930,8 +2194,10 @@ tree_enter_working_dir(struct tree *t)
 	 */
 	if (t->depth > 0 && (t->flags & onWorkingDir) == 0) {
 		r = fchdir(t->working_dir_fd);
-		if (r == 0)
+		if (r == 0) {
+			t->flags &= ~onInitialDir;
 			t->flags |= onWorkingDir;
+		}
 	}
 	return (r);
 }
@@ -2038,10 +2304,16 @@ tree_dir_next_posix(struct tree *t)
 #endif
 
 #if defined(HAVE_FDOPENDIR)
-		if ((t->d = fdopendir(dup(t->working_dir_fd))) == NULL) {
-#else
-		if ((t->d = opendir(".")) == NULL) {
+		t->d = fdopendir(tree_dup(t->working_dir_fd));
+#else /* HAVE_FDOPENDIR */
+		if (tree_enter_working_dir(t) == 0) {
+			t->d = opendir(".");
+#if HAVE_DIRFD || defined(dirfd)
+			__archive_ensure_cloexec_flag(dirfd(t->d));
 #endif
+		}
+#endif /* HAVE_FDOPENDIR */
+		if (t->d == NULL) {
 			r = tree_ascend(t); /* Undo "chdir" */
 			tree_pop(t);
 			t->tree_errno = errno;
@@ -2068,11 +2340,21 @@ tree_dir_next_posix(struct tree *t)
 #endif /* HAVE_READDIR_R */
 	}
 	for (;;) {
+		errno = 0;
 #if defined(HAVE_READDIR_R)
 		r = readdir_r(t->d, t->dirent, &t->de);
+#ifdef _AIX
+		/* Note: According to the man page, return value 9 indicates
+		 * that the readdir_r was not successful and the error code
+		 * is set to the global errno variable. And then if the end
+		 * of directory entries was reached, the return value is 9
+		 * and the third parameter is set to NULL and errno is
+		 * unchanged. */
+		if (r == 9)
+			r = errno;
+#endif /* _AIX */
 		if (r != 0 || t->de == NULL) {
 #else
-		errno = 0;
 		t->de = readdir(t->d);
 		if (t->de == NULL) {
 			r = errno;
@@ -2111,6 +2393,8 @@ tree_current_stat(struct tree *t)
 		if (fstatat(tree_current_dir_fd(t),
 		    tree_current_access_path(t), &t->st, 0) != 0)
 #else
+		if (tree_enter_working_dir(t) != 0)
+			return NULL;
 		if (stat(tree_current_access_path(t), &t->st) != 0)
 #endif
 			return NULL;
@@ -2131,6 +2415,8 @@ tree_current_lstat(struct tree *t)
 		    tree_current_access_path(t), &t->lst,
 		    AT_SYMLINK_NOFOLLOW) != 0)
 #else
+		if (tree_enter_working_dir(t) != 0)
+			return NULL;
 		if (lstat(tree_current_access_path(t), &t->lst) != 0)
 #endif
 			return NULL;
@@ -2152,11 +2438,14 @@ tree_current_is_dir(struct tree *t)
 	 */
 	if (t->flags & hasLstat) {
 		/* If lstat() says it's a dir, it must be a dir. */
-		if (S_ISDIR(tree_current_lstat(t)->st_mode))
+		st = tree_current_lstat(t);
+		if (st == NULL)
+			return 0;
+		if (S_ISDIR(st->st_mode))
 			return 1;
 		/* Not a dir; might be a link to a dir. */
 		/* If it's not a link, then it's not a link to a dir. */
-		if (!S_ISLNK(tree_current_lstat(t)->st_mode))
+		if (!S_ISLNK(st->st_mode))
 			return 0;
 		/*
 		 * It's a link, but we don't know what it's a link to,
@@ -2186,9 +2475,13 @@ tree_current_is_physical_dir(struct tree *t)
 	 * If stat() says it isn't a dir, then it's not a dir.
 	 * If stat() data is cached, this check is free, so do it first.
 	 */
-	if ((t->flags & hasStat)
-	    && (!S_ISDIR(tree_current_stat(t)->st_mode)))
-		return 0;
+	if (t->flags & hasStat) {
+		st = tree_current_stat(t);
+		if (st == NULL)
+			return (0);
+		if (!S_ISDIR(st->st_mode))
+			return (0);
+	}
 
 	/*
 	 * Either stat() said it was a dir (in which case, we have
@@ -2214,7 +2507,8 @@ tree_target_is_same_as_parent(struct tree *t, const struct stat *st)
 	struct tree_entry *te;
 
 	for (te = t->current->parent; te != NULL; te = te->parent) {
-		if (te->dev == st->st_dev && te->ino == st->st_ino)
+		if (te->dev == (int64_t)st->st_dev &&
+		    te->ino == (int64_t)st->st_ino)
 			return (1);
 	}
 	return (0);
@@ -2231,7 +2525,8 @@ tree_current_is_symblic_link_target(struct tree *t)
 
 	lst = tree_current_lstat(t);
 	st = tree_current_stat(t);
-	return (st != NULL && st->st_dev == t->current_filesystem->dev &&
+	return (st != NULL && lst != NULL &&
+	    (int64_t)st->st_dev == t->current_filesystem->dev &&
 	    st->st_dev != lst->st_dev);
 }
 
diff --git a/libarchive/archive_read_disk_private.h b/libarchive/archive_read_disk_private.h
index 4446474..e5af16b 100644
--- a/libarchive/archive_read_disk_private.h
+++ b/libarchive/archive_read_disk_private.h
@@ -34,6 +34,7 @@
 #define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
 
 struct tree;
+struct archive_entry;
 
 struct archive_read_disk {
 	struct archive	archive;
@@ -55,10 +56,18 @@ struct archive_read_disk {
 
 	/* Directory traversals. */
 	struct tree *tree;
+	int	(*open_on_current_dir)(struct tree*, const char *, int);
+	int	(*tree_current_dir_fd)(struct tree*);
+	int	(*tree_enter_working_dir)(struct tree*);
 
 	/* Set 1 if users request to restore atime . */
 	int		 restore_time;
-	int		 entry_wd_fd;
+	/* Set 1 if users request to honor nodump flag . */
+	int		 honor_nodump;
+	/* Set 1 if users request to enable mac copyfile. */
+	int		 enable_copyfile;
+	/* Set 1 if users request to traverse mount points. */
+	int		 traverse_mount_points;
 
 	const char * (*lookup_gname)(void *private, int64_t gid);
 	void	(*cleanup_gname)(void *private);
@@ -66,6 +75,18 @@ struct archive_read_disk {
 	const char * (*lookup_uname)(void *private, int64_t uid);
 	void	(*cleanup_uname)(void *private);
 	void	 *lookup_uname_data;
+
+	int	(*metadata_filter_func)(struct archive *, void *,
+			struct archive_entry *);
+	void	*metadata_filter_data;
+
+	/* ARCHIVE_MATCH object. */
+	struct archive	*matching;
+	/* Callback function, this will be invoked when ARCHIVE_MATCH
+	 * archive_match_*_excluded_ae return true. */
+	void	(*excluded_cb_func)(struct archive *, void *,
+			 struct archive_entry *);
+	void	*excluded_cb_data;
 };
 
 #endif
diff --git a/libarchive/archive_read_disk_windows.c b/libarchive/archive_read_disk_windows.c
index d8a1f55..9c5420d 100644
--- a/libarchive/archive_read_disk_windows.c
+++ b/libarchive/archive_read_disk_windows.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2003-2009 Tim Kientzle
- * Copyright (c) 2010-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,48 +29,13 @@ __FBSDID("$FreeBSD$");
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
 
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef HAVE_SYS_MOUNT_H
-#include <sys/mount.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_SYS_STATVFS_H
-#include <sys/statvfs.h>
-#endif
-#ifdef HAVE_SYS_VFS_H
-#include <sys/vfs.h>
-#endif
-#ifdef HAVE_LINUX_MAGIC_H
-#include <linux/magic.h>
-#endif
-#ifdef HAVE_DIRECT_H
-#include <direct.h>
-#endif
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if defined(HAVE_WINIOCTL_H) && !defined(__CYGWIN__)
 #include <winioctl.h>
-#endif
 
 #include "archive.h"
 #include "archive_string.h"
@@ -86,21 +51,6 @@ __FBSDID("$FreeBSD$");
 #define	IO_REPARSE_TAG_SYMLINK 0xA000000CL
 #endif
 
-static BOOL SetFilePointerEx_perso(HANDLE hFile,
-                             LARGE_INTEGER liDistanceToMove,
-                             PLARGE_INTEGER lpNewFilePointer,
-                             DWORD dwMoveMethod)
-{
-	LARGE_INTEGER li;
-	li.QuadPart = liDistanceToMove.QuadPart;
-	li.LowPart = SetFilePointer(
-	    hFile, li.LowPart, &li.HighPart, dwMoveMethod);
-	if(lpNewFilePointer) {
-		lpNewFilePointer->QuadPart = li.QuadPart;
-	}
-	return li.LowPart != -1 || GetLastError() == NO_ERROR;
-}
-
 /*-
  * This is a new directory-walking system that addresses a number
  * of problems I've had with fts(3).  In particular, it has no
@@ -120,11 +70,6 @@ static BOOL SetFilePointerEx_perso(HANDLE hFile,
  * indicating how to get back to the parent (via chdir("..") for a
  * regular dir or via fchdir(2) for a symlink).
  */
-/*
- * TODO:
- *    1) Loop checking.
- *    3) Arbitrary logical traversals by closing/reopening intermediate fds.
- */
 
 struct restore_time {
 	const wchar_t		*full_path;
@@ -153,6 +98,7 @@ struct filesystem {
 	int64_t		dev;
 	int		synthetic;
 	int		remote;
+	DWORD		bytesPerSector;
 };
 
 /* Definitions for tree_entry.flags bitmap. */
@@ -170,6 +116,11 @@ struct filesystem {
  * "first visit" is just returned to the client.
  */
 
+#define MAX_OVERLAPPED	8
+#define BUFFER_SIZE	(1024 * 8)
+#define DIRECT_IO	0/* Disabled */
+#define ASYNC_IO	1/* Enabled */
+
 /*
  * Local data for this package.
  */
@@ -177,7 +128,6 @@ struct tree {
 	struct tree_entry	*stack;
 	struct tree_entry	*current;
 	HANDLE d;
-#define	INVALID_DIR_HANDLE INVALID_HANDLE_VALUE
 	WIN32_FIND_DATAW	_findData;
 	WIN32_FIND_DATAW	*findData;
 	int			 flags;
@@ -215,6 +165,7 @@ struct tree {
 	char			 symlink_mode;
 	struct filesystem	*current_filesystem;
 	struct filesystem	*filesystem_table;
+	int			 initial_filesystem_id;
 	int			 current_filesystem_id;
 	int			 max_filesystem_id;
 	int			 allocated_filesytem;
@@ -223,8 +174,24 @@ struct tree {
 	int			 entry_eof;
 	int64_t			 entry_remaining_bytes;
 	int64_t			 entry_total;
-	unsigned char		*entry_buff;
-	size_t			 entry_buff_size;
+
+	int			 ol_idx_doing;
+	int			 ol_idx_done;
+	int			 ol_num_doing;
+	int			 ol_num_done;
+	int64_t			 ol_remaining_bytes;
+	int64_t			 ol_total;
+	struct la_overlapped {
+		OVERLAPPED	 ol;
+		struct archive * _a;
+		unsigned char	*buff;
+		size_t		 buff_size;
+		int64_t		 offset;
+		size_t		 bytes_expected;
+		size_t		 bytes_transferred;
+	}			 ol[MAX_OVERLAPPED];
+	int			 direct_io;
+	int			 async_io;
 };
 
 #define bhfi_dev(bhfi)	((bhfi)->dwVolumeSerialNumber)
@@ -242,13 +209,6 @@ struct tree {
 static int
 tree_dir_next_windows(struct tree *t, const wchar_t *pattern);
 
-#ifdef HAVE_DIRENT_D_NAMLEN
-/* BSD extension; avoids need for a strlen() call. */
-#define	D_NAMELEN(dp)	(dp)->d_namlen
-#else
-#define	D_NAMELEN(dp)	(strlen((dp)->d_name))
-#endif
-
 /* Initiate/terminate a tree traversal. */
 static struct tree *tree_open(const wchar_t *, int, int);
 static struct tree *tree_reopen(struct tree *, const wchar_t *, int);
@@ -435,7 +395,8 @@ archive_read_disk_new(void)
 	a->archive.vtable = archive_read_disk_vtable();
 	a->lookup_uname = trivial_lookup_uname;
 	a->lookup_gname = trivial_lookup_gname;
-	a->entry_wd_fd = -1;
+	a->enable_copyfile = 1;
+	a->traverse_mount_points = 1;
 	return (&a->archive);
 }
 
@@ -536,6 +497,37 @@ archive_read_disk_set_atime_restored(struct archive *_a)
 	return (ARCHIVE_OK);
 }
 
+int
+archive_read_disk_set_behavior(struct archive *_a, int flags)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	int r = ARCHIVE_OK;
+
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
+
+	if (flags & ARCHIVE_READDISK_RESTORE_ATIME)
+		r = archive_read_disk_set_atime_restored(_a);
+	else {
+		a->restore_time = 0;
+		if (a->tree != NULL)
+			a->tree->flags &= ~needsRestoreTimes;
+	}
+	if (flags & ARCHIVE_READDISK_HONOR_NODUMP)
+		a->honor_nodump = 1;
+	else
+		a->honor_nodump = 0;
+	if (flags & ARCHIVE_READDISK_MAC_COPYFILE)
+		a->enable_copyfile = 1;
+	else
+		a->enable_copyfile = 0;
+	if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
+		a->traverse_mount_points = 0;
+	else
+		a->traverse_mount_points = 1;
+	return (r);
+}
+
 /*
  * Trivial implementations of gname/uname lookup functions.
  * These are normally overridden by the client, but these stub
@@ -557,71 +549,92 @@ trivial_lookup_uname(void *private_data, int64_t uid)
 	return (NULL);
 }
 
+static int64_t
+align_num_per_sector(struct tree *t, int64_t size)
+{
+	int64_t surplus;
+
+	size += t->current_filesystem->bytesPerSector -1;
+	surplus = size % t->current_filesystem->bytesPerSector;
+	size -= surplus;
+	return (size);
+}
+
 static int
-_archive_read_data_block(struct archive *_a, const void **buff,
-    size_t *size, int64_t *offset)
+start_next_async_read(struct archive_read_disk *a, struct tree *t)
 {
-	struct archive_read_disk *a = (struct archive_read_disk *)_a;
-	struct tree *t = a->tree;
-	int r;
-	int64_t bytes;
-	size_t buffbytes;
+	struct la_overlapped *olp;
+	DWORD buffbytes, rbytes;
 
-	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
-	    "archive_read_data_block");
+	if (t->ol_remaining_bytes == 0)
+		return (ARCHIVE_EOF);
 
-	if (t->entry_eof || t->entry_remaining_bytes <= 0) {
-		r = ARCHIVE_EOF;
-		goto abort_read_data;
-	}
+	olp = &(t->ol[t->ol_idx_doing]);
+	t->ol_idx_doing = (t->ol_idx_doing + 1) % MAX_OVERLAPPED;
 
 	/* Allocate read buffer. */
-	if (t->entry_buff == NULL) {
-		t->entry_buff = malloc(1024 * 64);
-		if (t->entry_buff == NULL) {
+	if (olp->buff == NULL) {
+		void *p;
+		size_t s = (size_t)align_num_per_sector(t, BUFFER_SIZE);
+		p = VirtualAlloc(NULL, s, MEM_COMMIT, PAGE_READWRITE);
+		if (p == NULL) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Couldn't allocate memory");
-			r = ARCHIVE_FATAL;
 			a->archive.state = ARCHIVE_STATE_FATAL;
-			goto abort_read_data;
+			return (ARCHIVE_FATAL);
 		}
-		t->entry_buff_size = 1024 * 64;
-	}
+		olp->buff = p;
+		olp->buff_size = s;
+		olp->_a = &a->archive;
+		olp->ol.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+		if (olp->ol.hEvent == NULL) {
+			la_dosmaperr(GetLastError());
+			archive_set_error(&a->archive, errno,
+			    "CreateEvent failed");
+			a->archive.state = ARCHIVE_STATE_FATAL;
+			return (ARCHIVE_FATAL);
+		}
+	} else
+		ResetEvent(olp->ol.hEvent);
 
-	buffbytes = t->entry_buff_size;
+	buffbytes = (DWORD)olp->buff_size;
 	if (buffbytes > t->current_sparse->length)
-		buffbytes = t->current_sparse->length;
+		buffbytes = (DWORD)t->current_sparse->length;
 
-	/*
-	 * Skip hole.
-	 */
-	if (t->current_sparse->offset > t->entry_total) {
-		LARGE_INTEGER distance;
-		distance.QuadPart = t->current_sparse->offset;
-		if (!SetFilePointerEx_perso(t->entry_fh, distance, NULL, FILE_BEGIN)) {
-			DWORD lasterr;
-
-			lasterr = GetLastError();
-			if (lasterr == ERROR_ACCESS_DENIED)
-				errno = EBADF;
-			else
-				la_dosmaperr(lasterr);
-			archive_set_error(&a->archive, errno, "Seek error");
-			r = ARCHIVE_FATAL;
-			a->archive.state = ARCHIVE_STATE_FATAL;
-			goto abort_read_data;
-		}
-		bytes = t->current_sparse->offset - t->entry_total;
-		t->entry_remaining_bytes -= bytes;
-		t->entry_total += bytes;
+	/* Skip hole. */
+	if (t->current_sparse->offset > t->ol_total) {
+		t->ol_remaining_bytes -=
+			t->current_sparse->offset - t->ol_total;
+	}
+
+	olp->offset = t->current_sparse->offset;
+	olp->ol.Offset = (DWORD)(olp->offset & 0xffffffff);
+	olp->ol.OffsetHigh = (DWORD)(olp->offset >> 32);
+
+	if (t->ol_remaining_bytes > buffbytes) {
+		olp->bytes_expected = buffbytes;
+		t->ol_remaining_bytes -= buffbytes;
+	} else {
+		olp->bytes_expected = (size_t)t->ol_remaining_bytes;
+		t->ol_remaining_bytes = 0;
 	}
-	if (buffbytes > 0) {
-		DWORD bytes_read;
-		if (!ReadFile(t->entry_fh, t->entry_buff,
-		    (uint32_t)buffbytes, &bytes_read, NULL)) {
-			DWORD lasterr;
+	olp->bytes_transferred = 0;
+	t->current_sparse->offset += buffbytes;
+	t->current_sparse->length -= buffbytes;
+	t->ol_total = t->current_sparse->offset;
+	if (t->current_sparse->length == 0 && t->ol_remaining_bytes > 0)
+		t->current_sparse++;
 
-			lasterr = GetLastError();
+	if (!ReadFile(t->entry_fh, olp->buff, buffbytes, &rbytes, &(olp->ol))) {
+		DWORD lasterr;
+
+		lasterr = GetLastError();
+		if (lasterr == ERROR_HANDLE_EOF) {
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Reading file truncated");
+			a->archive.state = ARCHIVE_STATE_FATAL;
+			return (ARCHIVE_FATAL);
+		} else if (lasterr != ERROR_IO_PENDING) {
 			if (lasterr == ERROR_NO_DATA)
 				errno = EAGAIN;
 			else if (lasterr == ERROR_ACCESS_DENIED)
@@ -629,34 +642,96 @@ _archive_read_data_block(struct archive *_a, const void **buff,
 			else
 				la_dosmaperr(lasterr);
 			archive_set_error(&a->archive, errno, "Read error");
-			r = ARCHIVE_FATAL;
 			a->archive.state = ARCHIVE_STATE_FATAL;
-			goto abort_read_data;
+			return (ARCHIVE_FATAL);
 		}
-		bytes = bytes_read;
 	} else
-		bytes = 0;
-	if (bytes == 0) {
-		/* Get EOF */
-		t->entry_eof = 1;
+		olp->bytes_transferred = rbytes;
+	t->ol_num_doing++;
+
+	return (t->ol_remaining_bytes == 0)? ARCHIVE_EOF: ARCHIVE_OK;
+}
+
+static void
+cancel_async(struct tree *t)
+{
+	if (t->ol_num_doing != t->ol_num_done) {
+		CancelIo(t->entry_fh);
+		t->ol_num_doing = t->ol_num_done = 0;
+	}
+}
+
+static int
+_archive_read_data_block(struct archive *_a, const void **buff,
+    size_t *size, int64_t *offset)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	struct tree *t = a->tree;
+	struct la_overlapped *olp;
+	DWORD bytes_transferred;
+	int r = ARCHIVE_FATAL;
+
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
+	    "archive_read_data_block");
+
+	if (t->entry_eof || t->entry_remaining_bytes <= 0) {
 		r = ARCHIVE_EOF;
 		goto abort_read_data;
 	}
-	*buff = t->entry_buff;
-	*size = bytes;
-	*offset = t->entry_total;
-	t->entry_total += bytes;
-	t->entry_remaining_bytes -= bytes;
+
+	/*
+	 * Make a request to read the file in asynchronous.
+	 */
+	if (t->ol_num_doing == 0) {
+		do {
+			r = start_next_async_read(a, t);
+			if (r == ARCHIVE_FATAL)
+				goto abort_read_data;
+			if (!t->async_io)
+				break;
+		} while (r == ARCHIVE_OK && t->ol_num_doing < MAX_OVERLAPPED);
+	} else {
+		if (start_next_async_read(a, t) == ARCHIVE_FATAL)
+			goto abort_read_data;
+	}
+
+	olp = &(t->ol[t->ol_idx_done]);
+	t->ol_idx_done = (t->ol_idx_done + 1) % MAX_OVERLAPPED;
+	if (olp->bytes_transferred)
+		bytes_transferred = (DWORD)olp->bytes_transferred;
+	else if (!GetOverlappedResult(t->entry_fh, &(olp->ol),
+	    &bytes_transferred, TRUE)) {
+		la_dosmaperr(GetLastError());
+		archive_set_error(&a->archive, errno,
+		    "GetOverlappedResult failed");
+		a->archive.state = ARCHIVE_STATE_FATAL;
+		r = ARCHIVE_FATAL;
+		goto abort_read_data;
+	}
+	t->ol_num_done++;
+
+	if (bytes_transferred == 0 ||
+	    olp->bytes_expected != bytes_transferred) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+		    "Reading file truncated");
+		a->archive.state = ARCHIVE_STATE_FATAL;
+		r = ARCHIVE_FATAL;
+		goto abort_read_data;
+	}
+
+	*buff = olp->buff;
+	*size = bytes_transferred;
+	*offset = olp->offset;
+	if (olp->offset > t->entry_total)
+		t->entry_remaining_bytes -= olp->offset - t->entry_total;
+	t->entry_total = olp->offset + *size;
+	t->entry_remaining_bytes -= *size;
 	if (t->entry_remaining_bytes == 0) {
 		/* Close the current file descriptor */
 		close_and_restore_time(t->entry_fh, t, &t->restore_time);
 		t->entry_fh = INVALID_HANDLE_VALUE;
 		t->entry_eof = 1;
 	}
-	t->current_sparse->offset += bytes;
-	t->current_sparse->length -= bytes;
-	if (t->current_sparse->length == 0 && !t->entry_eof)
-		t->current_sparse++;
 	return (ARCHIVE_OK);
 
 abort_read_data:
@@ -664,6 +739,7 @@ abort_read_data:
 	*size = 0;
 	*offset = t->entry_total;
 	if (t->entry_fh != INVALID_HANDLE_VALUE) {
+		cancel_async(t);
 		/* Close the current file descriptor */
 		close_and_restore_time(t->entry_fh, t, &t->restore_time);
 		t->entry_fh = INVALID_HANDLE_VALUE;
@@ -672,26 +748,17 @@ abort_read_data:
 }
 
 static int
-_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
+next_entry(struct archive_read_disk *a, struct tree *t,
+    struct archive_entry *entry)
 {
-	struct archive_read_disk *a = (struct archive_read_disk *)_a;
-	struct tree *t;
 	const BY_HANDLE_FILE_INFORMATION *st;
 	const BY_HANDLE_FILE_INFORMATION *lst;
 	const char*name;
 	int descend, r;
 
-	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
-	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
-	    "archive_read_next_header2");
-
-	t = a->tree;
-	if (t->entry_fh != INVALID_HANDLE_VALUE) {
-		close_and_restore_time(t->entry_fh, t, &t->restore_time);
-		t->entry_fh = INVALID_HANDLE_VALUE;
-	}
 	st = NULL;
 	lst = NULL;
+	t->descend = 0;
 	do {
 		switch (tree_next(t)) {
 		case TREE_ERROR_FATAL:
@@ -701,7 +768,7 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 			a->archive.state = ARCHIVE_STATE_FATAL;
 			return (ARCHIVE_FATAL);
 		case TREE_ERROR_DIR:
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			archive_set_error(&a->archive, t->tree_errno,
 			    "%ls: Couldn't visit directory",
 			    tree_current_path(t));
 			return (ARCHIVE_FAILED);
@@ -713,7 +780,7 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 		case TREE_REGULAR:
 			lst = tree_current_lstat(t);
 			if (lst == NULL) {
-				archive_set_error(&a->archive, errno,
+				archive_set_error(&a->archive, t->tree_errno,
 				    "%ls: Cannot stat",
 				    tree_current_path(t));
 				return (ARCHIVE_FAILED);
@@ -722,6 +789,26 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 		}	
 	} while (lst == NULL);
 
+	archive_entry_copy_pathname_w(entry, tree_current_path(t));
+
+	/*
+	 * Perform path matching.
+	 */
+	if (a->matching) {
+		r = archive_match_path_excluded(a->matching, entry);
+		if (r < 0) {
+			archive_set_error(&(a->archive), errno,
+			    "Faild : %s", archive_error_string(a->matching));
+			return (r);
+		}
+		if (r) {
+			if (a->excluded_cb_func)
+				a->excluded_cb_func(&(a->archive),
+				    a->excluded_cb_data, entry);
+			return (ARCHIVE_RETRY);
+		}
+	}
+
 	/*
 	 * Distinguish 'L'/'P'/'H' symlink following.
 	 */
@@ -759,31 +846,90 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 		a->archive.state = ARCHIVE_STATE_FATAL;
 		return (ARCHIVE_FATAL);
 	}
+	if (t->initial_filesystem_id == -1)
+		t->initial_filesystem_id = t->current_filesystem_id;
+	if (!a->traverse_mount_points) {
+		if (t->initial_filesystem_id != t->current_filesystem_id)
+			return (ARCHIVE_RETRY);
+	}
 	t->descend = descend;
 
-	archive_entry_copy_pathname_w(entry, tree_current_path(t));
-	archive_entry_copy_sourcepath_w(entry, tree_current_access_path(t));
 	tree_archive_entry_copy_bhfi(entry, t, st);
 
-	/* Save the times to be restored. */
+	/* Save the times to be restored. This must be in before
+	 * calling archive_read_disk_descend() or any chance of it,
+	 * especially, invokng a callback. */
 	t->restore_time.lastWriteTime = st->ftLastWriteTime;
 	t->restore_time.lastAccessTime = st->ftLastAccessTime;
 	t->restore_time.filetype = archive_entry_filetype(entry);
 
+	/*
+	 * Perform time matching.
+	 */
+	if (a->matching) {
+		r = archive_match_time_excluded(a->matching, entry);
+		if (r < 0) {
+			archive_set_error(&(a->archive), errno,
+			    "Faild : %s", archive_error_string(a->matching));
+			return (r);
+		}
+		if (r) {
+			if (a->excluded_cb_func)
+				a->excluded_cb_func(&(a->archive),
+				    a->excluded_cb_data, entry);
+			return (ARCHIVE_RETRY);
+		}
+	}
+
 	/* Lookup uname/gname */
-	name = archive_read_disk_uname(_a, archive_entry_uid(entry));
+	name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry));
 	if (name != NULL)
 		archive_entry_copy_uname(entry, name);
-	name = archive_read_disk_gname(_a, archive_entry_gid(entry));
+	name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry));
 	if (name != NULL)
 		archive_entry_copy_gname(entry, name);
 
+	/*
+	 * Perform owner matching.
+	 */
+	if (a->matching) {
+		r = archive_match_owner_excluded(a->matching, entry);
+		if (r < 0) {
+			archive_set_error(&(a->archive), errno,
+			    "Faild : %s", archive_error_string(a->matching));
+			return (r);
+		}
+		if (r) {
+			if (a->excluded_cb_func)
+				a->excluded_cb_func(&(a->archive),
+				    a->excluded_cb_data, entry);
+			return (ARCHIVE_RETRY);
+		}
+	}
+
+	/*
+	 * Invoke a meta data filter callback.
+	 */
+	if (a->metadata_filter_func) {
+		if (!a->metadata_filter_func(&(a->archive),
+		    a->metadata_filter_data, entry))
+			return (ARCHIVE_RETRY);
+	}
+
+	archive_entry_copy_sourcepath_w(entry, tree_current_access_path(t));
+
 	r = ARCHIVE_OK;
 	if (archive_entry_filetype(entry) == AE_IFREG &&
 	    archive_entry_size(entry) > 0) {
+		DWORD flags = FILE_FLAG_BACKUP_SEMANTICS;
+		if (t->async_io)
+			flags |= FILE_FLAG_OVERLAPPED;
+		if (t->direct_io)
+			flags |= FILE_FLAG_NO_BUFFERING;
+		else
+			flags |= FILE_FLAG_SEQUENTIAL_SCAN;
 		t->entry_fh = CreateFileW(tree_current_access_path(t),
-		    GENERIC_READ, 0, NULL, OPEN_EXISTING,
-		    FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+		    GENERIC_READ, 0, NULL, OPEN_EXISTING, flags, NULL);
 		if (t->entry_fh == INVALID_HANDLE_VALUE) {
 			archive_set_error(&a->archive, errno,
 			    "Couldn't open %ls", tree_current_path(a->tree));
@@ -795,6 +941,29 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 		    (st->dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0)
 			r = setup_sparse_from_disk(a, entry, t->entry_fh);
 	}
+	return (r);
+}
+
+static int
+_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	struct tree *t;
+	int r;
+
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+	    "archive_read_next_header2");
+
+	t = a->tree;
+	if (t->entry_fh != INVALID_HANDLE_VALUE) {
+		cancel_async(t);
+		close_and_restore_time(t->entry_fh, t, &t->restore_time);
+		t->entry_fh = INVALID_HANDLE_VALUE;
+	}
+
+	while ((r = next_entry(a, t, entry)) == ARCHIVE_RETRY)
+		archive_entry_clear(entry);
 
 	/*
 	 * EOF and FATAL are persistent at this layer.  By
@@ -818,6 +987,10 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 			t->entry_remaining_bytes = 0;
 			t->entry_eof = 1;
 		}
+		t->ol_idx_doing = t->ol_idx_done = 0;
+		t->ol_num_doing = t->ol_num_done = 0;
+		t->ol_remaining_bytes = t->entry_remaining_bytes;
+		t->ol_total = 0;
 		a->archive.state = ARCHIVE_STATE_DATA;
 		break;
 	case ARCHIVE_RETRY:
@@ -834,7 +1007,7 @@ static int
 setup_sparse(struct archive_read_disk *a, struct archive_entry *entry)
 {
 	struct tree *t = a->tree;
-	int64_t length, offset;
+	int64_t aligned, length, offset;
 	int i;
 
 	t->sparse_count = archive_entry_sparse_reset(entry);
@@ -851,23 +1024,101 @@ setup_sparse(struct archive_read_disk *a, struct archive_entry *entry)
 			return (ARCHIVE_FATAL);
 		}
 	}
+	/*
+	 * Get sparse list and make sure those offsets and lengths are
+	 * aligned by a sector size.
+	 */
 	for (i = 0; i < t->sparse_count; i++) {
 		archive_entry_sparse_next(entry, &offset, &length);
-		t->sparse_list[i].offset = offset;
-		t->sparse_list[i].length = length;
+		aligned = align_num_per_sector(t, offset);
+		if (aligned != offset) {
+			aligned -= t->current_filesystem->bytesPerSector;
+			length += offset - aligned;
+		}
+		t->sparse_list[i].offset = aligned;
+		aligned = align_num_per_sector(t, length);
+		t->sparse_list[i].length = aligned;
 	}
+
+	aligned = align_num_per_sector(t, archive_entry_size(entry));
 	if (i == 0) {
 		t->sparse_list[i].offset = 0;
-		t->sparse_list[i].length = archive_entry_size(entry);
+		t->sparse_list[i].length = aligned;
 	} else {
-		t->sparse_list[i].offset = archive_entry_size(entry);
+		int j, last = i;
+
+		t->sparse_list[i].offset = aligned;
 		t->sparse_list[i].length = 0;
+		for (i = 0; i < last; i++) {
+			if ((t->sparse_list[i].offset +
+			       t->sparse_list[i].length) <= 
+					t->sparse_list[i+1].offset)
+				continue;
+			/*
+			 * Now sparse_list[i+1] is overlapped by sparse_list[i].
+			 * Merge those two.
+			 */
+			length = t->sparse_list[i+1].offset -
+					t->sparse_list[i].offset;
+			t->sparse_list[i+1].offset = t->sparse_list[i].offset;
+			t->sparse_list[i+1].length += length;
+			/* Remove sparse_list[i]. */
+			for (j = i; j < last; j++) {
+				t->sparse_list[j].offset =
+				    t->sparse_list[j+1].offset;
+				t->sparse_list[j].length =
+				    t->sparse_list[j+1].length;
+			}
+			last--;
+		}
 	}
 	t->current_sparse = t->sparse_list;
 
 	return (ARCHIVE_OK);
 }
 
+int
+archive_read_disk_set_matching(struct archive *_a, struct archive *_ma,
+    void (*_excluded_func)(struct archive *, void *, struct archive_entry *),
+    void *_client_data)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_ANY, "archive_read_disk_set_matching");
+	a->matching = _ma;
+	a->excluded_cb_func = _excluded_func;
+	a->excluded_cb_data = _client_data;
+	return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_metadata_filter_callback(struct archive *_a,
+    int (*_metadata_filter_func)(struct archive *, void *,
+    struct archive_entry *), void *_client_data)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY,
+	    "archive_read_disk_set_metadata_filter_callback");
+
+	a->metadata_filter_func = _metadata_filter_func;
+	a->metadata_filter_data = _client_data;
+	return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_can_descend(struct archive *_a)
+{
+	struct archive_read_disk *a = (struct archive_read_disk *)_a;
+	struct tree *t = a->tree;
+
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+	    "archive_read_disk_can_descend");
+
+	return (t->visit_type == TREE_REGULAR && t->descend);
+}
+
 /*
  * Called by the client to mark the directory just returned from
  * tree_next() as needing to be visited.
@@ -878,14 +1129,12 @@ archive_read_disk_descend(struct archive *_a)
 	struct archive_read_disk *a = (struct archive_read_disk *)_a;
 	struct tree *t = a->tree;
 
-	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
+	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
 	    "archive_read_disk_descend");
 
-	if (t->visit_type != TREE_REGULAR || !t->descend) {
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "Ignored the request descending the current object");
-		return (ARCHIVE_WARN);
-	}
+	if (t->visit_type != TREE_REGULAR || !t->descend)
+		return (ARCHIVE_OK);
 
 	if (tree_current_is_physical_dir(t)) {
 		tree_push(t, t->basename, t->full_path.s,
@@ -920,8 +1169,12 @@ archive_read_disk_open(struct archive *_a, const char *pathname)
 	archive_string_init(&wpath);
 	if (archive_wstring_append_from_mbs(&wpath, pathname,
 	    strlen(pathname)) != 0) {
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "Can't convert a path to a wchar_t string");
+		if (errno == ENOMEM)
+			archive_set_error(&a->archive, ENOMEM,
+			    "Can't allocate memory");
+		else
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Can't convert a path to a wchar_t string");
 		a->archive.state = ARCHIVE_STATE_FATAL;
 		ret = ARCHIVE_FATAL;
 	} else
@@ -955,7 +1208,7 @@ _archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname)
 		a->tree = tree_open(pathname, a->symlink_mode, a->restore_time);
 	if (a->tree == NULL) {
 		archive_set_error(&a->archive, ENOMEM,
-		    "Can't allocate direcotry traversal data");
+		    "Can't allocate directory traversal data");
 		a->archive.state = ARCHIVE_STATE_FATAL;
 		return (ARCHIVE_FATAL);
 	}
@@ -1004,16 +1257,18 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
 	fid = t->max_filesystem_id++;
 	if (t->max_filesystem_id > t->allocated_filesytem) {
 		size_t s;
+		void *p;
 
 		s = t->max_filesystem_id * 2;
-		t->filesystem_table = realloc(t->filesystem_table,
-		    s * sizeof(*t->filesystem_table));
-		if (t->filesystem_table == NULL) {
+		p = realloc(t->filesystem_table,
+			s * sizeof(*t->filesystem_table));
+		if (p == NULL) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate tar data");
 			return (ARCHIVE_FATAL);
 		}
-		t->allocated_filesytem = s;
+		t->filesystem_table = (struct filesystem *)p;
+		t->allocated_filesytem = (int)s;
 	}
 	t->current_filesystem_id = fid;
 	t->current_filesystem = &(t->filesystem_table[fid]);
@@ -1091,6 +1346,7 @@ setup_current_filesystem(struct archive_read_disk *a)
 	if (!GetVolumePathNameW(path, vol, sizeof(vol)/sizeof(vol[0]))) {
 		free(path);
 		t->current_filesystem->remote = -1;
+		t->current_filesystem->bytesPerSector = 0;
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                         "GetVolumePathName failed: %d", (int)GetLastError());
 		return (ARCHIVE_FAILED);
@@ -1109,6 +1365,14 @@ setup_current_filesystem(struct archive_read_disk *a)
 		break;
 	}
 
+	if (!GetDiskFreeSpaceW(vol, NULL,
+	    &(t->current_filesystem->bytesPerSector), NULL, NULL)) {
+		t->current_filesystem->bytesPerSector = 0;
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                        "GetDiskFreeSpace failed: %d", (int)GetLastError());
+		return (ARCHIVE_FAILED);
+	}
+
 	return (ARCHIVE_OK);
 }
 
@@ -1249,13 +1513,14 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
 	t->depth = 0;
 	t->descend = 0;
 	t->current = NULL;
-	t->d = INVALID_DIR_HANDLE;
+	t->d = INVALID_HANDLE_VALUE;
 	t->symlink_mode = t->initial_symlink_mode;
 	archive_string_empty(&(t->full_path));
 	archive_string_empty(&t->path);
 	t->entry_fh = INVALID_HANDLE_VALUE;
 	t->entry_eof = 0;
 	t->entry_remaining_bytes = 0;
+	t->initial_filesystem_id = -1;
 
 	/* Get wchar_t strings from char strings. */
 	archive_string_init(&ws);
@@ -1277,8 +1542,12 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
 
 	/* First item is set up a lot like a symlink traversal. */
 	/* printf("Looking for wildcard in %s\n", path); */
-	/* TODO: wildcard detection here screws up on \\?\c:\ UNC names */
-	if (wcschr(base, L'*') || wcschr(base, L'?')) {
+	if ((base[0] == L'/' && base[1] == L'/' &&
+	     base[2] == L'?' && base[3] == L'/' &&
+	     (wcschr(base+4, L'*') || wcschr(base+4, L'?'))) ||
+	    (!(base[0] == L'/' && base[1] == L'/' &&
+	       base[2] == L'?' && base[3] == L'/') &&
+	       (wcschr(base, L'*') || wcschr(base, L'?')))) {
 		// It has a wildcard in it...
 		// Separate the last element.
 		p = wcsrchr(base, L'/');
@@ -1298,6 +1567,32 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
 	tree_push(t, base, t->full_path.s, 0, 0, 0, NULL);
 	archive_wstring_free(&ws);
 	t->stack->flags = needsFirstVisit;
+	/*
+	 * Debug flag for Direct IO(No buffering) or Async IO.
+	 * Those dependant on environment variable switches
+	 * will be removed until next release.
+	 */
+	{
+		const char *e;
+		if ((e = getenv("LIBARCHIVE_DIRECT_IO")) != NULL) {
+			if (e[0] == '0')
+				t->direct_io = 0;
+			else
+				t->direct_io = 1;
+			fprintf(stderr, "LIBARCHIVE_DIRECT_IO=%s\n",
+				(t->direct_io)?"Enabled":"Disabled");
+		} else
+			t->direct_io = DIRECT_IO;
+		if ((e = getenv("LIBARCHIVE_ASYNC_IO")) != NULL) {
+			if (e[0] == '0')
+				t->async_io = 0;
+			else
+				t->async_io = 1;
+			fprintf(stderr, "LIBARCHIVE_ASYNC_IO=%s\n",
+			    (t->async_io)?"Enabled":"Disabled");
+		} else
+			t->async_io = ASYNC_IO;
+	}
 	return (t);
 failed:
 	archive_wstring_free(&ws);
@@ -1324,7 +1619,7 @@ tree_ascend(struct tree *t)
 
 	te = t->stack;
 	t->depth--;
-	close_and_restore_time(INVALID_DIR_HANDLE, t, &te->restore_time);
+	close_and_restore_time(INVALID_HANDLE_VALUE, t, &te->restore_time);
 	return (0);
 }
 
@@ -1364,7 +1659,7 @@ tree_next(struct tree *t)
 
 	while (t->stack != NULL) {
 		/* If there's an open dir, get the next entry from there. */
-		if (t->d != INVALID_DIR_HANDLE) {
+		if (t->d != INVALID_HANDLE_VALUE) {
 			r = tree_dir_next_windows(t, NULL);
 			if (r == 0)
 				continue;
@@ -1374,14 +1669,17 @@ tree_next(struct tree *t)
 		if (t->stack->flags & needsFirstVisit) {
 			wchar_t *d = t->stack->name.s;
 			t->stack->flags &= ~needsFirstVisit;
-			if (wcschr(d, L'*') || wcschr(d, L'?')) {
+			if (!(d[0] == L'/' && d[1] == L'/' &&
+			      d[2] == L'?' && d[3] == L'/') &&
+			    (wcschr(d, L'*') || wcschr(d, L'?'))) {
 				r = tree_dir_next_windows(t, d);
 				if (r == 0)
 					continue;
 				return (r);
 			} else {
 				HANDLE h = FindFirstFileW(d, &t->_findData);
-				if (h == INVALID_DIR_HANDLE) {
+				if (h == INVALID_HANDLE_VALUE) {
+					la_dosmaperr(GetLastError());
 					t->tree_errno = errno;
 					t->visit_type = TREE_ERROR_DIR;
 					return (t->visit_type);
@@ -1452,10 +1750,11 @@ tree_dir_next_windows(struct tree *t, const wchar_t *pattern)
 			archive_wstrcat(&pt, pattern);
 			t->d = FindFirstFileW(pt.s, &t->_findData);
 			archive_wstring_free(&pt);
-			if (t->d == INVALID_DIR_HANDLE) {
+			if (t->d == INVALID_HANDLE_VALUE) {
+				la_dosmaperr(GetLastError());
+				t->tree_errno = errno;
 				r = tree_ascend(t); /* Undo "chdir" */
 				tree_pop(t);
-				t->tree_errno = errno;
 				t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
 				return (t->visit_type);
 			}
@@ -1463,7 +1762,7 @@ tree_dir_next_windows(struct tree *t, const wchar_t *pattern)
 			pattern = NULL;
 		} else if (!FindNextFileW(t->d, &t->_findData)) {
 			FindClose(t->d);
-			t->d = INVALID_DIR_HANDLE;
+			t->d = INVALID_HANDLE_VALUE;
 			t->findData = NULL;
 			return (0);
 		}
@@ -1482,7 +1781,7 @@ tree_dir_next_windows(struct tree *t, const wchar_t *pattern)
 
 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 static void
-fileTimeToUtc(const FILETIME *filetime, time_t *time, long *ns)
+fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns)
 {
 	ULARGE_INTEGER utc;
 
@@ -1491,11 +1790,11 @@ fileTimeToUtc(const FILETIME *filetime, time_t *time, long *ns)
 	if (utc.QuadPart >= EPOC_TIME) {
 		utc.QuadPart -= EPOC_TIME;
 		/* milli seconds base */
-		*time = (time_t)(utc.QuadPart / 10000000);
+		*t = (time_t)(utc.QuadPart / 10000000);
 		/* nano seconds base */
 		*ns = (long)(utc.QuadPart % 10000000) * 100;
 	} else {
-		*time = 0;
+		*t = 0;
 		*ns = 0;
 	}
 }
@@ -1589,8 +1888,11 @@ tree_current_file_information(struct tree *t, BY_HANDLE_FILE_INFORMATION *st,
 		flag |= FILE_FLAG_OPEN_REPARSE_POINT;
 	h = CreateFileW(tree_current_access_path(t), 0, 0, NULL,
 	    OPEN_EXISTING, flag, NULL);
-	if (h == INVALID_HANDLE_VALUE)
+	if (h == INVALID_HANDLE_VALUE) {
+		la_dosmaperr(GetLastError());
+		t->tree_errno = errno;
 		return (0);
+	}
 	r = GetFileInformationByHandle(h, st);
 	CloseHandle(h);
 	return (r);
@@ -1709,13 +2011,14 @@ tree_close(struct tree *t)
 	if (t == NULL)
 		return;
 	if (t->entry_fh != INVALID_HANDLE_VALUE) {
+		cancel_async(t);
 		close_and_restore_time(t->entry_fh, t, &t->restore_time);
 		t->entry_fh = INVALID_HANDLE_VALUE;
 	}
 	/* Close the handle of FindFirstFileW */
-	if (t->d != INVALID_DIR_HANDLE) {
+	if (t->d != INVALID_HANDLE_VALUE) {
 		FindClose(t->d);
-		t->d = INVALID_DIR_HANDLE;
+		t->d = INVALID_HANDLE_VALUE;
 		t->findData = NULL;
 	}
 	/* Release anything remaining in the stack. */
@@ -1729,13 +2032,19 @@ tree_close(struct tree *t)
 static void
 tree_free(struct tree *t)
 {
+	int i;
+
 	if (t == NULL)
 		return;
 	archive_wstring_free(&t->path);
 	archive_wstring_free(&t->full_path);
 	free(t->sparse_list);
 	free(t->filesystem_table);
-	free(t->entry_buff);
+	for (i = 0; i < MAX_OVERLAPPED; i++) {
+		if (t->ol[i].buff)
+			VirtualFree(t->ol[i].buff, 0, MEM_RELEASE);
+		CloseHandle(t->ol[i].ol.hEvent);
+	}
 	free(t);
 }
 
@@ -1775,7 +2084,8 @@ archive_read_disk_entry_from_file(struct archive *_a,
 			h = (HANDLE)_get_osfhandle(fd);
 			r = GetFileInformationByHandle(h, &bhfi);
 			if (r == 0) {
-				archive_set_error(&a->archive, GetLastError(),
+				la_dosmaperr(GetLastError());
+				archive_set_error(&a->archive, errno,
 				    "Can't GetFileInformationByHandle");
 				return (ARCHIVE_FAILED);
 			}
@@ -1785,8 +2095,9 @@ archive_read_disk_entry_from_file(struct archive *_a,
 			DWORD flag, desiredAccess;
 	
 			h = FindFirstFileW(path, &findData);
-			if (h == INVALID_DIR_HANDLE) {
-				archive_set_error(&a->archive, GetLastError(),
+			if (h == INVALID_HANDLE_VALUE) {
+				la_dosmaperr(GetLastError());
+				archive_set_error(&a->archive, errno,
 				    "Can't FindFirstFileW");
 				return (ARCHIVE_FAILED);
 			}
@@ -1807,15 +2118,15 @@ archive_read_disk_entry_from_file(struct archive *_a,
 			h = CreateFileW(path, desiredAccess, 0, NULL,
 			    OPEN_EXISTING, flag, NULL);
 			if (h == INVALID_HANDLE_VALUE) {
-				archive_set_error(&a->archive,
-				    GetLastError(),
+				la_dosmaperr(GetLastError());
+				archive_set_error(&a->archive, errno,
 				    "Can't CreateFileW");
 				return (ARCHIVE_FAILED);
 			}
 			r = GetFileInformationByHandle(h, &bhfi);
 			if (r == 0) {
-				archive_set_error(&a->archive,
-				    GetLastError(),
+				la_dosmaperr(GetLastError());
+				archive_set_error(&a->archive, errno,
 				    "Can't GetFileInformationByHandle");
 				CloseHandle(h);
 				return (ARCHIVE_FAILED);
@@ -1825,7 +2136,7 @@ archive_read_disk_entry_from_file(struct archive *_a,
 		fileAttributes = bhfi.dwFileAttributes;
 	} else {
 		archive_entry_copy_stat(entry, st);
-		h = INVALID_DIR_HANDLE;
+		h = INVALID_HANDLE_VALUE;
 	}
 
 	/* Lookup uname/gname */
@@ -1854,14 +2165,16 @@ archive_read_disk_entry_from_file(struct archive *_a,
 			h = CreateFileW(path, GENERIC_READ, 0, NULL,
 			    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
 			if (h == INVALID_HANDLE_VALUE) {
-				archive_set_error(&a->archive, GetLastError(),
+				la_dosmaperr(GetLastError());
+				archive_set_error(&a->archive, errno,
 				    "Can't CreateFileW");
 				return (ARCHIVE_FAILED);
 			}
 		}
 		r = GetFileInformationByHandle(h, &bhfi);
 		if (r == 0) {
-			archive_set_error(&a->archive, GetLastError(),
+			la_dosmaperr(GetLastError());
+			archive_set_error(&a->archive, errno,
 			    "Can't GetFileInformationByHandle");
 			if (h != INVALID_HANDLE_VALUE && fd < 0)
 				CloseHandle(h);
@@ -1909,7 +2222,7 @@ setup_sparse_from_disk(struct archive_read_disk *a,
 	outranges_size = 2048;
 	outranges = (FILE_ALLOCATED_RANGE_BUFFER *)malloc(outranges_size);
 	if (outranges == NULL) {
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+		archive_set_error(&a->archive, ENOMEM,
 			"Couldn't allocate memory");
 		exit_sts = ARCHIVE_FATAL;
 		goto exit_setup_sparse;
@@ -1923,15 +2236,14 @@ setup_sparse_from_disk(struct archive_read_disk *a,
 			ret = DeviceIoControl(handle,
 			    FSCTL_QUERY_ALLOCATED_RANGES,
 			    &range, sizeof(range), outranges,
-			    outranges_size, &retbytes, NULL);
+			    (DWORD)outranges_size, &retbytes, NULL);
 			if (ret == 0 && GetLastError() == ERROR_MORE_DATA) {
 				free(outranges);
 				outranges_size *= 2;
 				outranges = (FILE_ALLOCATED_RANGE_BUFFER *)
 				    malloc(outranges_size);
 				if (outranges == NULL) {
-					archive_set_error(&a->archive,
-					    ARCHIVE_ERRNO_MISC,
+					archive_set_error(&a->archive, ENOMEM,
 					    "Couldn't allocate memory");
 					exit_sts = ARCHIVE_FATAL;
 					goto exit_setup_sparse;
@@ -1968,7 +2280,8 @@ setup_sparse_from_disk(struct archive_read_disk *a,
 			}
 			break;
 		} else {
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			la_dosmaperr(GetLastError());
+			archive_set_error(&a->archive, errno,
 			    "DeviceIoControl Failed: %lu", GetLastError());
 			exit_sts = ARCHIVE_FAILED;
 			goto exit_setup_sparse;
diff --git a/libarchive/archive_read_extract.3 b/libarchive/archive_read_extract.3
index 882c6e1..6ec0ced 100644
--- a/libarchive/archive_read_extract.3
+++ b/libarchive/archive_read_extract.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 22, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_EXTRACT 3
 .Os
 .Sh NAME
@@ -32,6 +32,8 @@
 .Nm archive_read_extract2 ,
 .Nm archive_read_extract_set_progress_callback
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_read_extract.c b/libarchive/archive_read_extract.c
index aad8ac5..795f2ab 100644
--- a/libarchive/archive_read_extract.c
+++ b/libarchive/archive_read_extract.c
@@ -154,7 +154,7 @@ copy_data(struct archive *ar, struct archive *aw)
 			return (ARCHIVE_OK);
 		if (r != ARCHIVE_OK)
 			return (r);
-		r = archive_write_data_block(aw, buff, size, offset);
+		r = (int)archive_write_data_block(aw, buff, size, offset);
 		if (r < ARCHIVE_WARN)
 			r = ARCHIVE_WARN;
 		if (r != ARCHIVE_OK) {
diff --git a/libarchive/archive_read_filter.3 b/libarchive/archive_read_filter.3
index 1cfa215..8761127 100644
--- a/libarchive/archive_read_filter.3
+++ b/libarchive/archive_read_filter.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 19, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_FILTER 3
 .Os
 .Sh NAME
@@ -39,6 +39,8 @@
 .Nm archive_read_support_filter_program_signature
 .Nd functions for reading streaming archives
 .\"
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_read_format.3 b/libarchive/archive_read_format.3
index e707e05..53b9a7e 100644
--- a/libarchive/archive_read_format.3
+++ b/libarchive/archive_read_format.3
@@ -22,9 +22,9 @@
 .\" 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 $
+.\" $FreeBSD$
 .\"
-.Dd March 19, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_FORMAT 3
 .Os
 .Sh NAME
@@ -45,6 +45,8 @@
 .Nm archive_read_support_format_zip
 .Nd functions for reading streaming archives
 .\"
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_read_free.3 b/libarchive/archive_read_free.3
index f5f2515..5b21822 100644
--- a/libarchive/archive_read_free.3
+++ b/libarchive/archive_read_free.3
@@ -22,9 +22,9 @@
 .\" 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 $
+.\" $FreeBSD$
 .\"
-.Dd March 20, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_FREE 3
 .Os
 .Sh NAME
@@ -32,6 +32,8 @@
 .Nm archive_read_finish ,
 .Nm archive_read_free
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_read_header.3 b/libarchive/archive_read_header.3
index 999e963..480a666 100644
--- a/libarchive/archive_read_header.3
+++ b/libarchive/archive_read_header.3
@@ -24,13 +24,15 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 22, 2011
+.Dd February 2, 2012
 .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 LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_read_new.3 b/libarchive/archive_read_new.3
index e04406a..0c9d1a7 100644
--- a/libarchive/archive_read_new.3
+++ b/libarchive/archive_read_new.3
@@ -22,14 +22,16 @@
 .\" 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 $
+.\" $FreeBSD$
 .\"
-.Dd March 20, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_NEW 3
 .Os
 .Sh NAME
 .Nm archive_read_new
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft struct archive *
diff --git a/libarchive/archive_read_open.3 b/libarchive/archive_read_open.3
index 09c0575..30a740b 100644
--- a/libarchive/archive_read_open.3
+++ b/libarchive/archive_read_open.3
@@ -22,9 +22,9 @@
 .\" 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 $
+.\" $FreeBSD$
 .\"
-.Dd March 19, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_OPEN 3
 .Os
 .Sh NAME
@@ -35,6 +35,8 @@
 .Nm archive_read_open_filename ,
 .Nm archive_read_open_memory ,
 .Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_read_open_fd.c b/libarchive/archive_read_open_fd.c
index d8f6572..e0f95bf 100644
--- a/libarchive/archive_read_open_fd.c
+++ b/libarchive/archive_read_open_fd.c
@@ -119,7 +119,8 @@ file_read(struct archive *a, void *client_data, const void **buff)
 		if (bytes_read < 0) {
 			if (errno == EINTR)
 				continue;
-			archive_set_error(a, errno, "Error reading fd %d", mine->fd);
+			archive_set_error(a, errno, "Error reading fd %d",
+			    mine->fd);
 		}
 		return (bytes_read);
 	}
@@ -129,8 +130,8 @@ 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;
+	int64_t skip = request;
+	int64_t old_offset, new_offset;
 	int skip_bits = sizeof(skip) * 8 - 1;  /* off_t is a signed type. */
 
 	if (!mine->use_lseek)
diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c
index b1aac0a..3a33c25 100644
--- a/libarchive/archive_read_open_file.c
+++ b/libarchive/archive_read_open_file.c
@@ -108,11 +108,11 @@ 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;
+	size_t bytes_read;
 
 	*buff = mine->buffer;
 	bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f);
-	if (bytes_read < 0) {
+	if (bytes_read < mine->block_size && ferror(mine->f)) {
 		archive_set_error(a, errno, "Error reading file");
 	}
 	return (bytes_read);
diff --git a/libarchive/archive_read_open_filename.c b/libarchive/archive_read_open_filename.c
index bf52697..fefcd90 100644
--- a/libarchive/archive_read_open_filename.c
+++ b/libarchive/archive_read_open_filename.c
@@ -60,11 +60,15 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_filename.c 201093 2009
 #endif
 
 #include "archive.h"
+#include "archive_private.h"
 #include "archive_string.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
 
 struct read_file_data {
 	int	 fd;
@@ -79,9 +83,10 @@ struct read_file_data {
 	} filename; /* Must be last! */
 };
 
+static int	file_open(struct archive *, void *);
 static int	file_close(struct archive *, void *);
-static int	file_open_filename(struct archive *, enum fnt_e, const void *,
-		    size_t);
+static int file_close2(struct archive *, void *);
+static int file_switch(struct archive *, void *, void *);
 static ssize_t	file_read(struct archive *, void *, const void **buff);
 static int64_t	file_seek(struct archive *, void *, int64_t request, int);
 static int64_t	file_skip(struct archive *, void *, int64_t request);
@@ -98,26 +103,76 @@ int
 archive_read_open_filename(struct archive *a, const char *filename,
     size_t block_size)
 {
-	enum fnt_e filename_type;
+	const char *filenames[2] = { filename, NULL };
+	return archive_read_open_filenames(a, filenames, block_size);
+}
+
+int
+archive_read_open_filenames(struct archive *a, const char **filenames,
+    size_t block_size)
+{
+	struct read_file_data *mine;
+	const char *filename = NULL;
+	if (filenames)
+		filename = *(filenames++);
+
+	archive_clear_error(a);
+	do
+	{
+		if (filename == NULL)
+			filename = "";
+		mine = (struct read_file_data *)calloc(1,
+			sizeof(*mine) + strlen(filename));
+		if (mine == NULL)
+			goto no_memory;
+		strcpy(mine->filename.m, filename);
+		mine->block_size = block_size;
+		mine->fd = -1;
+		mine->buffer = NULL;
+		mine->st_mode = mine->use_lseek = 0;
+		if (filename == NULL || filename[0] == '\0') {
+			mine->filename_type = FNT_STDIN;
+		} else
+			mine->filename_type = FNT_MBS;
+		if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK))
+			return (ARCHIVE_FATAL);
+		if (filenames == NULL)
+			break;
+		filename = *(filenames++);
+	} while (filename != NULL && filename[0] != '\0');
+	archive_read_set_open_callback(a, file_open);
+	archive_read_set_read_callback(a, file_read);
+	archive_read_set_skip_callback(a, file_skip);
+	archive_read_set_close_callback(a, file_close);
+	archive_read_set_switch_callback(a, file_switch);
+	archive_read_set_seek_callback(a, file_seek);
 
-	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));
+	return (archive_read_open1(a));
+no_memory:
+	archive_set_error(a, ENOMEM, "No memory");
+	return (ARCHIVE_FATAL);
 }
 
 int
 archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
     size_t block_size)
 {
-	enum fnt_e filename_type;
+	struct read_file_data *mine = (struct read_file_data *)calloc(1,
+		sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t));
+	if (!mine)
+	{
+		archive_set_error(a, ENOMEM, "No memory");
+		return (ARCHIVE_FATAL);
+	}
+	mine->fd = -1;
+	mine->block_size = block_size;
 
 	if (wfilename == NULL || wfilename[0] == L'\0') {
-		filename_type = FNT_STDIN;
+		mine->filename_type = FNT_STDIN;
 	} else {
 #if defined(_WIN32) && !defined(__CYGWIN__)
-		filename_type = FNT_WCS;
+		mine->filename_type = FNT_WCS;
+		wcscpy(mine->filename.w, wfilename);
 #else
 		/*
 		 * POSIX system does not support a wchar_t interface for
@@ -125,31 +180,43 @@ archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
 		 * 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");
+			if (errno == ENOMEM)
+				archive_set_error(a, errno,
+				    "Can't allocate memory");
+			else
+				archive_set_error(a, EINVAL,
+				    "Failed to convert a wide-character"
+				    " filename to a multi-byte filename");
 			archive_string_free(&fn);
+			free(mine);
 			return (ARCHIVE_FATAL);
 		}
-		r = file_open_filename(a, FNT_MBS, fn.s, block_size);
+		mine->filename_type = FNT_MBS;
+		strcpy(mine->filename.m, fn.s);
 		archive_string_free(&fn);
-		return (r);
 #endif
 	}
-	return (file_open_filename(a, filename_type, wfilename, block_size));
+	if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK))
+		return (ARCHIVE_FATAL);
+	archive_read_set_open_callback(a, file_open);
+	archive_read_set_read_callback(a, file_read);
+	archive_read_set_skip_callback(a, file_skip);
+	archive_read_set_close_callback(a, file_close);
+	archive_read_set_switch_callback(a, file_switch);
+	archive_read_set_seek_callback(a, file_seek);
+
+	return (archive_read_open1(a));
 }
 
 static int
-file_open_filename(struct archive *a, enum fnt_e filename_type,
-    const void *_filename, size_t block_size)
+file_open(struct archive *a, void *client_data)
 {
 	struct stat st;
-	struct read_file_data *mine;
+	struct read_file_data *mine = (struct read_file_data *)client_data;
 	void *buffer;
 	const char *filename = NULL;
 	const wchar_t *wfilename = NULL;
@@ -164,7 +231,7 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 #endif
 
 	archive_clear_error(a);
-	if (filename_type == FNT_STDIN) {
+	if (mine->filename_type == FNT_STDIN) {
 		/* We used to delegate stdin support by
 		 * directly calling archive_read_open_fd(a,0,block_size)
 		 * here, but that doesn't (and shouldn't) handle the
@@ -179,9 +246,10 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 		setmode(0, O_BINARY);
 #endif
 		filename = "";
-	} else if (filename_type == FNT_MBS) {
-		filename = (const char *)_filename;
-		fd = open(filename, O_RDONLY | O_BINARY);
+	} else if (mine->filename_type == FNT_MBS) {
+		filename = mine->filename.m;
+		fd = open(filename, O_RDONLY | O_BINARY | O_CLOEXEC);
+		__archive_ensure_cloexec_flag(fd);
 		if (fd < 0) {
 			archive_set_error(a, errno,
 			    "Failed to open '%s'", filename);
@@ -189,7 +257,7 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 		}
 	} else {
 #if defined(_WIN32) && !defined(__CYGWIN__)
-		wfilename = (const wchar_t *)_filename;
+		wfilename = mine->filename.w;
 		fd = _wopen(wfilename, O_RDONLY | O_BINARY);
 		if (fd < 0 && errno == ENOENT) {
 			wchar_t *fullpath;
@@ -211,7 +279,7 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 #endif
 	}
 	if (fstat(fd, &st) != 0) {
-		if (filename_type == FNT_WCS)
+		if (mine->filename_type == FNT_WCS)
 			archive_set_error(a, errno, "Can't stat '%S'",
 			    wfilename);
 		else
@@ -276,50 +344,32 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 #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
+		while (new_block_size < mine->block_size
 		    && new_block_size < 64 * 1024 * 1024)
 			new_block_size *= 2;
-		block_size = new_block_size;
+		mine->block_size = new_block_size;
 	}
-	buffer = malloc(block_size);
+	buffer = malloc(mine->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);
+	if (is_disk_like)
 		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));
+	return (ARCHIVE_OK);
 }
 
 static ssize_t
@@ -397,9 +447,7 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request)
 	/* 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.
+	 * tries to obtain a 64-bit off_t.
 	 */
 	if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 &&
 	    (new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0)
@@ -450,7 +498,7 @@ 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;
+	int64_t r;
 
 	/* We use off_t here because lseek() is declared that way. */
 	/* See above for notes about when off_t is less than 64 bits. */
@@ -471,7 +519,7 @@ file_seek(struct archive *a, void *client_data, int64_t request, int whence)
 }
 
 static int
-file_close(struct archive *a, void *client_data)
+file_close2(struct archive *a, void *client_data)
 {
 	struct read_file_data *mine = (struct read_file_data *)client_data;
 
@@ -504,6 +552,23 @@ file_close(struct archive *a, void *client_data)
 			close(mine->fd);
 	}
 	free(mine->buffer);
+	mine->buffer = NULL;
+	mine->fd = -1;
+	return (ARCHIVE_OK);
+}
+
+static int
+file_close(struct archive *a, void *client_data)
+{
+	struct read_file_data *mine = (struct read_file_data *)client_data;
+	file_close2(a, client_data);
 	free(mine);
 	return (ARCHIVE_OK);
 }
+
+static int
+file_switch(struct archive *a, void *client_data1, void *client_data2)
+{
+	file_close2(a, client_data1);
+	return file_open(a, client_data2);
+}
diff --git a/libarchive/archive_read_open_memory.c b/libarchive/archive_read_open_memory.c
index 07940a2..bcc7d6f 100644
--- a/libarchive/archive_read_open_memory.c
+++ b/libarchive/archive_read_open_memory.c
@@ -149,6 +149,7 @@ memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whenc
 {
 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
 
+	(void)a; /* UNUSED */
 	switch (whence) {
 	case SEEK_SET:
 		mine->p = mine->start + offset;
diff --git a/libarchive/archive_read_private.h b/libarchive/archive_read_private.h
index 76d0b91..8a6c859 100644
--- a/libarchive/archive_read_private.h
+++ b/libarchive/archive_read_private.h
@@ -58,6 +58,8 @@ struct archive_read_filter;
 struct archive_read_filter_bidder {
 	/* Configuration data for the bidder. */
 	void *data;
+	/* Name of the filter */
+	const char *name;
 	/* Taste the upstream filter to see if we handle this. */
 	int (*bid)(struct archive_read_filter_bidder *,
 	    struct archive_read_filter *);
@@ -82,6 +84,8 @@ struct archive_read_filter {
 	struct archive_read_filter_bidder *bidder; /* My bidder. */
 	struct archive_read_filter *upstream; /* Who I read from. */
 	struct archive_read *archive; /* Associated archive. */
+	/* Open a block for reading */
+	int (*open)(struct archive_read_filter *self);
 	/* Return next block. */
 	ssize_t (*read)(struct archive_read_filter *, const void **);
 	/* Skip forward this many bytes. */
@@ -90,6 +94,8 @@ struct archive_read_filter {
 	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);
+	/* Function that handles switching from reading one block to the next/prev */
+	int (*sswitch)(struct archive_read_filter *self, unsigned int iindex);
 	/* My private data. */
 	void *data;
 
@@ -118,13 +124,22 @@ struct archive_read_filter {
  * transformation filters.  This will probably break the API/ABI and
  * so should be deferred at least until libarchive 3.0.
  */
+struct archive_read_data_node {
+	int64_t begin_position;
+	int64_t total_size;
+	void *data;
+};
 struct archive_read_client {
 	archive_open_callback	*opener;
 	archive_read_callback	*reader;
 	archive_skip_callback	*skipper;
 	archive_seek_callback	*seeker;
 	archive_close_callback	*closer;
-	void *data;
+	archive_switch_callback *switcher;
+	unsigned int nodes;
+	unsigned int cursor;
+	int64_t position;
+	struct archive_read_data_node *dataset;
 };
 
 struct archive_read {
@@ -134,8 +149,8 @@ struct archive_read {
 
 	/* Dev/ino of the archive being read/written. */
 	int		  skip_file_set;
-	dev_t		  skip_file_dev;
-	ino_t		  skip_file_ino;
+	int64_t		  skip_file_dev;
+	int64_t		  skip_file_ino;
 
 	/*
 	 * Used by archive_read_data() to track blocks and copy
@@ -146,18 +161,33 @@ struct archive_read {
 	int64_t		  read_data_output_offset;
 	size_t		  read_data_remaining;
 
-	/* Callbacks to open/read/write/close client archive stream. */
+	/*
+	 * Used by formats/filters to determine the amount of data
+	 * requested from a call to archive_read_data(). This is only
+	 * useful when the format/filter has seek support.
+	 */
+	char		  read_data_is_posix_read;
+	size_t		  read_data_requested;
+
+	/* Callbacks to open/read/write/close client archive streams. */
 	struct archive_read_client client;
 
 	/* Registered filter bidders. */
-	struct archive_read_filter_bidder bidders[9];
+	struct archive_read_filter_bidder bidders[14];
 
 	/* Last filter in chain */
 	struct archive_read_filter *filter;
 
+	/* Whether to bypass filter bidding process */
+	int bypass_filter_bidding;
+
 	/* File offset of beginning of most recently-read header. */
 	int64_t		  header_position;
 
+	/* Nodes and offsets of compressed data block */
+	unsigned int data_start_node;
+	unsigned int data_end_node;
+
 	/*
 	 * Format detection is mostly the same as compression
 	 * detection, with one significant difference: The bidders
@@ -175,6 +205,7 @@ struct archive_read {
 		int	(*read_header)(struct archive_read *, struct archive_entry *);
 		int	(*read_data)(struct archive_read *, const void **, size_t *, int64_t *);
 		int	(*read_data_skip)(struct archive_read *);
+		int64_t	(*seek_data)(struct archive_read *, int64_t, int);
 		int	(*cleanup)(struct archive_read *);
 	}	formats[16];
 	struct archive_format_descriptor	*format; /* Active format. */
@@ -194,6 +225,7 @@ int	__archive_read_register_format(struct archive_read *a,
 	    int (*read_header)(struct archive_read *, struct archive_entry *),
 	    int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
 	    int (*read_data_skip)(struct archive_read *),
+	    int64_t (*seek_data)(struct archive_read *, int64_t, int),
 	    int (*cleanup)(struct archive_read *));
 
 int __archive_read_get_bidder(struct archive_read *a,
@@ -207,4 +239,6 @@ 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 *);
+void __archive_read_free_filters(struct archive_read *);
+int  __archive_read_close_filters(struct archive_read *);
 #endif
diff --git a/libarchive/archive_read_set_format.c b/libarchive/archive_read_set_format.c
new file mode 100644
index 0000000..190f436
--- /dev/null
+++ b/libarchive/archive_read_set_format.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2003-2012 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+int
+archive_read_set_format(struct archive *_a, int code)
+{
+  int r1, r2, slots, i;
+  char str[10];
+  struct archive_read *a = (struct archive_read *)_a;
+
+  if ((r1 = archive_read_support_format_by_code(_a, code)) < (ARCHIVE_OK))
+    return r1;
+
+  r1 = r2 = (ARCHIVE_OK);
+  if (a->format)
+    r2 = (ARCHIVE_WARN);
+  switch (code & ARCHIVE_FORMAT_BASE_MASK)
+  {
+    case ARCHIVE_FORMAT_7ZIP:
+      strcpy(str, "7zip");
+      break;
+    case ARCHIVE_FORMAT_AR:
+      strcpy(str, "ar");
+      break;
+    case ARCHIVE_FORMAT_CAB:
+      strcpy(str, "cab");
+      break;
+    case ARCHIVE_FORMAT_CPIO:
+      strcpy(str, "cpio");
+      break;
+    case ARCHIVE_FORMAT_ISO9660:
+      strcpy(str, "iso9660");
+      break;
+    case ARCHIVE_FORMAT_LHA:
+      strcpy(str, "lha");
+      break;
+    case ARCHIVE_FORMAT_MTREE:
+      strcpy(str, "mtree");
+      break;
+    case ARCHIVE_FORMAT_RAR:
+      strcpy(str, "rar");
+      break;
+    case ARCHIVE_FORMAT_TAR:
+      strcpy(str, "tar");
+      break;
+    case ARCHIVE_FORMAT_XAR:
+      strcpy(str, "xar");
+      break;
+    case ARCHIVE_FORMAT_ZIP:
+      strcpy(str, "zip");
+      break;
+    default:
+      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+          "Invalid format code specified");
+      return (ARCHIVE_FATAL);
+  }
+
+  slots = sizeof(a->formats) / sizeof(a->formats[0]);
+  a->format = &(a->formats[0]);
+  for (i = 0; i < slots; i++, a->format++) {
+    if (!a->format->name || !strcmp(a->format->name, str))
+      break;
+  }
+  if (!a->format->name || strcmp(a->format->name, str))
+  {
+    archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+        "Internal error: Unable to set format");
+    r1 = (ARCHIVE_FATAL);
+  }
+
+  return (r1 < r2) ? r1 : r2;
+}
diff --git a/libarchive/archive_read_set_options.3 b/libarchive/archive_read_set_options.3
index 81efb08..6fe9f90 100644
--- a/libarchive/archive_read_set_options.3
+++ b/libarchive/archive_read_set_options.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 13, 2009
+.Dd February 2, 2012
 .Dt ARCHIVE_READ_OPTIONS 3
 .Os
 .Sh NAME
@@ -34,6 +34,8 @@
 .Nm archive_read_set_options
 .Nd functions controlling options for reading archives
 .\"
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Ft int
 .Fo archive_read_set_filter_option
diff --git a/libarchive/archive_read_set_options.c b/libarchive/archive_read_set_options.c
index d6a5f45..793f8f7 100644
--- a/libarchive/archive_read_set_options.c
+++ b/libarchive/archive_read_set_options.c
@@ -78,7 +78,7 @@ archive_set_format_option(struct archive *_a, const char *m, const char *o,
 	struct archive_read *a = (struct archive_read *)_a;
 	struct archive_format_descriptor *format;
 	size_t i;
-	int r, rv = ARCHIVE_FAILED;
+	int r, rv = ARCHIVE_WARN;
 
 	for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) {
 		format = &a->formats[i];
@@ -102,6 +102,10 @@ archive_set_format_option(struct archive *_a, const char *m, const char *o,
 		if (r == ARCHIVE_OK)
 			rv = ARCHIVE_OK;
 	}
+	/* If the format name didn't match, return a special code for
+	 * _archive_set_option[s]. */
+	if (rv == ARCHIVE_WARN && m != NULL)
+		rv = ARCHIVE_WARN - 1;
 	return (rv);
 }
 
@@ -112,7 +116,7 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o,
 	struct archive_read *a = (struct archive_read *)_a;
 	struct archive_read_filter *filter;
 	struct archive_read_filter_bidder *bidder;
-	int r, rv = ARCHIVE_FAILED;
+	int r, rv = ARCHIVE_WARN;
 
 	for (filter = a->filter; filter != NULL; filter = filter->upstream) {
 		bidder = filter->bidder;
@@ -135,6 +139,10 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o,
 		if (r == ARCHIVE_OK)
 			rv = ARCHIVE_OK;
 	}
+	/* If the filter name didn't match, return a special code for
+	 * _archive_set_option[s]. */
+	if (rv == ARCHIVE_WARN && m != NULL)
+		rv = ARCHIVE_WARN - 1;
 	return (rv);
 }
 
diff --git a/libarchive/archive_read_support_filter_all.c b/libarchive/archive_read_support_filter_all.c
index 733d862..b778cfb 100644
--- a/libarchive/archive_read_support_filter_all.c
+++ b/libarchive/archive_read_support_filter_all.c
@@ -48,7 +48,7 @@ archive_read_support_filter_all(struct archive *a)
 	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. */
+	/* Gzip decompress falls back to "gzip -d" command-line. */
 	archive_read_support_filter_gzip(a);
 	/* Lzip falls back to "unlzip" command-line program. */
 	archive_read_support_filter_lzip(a);
@@ -63,6 +63,12 @@ archive_read_support_filter_all(struct archive *a)
 	archive_read_support_filter_uu(a);
 	/* The decode code doesn't use an outside library. */
 	archive_read_support_filter_rpm(a);
+	/* The decode code always uses "lrzip -q -d" command-line. */
+	archive_read_support_filter_lrzip(a);
+	/* Lzop decompress falls back to "lzop -d" command-line. */
+	archive_read_support_filter_lzop(a);
+	/* The decode code always uses "grzip -d" command-line. */
+	archive_read_support_filter_grzip(a);
 
 	/* Note: We always return ARCHIVE_OK here, even if some of the
 	 * above return ARCHIVE_WARN.  The intent here is to enable
diff --git a/libarchive/archive_read_support_filter_bzip2.c b/libarchive/archive_read_support_filter_bzip2.c
index 8d5bd1c..3885a7c 100644
--- a/libarchive/archive_read_support_filter_bzip2.c
+++ b/libarchive/archive_read_support_filter_bzip2.c
@@ -94,6 +94,7 @@ archive_read_support_filter_bzip2(struct archive *_a)
 		return (ARCHIVE_FATAL);
 
 	reader->data = NULL;
+	reader->name = "bzip2";
 	reader->bid = bzip2_reader_bid;
 	reader->init = bzip2_reader_init;
 	reader->options = NULL;
@@ -102,7 +103,7 @@ archive_read_support_filter_bzip2(struct archive *_a)
 	return (ARCHIVE_OK);
 #else
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-	    "Using external bunzip2 program");
+	    "Using external bzip2 program");
 	return (ARCHIVE_WARN);
 #endif
 }
@@ -170,11 +171,11 @@ bzip2_reader_init(struct archive_read_filter *self)
 {
 	int r;
 
-	r = __archive_read_program(self, "bunzip2");
+	r = __archive_read_program(self, "bzip2 -d");
 	/* Note: We set the format here even if __archive_read_program()
 	 * above fails.  We do, after all, know what the format is
 	 * even if we weren't able to read it. */
-	self->code = ARCHIVE_COMPRESSION_BZIP2;
+	self->code = ARCHIVE_FILTER_BZIP2;
 	self->name = "bzip2";
 	return (r);
 }
@@ -192,7 +193,7 @@ bzip2_reader_init(struct archive_read_filter *self)
 	void *out_block;
 	struct private_data *state;
 
-	self->code = ARCHIVE_COMPRESSION_BZIP2;
+	self->code = ARCHIVE_FILTER_BZIP2;
 	self->name = "bzip2";
 
 	state = (struct private_data *)calloc(sizeof(*state), 1);
diff --git a/libarchive/archive_read_support_filter_compress.c b/libarchive/archive_read_support_filter_compress.c
index 1b85300..3f5d1f3 100644
--- a/libarchive/archive_read_support_filter_compress.c
+++ b/libarchive/archive_read_support_filter_compress.c
@@ -163,6 +163,7 @@ archive_read_support_filter_compress(struct archive *_a)
 		return (ARCHIVE_FATAL);
 
 	bidder->data = NULL;
+	bidder->name = "compress (.Z)";
 	bidder->bid = compress_bidder_bid;
 	bidder->init = compress_bidder_init;
 	bidder->options = NULL;
@@ -212,7 +213,7 @@ compress_bidder_init(struct archive_read_filter *self)
 	void *out_block;
 	int code;
 
-	self->code = ARCHIVE_COMPRESSION_COMPRESS;
+	self->code = ARCHIVE_FILTER_COMPRESS;
 	self->name = "compress (.Z)";
 
 	state = (struct private_data *)calloc(sizeof(*state), 1);
diff --git a/libarchive/archive_read_support_filter_grzip.c b/libarchive/archive_read_support_filter_grzip.c
new file mode 100644
index 0000000..84c86ae
--- /dev/null
+++ b/libarchive/archive_read_support_filter_grzip.c
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+static const unsigned char grzip_magic[] = {
+	0x47, 0x52, 0x5a, 0x69, 0x70, 0x49, 0x49, 0x00,
+	0x02, 0x04, 0x3a, 0x29 };
+
+static int	grzip_bidder_bid(struct archive_read_filter_bidder *,
+		    struct archive_read_filter *);
+static int	grzip_bidder_init(struct archive_read_filter *);
+
+
+static int
+grzip_reader_free(struct archive_read_filter_bidder *self)
+{
+	(void)self; /* UNUSED */
+	return (ARCHIVE_OK);
+}
+
+int
+archive_read_support_filter_grzip(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_grzip");
+
+	if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
+		return (ARCHIVE_FATAL);
+
+	reader->data = NULL;
+	reader->bid = grzip_bidder_bid;
+	reader->init = grzip_bidder_init;
+	reader->options = NULL;
+	reader->free = grzip_reader_free;
+	/* This filter always uses an external program. */
+	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+	    "Using external grzip program for grzip decompression");
+	return (ARCHIVE_WARN);
+}
+
+/*
+ * Bidder just verifies the header and returns the number of verified bits.
+ */
+static int
+grzip_bidder_bid(struct archive_read_filter_bidder *self,
+    struct archive_read_filter *filter)
+{
+	const unsigned char *p;
+	ssize_t avail;
+
+	(void)self; /* UNUSED */
+
+	p = __archive_read_filter_ahead(filter, sizeof(grzip_magic), &avail);
+	if (p == NULL || avail == 0)
+		return (0);
+
+	if (memcmp(p, grzip_magic, sizeof(grzip_magic)))
+		return (0);
+
+	return (sizeof(grzip_magic) * 8);
+}
+
+static int
+grzip_bidder_init(struct archive_read_filter *self)
+{
+	int r;
+
+	r = __archive_read_program(self, "grzip -d");
+	/* Note: We set the format here even if __archive_read_program()
+	 * above fails.  We do, after all, know what the format is
+	 * even if we weren't able to read it. */
+	self->code = ARCHIVE_FILTER_GRZIP;
+	self->name = "grzip";
+	return (r);
+}
diff --git a/libarchive/archive_read_support_filter_gzip.c b/libarchive/archive_read_support_filter_gzip.c
index f6d5595..fa8c675 100644
--- a/libarchive/archive_read_support_filter_gzip.c
+++ b/libarchive/archive_read_support_filter_gzip.c
@@ -72,7 +72,7 @@ static int	gzip_filter_close(struct archive_read_filter *);
  *
  * TODO: If zlib is unavailable, gzip_bidder_init() should
  * use the compress_program framework to try to fire up an external
- * gunzip program.
+ * gzip program.
  */
 static int	gzip_bidder_bid(struct archive_read_filter_bidder *,
 		    struct archive_read_filter *);
@@ -100,6 +100,7 @@ archive_read_support_filter_gzip(struct archive *_a)
 		return (ARCHIVE_FATAL);
 
 	bidder->data = NULL;
+	bidder->name = "gzip";
 	bidder->bid = gzip_bidder_bid;
 	bidder->init = gzip_bidder_init;
 	bidder->options = NULL;
@@ -109,7 +110,7 @@ archive_read_support_filter_gzip(struct archive *_a)
 	return (ARCHIVE_OK);
 #else
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-	    "Using external gunzip program");
+	    "Using external gzip program");
 	return (ARCHIVE_WARN);
 #endif
 }
@@ -121,7 +122,7 @@ archive_read_support_filter_gzip(struct archive *_a)
  * number of bytes in header.  If pbits is non-NULL, it receives a
  * count of bits verified, suitable for use by bidder.
  */
-static int
+static ssize_t
 peek_at_header(struct archive_read_filter *filter, int *pbits)
 {
 	const unsigned char *p;
@@ -223,7 +224,7 @@ gzip_bidder_bid(struct archive_read_filter_bidder *self,
 
 /*
  * If we don't have the library on this system, we can't do the
- * decompression directly.  We can, however, try to run gunzip
+ * decompression directly.  We can, however, try to run "gzip -d"
  * in case that's available.
  */
 static int
@@ -231,11 +232,11 @@ gzip_bidder_init(struct archive_read_filter *self)
 {
 	int r;
 
-	r = __archive_read_program(self, "gunzip");
+	r = __archive_read_program(self, "gzip -d");
 	/* Note: We set the format here even if __archive_read_program()
 	 * above fails.  We do, after all, know what the format is
 	 * even if we weren't able to read it. */
-	self->code = ARCHIVE_COMPRESSION_GZIP;
+	self->code = ARCHIVE_FILTER_GZIP;
 	self->name = "gzip";
 	return (r);
 }
@@ -252,7 +253,7 @@ gzip_bidder_init(struct archive_read_filter *self)
 	static const size_t out_block_size = 64 * 1024;
 	void *out_block;
 
-	self->code = ARCHIVE_COMPRESSION_GZIP;
+	self->code = ARCHIVE_FILTER_GZIP;
 	self->name = "gzip";
 
 	state = (struct private_data *)calloc(sizeof(*state), 1);
@@ -299,7 +300,7 @@ consume_header(struct archive_read_filter *self)
 	/* Initialize compression library. */
 	state->stream.next_in = (unsigned char *)(uintptr_t)
 	    __archive_read_filter_ahead(self->upstream, 1, &avail);
-	state->stream.avail_in = avail;
+	state->stream.avail_in = (uInt)avail;
 	ret = inflateInit2(&(state->stream),
 	    -15 /* Don't check for zlib header */);
 
@@ -380,7 +381,7 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
 
 	/* Empty our output buffer. */
 	state->stream.next_out = state->out_block;
-	state->stream.avail_out = state->out_block_size;
+	state->stream.avail_out = (uInt)state->out_block_size;
 
 	/* Try to fill the output buffer. */
 	while (state->stream.avail_out > 0 && !state->eof) {
@@ -407,7 +408,7 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
 			    "truncated gzip input");
 			return (ARCHIVE_FATAL);
 		}
-		state->stream.avail_in = avail_in;
+		state->stream.avail_in = (uInt)avail_in;
 
 		/* Decompress and consume some of that data. */
 		ret = inflate(&(state->stream), 0);
diff --git a/libarchive/archive_read_support_filter_lrzip.c b/libarchive/archive_read_support_filter_lrzip.c
new file mode 100644
index 0000000..c82a8e2
--- /dev/null
+++ b/libarchive/archive_read_support_filter_lrzip.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+#define LRZIP_HEADER_MAGIC "LRZI"
+#define LRZIP_HEADER_MAGIC_LEN 4
+
+static int	lrzip_bidder_bid(struct archive_read_filter_bidder *,
+		    struct archive_read_filter *);
+static int	lrzip_bidder_init(struct archive_read_filter *);
+
+
+static int
+lrzip_reader_free(struct archive_read_filter_bidder *self)
+{
+	(void)self; /* UNUSED */
+	return (ARCHIVE_OK);
+}
+
+int
+archive_read_support_filter_lrzip(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_lrzip");
+
+	if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
+		return (ARCHIVE_FATAL);
+
+	reader->data = NULL;
+	reader->name = "lrzip";
+	reader->bid = lrzip_bidder_bid;
+	reader->init = lrzip_bidder_init;
+	reader->options = NULL;
+	reader->free = lrzip_reader_free;
+	/* This filter always uses an external program. */
+	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+	    "Using external lrzip program for lrzip decompression");
+	return (ARCHIVE_WARN);
+}
+
+/*
+ * Bidder just verifies the header and returns the number of verified bits.
+ */
+static int
+lrzip_bidder_bid(struct archive_read_filter_bidder *self,
+    struct archive_read_filter *filter)
+{
+	const unsigned char *p;
+	ssize_t avail, len;
+	int i;
+
+	(void)self; /* UNUSED */
+	/* Start by looking at the first six bytes of the header, which
+	 * is all fixed layout. */
+	len = 6;
+	p = __archive_read_filter_ahead(filter, len, &avail);
+	if (p == NULL || avail == 0)
+		return (0);
+
+	if (memcmp(p, LRZIP_HEADER_MAGIC, LRZIP_HEADER_MAGIC_LEN))
+		return (0);
+
+	/* current major version is always 0, verify this */
+	if (p[LRZIP_HEADER_MAGIC_LEN])
+		return 0;
+	/* support only v0.6+ lrzip for sanity */
+	i = p[LRZIP_HEADER_MAGIC_LEN + 1];
+	if ((i < 6) || (i > 10))
+		return 0;
+
+	return (int)len;
+}
+
+static int
+lrzip_bidder_init(struct archive_read_filter *self)
+{
+	int r;
+
+	r = __archive_read_program(self, "lrzip -d -q");
+	/* Note: We set the format here even if __archive_read_program()
+	 * above fails.  We do, after all, know what the format is
+	 * even if we weren't able to read it. */
+	self->code = ARCHIVE_FILTER_LRZIP;
+	self->name = "lrzip";
+	return (r);
+}
diff --git a/libarchive/archive_read_support_filter_lzop.c b/libarchive/archive_read_support_filter_lzop.c
new file mode 100644
index 0000000..713af31
--- /dev/null
+++ b/libarchive/archive_read_support_filter_lzop.c
@@ -0,0 +1,486 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_LZO_LZOCONF_H
+#include <lzo/lzoconf.h>
+#endif
+#ifdef HAVE_LZO_LZO1X_H
+#include <lzo/lzo1x.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h> /* for crc32 and adler32 */
+#endif
+
+#include "archive.h"
+#if !defined(HAVE_ZLIB_H) &&\
+     defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+#include "archive_crc32.h"
+#endif
+#include "archive_endian.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+#ifndef HAVE_ZLIB_H
+#define adler32	lzo_adler32
+#endif
+
+#define LZOP_HEADER_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a"
+#define LZOP_HEADER_MAGIC_LEN 9
+
+#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+struct read_lzop {
+	unsigned char	*out_block;
+	size_t		 out_block_size;
+	int64_t		 total_out;
+	int		 flags;
+	uint32_t	 compressed_cksum;
+	uint32_t	 uncompressed_cksum;
+	size_t		 compressed_size;
+	size_t		 uncompressed_size;
+	size_t		 unconsumed_bytes;
+	char		 in_stream;
+	char		 eof; /* True = found end of compressed data. */
+};
+
+#define FILTER			0x0800
+#define CRC32_HEADER		0x1000
+#define EXTRA_FIELD		0x0040
+#define ADLER32_UNCOMPRESSED	0x0001
+#define ADLER32_COMPRESSED	0x0002
+#define CRC32_UNCOMPRESSED	0x0100
+#define CRC32_COMPRESSED	0x0200
+#define MAX_BLOCK_SIZE		(64 * 1024 * 1024)
+
+static ssize_t  lzop_filter_read(struct archive_read_filter *, const void **);
+static int	lzop_filter_close(struct archive_read_filter *);
+#endif
+
+static int lzop_bidder_bid(struct archive_read_filter_bidder *,
+    struct archive_read_filter *);
+static int lzop_bidder_init(struct archive_read_filter *);
+
+int
+archive_read_support_filter_lzop(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_lzop");
+
+	if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
+		return (ARCHIVE_FATAL);
+
+	reader->data = NULL;
+	reader->bid = lzop_bidder_bid;
+	reader->init = lzop_bidder_init;
+	reader->options = NULL;
+	reader->free = NULL;
+	/* Signal the extent of lzop support with the return value here. */
+#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+	return (ARCHIVE_OK);
+#else
+	/* Return ARCHIVE_WARN since this always uses an external program. */
+	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+	    "Using external lzop program for lzop decompression");
+	return (ARCHIVE_WARN);
+#endif
+}
+
+/*
+ * Bidder just verifies the header and returns the number of verified bits.
+ */
+static int
+lzop_bidder_bid(struct archive_read_filter_bidder *self,
+    struct archive_read_filter *filter)
+{
+	const unsigned char *p;
+	ssize_t avail;
+
+	(void)self; /* UNUSED */
+
+	p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, &avail);
+	if (p == NULL || avail == 0)
+		return (0);
+
+	if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
+		return (0);
+
+	return (LZOP_HEADER_MAGIC_LEN * 8);
+}
+
+#if !defined(HAVE_LZO_LZOCONF_H) || !defined(HAVE_LZO_LZO1X_H)
+/*
+ * If we don't have the library on this system, we can't do the
+ * decompression directly.  We can, however, try to run "lzop -d"
+ * in case that's available.
+ */
+static int
+lzop_bidder_init(struct archive_read_filter *self)
+{
+	int r;
+
+	r = __archive_read_program(self, "lzop -d");
+	/* Note: We set the format here even if __archive_read_program()
+	 * above fails.  We do, after all, know what the format is
+	 * even if we weren't able to read it. */
+	self->code = ARCHIVE_FILTER_LZOP;
+	self->name = "lzop";
+	return (r);
+}
+#else
+/*
+ * Initialize the filter object.
+ */
+static int
+lzop_bidder_init(struct archive_read_filter *self)
+{
+	struct read_lzop *state;
+
+	self->code = ARCHIVE_FILTER_LZOP;
+	self->name = "lzop";
+
+	state = (struct read_lzop *)calloc(sizeof(*state), 1);
+	if (state == NULL) {
+		archive_set_error(&self->archive->archive, ENOMEM,
+		    "Can't allocate data for lzop decompression");
+		return (ARCHIVE_FATAL);
+	}
+
+	self->data = state;
+	self->read = lzop_filter_read;
+	self->skip = NULL; /* not supported */
+	self->close = lzop_filter_close;
+
+	return (ARCHIVE_OK);
+}
+
+static int
+consume_header(struct archive_read_filter *self)
+{
+	struct read_lzop *state = (struct read_lzop *)self->data;
+	const unsigned char *p, *_p;
+	unsigned checksum, flags, len, method, version;
+
+	/*
+	 * Check LZOP magic code.
+	 */
+	p = __archive_read_filter_ahead(self->upstream,
+		LZOP_HEADER_MAGIC_LEN, NULL);
+	if (p == NULL)
+		return (ARCHIVE_EOF);
+
+	if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
+		return (ARCHIVE_EOF);
+	__archive_read_filter_consume(self->upstream,
+	    LZOP_HEADER_MAGIC_LEN);
+
+	p = __archive_read_filter_ahead(self->upstream, 29, NULL);
+	if (p == NULL)
+		goto truncated;
+	_p = p;
+	version = archive_be16dec(p);
+	p += 4;/* version(2 bytes) + library version(2 bytes) */
+
+	if (version >= 0x940) {
+		unsigned reqversion = archive_be16dec(p); p += 2;
+		if (reqversion < 0x900) {
+			archive_set_error(&self->archive->archive,
+			    ARCHIVE_ERRNO_MISC, "Invalid required version");
+			return (ARCHIVE_FAILED);
+		}
+	}
+
+	method = *p++;
+	if (method < 1 || method > 3) {
+		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+		    "Unsupported method");
+		return (ARCHIVE_FAILED);
+	}
+
+	if (version >= 0x940) {
+		unsigned level = *p++;
+		if (method == 1 && level == 0) level = 3;
+		if (method == 2 && level == 0) level = 1;
+		if (method == 3 && level == 0) level = 9;
+		if (level < 1 && level > 9) {
+			archive_set_error(&self->archive->archive,
+			    ARCHIVE_ERRNO_MISC, "Invalid level");
+			return (ARCHIVE_FAILED);
+		}
+	}
+
+	flags = archive_be32dec(p); p += 4;
+
+	if (flags & FILTER)
+		p += 4; /* Skip filter */
+	p += 4; /* Skip mode */
+	if (version >= 0x940)
+		p += 8; /* Skip mtime */
+	else
+		p += 4; /* Skip mtime */
+	len = *p++; /* Read filename length */
+	len += p - _p;
+	/* Make sure we have all bytes we need to calculate checksum. */
+	p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);
+	if (p == NULL)
+		goto truncated;
+	if (flags & CRC32_HEADER)
+		checksum = crc32(crc32(0, NULL, 0), p, len);
+	else
+		checksum = adler32(adler32(0, NULL, 0), p, len);
+	if (archive_be32dec(p + len) != checksum)
+		goto corrupted;
+	__archive_read_filter_consume(self->upstream, len + 4);
+	if (flags & EXTRA_FIELD) {
+		/* Skip extra field */
+		p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+		if (p == NULL)
+			goto truncated;
+		len = archive_be32dec(p);
+		__archive_read_filter_consume(self->upstream, len + 4 + 4);
+	}
+	state->flags = flags;
+	state->in_stream = 1;
+	return (ARCHIVE_OK);
+truncated:
+	archive_set_error(&self->archive->archive,
+	    ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
+	return (ARCHIVE_FAILED);
+corrupted:
+	archive_set_error(&self->archive->archive,
+	    ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
+	return (ARCHIVE_FAILED);
+}
+
+static int
+consume_block_info(struct archive_read_filter *self)
+{
+	struct read_lzop *state = (struct read_lzop *)self->data;
+	const unsigned char *p;
+	unsigned flags = state->flags;
+
+	p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+	if (p == NULL)
+		goto truncated;
+	state->uncompressed_size = archive_be32dec(p);
+	__archive_read_filter_consume(self->upstream, 4);
+	if (state->uncompressed_size == 0)
+		return (ARCHIVE_EOF);
+	if (state->uncompressed_size > MAX_BLOCK_SIZE)
+		goto corrupted;
+
+	p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+	if (p == NULL)
+		goto truncated;
+	state->compressed_size = archive_be32dec(p);
+	__archive_read_filter_consume(self->upstream, 4);
+	if (state->compressed_size > state->uncompressed_size)
+		goto corrupted;
+
+	if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {
+		p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+		if (p == NULL)
+			goto truncated;
+		state->compressed_cksum = state->uncompressed_cksum =
+		    archive_be32dec(p);
+		__archive_read_filter_consume(self->upstream, 4);
+	}
+	if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&
+	    state->compressed_size < state->uncompressed_size) {
+		p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+		if (p == NULL)
+			goto truncated;
+		state->compressed_cksum = archive_be32dec(p);
+		__archive_read_filter_consume(self->upstream, 4);
+	}
+	return (ARCHIVE_OK);
+truncated:
+	archive_set_error(&self->archive->archive,
+	    ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
+	return (ARCHIVE_FAILED);
+corrupted:
+	archive_set_error(&self->archive->archive,
+	    ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
+	return (ARCHIVE_FAILED);
+}
+
+static ssize_t
+lzop_filter_read(struct archive_read_filter *self, const void **p)
+{
+	struct read_lzop *state = (struct read_lzop *)self->data;
+	const void *b;
+	lzo_uint out_size;
+	uint32_t cksum;
+	int ret, r;
+
+	if (state->unconsumed_bytes) {
+		__archive_read_filter_consume(self->upstream,
+		    state->unconsumed_bytes);
+		state->unconsumed_bytes = 0;
+	}
+	if (state->eof)
+		return (0);
+
+	for (;;) {
+		if (!state->in_stream) {
+			ret = consume_header(self);
+			if (ret < ARCHIVE_OK)
+				return (ret);
+			if (ret == ARCHIVE_EOF) {
+				state->eof = 1;
+				return (0);
+			}
+		}
+		ret = consume_block_info(self);
+		if (ret < ARCHIVE_OK)
+			return (ret);
+		if (ret == ARCHIVE_EOF)
+			state->in_stream = 0;
+		else
+			break;
+	}
+
+	if (state->out_block == NULL ||
+	    state->out_block_size < state->uncompressed_size) {
+		void *new_block;
+
+		new_block = realloc(state->out_block, state->uncompressed_size);
+		if (new_block == NULL) {
+			archive_set_error(&self->archive->archive, ENOMEM,
+			    "Can't allocate data for lzop decompression");
+			return (ARCHIVE_FATAL);
+		}
+		state->out_block = new_block;
+		state->out_block_size = state->uncompressed_size;
+	}
+
+	b = __archive_read_filter_ahead(self->upstream,
+		state->compressed_size, NULL);
+	if (b == NULL) {
+		archive_set_error(&self->archive->archive,
+		    ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
+		return (ARCHIVE_FATAL);
+	}
+	if (state->flags & CRC32_COMPRESSED)
+		cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);
+	else if (state->flags & ADLER32_COMPRESSED)
+		cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);
+	else
+		cksum = state->compressed_cksum;
+	if (cksum != state->compressed_cksum) {
+		archive_set_error(&self->archive->archive,
+		    ARCHIVE_ERRNO_MISC, "Corrupted data");
+		return (ARCHIVE_FATAL);
+	}
+
+	/*
+	 * If the both uncompressed size and compressed size are the same,
+	 * we do not decompress this block.
+	 */
+	if (state->uncompressed_size == state->compressed_size) {
+		*p = b;
+		state->total_out += state->compressed_size;
+		state->unconsumed_bytes = state->compressed_size;
+		return ((ssize_t)state->uncompressed_size);
+	}
+
+	/*
+	 * Drive lzo uncompresison.
+	 */
+	out_size = (lzo_uint)state->uncompressed_size;
+	r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,
+		state->out_block, &out_size, NULL);
+	switch (r) {
+	case LZO_E_OK:
+		if (out_size == state->uncompressed_size)
+			break;
+		archive_set_error(&self->archive->archive,
+		    ARCHIVE_ERRNO_MISC, "Corrupted data");
+		return (ARCHIVE_FATAL);
+	case LZO_E_OUT_OF_MEMORY:
+		archive_set_error(&self->archive->archive, ENOMEM,
+		    "lzop decompression failed: out of memory");
+		return (ARCHIVE_FATAL);
+	default:
+		archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+		    "lzop decompression failed: %d", r);
+		return (ARCHIVE_FATAL);
+	}
+
+	if (state->flags & CRC32_UNCOMPRESSED)
+		cksum = crc32(crc32(0, NULL, 0), state->out_block,
+		    state->uncompressed_size);
+	else if (state->flags & ADLER32_UNCOMPRESSED)
+		cksum = adler32(adler32(0, NULL, 0), state->out_block,
+		    state->uncompressed_size);
+	else
+		cksum = state->uncompressed_cksum;
+	if (cksum != state->uncompressed_cksum) {
+		archive_set_error(&self->archive->archive,
+		    ARCHIVE_ERRNO_MISC, "Corrupted data");
+		return (ARCHIVE_FATAL);
+	}
+
+	__archive_read_filter_consume(self->upstream, state->compressed_size);
+	*p = state->out_block;
+	state->total_out += out_size;
+	return ((ssize_t)out_size);
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+lzop_filter_close(struct archive_read_filter *self)
+{
+	struct read_lzop *state = (struct read_lzop *)self->data;
+
+	free(state->out_block);
+	free(state);
+	return (ARCHIVE_OK);
+}
+
+#endif
diff --git a/libarchive/archive_read_support_filter_program.c b/libarchive/archive_read_support_filter_program.c
index b05eb03..66dc2f4 100644
--- a/libarchive/archive_read_support_filter_program.c
+++ b/libarchive/archive_read_support_filter_program.c
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2007 Joerg Sonnenberger
+ * Copyright (c) 2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,7 +54,9 @@ __FBSDID("$FreeBSD$");
 
 #include "archive.h"
 #include "archive_private.h"
+#include "archive_string.h"
 #include "archive_read_private.h"
+#include "filter_fork.h"
 
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
@@ -79,50 +82,13 @@ 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 *description;
 	char *cmd;
 	void *signature;
 	size_t signature_len;
@@ -138,8 +104,12 @@ 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;
+	struct archive_string description;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	HANDLE		 child;
+#else
 	pid_t		 child;
+#endif
 	int		 exit_status;
 	int		 waitpid_return;
 	int		 child_stdin, child_stdout;
@@ -151,6 +121,29 @@ struct program_filter {
 static ssize_t	program_filter_read(struct archive_read_filter *,
 		    const void **);
 static int	program_filter_close(struct archive_read_filter *);
+static void	free_state(struct program_bidder *);
+
+static int
+set_bidder_signature(struct archive_read_filter_bidder *bidder,
+    struct program_bidder *state, const void *signature, size_t signature_len)
+{
+
+	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);
+}
 
 int
 archive_read_support_filter_program_signature(struct archive *_a,
@@ -169,37 +162,40 @@ archive_read_support_filter_program_signature(struct archive *_a,
 	/*
 	 * Allocate our private state.
 	 */
-	state = (struct program_bidder *)calloc(sizeof (*state), 1);
+	state = (struct program_bidder *)calloc(1, sizeof (*state));
 	if (state == NULL)
-		return (ARCHIVE_FATAL);
+		goto memerr;
 	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);
-	}
+	if (state->cmd == NULL)
+		goto memerr;
 
-	/*
-	 * 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);
+	return set_bidder_signature(bidder, state, signature, signature_len);
+memerr:
+	free_state(state);
+	archive_set_error(_a, ENOMEM, "Can't allocate memory");
+	return (ARCHIVE_FATAL);
 }
 
 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);
+
+	free_state(state);
 	return (ARCHIVE_OK);
 }
 
+static void
+free_state(struct program_bidder *state)
+{
+
+	if (state) {
+		free(state->cmd);
+		free(state->signature);
+		free(state);
+	}
+}
+
 /*
  * If we do have a signature, bid only if that matches.
  *
@@ -258,6 +254,9 @@ child_stop(struct archive_read_filter *self, struct program_filter *state)
 			state->waitpid_return
 			    = waitpid(state->child, &state->exit_status, 0);
 		} while (state->waitpid_return == -1 && errno == EINTR);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+		CloseHandle(state->child);
+#endif
 		state->child = 0;
 	}
 
@@ -310,11 +309,35 @@ child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
 	struct program_filter *state = self->data;
 	ssize_t ret, requested, avail;
 	const char *p;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout);
+#endif
 
 	requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
 
 	for (;;) {
 		do {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+			/* Avoid infinity wait.
+			 * Note: If there is no data in the pipe, ReadFile()
+			 * called in read() never returns and so we won't
+			 * write remaining encoded data to the pipe.
+			 * Note: This way may cause performance problem.
+			 * we are looking forward to great code to resolve
+			 * this.  */
+			DWORD pipe_avail = -1;
+			int cnt = 2;
+
+			while (PeekNamedPipe(handle, NULL, 0, NULL,
+			    &pipe_avail, NULL) != 0 && pipe_avail == 0 &&
+			    cnt--)
+				Sleep(5);
+			if (pipe_avail == 0) {
+				ret = -1;
+				errno = EAGAIN;
+				break;
+			}
+#endif
 			ret = read(state->child_stdout, buf, requested);
 		} while (ret == -1 && errno == EINTR);
 
@@ -376,38 +399,57 @@ __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: ";
+	pid_t child;
+	size_t l;
 
+	l = strlen(prefix) + strlen(cmd) + 1;
 	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) {
+	if (state == NULL || out_buf == NULL ||
+	    archive_string_ensure(&state->description, l) == NULL) {
 		archive_set_error(&self->archive->archive, ENOMEM,
 		    "Can't allocate input data");
-		free(state);
+		if (state != NULL) {
+			archive_string_free(&state->description);
+			free(state);
+		}
 		free(out_buf);
-		free(description);
 		return (ARCHIVE_FATAL);
 	}
+	archive_strcpy(&state->description, prefix);
+	archive_strcat(&state->description, cmd);
 
-	self->code = ARCHIVE_COMPRESSION_PROGRAM;
-	state->description = description;
-	strcpy(state->description, prefix);
-	strcat(state->description, cmd);
-	self->name = state->description;
+	self->code = ARCHIVE_FILTER_PROGRAM;
+	self->name = state->description.s;
 
 	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) {
+	child = __archive_create_child(cmd, &state->child_stdin,
+	    &state->child_stdout);
+	if (child == -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);
+	}
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	state->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child);
+	if (state->child == NULL) {
+		child_stop(self, state);
 		free(state->out_buf);
 		free(state);
 		archive_set_error(&self->archive->archive, EINVAL,
-		    "Can't initialize filter; unable to run program \"%s\"", cmd);
+		    "Can't initialize filter; unable to run program \"%s\"",
+		    cmd);
 		return (ARCHIVE_FATAL);
 	}
+#else
+	state->child = child;
+#endif
 
 	self->data = state;
 	self->read = program_filter_read;
@@ -467,10 +509,8 @@ program_filter_close(struct archive_read_filter *self)
 
 	/* Release our private data. */
 	free(state->out_buf);
-	free(state->description);
+	archive_string_free(&state->description);
 	free(state);
 
 	return (e);
 }
-
-#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */
diff --git a/libarchive/archive_read_support_filter_rpm.c b/libarchive/archive_read_support_filter_rpm.c
index 7dbfc0e..e7e58e5 100644
--- a/libarchive/archive_read_support_filter_rpm.c
+++ b/libarchive/archive_read_support_filter_rpm.c
@@ -85,6 +85,7 @@ archive_read_support_filter_rpm(struct archive *_a)
 		return (ARCHIVE_FATAL);
 
 	bidder->data = NULL;
+	bidder->name = "rpm";
 	bidder->bid = rpm_bidder_bid;
 	bidder->init = rpm_bidder_init;
 	bidder->options = NULL;
@@ -137,7 +138,7 @@ rpm_bidder_init(struct archive_read_filter *self)
 {
 	struct rpm   *rpm;
 
-	self->code = ARCHIVE_COMPRESSION_RPM;
+	self->code = ARCHIVE_FILTER_RPM;
 	self->name = "rpm";
 	self->read = rpm_filter_read;
 	self->skip = NULL; /* not supported */
@@ -188,7 +189,7 @@ rpm_filter_read(struct archive_read_filter *self, const void **buff)
 			if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
 				used += avail_in;
 			else {
-				n = RPM_LEAD_SIZE - rpm->total_in;
+				n = (size_t)(RPM_LEAD_SIZE - rpm->total_in);
 				used += n;
 				b += n;
 				rpm->state = ST_HEADER;
diff --git a/libarchive/archive_read_support_filter_uu.c b/libarchive/archive_read_support_filter_uu.c
index a75ef75..471771b 100644
--- a/libarchive/archive_read_support_filter_uu.c
+++ b/libarchive/archive_read_support_filter_uu.c
@@ -56,6 +56,7 @@ struct uudecode {
 #define ST_READ_UU	1
 #define ST_UUEND	2
 #define ST_READ_BASE64	3
+#define ST_IGNORE	4
 };
 
 static int	uudecode_bidder_bid(struct archive_read_filter_bidder *,
@@ -88,6 +89,7 @@ archive_read_support_filter_uu(struct archive *_a)
 		return (ARCHIVE_FATAL);
 
 	bidder->data = NULL;
+	bidder->name = "uu";
 	bidder->bid = uudecode_bidder_bid;
 	bidder->init = uudecode_bidder_init;
 	bidder->options = NULL;
@@ -377,7 +379,7 @@ uudecode_bidder_init(struct archive_read_filter *self)
 	void *out_buff;
 	void *in_buff;
 
-	self->code = ARCHIVE_COMPRESSION_UU;
+	self->code = ARCHIVE_FILTER_UU;
 	self->name = "uu";
 	self->read = uudecode_filter_read;
 	self->skip = NULL; /* not supported */
@@ -470,6 +472,10 @@ read_more:
 	total = 0;
 	out = uudecode->out_buff;
 	ravail = avail_in;
+	if (uudecode->state == ST_IGNORE) {
+		used = avail_in;
+		goto finish;
+	}
 	if (uudecode->in_cnt) {
 		/*
 		 * If there is remaining data which is saved by
@@ -485,12 +491,18 @@ read_more:
 		uudecode->in_cnt = 0;
 	}
 	for (;used < avail_in; d += llen, used += llen) {
-		int l, body;
+		int64_t l, body;
 
 		b = d;
 		len = get_line(b, avail_in - used, &nl);
 		if (len < 0) {
 			/* Non-ascii character is found. */
+			if (uudecode->state == ST_FIND_HEAD &&
+			    (uudecode->total > 0 || total > 0)) {
+				uudecode->state = ST_IGNORE;
+				used = avail_in;
+				goto finish;
+			}
 			archive_set_error(&self->archive->archive,
 			    ARCHIVE_ERRNO_MISC,
 			    "Insufficient compressed data");
@@ -507,7 +519,7 @@ read_more:
 				return (ARCHIVE_FATAL);
 			if (uudecode->in_buff != b)
 				memmove(uudecode->in_buff, b, len);
-			uudecode->in_cnt = len;
+			uudecode->in_cnt = (int)len;
 			if (total == 0) {
 				/* Do not return 0; it means end-of-file.
 				 * We should try to read bytes more. */
@@ -545,7 +557,7 @@ read_more:
 			break;
 		case ST_READ_UU:
 			if (total + len * 2 > OUT_BUFF_SIZE)
-				break;
+				goto finish;
 			body = len - nl;
 			if (!uuchar[*b] || body <= 0) {
 				archive_set_error(&self->archive->archive,
@@ -611,7 +623,7 @@ read_more:
 			break;
 		case ST_READ_BASE64:
 			if (total + len * 2 > OUT_BUFF_SIZE)
-				break;
+				goto finish;
 			l = len - nl;
 			if (l >= 3 && b[0] == '=' && b[1] == '=' &&
 			    b[2] == '=') {
@@ -657,8 +669,10 @@ read_more:
 			break;
 		}
 	}
-
-	__archive_read_filter_consume(self->upstream, ravail);
+finish:
+	if (ravail < avail_in)
+		used -= avail_in - ravail;
+	__archive_read_filter_consume(self->upstream, used);
 
 	*buff = uudecode->out_buff;
 	uudecode->total += total;
diff --git a/libarchive/archive_read_support_filter_xz.c b/libarchive/archive_read_support_filter_xz.c
index cf762a4..15824b1 100644
--- a/libarchive/archive_read_support_filter_xz.c
+++ b/libarchive/archive_read_support_filter_xz.c
@@ -136,6 +136,7 @@ archive_read_support_filter_xz(struct archive *_a)
 		return (ARCHIVE_FATAL);
 
 	bidder->data = NULL;
+	bidder->name = "xz";
 	bidder->bid = xz_bidder_bid;
 	bidder->init = xz_bidder_init;
 	bidder->options = NULL;
@@ -144,7 +145,7 @@ archive_read_support_filter_xz(struct archive *_a)
 	return (ARCHIVE_OK);
 #else
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-	    "Using external unxz program for xz decompression");
+	    "Using external xz program for xz decompression");
 	return (ARCHIVE_WARN);
 #endif
 }
@@ -170,6 +171,7 @@ archive_read_support_filter_lzma(struct archive *_a)
 		return (ARCHIVE_FATAL);
 
 	bidder->data = NULL;
+	bidder->name = "lzma";
 	bidder->bid = lzma_bidder_bid;
 	bidder->init = lzma_bidder_init;
 	bidder->options = NULL;
@@ -180,7 +182,7 @@ archive_read_support_filter_lzma(struct archive *_a)
 	return (ARCHIVE_OK);
 #else
 	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-	    "Using external unlzma program for lzma decompression");
+	    "Using external lzma program for lzma decompression");
 	return (ARCHIVE_WARN);
 #endif
 }
@@ -207,6 +209,7 @@ archive_read_support_filter_lzip(struct archive *_a)
 		return (ARCHIVE_FATAL);
 
 	bidder->data = NULL;
+	bidder->name = "lzip";
 	bidder->bid = lzip_bidder_bid;
 	bidder->init = lzip_bidder_init;
 	bidder->options = NULL;
@@ -415,7 +418,7 @@ lzip_bidder_bid(struct archive_read_filter_bidder *self,
 static int
 xz_bidder_init(struct archive_read_filter *self)
 {
-	self->code = ARCHIVE_COMPRESSION_XZ;
+	self->code = ARCHIVE_FILTER_XZ;
 	self->name = "xz";
 	return (xz_lzma_bidder_init(self));
 }
@@ -423,7 +426,7 @@ xz_bidder_init(struct archive_read_filter *self)
 static int
 lzma_bidder_init(struct archive_read_filter *self)
 {
-	self->code = ARCHIVE_COMPRESSION_LZMA;
+	self->code = ARCHIVE_FILTER_LZMA;
 	self->name = "lzma";
 	return (xz_lzma_bidder_init(self));
 }
@@ -431,7 +434,7 @@ lzma_bidder_init(struct archive_read_filter *self)
 static int
 lzip_bidder_init(struct archive_read_filter *self)
 {
-	self->code = ARCHIVE_COMPRESSION_LZIP;
+	self->code = ARCHIVE_FILTER_LZIP;
 	self->name = "lzip";
 	return (xz_lzma_bidder_init(self));
 }
@@ -518,7 +521,7 @@ xz_lzma_bidder_init(struct archive_read_filter *self)
 	state->stream.avail_out = state->out_block_size;
 
 	state->crc32 = 0;
-	if (self->code == ARCHIVE_COMPRESSION_LZIP) {
+	if (self->code == ARCHIVE_FILTER_LZIP) {
 		/*
 		 * We have to read a lzip header and use it to initialize
 		 * compression library, thus we cannot initialize the
@@ -530,7 +533,7 @@ xz_lzma_bidder_init(struct archive_read_filter *self)
 		state->in_stream = 1;
 
 	/* Initialize compression library. */
-	if (self->code == ARCHIVE_COMPRESSION_XZ)
+	if (self->code == ARCHIVE_FILTER_XZ)
 		ret = lzma_stream_decoder(&(state->stream),
 		    LZMA_MEMLIMIT,/* memlimit */
 		    LZMA_CONCATENATED);
@@ -730,7 +733,7 @@ xz_filter_read(struct archive_read_filter *self, const void **p)
 		*p = NULL;
 	else {
 		*p = state->out_block;
-		if (self->code == ARCHIVE_COMPRESSION_LZIP) {
+		if (self->code == ARCHIVE_FILTER_LZIP) {
 			state->crc32 = lzma_crc32(state->out_block,
 			    decompressed, state->crc32);
 			if (state->eof) {
@@ -778,7 +781,7 @@ lzma_bidder_init(struct archive_read_filter *self)
 	struct private_data *state;
 	ssize_t ret, avail_in;
 
-	self->code = ARCHIVE_COMPRESSION_LZMA;
+	self->code = ARCHIVE_FILTER_LZMA;
 	self->name = "lzma";
 
 	state = (struct private_data *)calloc(sizeof(*state), 1);
@@ -941,11 +944,11 @@ lzma_bidder_init(struct archive_read_filter *self)
 {
 	int r;
 
-	r = __archive_read_program(self, "unlzma");
+	r = __archive_read_program(self, "lzma -d -qq");
 	/* Note: We set the format here even if __archive_read_program()
 	 * above fails.  We do, after all, know what the format is
 	 * even if we weren't able to read it. */
-	self->code = ARCHIVE_COMPRESSION_LZMA;
+	self->code = ARCHIVE_FILTER_LZMA;
 	self->name = "lzma";
 	return (r);
 }
@@ -958,11 +961,11 @@ xz_bidder_init(struct archive_read_filter *self)
 {
 	int r;
 
-	r = __archive_read_program(self, "unxz");
+	r = __archive_read_program(self, "xz -d -qq");
 	/* Note: We set the format here even if __archive_read_program()
 	 * above fails.  We do, after all, know what the format is
 	 * even if we weren't able to read it. */
-	self->code = ARCHIVE_COMPRESSION_XZ;
+	self->code = ARCHIVE_FILTER_XZ;
 	self->name = "xz";
 	return (r);
 }
@@ -972,11 +975,11 @@ lzip_bidder_init(struct archive_read_filter *self)
 {
 	int r;
 
-	r = __archive_read_program(self, "unlzip");
+	r = __archive_read_program(self, "lzip -d -q");
 	/* Note: We set the format here even if __archive_read_program()
 	 * above fails.  We do, after all, know what the format is
 	 * even if we weren't able to read it. */
-	self->code = ARCHIVE_COMPRESSION_LZIP;
+	self->code = ARCHIVE_FILTER_LZIP;
 	self->name = "lzip";
 	return (r);
 }
diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c
index 330ba6a..194b8d5 100644
--- a/libarchive/archive_read_support_format_7zip.c
+++ b/libarchive/archive_read_support_format_7zip.c
@@ -318,7 +318,7 @@ struct _7zip {
 	uint32_t		 bcj2_code;
 	uint64_t		 bcj2_outPos;
 
-	/* Filename character-set convertion data. */
+	/* Filename character-set conversion data. */
 	struct archive_string_conv *sconv;
 
 	char			 format_name[64];
@@ -409,6 +409,7 @@ archive_read_support_format_7zip(struct archive *_a)
 	    archive_read_format_7zip_read_header,
 	    archive_read_format_7zip_read_data,
 	    archive_read_format_7zip_read_data_skip,
+	    NULL,
 	    archive_read_format_7zip_cleanup);
 
 	if (r != ARCHIVE_OK)
@@ -481,7 +482,7 @@ check_7zip_header_in_sfx(const char *p)
 		 * Magic Code, so we should do this in order not to
 		 * make a mis-detection.
 		 */
-		if (crc32(0, (unsigned char *)p + 12, 20)
+		if (crc32(0, (const unsigned char *)p + 12, 20)
 			!= archive_le32dec(p + 8))
 			return (6); 
 		/* Hit the header! */
@@ -580,7 +581,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
 		free_Header(&header);
 		if (r != ARCHIVE_OK)
 			return (r);
-		zip->entries_remaining = zip->numFiles;
+		zip->entries_remaining = (size_t)zip->numFiles;
 		zip->entry = zip->entries;
 	} else {
 		++zip->entry;
@@ -630,7 +631,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
 	if (zip_entry->flg & ATIME_IS_SET)
 		archive_entry_set_atime(entry, zip_entry->atime,
 		    zip_entry->atime_ns);
-	if (zip_entry->ssIndex != -1) {
+	if (zip_entry->ssIndex != (uint32_t)-1) {
 		zip->entry_bytes_remaining =
 		    zip->si.ss.unpackSizes[zip_entry->ssIndex];
 		archive_entry_set_size(entry, zip->entry_bytes_remaining);
@@ -646,7 +647,6 @@ archive_read_format_7zip_read_header(struct archive_read *a,
 	if ((zip_entry->mode & AE_IFMT) == AE_IFLNK) {
 		unsigned char *symname = NULL;
 		size_t symsize = 0;
-		int r;
 
 		/*
 		 * Symbolic-name is recorded as its contents. We have to
@@ -654,19 +654,24 @@ archive_read_format_7zip_read_header(struct archive_read *a,
 		 */
 		while (zip->entry_bytes_remaining > 0) {
 			const void *buff;
+			unsigned char *mem;
 			size_t size;
 			int64_t offset;
 
 			r = archive_read_format_7zip_read_data(a, &buff,
 				&size, &offset);
-			if (r < ARCHIVE_WARN)
+			if (r < ARCHIVE_WARN) {
+				free(symname);
 				return (r);
-			symname = realloc(symname, symsize + size + 1);
-			if (symname == NULL) {
+			}
+			mem = realloc(symname, symsize + size + 1);
+			if (mem == NULL) {
+				free(symname);
 				archive_set_error(&a->archive, ENOMEM,
 				    "Can't allocate memory for Symname");
 				return (ARCHIVE_FATAL);
 			}
+			symname = mem;
 			memcpy(symname+symsize, buff, size);
 			symsize += size;
 		}
@@ -680,8 +685,8 @@ archive_read_format_7zip_read_header(struct archive_read *a,
 			symname[symsize] = '\0';
 			archive_entry_copy_symlink(entry,
 			    (const char *)symname);
-			free(symname);
 		}
+		free(symname);
 		archive_entry_set_size(entry, 0);
 	}
 
@@ -705,18 +710,18 @@ archive_read_format_7zip_read_data(struct archive_read *a,
 	if (zip->pack_stream_bytes_unconsumed)
 		read_consume(a);
 
+	*offset = zip->entry_offset;
+	*size = 0;
+	*buff = NULL;
 	/*
 	 * If we hit end-of-entry last time, clean up and return
 	 * ARCHIVE_EOF this time.
 	 */
-	if (zip->end_of_entry) {
-		*offset = zip->entry_offset;
-		*size = 0;
-		*buff = NULL;
+	if (zip->end_of_entry)
 		return (ARCHIVE_EOF);
-	}
 
-	bytes = read_stream(a, buff, zip->entry_bytes_remaining, 0);
+	bytes = read_stream(a, buff,
+		(size_t)zip->entry_bytes_remaining, 0);
 	if (bytes < 0)
 		return ((int)bytes);
 	if (bytes == 0) {
@@ -731,7 +736,8 @@ archive_read_format_7zip_read_data(struct archive_read *a,
 
 	/* Update checksum */
 	if ((zip->entry->flg & CRC32_IS_SET) && bytes)
-		zip->entry_crc32 = crc32(zip->entry_crc32, *buff, bytes);
+		zip->entry_crc32 = crc32(zip->entry_crc32, *buff,
+		    (unsigned)bytes);
 
 	/* If we hit the end, swallow any end-of-data marker. */
 	if (zip->end_of_entry) {
@@ -774,7 +780,7 @@ archive_read_format_7zip_read_data_skip(struct archive_read *a)
 	 * If the length is at the beginning, we can skip the
 	 * compressed data much more quickly.
 	 */
-	bytes_skipped = skip_stream(a, zip->entry_bytes_remaining);
+	bytes_skipped = skip_stream(a, (size_t)zip->entry_bytes_remaining);
 	if (bytes_skipped < 0)
 		return (ARCHIVE_FATAL);
 	zip->entry_bytes_remaining = 0;
@@ -1054,7 +1060,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
 		ff = &filters[fi];
 #endif
 		r = lzma_properties_decode(&filters[fi], NULL,
-		    coder1->properties, coder1->propertiesSize);
+		    coder1->properties, (size_t)coder1->propertiesSize);
 		if (r != LZMA_OK) {
 			set_error(a, r);
 			return (ARCHIVE_FAILED);
@@ -1358,9 +1364,9 @@ decompress(struct archive_read *a, struct _7zip *zip,
 #ifdef HAVE_ZLIB_H
 	case _7Z_DEFLATE:
 		zip->stream.next_in = (Bytef *)(uintptr_t)t_next_in;
-		zip->stream.avail_in = t_avail_in;
+		zip->stream.avail_in = (uInt)t_avail_in;
 		zip->stream.next_out = t_next_out;
-		zip->stream.avail_out = t_avail_out;
+		zip->stream.avail_out = (uInt)t_avail_out;
 		r = inflate(&(zip->stream), 0);
 		switch (r) {
 		case Z_STREAM_END: /* Found end of stream. */
@@ -1382,7 +1388,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
 		uint64_t flush_bytes;
 
 		if (!zip->ppmd7_valid || zip->ppmd7_stat < 0 ||
-		    t_avail_in < 0 || t_avail_out <= 0) {
+		    t_avail_out <= 0) {
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
 			    "Decompression internal error");
@@ -1442,8 +1448,8 @@ decompress(struct archive_read *a, struct _7zip *zip,
 		} while (zip->ppstream.avail_out &&
 			(zip->ppstream.avail_in || flush_bytes));
 
-		t_avail_in = zip->ppstream.avail_in;
-		t_avail_out = zip->ppstream.avail_out;
+		t_avail_in = (size_t)zip->ppstream.avail_in;
+		t_avail_out = (size_t)zip->ppstream.avail_out;
 		break;
 	}
 	default:
@@ -1506,6 +1512,10 @@ free_decompression(struct archive_read *a, struct _7zip *zip)
 {
 	int r = ARCHIVE_OK;
 
+#if !defined(HAVE_ZLIB_H) &&\
+	!(defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR))
+	(void)a;/* UNUSED */
+#endif
 #ifdef HAVE_LZMA_H
 	if (zip->lzstream_valid)
 		lzma_end(&(zip->lzstream));
@@ -1598,9 +1608,10 @@ read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num)
 	const unsigned char *p;
 	unsigned i;
 
+	if (num == 0)
+		return (-1);
 	memset(d, 0, sizeof(*d));
 
-
 	d->defineds = malloc(num);
 	if (d->defineds == NULL)
 		return (-1);
@@ -1672,8 +1683,8 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
 		return (0);
 	if (*p != kSize)
 		return (-1);
-	pi->sizes = calloc(pi->numPackStreams, sizeof(uint64_t));
-	pi->positions = calloc(pi->numPackStreams, sizeof(uint64_t));
+	pi->sizes = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
+	pi->positions = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
 	if (pi->sizes == NULL || pi->positions == NULL)
 		return (-1);
 
@@ -1690,9 +1701,9 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
 	if (*p == kEnd) {
 		/* PackStreamDigests[num] are not present. */
 		pi->digest.defineds =
-		    calloc(pi->numPackStreams, sizeof(*pi->digest.defineds));
+		    calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));
 		pi->digest.digests =
-		    calloc(pi->numPackStreams, sizeof(*pi->digest.digests));
+		    calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests));
 		if (pi->digest.defineds == NULL || pi->digest.digests == NULL)
 			return (-1);
 		return (0);
@@ -1701,7 +1712,7 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
 	if (*p != kSize)
 		return (-1);
 
-	if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0)
+	if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)
 		return (-1);
 
 	/*
@@ -1750,7 +1761,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
 		/* Too many coders. */
 		return (-1);
 
-	f->coders = calloc(f->numCoders, sizeof(*f->coders));
+	f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders));
 	if (f->coders == NULL)
 		return (-1);
 	for (i = 0; i< f->numCoders; i++) {
@@ -1802,14 +1813,14 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
 			    a, &(f->coders[i].propertiesSize)) < 0)
 				return (-1);
 			if ((p = header_bytes(
-			    a, f->coders[i].propertiesSize)) == NULL)
+			    a, (size_t)f->coders[i].propertiesSize)) == NULL)
 				return (-1);
 			f->coders[i].properties =
-			    malloc(f->coders[i].propertiesSize);
+			    malloc((size_t)f->coders[i].propertiesSize);
 			if (f->coders[i].properties == NULL)
 				return (-1);
 			memcpy(f->coders[i].properties, p,
-			    f->coders[i].propertiesSize);
+			    (size_t)f->coders[i].propertiesSize);
 		}
 
 		numInStreamsTotal += f->coders[i].numInStreams;
@@ -1823,9 +1834,13 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
 	f->numBindPairs = numOutStreamsTotal - 1;
 	if (zip->header_bytes_remaining < f->numBindPairs)
 			return (-1);
-	f->bindPairs = calloc(f->numBindPairs, sizeof(*f->bindPairs));
-	if (f->bindPairs == NULL)
-		return (-1);
+	if (f->numBindPairs > 0) {
+		f->bindPairs =
+			calloc((size_t)f->numBindPairs, sizeof(*f->bindPairs));
+		if (f->bindPairs == NULL)
+			return (-1);
+	} else
+		f->bindPairs = NULL;
 	for (i = 0; i < f->numBindPairs; i++) {
 		if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
 			return (-1);
@@ -1839,7 +1854,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
 
 	f->numPackedStreams = numInStreamsTotal - f->numBindPairs;
 	f->packedStreams =
-	    calloc(f->numPackedStreams, sizeof(*f->packedStreams));
+	    calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams));
 	if (f->packedStreams == NULL)
 		return (-1);
 	if (f->numPackedStreams == 1) {
@@ -1911,7 +1926,8 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
 		goto failed;
 	switch (*p) {
 	case 0:
-		ci->folders = calloc(ci->numFolders, sizeof(*ci->folders));
+		ci->folders =
+			calloc((size_t)ci->numFolders, sizeof(*ci->folders));
 		if (ci->folders == NULL)
 			return (-1);
 		for (i = 0; i < ci->numFolders; i++) {
@@ -1937,7 +1953,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
 		unsigned j;
 
 		folder->unPackSize =
-		    calloc(folder->numOutStreams, sizeof(*folder->unPackSize));
+		    calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));
 		if (folder->unPackSize == NULL)
 			goto failed;
 		for (j = 0; j < folder->numOutStreams; j++) {
@@ -1955,7 +1971,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
 		return (0);
 	if (*p != kCRC)
 		goto failed;
-	if (read_Digests(a, &digest, ci->numFolders) < 0)
+	if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)
 		goto failed;
 	for (i = 0; i < ci->numFolders; i++) {
 		ci->folders[i].digest_defined = digest.defineds[i];
@@ -1979,13 +1995,13 @@ failed:
 static uint64_t
 folder_uncompressed_size(struct _7z_folder *f)
 {
-	int n = f->numOutStreams;
-	unsigned pairs = f->numBindPairs;
+	int n = (int)f->numOutStreams;
+	unsigned pairs = (unsigned)f->numBindPairs;
 
 	while (--n >= 0) {
 		unsigned i;
 		for (i = 0; i < pairs; i++) {
-			if (f->bindPairs[i].outIndex == n)
+			if (f->bindPairs[i].outIndex == (uint64_t)n)
 				break;
 		}
 		if (i >= pairs)
@@ -2029,7 +2045,7 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
 				return (-1);
 			if (1000000 < f[i].numUnpackStreams)
 				return (-1);
-			unpack_streams += f[i].numUnpackStreams;
+			unpack_streams += (size_t)f[i].numUnpackStreams;
 		}
 		if ((p = header_bytes(a, 1)) == NULL)
 			return (-1);
@@ -2083,7 +2099,7 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
 	numDigests = 0;
 	for (i = 0; i < numFolders; i++) {
 		if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)
-			numDigests += f[i].numUnpackStreams;
+			numDigests += (uint32_t)f[i].numUnpackStreams;
 	}
 
 	if (type == kCRC) {
@@ -2181,7 +2197,7 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
 		f = si->ci.folders;
 		for (i = 0; i < si->ci.numFolders; i++) {
 			f[i].packIndex = packIndex;
-			packIndex += f[i].numPackedStreams;
+			packIndex += (uint32_t)f[i].numPackedStreams;
 			if (packIndex > si->pi.numPackStreams)
 				return (-1);
 		}
@@ -2191,7 +2207,7 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
 
 	if (*p == kSubStreamsInfo) {
 		if (read_SubStreamsInfo(a, &(si->ss),
-		    si->ci.folders, si->ci.numFolders) < 0)
+		    si->ci.folders, (size_t)si->ci.numFolders) < 0)
 			return (-1);
 		if ((p = header_bytes(a, 1)) == NULL)
 			return (-1);
@@ -2279,7 +2295,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 	if (1000000 < zip->numFiles)
 			return (-1);
 
-	zip->entries = calloc(zip->numFiles, sizeof(*zip->entries));
+	zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
 	if (zip->entries == NULL)
 		return (-1);
 	entries = zip->entries;
@@ -2304,12 +2320,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 
 		switch (type) {
 		case kEmptyStream:
-			h->emptyStreamBools = calloc(zip->numFiles,
+			h->emptyStreamBools = calloc((size_t)zip->numFiles,
 			    sizeof(*h->emptyStreamBools));
 			if (h->emptyStreamBools == NULL)
 				return (-1);
 			if (read_Bools(
-			    a, h->emptyStreamBools, zip->numFiles) < 0)
+			    a, h->emptyStreamBools, (size_t)zip->numFiles) < 0)
 				return (-1);
 			empty_streams = 0;
 			for (i = 0; i < zip->numFiles; i++) {
@@ -2318,6 +2334,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 			}
 			break;
 		case kEmptyFile:
+			if (empty_streams <= 0) {
+				/* Unexcepted sequence. Skip this. */
+				if (header_bytes(a, ll) == NULL)
+					return (-1);
+				break;
+			}
 			h->emptyFileBools = calloc(empty_streams,
 			    sizeof(*h->emptyFileBools));
 			if (h->emptyFileBools == NULL)
@@ -2326,6 +2348,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 				return (-1);
 			break;
 		case kAnti:
+			if (empty_streams <= 0) {
+				/* Unexcepted sequence. Skip this. */
+				if (header_bytes(a, ll) == NULL)
+					return (-1);
+				break;
+			}
 			h->antiBools = calloc(empty_streams,
 			    sizeof(*h->antiBools));
 			if (h->antiBools == NULL)
@@ -2404,15 +2432,15 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 			if ((p = header_bytes(a, 2)) == NULL)
 				return (-1);
 			allAreDefined = *p;
-			h->attrBools = calloc(zip->numFiles,
+			h->attrBools = calloc((size_t)zip->numFiles,
 			    sizeof(*h->attrBools));
 			if (h->attrBools == NULL)
 				return (-1);
 			if (allAreDefined)
-				memset(h->attrBools, 1, zip->numFiles);
+				memset(h->attrBools, 1, (size_t)zip->numFiles);
 			else {
 				if (read_Bools(a, h->attrBools,
-				      zip->numFiles) < 0)
+				      (size_t)zip->numFiles) < 0)
 					return (-1);
 			}
 			for (i = 0; i < zip->numFiles; i++) {
@@ -2446,7 +2474,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 			if ((size_t)sindex >= si->ss.unpack_streams)
 				return (-1);
 			if (entries[i].mode == 0)
-				entries[i].mode = AE_IFREG | 0777;
+				entries[i].mode = AE_IFREG | 0666;
 			if (si->ss.digestsDefined[sindex])
 				entries[i].flg |= CRC32_IS_SET;
 			entries[i].ssIndex = sindex;
@@ -2466,7 +2494,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 				if (dir)
 					entries[i].mode = AE_IFDIR | 0777;
 				else
-					entries[i].mode = AE_IFREG | 0777;
+					entries[i].mode = AE_IFREG | 0666;
 			} else if (dir &&
 			    (entries[i].mode & AE_IFMT) != AE_IFDIR) {
 				entries[i].mode &= ~AE_IFMT;
@@ -2517,17 +2545,17 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
 
 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 static void
-fileTimeToUtc(uint64_t fileTime, time_t *time, long *ns)
+fileTimeToUtc(uint64_t fileTime, time_t *timep, long *ns)
 {
 
 	if (fileTime >= EPOC_TIME) {
 		fileTime -= EPOC_TIME;
 		/* milli seconds base */
-		*time = (time_t)(fileTime / 10000000);
+		*timep = (time_t)(fileTime / 10000000);
 		/* nano seconds base */
 		*ns = (long)(fileTime % 10000000) * 100;
 	} else {
-		*time = 0;
+		*timep = 0;
 		*ns = 0;
 	}
 }
@@ -2542,7 +2570,7 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
 	int allAreDefined;
 	unsigned i;
 
-	timeBools = calloc(zip->numFiles, sizeof(*timeBools));
+	timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools));
 	if (timeBools == NULL)
 		return (-1);
 
@@ -2551,9 +2579,9 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
 		goto failed;
 	allAreDefined = *p;
 	if (allAreDefined)
-		memset(timeBools, 1, zip->numFiles);
+		memset(timeBools, 1, (size_t)zip->numFiles);
 	else {
-		if (read_Bools(a, timeBools, zip->numFiles) < 0)
+		if (read_Bools(a, timeBools, (size_t)zip->numFiles) < 0)
 			goto failed;
 	}
 
@@ -2564,7 +2592,7 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
 		if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
 			goto failed;
 		if (1000000 < h->dataIndex)
-			return (-1);
+			goto failed;
 	}
 
 	for (i = 0; i < zip->numFiles; i++) {
@@ -2661,7 +2689,7 @@ header_bytes(struct archive_read *a, size_t rbytes)
 	}
 
 	/* Update checksum */
-	zip->header_crc32 = crc32(zip->header_crc32, p, rbytes);
+	zip->header_crc32 = crc32(zip->header_crc32, p, (unsigned)rbytes);
 	return (p);
 }
 
@@ -2695,7 +2723,8 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
 	}
 
 	/* CRC check. */
-	if (crc32(0, (unsigned char *)p + 12, 20) != archive_le32dec(p + 8)) {
+	if (crc32(0, (const unsigned char *)p + 12, 20)
+	    != archive_le32dec(p + 8)) {
 		archive_set_error(&a->archive, -1, "Header CRC error");
 		return (ARCHIVE_FATAL);
 	}
@@ -2714,7 +2743,7 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
 	}
 	__archive_read_consume(a, 32);
 	if (next_header_offset != 0) {
-		if (bytes_avail >= next_header_offset)
+		if (bytes_avail >= (ssize_t)next_header_offset)
 			__archive_read_consume(a, next_header_offset);
 		else if (__archive_read_seek(a,
 		    next_header_offset + zip->seek_base, SEEK_SET) < 0)
@@ -2827,7 +2856,7 @@ get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,
 	struct _7zip *zip = (struct _7zip *)a->format->data;
 	ssize_t bytes_avail;
 
-	if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
+	if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
 		/* Copy mode. */
 
 		/*
@@ -2886,7 +2915,7 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
 	ssize_t bytes_avail;
 	int r;
 
-	if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
+	if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
 		if (minimum == 0)
 			minimum = 1;
 		if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL
@@ -2896,11 +2925,11 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
 			    "Truncated 7-Zip file body");
 			return (ARCHIVE_FATAL);
 		}
-		if (bytes_avail > zip->pack_stream_inbytes_remaining)
-			bytes_avail = zip->pack_stream_inbytes_remaining;
+		if (bytes_avail > (ssize_t)zip->pack_stream_inbytes_remaining)
+			bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining;
 		zip->pack_stream_inbytes_remaining -= bytes_avail;
-		if (bytes_avail > zip->folder_outbytes_remaining)
-			bytes_avail = zip->folder_outbytes_remaining;
+		if (bytes_avail > (ssize_t)zip->folder_outbytes_remaining)
+			bytes_avail = (ssize_t)zip->folder_outbytes_remaining;
 		zip->folder_outbytes_remaining -= bytes_avail;
 		zip->uncompressed_buffer_bytes_remaining = bytes_avail;
 		return (ARCHIVE_OK);
@@ -2939,16 +2968,19 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
 			 * Expand the uncompressed buffer up to
 			 * the minimum size.
 			 */
-			zip->uncompressed_buffer_size = minimum + 1023;
-			zip->uncompressed_buffer_size &= ~0x3ff;
-			zip->uncompressed_buffer =
-			    realloc(zip->uncompressed_buffer,
-				zip->uncompressed_buffer_size);
-			if (zip->uncompressed_buffer == NULL) {
+			void *p;
+			size_t new_size;
+
+			new_size = minimum + 1023;
+			new_size &= ~0x3ff;
+			p = realloc(zip->uncompressed_buffer, new_size);
+			if (p == NULL) {
 				archive_set_error(&a->archive, ENOMEM,
 				    "No memory for 7-Zip decompression");
 				return (ARCHIVE_FATAL);
 			}
+			zip->uncompressed_buffer = (unsigned char *)p;
+			zip->uncompressed_buffer_size = new_size;
 		}
 		/*
 		 * Move unconsumed bytes to the head.
@@ -2965,7 +2997,7 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
 		size_t bytes_in, bytes_out;
 		const void *buff_in;
 		unsigned char *buff_out;
-		int eof;
+		int end_of_data;
 
 		/*
 		 * Note: '1' here is a performance optimization.
@@ -2987,23 +3019,23 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
 			- zip->uncompressed_buffer_bytes_remaining;
 		bytes_in = bytes_avail;
 		if (bytes_in > zip->pack_stream_inbytes_remaining)
-			bytes_in = zip->pack_stream_inbytes_remaining;
+			bytes_in = (size_t)zip->pack_stream_inbytes_remaining;
 		/* Drive decompression. */
 		r = decompress(a, zip, buff_out, &bytes_out,
 			buff_in, &bytes_in);
 		switch (r) {
 		case ARCHIVE_OK:
-			eof = 0;
+			end_of_data = 0;
 			break;
 		case ARCHIVE_EOF:
-			eof = 1;
+			end_of_data = 1;
 			break;
 		default:
 			return (ARCHIVE_FATAL);
 		}
 		zip->pack_stream_inbytes_remaining -= bytes_in;
 		if (bytes_out > zip->folder_outbytes_remaining)
-			bytes_out = zip->folder_outbytes_remaining;
+			bytes_out = (size_t)zip->folder_outbytes_remaining;
 		zip->folder_outbytes_remaining -= bytes_out;
 		zip->uncompressed_buffer_bytes_remaining += bytes_out;
 		zip->pack_stream_bytes_unconsumed = bytes_in;
@@ -3021,7 +3053,7 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
 		if (zip->pack_stream_inbytes_remaining == 0 &&
 		    zip->folder_outbytes_remaining == 0)
 			break;
-		if (eof || (bytes_in == 0 && bytes_out == 0)) {
+		if (end_of_data || (bytes_in == 0 && bytes_out == 0)) {
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
 			return (ARCHIVE_FATAL);
@@ -3041,7 +3073,7 @@ static int
 seek_pack(struct archive_read *a)
 {
 	struct _7zip *zip = (struct _7zip *)a->format->data;
-	uint64_t pack_offset;
+	int64_t pack_offset;
 
 	if (zip->pack_stream_remaining <= 0) {
 		archive_set_error(&(a->archive),
@@ -3068,7 +3100,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
 {
 	struct _7zip *zip = (struct _7zip *)a->format->data;
 	uint64_t skip_bytes = 0;
-	int r;
+	ssize_t r;
 
 	if (zip->uncompressed_buffer_bytes_remaining == 0) {
 		if (zip->pack_stream_inbytes_remaining > 0) {
@@ -3160,7 +3192,8 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
 				return (ARCHIVE_FATAL);
 			}
 		}
-		skipped = get_uncompressed_data(a, buff, skip_bytes, 0);
+		skipped = get_uncompressed_data(
+			a, buff, (size_t)skip_bytes, 0);
 		if (skipped < 0)
 			return (skipped);
 		skip_bytes -= skipped;
@@ -3292,13 +3325,13 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
 			}
 			coder2 = &(fc[3]);
 			zip->main_stream_bytes_remaining =
-				folder->unPackSize[2];
+				(size_t)folder->unPackSize[2];
 		} else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 &&
 		    zip->pack_stream_remaining == 4 &&
 		    folder->numInStreams == 5 && folder->numOutStreams == 2) {
 			/* Source type 0 made by 7z */
 			zip->main_stream_bytes_remaining =
-				folder->unPackSize[0];
+				(size_t)folder->unPackSize[0];
 		} else {
 			/* We got an unexpected form. */
 			archive_set_error(&(a->archive),
@@ -3311,30 +3344,35 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
 		if ((r = seek_pack(a)) < 0)
 			return (r);
 		zip->pack_stream_bytes_unconsumed =
-		    zip->pack_stream_inbytes_remaining;
+		    (size_t)zip->pack_stream_inbytes_remaining;
 		read_consume(a);
 
 		/* Read following three sub streams. */
 		for (i = 0; i < 3; i++) {
 			const struct _7z_coder *coder = scoder[i];
 
-			if ((r = seek_pack(a)) < 0)
+			if ((r = seek_pack(a)) < 0) {
+				free(b[0]); free(b[1]); free(b[2]);
 				return (r);
+			}
 
-			if (sunpack[i] == -1)
+			if (sunpack[i] == (uint64_t)-1)
 				zip->folder_outbytes_remaining =
 				    zip->pack_stream_inbytes_remaining;
 			else
 				zip->folder_outbytes_remaining = sunpack[i];
 
 			r = init_decompression(a, zip, coder, NULL);
-			if (r != ARCHIVE_OK)
+			if (r != ARCHIVE_OK) {
+				free(b[0]); free(b[1]); free(b[2]);
 				return (ARCHIVE_FATAL);
+			}
 
 			/* Allocate memory for the decorded data of a sub
 			 * stream. */
-			b[i] = malloc(zip->folder_outbytes_remaining);
+			b[i] = malloc((size_t)zip->folder_outbytes_remaining);
 			if (b[i] == NULL) {
+				free(b[0]); free(b[1]); free(b[2]);
 				archive_set_error(&a->archive, ENOMEM,
 				    "No memory for 7-Zip decompression");
 				return (ARCHIVE_FATAL);
@@ -3342,14 +3380,18 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
 
 			/* Extract a sub stream. */
 			while (zip->pack_stream_inbytes_remaining > 0) {
-				r = extract_pack_stream(a, 0);
-				if (r < 0)
+				r = (int)extract_pack_stream(a, 0);
+				if (r < 0) {
+					free(b[0]); free(b[1]); free(b[2]);
 					return (r);
+				}
 				bytes = get_uncompressed_data(a, &buff,
 				    zip->uncompressed_buffer_bytes_remaining,
 				    0);
-				if (bytes < 0)
+				if (bytes < 0) {
+					free(b[0]); free(b[1]); free(b[2]);
 					return ((int)bytes);
+				}
 				memcpy(b[i]+s[i], buff, bytes);
 				s[i] += bytes;
 				if (zip->pack_stream_bytes_unconsumed)
@@ -3428,7 +3470,7 @@ skip_stream(struct archive_read *a, size_t skip_bytes)
 			    "Truncated 7-Zip file body");
 			return (ARCHIVE_FATAL);
 		}
-		bytes -= skipped_bytes;
+		bytes -= (size_t)skipped_bytes;
 		if (zip->pack_stream_bytes_unconsumed)
 			read_consume(a);
 	}
@@ -3506,16 +3548,16 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
 			uint32_t dest;
 			for (;;) {
 				uint8_t b;
-				int index;
+				int b_index;
 
 				dest = src - (ip + (uint32_t)bufferPos);
 				if (prevMask == 0)
 					break;
-				index = kMaskToBitNumber[prevMask] * 8;
-				b = (uint8_t)(dest >> (24 - index));
+				b_index = kMaskToBitNumber[prevMask] * 8;
+				b = (uint8_t)(dest >> (24 - b_index));
 				if (!Test86MSByte(b))
 					break;
-				src = dest ^ ((1 << (32 - index)) - 1);
+				src = dest ^ ((1 << (32 - b_index)) - 1);
 			}
 			p[4] = (uint8_t)(~(((dest >> 24) & 1) - 1));
 			p[3] = (uint8_t)(dest >> 16);
@@ -3529,7 +3571,7 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
 	}
 	zip->bcj_prevPosT = prevPosT;
 	zip->bcj_prevMask = prevMask;
-	zip->bcj_ip += bufferPos;
+	zip->bcj_ip += (uint32_t)bufferPos;
 	return (bufferPos);
 }
 
@@ -3556,7 +3598,7 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
 #define RC_READ_BYTE (*buffer++)
 #define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
 #define RC_INIT2 zip->bcj2_code = 0; zip->bcj2_range = 0xFFFFFFFF; \
-  { int i; for (i = 0; i < 5; i++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
+  { int ii; for (ii = 0; ii < 5; ii++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
 
 #define NORMALIZE if (zip->bcj2_range < kTopValue) { RC_TEST; zip->bcj2_range <<= 8; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }
 
@@ -3622,14 +3664,14 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
 
 		if (zip->bcj_state == 1) {
 			while (limit != 0) {
-				uint8_t b = buf0[inPos];
-				outBuf[outPos++] = b;
-				if (IsJ(zip->bcj2_prevByte, b)) {
+				uint8_t bb = buf0[inPos];
+				outBuf[outPos++] = bb;
+				if (IsJ(zip->bcj2_prevByte, bb)) {
 					zip->bcj_state = 2;
 					break;
 				}
 				inPos++;
-				zip->bcj2_prevByte = b;
+				zip->bcj2_prevByte = bb;
 				limit--;
 			}
 		}
@@ -3673,7 +3715,7 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
 			    ((uint32_t)v[1] << 16) |
 			    ((uint32_t)v[2] << 8) |
 			    ((uint32_t)v[3])) -
-			    ((uint32_t)zip->bcj2_outPos + outPos + 4);
+			    ((uint32_t)zip->bcj2_outPos + (uint32_t)outPos + 4);
 			out[0] = (uint8_t)dest;
 			out[1] = (uint8_t)(dest >> 8);
 			out[2] = (uint8_t)(dest >> 16);
@@ -3688,7 +3730,7 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
 				 */
 				zip->odd_bcj_size = 4 -i;
 				for (; i < 4; i++) {
-					j = i - 4 + zip->odd_bcj_size;
+					j = i - 4 + (unsigned)zip->odd_bcj_size;
 					zip->odd_bcj[j] = out[i];
 				}
 				break;
diff --git a/libarchive/archive_read_support_format_ar.c b/libarchive/archive_read_support_format_ar.c
index 9feb547..40be18c 100644
--- a/libarchive/archive_read_support_format_ar.c
+++ b/libarchive/archive_read_support_format_ar.c
@@ -121,6 +121,7 @@ archive_read_support_format_ar(struct archive *_a)
 	    archive_read_format_ar_read_header,
 	    archive_read_format_ar_read_data,
 	    archive_read_format_ar_skip,
+	    NULL,
 	    archive_read_format_ar_cleanup);
 
 	if (r != ARCHIVE_OK) {
diff --git a/libarchive/archive_read_support_format_cab.c b/libarchive/archive_read_support_format_cab.c
index 1b81ee9..3c9f94c 100644
--- a/libarchive/archive_read_support_format_cab.c
+++ b/libarchive/archive_read_support_format_cab.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2010-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -292,6 +292,8 @@ struct cab {
 	char			 end_of_archive;
 	char			 end_of_entry;
 	char			 end_of_entry_cleanup;
+	char			 read_data_invoked;
+	int64_t			 bytes_skipped;
 
 	unsigned char		*uncompressed_buffer;
 	size_t			 uncompressed_buffer_size;
@@ -349,7 +351,7 @@ static int	lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);
 static int	lzx_huffman_init(struct huffman *, size_t, int);
 static void	lzx_huffman_free(struct huffman *);
 static int	lzx_make_huffman_table(struct huffman *);
-static int inline lzx_decode_huffman(struct huffman *, unsigned);
+static inline int lzx_decode_huffman(struct huffman *, unsigned);
 static int	lzx_decode_huffman_tree(struct huffman *, unsigned, int);
 
 
@@ -380,6 +382,7 @@ archive_read_support_format_cab(struct archive *_a)
 	    archive_read_format_cab_read_header,
 	    archive_read_format_cab_read_data,
 	    archive_read_format_cab_read_data_skip,
+	    NULL,
 	    archive_read_format_cab_cleanup);
 
 	if (r != ARCHIVE_OK)
@@ -478,11 +481,13 @@ archive_read_format_cab_options(struct archive_read *a,
 			else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "cab: unknown keyword ``%s''", key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 static int
@@ -535,7 +540,7 @@ truncated_error(struct archive_read *a)
 	return (ARCHIVE_FATAL);
 }
 
-static int
+static ssize_t
 cab_strnlen(const unsigned char *p, size_t maxlen)
 {
 	size_t i;
@@ -546,7 +551,7 @@ cab_strnlen(const unsigned char *p, size_t maxlen)
 	}
 	if (i > maxlen)
 		return (-1);/* invalid */
-	return (i);
+	return ((ssize_t)i);
 }
 
 /* Read bytes as much as remaining. */
@@ -622,8 +627,9 @@ cab_read_header(struct archive_read *a)
 	struct cab *cab;
 	struct cfheader *hd;
 	size_t bytes, used;
+	ssize_t len;
 	int64_t skip;
-	int err, i, len;
+	int err, i;
 	int cur_folder, prev_folder;
 	uint32_t offset32;
 	
@@ -796,7 +802,7 @@ cab_read_header(struct archive_read *a)
 		file->offset = archive_le32dec(p + CFFILE_uoffFolderStart);
 		file->folder = archive_le16dec(p + CFFILE_iFolder);
 		file->mtime = cab_dos_time(p + CFFILE_date_time);
-		file->attr = archive_le16dec(p + CFFILE_attribs);
+		file->attr = (uint8_t)archive_le16dec(p + CFFILE_attribs);
 		__archive_read_consume(a, 16);
 
 		cab->cab_offset += 16;
@@ -986,7 +992,7 @@ archive_read_format_cab_read_header(struct archive_read *a,
 	if (file->attr & ATTR_RDONLY)
 		archive_entry_set_mode(entry, AE_IFREG | 0555);
 	else
-		archive_entry_set_mode(entry, AE_IFREG | 0777);
+		archive_entry_set_mode(entry, AE_IFREG | 0666);
 	archive_entry_set_mtime(entry, file->mtime, 0);
 
 	cab->entry_bytes_remaining = file->uncompressed_size;
@@ -1024,9 +1030,22 @@ archive_read_format_cab_read_data(struct archive_read *a,
 	default:
 		break;
 	}
+	if (cab->read_data_invoked == 0) {
+		if (cab->bytes_skipped) {
+			if (cab->entry_cfdata == NULL) {
+				r = cab_next_cfdata(a);
+				if (r < 0)
+					return (r);
+			}
+			if (cab_consume_cfdata(a, cab->bytes_skipped) < 0)
+				return (ARCHIVE_FATAL);
+			cab->bytes_skipped = 0;
+		}
+		cab->read_data_invoked = 1;
+	}
 	if (cab->entry_unconsumed) {
 		/* Consume as much as the compressor actually used. */
-		r = cab_consume_cfdata(a, cab->entry_unconsumed);
+		r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
 		cab->entry_unconsumed = 0;
 		if (r < 0)
 			return (r);
@@ -1049,13 +1068,13 @@ static uint32_t
 cab_checksum_cfdata_4(const void *p, size_t bytes, uint32_t seed)
 {
 	const unsigned char *b;
-	int u32num;
+	unsigned u32num;
 	uint32_t sum;
 
-	u32num = bytes / 4;
+	u32num = (unsigned)bytes / 4;
 	sum = seed;
 	b = p;
-	while (--u32num >= 0) {
+	for (;u32num > 0; --u32num) {
 		sum ^= archive_le32dec(b);
 		b += 4;
 	}
@@ -1356,46 +1375,25 @@ cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)
 	struct cab *cab = (struct cab *)(a->format->data);
 	struct cfdata *cfdata;
 	const void *d;
-	int64_t skipped_bytes;
 
 	cfdata = cab->entry_cfdata;
 
-	if (cfdata->uncompressed_avail == 0 &&
-		cfdata->read_offset > 0) {
-		/* we've already skipped some bytes before really read. */
-		skipped_bytes = cfdata->read_offset;
-		cfdata->read_offset = 0;
-		cfdata->uncompressed_bytes_remaining += skipped_bytes;
-	} else
-		skipped_bytes = 0;
-	do {
-		/*
-		 * Note: '1' here is a performance optimization.
-		 * Recall that the decompression layer returns a count of
-		 * available bytes; asking for more than that forces the
-		 * decompressor to combine reads by copying data.
-		 */
-		d = __archive_read_ahead(a, 1, avail);
-		if (*avail <= 0) {
-			*avail = truncated_error(a);
-			return (NULL);
-		}
-		if (*avail > cfdata->uncompressed_bytes_remaining)
-			*avail = cfdata->uncompressed_bytes_remaining;
-		cfdata->uncompressed_avail = cfdata->uncompressed_size;
-		cfdata->unconsumed = *avail;
-		cfdata->sum_ptr = d;
-		if (skipped_bytes > 0) {
-			skipped_bytes =
-			    cab_minimum_consume_cfdata(a, skipped_bytes);
-			if (skipped_bytes < 0) {
-				*avail = ARCHIVE_FATAL;
-				return (NULL);
-			}
-			continue;
-		}
-	} while (0);
-
+	/*
+	 * Note: '1' here is a performance optimization.
+	 * Recall that the decompression layer returns a count of
+	 * available bytes; asking for more than that forces the
+	 * decompressor to combine reads by copying data.
+	 */
+	d = __archive_read_ahead(a, 1, avail);
+	if (*avail <= 0) {
+		*avail = truncated_error(a);
+		return (NULL);
+	}
+	if (*avail > cfdata->uncompressed_bytes_remaining)
+		*avail = cfdata->uncompressed_bytes_remaining;
+	cfdata->uncompressed_avail = cfdata->uncompressed_size;
+	cfdata->unconsumed = *avail;
+	cfdata->sum_ptr = d;
 	return (d);
 }
 
@@ -1489,7 +1487,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
 		 * cast to remove 'const'.
 		 */
 		cab->stream.next_in = (Bytef *)(uintptr_t)d;
-		cab->stream.avail_in = bytes_avail;
+		cab->stream.avail_in = (uInt)bytes_avail;
 		cab->stream.total_in = 0;
 
 		/* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */
@@ -1510,7 +1508,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
 					*avail = ARCHIVE_FATAL;
 					return (NULL);
 				}
-				mszip -= bytes_avail;
+				mszip -= (int)bytes_avail;
 				continue;
 			}
 			if (mszip == 1 && cab->stream.next_in[0] != 0x4b)
@@ -1541,7 +1539,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
 			return (NULL);
 		}
 	}
-	uavail = cab->stream.total_out;
+	uavail = (uint16_t)cab->stream.total_out;
 
 	if (uavail < cfdata->uncompressed_size) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -1719,7 +1717,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
 		}
 	}
 
-	uavail = cab->xstrm.total_out;
+	uavail = (uint16_t)cab->xstrm.total_out;
 	/*
 	 * Make sure a read pointer advances to next CFDATA.
 	 */
@@ -1791,9 +1789,8 @@ cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 		rbytes -= cbytes;
 
 		if (cfdata->uncompressed_avail == 0 &&
-		    (cab->entry_cffolder->comptype == COMPTYPE_NONE ||
-		     cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||
-			 cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {
+		   (cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||
+		    cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {
 			/* We have not read any data yet. */
 			if (cbytes == cfdata->uncompressed_bytes_remaining) {
 				/* Skip whole current CFDATA. */
@@ -1819,8 +1816,8 @@ cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 				}
 				continue;
 			}
-			cfdata->read_offset += cbytes;
-			cfdata->uncompressed_bytes_remaining -= cbytes;
+			cfdata->read_offset += (uint16_t)cbytes;
+			cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
 			break;
 		} else if (cbytes == 0) {
 			err = cab_next_cfdata(a);
@@ -1844,7 +1841,7 @@ cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 			if (avail <= 0)
 				return (ARCHIVE_FATAL);
 			if (avail > cbytes)
-				avail = cbytes;
+				avail = (ssize_t)cbytes;
 			if (cab_minimum_consume_cfdata(a, avail) < 0)
 				return (ARCHIVE_FATAL);
 			cbytes -= avail;
@@ -1873,8 +1870,8 @@ cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 		else
 			cbytes = cfdata->unconsumed;
 		rbytes -= cbytes; 
-		cfdata->read_offset += cbytes;
-		cfdata->uncompressed_bytes_remaining -= cbytes;
+		cfdata->read_offset += (uint16_t)cbytes;
+		cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
 		cfdata->unconsumed -= cbytes;
 	} else {
 		cbytes = cfdata->uncompressed_avail - cfdata->read_offset;
@@ -1882,8 +1879,8 @@ cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 			if (consumed_bytes < cbytes)
 				cbytes = consumed_bytes;
 			rbytes -= cbytes;
-			cfdata->read_offset += cbytes;
-			cfdata->uncompressed_bytes_remaining -= cbytes;
+			cfdata->read_offset += (uint16_t)cbytes;
+			cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
 		}
 
 		if (cfdata->unconsumed) {
@@ -1894,12 +1891,12 @@ cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
 	}
 	if (cbytes) {
 		/* Compute the sum. */
-		cab_checksum_update(a, cbytes);
+		cab_checksum_update(a, (size_t)cbytes);
 
 		/* Consume as much as the compressor actually used. */
 		__archive_read_consume(a, cbytes);
 		cab->cab_offset += cbytes;
-		cfdata->compressed_bytes_remaining -= cbytes;
+		cfdata->compressed_bytes_remaining -= (uint16_t)cbytes;
 		if (cfdata->compressed_bytes_remaining == 0) {
 			err = cab_checksum_finish(a);
 			if (err < 0)
@@ -1940,10 +1937,10 @@ cab_read_data(struct archive_read *a, const void **buff,
 			    ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA");
 			return (ARCHIVE_FATAL);
 		} else
-			return (bytes_avail);
+			return ((int)bytes_avail);
 	}
 	if (bytes_avail > cab->entry_bytes_remaining)
-		bytes_avail = cab->entry_bytes_remaining;
+		bytes_avail = (ssize_t)cab->entry_bytes_remaining;
 
 	*size = bytes_avail;
 	*offset = cab->entry_offset;
@@ -1952,6 +1949,11 @@ cab_read_data(struct archive_read *a, const void **buff,
 	if (cab->entry_bytes_remaining == 0)
 		cab->end_of_entry = 1;
 	cab->entry_unconsumed = bytes_avail;
+	if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {
+		/* Don't consume more than current entry used. */
+		if (cab->entry_cfdata->unconsumed > cab->entry_unconsumed)
+			cab->entry_cfdata->unconsumed = cab->entry_unconsumed;
+	}
 	return (ARCHIVE_OK);
 }
 
@@ -1967,9 +1969,17 @@ archive_read_format_cab_read_data_skip(struct archive_read *a)
 	if (cab->end_of_archive)
 		return (ARCHIVE_EOF);
 
+	if (!cab->read_data_invoked) {
+		cab->bytes_skipped += cab->entry_bytes_remaining;
+		cab->entry_bytes_remaining = 0;
+		/* This entry is finished and done. */
+		cab->end_of_entry_cleanup = cab->end_of_entry = 1;
+		return (ARCHIVE_OK);
+	}
+
 	if (cab->entry_unconsumed) {
 		/* Consume as much as the compressor actually used. */
-		r = cab_consume_cfdata(a, cab->entry_unconsumed);
+		r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
 		cab->entry_unconsumed = 0;
 		if (r < 0)
 			return (r);
@@ -1991,6 +2001,12 @@ archive_read_format_cab_read_data_skip(struct archive_read *a)
 	if (bytes_skipped < 0)
 		return (ARCHIVE_FATAL);
 
+	/* If the compression type is none(uncompressed), we've already
+	 * consumed data as much as the current entry size. */
+	if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
+	    cab->entry_cfdata != NULL)
+		cab->entry_cfdata->unconsumed = 0;
+
 	/* This entry is finished and done. */
 	cab->end_of_entry_cleanup = cab->end_of_entry = 1;
 	return (ARCHIVE_OK);
@@ -2066,6 +2082,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
 	struct lzx_dec *ds;
 	int slot, w_size, w_slot;
 	int base, footer;
+	int base_inc[18];
 
 	if (strm->ds == NULL) {
 		strm->ds = calloc(1, sizeof(*strm->ds));
@@ -2100,13 +2117,15 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
 		lzx_huffman_free(&(ds->mt));
 	}
 
+	for (footer = 0; footer < 18; footer++)
+		base_inc[footer] = 1 << footer;
 	base = footer = 0;
 	for (slot = 0; slot < w_slot; slot++) {
 		int n;
 		if (footer == 0)
 			base = slot;
 		else
-			base += 1 << footer;
+			base += base_inc[footer];
 		if (footer < 17) {
 			footer = -2;
 			for (n = base; n; n >>= 1)
@@ -2180,11 +2199,11 @@ lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
 	end = b + size - 10;
 	while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {
 		size_t i = b - (unsigned char *)p;
-		long cp, displacement, value;
+		int32_t cp, displacement, value;
 
-		cp = offset + i;
+		cp = (int32_t)(offset + (uint32_t)i);
 		value = archive_le32dec(&b[1]);
-		if (value >= -cp && value < (long)ds->translation_size) {
+		if (value >= -cp && value < (int32_t)ds->translation_size) {
 			if (value >= 0)
 				displacement = value - cp;
 			else
@@ -2222,7 +2241,9 @@ lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
 
 /* Notify how many bits we consumed. */
 #define lzx_br_consume(br, n)	((br)->cache_avail -= (n))
-#define lzx_br_consume_unalined_bits(br) ((br)->cache_avail &= ~0x0f)
+#define lzx_br_consume_unaligned_bits(br) ((br)->cache_avail &= ~0x0f)
+
+#define lzx_br_is_unaligned(br)	((br)->cache_avail & 0x0f)
 
 static const uint32_t cache_masks[] = {
 	0x00000000, 0x00000001, 0x00000003, 0x00000007,
@@ -2349,24 +2370,25 @@ lzx_cleanup_bitstream(struct lzx_stream *strm)
 #define ST_RD_TRANSLATION_SIZE	1
 #define ST_RD_BLOCK_TYPE	2
 #define ST_RD_BLOCK_SIZE	3
-#define ST_RD_R0		4
-#define ST_RD_R1		5
-#define ST_RD_R2		6
-#define ST_COPY_UNCOMP1		7
-#define ST_COPY_UNCOMP2		8
-#define ST_RD_ALIGNED_OFFSET	9
-#define ST_RD_VERBATIM		10
-#define ST_RD_PRE_MAIN_TREE_256	11
-#define ST_MAIN_TREE_256	12
-#define ST_RD_PRE_MAIN_TREE_REM	13
-#define ST_MAIN_TREE_REM	14
-#define ST_RD_PRE_LENGTH_TREE	15
-#define ST_LENGTH_TREE		16
-#define ST_MAIN			17
-#define ST_LENGTH		18
-#define ST_OFFSET		19
-#define ST_REAL_POS		20
-#define ST_COPY			21
+#define ST_RD_ALIGNMENT		4
+#define ST_RD_R0		5
+#define ST_RD_R1		6
+#define ST_RD_R2		7
+#define ST_COPY_UNCOMP1		8
+#define ST_COPY_UNCOMP2		9
+#define ST_RD_ALIGNED_OFFSET	10
+#define ST_RD_VERBATIM		11
+#define ST_RD_PRE_MAIN_TREE_256	12
+#define ST_MAIN_TREE_256	13
+#define ST_RD_PRE_MAIN_TREE_REM	14
+#define ST_MAIN_TREE_REM	15
+#define ST_RD_PRE_LENGTH_TREE	16
+#define ST_LENGTH_TREE		17
+#define ST_MAIN			18
+#define ST_LENGTH		19
+#define ST_OFFSET		20
+#define ST_REAL_POS		21
+#define ST_COPY			22
 
 static int
 lzx_decode(struct lzx_stream *strm, int last)
@@ -2470,12 +2492,25 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
 					ds->state = ST_RD_ALIGNED_OFFSET;
 				break;
 			}
+			/* FALL THROUGH */
+		case ST_RD_ALIGNMENT:
 			/*
 			 * Handle an Uncompressed Block.
 			 */
 			/* Skip padding to align following field on
 			 * 16-bit boundary. */
-			lzx_br_consume_unalined_bits(br);
+			if (lzx_br_is_unaligned(br))
+				lzx_br_consume_unaligned_bits(br);
+			else {
+				if (lzx_br_read_ahead(strm, br, 16))
+					lzx_br_consume(br, 16);
+				else {
+					ds->state = ST_RD_ALIGNMENT;
+					if (last)
+						goto failed;
+					return (ARCHIVE_OK);
+				}
+			}
 			/* Preparation to read repeated offsets R0,R1 and R2. */
 			ds->rbytes_avail = 0;
 			ds->state = ST_RD_R0;
@@ -2500,8 +2535,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
 					lzx_br_consume(br, 16);
 					archive_le16enc(ds->rbytes, u16);
 					ds->rbytes_avail = 2;
-				} else
-					ds->rbytes_avail = 0;
+				}
 				if (ds->rbytes_avail < 4 && ds->br.have_odd) {
 					ds->rbytes[ds->rbytes_avail++] =
 					    ds->br.odd;
@@ -2517,6 +2551,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
 					    *strm->next_in++;
 					strm->avail_in--;
 				}
+				ds->rbytes_avail = 0;
 				if (ds->state == ST_RD_R0) {
 					ds->r0 = archive_le32dec(ds->rbytes);
 					if (ds->r0 < 0)
@@ -2541,8 +2576,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
 			 * Copy bytes form next_in to next_out directly.
 			 */
 			while (ds->block_bytes_avail) {
-				unsigned char *d;
-				int l,ll;
+				int l;
 
 				if (strm->avail_out <= 0)
 					/* Output buffer is empty. */
@@ -2553,24 +2587,23 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
 						goto failed;
 					return (ARCHIVE_OK);
 				}
-				l = ds->block_bytes_avail;
+				l = (int)ds->block_bytes_avail;
 				if (l > ds->w_size - ds->w_pos)
 					l = ds->w_size - ds->w_pos;
 				if (l > strm->avail_out)
 					l = (int)strm->avail_out;
 				if (l > strm->avail_in)
 					l = (int)strm->avail_in;
-				ll = l;
-				d = &(ds->w_buff[ds->w_pos]);
-				while (--l >= 0) {
-					*strm->next_out++ = *strm->next_in;
-					*d++ = *strm->next_in++;
-				}
-				strm->avail_out -= ll;
-				strm->total_out += ll;
-				strm->avail_in -= ll;
-				ds->w_pos = (ds->w_pos + ll) & ds->w_mask;
-				ds->block_bytes_avail -= ll;
+				memcpy(strm->next_out, strm->next_in, l);
+				memcpy(&(ds->w_buff[ds->w_pos]),
+				    strm->next_in, l);
+				strm->next_in += l;
+				strm->avail_in -= l;
+				strm->next_out += l;
+				strm->avail_out -= l;
+				strm->total_out += l;
+				ds->w_pos = (ds->w_pos + l) & ds->w_mask;
+				ds->block_bytes_avail -= l;
 			}
 			/* FALL THROUGH */
 		case ST_COPY_UNCOMP2:
@@ -2716,8 +2749,8 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
 	struct lzx_br bre = ds->br;
 	struct huffman *at = &(ds->at), *lt = &(ds->lt), *mt = &(ds->mt);
 	const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
-	unsigned char *outp = strm->next_out;
-	unsigned char *endp = outp + strm->avail_out;
+	unsigned char *noutp = strm->next_out;
+	unsigned char *endp = noutp + strm->avail_out;
 	unsigned char *w_buff = ds->w_buff;
 	unsigned char *at_bitlen = at->bitlen;
 	unsigned char *lt_bitlen = lt->bitlen;
@@ -2751,10 +2784,10 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
 					ds->position_slot = position_slot;
 					ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
 					ds->w_pos = w_pos;
-					strm->avail_out = endp - outp;
+					strm->avail_out = endp - noutp;
 					return (ARCHIVE_EOF);
 				}
-				if (outp >= endp)
+				if (noutp >= endp)
 					/* Output buffer is empty. */
 					goto next_data;
 
@@ -2788,7 +2821,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
 				w_buff[w_pos] = c;
 				w_pos = (w_pos + 1) & w_mask;
 				/* Store the decoded code to output buffer. */
-				*outp++ = c;
+				*noutp++ = c;
 				block_bytes_avail--;
 			}
 			/*
@@ -2933,22 +2966,22 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
 					if (l > w_size - w_pos)
 						l = w_size - w_pos;
 				}
-				if (outp + l >= endp)
-					l = endp - outp;
+				if (noutp + l >= endp)
+					l = (int)(endp - noutp);
 				s = w_buff + copy_pos;
 				if (l >= 8 && ((copy_pos + l < w_pos)
 				  || (w_pos + l < copy_pos))) {
 					memcpy(w_buff + w_pos, s, l);
-					memcpy(outp, s, l);
+					memcpy(noutp, s, l);
 				} else {
 					unsigned char *d;
 					int li;
 
 					d = w_buff + w_pos;
 					for (li = 0; li < l; li++)
-						outp[li] = d[li] = s[li];
+						noutp[li] = d[li] = s[li];
 				}
-				outp += l;
+				noutp += l;
 				copy_pos = (copy_pos + l) & w_mask;
 				w_pos = (w_pos + l) & w_mask;
 				block_bytes_avail -= l;
@@ -2956,7 +2989,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
 					/* A copy of current pattern ended. */
 					break;
 				copy_len -= l;
-				if (outp >= endp) {
+				if (noutp >= endp) {
 					/* Output buffer is empty. */
 					state = ST_COPY;
 					goto next_data;
@@ -2979,7 +3012,7 @@ next_data:
 	ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
 	ds->state = state;
 	ds->w_pos = w_pos;
-	strm->avail_out = endp - outp;
+	strm->avail_out = endp - noutp;
 	return (ARCHIVE_OK);
 }
 
@@ -3096,7 +3129,7 @@ lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 		hf->bitlen = calloc(len_size,  sizeof(hf->bitlen[0]));
 		if (hf->bitlen == NULL)
 			return (ARCHIVE_FATAL);
-		hf->len_size = len_size;
+		hf->len_size = (int)len_size;
 	} else
 		memset(hf->bitlen, 0, len_size *  sizeof(hf->bitlen[0]));
 	if (hf->tbl == NULL) {
@@ -3104,7 +3137,7 @@ lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 			bits = tbl_bits;
 		else
 			bits = HTBL_BITS;
-		hf->tbl = malloc((1 << bits) * sizeof(hf->tbl[0]));
+		hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0]));
 		if (hf->tbl == NULL)
 			return (ARCHIVE_FATAL);
 		hf->tbl_bits = tbl_bits;
diff --git a/libarchive/archive_read_support_format_cpio.c b/libarchive/archive_read_support_format_cpio.c
index 5ae73d7..819f4a4 100644
--- a/libarchive/archive_read_support_format_cpio.c
+++ b/libarchive/archive_read_support_format_cpio.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2010-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -242,6 +242,7 @@ archive_read_support_format_cpio(struct archive *_a)
 	    archive_read_format_cpio_read_header,
 	    archive_read_format_cpio_read_data,
 	    archive_read_format_cpio_skip,
+	    NULL,
 	    archive_read_format_cpio_cleanup);
 
 	if (r != ARCHIVE_OK)
@@ -325,7 +326,7 @@ archive_read_format_cpio_options(struct archive_read *a,
 	if (strcmp(key, "compat-2x")  == 0) {
 		/* Handle filnames as libarchive 2.x */
 		cpio->init_default_conversion = (val != NULL)?1:0;
-		ret = ARCHIVE_OK;
+		return (ARCHIVE_OK);
 	} else if (strcmp(key, "hdrcharset")  == 0) {
 		if (val == NULL || val[0] == 0)
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -339,11 +340,13 @@ archive_read_format_cpio_options(struct archive_read *a,
 			else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "cpio: unknown keyword ``%s''", key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 static int
@@ -396,11 +399,12 @@ archive_read_format_cpio_read_header(struct archive_read *a,
 
 	/* If this is a symlink, read the link contents. */
 	if (archive_entry_filetype(entry) == AE_IFLNK) {
-		h = __archive_read_ahead(a, cpio->entry_bytes_remaining, NULL);
+		h = __archive_read_ahead(a,
+			(size_t)cpio->entry_bytes_remaining, NULL);
 		if (h == NULL)
 			return (ARCHIVE_FATAL);
 		if (archive_entry_copy_symlink_l(entry, (const char *)h,
-		    cpio->entry_bytes_remaining, sconv) != 0) {
+		    (size_t)cpio->entry_bytes_remaining, sconv) != 0) {
 			if (errno == ENOMEM) {
 				archive_set_error(&a->archive, ENOMEM,
 				    "Can't allocate memory for Linkname");
@@ -456,7 +460,7 @@ archive_read_format_cpio_read_data(struct archive_read *a,
 		if (bytes_read <= 0)
 			return (ARCHIVE_FATAL);
 		if (bytes_read > cpio->entry_bytes_remaining)
-			bytes_read = cpio->entry_bytes_remaining;
+			bytes_read = (ssize_t)cpio->entry_bytes_remaining;
 		*size = bytes_read;
 		cpio->entry_bytes_unconsumed = bytes_read;
 		*offset = cpio->entry_offset;
@@ -601,17 +605,23 @@ header_newc(struct archive_read *a, struct cpio *cpio,
 		/* TODO: Abort here? */
 	}
 
-	archive_entry_set_devmajor(entry, atol16(header + newc_devmajor_offset, newc_devmajor_size));
-	archive_entry_set_devminor(entry, atol16(header + newc_devminor_offset, newc_devminor_size));
+	archive_entry_set_devmajor(entry,
+		(dev_t)atol16(header + newc_devmajor_offset, newc_devmajor_size));
+	archive_entry_set_devminor(entry, 
+		(dev_t)atol16(header + newc_devminor_offset, newc_devminor_size));
 	archive_entry_set_ino(entry, atol16(header + newc_ino_offset, newc_ino_size));
-	archive_entry_set_mode(entry, atol16(header + newc_mode_offset, newc_mode_size));
+	archive_entry_set_mode(entry, 
+		(mode_t)atol16(header + newc_mode_offset, newc_mode_size));
 	archive_entry_set_uid(entry, atol16(header + newc_uid_offset, newc_uid_size));
 	archive_entry_set_gid(entry, atol16(header + newc_gid_offset, newc_gid_size));
-	archive_entry_set_nlink(entry, atol16(header + newc_nlink_offset, newc_nlink_size));
-	archive_entry_set_rdevmajor(entry, atol16(header + newc_rdevmajor_offset, newc_rdevmajor_size));
-	archive_entry_set_rdevminor(entry, atol16(header + newc_rdevminor_offset, newc_rdevminor_size));
+	archive_entry_set_nlink(entry,
+		(unsigned int)atol16(header + newc_nlink_offset, newc_nlink_size));
+	archive_entry_set_rdevmajor(entry,
+		(dev_t)atol16(header + newc_rdevmajor_offset, newc_rdevmajor_size));
+	archive_entry_set_rdevminor(entry,
+		(dev_t)atol16(header + newc_rdevminor_offset, newc_rdevminor_size));
 	archive_entry_set_mtime(entry, atol16(header + newc_mtime_offset, newc_mtime_size), 0);
-	*namelength = atol16(header + newc_namesize_offset, newc_namesize_size);
+	*namelength = (size_t)atol16(header + newc_namesize_offset, newc_namesize_size);
 	/* Pad name to 2 more than a multiple of 4. */
 	*name_pad = (2 - *namelength) & 3;
 
@@ -765,15 +775,19 @@ header_odc(struct archive_read *a, struct cpio *cpio,
 	/* Parse out octal fields. */
 	header = (const char *)h;
 
-	archive_entry_set_dev(entry, atol8(header + odc_dev_offset, odc_dev_size));
+	archive_entry_set_dev(entry, 
+		(dev_t)atol8(header + odc_dev_offset, odc_dev_size));
 	archive_entry_set_ino(entry, atol8(header + odc_ino_offset, odc_ino_size));
-	archive_entry_set_mode(entry, atol8(header + odc_mode_offset, odc_mode_size));
+	archive_entry_set_mode(entry, 
+		(mode_t)atol8(header + odc_mode_offset, odc_mode_size));
 	archive_entry_set_uid(entry, atol8(header + odc_uid_offset, odc_uid_size));
 	archive_entry_set_gid(entry, atol8(header + odc_gid_offset, odc_gid_size));
-	archive_entry_set_nlink(entry, atol8(header + odc_nlink_offset, odc_nlink_size));
-	archive_entry_set_rdev(entry, atol8(header + odc_rdev_offset, odc_rdev_size));
+	archive_entry_set_nlink(entry, 
+		(unsigned int)atol8(header + odc_nlink_offset, odc_nlink_size));
+	archive_entry_set_rdev(entry,
+		(dev_t)atol8(header + odc_rdev_offset, odc_rdev_size));
 	archive_entry_set_mtime(entry, atol8(header + odc_mtime_offset, odc_mtime_size), 0);
-	*namelength = atol8(header + odc_namesize_offset, odc_namesize_size);
+	*namelength = (size_t)atol8(header + odc_namesize_offset, odc_namesize_size);
 	*name_pad = 0; /* No padding of filename. */
 
 	/*
@@ -814,15 +828,19 @@ header_afiol(struct archive_read *a, struct cpio *cpio,
 	/* Parse out octal fields. */
 	header = (const char *)h;
 
-	archive_entry_set_dev(entry, atol16(header + afiol_dev_offset, afiol_dev_size));
+	archive_entry_set_dev(entry, 
+		(dev_t)atol16(header + afiol_dev_offset, afiol_dev_size));
 	archive_entry_set_ino(entry, atol16(header + afiol_ino_offset, afiol_ino_size));
-	archive_entry_set_mode(entry, atol8(header + afiol_mode_offset, afiol_mode_size));
+	archive_entry_set_mode(entry,
+		(mode_t)atol8(header + afiol_mode_offset, afiol_mode_size));
 	archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size));
 	archive_entry_set_gid(entry, atol16(header + afiol_gid_offset, afiol_gid_size));
-	archive_entry_set_nlink(entry, atol16(header + afiol_nlink_offset, afiol_nlink_size));
-	archive_entry_set_rdev(entry, atol16(header + afiol_rdev_offset, afiol_rdev_size));
+	archive_entry_set_nlink(entry,
+		(unsigned int)atol16(header + afiol_nlink_offset, afiol_nlink_size));
+	archive_entry_set_rdev(entry,
+		(dev_t)atol16(header + afiol_rdev_offset, afiol_rdev_size));
 	archive_entry_set_mtime(entry, atol16(header + afiol_mtime_offset, afiol_mtime_size), 0);
-	*namelength = atol16(header + afiol_namesize_offset, afiol_namesize_size);
+	*namelength = (size_t)atol16(header + afiol_namesize_offset, afiol_namesize_size);
 	*name_pad = 0; /* No padding of filename. */
 
 	cpio->entry_bytes_remaining =
diff --git a/libarchive/archive_read_support_format_empty.c b/libarchive/archive_read_support_format_empty.c
index 3dc2196..3660738 100644
--- a/libarchive/archive_read_support_format_empty.c
+++ b/libarchive/archive_read_support_format_empty.c
@@ -53,6 +53,7 @@ archive_read_support_format_empty(struct archive *_a)
 	    archive_read_format_empty_read_header,
 	    archive_read_format_empty_read_data,
 	    NULL,
+	    NULL,
 	    NULL);
 
 	return (r);
diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c
index 4f68ef8..914bc71 100644
--- a/libarchive/archive_read_support_format_iso9660.c
+++ b/libarchive/archive_read_support_format_iso9660.c
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
  * Copyright (c) 2009 Andreas Henriksson <andreas at fatal.se>
- * Copyright (c) 2009-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -374,6 +374,8 @@ struct iso9660 {
 	size_t		 utf16be_path_len;
 	unsigned char *utf16be_previous_path;
 	size_t		 utf16be_previous_path_len;
+	/* Null buufer used in bidder to improve its performance. */
+	unsigned char	 null[2048];
 };
 
 static int	archive_read_format_iso9660_bid(struct archive_read *, int);
@@ -475,6 +477,7 @@ archive_read_support_format_iso9660(struct archive *_a)
 	    archive_read_format_iso9660_read_header,
 	    archive_read_format_iso9660_read_data,
 	    archive_read_format_iso9660_read_data_skip,
+	    NULL,
 	    archive_read_format_iso9660_cleanup);
 
 	if (r != ARCHIVE_OK) {
@@ -588,6 +591,23 @@ archive_read_format_iso9660_options(struct archive_read *a,
 }
 
 static int
+isNull(struct iso9660 *iso9660, const unsigned char *h, unsigned offset,
+unsigned bytes)
+{
+
+	while (bytes >= sizeof(iso9660->null)) {
+		if (!memcmp(iso9660->null, h + offset, sizeof(iso9660->null)))
+			return (0);
+		offset += sizeof(iso9660->null);
+		bytes -= sizeof(iso9660->null);
+	}
+	if (bytes)
+		return memcmp(iso9660->null, h + offset, bytes) == 0;
+	else
+		return (1);
+}
+
+static int
 isBootRecord(struct iso9660 *iso9660, const unsigned char *h)
 {
 	(void)iso9660; /* UNUSED */
@@ -632,8 +652,6 @@ isVolumePartition(struct iso9660 *iso9660, const unsigned char *h)
 static int
 isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
 {
-	int i;
-
 	(void)iso9660; /* UNUSED */
 
 	/* Type of the Volume Descriptor Set Terminator must be 255. */
@@ -645,9 +663,8 @@ isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
 		return (0);
 
 	/* Reserved field must be 0. */
-	for (i = 7; i < 2048; ++i)
-		if (h[i] != 0)
-			return (0);
+	if (!isNull(iso9660, h, 7, 2048-7))
+		return (0);
 
 	return (1);
 }
@@ -708,7 +725,6 @@ isSVD(struct iso9660 *iso9660, const unsigned char *h)
 	ssize_t logical_block_size;
 	int32_t volume_block;
 	int32_t location;
-	int i;
 
 	(void)iso9660; /* UNUSED */
 
@@ -717,15 +733,12 @@ isSVD(struct iso9660 *iso9660, const unsigned char *h)
 		return (0);
 
 	/* Reserved field must be 0. */
-	for (i = 0; i < SVD_reserved1_size; ++i)
-		if (h[SVD_reserved1_offset + i] != 0)
-			return (0);
-	for (i = 0; i < SVD_reserved2_size; ++i)
-		if (h[SVD_reserved2_offset + i] != 0)
-			return (0);
-	for (i = 0; i < SVD_reserved3_size; ++i)
-		if (h[SVD_reserved3_offset + i] != 0)
-			return (0);
+	if (!isNull(iso9660, h, SVD_reserved1_offset, SVD_reserved1_size))
+		return (0);
+	if (!isNull(iso9660, h, SVD_reserved2_offset, SVD_reserved2_size))
+		return (0);
+	if (!isNull(iso9660, h, SVD_reserved3_offset, SVD_reserved3_size))
+		return (0);
 
 	/* File structure version must be 1 for ISO9660/ECMA119. */
 	if (h[SVD_file_structure_version_offset] != 1)
@@ -771,7 +784,6 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
 	ssize_t logical_block_size;
 	int32_t volume_block;
 	int32_t location;
-	int i;
 
 	(void)iso9660; /* UNUSED */
 
@@ -788,14 +800,12 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
 		return (0);
 
 	/* Reserved field must be 0. */
-	for (i = 0; i < PVD_reserved2_size; ++i)
-		if (h[PVD_reserved2_offset + i] != 0)
-			return (0);
+	if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
+		return (0);
 
 	/* Reserved field must be 0. */
-	for (i = 0; i < PVD_reserved3_size; ++i)
-		if (h[PVD_reserved3_offset + i] != 0)
-			return (0);
+	if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
+		return (0);
 
 	/* Logical block size must be > 0. */
 	/* I've looked at Ecma 119 and can't find any stronger
@@ -830,14 +840,12 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
 		return (0);
 
 	/* Reserved field must be 0. */
-	for (i = 0; i < PVD_reserved4_size; ++i)
-		if (h[PVD_reserved4_offset + i] != 0)
-			return (0);
+	if (!isNull(iso9660, h, PVD_reserved4_offset, PVD_reserved4_size))
+		return (0);
 
 	/* Reserved field must be 0. */
-	for (i = 0; i < PVD_reserved5_size; ++i)
-		if (h[PVD_reserved5_offset + i] != 0)
-			return (0);
+	if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
+		return (0);
 
 	/* Read Root Directory Record in Volume Descriptor. */
 	p = h + PVD_root_directory_record_offset;
@@ -869,14 +877,12 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
 		return (0);
 
 	/* Reserved field must be 0. */
-	for (i = 0; i < PVD_reserved2_size; ++i)
-		if (h[PVD_reserved2_offset + i] != 0)
-			return (0);
+	if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
+		return (0);
 
 	/* Reserved field must be 0. */
-	for (i = 0; i < PVD_reserved3_size; ++i)
-		if (h[PVD_reserved3_offset + i] != 0)
-			return (0);
+	if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
+		return (0);
 
 	/* Logical block size must be > 0. */
 	/* I've looked at Ecma 119 and can't find any stronger
@@ -919,9 +925,8 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
 			return (0);
 
 	/* Reserved field must be 0. */
-	for (i = 0; i < PVD_reserved5_size; ++i)
-		if (h[PVD_reserved5_offset + i] != 0)
-			return (0);
+	if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
+		return (0);
 
 	/* XXX TODO: Check other values for sanity; reject more
 	 * malformed PVDs. XXX */
@@ -934,8 +939,10 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
 	if (!iso9660->primary.location) {
 		iso9660->logical_block_size = logical_block_size;
 		iso9660->volume_block = volume_block;
-		iso9660->volume_size = logical_block_size * (uint64_t)volume_block;
-		iso9660->primary.location = archive_le32dec(p + DR_extent_offset);
+		iso9660->volume_size =
+		    logical_block_size * (uint64_t)volume_block;
+		iso9660->primary.location =
+		    archive_le32dec(p + DR_extent_offset);
 		iso9660->primary.size = archive_le32dec(p + DR_size_offset);
 	}
 
@@ -951,6 +958,12 @@ read_children(struct archive_read *a, struct file_info *parent)
 	size_t step, skip_size;
 
 	iso9660 = (struct iso9660 *)(a->format->data);
+	/* flush any remaining bytes from the last round to ensure
+	 * we're positioned */
+	if (iso9660->entry_bytes_unconsumed) {
+		__archive_read_consume(a, iso9660->entry_bytes_unconsumed);
+		iso9660->entry_bytes_unconsumed = 0;
+	}
 	if (iso9660->current_position > parent->offset) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "Ignoring out-of-order directory (%s) %jd > %jd",
@@ -975,8 +988,8 @@ read_children(struct archive_read *a, struct file_info *parent)
 		iso9660->current_position = parent->offset;
 	}
 
-	step = ((parent->size + iso9660->logical_block_size -1) /
-	    iso9660->logical_block_size) * iso9660->logical_block_size;
+	step = (size_t)(((parent->size + iso9660->logical_block_size -1) /
+	    iso9660->logical_block_size) * iso9660->logical_block_size);
 	b = __archive_read_ahead(a, step, NULL);
 	if (b == NULL) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -1060,101 +1073,112 @@ read_children(struct archive_read *a, struct file_info *parent)
 }
 
 static int
-archive_read_format_iso9660_read_header(struct archive_read *a,
-    struct archive_entry *entry)
+choose_volume(struct archive_read *a, struct iso9660 *iso9660)
 {
-	struct iso9660 *iso9660;
 	struct file_info *file;
-	int r, rd_r = ARCHIVE_OK;
-
-	iso9660 = (struct iso9660 *)(a->format->data);
+	int64_t skipsize;
+	struct vd *vd;
+	const void *block;
+	char seenJoliet;
 
-	if (!a->archive.archive_format) {
-		a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
-		a->archive.archive_format_name = "ISO9660";
+	vd = &(iso9660->primary);
+	if (!iso9660->opt_support_joliet)
+		iso9660->seenJoliet = 0;
+	if (iso9660->seenJoliet &&
+		vd->location > iso9660->joliet.location)
+		/* This condition is unlikely; by way of caution. */
+		vd = &(iso9660->joliet);
+
+	skipsize = LOGICAL_BLOCK_SIZE * vd->location;
+	skipsize = __archive_read_consume(a, skipsize);
+	if (skipsize < 0)
+		return ((int)skipsize);
+	iso9660->current_position = skipsize;
+
+	block = __archive_read_ahead(a, vd->size, NULL);
+	if (block == NULL) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+		    "Failed to read full block when scanning "
+		    "ISO9660 directory list");
+		return (ARCHIVE_FATAL);
 	}
 
-	if (iso9660->current_position == 0) {
-		int64_t skipsize;
-		struct vd *vd;
-		const void *block;
-		char seenJoliet;
-
-		vd = &(iso9660->primary);
-		if (!iso9660->opt_support_joliet)
-			iso9660->seenJoliet = 0;
-		if (iso9660->seenJoliet &&
-			vd->location > iso9660->joliet.location)
-			/* This condition is unlikely; by way of caution. */
-			vd = &(iso9660->joliet);
+	/*
+	 * While reading Root Directory, flag seenJoliet must be zero to
+	 * avoid converting special name 0x00(Current Directory) and
+	 * next byte to UCS2.
+	 */
+	seenJoliet = iso9660->seenJoliet;/* Save flag. */
+	iso9660->seenJoliet = 0;
+	file = parse_file_info(a, NULL, block);
+	if (file == NULL)
+		return (ARCHIVE_FATAL);
+	iso9660->seenJoliet = seenJoliet;
 
+	/*
+	 * If the iso image has both RockRidge and Joliet, we preferentially
+	 * use RockRidge Extensions rather than Joliet ones.
+	 */
+	if (vd == &(iso9660->primary) && iso9660->seenRockridge
+	    && iso9660->seenJoliet)
+		iso9660->seenJoliet = 0;
+
+	if (vd == &(iso9660->primary) && !iso9660->seenRockridge
+	    && iso9660->seenJoliet) {
+		/* Switch reading data from primary to joliet. */
+		vd = &(iso9660->joliet);
 		skipsize = LOGICAL_BLOCK_SIZE * vd->location;
+		skipsize -= iso9660->current_position;
 		skipsize = __archive_read_consume(a, skipsize);
 		if (skipsize < 0)
 			return ((int)skipsize);
-		iso9660->current_position = skipsize;
+		iso9660->current_position += skipsize;
 
 		block = __archive_read_ahead(a, vd->size, NULL);
 		if (block == NULL) {
-			archive_set_error(&a->archive,
-			    ARCHIVE_ERRNO_MISC,
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			    "Failed to read full block when scanning "
 			    "ISO9660 directory list");
 			return (ARCHIVE_FATAL);
 		}
-
-		/*
-		 * While reading Root Directory, flag seenJoliet
-		 * must be zero to avoid converting special name
-		 * 0x00(Current Directory) and next byte to UCS2.
-		 */
-		seenJoliet = iso9660->seenJoliet;/* Save flag. */
 		iso9660->seenJoliet = 0;
 		file = parse_file_info(a, NULL, block);
 		if (file == NULL)
 			return (ARCHIVE_FATAL);
 		iso9660->seenJoliet = seenJoliet;
-		if (vd == &(iso9660->primary) && iso9660->seenRockridge
-		    && iso9660->seenJoliet)
-			/*
-			 * If iso image has RockRidge and Joliet,
-			 * we use RockRidge Extensions.
-			 */
-			iso9660->seenJoliet = 0;
-		if (vd == &(iso9660->primary) && !iso9660->seenRockridge
-		    && iso9660->seenJoliet) {
-			/* Switch reading data from primary to joliet. */ 
-			vd = &(iso9660->joliet);
-			skipsize = LOGICAL_BLOCK_SIZE * vd->location;
-			skipsize -= iso9660->current_position;
-			skipsize = __archive_read_consume(a, skipsize);
-			if (skipsize < 0)
-				return ((int)skipsize);
-			iso9660->current_position += skipsize;
-
-			block = __archive_read_ahead(a, vd->size, NULL);
-			if (block == NULL) {
-				archive_set_error(&a->archive,
-				    ARCHIVE_ERRNO_MISC,
-				    "Failed to read full block when scanning "
-				    "ISO9660 directory list");
-				return (ARCHIVE_FATAL);
-			}
-			iso9660->seenJoliet = 0;
-			file = parse_file_info(a, NULL, block);
-			if (file == NULL)
-				return (ARCHIVE_FATAL);
-			iso9660->seenJoliet = seenJoliet;
-		}
-		/* Store the root directory in the pending list. */
-		if (add_entry(a, iso9660, file) != ARCHIVE_OK)
-			return (ARCHIVE_FATAL);
-		if (iso9660->seenRockridge) {
-			a->archive.archive_format =
-			    ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
-			a->archive.archive_format_name =
-			    "ISO9660 with Rockridge extensions";
-		}
+	}
+
+	/* Store the root directory in the pending list. */
+	if (add_entry(a, iso9660, file) != ARCHIVE_OK)
+		return (ARCHIVE_FATAL);
+	if (iso9660->seenRockridge) {
+		a->archive.archive_format = ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
+		a->archive.archive_format_name =
+		    "ISO9660 with Rockridge extensions";
+	}
+
+	return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_iso9660_read_header(struct archive_read *a,
+    struct archive_entry *entry)
+{
+	struct iso9660 *iso9660;
+	struct file_info *file;
+	int r, rd_r = ARCHIVE_OK;
+
+	iso9660 = (struct iso9660 *)(a->format->data);
+
+	if (!a->archive.archive_format) {
+		a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
+		a->archive.archive_format_name = "ISO9660";
+	}
+
+	if (iso9660->current_position == 0) {
+		r = choose_volume(a, iso9660);
+		if (r != ARCHIVE_OK)
+			return (r);
 	}
 
 	file = NULL;/* Eliminate a warning. */
@@ -1227,14 +1251,14 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
 	}
 
 	iso9660->entry_bytes_remaining = file->size;
-	iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */
+	/* Offset for sparse-file-aware clients. */
+	iso9660->entry_sparse_offset = 0;
 
 	if (file->offset + file->size > iso9660->volume_size) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "File is beyond end-of-media: %s",
 		    archive_entry_pathname(entry));
 		iso9660->entry_bytes_remaining = 0;
-		iso9660->entry_sparse_offset = 0;
 		return (ARCHIVE_WARN);
 	}
 
@@ -1286,36 +1310,33 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
 			    iso9660->previous_pathname.s);
 		archive_entry_unset_size(entry);
 		iso9660->entry_bytes_remaining = 0;
-		iso9660->entry_sparse_offset = 0;
 		return (rd_r);
 	}
 
-	/* Except for the hardlink case above, if the offset of the
-	 * next entry is before our current position, we can't seek
-	 * backwards to extract it, so issue a warning.  Note that
-	 * this can only happen if this entry was added to the heap
-	 * after we passed this offset, that is, only if the directory
-	 * mentioning this entry is later than the body of the entry.
-	 * Such layouts are very unusual; most ISO9660 writers lay out
-	 * and record all directory information first, then store
-	 * all file bodies. */
-	/* TODO: Someday, libarchive's I/O core will support optional
-	 * seeking.  When that day comes, this code should attempt to
-	 * seek and only return the error if the seek fails.  That
-	 * will give us support for whacky ISO images that require
-	 * seeking while retaining the ability to read almost all ISO
-	 * images in a streaming fashion. */
 	if ((file->mode & AE_IFMT) != AE_IFDIR &&
 	    file->offset < iso9660->current_position) {
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "Ignoring out-of-order file @%jx (%s) %jd < %jd",
-		    (intmax_t)file->number,
-		    iso9660->pathname.s,
-		    (intmax_t)file->offset,
-		    (intmax_t)iso9660->current_position);
-		iso9660->entry_bytes_remaining = 0;
-		iso9660->entry_sparse_offset = 0;
-		return (ARCHIVE_WARN);
+		int64_t r64;
+
+		r64 = __archive_read_seek(a, file->offset, SEEK_SET);
+		if (r64 != (int64_t)file->offset) {
+			/* We can't seek backwards to extract it, so issue
+			 * a warning.  Note that this can only happen if
+			 * this entry was added to the heap after we passed
+			 * this offset, that is, only if the directory
+			 * mentioning this entry is later than the body of
+			 * the entry. Such layouts are very unusual; most
+			 * ISO9660 writers lay out and record all directory
+			 * information first, then store all file bodies. */
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Ignoring out-of-order file @%jx (%s) %jd < %jd",
+			    (intmax_t)file->number,
+			    iso9660->pathname.s,
+			    (intmax_t)file->offset,
+			    (intmax_t)iso9660->current_position);
+			iso9660->entry_bytes_remaining = 0;
+			return (ARCHIVE_WARN);
+		}
+		iso9660->current_position = (uint64_t)r64;
 	}
 
 	/* Initialize zisofs variables. */
@@ -1356,7 +1377,6 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
 		archive_entry_set_nlink(entry, 2 + file->subdirs);
 		/* Directory data has been read completely. */
 		iso9660->entry_bytes_remaining = 0;
-		iso9660->entry_sparse_offset = 0;
 	}
 
 	if (rd_r != ARCHIVE_OK)
@@ -1397,7 +1417,7 @@ zisofs_read_data(struct archive_read *a,
 		return (ARCHIVE_FATAL);
 	}
 	if (bytes_read > iso9660->entry_bytes_remaining)
-		bytes_read = iso9660->entry_bytes_remaining;
+		bytes_read = (ssize_t)iso9660->entry_bytes_remaining;
 	avail = bytes_read;
 	uncompressed_size = 0;
 
@@ -1405,9 +1425,9 @@ zisofs_read_data(struct archive_read *a,
 		size_t ceil, xsize;
 
 		/* Allocate block pointers buffer. */
-		ceil = (zisofs->pz_uncompressed_size +
-			(1LL << zisofs->pz_log2_bs) - 1)
-			>> zisofs->pz_log2_bs;
+		ceil = (size_t)((zisofs->pz_uncompressed_size +
+			(((int64_t)1) << zisofs->pz_log2_bs) - 1)
+			>> zisofs->pz_log2_bs);
 		xsize = (ceil + 1) * 4;
 		if (zisofs->block_pointers_alloc < xsize) {
 			size_t alloc;
@@ -1426,7 +1446,7 @@ zisofs_read_data(struct archive_read *a,
 		zisofs->block_pointers_size = xsize;
 
 		/* Allocate uncompressed data buffer. */
-		xsize = 1UL << zisofs->pz_log2_bs;
+		xsize = (size_t)1UL << zisofs->pz_log2_bs;
 		if (zisofs->uncompressed_buffer_size < xsize) {
 			if (zisofs->uncompressed_buffer != NULL)
 				free(zisofs->uncompressed_buffer);
@@ -1563,9 +1583,10 @@ zisofs_read_data(struct archive_read *a,
 		if (avail > zisofs->block_avail)
 			zisofs->stream.avail_in = zisofs->block_avail;
 		else
-			zisofs->stream.avail_in = avail;
+			zisofs->stream.avail_in = (uInt)avail;
 		zisofs->stream.next_out = zisofs->uncompressed_buffer;
-		zisofs->stream.avail_out = zisofs->uncompressed_buffer_size;
+		zisofs->stream.avail_out =
+		    (uInt)zisofs->uncompressed_buffer_size;
 
 		r = inflate(&zisofs->stream, 0);
 		switch (r) {
@@ -1580,7 +1601,7 @@ zisofs_read_data(struct archive_read *a,
 		uncompressed_size =
 		    zisofs->uncompressed_buffer_size - zisofs->stream.avail_out;
 		avail -= zisofs->stream.next_in - p;
-		zisofs->block_avail -= zisofs->stream.next_in - p;
+		zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);
 	}
 next_data:
 	bytes_read -= avail;
@@ -1590,7 +1611,7 @@ next_data:
 	iso9660->entry_sparse_offset += uncompressed_size;
 	iso9660->entry_bytes_remaining -= bytes_read;
 	iso9660->current_position += bytes_read;
-	zisofs->pz_offset += bytes_read;
+	zisofs->pz_offset += (uint32_t)bytes_read;
 	iso9660->entry_bytes_unconsumed += bytes_read;
 
 	return (ARCHIVE_OK);
@@ -1671,7 +1692,7 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
 	if (*buff == NULL)
 		return (ARCHIVE_FATAL);
 	if (bytes_read > iso9660->entry_bytes_remaining)
-		bytes_read = iso9660->entry_bytes_remaining;
+		bytes_read = (ssize_t)iso9660->entry_bytes_remaining;
 	*size = bytes_read;
 	*offset = iso9660->entry_sparse_offset;
 	iso9660->entry_sparse_offset += bytes_read;
@@ -1756,7 +1777,8 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
 	 */
 	if (location > 0 &&
 	    (location + ((fsize + iso9660->logical_block_size -1)
-	       / iso9660->logical_block_size)) > iso9660->volume_block) {
+	       / iso9660->logical_block_size))
+			> (uint32_t)iso9660->volume_block) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "Invalid location of extent of file");
 		return (NULL);
@@ -1872,9 +1894,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
 	if (iso9660->opt_support_rockridge) {
 		if (parent == NULL && rr_end - rr_start >= 7) {
 			p = rr_start;
-			if (p[0] == 'S' && p[1] == 'P'
-			    && p[2] == 7 && p[3] == 1
-			    && p[4] == 0xBE && p[5] == 0xEF) {
+			if (memcmp(p, "SP\x07\x01\xbe\xef", 6) == 0) {
 				/*
 				 * SP extension stores the suspOffset
 				 * (Number of bytes to skip between
@@ -1907,6 +1927,19 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
 				free(file);
 				return (NULL);
 			}
+			/*
+			 * A file size of symbolic link files in ISO images
+			 * made by makefs is not zero and its location is
+			 * the same as those of next regular file. That is
+			 * the same as hard like file and it causes unexpected
+			 * error. 
+			 */
+			if (file->size > 0 &&
+			    (file->mode & AE_IFMT) == AE_IFLNK) {
+				file->size = 0;
+				file->number = -1;
+				file->offset = -1;
+			}
 		} else
 			/* If there isn't SUSP, disable parsing
 			 * rock ridge extensions. */
@@ -1921,6 +1954,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
 	if (iso9660->seenRockridge) {
 		if (parent != NULL && parent->parent == NULL &&
 		    (flags & 0x02) && iso9660->rr_moved == NULL &&
+		    file->name.s &&
 		    (strcmp(file->name.s, "rr_moved") == 0 ||
 		     strcmp(file->name.s, ".rr_moved") == 0)) {
 			iso9660->rr_moved = file;
@@ -2053,14 +2087,9 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
 		int data_length = p[2] - 4;
 		int version = p[3];
 
-		/*
-		 * Yes, each 'if' here does test p[0] again.
-		 * Otherwise, the fall-through handling to catch
-		 * unsupported extensions doesn't work.
-		 */
 		switch(p[0]) {
 		case 'C':
-			if (p[0] == 'C' && p[1] == 'E') {
+			if (p[1] == 'E') {
 				if (version == 1 && data_length == 24) {
 					/*
 					 * CE extension comprises:
@@ -2078,53 +2107,42 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
 					    != ARCHIVE_OK)
 						return (ARCHIVE_FATAL);
 				}
-				break;
 			}
-			if (p[0] == 'C' && p[1] == 'L') {
+			else if (p[1] == 'L') {
 				if (version == 1 && data_length == 8) {
 					file->cl_offset = (uint64_t)
 					    iso9660->logical_block_size *
 					    (uint64_t)archive_le32dec(data);
 					iso9660->seenRockridge = 1;
 				}
-				break;
 			}
-			/* FALLTHROUGH */
+			break;
 		case 'N':
-			if (p[0] == 'N' && p[1] == 'M') {
+			if (p[1] == 'M') {
 				if (version == 1) {
 					parse_rockridge_NM1(file,
 					    data, data_length);
 					iso9660->seenRockridge = 1;
 				}
-				break;
 			}
-			/* FALLTHROUGH */
+			break;
 		case 'P':
-			if (p[0] == 'P' && p[1] == 'D') {
-				/*
-				 * PD extension is padding;
-				 * contents are always ignored.
-				 */
-				break;
-			}
-			if (p[0] == 'P' && p[1] == 'L') {
-				/*
-				 * PL extension won't appear;
-				 * contents are always ignored.
-				 */
-				break;
-			}
-			if (p[0] == 'P' && p[1] == 'N') {
+			/*
+			 * PD extension is padding;
+			 * contents are always ignored.
+			 *
+			 * PL extension won't appear;
+			 * contents are always ignored.
+			 */
+			if (p[1] == 'N') {
 				if (version == 1 && data_length == 16) {
 					file->rdev = toi(data,4);
 					file->rdev <<= 32;
 					file->rdev |= toi(data + 8, 4);
 					iso9660->seenRockridge = 1;
 				}
-				break;
 			}
-			if (p[0] == 'P' && p[1] == 'X') {
+			else if (p[1] == 'X') {
 				/*
 				 * PX extension comprises:
 				 *   8 bytes for mode,
@@ -2151,35 +2169,31 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
 						    = toi(data + 32, 4);
 					iso9660->seenRockridge = 1;
 				}
-				break;
 			}
-			/* FALLTHROUGH */
+			break;
 		case 'R':
-			if (p[0] == 'R' && p[1] == 'E' && version == 1) {
+			if (p[1] == 'E' && version == 1) {
 				file->re = 1;
 				iso9660->seenRockridge = 1;
-				break;
 			}
-			if (p[0] == 'R' && p[1] == 'R' && version == 1) {
+			else if (p[1] == 'R' && version == 1) {
 				/*
 				 * RR extension comprises:
 				 *    one byte flag value
 				 * This extension is obsolete,
 				 * so contents are always ignored.
 				 */
-				break;
 			}
-			/* FALLTHROUGH */
+			break;
 		case 'S':
-			if (p[0] == 'S' && p[1] == 'L') {
+			if (p[1] == 'L') {
 				if (version == 1) {
 					parse_rockridge_SL1(file,
 					    data, data_length);
 					iso9660->seenRockridge = 1;
 				}
-				break;
 			}
-			if (p[0] == 'S' && p[1] == 'T'
+			else if (p[1] == 'T'
 			    && data_length == 0 && version == 1) {
 				/*
 				 * ST extension marks end of this
@@ -2194,32 +2208,27 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
 				iso9660->seenRockridge = 0;
 				return (ARCHIVE_OK);
 			}
+			break;
 		case 'T':
-			if (p[0] == 'T' && p[1] == 'F') {
+			if (p[1] == 'F') {
 				if (version == 1) {
 					parse_rockridge_TF1(file,
 					    data, data_length);
 					iso9660->seenRockridge = 1;
 				}
-				break;
 			}
-			/* FALLTHROUGH */
+			break;
 		case 'Z':
-			if (p[0] == 'Z' && p[1] == 'F') {
+			if (p[1] == 'F') {
 				if (version == 1)
 					parse_rockridge_ZF1(file,
 					    data, data_length);
-				break;
 			}
-			/* FALLTHROUGH */
+			break;
 		default:
-			/* The FALLTHROUGHs above leave us here for
-			 * any unsupported extension. */
 			break;
 		}
 
-
-
 		p += p[2];
 	}
 	return (ARCHIVE_OK);
@@ -2241,7 +2250,7 @@ register_CE(struct archive_read *a, int32_t location,
 	    offset >= file->offset) ||
 	    offset < iso9660->current_position ||
 	    (((uint64_t)file->ce_offset) + file->ce_size)
-	      > iso9660->logical_block_size ||
+	      > (uint64_t)iso9660->logical_block_size ||
 	    offset + file->ce_offset + file->ce_size
 		  > iso9660->volume_size) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -2263,7 +2272,7 @@ register_CE(struct archive_read *a, int32_t location,
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
 		}
-		p = malloc(new_size * sizeof(p[0]));
+		p = calloc(new_size, sizeof(p[0]));
 		if (p == NULL) {
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
@@ -2513,9 +2522,6 @@ parse_rockridge_SL1(struct file_info *file, const unsigned char *data,
 
 	if (!file->symlink_continues || file->symlink.length < 1)
 		archive_string_empty(&file->symlink);
-	else if (!file->symlink_continues &&
-	    file->symlink.s[file->symlink.length - 1] != '/')
-		separator = "/";
 	file->symlink_continues = 0;
 
 	/*
@@ -2882,8 +2888,9 @@ next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,
 
 fatal_rr:
 	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-	    "Failed to connect 'CL' pointer to 'RE' rr_moved pointer of"
-	    "Rockridge extensions");
+	    "Failed to connect 'CL' pointer to 'RE' rr_moved pointer of "
+	    "Rockridge extensions: current position = %jd, CL offset = %jd",
+	    (intmax_t)iso9660->current_position, (intmax_t)file->cl_offset);
 	return (ARCHIVE_FATAL);
 }
 
@@ -3085,6 +3092,8 @@ isodate7(const unsigned char *v)
 {
 	struct tm tm;
 	int offset;
+	time_t t;
+
 	memset(&tm, 0, sizeof(tm));
 	tm.tm_year = v[0];
 	tm.tm_mon = v[1] - 1;
@@ -3098,7 +3107,10 @@ isodate7(const unsigned char *v)
 		tm.tm_hour -= offset / 4;
 		tm.tm_min -= (offset % 4) * 15;
 	}
-	return (time_from_tm(&tm));
+	t = time_from_tm(&tm);
+	if (t == (time_t)-1)
+		return ((time_t)0);
+	return (t);
 }
 
 static time_t
@@ -3106,6 +3118,8 @@ isodate17(const unsigned char *v)
 {
 	struct tm tm;
 	int offset;
+	time_t t;
+
 	memset(&tm, 0, sizeof(tm));
 	tm.tm_year = (v[0] - '0') * 1000 + (v[1] - '0') * 100
 	    + (v[2] - '0') * 10 + (v[3] - '0')
@@ -3121,7 +3135,10 @@ isodate17(const unsigned char *v)
 		tm.tm_hour -= offset / 4;
 		tm.tm_min -= (offset % 4) * 15;
 	}
-	return (time_from_tm(&tm));
+	t = time_from_tm(&tm);
+	if (t == (time_t)-1)
+		return ((time_t)0);
+	return (t);
 }
 
 static time_t
@@ -3135,7 +3152,8 @@ time_from_tm(struct tm *t)
 #else
 	/* Else use direct calculation using POSIX assumptions. */
 	/* First, fix up tm_yday based on the year/month/day. */
-	mktime(t);
+	if (mktime(t) == (time_t)-1)
+		return ((time_t)-1);
 	/* Then we can compute timegm() from first principles. */
 	return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600
 	    + t->tm_yday * 86400 + (t->tm_year - 70) * 31536000
@@ -3204,10 +3222,12 @@ dump_isodirrec(FILE *out, const unsigned char *isodirrec)
 	fprintf(out, " ilv %d,",
 	    toi(isodirrec + DR_interleave_offset, DR_interleave_size));
 	fprintf(out, " seq %d,",
-	    toi(isodirrec + DR_volume_sequence_number_offset, DR_volume_sequence_number_size));
+	    toi(isodirrec + DR_volume_sequence_number_offset,
+		DR_volume_sequence_number_size));
 	fprintf(out, " nl %d:",
 	    toi(isodirrec + DR_name_len_offset, DR_name_len_size));
 	fprintf(out, " `%.*s'",
-	    toi(isodirrec + DR_name_len_offset, DR_name_len_size), isodirrec + DR_name_offset);
+	    toi(isodirrec + DR_name_len_offset, DR_name_len_size),
+		isodirrec + DR_name_offset);
 }
 #endif
diff --git a/libarchive/archive_read_support_format_lha.c b/libarchive/archive_read_support_format_lha.c
index 50256b1..f702949 100644
--- a/libarchive/archive_read_support_format_lha.c
+++ b/libarchive/archive_read_support_format_lha.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2008-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2008-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -272,7 +272,7 @@ static int	lha_skip_sfx(struct archive_read *);
 static time_t	lha_dos_time(const unsigned char *);
 static time_t	lha_win_time(uint64_t, long *);
 static unsigned char	lha_calcsum(unsigned char, const void *,
-		    int, int);
+		    int, size_t);
 static int	lha_parse_linkname(struct archive_string *,
 		    struct archive_string *);
 static int	lha_read_data_none(struct archive_read *, const void **,
@@ -289,7 +289,7 @@ static void	lzh_huffman_free(struct huffman *);
 static int	lzh_read_pt_bitlen(struct lzh_stream *, int start, int end);
 static int	lzh_make_fake_table(struct huffman *, uint16_t);
 static int	lzh_make_huffman_table(struct huffman *);
-static int inline lzh_decode_huffman(struct huffman *, unsigned);
+static inline int lzh_decode_huffman(struct huffman *, unsigned);
 static int	lzh_decode_huffman_tree(struct huffman *, unsigned, int);
 
 
@@ -319,6 +319,7 @@ archive_read_support_format_lha(struct archive *_a)
 	    archive_read_format_lha_read_header,
 	    archive_read_format_lha_read_data,
 	    archive_read_format_lha_read_data_skip,
+	    NULL,
 	    archive_read_format_lha_cleanup);
 
 	if (r != ARCHIVE_OK)
@@ -445,11 +446,13 @@ archive_read_format_lha_options(struct archive_read *a,
 			else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "lha: unknown keyword ``%s''", key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 static int
@@ -696,7 +699,7 @@ archive_read_format_lha_read_header(struct archive_read *a,
 		archive_entry_set_symlink(entry, NULL);
 	archive_string_free(&linkname);
 	/*
-	 * When a header level is 0, there is a possibilty that
+	 * When a header level is 0, there is a possibility that
 	 * a pathname and a symlink has '\' character, a directory
 	 * separator in DOS/Windows. So we should convert it to '/'.
 	 */
@@ -949,7 +952,7 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha)
 
 	/* Read extended headers */
 	err2 = lha_read_file_extended_header(a, lha, NULL, 2,
-	    lha->compsize + 2, &extdsize);
+	    (size_t)(lha->compsize + 2), &extdsize);
 	if (err2 < ARCHIVE_WARN)
 		return (err2);
 	if (err2 < err)
@@ -1444,7 +1447,7 @@ lha_read_data_none(struct archive_read *a, const void **buff,
 		return (ARCHIVE_FATAL);
 	}
 	if (bytes_avail > lha->entry_bytes_remaining)
-		bytes_avail = lha->entry_bytes_remaining;
+		bytes_avail = (ssize_t)lha->entry_bytes_remaining;
 	lha->entry_crc_calculated =
 	    lha_crc16(lha->entry_crc_calculated, *buff, bytes_avail);
 	*size = bytes_avail;
@@ -1527,7 +1530,7 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
 		return (ARCHIVE_FATAL);
 	}
 	if (bytes_avail > lha->entry_bytes_remaining)
-		bytes_avail = lha->entry_bytes_remaining;
+		bytes_avail = (ssize_t)lha->entry_bytes_remaining;
 
 	lha->strm.avail_in = bytes_avail;
 	lha->strm.total_in = 0;
@@ -1573,7 +1576,7 @@ static int
 archive_read_format_lha_read_data_skip(struct archive_read *a)
 {
 	struct lha *lha;
-	off_t bytes_skipped;
+	int64_t bytes_skipped;
 
 	lha = (struct lha *)(a->format->data);
 
@@ -1632,7 +1635,7 @@ lha_parse_linkname(struct archive_string *linkname,
     struct archive_string *pathname)
 {
 	char *	linkptr;
-	int 	symlen;
+	size_t 	symlen;
 
 	linkptr = strchr(pathname->s, '|');
 	if (linkptr != NULL) {
@@ -1687,12 +1690,12 @@ lha_win_time(uint64_t wintime, long *ns)
 }
 
 static unsigned char
-lha_calcsum(unsigned char sum, const void *pp, int offset, int size)
+lha_calcsum(unsigned char sum, const void *pp, int offset, size_t size)
 {
 	unsigned char const *p = (unsigned char const *)pp;
 
 	p += offset;
-	while (--size >= 0)
+	for (;size > 0; --size)
 		sum += *p++;
 	return (sum);
 }
@@ -2014,18 +2017,18 @@ lzh_copy_from_window(struct lzh_stream *strm, struct lzh_dec *ds)
 		if (ds->w_pos - ds->copy_pos <= strm->avail_out)
 			copy_bytes = ds->w_pos - ds->copy_pos;
 		else
-			copy_bytes = strm->avail_out;
+			copy_bytes = (size_t)strm->avail_out;
 		memcpy(strm->next_out,
 		    ds->w_buff + ds->copy_pos, copy_bytes);
-		ds->copy_pos += copy_bytes;
+		ds->copy_pos += (int)copy_bytes;
 	} else {
 		if (ds->w_remaining <= strm->avail_out)
 			copy_bytes = ds->w_remaining;
 		else
-			copy_bytes = strm->avail_out;
+			copy_bytes = (size_t)strm->avail_out;
 		memcpy(strm->next_out,
 		    ds->w_buff + ds->w_size - ds->w_remaining, copy_bytes);
-		ds->w_remaining -= copy_bytes;
+		ds->w_remaining -= (int)copy_bytes;
 	}
 	strm->next_out += copy_bytes;
 	strm->avail_out -= copy_bytes;
@@ -2479,7 +2482,7 @@ lzh_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 			bits = tbl_bits;
 		else
 			bits = HTBL_BITS;
-		hf->tbl = malloc((1 << bits) * sizeof(hf->tbl[0]));
+		hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0]));
 		if (hf->tbl == NULL)
 			return (ARCHIVE_FATAL);
 	}
@@ -2489,7 +2492,7 @@ lzh_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 		if (hf->tree == NULL)
 			return (ARCHIVE_FATAL);
 	}
-	hf->len_size = len_size;
+	hf->len_size = (int)len_size;
 	hf->tbl_bits = tbl_bits;
 	return (ARCHIVE_OK);
 }
diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c
index 6ac7db8..c4e7021 100644
--- a/libarchive/archive_read_support_format_mtree.c
+++ b/libarchive/archive_read_support_format_mtree.c
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
  * Copyright (c) 2008 Joerg Sonnenberger
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,6 +55,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
 #ifndef O_BINARY
 #define	O_BINARY 0
 #endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
 
 #define	MTREE_HAS_DEVICE	0x0001
 #define	MTREE_HAS_FFLAGS	0x0002
@@ -69,6 +72,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
 #define	MTREE_HAS_UNAME		0x0400
 
 #define	MTREE_HAS_OPTIONAL	0x0800
+#define	MTREE_HAS_NOCHANGE	0x1000 /* FreeBSD specific */
 
 struct mtree_option {
 	struct mtree_option *next;
@@ -101,7 +105,9 @@ struct mtree {
 	int64_t			 cur_size;
 };
 
+static int	bid_keycmp(const char *, const char *, ssize_t);
 static int	cleanup(struct archive_read *);
+static int	detect_form(struct archive_read *, int *);
 static int	mtree_bid(struct archive_read *, int);
 static int	parse_file(struct archive_read *, struct archive_entry *,
 		    struct mtree *, struct mtree_entry *, int *);
@@ -199,7 +205,7 @@ archive_read_support_format_mtree(struct archive *_a)
 	mtree->fd = -1;
 
 	r = __archive_read_register_format(a, mtree, "mtree",
-	    mtree_bid, NULL, read_header, read_data, skip, cleanup);
+	    mtree_bid, NULL, read_header, read_data, skip, NULL, cleanup);
 
 	if (r != ARCHIVE_OK)
 		free(mtree);
@@ -317,7 +323,7 @@ next_line(struct archive_read *a,
  * Returns the length of a mtree keyword if matched.
  * Returns 0 if not matched.
  */
-int
+static int
 bid_keycmp(const char *p, const char *key, ssize_t len)
 {
 	int match_len = 0;
@@ -348,7 +354,7 @@ bid_keycmp(const char *p, const char *key, ssize_t len)
  * Returns the length of a detected keyword.
  * Returns 0 if any keywords were not found.
  */
-static ssize_t
+static int
 bid_keyword(const char *p,  ssize_t len)
 {
 	static const char *keys_c[] = {
@@ -367,7 +373,7 @@ bid_keyword(const char *p,  ssize_t len)
 		"md5", "md5digest", "mode", NULL
 	};
 	static const char *keys_no[] = {
-		"nlink", "optional", NULL
+		"nlink", "nochange", "optional", NULL
 	};
 	static const char *keys_r[] = {
 		"rmd160", "rmd160digest", NULL
@@ -407,7 +413,7 @@ bid_keyword(const char *p,  ssize_t len)
 		if (l > 0)
 			return (l);
 	}
-	return (0);/* Unkown key */
+	return (0);/* Unknown key */
 }
 
 /*
@@ -418,7 +424,7 @@ bid_keyword(const char *p,  ssize_t len)
  * When "unset" is specified, expects a set of "<space characters>keyword".
  */
 static int
-bid_keyword_list(const char *p,  ssize_t len, int unset)
+bid_keyword_list(const char *p,  ssize_t len, int unset, int last_is_path)
 {
 	int l;
 	int keycnt = 0;
@@ -436,8 +442,10 @@ bid_keyword_list(const char *p,  ssize_t len, int unset)
 			break;
 		if (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r'))
 			break;
-		if (!blank) /* No blank character. */
+		if (!blank && !last_is_path) /* No blank character. */
 			return (-1);
+		if (last_is_path && len == 0)
+				return (keycnt);
 
 		if (unset) {
 			l = bid_keycmp(p, "all", len);
@@ -472,7 +480,7 @@ bid_keyword_list(const char *p,  ssize_t len, int unset)
 }
 
 static int
-bid_entry(const char *p, ssize_t len)
+bid_entry(const char *p, ssize_t len, ssize_t nl, int *last_is_path)
 {
 	int f = 0;
 	static const unsigned char safe_char[256] = {
@@ -499,22 +507,60 @@ bid_entry(const char *p, ssize_t len)
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
 	};
+	ssize_t ll = len;
+	const char *pp = p;
 
+	*last_is_path = 0;
 	/*
 	 * Skip the path-name which is quoted.
 	 */
-	while (len > 0 && *p != ' ' && *p != '\t') {
-		if (!safe_char[*(const unsigned char *)p])
-			return (-1);
-		++p;
-		--len;
+	while (ll > 0 && *pp != ' ' &&*pp != '\t' && *pp != '\r' &&
+	    *pp != '\n') {
+		if (!safe_char[*(const unsigned char *)pp]) {
+			f = 0;
+			break;
+		}
+		++pp;
+		--ll;
 		++f;
 	}
-	/* If a path-name was not found, returns error. */
-	if (f == 0)
-		return (-1);
+	/* If a path-name was not found at the first, try to check
+	 * a mtree format ``NetBSD's mtree -D'' creates, which
+	 * places the path-name at the last. */
+	if (f == 0) {
+		const char *pb = p + len - nl;
+		int name_len = 0;
+		int slash;
+
+		/* Do not accept multi lines for form D. */
+		if (pb-2 >= p &&
+		    pb[-1] == '\\' && (pb[-2] == ' ' || pb[-2] == '\t'))
+			return (-1);
+		if (pb-1 >= p && pb[-1] == '\\')
+			return (-1);
+
+		slash = 0;
+		while (p <= --pb && *pb != ' ' && *pb != '\t') {
+			if (!safe_char[*(const unsigned char *)pb])
+				return (-1);
+			name_len++;
+			/* The pathname should have a slash in this
+			 * format. */
+			if (*pb == '/')
+				slash = 1;
+		}
+		if (name_len == 0 || slash == 0)
+			return (-1);
+		/* If '/' is placed at the first in this field, this is not
+		 * a valid filename. */
+		if (pb[1] == '/')
+			return (-1);
+		ll = len - nl - name_len;
+		pp = p;
+		*last_is_path = 1;
+	}
 
-	return (bid_keyword_list(p, len, 0));
+	return (bid_keyword_list(pp, ll, 0, *last_is_path));
 }
 
 #define MAX_BID_ENTRY	3
@@ -524,14 +570,11 @@ mtree_bid(struct archive_read *a, int best_bid)
 {
 	const char *signature = "#mtree";
 	const char *p;
-	ssize_t avail, ravail;
-	ssize_t len, nl;
-	int detected_bytes = 0, entry_cnt = 0, multiline = 0;
 
 	(void)best_bid; /* UNUSED */
 
 	/* Now let's look at the actual header and see if it matches. */
-	p = __archive_read_ahead(a, strlen(signature), &avail);
+	p = __archive_read_ahead(a, strlen(signature), NULL);
 	if (p == NULL)
 		return (-1);
 
@@ -541,6 +584,24 @@ mtree_bid(struct archive_read *a, int best_bid)
 	/*
 	 * There is not a mtree signature. Let's try to detect mtree format.
 	 */
+	return (detect_form(a, NULL));
+}
+
+static int
+detect_form(struct archive_read *a, int *is_form_d)
+{
+	const char *p;
+	ssize_t avail, ravail;
+	ssize_t detected_bytes = 0, len, nl;
+	int entry_cnt = 0, multiline = 0;
+	int form_D = 0;/* The archive is generated by `NetBSD mtree -D'
+			* (In this source we call it `form D') . */
+
+	if (is_form_d != NULL)
+		*is_form_d = 0;
+	p = __archive_read_ahead(a, 1, &avail);
+	if (p == NULL)
+		return (-1);
 	ravail = avail;
 	for (;;) {
 		len = next_line(a, &p, &avail, &ravail, &nl);
@@ -565,7 +626,7 @@ mtree_bid(struct archive_read *a, int best_bid)
 		} else {
 			/* A continuance line; the terminal
 			 * character of previous line was '\' character. */
-			if (bid_keyword_list(p, len, 0) <= 0)
+			if (bid_keyword_list(p, len, 0, 0) <= 0)
 				break;
 			if (multiline == 1)
 				detected_bytes += len;
@@ -580,9 +641,25 @@ mtree_bid(struct archive_read *a, int best_bid)
 			continue;
 		}
 		if (p[0] != '/') {
-			if (bid_entry(p, len) >= 0) {
+			int last_is_path, keywords;
+
+			keywords = bid_entry(p, len, nl, &last_is_path);
+			if (keywords >= 0) {
 				detected_bytes += len;
-				if (p[len-nl-1] == '\\')
+				if (form_D == 0) {
+					if (last_is_path)
+						form_D = 1;
+					else if (keywords > 0)
+						/* This line is not `form D'. */
+						form_D = -1;
+				} else if (form_D == 1) {
+					if (!last_is_path && keywords > 0)
+						/* This this is not `form D'
+						 * and We cannot accept mixed
+						 * format. */
+						break;
+				}
+				if (!last_is_path && p[len-nl-1] == '\\')
 					/* This line continues. */
 					multiline = 1;
 				else {
@@ -595,13 +672,13 @@ mtree_bid(struct archive_read *a, int best_bid)
 			} else
 				break;
 		} else if (strncmp(p, "/set", 4) == 0) {
-			if (bid_keyword_list(p+4, len-4, 0) <= 0)
+			if (bid_keyword_list(p+4, len-4, 0, 0) <= 0)
 				break;
 			/* This line continues. */
 			if (p[len-nl-1] == '\\')
 				multiline = 2;
 		} else if (strncmp(p, "/unset", 6) == 0) {
-			if (bid_keyword_list(p+6, len-6, 1) <= 0)
+			if (bid_keyword_list(p+6, len-6, 1, 0) <= 0)
 				break;
 			/* This line continues. */
 			if (p[len-nl-1] == '\\')
@@ -613,8 +690,13 @@ mtree_bid(struct archive_read *a, int best_bid)
 		p += len;
 		avail -= len;
 	}
-	if (entry_cnt >= MAX_BID_ENTRY || (entry_cnt > 0 && len == 0))
+	if (entry_cnt >= MAX_BID_ENTRY || (entry_cnt > 0 && len == 0)) {
+		if (is_form_d != NULL) {
+			if (form_D == 1)
+				*is_form_d = 1;
+		}
 		return (32);
+	}
 
 	return (0);
 }
@@ -738,12 +820,12 @@ process_global_unset(struct archive_read *a,
 
 static int
 process_add_entry(struct archive_read *a, struct mtree *mtree,
-    struct mtree_option **global, const char *line,
-    struct mtree_entry **last_entry)
+    struct mtree_option **global, const char *line, ssize_t line_len,
+    struct mtree_entry **last_entry, int is_form_d)
 {
 	struct mtree_entry *entry;
 	struct mtree_option *iter;
-	const char *next, *eq;
+	const char *next, *eq, *name, *end;
 	size_t len;
 	int r;
 
@@ -764,17 +846,46 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
 		(*last_entry)->next = entry;
 	*last_entry = entry;
 
-	len = strcspn(line, " \t\r\n");
+	if (is_form_d) {
+		/*
+		 * This form places the file name as last parameter.
+		 */
+		name = line + line_len -1;
+		while (line_len > 0) {
+			if (*name != '\r' && *name != '\n' &&
+			    *name != '\t' && *name != ' ')
+				break;
+			name--;
+			line_len--;
+		}
+		len = 0;
+		while (line_len > 0) {
+			if (*name == '\r' || *name == '\n' ||
+			    *name == '\t' || *name == ' ') {
+				name++;
+				break;
+			}
+			name--;
+			line_len--;
+			len++;
+		}
+		end = name;
+	} else {
+		len = strcspn(line, " \t\r\n");
+		name = line;
+		line += len;
+		end = line + line_len;
+	}
+
 	if ((entry->name = malloc(len + 1)) == NULL) {
 		archive_set_error(&a->archive, errno, "Can't allocate memory");
 		return (ARCHIVE_FATAL);
 	}
 
-	memcpy(entry->name, line, len);
+	memcpy(entry->name, name, len);
 	entry->name[len] = '\0';
 	parse_escapes(entry->name, entry);
 
-	line += len;
 	for (iter = *global; iter != NULL; iter = iter->next) {
 		r = add_option(a, &entry->options, iter->value,
 		    strlen(iter->value));
@@ -786,6 +897,8 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
 		next = line + strspn(line, " \t\r\n");
 		if (*next == '\0')
 			return (ARCHIVE_OK);
+		if (next >= end)
+			return (ARCHIVE_OK);
 		line = next;
 		next = line + strcspn(line, " \t\r\n");
 		eq = strchr(line, '=');
@@ -810,7 +923,7 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
 	char *p;
 	struct mtree_option *global;
 	struct mtree_entry *last_entry;
-	int r;
+	int r, is_form_d;
 
 	mtree->archive_format = ARCHIVE_FORMAT_MTREE;
 	mtree->archive_format_name = "mtree";
@@ -818,6 +931,8 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
 	global = NULL;
 	last_entry = NULL;
 
+	(void)detect_form(a, &is_form_d);
+
 	for (counter = 1; ; ++counter) {
 		len = readline(a, mtree, &p, 65536);
 		if (len == 0) {
@@ -827,7 +942,7 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
 		}
 		if (len < 0) {
 			free_options(global);
-			return (len);
+			return ((int)len);
 		}
 		/* Leading whitespace is never significant, ignore it. */
 		while (*p == ' ' || *p == '\t') {
@@ -840,8 +955,8 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
 		if (*p == '\r' || *p == '\n' || *p == '\0')
 			continue;
 		if (*p != '/') {
-			r = process_add_entry(a, mtree, &global, p,
-			    &last_entry);
+			r = process_add_entry(a, mtree, &global, p, len,
+			    &last_entry, is_form_d);
 		} else if (strncmp(p, "/set", 4) == 0) {
 			if (p[4] != ' ' && p[4] != '\t')
 				break;
@@ -1007,7 +1122,8 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
 
 	if (archive_entry_filetype(entry) == AE_IFREG ||
 	    archive_entry_filetype(entry) == AE_IFDIR) {
-		mtree->fd = open(path, O_RDONLY | O_BINARY);
+		mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC);
+		__archive_ensure_cloexec_flag(mtree->fd);
 		if (mtree->fd == -1 &&
 		    (errno != ENOENT ||
 		     archive_strlen(&mtree->contents_name) > 0)) {
@@ -1090,15 +1206,19 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
 	 * if it wasn't already parsed from the specification.
 	 */
 	if (st != NULL) {
-		if ((parsed_kws & MTREE_HAS_DEVICE) == 0 &&
+		if (((parsed_kws & MTREE_HAS_DEVICE) == 0 ||
+		     (parsed_kws & MTREE_HAS_NOCHANGE) != 0) &&
 		    (archive_entry_filetype(entry) == AE_IFCHR ||
 		     archive_entry_filetype(entry) == AE_IFBLK))
 			archive_entry_set_rdev(entry, st->st_rdev);
-		if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0)
+		if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0 ||
+		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
 			archive_entry_set_gid(entry, st->st_gid);
-		if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0)
+		if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0 ||
+		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
 			archive_entry_set_uid(entry, st->st_uid);
-		if ((parsed_kws & MTREE_HAS_MTIME) == 0) {
+		if ((parsed_kws & MTREE_HAS_MTIME) == 0 ||
+		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0) {
 #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
 			archive_entry_set_mtime(entry, st->st_mtime,
 			    st->st_mtimespec.tv_nsec);
@@ -1118,11 +1238,14 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
 			archive_entry_set_mtime(entry, st->st_mtime, 0);
 #endif
 		}
-		if ((parsed_kws & MTREE_HAS_NLINK) == 0)
+		if ((parsed_kws & MTREE_HAS_NLINK) == 0 ||
+		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
 			archive_entry_set_nlink(entry, st->st_nlink);
-		if ((parsed_kws & MTREE_HAS_PERM) == 0)
+		if ((parsed_kws & MTREE_HAS_PERM) == 0 ||
+		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
 			archive_entry_set_perm(entry, st->st_mode);
-		if ((parsed_kws & MTREE_HAS_SIZE) == 0)
+		if ((parsed_kws & MTREE_HAS_SIZE) == 0 ||
+		    (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
 			archive_entry_set_size(entry, st->st_size);
 		archive_entry_set_ino(entry, st->st_ino);
 		archive_entry_set_dev(entry, st->st_dev);
@@ -1182,7 +1305,7 @@ parse_device(struct archive *a, struct archive_entry *entry, char *val)
 
 	comma1 = strchr(val, ',');
 	if (comma1 == NULL) {
-		archive_entry_set_dev(entry, mtree_atol10(&val));
+		archive_entry_set_dev(entry, (dev_t)mtree_atol10(&val));
 		return (ARCHIVE_OK);
 	}
 	++comma1;
@@ -1193,8 +1316,8 @@ parse_device(struct archive *a, struct archive_entry *entry, char *val)
 		return (ARCHIVE_WARN);
 	}
 	++comma2;
-	archive_entry_set_rdevmajor(entry, mtree_atol(&comma1));
-	archive_entry_set_rdevminor(entry, mtree_atol(&comma2));
+	archive_entry_set_rdevmajor(entry, (dev_t)mtree_atol(&comma1));
+	archive_entry_set_rdevminor(entry, (dev_t)mtree_atol(&comma2));
 	return (ARCHIVE_OK);
 }
 
@@ -1212,6 +1335,10 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 	if (*key == '\0')
 		return (ARCHIVE_OK);
 
+	if (strcmp(key, "nochange") == 0) {
+		*parsed_kws |= MTREE_HAS_NOCHANGE;
+		return (ARCHIVE_OK);
+	}
 	if (strcmp(key, "optional") == 0) {
 		*parsed_kws |= MTREE_HAS_OPTIONAL;
 		return (ARCHIVE_OK);
@@ -1279,7 +1406,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 			if (val[0] >= '0' && val[0] <= '9') {
 				*parsed_kws |= MTREE_HAS_PERM;
 				archive_entry_set_perm(entry,
-				    mtree_atol8(&val));
+				    (mode_t)mtree_atol8(&val));
 			} else {
 				archive_set_error(&a->archive,
 				    ARCHIVE_ERRNO_FILE_FORMAT,
@@ -1291,7 +1418,8 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 	case 'n':
 		if (strcmp(key, "nlink") == 0) {
 			*parsed_kws |= MTREE_HAS_NLINK;
-			archive_entry_set_nlink(entry, mtree_atol10(&val));
+			archive_entry_set_nlink(entry,
+				(unsigned int)mtree_atol10(&val));
 			break;
 		}
 	case 'r':
@@ -1433,7 +1561,7 @@ read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offs
 	*buff = mtree->buff;
 	*offset = mtree->offset;
 	if ((int64_t)mtree->buffsize > mtree->cur_size - mtree->offset)
-		bytes_to_read = mtree->cur_size - mtree->offset;
+		bytes_to_read = (size_t)(mtree->cur_size - mtree->offset);
 	else
 		bytes_to_read = mtree->buffsize;
 	bytes_read = read(mtree->fd, mtree->buff, bytes_to_read);
diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c
index a5f2041..99c57a0 100644
--- a/libarchive/archive_read_support_format_rar.c
+++ b/libarchive/archive_read_support_format_rar.c
@@ -136,7 +136,7 @@
 #define MAX_SYMBOLS       20
 
 /*
- * Considering L1,L2 cache miss and a calling of write sytem-call,
+ * Considering L1,L2 cache miss and a calling of write system-call,
  * the best size of the output buffer(uncompressed buffer) is 128K.
  * If the structure of extracting process is changed, this value
  * might be researched again.
@@ -199,6 +199,13 @@ struct lzss
   int64_t position;
 };
 
+struct data_block_offsets
+{
+  int64_t header_size;
+  int64_t start_offset;
+  int64_t end_offset;
+};
+
 struct rar
 {
   /* Entries from main RAR header */
@@ -217,6 +224,7 @@ struct rar
   long mnsec;
   mode_t mode;
   char *filename;
+  char *filename_save;
   size_t filename_allocated;
 
   /* File header optional entries */
@@ -234,6 +242,7 @@ struct rar
   int64_t bytes_uncopied;
   int64_t offset;
   int64_t offset_outgoing;
+  int64_t offset_seek;
   char valid;
   unsigned int unp_offset;
   unsigned int unp_buffer_size;
@@ -243,6 +252,10 @@ struct rar
   char entry_eof;
   unsigned long crc_calculated;
   int found_first_header;
+  char has_endarc_header;
+  struct data_block_offsets *dbo;
+  unsigned int cursor;
+  unsigned int nodes;
 
   /* LZSS members */
   struct huffman_code maincode;
@@ -301,11 +314,13 @@ static int archive_read_format_rar_read_header(struct archive_read *,
 static int archive_read_format_rar_read_data(struct archive_read *,
     const void **, size_t *, int64_t *);
 static int archive_read_format_rar_read_data_skip(struct archive_read *a);
+static int64_t archive_read_format_rar_seek_data(struct archive_read *, int64_t,
+    int);
 static int archive_read_format_rar_cleanup(struct archive_read *);
 
 /* Support functions */
 static int read_header(struct archive_read *, struct archive_entry *, char);
-static time_t get_time(int time);
+static time_t get_time(int);
 static int read_exttime(const char *, struct rar *, const char *);
 static int read_symlink_stored(struct archive_read *, struct archive_entry *,
                                struct archive_string_conv *);
@@ -328,6 +343,7 @@ static int make_table_recurse(struct archive_read *, struct huffman_code *, int,
 static int64_t expand(struct archive_read *, int64_t);
 static int copy_from_lzss_window(struct archive_read *, const void **,
                                    int64_t, int);
+static const void *rar_read_ahead(struct archive_read *, size_t, ssize_t *);
 
 /*
  * Bit stream reader.
@@ -449,11 +465,9 @@ rar_br_fillup(struct archive_read *a, struct rar_br *br)
         __archive_read_consume(a, rar->bytes_unconsumed);
         rar->bytes_unconsumed = 0;
       }
-      br->next_in = __archive_read_ahead(a, 1, &(br->avail_in));
+      br->next_in = rar_read_ahead(a, 1, &(br->avail_in));
       if (br->next_in == NULL)
         return (0);
-      if (br->avail_in > rar->bytes_remaining)
-        br->avail_in = rar->bytes_remaining;
       if (br->avail_in == 0)
         return (0);
     }
@@ -473,15 +487,13 @@ rar_br_preparation(struct archive_read *a, struct rar_br *br)
   struct rar *rar = (struct rar *)(a->format->data);
 
   if (rar->bytes_remaining > 0) {
-    br->next_in = __archive_read_ahead(a, 1, &(br->avail_in));
+    br->next_in = rar_read_ahead(a, 1, &(br->avail_in));
     if (br->next_in == NULL) {
       archive_set_error(&a->archive,
           ARCHIVE_ERRNO_FILE_FORMAT,
           "Truncated RAR file data");
       return (ARCHIVE_FATAL);
     }
-    if (br->avail_in > rar->bytes_remaining)
-      br->avail_in = rar->bytes_remaining;
     if (br->cache_avail == 0)
       (void)rar_br_fillup(a, br);
   }
@@ -522,7 +534,7 @@ lzss_size(struct lzss *lzss)
 static inline int
 lzss_offset_for_position(struct lzss *lzss, int64_t pos)
 {
-  return pos & lzss->mask;
+  return (int)(pos & lzss->mask);
 }
 
 static inline unsigned char *
@@ -642,6 +654,7 @@ archive_read_support_format_rar(struct archive *_a)
                                      archive_read_format_rar_read_header,
                                      archive_read_format_rar_read_data,
                                      archive_read_format_rar_read_data_skip,
+                                     archive_read_format_rar_seek_data,
                                      archive_read_format_rar_cleanup);
 
   if (r != ARCHIVE_OK)
@@ -757,11 +770,13 @@ archive_read_format_rar_options(struct archive_read *a,
       else
         ret = ARCHIVE_FATAL;
     }
-  } else
-    archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-        "rar: unknown keyword ``%s''", key);
-                
-  return (ret);
+    return (ret);
+  }
+
+  /* Note: The "warn" return is just to inform the options
+   * supervisor that we didn't handle it.  It will generate
+   * a suitable error if no one used this option. */
+  return (ARCHIVE_WARN);
 }
 
 static int
@@ -842,13 +857,6 @@ archive_read_format_rar_read_header(struct archive_read *a,
                             sizeof(rar->reserved2));
       }
 
-      if (rar->main_flags & MHD_VOLUME ||
-          rar->main_flags & MHD_FIRSTVOLUME)
-      {
-        archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                          "RAR volume support unavailable.");
-        return (ARCHIVE_FATAL);
-      }
       if (rar->main_flags & MHD_PASSWORD)
       {
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -856,7 +864,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
         return (ARCHIVE_FATAL);
       }
 
-      crc32_val = crc32(0, (const unsigned char *)p + 2, skip - 2);
+      crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);
       if ((crc32_val & 0xffff) != archive_le16dec(p)) {
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
           "Header CRC error");
@@ -873,6 +881,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
     case SUB_HEAD:
     case PROTECT_HEAD:
     case SIGN_HEAD:
+    case ENDARC_HEAD:
       flags = archive_le16dec(p + 3);
       skip = archive_le16dec(p + 5);
       if (skip < 7) {
@@ -898,13 +907,15 @@ archive_read_format_rar_read_header(struct archive_read *a,
         p = h;
       }
 
-      crc32_val = crc32(0, (const unsigned char *)p + 2, skip - 2);
+      crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);
       if ((crc32_val & 0xffff) != archive_le16dec(p)) {
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
           "Header CRC error");
         return (ARCHIVE_FATAL);
       }
       __archive_read_consume(a, skip);
+      if (head_type == ENDARC_HEAD)
+        return (ARCHIVE_EOF);
       break;
 
     case NEWSUB_HEAD:
@@ -912,9 +923,6 @@ archive_read_format_rar_read_header(struct archive_read *a,
         return ret;
       break;
 
-    case ENDARC_HEAD:
-      return (ARCHIVE_EOF);
-
     default:
       archive_set_error(&a->archive,  ARCHIVE_ERRNO_FILE_FORMAT,
                         "Bad RAR file");
@@ -936,10 +944,12 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
       rar->bytes_unconsumed = 0;
   }
 
-  if (rar->entry_eof) {
+  if (rar->entry_eof || rar->offset_seek >= rar->unp_size) {
     *buff = NULL;
     *size = 0;
     *offset = rar->offset;
+    if (*offset < rar->unp_size)
+      *offset = rar->unp_size;
     return (ARCHIVE_EOF);
   }
 
@@ -973,6 +983,7 @@ archive_read_format_rar_read_data_skip(struct archive_read *a)
 {
   struct rar *rar;
   int64_t bytes_skipped;
+  int ret;
 
   rar = (struct rar *)(a->format->data);
 
@@ -987,9 +998,179 @@ archive_read_format_rar_read_data_skip(struct archive_read *a)
     if (bytes_skipped < 0)
       return (ARCHIVE_FATAL);
   }
+
+  /* Compressed data to skip must be read from each header in a multivolume
+   * archive.
+   */
+  if (rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER)
+  {
+    ret = archive_read_format_rar_read_header(a, a->entry);
+    if (ret == (ARCHIVE_EOF))
+      ret = archive_read_format_rar_read_header(a, a->entry);
+    if (ret != (ARCHIVE_OK))
+      return ret;
+    return archive_read_format_rar_read_data_skip(a);
+  }
+
   return (ARCHIVE_OK);
 }
 
+static int64_t
+archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
+    int whence)
+{
+  int64_t client_offset, ret;
+  unsigned int i;
+  struct rar *rar = (struct rar *)(a->format->data);
+
+  if (rar->compression_method == COMPRESS_METHOD_STORE)
+  {
+    /* Modify the offset for use with SEEK_SET */
+    switch (whence)
+    {
+      case SEEK_CUR:
+        client_offset = rar->offset_seek;
+        break;
+      case SEEK_END:
+        client_offset = rar->unp_size;
+        break;
+      case SEEK_SET:
+      default:
+        client_offset = 0;
+    }
+    client_offset += offset;
+    if (client_offset < 0)
+    {
+      /* Can't seek past beginning of data block */
+      return -1;
+    }
+    else if (client_offset > rar->unp_size)
+    {
+      /*
+       * Set the returned offset but only seek to the end of
+       * the data block.
+       */
+      rar->offset_seek = client_offset;
+      client_offset = rar->unp_size;
+    }
+
+    client_offset += rar->dbo[0].start_offset;
+    i = 0;
+    while (i < rar->cursor)
+    {
+      i++;
+      client_offset += rar->dbo[i].start_offset - rar->dbo[i-1].end_offset;
+    }
+    if (rar->main_flags & MHD_VOLUME)
+    {
+      /* Find the appropriate offset among the multivolume archive */
+      while (1)
+      {
+        if (client_offset < rar->dbo[rar->cursor].start_offset &&
+          rar->file_flags & FHD_SPLIT_BEFORE)
+        {
+          /* Search backwards for the correct data block */
+          if (rar->cursor == 0)
+          {
+            archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+              "Attempt to seek past beginning of RAR data block");
+            return (ARCHIVE_FAILED);
+          }
+          rar->cursor--;
+          client_offset -= rar->dbo[rar->cursor+1].start_offset -
+            rar->dbo[rar->cursor].end_offset;
+          if (client_offset < rar->dbo[rar->cursor].start_offset)
+            continue;
+          ret = __archive_read_seek(a, rar->dbo[rar->cursor].start_offset -
+            rar->dbo[rar->cursor].header_size, SEEK_SET);
+          if (ret < (ARCHIVE_OK))
+            return ret;
+          ret = archive_read_format_rar_read_header(a, a->entry);
+          if (ret != (ARCHIVE_OK))
+          {
+            archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+              "Error during seek of RAR file");
+            return (ARCHIVE_FAILED);
+          }
+          rar->cursor--;
+          break;
+        }
+        else if (client_offset > rar->dbo[rar->cursor].end_offset &&
+          rar->file_flags & FHD_SPLIT_AFTER)
+        {
+          /* Search forward for the correct data block */
+          rar->cursor++;
+          if (rar->cursor < rar->nodes &&
+            client_offset > rar->dbo[rar->cursor].end_offset)
+          {
+            client_offset += rar->dbo[rar->cursor].start_offset -
+              rar->dbo[rar->cursor-1].end_offset;
+            continue;
+          }
+          rar->cursor--;
+          ret = __archive_read_seek(a, rar->dbo[rar->cursor].end_offset,
+                                    SEEK_SET);
+          if (ret < (ARCHIVE_OK))
+            return ret;
+          ret = archive_read_format_rar_read_header(a, a->entry);
+          if (ret == (ARCHIVE_EOF))
+          {
+            rar->has_endarc_header = 1;
+            ret = archive_read_format_rar_read_header(a, a->entry);
+          }
+          if (ret != (ARCHIVE_OK))
+          {
+            archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+              "Error during seek of RAR file");
+            return (ARCHIVE_FAILED);
+          }
+          client_offset += rar->dbo[rar->cursor].start_offset -
+            rar->dbo[rar->cursor-1].end_offset;
+          continue;
+        }
+        break;
+      }
+    }
+
+    ret = __archive_read_seek(a, client_offset, SEEK_SET);
+    if (ret < (ARCHIVE_OK))
+      return ret;
+    rar->bytes_remaining = rar->dbo[rar->cursor].end_offset - ret;
+    i = rar->cursor;
+    while (i > 0)
+    {
+      i--;
+      ret -= rar->dbo[i+1].start_offset - rar->dbo[i].end_offset;
+    }
+    ret -= rar->dbo[0].start_offset;
+
+    /* Always restart reading the file after a seek */
+    a->read_data_block = NULL;
+    a->read_data_offset = 0;
+    a->read_data_output_offset = 0;
+    a->read_data_remaining = 0;
+    rar->bytes_unconsumed = 0;
+    rar->offset = 0;
+
+    /*
+     * If a seek past the end of file was requested, return the requested
+     * offset.
+     */
+    if (ret == rar->unp_size && rar->offset_seek > rar->unp_size)
+      return rar->offset_seek;
+
+    /* Return the new offset */
+    rar->offset_seek = ret;
+    return rar->offset_seek;
+  }
+  else
+  {
+    archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+      "Seeking of compressed RAR files is unsupported");
+  }
+  return (ARCHIVE_FAILED);
+}
+
 static int
 archive_read_format_rar_cleanup(struct archive_read *a)
 {
@@ -998,6 +1179,8 @@ archive_read_format_rar_cleanup(struct archive_read *a)
   rar = (struct rar *)(a->format->data);
   free_codes(a);
   free(rar->filename);
+  free(rar->filename_save);
+  free(rar->dbo);
   free(rar->unp_buffer);
   free(rar->lzss.window);
   __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
@@ -1021,7 +1204,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
   char *strp;
   char packed_size[8];
   char unp_size[8];
-  int time;
+  int ttime;
   struct archive_string_conv *sconv, *fn_sconv;
   unsigned long crc32_val;
   int ret = (ARCHIVE_OK), ret2;
@@ -1047,7 +1230,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
   memcpy(&rar_header, p, sizeof(rar_header));
   rar->file_flags = archive_le16dec(rar_header.flags);
   header_size = archive_le16dec(rar_header.size);
-  if (header_size < sizeof(file_header) + 7) {
+  if (header_size < (int64_t)sizeof(file_header) + 7) {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
       "Invalid header size");
     return (ARCHIVE_FATAL);
@@ -1082,11 +1265,11 @@ read_header(struct archive_read *a, struct archive_entry *entry,
     return (ARCHIVE_FATAL);
   }
 
-  if ((h = __archive_read_ahead(a, header_size - 7, NULL)) == NULL)
+  if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
     return (ARCHIVE_FATAL);
 
   /* File Header CRC check. */
-  crc32_val = crc32(crc32_val, h, header_size - 7);
+  crc32_val = crc32(crc32_val, h, (unsigned)(header_size - 7));
   if ((crc32_val & 0xffff) != archive_le16dec(rar_header.crc)) {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
       "Header CRC error");
@@ -1100,8 +1283,8 @@ read_header(struct archive_read *a, struct archive_entry *entry,
 
   rar->compression_method = file_header.method;
 
-  time = archive_le32dec(file_header.file_time);
-  rar->mtime = get_time(time);
+  ttime = archive_le32dec(file_header.file_time);
+  rar->mtime = get_time(ttime);
 
   rar->file_crc = archive_le32dec(file_header.file_crc);
 
@@ -1129,9 +1312,6 @@ read_header(struct archive_read *a, struct archive_entry *entry,
     rar->unp_size = archive_le32dec(file_header.unp_size);
   }
 
-  /* TODO: Need to use CRC check for these kind of cases.
-   * For now, check if sizes are not < 0.
-   */
   if (rar->packed_size < 0 || rar->unp_size < 0)
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -1139,6 +1319,8 @@ read_header(struct archive_read *a, struct archive_entry *entry,
     return (ARCHIVE_FATAL);
   }
 
+  rar->bytes_remaining = rar->packed_size;
+
   /* TODO: RARv3 subblocks contain comments. For now the complete block is
    * consumed at the end.
    */
@@ -1146,7 +1328,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
     size_t distance = p - (const char *)h;
     header_size += rar->packed_size;
     /* Make sure we have the extended data. */
-    if ((h = __archive_read_ahead(a, header_size - 7, NULL)) == NULL)
+    if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
         return (ARCHIVE_FATAL);
     p = h;
     endp = p + header_size - 7;
@@ -1159,13 +1341,17 @@ read_header(struct archive_read *a, struct archive_entry *entry,
       "Invalid filename size");
     return (ARCHIVE_FATAL);
   }
-  if (rar->filename_allocated < filename_size+2) {
-    rar->filename = realloc(rar->filename, filename_size+2);
-    if (rar->filename == NULL) {
+  if (rar->filename_allocated < filename_size * 2 + 2) {
+    char *newptr;
+    size_t newsize = filename_size * 2 + 2;
+    newptr = realloc(rar->filename, newsize);
+    if (newptr == NULL) {
       archive_set_error(&a->archive, ENOMEM,
                         "Couldn't allocate memory.");
       return (ARCHIVE_FATAL);
     }
+    rar->filename = newptr;
+    rar->filename_allocated = newsize;
   }
   filename = rar->filename;
   memcpy(filename, p, filename_size);
@@ -1174,15 +1360,17 @@ read_header(struct archive_read *a, struct archive_entry *entry,
   {
     if (filename_size != strlen(filename))
     {
-      unsigned char highbyte, flagbits, flagbyte, length, offset;
+      unsigned char highbyte, flagbits, flagbyte;
+      unsigned fn_end, offset;
 
       end = filename_size;
+      fn_end = filename_size * 2;
       filename_size = 0;
-      offset = strlen(filename) + 1;
+      offset = (unsigned)strlen(filename) + 1;
       highbyte = *(p + offset++);
       flagbits = 0;
       flagbyte = 0;
-      while (offset < end && filename_size < end)
+      while (offset < end && filename_size < fn_end)
       {
         if (!flagbits)
         {
@@ -1208,19 +1396,26 @@ read_header(struct archive_read *a, struct archive_entry *entry,
             break;
           case 3:
           {
-            length = *(p + offset++);
-            while (length)
-            {
-	          if (filename_size >= end)
-			    break;
-              filename[filename_size++] = *(p + offset);
+            char extra, high;
+            uint8_t length = *(p + offset++);
+
+            if (length & 0x80) {
+              extra = *(p + offset++);
+              high = (char)highbyte;
+            } else
+              extra = high = 0;
+            length = (length & 0x7f) + 2;
+            while (length && filename_size < fn_end) {
+              unsigned cp = filename_size >> 1;
+              filename[filename_size++] = high;
+              filename[filename_size++] = p[cp] + extra;
               length--;
             }
           }
           break;
         }
       }
-      if (filename_size >= end) {
+      if (filename_size > fn_end) {
         archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
           "Invalid filename");
         return (ARCHIVE_FATAL);
@@ -1272,6 +1467,51 @@ read_header(struct archive_read *a, struct archive_entry *entry,
     p += filename_size;
   }
 
+  /* Split file in multivolume RAR. No more need to process header. */
+  if (rar->filename_save &&
+    !memcmp(rar->filename, rar->filename_save, filename_size + 1))
+  {
+    __archive_read_consume(a, header_size - 7);
+    rar->cursor++;
+    if (rar->cursor >= rar->nodes)
+    {
+      rar->nodes++;
+      if ((rar->dbo =
+        realloc(rar->dbo, sizeof(*rar->dbo) * rar->nodes)) == NULL)
+      {
+        archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
+        return (ARCHIVE_FATAL);
+      }
+      rar->dbo[rar->cursor].header_size = header_size;
+      rar->dbo[rar->cursor].start_offset = -1;
+      rar->dbo[rar->cursor].end_offset = -1;
+    }
+    if (rar->dbo[rar->cursor].start_offset < 0)
+    {
+      rar->dbo[rar->cursor].start_offset = a->filter->position;
+      rar->dbo[rar->cursor].end_offset = rar->dbo[rar->cursor].start_offset +
+        rar->packed_size;
+    }
+    return ret;
+  }
+
+  rar->filename_save = (char*)realloc(rar->filename_save,
+                                      filename_size + 1);
+  memcpy(rar->filename_save, rar->filename, filename_size + 1);
+
+  /* Set info for seeking */
+  free(rar->dbo);
+  if ((rar->dbo = calloc(1, sizeof(*rar->dbo))) == NULL)
+  {
+    archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
+    return (ARCHIVE_FATAL);
+  }
+  rar->dbo[0].header_size = header_size;
+  rar->dbo[0].start_offset = -1;
+  rar->dbo[0].end_offset = -1;
+  rar->cursor = 0;
+  rar->nodes = 1;
+
   if (rar->file_flags & FHD_SALT)
   {
     if (p + 8 > endp) {
@@ -1292,6 +1532,8 @@ read_header(struct archive_read *a, struct archive_entry *entry,
   }
 
   __archive_read_consume(a, header_size - 7);
+  rar->dbo[0].start_offset = a->filter->position;
+  rar->dbo[0].end_offset = rar->dbo[0].start_offset + rar->packed_size;
 
   switch(file_header.host_os)
   {
@@ -1318,9 +1560,10 @@ read_header(struct archive_read *a, struct archive_entry *entry,
     return (ARCHIVE_FATAL);
   }
 
-  rar->bytes_remaining = rar->packed_size;
   rar->bytes_uncopied = rar->bytes_unconsumed = 0;
-  rar->lzss.position = rar->dictionary_size = rar->offset = 0;
+  rar->lzss.position = rar->offset = 0;
+  rar->offset_seek = 0;
+  rar->dictionary_size = 0;
   rar->offset_outgoing = 0;
   rar->br.cache_avail = 0;
   rar->br.avail_in = 0;
@@ -1381,15 +1624,15 @@ read_header(struct archive_read *a, struct archive_entry *entry,
 }
 
 static time_t
-get_time(int time)
+get_time(int ttime)
 {
   struct tm tm;
-  tm.tm_sec = 2 * (time & 0x1f);
-  tm.tm_min = (time >> 5) & 0x3f;
-  tm.tm_hour = (time >> 11) & 0x1f;
-  tm.tm_mday = (time >> 16) & 0x1f;
-  tm.tm_mon = ((time >> 21) & 0x0f) - 1;
-  tm.tm_year = ((time >> 25) & 0x7f) + 80;
+  tm.tm_sec = 2 * (ttime & 0x1f);
+  tm.tm_min = (ttime >> 5) & 0x3f;
+  tm.tm_hour = (ttime >> 11) & 0x1f;
+  tm.tm_mday = (ttime >> 16) & 0x1f;
+  tm.tm_mon = ((ttime >> 21) & 0x0f) - 1;
+  tm.tm_year = ((ttime >> 25) & 0x7f) + 80;
   tm.tm_isdst = -1;
   return mktime(&tm);
 }
@@ -1398,7 +1641,7 @@ static int
 read_exttime(const char *p, struct rar *rar, const char *endp)
 {
   unsigned rmode, flags, rem, j, count;
-  int time, i;
+  int ttime, i;
   struct tm *tm;
   time_t t;
   long nsec;
@@ -1420,8 +1663,8 @@ read_exttime(const char *p, struct rar *rar, const char *endp)
       {
         if (p + 4 > endp)
           return (-1);
-        time = archive_le32dec(p);
-        t = get_time(time);
+        ttime = archive_le32dec(p);
+        t = get_time(ttime);
         p += 4;
       }
       rem = 0;
@@ -1475,11 +1718,12 @@ read_symlink_stored(struct archive_read *a, struct archive_entry *entry,
   int ret = (ARCHIVE_OK);
 
   rar = (struct rar *)(a->format->data);
-  if ((h = __archive_read_ahead(a, rar->packed_size, NULL)) == NULL)
+  if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL)
     return (ARCHIVE_FATAL);
   p = h;
 
-  if (archive_entry_copy_symlink_l(entry, p, rar->packed_size, sconv))
+  if (archive_entry_copy_symlink_l(entry,
+      p, (size_t)rar->packed_size, sconv))
   {
     if (errno == ENOMEM)
     {
@@ -1504,7 +1748,8 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
   ssize_t bytes_avail;
 
   rar = (struct rar *)(a->format->data);
-  if (rar->bytes_remaining == 0)
+  if (rar->bytes_remaining == 0 &&
+    !(rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER))
   {
     *buff = NULL;
     *size = 0;
@@ -1518,23 +1763,23 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
     return (ARCHIVE_EOF);
   }
 
-  *buff = __archive_read_ahead(a, 1, &bytes_avail);
+  *buff = rar_read_ahead(a, 1, &bytes_avail);
   if (bytes_avail <= 0)
   {
     archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
                       "Truncated RAR file data");
     return (ARCHIVE_FATAL);
   }
-  if (bytes_avail > rar->bytes_remaining)
-    bytes_avail = rar->bytes_remaining;
 
   *size = bytes_avail;
   *offset = rar->offset;
   rar->offset += bytes_avail;
+  rar->offset_seek += bytes_avail;
   rar->bytes_remaining -= bytes_avail;
   rar->bytes_unconsumed = bytes_avail;
   /* Calculate File CRC. */
-  rar->crc_calculated = crc32(rar->crc_calculated, *buff, bytes_avail);
+  rar->crc_calculated = crc32(rar->crc_calculated, *buff,
+    (unsigned)bytes_avail);
   return (ARCHIVE_OK);
 }
 
@@ -1564,7 +1809,8 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
         *offset = rar->offset_outgoing;
         rar->offset_outgoing += *size;
         /* Calculate File CRC. */
-        rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
+        rar->crc_calculated = crc32(rar->crc_calculated, *buff,
+          (unsigned)*size);
         rar->unp_offset = 0;
         return (ARCHIVE_OK);
       }
@@ -1585,8 +1831,8 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
       if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
         bs = rar->unp_buffer_size - rar->unp_offset;
       else
-        bs = rar->bytes_uncopied;
-      ret = copy_from_lzss_window(a, buff, rar->offset, bs);
+        bs = (size_t)rar->bytes_uncopied;
+      ret = copy_from_lzss_window(a, buff, rar->offset, (int)bs);
       if (ret != ARCHIVE_OK)
         return (ret);
       rar->offset += bs;
@@ -1597,7 +1843,8 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
         *offset = rar->offset_outgoing;
         rar->offset_outgoing += *size;
         /* Calculate File CRC. */
-        rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
+        rar->crc_calculated = crc32(rar->crc_calculated, *buff,
+          (unsigned)*size);
         return (ret);
       }
       continue;
@@ -1713,8 +1960,8 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
     if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
       bs = rar->unp_buffer_size - rar->unp_offset;
     else
-      bs = rar->bytes_uncopied;
-    ret = copy_from_lzss_window(a, buff, rar->offset, bs);
+      bs = (size_t)rar->bytes_uncopied;
+    ret = copy_from_lzss_window(a, buff, rar->offset, (int)bs);
     if (ret != ARCHIVE_OK)
       return (ret);
     rar->offset += bs;
@@ -1730,7 +1977,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
   *offset = rar->offset_outgoing;
   rar->offset_outgoing += *size;
   /* Calculate File CRC. */
-  rar->crc_calculated = crc32(rar->crc_calculated, *buff, *size);
+  rar->crc_calculated = crc32(rar->crc_calculated, *buff, (unsigned)*size);
   return ret;
 }
 
@@ -1973,17 +2220,21 @@ parse_codes(struct archive_read *a)
     /* Seems as though dictionary sizes are not used. Even so, minimize
      * memory usage as much as possible.
      */
+    void *new_window;
+    unsigned int new_size;
+
     if (rar->unp_size >= DICTIONARY_MAX_SIZE)
-      rar->dictionary_size = DICTIONARY_MAX_SIZE;
+      new_size = DICTIONARY_MAX_SIZE;
     else
-      rar->dictionary_size = rar_fls(rar->unp_size) << 1;
-    rar->lzss.window = (unsigned char *)realloc(rar->lzss.window,
-                                                rar->dictionary_size);
-    if (rar->lzss.window == NULL) {
+      new_size = rar_fls((unsigned int)rar->unp_size) << 1;
+    new_window = realloc(rar->lzss.window, new_size);
+    if (new_window == NULL) {
       archive_set_error(&a->archive, ENOMEM,
                         "Unable to allocate memory for uncompressed data.");
       return (ARCHIVE_FATAL);
     }
+    rar->lzss.window = (unsigned char *)new_window;
+    rar->dictionary_size = new_size;
     memset(rar->lzss.window, 0, rar->dictionary_size);
     rar->lzss.mask = rar->dictionary_size - 1;
   }
@@ -2221,10 +2472,12 @@ add_value(struct archive_read *a, struct huffman_code *code, int value,
 static int
 new_node(struct huffman_code *code)
 {
-  code->tree = (struct huffman_tree_node *)realloc(code->tree,
-    (code->numentries + 1) * sizeof(*code->tree));
-  if (code->tree == NULL)
+  void *new_tree;
+
+  new_tree = realloc(code->tree, (code->numentries + 1) * sizeof(*code->tree));
+  if (new_tree == NULL)
     return (-1);
+  code->tree = (struct huffman_tree_node *)new_tree;
   code->tree[code->numentries].branches[0] = -1;
   code->tree[code->numentries].branches[1] = -2;
   return 1;
@@ -2239,8 +2492,8 @@ make_table(struct archive_read *a, struct huffman_code *code)
     code->tablesize = code->maxlength;
 
   code->table =
-    (struct huffman_table_entry *)malloc(sizeof(*code->table)
-    * (1 << code->tablesize));
+    (struct huffman_table_entry *)calloc(1, sizeof(*code->table)
+    * ((size_t)1 << code->tablesize));
 
   return make_table_recurse(a, code, 0, code->table, 0, code->tablesize);
 }
@@ -2408,9 +2661,9 @@ expand(struct archive_read *a, int64_t end)
 
       if ((lensymbol = read_next_symbol(a, &rar->lengthcode)) < 0)
         goto bad_data;
-      if (lensymbol > sizeof(lengthbases)/sizeof(lengthbases[0]))
+      if (lensymbol > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
         goto bad_data;
-      if (lensymbol > sizeof(lengthbits)/sizeof(lengthbits[0]))
+      if (lensymbol > (int)(sizeof(lengthbits)/sizeof(lengthbits[0])))
         goto bad_data;
       len = lengthbases[lensymbol] + 2;
       if (lengthbits[lensymbol] > 0) {
@@ -2442,9 +2695,9 @@ expand(struct archive_read *a, int64_t end)
     }
     else
     {
-      if (symbol-271 > sizeof(lengthbases)/sizeof(lengthbases[0]))
+      if (symbol-271 > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
         goto bad_data;
-      if (symbol-271 > sizeof(lengthbits)/sizeof(lengthbits[0]))
+      if (symbol-271 > (int)(sizeof(lengthbits)/sizeof(lengthbits[0])))
         goto bad_data;
       len = lengthbases[symbol-271]+3;
       if(lengthbits[symbol-271] > 0) {
@@ -2456,9 +2709,9 @@ expand(struct archive_read *a, int64_t end)
 
       if ((offssymbol = read_next_symbol(a, &rar->offsetcode)) < 0)
         goto bad_data;
-      if (offssymbol > sizeof(offsetbases)/sizeof(offsetbases[0]))
+      if (offssymbol > (int)(sizeof(offsetbases)/sizeof(offsetbases[0])))
         goto bad_data;
-      if (offssymbol > sizeof(offsetbits)/sizeof(offsetbits[0]))
+      if (offssymbol > (int)(sizeof(offsetbits)/sizeof(offsetbits[0])))
         goto bad_data;
       offs = offsetbases[offssymbol]+1;
       if(offsetbits[offssymbol] > 0)
@@ -2572,3 +2825,34 @@ copy_from_lzss_window(struct archive_read *a, const void **buffer,
     *buffer = NULL;
   return (ARCHIVE_OK);
 }
+
+static const void *
+rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
+{
+  struct rar *rar = (struct rar *)(a->format->data);
+  const void *h = __archive_read_ahead(a, min, avail);
+  int ret;
+  if (avail)
+  {
+    if (a->read_data_is_posix_read && *avail > (ssize_t)a->read_data_requested)
+      *avail = a->read_data_requested;
+    if (*avail > rar->bytes_remaining)
+      *avail = (ssize_t)rar->bytes_remaining;
+    if (*avail < 0)
+      return NULL;
+    else if (*avail == 0 && rar->main_flags & MHD_VOLUME &&
+      rar->file_flags & FHD_SPLIT_AFTER)
+    {
+      ret = archive_read_format_rar_read_header(a, a->entry);
+      if (ret == (ARCHIVE_EOF))
+      {
+        rar->has_endarc_header = 1;
+        ret = archive_read_format_rar_read_header(a, a->entry);
+      }
+      if (ret != (ARCHIVE_OK))
+        return NULL;
+      return rar_read_ahead(a, min, avail);
+    }
+  }
+  return h;
+}
diff --git a/libarchive/archive_read_support_format_raw.c b/libarchive/archive_read_support_format_raw.c
index df2c00c..8434978 100644
--- a/libarchive/archive_read_support_format_raw.c
+++ b/libarchive/archive_read_support_format_raw.c
@@ -77,6 +77,7 @@ archive_read_support_format_raw(struct archive *_a)
 	    archive_read_format_raw_read_header,
 	    archive_read_format_raw_read_data,
 	    archive_read_format_raw_read_data_skip,
+	    NULL,
 	    archive_read_format_raw_cleanup);
 	if (r != ARCHIVE_OK)
 		free(info);
@@ -157,7 +158,7 @@ archive_read_format_raw_read_data(struct archive_read *a,
 		/* Record and return an error. */
 		*size = 0;
 		*offset = info->offset;
-		return (avail);
+		return ((int)avail);
 	}
 }
 
diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c
index 89a1d4f..e9523cb 100644
--- a/libarchive/archive_read_support_format_tar.c
+++ b/libarchive/archive_read_support_format_tar.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -210,10 +210,10 @@ static int	read_body_to_string(struct archive_read *, struct tar *,
 		    struct archive_string *, const void *h, size_t *);
 static int	solaris_sparse_parse(struct archive_read *, struct tar *,
 		    struct archive_entry *, const char *);
-static int64_t	tar_atol(const char *, unsigned);
-static int64_t	tar_atol10(const char *, unsigned);
-static int64_t	tar_atol256(const char *, unsigned);
-static int64_t	tar_atol8(const char *, unsigned);
+static int64_t	tar_atol(const char *, size_t);
+static int64_t	tar_atol10(const char *, size_t);
+static int64_t	tar_atol256(const char *, size_t);
+static int64_t	tar_atol8(const char *, size_t);
 static int	tar_read_header(struct archive_read *, struct tar *,
 		    struct archive_entry *, size_t *);
 static int	tohex(int c);
@@ -253,6 +253,7 @@ archive_read_support_format_tar(struct archive *_a)
 	    archive_read_format_tar_read_header,
 	    archive_read_format_tar_read_data,
 	    archive_read_format_tar_skip,
+	    NULL,
 	    archive_read_format_tar_cleanup);
 
 	if (r != ARCHIVE_OK)
@@ -369,7 +370,7 @@ archive_read_format_tar_options(struct archive_read *a,
 		/* Handle UTF-8 filnames as libarchive 2.x */
 		tar->compat_2x = (val != NULL)?1:0;
 		tar->init_default_conversion = tar->compat_2x;
-		ret = ARCHIVE_OK;
+		return (ARCHIVE_OK);
 	} else if (strcmp(key, "hdrcharset")  == 0) {
 		if (val == NULL || val[0] == 0)
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -383,11 +384,13 @@ archive_read_format_tar_options(struct archive_read *a,
 			else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "tar: unknown keyword ``%s''", key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 /* utility function- this exists to centralize the logic of tracking
@@ -525,56 +528,57 @@ archive_read_format_tar_read_data(struct archive_read *a,
 
 	tar = (struct tar *)(a->format->data);
 
-skip_hole:
-	/* Remove exhausted entries from sparse list. */
-	while (tar->sparse_list != NULL &&
-	    tar->sparse_list->remaining == 0) {
-		p = tar->sparse_list;
-		tar->sparse_list = p->next;
-		free(p);
-	}
+	for (;;) {
+		/* Remove exhausted entries from sparse list. */
+		while (tar->sparse_list != NULL &&
+		    tar->sparse_list->remaining == 0) {
+			p = tar->sparse_list;
+			tar->sparse_list = p->next;
+			free(p);
+		}
 
-	if (tar->entry_bytes_unconsumed) {
-		__archive_read_consume(a, tar->entry_bytes_unconsumed);
-		tar->entry_bytes_unconsumed = 0;
-	}
+		if (tar->entry_bytes_unconsumed) {
+			__archive_read_consume(a, tar->entry_bytes_unconsumed);
+			tar->entry_bytes_unconsumed = 0;
+		}
 
-	/* If we're at end of file, return EOF. */
-	if (tar->sparse_list == NULL || tar->entry_bytes_remaining == 0) {
-		if (__archive_read_consume(a, tar->entry_padding) < 0)
-			return (ARCHIVE_FATAL);
-		tar->entry_padding = 0;
-		*buff = NULL;
-		*size = 0;
-		*offset = tar->realsize;
-		return (ARCHIVE_EOF);
-	}
+		/* If we're at end of file, return EOF. */
+		if (tar->sparse_list == NULL ||
+		    tar->entry_bytes_remaining == 0) {
+			if (__archive_read_consume(a, tar->entry_padding) < 0)
+				return (ARCHIVE_FATAL);
+			tar->entry_padding = 0;
+			*buff = NULL;
+			*size = 0;
+			*offset = tar->realsize;
+			return (ARCHIVE_EOF);
+		}
 
-	*buff = __archive_read_ahead(a, 1, &bytes_read);
-	if (bytes_read < 0)
-		return (ARCHIVE_FATAL);
-	if (*buff == NULL) {
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "Truncated tar archive");
-		return (ARCHIVE_FATAL);
+		*buff = __archive_read_ahead(a, 1, &bytes_read);
+		if (bytes_read < 0)
+			return (ARCHIVE_FATAL);
+		if (*buff == NULL) {
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Truncated tar archive");
+			return (ARCHIVE_FATAL);
+		}
+		if (bytes_read > tar->entry_bytes_remaining)
+			bytes_read = (ssize_t)tar->entry_bytes_remaining;
+		/* Don't read more than is available in the
+		 * current sparse block. */
+		if (tar->sparse_list->remaining < bytes_read)
+			bytes_read = (ssize_t)tar->sparse_list->remaining;
+		*size = bytes_read;
+		*offset = tar->sparse_list->offset;
+		tar->sparse_list->remaining -= bytes_read;
+		tar->sparse_list->offset += bytes_read;
+		tar->entry_bytes_remaining -= bytes_read;
+		tar->entry_bytes_unconsumed = bytes_read;
+
+		if (!tar->sparse_list->hole)
+			return (ARCHIVE_OK);
+		/* Current is hole data and skip this. */
 	}
-	if (bytes_read > tar->entry_bytes_remaining)
-		bytes_read = tar->entry_bytes_remaining;
-	/* Don't read more than is available in the
-	 * current sparse block. */
-	if (tar->sparse_list->remaining < bytes_read)
-		bytes_read = tar->sparse_list->remaining;
-	*size = bytes_read;
-	*offset = tar->sparse_list->offset;
-	tar->sparse_list->remaining -= bytes_read;
-	tar->sparse_list->offset += bytes_read;
-	tar->entry_bytes_remaining -= bytes_read;
-	tar->entry_bytes_unconsumed = bytes_read;
-
-	if (tar->sparse_list->hole)
-		goto skip_hole;
-
-	return (ARCHIVE_OK);
 }
 
 static int
@@ -613,13 +617,14 @@ tar_read_header(struct archive_read *a, struct tar *tar,
 	int err;
 	const char *h;
 	const struct archive_entry_header_ustar *header;
+	const struct archive_entry_header_gnutar *gnuheader;
 
 	tar_flush_unconsumed(a, unconsumed);
 
 	/* Read 512-byte header record */
 	h = __archive_read_ahead(a, 512, &bytes);
 	if (bytes < 0)
-		return (bytes);
+		return ((int)bytes);
 	if (bytes == 0) { /* EOF at a block boundary. */
 		/* Some writers do omit the block of nulls. <sigh> */
 		return (ARCHIVE_EOF);
@@ -700,7 +705,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
 		err = header_pax_extensions(a, tar, entry, h, unconsumed);
 		break;
 	default:
-		if (memcmp(header->magic, "ustar  \0", 8) == 0) {
+		gnuheader = (const struct archive_entry_header_gnutar *)h;
+		if (memcmp(gnuheader->magic, "ustar  \0", 8) == 0) {
 			a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
 			a->archive.archive_format_name = "GNU tar format";
 			err = header_gnutar(a, tar, entry, h, unconsumed);
@@ -749,7 +755,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
 				bytes_read = gnu_sparse_10_read(a, tar, unconsumed);
 				tar->entry_bytes_remaining -= bytes_read;
 				if (bytes_read < 0)
-					return (bytes_read);
+					return ((int)bytes_read);
 			} else {
 				archive_set_error(&a->archive,
 				    ARCHIVE_ERRNO_MISC,
@@ -784,7 +790,7 @@ checksum(struct archive_read *a, const void *h)
 	 * Test the checksum.  Note that POSIX specifies _unsigned_
 	 * bytes for this calculation.
 	 */
-	sum = tar_atol(header->checksum, sizeof(header->checksum));
+	sum = (int)tar_atol(header->checksum, sizeof(header->checksum));
 	check = 0;
 	for (i = 0; i < 148; i++)
 		check += (unsigned char)bytes[i];
@@ -845,7 +851,7 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
 	 * more to make sure that we don't overrun acl_text later.
 	 */
 	header = (const struct archive_entry_header_ustar *)h;
-	size = tar_atol(header->size, sizeof(header->size));
+	size = (size_t)tar_atol(header->size, sizeof(header->size));
 	err = read_body_to_string(a, tar, &(tar->acl_text), h, unconsumed);
 	if (err != ARCHIVE_OK)
 		return (err);
@@ -1019,7 +1025,7 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
 	}
 
 	/* Fail if we can't make our buffer big enough. */
-	if (archive_string_ensure(as, size+1) == NULL) {
+	if (archive_string_ensure(as, (size_t)size+1) == NULL) {
 		archive_set_error(&a->archive, ENOMEM,
 		    "No memory");
 		return (ARCHIVE_FATAL);
@@ -1028,15 +1034,15 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
 	tar_flush_unconsumed(a, unconsumed);
 
 	/* Read the body into the string. */
-	*unconsumed = (size + 511) & ~ 511;
+	*unconsumed = (size_t)((size + 511) & ~ 511);
 	src = __archive_read_ahead(a, *unconsumed, NULL);
 	if (src == NULL) {
 		*unconsumed = 0;
 		return (ARCHIVE_FATAL);
 	}
-	memcpy(as->s, src, size);
+	memcpy(as->s, src, (size_t)size);
 	as->s[size] = '\0';
-	as->length = size;
+	as->length = (size_t)size;
 	return (ARCHIVE_OK);
 }
 
@@ -1066,7 +1072,8 @@ header_common(struct archive_read *a, struct tar *tar,
 		archive_string_empty(&(tar->entry_linkpath));
 
 	/* Parse out the numeric fields (all are octal) */
-	archive_entry_set_mode(entry, tar_atol(header->mode, sizeof(header->mode)));
+	archive_entry_set_mode(entry,
+		(mode_t)tar_atol(header->mode, sizeof(header->mode)));
 	archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid)));
 	archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
 	tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size));
@@ -1308,13 +1315,13 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar,
 	 * Q: Is the above idea really possible?  Even
 	 * when there are GNU or pax extension entries?
 	 */
-	data = __archive_read_ahead(a, size, NULL);
+	data = __archive_read_ahead(a, (size_t)size, NULL);
 	if (data == NULL) {
 		*unconsumed = 0;
 		return (ARCHIVE_FATAL);
 	}
-	archive_entry_copy_mac_metadata(entry, data, size);
-	*unconsumed = (size + 511) & ~ 511;
+	archive_entry_copy_mac_metadata(entry, data, (size_t)size);
+	*unconsumed = (size_t)((size + 511) & ~ 511);
 	tar_flush_unconsumed(a, unconsumed);
 	return (tar_read_header(a, tar, entry, unconsumed));
 }
@@ -1422,9 +1429,9 @@ header_ustar(struct archive_read *a, struct tar *tar,
 
 	/* Parse out device numbers only for char and block specials. */
 	if (header->typeflag[0] == '3' || header->typeflag[0] == '4') {
-		archive_entry_set_rdevmajor(entry,
+		archive_entry_set_rdevmajor(entry, (dev_t)
 		    tar_atol(header->rdevmajor, sizeof(header->rdevmajor)));
-		archive_entry_set_rdevminor(entry,
+		archive_entry_set_rdevminor(entry, (dev_t)
 		    tar_atol(header->rdevminor, sizeof(header->rdevminor)));
 	}
 
@@ -1661,6 +1668,9 @@ pax_attribute(struct archive_read *a, struct tar *tar,
 	long n;
 	int err = ARCHIVE_OK, r;
 
+	if (value == NULL)
+		value = "";	/* Disable compiler warning; do not pass
+				 * NULL pointer to strlen().  */
 	switch (key[0]) {
 	case 'G':
 		/* GNU "0.0" sparse pax format. */
@@ -1707,11 +1717,11 @@ pax_attribute(struct archive_read *a, struct tar *tar,
 
 		/* GNU "1.0" sparse pax format */
 		if (strcmp(key, "GNU.sparse.major") == 0) {
-			tar->sparse_gnu_major = tar_atol10(value, strlen(value));
+			tar->sparse_gnu_major = (int)tar_atol10(value, strlen(value));
 			tar->sparse_gnu_pending = 1;
 		}
 		if (strcmp(key, "GNU.sparse.minor") == 0) {
-			tar->sparse_gnu_minor = tar_atol10(value, strlen(value));
+			tar->sparse_gnu_minor = (int)tar_atol10(value, strlen(value));
 			tar->sparse_gnu_pending = 1;
 		}
 		if (strcmp(key, "GNU.sparse.name") == 0) {
@@ -1794,20 +1804,20 @@ pax_attribute(struct archive_read *a, struct tar *tar,
 			}
 		} else if (strcmp(key, "SCHILY.devmajor") == 0) {
 			archive_entry_set_rdevmajor(entry,
-			    tar_atol10(value, strlen(value)));
+			    (dev_t)tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.devminor") == 0) {
 			archive_entry_set_rdevminor(entry,
-			    tar_atol10(value, strlen(value)));
+			    (dev_t)tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.fflags") == 0) {
 			archive_entry_copy_fflags_text(entry, value);
 		} else if (strcmp(key, "SCHILY.dev") == 0) {
 			archive_entry_set_dev(entry,
-			    tar_atol10(value, strlen(value)));
+			    (dev_t)tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.ino") == 0) {
 			archive_entry_set_ino(entry,
 			    tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.nlink") == 0) {
-			archive_entry_set_nlink(entry,
+			archive_entry_set_nlink(entry, (unsigned)
 			    tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.realsize") == 0) {
 			tar->realsize = tar_atol10(value, strlen(value));
@@ -2016,9 +2026,9 @@ header_gnutar(struct archive_read *a, struct tar *tar,
 
 	/* Parse out device numbers only for char and block specials */
 	if (header->typeflag[0] == '3' || header->typeflag[0] == '4') {
-		archive_entry_set_rdevmajor(entry,
+		archive_entry_set_rdevmajor(entry, (dev_t)
 		    tar_atol(header->rdevmajor, sizeof(header->rdevmajor)));
-		archive_entry_set_rdevminor(entry,
+		archive_entry_set_rdevminor(entry, (dev_t)
 		    tar_atol(header->rdevminor, sizeof(header->rdevminor)));
 	} else
 		archive_entry_set_rdev(entry, 0);
@@ -2253,7 +2263,8 @@ gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
 	 * don't require this, but they should.
 	 */
 	do {
-		bytes_read = readline(a, tar, &p, tar_min(*remaining, 100), unconsumed);
+		bytes_read = readline(a, tar, &p,
+			(ssize_t)tar_min(*remaining, 100), unconsumed);
 		if (bytes_read <= 0)
 			return (ARCHIVE_FATAL);
 		*remaining -= bytes_read;
@@ -2294,7 +2305,7 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed)
 	remaining = tar->entry_bytes_remaining;
 
 	/* Parse entries. */
-	entries = gnu_sparse_10_atol(a, tar, &remaining, unconsumed);
+	entries = (int)gnu_sparse_10_atol(a, tar, &remaining, unconsumed);
 	if (entries < 0)
 		return (ARCHIVE_FATAL);
 	/* Parse the individual entries. */
@@ -2312,16 +2323,16 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed)
 	}
 	/* Skip rest of block... */
 	tar_flush_unconsumed(a, unconsumed);
-	bytes_read = tar->entry_bytes_remaining - remaining;
+	bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining);
 	to_skip = 0x1ff & -bytes_read;
 	if (to_skip != __archive_read_consume(a, to_skip))
 		return (ARCHIVE_FATAL);
-	return (bytes_read + to_skip);
+	return ((ssize_t)(bytes_read + to_skip));
 }
 
 /*
  * Solaris pax extension for a sparse file. This is recorded with the
- * data and hole pairs. The way recording sparse infomation by Solaris'
+ * data and hole pairs. The way recording sparse information by Solaris'
  * pax simply indicates where data and sparse are, so the stored contents
  * consist of both data and hole.
  */
@@ -2333,6 +2344,8 @@ solaris_sparse_parse(struct archive_read *a, struct tar *tar,
 	int64_t start, end;
 	int hole = 1;
 
+	(void)entry; /* UNUSED */
+
 	end = 0;
 	if (*p == ' ')
 		p++;
@@ -2380,7 +2393,7 @@ solaris_sparse_parse(struct archive_read *a, struct tar *tar,
  * On read, this implementation supports both extensions.
  */
 static int64_t
-tar_atol(const char *p, unsigned char_cnt)
+tar_atol(const char *p, size_t char_cnt)
 {
 	/*
 	 * Technically, GNU tar considers a field to be in base-256
@@ -2397,70 +2410,55 @@ tar_atol(const char *p, unsigned char_cnt)
  * it does obey locale.
  */
 static int64_t
-tar_atol8(const char *p, unsigned char_cnt)
+tar_atol_base_n(const char *p, size_t char_cnt, int base)
 {
 	int64_t	l, limit, last_digit_limit;
-	int digit, sign, base;
+	int digit, sign;
 
-	base = 8;
 	limit = INT64_MAX / base;
 	last_digit_limit = INT64_MAX % base;
 
-	while (*p == ' ' || *p == '\t')
+	/* the pointer will not be dereferenced if char_cnt is zero
+	 * due to the way the && operator is evaulated.
+	 */
+	while (char_cnt != 0 && (*p == ' ' || *p == '\t')) {
 		p++;
-	if (*p == '-') {
+		char_cnt--;
+	}
+
+	sign = 1;
+	if (char_cnt != 0 && *p == '-') {
 		sign = -1;
 		p++;
-	} else
-		sign = 1;
+		char_cnt--;
+	}
 
 	l = 0;
-	digit = *p - '0';
-	while (digit >= 0 && digit < base  && char_cnt-- > 0) {
-		if (l>limit || (l == limit && digit > last_digit_limit)) {
-			l = INT64_MAX; /* Truncate on overflow. */
-			break;
+	if (char_cnt != 0) {
+		digit = *p - '0';
+		while (digit >= 0 && digit < base  && char_cnt != 0) {
+			if (l>limit || (l == limit && digit > last_digit_limit)) {
+				l = INT64_MAX; /* Truncate on overflow. */
+				break;
+			}
+			l = (l * base) + digit;
+			digit = *++p - '0';
+			char_cnt--;
 		}
-		l = (l * base) + digit;
-		digit = *++p - '0';
 	}
 	return (sign < 0) ? -l : l;
 }
 
-/*
- * Note that this implementation does not (and should not!) obey
- * locale settings; you cannot simply substitute strtol here, since
- * it does obey locale.
- */
 static int64_t
-tar_atol10(const char *p, unsigned char_cnt)
+tar_atol8(const char *p, size_t char_cnt)
 {
-	int64_t l, limit, last_digit_limit;
-	int base, digit, sign;
-
-	base = 10;
-	limit = INT64_MAX / base;
-	last_digit_limit = INT64_MAX % base;
-
-	while (*p == ' ' || *p == '\t')
-		p++;
-	if (*p == '-') {
-		sign = -1;
-		p++;
-	} else
-		sign = 1;
+	return tar_atol_base_n(p, char_cnt, 8);
+}
 
-	l = 0;
-	digit = *p - '0';
-	while (digit >= 0 && digit < base  && char_cnt-- > 0) {
-		if (l > limit || (l == limit && digit > last_digit_limit)) {
-			l = INT64_MAX; /* Truncate on overflow. */
-			break;
-		}
-		l = (l * base) + digit;
-		digit = *++p - '0';
-	}
-	return (sign < 0) ? -l : l;
+static int64_t
+tar_atol10(const char *p, size_t char_cnt)
+{
+	return tar_atol_base_n(p, char_cnt, 10);
 }
 
 /*
@@ -2469,7 +2467,7 @@ tar_atol10(const char *p, unsigned char_cnt)
  * ignored.
  */
 static int64_t
-tar_atol256(const char *_p, unsigned char_cnt)
+tar_atol256(const char *_p, size_t char_cnt)
 {
 	int64_t	l, upper_limit, lower_limit;
 	const unsigned char *p = (const unsigned char *)_p;
diff --git a/libarchive/archive_read_support_format_xar.c b/libarchive/archive_read_support_format_xar.c
index 3c01cbe..780e749 100644
--- a/libarchive/archive_read_support_format_xar.c
+++ b/libarchive/archive_read_support_format_xar.c
@@ -183,9 +183,9 @@ struct xar_file {
 	time_t			 mtime;
 	time_t			 atime;
 	struct archive_string	 uname;
-	uid_t			 uid;
+	int64_t			 uid;
 	struct archive_string	 gname;
-	gid_t			 gid;
+	int64_t			 gid;
 	mode_t			 mode;
 	dev_t			 dev;
 	dev_t			 devmajor;
@@ -467,6 +467,7 @@ archive_read_support_format_xar(struct archive *_a)
 	    xar_read_header,
 	    xar_read_data,
 	    xar_read_data_skip,
+	    NULL,
 	    xar_cleanup);
 	if (r != ARCHIVE_OK)
 		free(xar);
@@ -602,7 +603,8 @@ read_toc(struct archive_read *a)
 		r = move_reading_point(a, xar->toc_chksum_offset);
 		if (r != ARCHIVE_OK)
 			return (r);
-		b = __archive_read_ahead(a, xar->toc_chksum_size, &bytes);
+		b = __archive_read_ahead(a,
+			(size_t)xar->toc_chksum_size, &bytes);
 		if (bytes < 0)
 			return ((int)bytes);
 		if ((uint64_t)bytes < xar->toc_chksum_size) {
@@ -611,7 +613,8 @@ read_toc(struct archive_read *a)
 			    "Truncated archive file");
 			return (ARCHIVE_FATAL);
 		}
-		r = checksum_final(a, b, xar->toc_chksum_size, NULL, 0);
+		r = checksum_final(a, b,
+			(size_t)xar->toc_chksum_size, NULL, 0);
 		__archive_read_consume(a, xar->toc_chksum_size);
 		xar->offset += xar->toc_chksum_size;
 		if (r != ARCHIVE_OK)
@@ -2065,7 +2068,7 @@ xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
 					xar->file->hdnext = xar->hdlink_orgs;
 					xar->hdlink_orgs = xar->file;
 				} else {
-					xar->file->link = atol10(attr->value,
+					xar->file->link = (unsigned)atol10(attr->value,
 					    strlen(attr->value));
 					if (xar->file->link > 0)
 						if (add_link(a, xar, xar->file) != ARCHIVE_OK) {
@@ -2624,6 +2627,7 @@ strappend_base64(struct xar *xar,
 	const unsigned char *b;
 	size_t len;
 
+	(void)xar; /* UNUSED */
 	len = 0;
 	out = buff;
 	b = (const unsigned char *)s;
@@ -2760,7 +2764,7 @@ xml_data(void *userData, const char *s, int len)
 		xar->file->has |= HAS_MODE;
 		xar->file->mode =
 		    (xar->file->mode & AE_IFMT) |
-		    (atol8(s, len) & ~AE_IFMT);
+		    ((mode_t)(atol8(s, len)) & ~AE_IFMT);
 		break;
 	case FILE_GROUP:
 		xar->file->has |= HAS_GID;
@@ -3075,12 +3079,15 @@ xml2_xmlattr_setup(struct archive_read *a,
 		attr->name = strdup(
 		    (const char *)xmlTextReaderConstLocalName(reader));
 		if (attr->name == NULL) {
+			free(attr);
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
 		}
 		attr->value = strdup(
 		    (const char *)xmlTextReaderConstValue(reader));
 		if (attr->value == NULL) {
+			free(attr->name);
+			free(attr);
 			archive_set_error(&a->archive, ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
 		}
diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c
index a812422..450a6f7 100644
--- a/libarchive/archive_read_support_format_zip.c
+++ b/libarchive/archive_read_support_format_zip.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2004 Tim Kientzle
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,23 +38,26 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102
 #endif
 
 #include "archive.h"
+#include "archive_endian.h"
 #include "archive_entry.h"
 #include "archive_entry_locale.h"
 #include "archive_private.h"
+#include "archive_rb.h"
 #include "archive_read_private.h"
-#include "archive_endian.h"
 
 #ifndef HAVE_ZLIB_H
 #include "archive_crc32.h"
 #endif
 
 struct zip_entry {
+	struct archive_rb_node	node;
 	int64_t			local_header_offset;
 	int64_t			compressed_size;
 	int64_t			uncompressed_size;
 	int64_t			gid;
 	int64_t			uid;
 	struct archive_entry	*entry;
+	struct archive_string	rsrcname;
 	time_t			mtime;
 	time_t			atime;
 	time_t			ctime;
@@ -67,15 +70,19 @@ struct zip_entry {
 
 struct zip {
 	/* Structural information about the archive. */
+	int64_t			end_of_central_directory_offset;
 	int64_t			central_directory_offset;
 	size_t			central_directory_size;
 	size_t			central_directory_entries;
 	char			have_central_directory;
+	int64_t			offset;
 
 	/* List of entries (seekable Zip only) */
 	size_t			entries_remaining;
 	struct zip_entry	*zip_entries;
 	struct zip_entry	*entry;
+	struct archive_rb_tree	tree;
+	struct archive_rb_tree	tree_rsrc;
 
 	size_t			unconsumed;
 
@@ -116,29 +123,36 @@ struct zip {
 #define ZIP_STRONG_ENCRYPTED	(1<<6)	
 #define ZIP_UTF8_NAME		(1<<11)	
 
-static int	archive_read_format_zip_streamable_bid(struct archive_read *, int);
-static int	archive_read_format_zip_seekable_bid(struct archive_read *, int);
+static int	archive_read_format_zip_streamable_bid(struct archive_read *,
+		    int);
+static int	archive_read_format_zip_seekable_bid(struct archive_read *,
+		    int);
 static int	archive_read_format_zip_options(struct archive_read *,
 		    const char *, const char *);
 static int	archive_read_format_zip_cleanup(struct archive_read *);
 static int	archive_read_format_zip_read_data(struct archive_read *,
 		    const void **, size_t *, int64_t *);
 static int	archive_read_format_zip_read_data_skip(struct archive_read *a);
-static int	archive_read_format_zip_seekable_read_header(struct archive_read *,
-		    struct archive_entry *);
-static int	archive_read_format_zip_streamable_read_header(struct archive_read *,
-		    struct archive_entry *);
+static int	archive_read_format_zip_seekable_read_header(
+		    struct archive_read *, struct archive_entry *);
+static int	archive_read_format_zip_streamable_read_header(
+		    struct archive_read *, struct archive_entry *);
+static ssize_t	zip_get_local_file_header_size(struct archive_read *, size_t);
 #ifdef HAVE_ZLIB_H
+static int	zip_deflate_init(struct archive_read *, struct zip *);
 static int	zip_read_data_deflate(struct archive_read *a, const void **buff,
 		    size_t *size, int64_t *offset);
 #endif
 static int	zip_read_data_none(struct archive_read *a, const void **buff,
 		    size_t *size, int64_t *offset);
 static int	zip_read_local_file_header(struct archive_read *a,
-    struct archive_entry *entry, struct zip *);
+		    struct archive_entry *entry, struct zip *);
 static time_t	zip_time(const char *);
 static const char *compression_name(int compression);
-static void process_extra(const char *, size_t, struct zip_entry *);
+static void	process_extra(const char *, size_t, struct zip_entry *);
+
+int	archive_read_support_format_zip_streamable(struct archive *);
+int	archive_read_support_format_zip_seekable(struct archive *);
 
 int
 archive_read_support_format_zip_streamable(struct archive *_a)
@@ -166,6 +180,7 @@ archive_read_support_format_zip_streamable(struct archive *_a)
 	    archive_read_format_zip_streamable_read_header,
 	    archive_read_format_zip_read_data,
 	    archive_read_format_zip_read_data_skip,
+	    NULL,
 	    archive_read_format_zip_cleanup);
 
 	if (r != ARCHIVE_OK)
@@ -199,6 +214,7 @@ archive_read_support_format_zip_seekable(struct archive *_a)
 	    archive_read_format_zip_seekable_read_header,
 	    archive_read_format_zip_read_data,
 	    archive_read_format_zip_read_data_skip,
+	    NULL,
 	    archive_read_format_zip_cleanup);
 
 	if (r != ARCHIVE_OK)
@@ -217,14 +233,13 @@ archive_read_support_format_zip(struct archive *a)
 }
 
 /*
- * TODO: This is a performance sink because it forces
- * the read core to drop buffered data from the start
- * of file, which will then have to be re-read again
- * if this bidder loses.
+ * TODO: This is a performance sink because it forces the read core to
+ * drop buffered data from the start of file, which will then have to
+ * be re-read again if this bidder loses.
  *
- * Consider passing in the winning bid value to subsequent
- * bidders so that this bidder in particular can avoid
- * seeking if it knows it's going to lose anyway.
+ * We workaround this a little by passing in the best bid so far so
+ * that later bidders can do nothing if they know they'll never
+ * outbid.  But we can certainly do better...
  */
 static int
 archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
@@ -249,8 +264,48 @@ archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
 	/* First four bytes are signature for end of central directory
 	   record.  Four zero bytes ensure this isn't a multi-volume
 	   Zip file (which we don't yet support). */
-	if (memcmp(p, "PK\005\006\000\000\000\000", 8) != 0)
-		return 0;
+	if (memcmp(p, "PK\005\006\000\000\000\000", 8) != 0) {
+		int64_t i, tail;
+		int found;
+
+		/*
+		 * If there is a comment in end of central directory
+		 * record, 22 bytes are too short. we have to read more
+		 * to properly detect the record. Hopefully, a length
+		 * of the comment is not longer than 16362 bytes(16K-22).
+		 */
+		if (filesize + 22 > 1024 * 16) {
+			tail = 1024 * 16;
+			filesize = __archive_read_seek(a, tail * -1, SEEK_END);
+		} else {
+			tail = filesize + 22;
+			filesize = __archive_read_seek(a, 0, SEEK_SET);
+		}
+		if (filesize < 0)
+			return 0;
+		if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL)
+			return 0;
+		for (found = 0, i = 0;!found && i < tail - 22;) {
+			switch (p[i]) {
+			case 'P':
+				if (memcmp(p+i,
+				    "PK\005\006\000\000\000\000", 8) == 0) {
+					p += i;
+					filesize += tail -
+					    (22 + archive_le16dec(p+20));
+					found = 1;
+				} else
+					i += 8;
+				break;
+			case 'K': i += 7; break;
+			case 005: i += 6; break;
+			case 006: i += 5; break;
+			default: i += 1; break;
+			}
+		}
+		if (!found)
+			return 0;
+	}
 
 	/* Since we've already done the hard work of finding the
 	   end of central directory record, let's save the important
@@ -258,12 +313,14 @@ archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
 	zip->central_directory_entries = archive_le16dec(p + 10);
 	zip->central_directory_size = archive_le32dec(p + 12);
 	zip->central_directory_offset = archive_le32dec(p + 16);
+	zip->end_of_central_directory_offset = filesize;
 
 	/* Just one volume, so central dir must all be on this volume. */
 	if (zip->central_directory_entries != archive_le16dec(p + 8))
 		return 0;
 	/* Central directory can't extend beyond end of this file. */
-	if (zip->central_directory_offset + zip->central_directory_size > filesize)
+	if (zip->central_directory_offset +
+	    (int64_t)zip->central_directory_size > filesize)
 		return 0;
 
 	/* This is just a tiny bit higher than the maximum returned by
@@ -273,18 +330,117 @@ archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
 }
 
 static int
+cmp_node(const struct archive_rb_node *n1, const struct archive_rb_node *n2)
+{
+	const struct zip_entry *e1 = (const struct zip_entry *)n1;
+	const struct zip_entry *e2 = (const struct zip_entry *)n2;
+
+	return ((int)(e2->local_header_offset - e1->local_header_offset));
+}
+
+static int
+cmp_key(const struct archive_rb_node *n, const void *key)
+{
+	/* This function won't be called */
+	(void)n; /* UNUSED */
+	(void)key; /* UNUSED */
+	return 1;
+}
+
+static int
+rsrc_cmp_node(const struct archive_rb_node *n1,
+    const struct archive_rb_node *n2)
+{
+	const struct zip_entry *e1 = (const struct zip_entry *)n1;
+	const struct zip_entry *e2 = (const struct zip_entry *)n2;
+
+	return (strcmp(e2->rsrcname.s, e1->rsrcname.s));
+}
+
+static int
+rsrc_cmp_key(const struct archive_rb_node *n, const void *key)
+{
+	const struct zip_entry *e = (const struct zip_entry *)n;
+	return (strcmp((const char *)key, e->rsrcname.s));
+}
+
+static const char *
+rsrc_basename(const char *name, size_t name_length)
+{
+	const char *s, *r;
+
+	r = s = name;
+	for (;;) {
+		s = memchr(s, '/', name_length - (s - name));
+		if (s == NULL)
+			break;
+		r = ++s;
+	}
+	return (r);
+}
+
+static void
+expose_parent_dirs(struct zip *zip, const char *name, size_t name_length)
+{
+	struct archive_string str;
+	struct zip_entry *dir;
+	char *s;
+
+	archive_string_init(&str);
+	archive_strncpy(&str, name, name_length);
+	for (;;) {
+		s = strrchr(str.s, '/');
+		if (s == NULL)
+			break;
+		*s = '\0';
+		/* Transfer the parent directory from zip->tree_rsrc RB
+		 * tree to zip->tree RB tree to expose. */
+		dir = (struct zip_entry *)
+		    __archive_rb_tree_find_node(&zip->tree_rsrc, str.s);
+		if (dir == NULL)
+			break;
+		__archive_rb_tree_remove_node(&zip->tree_rsrc, &dir->node);
+		archive_string_free(&dir->rsrcname);
+		__archive_rb_tree_insert_node(&zip->tree, &dir->node);
+	}
+	archive_string_free(&str);
+}
+
+static int
 slurp_central_directory(struct archive_read *a, struct zip *zip)
 {
 	unsigned i;
+	int64_t correction;
+	static const struct archive_rb_tree_ops rb_ops = {
+		&cmp_node, &cmp_key
+	};
+	static const struct archive_rb_tree_ops rb_rsrc_ops = {
+		&rsrc_cmp_node, &rsrc_cmp_key
+	};
+
+	/*
+	 * Consider the archive file we are reading may be SFX.
+	 * So we have to calculate a SFX header size to revise
+	 * ZIP header offsets.
+	 */
+	correction = zip->end_of_central_directory_offset -
+	    (zip->central_directory_offset + zip->central_directory_size);
+	/* The central directory offset is relative value, and so
+	 * we revise this offset for SFX. */
+	zip->central_directory_offset += correction;
 
 	__archive_read_seek(a, zip->central_directory_offset, SEEK_SET);
+	zip->offset = zip->central_directory_offset;
+	__archive_rb_tree_init(&zip->tree, &rb_ops);
+	__archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops);
 
-	zip->zip_entries = calloc(zip->central_directory_entries, sizeof(struct zip_entry));
+	zip->zip_entries = calloc(zip->central_directory_entries,
+				sizeof(struct zip_entry));
 	for (i = 0; i < zip->central_directory_entries; ++i) {
 		struct zip_entry *zip_entry = &zip->zip_entries[i];
 		size_t filename_length, extra_length, comment_length;
 		uint32_t external_attributes;
-		const char *p;
+		const char *name, *p, *r;
 
 		if ((p = __archive_read_ahead(a, 46, NULL)) == NULL)
 			return ARCHIVE_FATAL;
@@ -298,7 +454,7 @@ slurp_central_directory(struct archive_read *a, struct zip *zip)
 		zip_entry->system = p[5];
 		/* version_required = archive_le16dec(p + 6); */
 		zip_entry->flags = archive_le16dec(p + 8);
-		zip_entry->compression = archive_le16dec(p + 10);
+		zip_entry->compression = (char)archive_le16dec(p + 10);
 		zip_entry->mtime = zip_time(p + 12);
 		zip_entry->crc32 = archive_le32dec(p + 16);
 		zip_entry->compressed_size = archive_le32dec(p + 20);
@@ -309,31 +465,233 @@ slurp_central_directory(struct archive_read *a, struct zip *zip)
 		/* disk_start = archive_le16dec(p + 34); */ /* Better be zero. */
 		/* internal_attributes = archive_le16dec(p + 36); */ /* text bit */
 		external_attributes = archive_le32dec(p + 38);
-		zip_entry->local_header_offset = archive_le32dec(p + 42);
+		zip_entry->local_header_offset =
+		    archive_le32dec(p + 42) + correction;
 
+		/* If we can't guess the mode, leave it zero here;
+		   when we read the local file header we might get
+		   more information. */
+		zip_entry->mode = 0;
 		if (zip_entry->system == 3) {
 			zip_entry->mode = external_attributes >> 16;
+		}
+
+		/*
+		 * Mac resource fork files are stored under the
+		 * "__MACOSX/" directory, so we should check if
+		 * it is.
+		 */
+		/* Make sure we have the file name. */
+		if ((p = __archive_read_ahead(a, 46 + filename_length, NULL))
+		    == NULL)
+			return ARCHIVE_FATAL;
+		name = p + 46;
+		r = rsrc_basename(name, filename_length);
+		if (filename_length >= 9 &&
+		    strncmp("__MACOSX/", name, 9) == 0) {
+			/* If this file is not a resource fork nor
+			 * a directory. We should treat it as a non
+			 * resource fork file to expose it. */
+			if (name[filename_length-1] != '/' &&
+			    (r - name < 3 || r[0] != '.' || r[1] != '_')) {
+				__archive_rb_tree_insert_node(&zip->tree,
+				    &zip_entry->node);
+				/* Expose its parent directories. */
+				expose_parent_dirs(zip, name, filename_length);
+			} else {
+				/* This file is a resource fork file or
+				 * a directory. */
+				archive_strncpy(&(zip_entry->rsrcname), name,
+				    filename_length);
+				__archive_rb_tree_insert_node(&zip->tree_rsrc,
+				    &zip_entry->node);
+			}
 		} else {
-			zip_entry->mode = AE_IFREG | 0777;
+			/* Generate resource fork name to find its resource
+			 * file at zip->tree_rsrc. */
+			archive_strcpy(&(zip_entry->rsrcname), "__MACOSX/");
+			archive_strncat(&(zip_entry->rsrcname), name, r - name);
+			archive_strcat(&(zip_entry->rsrcname), "._");
+			archive_strncat(&(zip_entry->rsrcname),
+			    name + (r - name), filename_length - (r - name));
+			/* Register an entry to RB tree to sort it by
+			 * file offset. */
+			__archive_rb_tree_insert_node(&zip->tree,
+			    &zip_entry->node);
 		}
 
-		/* Do we need to parse filename here? */
-		/* Or can we wait until we read the local header? */
+		/* We don't read the filename until we get to the
+		   local file header.  Reading it here would speed up
+		   table-of-contents operations (removing the need to
+		   find and read local file header to get the
+		   filename) at the cost of requiring a lot of extra
+		   space. */
+		/* We don't read the extra block here.  We assume it
+		   will be duplicated at the local file header. */
 		__archive_read_consume(a,
 		    46 + filename_length + extra_length + comment_length);
 	}
 
-	/* TODO: Sort zip entries. */
-
 	return ARCHIVE_OK;
 }
 
+static int64_t
+zip_read_consume(struct archive_read *a, int64_t bytes)
+{
+	struct zip *zip = (struct zip *)a->format->data;
+	int64_t skip;
+
+	skip = __archive_read_consume(a, bytes);
+	if (skip > 0)
+		zip->offset += skip;
+	return (skip);
+}
+
+static int
+zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
+    struct zip_entry *rsrc)
+{
+	struct zip *zip = (struct zip *)a->format->data;
+	unsigned char *metadata, *mp;
+	int64_t offset = zip->offset;
+	size_t remaining_bytes, metadata_bytes;
+	ssize_t hsize;
+	int ret = ARCHIVE_OK, eof;
+
+	switch(rsrc->compression) {
+	case 0:  /* No compression. */
+#ifdef HAVE_ZLIB_H
+	case 8: /* Deflate compression. */
+#endif
+		break;
+	default: /* Unsupported compression. */
+		/* Return a warning. */
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+		    "Unsupported ZIP compression method (%s)",
+		    compression_name(rsrc->compression));
+		/* We can't decompress this entry, but we will
+		 * be able to skip() it and try the next entry. */
+		return (ARCHIVE_WARN);
+	}
+
+	if (rsrc->uncompressed_size > (128 * 1024)) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+		    "Mac metadata is too large: %jd > 128K bytes",
+		    (intmax_t)rsrc->uncompressed_size);
+		return (ARCHIVE_WARN);
+	}
+
+	metadata = malloc((size_t)rsrc->uncompressed_size);
+	if (metadata == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate memory for Mac metadata");
+		return (ARCHIVE_FATAL);
+	}
+
+	if (zip->offset < rsrc->local_header_offset)
+		zip_read_consume(a, rsrc->local_header_offset - zip->offset);
+	else if (zip->offset != rsrc->local_header_offset) {
+		__archive_read_seek(a, rsrc->local_header_offset, SEEK_SET);
+		zip->offset = zip->entry->local_header_offset;
+	}
+
+	hsize = zip_get_local_file_header_size(a, 0);
+	zip_read_consume(a, hsize);
+
+	remaining_bytes = (size_t)rsrc->compressed_size;
+	metadata_bytes = (size_t)rsrc->uncompressed_size;
+	mp = metadata;
+	eof = 0;
+	while (!eof && remaining_bytes) {
+		const unsigned char *p;
+		ssize_t bytes_avail;
+		size_t bytes_used;
+
+		p = __archive_read_ahead(a, 1, &bytes_avail);
+		if (p == NULL) {
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_FILE_FORMAT,
+			    "Truncated ZIP file header");
+			ret = ARCHIVE_WARN;
+			goto exit_mac_metadata;
+		}
+		if ((size_t)bytes_avail > remaining_bytes)
+			bytes_avail = remaining_bytes;
+		switch(rsrc->compression) {
+		case 0:  /* No compression. */
+			memcpy(mp, p, bytes_avail);
+			bytes_used = (size_t)bytes_avail;
+			metadata_bytes -= bytes_used;
+			mp += bytes_used;
+			if (metadata_bytes == 0)
+				eof = 1;
+			break;
+#ifdef HAVE_ZLIB_H
+		case 8: /* Deflate compression. */
+		{
+			int r;
+
+			ret = zip_deflate_init(a, zip);
+			if (ret != ARCHIVE_OK)
+				goto exit_mac_metadata;
+			zip->stream.next_in =
+			    (Bytef *)(uintptr_t)(const void *)p;
+			zip->stream.avail_in = (uInt)bytes_avail;
+			zip->stream.total_in = 0;
+			zip->stream.next_out = mp;
+			zip->stream.avail_out = (uInt)metadata_bytes;
+			zip->stream.total_out = 0;
+
+			r = inflate(&zip->stream, 0);
+			switch (r) {
+			case Z_OK:
+				break;
+			case Z_STREAM_END:
+				eof = 1;
+				break;
+			case Z_MEM_ERROR:
+				archive_set_error(&a->archive, ENOMEM,
+				    "Out of memory for ZIP decompression");
+				ret = ARCHIVE_FATAL;
+				goto exit_mac_metadata;
+			default:
+				archive_set_error(&a->archive,
+				    ARCHIVE_ERRNO_MISC,
+				    "ZIP decompression failed (%d)", r);
+				ret = ARCHIVE_FATAL;
+				goto exit_mac_metadata;
+			}
+			bytes_used = zip->stream.total_in;
+			metadata_bytes -= zip->stream.total_out;
+			mp += zip->stream.total_out;
+			break;
+		}
+#endif
+		default:
+			bytes_used = 0;
+			break;
+		}
+		zip_read_consume(a, bytes_used);
+		remaining_bytes -= bytes_used;
+	}
+	archive_entry_copy_mac_metadata(entry, metadata,
+	    (size_t)rsrc->uncompressed_size - metadata_bytes);
+
+	__archive_read_seek(a, offset, SEEK_SET);
+	zip->offset = offset;
+exit_mac_metadata:
+	zip->decompress_init = 0;
+	free(metadata);
+	return (ret);
+}
+
 static int
 archive_read_format_zip_seekable_read_header(struct archive_read *a,
 	struct archive_entry *entry)
 {
 	struct zip *zip = (struct zip *)a->format->data;
-	int r;
+	struct zip_entry *rsrc;
+	int r, ret = ARCHIVE_OK;
 
 	a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
 	if (a->archive.archive_format_name == NULL)
@@ -344,26 +702,45 @@ archive_read_format_zip_seekable_read_header(struct archive_read *a,
 		zip->entries_remaining = zip->central_directory_entries;
 		if (r != ARCHIVE_OK)
 			return r;
-		zip->entry = zip->zip_entries;
-	} else {
-		++zip->entry;
+		/* Get first entry whose local header offset is lower than
+		 * other entries in the archive file. */
+		zip->entry =
+		    (struct zip_entry *)ARCHIVE_RB_TREE_MIN(&zip->tree);
+	} else if (zip->entry != NULL) {
+		/* Get next entry in local header offset order. */
+		zip->entry = (struct zip_entry *)__archive_rb_tree_iterate(
+		    &zip->tree, &zip->entry->node, ARCHIVE_RB_DIR_RIGHT);
 	}
 
-	if (zip->entries_remaining <= 0)
+	if (zip->entries_remaining <= 0 || zip->entry == NULL)
 		return ARCHIVE_EOF;
 	--zip->entries_remaining;
 
-	/* TODO: If entries are sorted by offset within the file, we
-	   should be able to skip here instead of seeking.  Skipping is
-	   typically faster (easier for I/O layer to optimize). */
-	__archive_read_seek(a, zip->entry->local_header_offset, SEEK_SET);
+	if (zip->entry->rsrcname.s)
+		rsrc = (struct zip_entry *)__archive_rb_tree_find_node(
+		    &zip->tree_rsrc, zip->entry->rsrcname.s);
+	else
+		rsrc = NULL;
+
+	/* File entries are sorted by the header offset, we should mostly
+	 * use zip_read_consume to advance a read point to avoid redundant
+	 * data reading.  */
+	if (zip->offset < zip->entry->local_header_offset)
+		zip_read_consume(a,
+		    zip->entry->local_header_offset - zip->offset);
+	else if (zip->offset != zip->entry->local_header_offset) {
+		__archive_read_seek(a, zip->entry->local_header_offset,
+			SEEK_SET);
+		zip->offset = zip->entry->local_header_offset;
+	}
 	zip->unconsumed = 0;
 	r = zip_read_local_file_header(a, entry, zip);
 	if (r != ARCHIVE_OK)
 		return r;
 	if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) {
 		const void *p;
-		size_t linkname_length = archive_entry_size(entry);
+		struct archive_string_conv *sconv;
+		size_t linkname_length = (size_t)archive_entry_size(entry);
 
 		archive_entry_set_size(entry, 0);
 		p = __archive_read_ahead(a, linkname_length, NULL);
@@ -373,17 +750,45 @@ archive_read_format_zip_seekable_read_header(struct archive_read *a,
 			return ARCHIVE_FATAL;
 		}
 
+		sconv = zip->sconv;
+		if (sconv == NULL && (zip->entry->flags & ZIP_UTF8_NAME))
+			sconv = zip->sconv_utf8;
+		if (sconv == NULL)
+			sconv = zip->sconv_default;
 		if (archive_entry_copy_symlink_l(entry, p, linkname_length,
-		    NULL) != 0) {
-			/* NOTE: If the last argument is NULL, this will
-			 * fail only by memeory allocation failure. */
-			archive_set_error(&a->archive, ENOMEM,
-			    "Can't allocate memory for Symlink");
-			return (ARCHIVE_FATAL);
+		    sconv) != 0) {
+			if (errno != ENOMEM && sconv == zip->sconv_utf8 &&
+			    (zip->entry->flags & ZIP_UTF8_NAME))
+			    archive_entry_copy_symlink_l(entry, p,
+				linkname_length, NULL);
+			if (errno == ENOMEM) {
+				archive_set_error(&a->archive, ENOMEM,
+				    "Can't allocate memory for Symlink");
+				return (ARCHIVE_FATAL);
+			}
+			/*
+			 * Since there is no character-set regulation for
+			 * symlink name, do not report the conversion error
+			 * in an automatic conversion.
+			 */
+			if (sconv != zip->sconv_utf8 ||
+			    (zip->entry->flags & ZIP_UTF8_NAME) == 0) {
+				archive_set_error(&a->archive,
+				    ARCHIVE_ERRNO_FILE_FORMAT,
+				    "Symlink cannot be converted "
+				    "from %s to current locale.",
+				    archive_string_conversion_charset_name(
+					sconv));
+				ret = ARCHIVE_WARN;
+			}
 		}
-		/* TODO: handle character-set issues? */
 	}
-	return ARCHIVE_OK;
+	if (rsrc) {
+		int ret2 = zip_read_mac_metadata(a, entry, rsrc);
+		if (ret2 < ret)
+			ret = ret2;
+	}
+	return (ret);
 }
 
 static int
@@ -410,6 +815,11 @@ archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid)
 			return (30);
 	}
 
+	/* TODO: It's worth looking ahead a little bit for a valid
+	 * PK signature.  In particular, that would make it possible
+	 * to read some UUEncoded SFX files or SFX files coming from
+	 * a network socket. */
+
 	return (0);
 }
 
@@ -424,11 +834,12 @@ archive_read_format_zip_options(struct archive_read *a,
 	if (strcmp(key, "compat-2x")  == 0) {
 		/* Handle filnames as libarchive 2.x */
 		zip->init_default_conversion = (val != NULL) ? 1 : 0;
-		ret = ARCHIVE_OK;
+		return (ARCHIVE_OK);
 	} else if (strcmp(key, "hdrcharset")  == 0) {
 		if (val == NULL || val[0] == 0)
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "zip: hdrcharset option needs a character-set name");
+			    "zip: hdrcharset option needs a character-set name"
+			);
 		else {
 			zip->sconv = archive_string_conversion_from_charset(
 			    &a->archive, val, 0);
@@ -439,11 +850,13 @@ archive_read_format_zip_options(struct archive_read *a,
 			} else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "zip: unknown keyword ``%s''", key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 static int
@@ -462,7 +875,8 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a,
 	if (zip->zip_entries == NULL) {
 		zip->zip_entries = malloc(sizeof(struct zip_entry));
 		if (zip->zip_entries == NULL) {
-			archive_set_error(&a->archive, ENOMEM, "Out  of memory");
+			archive_set_error(&a->archive, ENOMEM,
+			    "Out  of memory");
 			return ARCHIVE_FATAL;
 		}
 	}
@@ -470,7 +884,7 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a,
 	memset(zip->entry, 0, sizeof(struct zip_entry));
 
 	/* Search ahead for the next local file header. */
-	__archive_read_consume(a, zip->unconsumed);
+	zip_read_consume(a, zip->unconsumed);
 	zip->unconsumed = 0;
 	for (;;) {
 		int64_t skipped = 0;
@@ -490,8 +904,9 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a,
 
 				if (p[2] == '\003' && p[3] == '\004') {
 					/* Regular file entry. */
-					__archive_read_consume(a, skipped);
-					return zip_read_local_file_header(a, entry, zip);
+					zip_read_consume(a, skipped);
+					return zip_read_local_file_header(a,
+					    entry, zip);
 				}
 
 				if (p[2] == '\005' && p[3] == '\006')
@@ -501,8 +916,31 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a,
 			++p;
 			++skipped;
 		}
-		__archive_read_consume(a, skipped);
+		zip_read_consume(a, skipped);
+	}
+}
+
+static ssize_t
+zip_get_local_file_header_size(struct archive_read *a, size_t extra)
+{
+	const char *p;
+	ssize_t filename_length, extra_length;
+
+	if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+		    "Truncated ZIP file header");
+		return (ARCHIVE_WARN);
+	}
+	p += extra;
+
+	if (memcmp(p, "PK\003\004", 4) != 0) {
+		archive_set_error(&a->archive, -1, "Damaged Zip archive");
+		return ARCHIVE_WARN;
 	}
+	filename_length = archive_le16dec(p + 26);
+	extra_length = archive_le16dec(p + 28);
+
+	return (30 + filename_length + extra_length);
 }
 
 /*
@@ -550,7 +988,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
 	version = p[4];
 	zip_entry->system = p[5];
 	zip_entry->flags = archive_le16dec(p + 6);
-	zip_entry->compression = archive_le16dec(p + 8);
+	zip_entry->compression = (char)archive_le16dec(p + 8);
 	zip_entry->mtime = zip_time(p + 10);
 	local_crc32 = archive_le32dec(p + 14);
 	compressed_size = archive_le32dec(p + 18);
@@ -558,11 +996,11 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
 	filename_length = archive_le16dec(p + 26);
 	extra_length = archive_le16dec(p + 28);
 
-	__archive_read_consume(a, 30);
+	zip_read_consume(a, 30);
 
 	if (zip->have_central_directory) {
-		/* If we read the central dir entry, we must have size information
-		   as well, so ignore the length-at-end flag. */
+		/* If we read the central dir entry, we must have size
+		 * information as well, so ignore the length-at-end flag. */
 		zip_entry->flags &= ~ZIP_LENGTH_AT_END;
 		/* If we have values from both the local file header
 		   and the central directory, warn about mismatches
@@ -570,19 +1008,22 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
 		   writers always put zero in the local header; don't
 		   bother warning about that. */
 		if (local_crc32 != 0 && local_crc32 != zip_entry->crc32) {
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_FILE_FORMAT,
 			    "Inconsistent CRC32 values");
 			ret = ARCHIVE_WARN;
 		}
 		if (compressed_size != 0
 		    && compressed_size != zip_entry->compressed_size) {
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_FILE_FORMAT,
 			    "Inconsistent compressed size");
 			ret = ARCHIVE_WARN;
 		}
 		if (uncompressed_size != 0
 		    && uncompressed_size != zip_entry->uncompressed_size) {
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_FILE_FORMAT,
 			    "Inconsistent uncompressed size");
 			ret = ARCHIVE_WARN;
 		}
@@ -628,7 +1069,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
 		    archive_string_conversion_charset_name(sconv));
 		ret = ARCHIVE_WARN;
 	}
-	__archive_read_consume(a, filename_length);
+	zip_read_consume(a, filename_length);
 
 	if (zip_entry->mode == 0) {
 		/* Especially in streaming mode, we can end up
@@ -640,14 +1081,14 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
 			if (len > 0 && wp[len - 1] == L'/')
 				zip_entry->mode = AE_IFDIR | 0777;
 			else
-				zip_entry->mode = AE_IFREG | 0777;
+				zip_entry->mode = AE_IFREG | 0666;
 		} else {
 			cp = archive_entry_pathname(entry);
 			len = (cp != NULL)?strlen(cp):0;
 			if (len > 0 && cp[len - 1] == '/')
 				zip_entry->mode = AE_IFDIR | 0777;
 			else
-				zip_entry->mode = AE_IFREG | 0777;
+				zip_entry->mode = AE_IFREG | 0666;
 		}
 	}
 
@@ -658,7 +1099,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
 		return (ARCHIVE_FATAL);
 	}
 	process_extra(h, extra_length, zip_entry);
-	__archive_read_consume(a, extra_length);
+	zip_read_consume(a, extra_length);
 
 	/* Populate some additional entry fields: */
 	archive_entry_set_mode(entry, zip_entry->mode);
@@ -702,8 +1143,8 @@ compression_name(int compression)
 		"deflation"
 	};
 
-	if (compression <
-	    sizeof(compression_names)/sizeof(compression_names[0]))
+	if (0 <= compression && compression <
+	    (int)(sizeof(compression_names)/sizeof(compression_names[0])))
 		return compression_names[compression];
 	else
 		return "??";
@@ -755,7 +1196,7 @@ archive_read_format_zip_read_data(struct archive_read *a,
 		return (ARCHIVE_FAILED);
 	}
 
-	__archive_read_consume(a, zip->unconsumed);
+	zip_read_consume(a, zip->unconsumed);
 	zip->unconsumed = 0;
 
 	switch(zip->entry->compression) {
@@ -781,13 +1222,16 @@ archive_read_format_zip_read_data(struct archive_read *a,
 		return (r);
 	/* Update checksum */
 	if (*size)
-		zip->entry_crc32 = crc32(zip->entry_crc32, *buff, *size);
+		zip->entry_crc32 = crc32(zip->entry_crc32, *buff,
+		    (unsigned)*size);
 	/* If we hit the end, swallow any end-of-data marker. */
 	if (zip->end_of_entry) {
 		/* Check file size, CRC against these values. */
-		if (zip->entry->compressed_size != zip->entry_compressed_bytes_read) {
+		if (zip->entry->compressed_size !=
+		    zip->entry_compressed_bytes_read) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "ZIP compressed data is wrong size (read %jd, expected %jd)",
+			    "ZIP compressed data is wrong size "
+			    "(read %jd, expected %jd)",
 			    (intmax_t)zip->entry_compressed_bytes_read,
 			    (intmax_t)zip->entry->compressed_size);
 			return (ARCHIVE_WARN);
@@ -797,7 +1241,8 @@ archive_read_format_zip_read_data(struct archive_read *a,
 		if ((zip->entry->uncompressed_size & UINT32_MAX)
 		    != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "ZIP uncompressed data is wrong size (read %jd, expected %jd)",
+			    "ZIP uncompressed data is wrong size "
+			    "(read %jd, expected %jd)",
 			    (intmax_t)zip->entry_uncompressed_bytes_read,
 			    (intmax_t)zip->entry->uncompressed_size);
 			return (ARCHIVE_WARN);
@@ -846,6 +1291,8 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
 	const char *buff;
 	ssize_t bytes_avail;
 
+	(void)offset; /* UNUSED */
+
 	zip = (struct zip *)(a->format->data);
 
 	if (zip->entry->flags & ZIP_LENGTH_AT_END) {
@@ -858,7 +1305,8 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
 			   that are longer than this, so a failure to get at
 			   least 16 bytes really does indicate a truncated
 			   file. */
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_FILE_FORMAT,
 			    "Truncated ZIP file data");
 			return (ARCHIVE_FATAL);
 		}
@@ -867,8 +1315,10 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
 		if (p[0] == 'P' && p[1] == 'K' 
 		    && p[2] == '\007' && p[3] == '\010'
 		    && archive_le32dec(p + 4) == zip->entry_crc32
-		    && archive_le32dec(p + 8) == zip->entry_compressed_bytes_read
-		    && archive_le32dec(p + 12) == zip->entry_uncompressed_bytes_read) {
+		    && archive_le32dec(p + 8) ==
+			    zip->entry_compressed_bytes_read
+		    && archive_le32dec(p + 12) ==
+			    zip->entry_uncompressed_bytes_read) {
 			zip->entry->crc32 = archive_le32dec(p + 4);
 			zip->entry->compressed_size = archive_le32dec(p + 8);
 			zip->entry->uncompressed_size = archive_le32dec(p + 12);
@@ -879,9 +1329,10 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
 		/* If not at EOF, ensure we consume at least one byte. */
 		++p;
 
-		/* Scan forward until we see where a PK\007\010 signature might be. */
-		/* Return bytes up until that point.  On the next call, the code
-		   above will verify the data descriptor. */
+		/* Scan forward until we see where a PK\007\010 signature
+		 * might be. */
+		/* Return bytes up until that point.  On the next call,
+		 * the code above will verify the data descriptor. */
 		while (p < buff + bytes_avail - 4) {
 			if (p[3] == 'P') { p += 3; }
 			else if (p[3] == 'K') { p += 2; }
@@ -900,12 +1351,13 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
 		/* Grab a bunch of bytes. */
 		buff = __archive_read_ahead(a, 1, &bytes_avail);
 		if (bytes_avail <= 0) {
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_FILE_FORMAT,
 			    "Truncated ZIP file data");
 			return (ARCHIVE_FATAL);
 		}
 		if (bytes_avail > zip->entry_bytes_remaining)
-			bytes_avail = zip->entry_bytes_remaining;
+			bytes_avail = (ssize_t)zip->entry_bytes_remaining;
 	}
 	*size = bytes_avail;
 	zip->entry_bytes_remaining -= bytes_avail;
@@ -918,6 +1370,31 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
 
 #ifdef HAVE_ZLIB_H
 static int
+zip_deflate_init(struct archive_read *a, struct zip *zip)
+{
+	int r;
+
+	/* If we haven't yet read any data, initialize the decompressor. */
+	if (!zip->decompress_init) {
+		if (zip->stream_valid)
+			r = inflateReset(&zip->stream);
+		else
+			r = inflateInit2(&zip->stream,
+			    -15 /* Don't check for zlib header */);
+		if (r != Z_OK) {
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Can't initialize ZIP decompression.");
+			return (ARCHIVE_FATAL);
+		}
+		/* Stream structure has been set up. */
+		zip->stream_valid = 1;
+		/* We've initialized decompression for this stream. */
+		zip->decompress_init = 1;
+	}
+	return (ARCHIVE_OK);
+}
+
+static int
 zip_read_data_deflate(struct archive_read *a, const void **buff,
     size_t *size, int64_t *offset)
 {
@@ -926,6 +1403,8 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
 	const void *compressed_buff;
 	int r;
 
+	(void)offset; /* UNUSED */
+
 	zip = (struct zip *)(a->format->data);
 
 	/* If the buffer hasn't been allocated, allocate it now. */
@@ -940,23 +1419,9 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
 		}
 	}
 
-	/* If we haven't yet read any data, initialize the decompressor. */
-	if (!zip->decompress_init) {
-		if (zip->stream_valid)
-			r = inflateReset(&zip->stream);
-		else
-			r = inflateInit2(&zip->stream,
-			    -15 /* Don't check for zlib header */);
-		if (r != Z_OK) {
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Can't initialize ZIP decompression.");
-			return (ARCHIVE_FATAL);
-		}
-		/* Stream structure has been set up. */
-		zip->stream_valid = 1;
-		/* We've initialized decompression for this stream. */
-		zip->decompress_init = 1;
-	}
+	r = zip_deflate_init(a, zip);
+	if (r != ARCHIVE_OK)
+		return (r);
 
 	/*
 	 * Note: '1' here is a performance optimization.
@@ -967,7 +1432,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
 	compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
 	if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)
 	    && bytes_avail > zip->entry_bytes_remaining) {
-		bytes_avail = zip->entry_bytes_remaining;
+		bytes_avail = (ssize_t)zip->entry_bytes_remaining;
 	}
 	if (bytes_avail <= 0) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -982,10 +1447,10 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
 	 * cast to remove 'const'.
 	 */
 	zip->stream.next_in = (Bytef *)(uintptr_t)(const void *)compressed_buff;
-	zip->stream.avail_in = bytes_avail;
+	zip->stream.avail_in = (uInt)bytes_avail;
 	zip->stream.total_in = 0;
 	zip->stream.next_out = zip->uncompressed_buffer;
-	zip->stream.avail_out = zip->uncompressed_buffer_size;
+	zip->stream.avail_out = (uInt)zip->uncompressed_buffer_size;
 	zip->stream.total_out = 0;
 
 	r = inflate(&zip->stream, 0);
@@ -1007,7 +1472,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
 
 	/* Consume as much as the compressor actually used. */
 	bytes_avail = zip->stream.total_in;
-	__archive_read_consume(a, bytes_avail);
+	zip_read_consume(a, bytes_avail);
 	zip->entry_bytes_remaining -= bytes_avail;
 	zip->entry_compressed_bytes_read += bytes_avail;
 
@@ -1025,7 +1490,8 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
 			return (ARCHIVE_FATAL);
 		}
 		/* Consume the optional PK\007\010 marker. */
-		if (p[0] == 'P' && p[1] == 'K' && p[2] == '\007' && p[3] == '\010') {
+		if (p[0] == 'P' && p[1] == 'K' &&
+		    p[2] == '\007' && p[3] == '\010') {
 			zip->entry->crc32 = archive_le32dec(p + 4);
 			zip->entry->compressed_size = archive_le32dec(p + 8);
 			zip->entry->uncompressed_size = archive_le32dec(p + 12);
@@ -1047,14 +1513,11 @@ archive_read_format_zip_read_data_skip(struct archive_read *a)
 	/* If we've already read to end of data, we're done. */
 	if (zip->end_of_entry)
 		return (ARCHIVE_OK);
-	/* If we're seeking, we're done. */
-	if (zip->have_central_directory)
-		return (ARCHIVE_OK);
 
 	/* So we know we're streaming... */
 	if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)) {
 		/* We know the compressed length, so we can just skip. */
-		int64_t bytes_skipped = __archive_read_consume(a,
+		int64_t bytes_skipped = zip_read_consume(a,
 		    zip->entry_bytes_remaining + zip->unconsumed);
 		if (bytes_skipped < 0)
 			return (ARCHIVE_FATAL);
@@ -1077,36 +1540,36 @@ archive_read_format_zip_read_data_skip(struct archive_read *a)
 			if (r != ARCHIVE_OK)
 				return (r);
 		}
-		break;
+		return ARCHIVE_OK;
 #endif
 	default: /* Uncompressed or unknown. */
 		/* Scan for a PK\007\010 signature. */
-		__archive_read_consume(a, zip->unconsumed);
+		zip_read_consume(a, zip->unconsumed);
 		zip->unconsumed = 0;
 		for (;;) {
 			const char *p, *buff;
 			ssize_t bytes_avail;
 			buff = __archive_read_ahead(a, 16, &bytes_avail);
 			if (bytes_avail < 16) {
-				archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+				archive_set_error(&a->archive,
+				    ARCHIVE_ERRNO_FILE_FORMAT,
 				    "Truncated ZIP file data");
 				return (ARCHIVE_FATAL);
 			}
 			p = buff;
-			while (p < buff + bytes_avail - 16) {
+			while (p <= buff + bytes_avail - 16) {
 				if (p[3] == 'P') { p += 3; }
 				else if (p[3] == 'K') { p += 2; }
 				else if (p[3] == '\007') { p += 1; }
 				else if (p[3] == '\010' && p[2] == '\007'
 				    && p[1] == 'K' && p[0] == 'P') {
-					__archive_read_consume(a, p - buff + 16);
+					zip_read_consume(a, p - buff + 16);
 					return ARCHIVE_OK;
 				} else { p += 4; }
 			}
-			__archive_read_consume(a, p - buff);
+			zip_read_consume(a, p - buff);
 		}
 	}
-	return ARCHIVE_OK;
 }
 
 static int
@@ -1119,6 +1582,11 @@ archive_read_format_zip_cleanup(struct archive_read *a)
 	if (zip->stream_valid)
 		inflateEnd(&zip->stream);
 #endif
+	if (zip->zip_entries && zip->central_directory_entries) {
+		unsigned i;
+		for (i = 0; i < zip->central_directory_entries; i++)
+			archive_string_free(&(zip->zip_entries[i].rsrcname));
+	}
 	free(zip->zip_entries);
 	free(zip->uncompressed_buffer);
 	archive_string_free(&(zip->extra));
@@ -1201,11 +1669,14 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
 			/* Info-ZIP Unix Extra Field (old version) "UX". */
 			if (datasize >= 8) {
 				zip_entry->atime = archive_le32dec(p + offset);
-				zip_entry->mtime = archive_le32dec(p + offset + 4);
+				zip_entry->mtime =
+				    archive_le32dec(p + offset + 4);
 			}
 			if (datasize >= 12) {
-				zip_entry->uid = archive_le16dec(p + offset + 8);
-				zip_entry->gid = archive_le16dec(p + offset + 10);
+				zip_entry->uid =
+				    archive_le16dec(p + offset + 8);
+				zip_entry->gid =
+				    archive_le16dec(p + offset + 10);
 			}
 			break;
 		}
@@ -1219,7 +1690,8 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
 			if (datasize >= 2)
 				zip_entry->uid = archive_le16dec(p + offset);
 			if (datasize >= 4)
-				zip_entry->gid = archive_le16dec(p + offset + 2);
+				zip_entry->gid =
+				    archive_le16dec(p + offset + 2);
 			break;
 		case 0x7875:
 		{
@@ -1231,22 +1703,26 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
 					/* get a uid size. */
 					uidsize = p[offset+1];
 					if (uidsize == 2)
-						zip_entry->uid = archive_le16dec(
-						     p + offset + 2);
+						zip_entry->uid =
+						    archive_le16dec(
+						        p + offset + 2);
 					else if (uidsize == 4 && datasize >= 6)
-						zip_entry->uid = archive_le32dec(
-						     p + offset + 2);
+						zip_entry->uid =
+						    archive_le32dec(
+						        p + offset + 2);
 				}
 				if (datasize >= (2 + uidsize + 3)) {
 					/* get a gid size. */
 					gidsize = p[offset+2+uidsize];
 					if (gidsize == 2)
-						zip_entry->gid = archive_le16dec(
-						    p+offset+2+uidsize+1);
+						zip_entry->gid =
+						    archive_le16dec(
+						        p+offset+2+uidsize+1);
 					else if (gidsize == 4 &&
 					    datasize >= (2 + uidsize + 5))
-						zip_entry->gid = archive_le32dec(
-						    p+offset+2+uidsize+1);
+						zip_entry->gid =
+						    archive_le32dec(
+						        p+offset+2+uidsize+1);
 				}
 			}
 			break;
diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c
index 4dec82d..87f9288 100644
--- a/libarchive/archive_string.c
+++ b/libarchive/archive_string.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2003-2011 Tim Kientzle
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,9 +61,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_string.c 201095 2009-12-28 02:33
 #include <windows.h>
 #include <locale.h>
 #endif
-#if defined(__APPLE__)
-#include <CoreServices/CoreServices.h>
-#endif
 
 #include "archive_endian.h"
 #include "archive_private.h"
@@ -115,11 +112,6 @@ struct archive_string_conv {
 #endif
 	/* A temporary buffer for normalization. */
 	struct archive_string		 utftmp;
-#if defined(__APPLE__)
-	UnicodeToTextInfo		 uniInfo;
-	struct archive_string		 utf16nfc;
-	struct archive_string		 utf16nfd;
-#endif
 	int (*converter[2])(struct archive_string *, const void *, size_t,
 	    struct archive_string_conv *);
 	int				 nconverter;
@@ -164,29 +156,29 @@ static int archive_string_append_from_wcs_in_codepage(struct archive_string *,
 static int is_big_endian(void);
 static int strncat_in_codepage(struct archive_string *, const void *,
     size_t, struct archive_string_conv *);
-static int win_strncat_from_utf16be(struct archive_string *, const void *, size_t,
-    struct archive_string_conv *);
-static int win_strncat_from_utf16le(struct archive_string *, const void *, size_t,
-    struct archive_string_conv *);
-static int win_strncat_to_utf16be(struct archive_string *, const void *, size_t,
-    struct archive_string_conv *);
-static int win_strncat_to_utf16le(struct archive_string *, const void *, size_t,
-    struct archive_string_conv *);
-#endif
-static int best_effort_strncat_from_utf16be(struct archive_string *, const void *,
+static int win_strncat_from_utf16be(struct archive_string *, const void *,
     size_t, struct archive_string_conv *);
-static int best_effort_strncat_from_utf16le(struct archive_string *, const void *,
+static int win_strncat_from_utf16le(struct archive_string *, const void *,
     size_t, struct archive_string_conv *);
-static int best_effort_strncat_to_utf16be(struct archive_string *, const void *,
+static int win_strncat_to_utf16be(struct archive_string *, const void *,
     size_t, struct archive_string_conv *);
-static int best_effort_strncat_to_utf16le(struct archive_string *, const void *,
+static int win_strncat_to_utf16le(struct archive_string *, const void *,
     size_t, struct archive_string_conv *);
+#endif
+static int best_effort_strncat_from_utf16be(struct archive_string *,
+    const void *, size_t, struct archive_string_conv *);
+static int best_effort_strncat_from_utf16le(struct archive_string *,
+    const void *, size_t, struct archive_string_conv *);
+static int best_effort_strncat_to_utf16be(struct archive_string *,
+    const void *, size_t, struct archive_string_conv *);
+static int best_effort_strncat_to_utf16le(struct archive_string *,
+    const void *, size_t, struct archive_string_conv *);
 #if defined(HAVE_ICONV)
 static int iconv_strncat_in_locale(struct archive_string *, const void *,
     size_t, struct archive_string_conv *);
 #endif
-static int best_effort_strncat_in_locale(struct archive_string *, const void *,
-    size_t, struct archive_string_conv *);
+static int best_effort_strncat_in_locale(struct archive_string *,
+    const void *, size_t, struct archive_string_conv *);
 static int _utf8_to_unicode(uint32_t *, const char *, size_t);
 static int utf8_to_unicode(uint32_t *, const char *, size_t);
 static inline uint32_t combine_surrogate_pair(uint32_t, uint32_t);
@@ -201,10 +193,8 @@ static int strncat_from_utf8_to_utf8(struct archive_string *, const void *,
     size_t, struct archive_string_conv *);
 static int archive_string_normalize_C(struct archive_string *, const void *,
     size_t, struct archive_string_conv *);
-#if defined(__APPLE__)
 static int archive_string_normalize_D(struct archive_string *, const void *,
     size_t, struct archive_string_conv *);
-#endif
 static int archive_string_append_unicode(struct archive_string *,
     const void *, size_t, struct archive_string_conv *);
 
@@ -238,7 +228,8 @@ archive_string_concat(struct archive_string *dest, struct archive_string *src)
 }
 
 void
-archive_wstring_concat(struct archive_wstring *dest, struct archive_wstring *src)
+archive_wstring_concat(struct archive_wstring *dest,
+    struct archive_wstring *src)
 {
 	if (archive_wstring_append(dest, src->s, src->length) == NULL)
 		__archive_errx(1, "Out of memory");
@@ -443,10 +434,7 @@ int
 archive_wstring_append_from_mbs(struct archive_wstring *dest,
     const char *p, size_t len)
 {
-	int r = archive_wstring_append_from_mbs_in_codepage(dest, p, len, NULL);
-	if (r != 0 && errno == ENOMEM)
-		__archive_errx(1, "No memory");
-	return (r);
+	return archive_wstring_append_from_mbs_in_codepage(dest, p, len, NULL);
 }
 
 static int
@@ -479,7 +467,8 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
 			*ws++ = (wchar_t)*mp++;
 			count++;
 		}
-	} else if (sc != NULL && (sc->flag & SCONV_NORMALIZATION_C)) {
+	} else if (sc != NULL &&
+	    (sc->flag & (SCONV_NORMALIZATION_C | SCONV_NORMALIZATION_D))) {
 		/*
 		 * Normalize UTF-8 and UTF-16BE and convert it directly
 		 * to UTF-16 as wchar_t.
@@ -495,31 +484,36 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
 		if (sc->flag & SCONV_FROM_UTF16) {
 			/*
 			 *  UTF-16BE/LE NFD ===> UTF-16 NFC
+			 *  UTF-16BE/LE NFC ===> UTF-16 NFD
 			 */
-			count = utf16nbytes(s, length);
+			count = (int)utf16nbytes(s, length);
 		} else {
 			/*
 			 *  UTF-8 NFD ===> UTF-16 NFC
+			 *  UTF-8 NFC ===> UTF-16 NFD
 			 */
-			count = mbsnbytes(s, length);
+			count = (int)mbsnbytes(s, length);
 		}
 		u16.s = (char *)dest->s;
 		u16.length = dest->length << 1;;
 		u16.buffer_length = dest->buffer_length;
-		ret = archive_string_normalize_C(&u16, s, count, sc);
+		if (sc->flag & SCONV_NORMALIZATION_C)
+			ret = archive_string_normalize_C(&u16, s, count, sc);
+		else
+			ret = archive_string_normalize_D(&u16, s, count, sc);
 		dest->s = (wchar_t *)u16.s;
 		dest->length = u16.length >> 1;
 		dest->buffer_length = u16.buffer_length;
 		sc->flag = saved_flag;/* restore the saved flag. */
 		return (ret);
 	} else if (sc != NULL && (sc->flag & SCONV_FROM_UTF16)) {
-		count = utf16nbytes(s, length);
+		count = (int)utf16nbytes(s, length);
 		count >>= 1; /* to be WCS length */
 		/* Allocate memory for WCS. */
 		if (NULL == archive_wstring_ensure(dest,
 		    dest->length + count + 1))
 			return (-1);
-		wmemcpy(dest->s + dest->length, (wchar_t *)s, count);
+		wmemcpy(dest->s + dest->length, (const wchar_t *)s, count);
 		if ((sc->flag & SCONV_FROM_UTF16BE) && !is_big_endian()) {
 			uint16_t *u16 = (uint16_t *)(dest->s + dest->length);
 			int b;
@@ -537,6 +531,7 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
 		}
 	} else {
 		DWORD mbflag;
+		size_t buffsize;
 
 		if (sc == NULL)
 			mbflag = 0;
@@ -548,83 +543,30 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
 		} else
 			mbflag = MB_PRECOMPOSED;
 
-		if (length == 0) {
-			/*
-			 * We do not need to convert any characters but make
-			 * sure `dest' has a valid buffer(no NULL pointer).
-			 */
-			if (NULL == archive_wstring_ensure(dest,
-			    dest->length + 1))
+		buffsize = dest->length + length + 1;
+		do {
+			/* Allocate memory for WCS. */
+			if (NULL == archive_wstring_ensure(dest, buffsize))
 				return (-1);
-			dest->s[dest->length] = L'\0';
-			return (0);
-		}
-
-		/*
-		 * Count how many bytes are needed for WCS.
-		 */
-		count = MultiByteToWideChar(from_cp,
-		    mbflag, s, length, NULL, 0);
-		if (count == 0) {
-			if (dest->s == NULL) {
-				if (NULL == archive_wstring_ensure(dest,
-				    dest->length + 1))
-					return (-1);
+			/* Convert MBS to WCS. */
+			count = MultiByteToWideChar(from_cp,
+			    mbflag, s, (int)length, dest->s + dest->length,
+			    (int)(dest->buffer_length >> 1) -1);
+			if (count == 0 &&
+			    GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+				/* Expand the WCS buffer. */
+				buffsize = dest->buffer_length << 1;
+				continue;
 			}
-			dest->s[dest->length] = L'\0';
-			return (-1);
-		}
-		/* Allocate memory for WCS. */
-		if (NULL == archive_wstring_ensure(dest,
-		    dest->length + count + 1))
-			return (-1);
-		/* Convert MBS to WCS. */
-		count = MultiByteToWideChar(from_cp,
-		    mbflag, s, length, dest->s + dest->length, count);
-		if (count == 0)
-			ret = -1;
+			if (count == 0 && length != 0)
+				ret = -1;
+		} while (0);
 	}
 	dest->length += count;
 	dest->s[dest->length] = L'\0';
 	return (ret);
 }
 
-#elif defined(HAVE_MBSNRTOWCS)
-
-/*
- * Convert MBS to WCS.
- * Note: returns -1 if conversion fails.
- */
-int
-archive_wstring_append_from_mbs(struct archive_wstring *dest,
-    const char *p, size_t len)
-{
-	size_t r;
-	/*
-	 * No single byte will be more than one wide character,
-	 * so this length estimate will always be big enough.
-	 */
-	size_t wcs_length = len;
-	size_t mbs_length = len;
-	const char *mbs = p;
-	wchar_t *wcs;
-	mbstate_t shift_state;
-
-	memset(&shift_state, 0, sizeof(shift_state));
-	if (NULL == archive_wstring_ensure(dest, dest->length + wcs_length + 1))
-		__archive_errx(1,
-		    "No memory for archive_wstring_append_from_mbs()");
-	wcs = dest->s + dest->length;
-	r = mbsnrtowcs(wcs, &mbs, mbs_length, wcs_length, &shift_state);
-	if (r != (size_t)-1) {
-		dest->length += r;
-		dest->s[dest->length] = L'\0';
-		return (0);
-	}
-	dest->s[dest->length] = L'\0';
-	return (-1);
-}
-
 #else
 
 /*
@@ -636,6 +578,7 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest,
     const char *p, size_t len)
 {
 	size_t r;
+	int ret_val = 0;
 	/*
 	 * No single byte will be more than one wide character,
 	 * so this length estimate will always be big enough.
@@ -650,23 +593,36 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest,
 	memset(&shift_state, 0, sizeof(shift_state));
 #endif
 	if (NULL == archive_wstring_ensure(dest, dest->length + wcs_length + 1))
-		__archive_errx(1,
-		    "No memory for archive_wstring_append_from_mbs()");
+		return (-1);
 	wcs = dest->s + dest->length;
 	/*
 	 * We cannot use mbsrtowcs/mbstowcs here because those may convert
 	 * extra MBS when strlen(p) > len and one wide character consis of
 	 * multi bytes.
 	 */
-	while (wcs_length > 0 && *mbs && mbs_length > 0) {
+	while (*mbs && mbs_length > 0) {
+		if (wcs_length == 0) {
+			dest->length = wcs - dest->s;
+			dest->s[dest->length] = L'\0';
+			wcs_length = mbs_length;
+			if (NULL == archive_wstring_ensure(dest,
+			    dest->length + wcs_length + 1))
+				return (-1);
+			wcs = dest->s + dest->length;
+		}
 #if HAVE_MBRTOWC
 		r = mbrtowc(wcs, mbs, wcs_length, &shift_state);
 #else
 		r = mbtowc(wcs, mbs, wcs_length);
 #endif
 		if (r == (size_t)-1 || r == (size_t)-2) {
-			dest->s[dest->length] = L'\0';
-			return (-1);
+			ret_val = -1;
+			if (errno == EILSEQ) {
+				++mbs;
+				--mbs_length;
+				continue;
+			} else
+				break;
 		}
 		if (r == 0 || r > mbs_length)
 			break;
@@ -677,7 +633,7 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest,
 	}
 	dest->length = wcs - dest->s;
 	dest->s[dest->length] = L'\0';
-	return (0);
+	return (ret_val);
 }
 
 #endif
@@ -697,10 +653,7 @@ int
 archive_string_append_from_wcs(struct archive_string *as,
     const wchar_t *w, size_t len)
 {
-	int r = archive_string_append_from_wcs_in_codepage(as, w, len, NULL);
-	if (r != 0 && errno == ENOMEM)
-		__archive_errx(1, "No memory");
-	return (r);
+	return archive_string_append_from_wcs_in_codepage(as, w, len, NULL);
 }
 
 static int
@@ -774,7 +727,7 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
 			else
 				dp = &defchar_used;
 			count = WideCharToMultiByte(to_cp, 0, ws, wslen,
-			    as->s + as->length, as->buffer_length-1, NULL, dp);
+			    as->s + as->length, (int)as->buffer_length-1, NULL, dp);
 			if (count == 0 &&
 			    GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
 				/* Expand the MBS buffer and retry. */
@@ -792,73 +745,6 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
 	return (defchar_used?-1:ret);
 }
 
-#elif defined(HAVE_WCSNRTOMBS)
-
-/*
- * Translates a wide character string into current locale character set
- * and appends to the archive_string.  Note: returns -1 if conversion
- * fails.
- */
-int
-archive_string_append_from_wcs(struct archive_string *as,
-    const wchar_t *w, size_t len)
-{
-	mbstate_t shift_state;
-	size_t r, ndest, nwc;
-	char *dest;
-	const wchar_t *wp, *wpp;
-	int ret_val = 0;
-
-	wp = w;
-	nwc = len;
-	ndest = len * 2;
-	/* Initialize the shift state. */
-	memset(&shift_state, 0, sizeof(shift_state));
-	while (nwc > 0) {
-		/* Allocate buffer for MBS. */
-		if (archive_string_ensure(as, as->length + ndest + 1) == NULL)
-			__archive_errx(1, "Out of memory");
-
-		dest = as->s + as->length;
-		wpp = wp;
-		r = wcsnrtombs(dest, &wp, nwc,
-		    as->buffer_length - as->length -1,
-		    &shift_state);
-		if (r == (size_t)-1) {
-			if (errno == EILSEQ) {
-				/* Retry conversion just for safe WCS. */
-				size_t xwc = wp - wpp;
-				wp = wpp;
-				r = wcsnrtombs(dest, &wp, xwc,
-				    as->buffer_length - as->length -1,
-				    &shift_state);
-				if (r == (size_t)-1)
-					/* This would not happen. */
-					return (-1);
-				as->length += r;
-				nwc -= wp - wpp;
-				/* Skip an illegal wide char. */
-				as->s[as->length++] = '?';
-				wp++;
-				nwc--;
-				ret_val = -1;
-				continue;
-			} else {
-				ret_val = -1;
-				break;
-			}
-		}
-		as->length += r;
-		if (wp == NULL || (wp - wpp) >= nwc)
-			break;
-		/* Get a remaining WCS lenth. */
-		nwc -= wp - wpp;
-	}
-	/* All wide characters are translated to MBS. */
-	as->s[as->length] = '\0';
-	return (ret_val);
-}
-
 #elif defined(HAVE_WCTOMB) || defined(HAVE_WCRTOMB)
 
 /*
@@ -893,7 +779,7 @@ archive_string_append_from_wcs(struct archive_string *as,
 	 * as->s is still NULL.
 	 */
 	if (archive_string_ensure(as, as->length + len + 1) == NULL)
-		__archive_errx(1, "Out of memory");
+		return (-1);
 
 	p = as->s + as->length;
 	end = as->s + as->buffer_length - MB_CUR_MAX -1;
@@ -904,7 +790,7 @@ archive_string_append_from_wcs(struct archive_string *as,
 			/* Re-allocate buffer for MBS. */
 			if (archive_string_ensure(as,
 			    as->length + len * 2 + 1) == NULL)
-				__archive_errx(1, "Out of memory");
+				return (-1);
 			p = as->s + as->length;
 			end = as->s + as->buffer_length - MB_CUR_MAX -1;
 		}
@@ -946,6 +832,7 @@ archive_string_append_from_wcs(struct archive_string *as,
 	(void)as;/* UNUSED */
 	(void)w;/* UNUSED */
 	(void)len;/* UNUSED */
+	errno = ENOSYS;
 	return (-1);
 }
 
@@ -987,27 +874,6 @@ add_sconv_object(struct archive *a, struct archive_string_conv *sc)
 	*psc = sc;
 }
 
-#if defined(__APPLE__)
-
-static int
-createUniInfo(struct archive_string_conv *sconv)
-{
-	UnicodeMapping map;
-	OSStatus err;
-
-	map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
-	    kUnicodeNoSubset, kUnicode16BitFormat);
-	map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
-	    kUnicodeHFSPlusDecompVariant, kUnicode16BitFormat);
-	map.mappingVersion = kUnicodeUseLatestMapping;
-
-	sconv->uniInfo = NULL;
-	err = CreateUnicodeToTextInfo(&map, &(sconv->uniInfo));
-	return ((err == noErr)? 0: -1);
-}
-
-#endif /* __APPLE__ */
-
 static void
 add_converter(struct archive_string_conv *sc, int (*converter)
     (struct archive_string *, const void *, size_t,
@@ -1066,9 +932,11 @@ setup_converter(struct archive_string_conv *sc)
 
 		if (sc->flag & SCONV_BEST_EFFORT) {
 			if (sc->flag & SCONV_TO_UTF16BE)
-				add_converter(sc, best_effort_strncat_to_utf16be);
+				add_converter(sc,
+					best_effort_strncat_to_utf16be);
 			else
-				add_converter(sc, best_effort_strncat_to_utf16le);
+				add_converter(sc,
+					best_effort_strncat_to_utf16le);
 		} else
 			/* Make sure we have no converter. */
 			sc->nconverter = 0;
@@ -1082,12 +950,9 @@ setup_converter(struct archive_string_conv *sc)
 		/*
 		 * At least we should normalize a UTF-16BE string.
 		 */
-#if defined(__APPLE__)
 		if (sc->flag & SCONV_NORMALIZATION_D)
 			add_converter(sc,archive_string_normalize_D);
-		else
-#endif
-		if (sc->flag & SCONV_NORMALIZATION_C)
+		else if (sc->flag & SCONV_NORMALIZATION_C)
 			add_converter(sc, archive_string_normalize_C);
 
 		if (sc->flag & SCONV_TO_UTF8) {
@@ -1135,12 +1000,9 @@ setup_converter(struct archive_string_conv *sc)
 		/*
 		 * At least we should normalize a UTF-8 string.
 		 */
-#if defined(__APPLE__)
 		if (sc->flag & SCONV_NORMALIZATION_D)
 			add_converter(sc,archive_string_normalize_D);
-		else
-#endif
-		if (sc->flag & SCONV_NORMALIZATION_C)
+		else if (sc->flag & SCONV_NORMALIZATION_C)
 			add_converter(sc, archive_string_normalize_C);
 
 		/*
@@ -1174,6 +1036,16 @@ setup_converter(struct archive_string_conv *sc)
 #if HAVE_ICONV
 	if (sc->cd != (iconv_t)-1) {
 		add_converter(sc, iconv_strncat_in_locale);
+		/*
+		 * iconv generally does not support UTF-8-MAC and so
+		 * we have to the output of iconv from NFC to NFD if
+		 * need.
+		 */
+		if ((sc->flag & SCONV_FROM_CHARSET) &&
+		    (sc->flag & SCONV_TO_UTF8)) {
+			if (sc->flag & SCONV_NORMALIZATION_D)
+				add_converter(sc, archive_string_normalize_D);
+		}
 		return;
 	}
 #endif
@@ -1248,15 +1120,11 @@ create_sconv_object(const char *fc, const char *tc,
 	}
 	sc->to_charset = strdup(tc);
 	if (sc->to_charset == NULL) {
-		free(sc);
 		free(sc->from_charset);
+		free(sc);
 		return (NULL);
 	}
 	archive_string_init(&sc->utftmp);
-#if defined(__APPLE__)
-	archive_string_init(&sc->utf16nfc);
-	archive_string_init(&sc->utf16nfd);
-#endif
 
 	if (flag & SCONV_TO_CHARSET) {
 		/*
@@ -1286,7 +1154,7 @@ create_sconv_object(const char *fc, const char *tc,
 	 * Check if "from charset" and "to charset" are the same.
 	 */
 	if (strcmp(fc, tc) == 0 ||
-	    (sc->from_cp != -1 && sc->from_cp == sc->to_cp))
+	    (sc->from_cp != (unsigned)-1 && sc->from_cp == sc->to_cp))
 		sc->same = 1;
 	else
 		sc->same = 0;
@@ -1335,13 +1203,35 @@ create_sconv_object(const char *fc, const char *tc,
 	if ((flag & SCONV_FROM_CHARSET) &&
 	    (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8))) {
 #if defined(__APPLE__)
-		if (flag & SCONV_TO_UTF8) {
-			if (createUniInfo(sc) == 0)
-				flag |= SCONV_NORMALIZATION_D;
-		} else
+		if (flag & SCONV_TO_UTF8)
+			flag |= SCONV_NORMALIZATION_D;
+		else
 #endif
 			flag |= SCONV_NORMALIZATION_C;
 	}
+#if defined(__APPLE__)
+	/*
+	 * In case writing an archive file, make sure that a filename
+	 * going to be passed to iconv is a Unicode NFC string since
+	 * a filename in HFS Plus filesystem is a Unicode NFD one and
+	 * iconv cannot handle it with "UTF-8" charset. It is simpler
+	 * than a use of "UTF-8-MAC" charset.
+	 */
+	if ((flag & SCONV_TO_CHARSET) &&
+	    (flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) &&
+	    !(flag & (SCONV_TO_UTF16 | SCONV_TO_UTF8)))
+		flag |= SCONV_NORMALIZATION_C;
+	/*
+	 * In case reading an archive file. make sure that a filename
+	 * will be passed to users is a Unicode NFD string in order to
+	 * correctly compare the filename with other one which comes
+	 * from HFS Plus filesystem.
+	 */
+	if ((flag & SCONV_FROM_CHARSET) &&
+	   !(flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) &&
+	    (flag & SCONV_TO_UTF8))
+		flag |= SCONV_NORMALIZATION_D;
+#endif
 
 #if defined(HAVE_ICONV)
 	sc->cd_w = (iconv_t)-1;
@@ -1353,46 +1243,6 @@ create_sconv_object(const char *fc, const char *tc,
 	    (flag & SCONV_WIN_CP)) {
 		/* This case we won't use iconv. */
 		sc->cd = (iconv_t)-1;
-#if defined(__APPLE__)
-	} else if ((flag & SCONV_FROM_CHARSET) && (flag & SCONV_TO_UTF8)) {
-		/*
-		 * In case reading an archive file.
-		 * Translate non-Unicode filenames in an archive file to
-		 * UTF-8-MAC filenames.
-		 */
-		sc->cd = iconv_open("UTF-8-MAC", fc);
-		if (sc->cd == (iconv_t)-1) {
-			if ((sc->flag & SCONV_BEST_EFFORT) &&
-			    strcmp(fc, "CP932") == 0) {
-				sc->cd = iconv_open("UTF-8-MAC", "SJIS");
-				if (sc->cd == (iconv_t)-1) {
-					sc->cd = iconv_open(tc, fc);
-					if (sc->cd == (iconv_t)-1)
-						sc->cd = iconv_open(tc, "SJIS");
-				}
-			} else
-				sc->cd = iconv_open(tc, fc);
-		}
-	} else if ((flag & SCONV_TO_CHARSET) && (flag & SCONV_FROM_UTF8)) {
-		/*
-		 * In case writing an archive file.
-		 * Translate UTF-8-MAC filenames in HFS Plus to non-Unicode
-		 * filenames.
-		 */
-		sc->cd = iconv_open(tc, "UTF-8-MAC");
-		if (sc->cd == (iconv_t)-1) {
-			if ((sc->flag & SCONV_BEST_EFFORT) &&
-			    strcmp(tc, "CP932") == 0) {
-				sc->cd = iconv_open("SJIS", "UTF-8-MAC");
-				if (sc->cd == (iconv_t)-1) {
-					sc->cd = iconv_open(tc, fc);
-					if (sc->cd == (iconv_t)-1)
-						sc->cd = iconv_open("SJIS", fc);
-				}
-			} else
-				sc->cd = iconv_open(tc, fc);
-		}
-#endif
 	} else {
 		sc->cd = iconv_open(tc, fc);
 		if (sc->cd == (iconv_t)-1 && (sc->flag & SCONV_BEST_EFFORT)) {
@@ -1428,7 +1278,7 @@ create_sconv_object(const char *fc, const char *tc,
 	sc->flag = flag;
 
 	/*
-	 * Setup converters.
+	 * Set up converters.
 	 */
 	setup_converter(sc);
 
@@ -1450,12 +1300,6 @@ free_sconv_object(struct archive_string_conv *sc)
 	if (sc->cd_w != (iconv_t)-1)
 		iconv_close(sc->cd_w);
 #endif
-#if defined(__APPLE__)
-	archive_string_free(&sc->utf16nfc);
-	archive_string_free(&sc->utf16nfd);
-	if (sc->uniInfo != NULL)
-		DisposeUnicodeToTextInfo(&(sc->uniInfo));
-#endif
 	free(sc);
 }
 
@@ -1646,7 +1490,7 @@ make_codepage_from_charset(const char *charset)
  * Return ANSI Code Page of current locale set by setlocale().
  */
 static unsigned
-get_current_codepage()
+get_current_codepage(void)
 {
 	char *locale, *p;
 	unsigned cp;
@@ -1721,7 +1565,7 @@ static struct {
  * Return OEM Code Page of current locale set by setlocale().
  */
 static unsigned
-get_current_oemcp()
+get_current_oemcp(void)
 {
 	int i;
 	char *locale, *p;
@@ -1750,7 +1594,7 @@ get_current_oemcp()
  */
 
 static unsigned
-get_current_codepage()
+get_current_codepage(void)
 {
 	return (-1);/* Unknown */
 }
@@ -1761,7 +1605,7 @@ make_codepage_from_charset(const char *charset)
 	return (-1);/* Unknown */
 }
 static unsigned
-get_current_oemcp()
+get_current_oemcp(void)
 {
 	return (-1);/* Unknown */
 }
@@ -1995,11 +1839,37 @@ archive_string_conversion_set_opt(struct archive_string_conv *sc, int opt)
 #else
 		if ((sc->flag & SCONV_UTF8_LIBARCHIVE_2) == 0) {
 			sc->flag |= SCONV_UTF8_LIBARCHIVE_2;
-			/* Re-setup string converters. */
+			/* Set up string converters. */
 			setup_converter(sc);
 		}
 #endif
 		break;
+	case SCONV_SET_OPT_NORMALIZATION_C:
+		if ((sc->flag & SCONV_NORMALIZATION_C) == 0) {
+			sc->flag |= SCONV_NORMALIZATION_C;
+			sc->flag &= ~SCONV_NORMALIZATION_D;
+			/* Set up string converters. */
+			setup_converter(sc);
+		}
+		break;
+	case SCONV_SET_OPT_NORMALIZATION_D:
+#if defined(HAVE_ICONV)
+		/*
+		 * If iconv will take the string, do not change the
+		 * setting of the normalization.
+		 */
+		if (!(sc->flag & SCONV_WIN_CP) &&
+		     (sc->flag & (SCONV_FROM_UTF16 | SCONV_FROM_UTF8)) &&
+		    !(sc->flag & (SCONV_TO_UTF16 | SCONV_TO_UTF8)))
+			break;
+#endif
+		if ((sc->flag & SCONV_NORMALIZATION_D) == 0) {
+			sc->flag |= SCONV_NORMALIZATION_D;
+			sc->flag &= ~SCONV_NORMALIZATION_C;
+			/* Set up string converters. */
+			setup_converter(sc);
+		}
+		break;
 	default:
 		break;
 	}
@@ -2009,8 +1879,8 @@ archive_string_conversion_set_opt(struct archive_string_conv *sc, int opt)
  *
  * Copy one archive_string to another in locale conversion.
  *
- *	archive_strncpy_in_locale();
- *	archive_strcpy_in_locale();
+ *	archive_strncat_l();
+ *	archive_strncpy_l();
  *
  */
 
@@ -2056,15 +1926,15 @@ utf16nbytes(const void *_p, size_t n)
 }
 
 int
-archive_strncpy_in_locale(struct archive_string *as, const void *_p, size_t n,
+archive_strncpy_l(struct archive_string *as, const void *_p, size_t n,
     struct archive_string_conv *sc)
 {
 	as->length = 0;
-	return (archive_strncat_in_locale(as, _p, n, sc));
+	return (archive_strncat_l(as, _p, n, sc));
 }
 
 int
-archive_strncat_in_locale(struct archive_string *as, const void *_p, size_t n,
+archive_strncat_l(struct archive_string *as, const void *_p, size_t n,
     struct archive_string_conv *sc)
 {
 	const void *s;
@@ -2127,7 +1997,7 @@ static int
 iconv_strncat_in_locale(struct archive_string *as, const void *_p,
     size_t length, struct archive_string_conv *sc)
 {
-	ICONV_CONST char *inp;
+	ICONV_CONST char *itp;
 	size_t remaining;
 	iconv_t cd;
 	char *outp;
@@ -2148,12 +2018,12 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
 		return (-1);
 
 	cd = sc->cd;
-	inp = (char *)(uintptr_t)_p;
+	itp = (char *)(uintptr_t)_p;
 	remaining = length;
 	outp = as->s + as->length;
 	avail = as->buffer_length - as->length - to_size;
 	while (remaining >= (size_t)from_size) {
-		size_t result = iconv(cd, &inp, &remaining, &outp, &avail);
+		size_t result = iconv(cd, &itp, &remaining, &outp, &avail);
 
 		if (result != (size_t)-1)
 			break; /* Conversion completed. */
@@ -2195,7 +2065,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
 				*outp++ = '?';
 				avail--;
 			}
-			inp += from_size;
+			itp += from_size;
 			remaining -= from_size;
 			return_value = -1; /* failure */
 		} else {
@@ -2275,7 +2145,7 @@ invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc)
 	if (codepage != CP_UTF8)
 		mbflag |= MB_PRECOMPOSED;
 
-	if (MultiByteToWideChar(codepage, mbflag, p, n, NULL, 0) == 0)
+	if (MultiByteToWideChar(codepage, mbflag, p, (int)n, NULL, 0) == 0)
 		return (-1); /* Invalid */
 	return (0); /* Okay */
 }
@@ -2291,7 +2161,6 @@ invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc)
 	const char *p = (const char *)_p;
 	size_t r;
 
-	(void)sc; /* UNUSED */
 #if HAVE_MBRTOWC
 	mbstate_t shift_state;
 
@@ -2315,6 +2184,7 @@ invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc)
 		p += r;
 		n -= r;
 	}
+	(void)sc; /* UNUSED */
 	return (0); /* All Okey. */
 }
 
@@ -2332,8 +2202,8 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
     size_t length, struct archive_string_conv *sc)
 {
 	size_t remaining;
-	char *outp;
-	const char *inp;
+	char *otp;
+	const uint8_t *itp;
 	size_t avail;
 	int return_value = 0; /* success */
 
@@ -2357,41 +2227,41 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
 		return (-1);
 
 	remaining = length;
-	inp = (const char *)_p;
-	outp = as->s + as->length;
+	itp = (const uint8_t *)_p;
+	otp = as->s + as->length;
 	avail = as->buffer_length - as->length -1;
-	while (*inp && remaining > 0) {
-		if (*inp < 0 && (sc->flag & SCONV_TO_UTF8)) {
+	while (*itp && remaining > 0) {
+		if (*itp > 127 && (sc->flag & SCONV_TO_UTF8)) {
 			if (avail < UTF8_R_CHAR_SIZE) {
-				as->length = outp - as->s;
+				as->length = otp - as->s;
 				if (NULL == archive_string_ensure(as,
 				    as->buffer_length + remaining +
 				    UTF8_R_CHAR_SIZE))
 					return (-1);
-				outp = as->s + as->length;
+				otp = as->s + as->length;
 				avail = as->buffer_length - as->length -1;
 			}
 			/*
 		 	 * When coping a string in UTF-8, unknown character
 			 * should be U+FFFD (replacement character).
 			 */
-			UTF8_SET_R_CHAR(outp);
-			outp += UTF8_R_CHAR_SIZE;
+			UTF8_SET_R_CHAR(otp);
+			otp += UTF8_R_CHAR_SIZE;
 			avail -= UTF8_R_CHAR_SIZE;
-			inp++;
+			itp++;
 			remaining--;
 			return_value = -1;
-		} else if (*inp < 0) {
-			*outp++ = '?';
-			inp++;
+		} else if (*itp > 127) {
+			*otp++ = '?';
+			itp++;
 			remaining--;
 			return_value = -1;
 		} else {
-			*outp++ = *inp++;
+			*otp++ = (char)*itp++;
 			remaining--;
 		}
 	}
-	as->length = outp - as->s;
+	as->length = otp - as->s;
 	as->s[as->length] = '\0';
 	return (return_value);
 }
@@ -2452,7 +2322,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
 
 	/* Invalide sequence or there are not plenty bytes. */
 	if ((int)n < cnt) {
-		cnt = n;
+		cnt = (int)n;
 		for (i = 1; i < cnt; i++) {
 			if ((s[i] & 0xc0) != 0x80) {
 				cnt = i;
@@ -2521,7 +2391,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
 		else
 			cnt = 1;
 		if ((int)n < cnt)
-			cnt = n;
+			cnt = (int)n;
 		for (i = 1; i < cnt; i++) {
 			if ((s[i] & 0xc0) != 0x80) {
 				cnt = i;
@@ -2577,11 +2447,12 @@ combine_surrogate_pair(uint32_t uc, uint32_t uc2)
 static int
 cesu8_to_unicode(uint32_t *pwc, const char *s, size_t n)
 {
-	uint32_t wc, wc2;
+	uint32_t wc = 0;
 	int cnt;
 
 	cnt = _utf8_to_unicode(&wc, s, n);
 	if (cnt == 3 && IS_HIGH_SURROGATE_LA(wc)) {
+		uint32_t wc2 = 0;
 		if (n - 3 < 3) {
 			/* Invalid byte sequence. */
 			goto invalid_sequence;
@@ -2773,8 +2644,8 @@ unicode_to_utf16le(char *p, size_t remaining, uint32_t uc)
  * If any surrogate pair are found, it would be canonicalized.
  */
 static int
-strncat_from_utf8_to_utf8(struct archive_string *as, const void *_p, size_t len,
-    struct archive_string_conv *sc)
+strncat_from_utf8_to_utf8(struct archive_string *as, const void *_p,
+    size_t len, struct archive_string_conv *sc)
 {
 	const char *s;
 	char *p, *endp;
@@ -3250,8 +3121,8 @@ archive_string_normalize_C(struct archive_string *as, const void *_p,
 
 				/*
 				 * Remove ucx[i] by shifting
-				 * follwoing code points.
-				 */ 
+				 * following code points.
+				 */
 				for (j = i; j+1 < ucx_size; j++) {
 					ucx[j] = ucx[j+1];
 					ccx[j] = ccx[j+1];
@@ -3320,122 +3191,224 @@ archive_string_normalize_C(struct archive_string *as, const void *_p,
 	return (ret);
 }
 
-#if defined(__APPLE__)
-
-/*
- * Normalize UTF-8 characters to Form D and copy the result.
- */
 static int
-archive_string_normalize_D(struct archive_string *as, const void *_p,
-    size_t len, struct archive_string_conv *sc)
+get_nfd(uint32_t *cp1, uint32_t *cp2, uint32_t uc)
 {
-	const UniChar *inp;
-	char *outp;
-	size_t newsize;
-	ByteCount inCount, outCount;
-	ByteCount inAvail, outAvail;
-	OSStatus err;
-	int ret, saved_flag;
+	int t, b;
 
 	/*
-	 * Convert the current string to UTF-16LE for normalization.
-	 * The character-set of the current string must be UTF-16BE or
-	 * UTF-8.
+	 * These are not converted to NFD on Mac OS.
 	 */
-	archive_string_empty(&(sc->utf16nfc));
-	saved_flag = sc->flag;/* save a flag. */
-	sc->flag &= ~(SCONV_TO_UTF16BE | SCONV_TO_UTF8);
-	sc->flag |= SCONV_TO_UTF16LE;
-	ret = archive_string_append_unicode(&(sc->utf16nfc), _p, len, sc);
-	sc->flag = saved_flag;/* restore the saved flag */
-	if (archive_strlen(&(sc->utf16nfc)) == 0) {
-		if (archive_string_ensure(as, as->length + 1) == NULL)
-			return (-1);
-		return (ret);
-	}
-
+	if ((uc >= 0x2000 && uc <= 0x2FFF) ||
+	    (uc >= 0xF900 && uc <= 0xFAFF) ||
+	    (uc >= 0x2F800 && uc <= 0x2FAFF))
+		return (0);
 	/*
-	 * Normalize an NFC string to be an NFD(HFS Plus version).
+	 * Those code points are not converted to NFD on Mac OS.
+	 * I do not know the reason because it is undocumented.
+	 *   NFC        NFD
+	 *   1109A  ==> 11099 110BA
+	 *   1109C  ==> 1109B 110BA
+	 *   110AB  ==> 110A5 110BA
 	 */
-	newsize = sc->utf16nfc.length + 2;
-	if (archive_string_ensure(&(sc->utf16nfd), newsize) == NULL)
-		return (-1);
+	if (uc == 0x1109A || uc == 0x1109C || uc == 0x110AB)
+		return (0);
 
-	inp = (UniChar *)sc->utf16nfc.s;
-	inAvail = archive_strlen(&(sc->utf16nfc));
-	sc->utf16nfd.length = 0;
-	outp = sc->utf16nfd.s;
-	outAvail = sc->utf16nfd.buffer_length -2;
+	t = 0;
+	b = sizeof(u_decomposition_table)/sizeof(u_decomposition_table[0]) -1;
+	while (b >= t) {
+		int m = (t + b) / 2;
+		if (u_decomposition_table[m].nfc < uc)
+			t = m + 1;
+		else if (u_decomposition_table[m].nfc > uc)
+			b = m - 1;
+		else {
+			*cp1 = u_decomposition_table[m].cp1;
+			*cp2 = u_decomposition_table[m].cp2;
+			return (1);
+		}
+	}
+	return (0);
+}
 
-	do {
-		/* Reinitialize all state information. */
-		if (ResetUnicodeToTextInfo(sc->uniInfo) != noErr)
-			goto return_no_changed_data;
-
-		inCount = outCount = 0;
-		err = ConvertFromUnicodeToText(sc->uniInfo,
-		    inAvail, inp,
-		    kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL,
-		    outAvail, &inCount, &outCount, outp);
-
-		if (err == noErr) {
-			sc->utf16nfd.length = outCount;
-			sc->utf16nfd.s[sc->utf16nfd.length] = 0;
-			sc->utf16nfd.s[sc->utf16nfd.length+1] = 0;
-		} else if (err == kTECOutputBufferFullStatus) {
-			newsize = inAvail - inCount;
-			if (newsize > inAvail)
-				newsize = inAvail;
-			newsize += sc->utf16nfd.buffer_length + 2;
-			if (archive_string_ensure(&(sc->utf16nfd), newsize)
-			    == NULL)
-				return (-1);
-			outp = sc->utf16nfd.s;
-			outAvail = sc->utf16nfd.buffer_length -2;
-		} else
-			goto return_no_changed_data;
-	} while (err == kTECOutputBufferFullStatus);
+#define REPLACE_UC_WITH(cp) do {		\
+	uc = cp;				\
+	ucptr = NULL;				\
+} while (0)
 
-	/*
-	 * If there is a next-step conversion, we should convert
-	 * a UTF-16LE(NFD) string back to the original Unicode type.
-	 */
-	saved_flag = sc->flag;/* save a flag. */
-	if (!(sc->flag &
-	    (SCONV_TO_UTF16BE | SCONV_TO_UTF16LE | SCONV_TO_UTF8))) {
+/*
+ * Normalize UTF-8 characters to Form D and copy the result.
+ */
+static int
+archive_string_normalize_D(struct archive_string *as, const void *_p,
+    size_t len, struct archive_string_conv *sc)
+{
+	const char *s = (const char *)_p;
+	char *p, *endp;
+	uint32_t uc, uc2;
+	size_t w;
+	int always_replace, n, n2, ret = 0, spair, ts, tm;
+	int (*parse)(uint32_t *, const char *, size_t);
+	size_t (*unparse)(char *, size_t, uint32_t);
+
+	always_replace = 1;
+	ts = 1;/* text size. */
+	if (sc->flag & SCONV_TO_UTF16BE) {
+		unparse = unicode_to_utf16be;
+		ts = 2;
+		if (sc->flag & SCONV_FROM_UTF16BE)
+			always_replace = 0;
+	} else if (sc->flag & SCONV_TO_UTF16LE) {
+		unparse = unicode_to_utf16le;
+		ts = 2;
+		if (sc->flag & SCONV_FROM_UTF16LE)
+			always_replace = 0;
+	} else if (sc->flag & SCONV_TO_UTF8) {
+		unparse = unicode_to_utf8;
+		if (sc->flag & SCONV_FROM_UTF8)
+			always_replace = 0;
+	} else {
 		/*
 		 * This case is going to be converted to another
 		 * character-set through iconv.
 		 */
-		if (sc->flag & SCONV_FROM_UTF16BE)
-			sc->flag |= SCONV_TO_UTF16BE;
-		else if (sc->flag & SCONV_FROM_UTF16LE)
-			sc->flag |= SCONV_TO_UTF16LE;
+		always_replace = 0;
+		if (sc->flag & SCONV_FROM_UTF16BE) {
+			unparse = unicode_to_utf16be;
+			ts = 2;
+		} else if (sc->flag & SCONV_FROM_UTF16LE) {
+			unparse = unicode_to_utf16le;
+			ts = 2;
+		} else {
+			unparse = unicode_to_utf8;
+		}
+	}
+
+	if (sc->flag & SCONV_FROM_UTF16BE) {
+		parse = utf16be_to_unicode;
+		tm = 1;
+		spair = 4;/* surrogate pair size in UTF-16. */
+	} else if (sc->flag & SCONV_FROM_UTF16LE) {
+		parse = utf16le_to_unicode;
+		tm = 1;
+		spair = 4;/* surrogate pair size in UTF-16. */
+	} else {
+		parse = cesu8_to_unicode;
+		tm = ts;
+		spair = 6;/* surrogate pair size in UTF-8. */
+	}
+
+	if (archive_string_ensure(as, as->length + len * tm + ts) == NULL)
+		return (-1);
+
+	p = as->s + as->length;
+	endp = as->s + as->buffer_length - ts;
+	while ((n = parse(&uc, s, len)) != 0) {
+		const char *ucptr;
+		uint32_t cp1, cp2;
+		int SIndex;
+		struct {
+			uint32_t uc;
+			int ccc;
+		} fdc[FDC_MAX];
+		int fdi, fdj;
+		int ccc;
+
+check_first_code:
+		if (n < 0) {
+			/* Use a replaced unicode character. */
+			UNPARSE(p, endp, uc);
+			s += n*-1;
+			len -= n*-1;
+			ret = -1;
+			continue;
+		} else if (n == spair || always_replace)
+			/* uc is converted from a surrogate pair.
+			 * this should be treated as a changed code. */
+			ucptr = NULL;
 		else
-			sc->flag |= SCONV_TO_UTF8;
+			ucptr = s;
+		s += n;
+		len -= n;
+
+		/* Hangul Decomposition. */
+		if ((SIndex = uc - HC_SBASE) >= 0 && SIndex < HC_SCOUNT) {
+			int L = HC_LBASE + SIndex / HC_NCOUNT;
+			int V = HC_VBASE + (SIndex % HC_NCOUNT) / HC_TCOUNT;
+			int T = HC_TBASE + SIndex % HC_TCOUNT;
+
+			REPLACE_UC_WITH(L);
+			WRITE_UC();
+			REPLACE_UC_WITH(V);
+			WRITE_UC();
+			if (T != HC_TBASE) {
+				REPLACE_UC_WITH(T);
+				WRITE_UC();
+			}
+			continue;
+		}
+		if (IS_DECOMPOSABLE_BLOCK(uc) && CCC(uc) != 0) {
+			WRITE_UC();
+			continue;
+		}
+
+		fdi = 0;
+		while (get_nfd(&cp1, &cp2, uc) && fdi < FDC_MAX) {
+			int k;
+
+			for (k = fdi; k > 0; k--)
+				fdc[k] = fdc[k-1];
+			fdc[0].ccc = CCC(cp2);
+			fdc[0].uc = cp2;
+			fdi++;
+			REPLACE_UC_WITH(cp1);
+		}
+
+		/* Read following code points. */
+		while ((n2 = parse(&uc2, s, len)) > 0 &&
+		    (ccc = CCC(uc2)) != 0 && fdi < FDC_MAX) {
+			int j, k;
+
+			s += n2;
+			len -= n2;
+			for (j = 0; j < fdi; j++) {
+				if (fdc[j].ccc > ccc)
+					break;
+			}
+			if (j < fdi) {
+				for (k = fdi; k > j; k--)
+					fdc[k] = fdc[k-1];
+				fdc[j].ccc = ccc;
+				fdc[j].uc = uc2;
+			} else {
+				fdc[fdi].ccc = ccc;
+				fdc[fdi].uc = uc2;
+			}
+			fdi++;
+		}
+
+		WRITE_UC();
+		for (fdj = 0; fdj < fdi; fdj++) {
+			REPLACE_UC_WITH(fdc[fdj].uc);
+			WRITE_UC();
+		}
+
+		if (n2 == 0)
+			break;
+		REPLACE_UC_WITH(uc2);
+		n = n2;
+		goto check_first_code;
 	}
-	sc->flag &= ~(SCONV_FROM_UTF16BE | SCONV_FROM_UTF8);
-	sc->flag |= SCONV_FROM_UTF16LE;
-	if (archive_string_append_unicode(as, sc->utf16nfd.s,
-	    sc->utf16nfd.length, sc) != 0)
-		ret = -1;
-	sc->flag = saved_flag;/* restore the saved flag */
+	as->length = p - as->s;
+	as->s[as->length] = '\0';
+	if (ts == 2)
+		as->s[as->length+1] = '\0';
 	return (ret);
-
-return_no_changed_data:
-	/*
-	 * Something conversion error happend, so we return a no normalized
-	 * string with an error.
-	 */
-	(void)archive_string_append_unicode(as, _p, len, sc);
-	return (-1);
 }
 
-#endif /* __APPLE__ */
-
 /*
- * libarchive 2.x made incorrect UTF-8 strings in the wrong assumuption
- * that WCS is Unicode. it is true for servel platforms but some are false.
+ * libarchive 2.x made incorrect UTF-8 strings in the wrong assumption
+ * that WCS is Unicode. It is true for several platforms but some are false.
  * And then people who did not use UTF-8 locale on the non Unicode WCS
  * platform and made a tar file with libarchive(mostly bsdtar) 2.x. Those
  * now cannot get right filename from libarchive 3.x and later since we
@@ -3505,9 +3478,9 @@ strncat_from_utf8_libarchive2(struct archive_string *as,
 		 * Translates the wide-character into the current locale MBS.
 		 */
 #if HAVE_WCRTOMB
-		n = wcrtomb(p, wc, &shift_state);
+		n = (int)wcrtomb(p, wc, &shift_state);
 #else
-		n = wctomb(p, wc);
+		n = (int)wctomb(p, wc);
 #endif
 		if (n == -1)
 			return (-1);
@@ -3606,13 +3579,13 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
 	do {
 		defchar = 0;
 		ll = WideCharToMultiByte(sc->to_cp, 0,
-		    (LPCWSTR)u16, bytes>>1, mbs, mbs_size,
+		    (LPCWSTR)u16, (int)bytes>>1, mbs, (int)mbs_size,
 			NULL, &defchar);
 		if (ll == 0 &&
 		    GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
 			/* Need more buffer for MBS. */
 			ll = WideCharToMultiByte(sc->to_cp, 0,
-			    (LPCWSTR)u16, bytes, NULL, 0, NULL, NULL);
+			    (LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL);
 			if (archive_string_ensure(as, ll +1) == NULL)
 				return (-1);
 			mbs = as->s + as->length;
@@ -3629,15 +3602,15 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
 }
 
 static int
-win_strncat_from_utf16be(struct archive_string *as, const void *_p, size_t bytes,
-    struct archive_string_conv *sc)
+win_strncat_from_utf16be(struct archive_string *as, const void *_p,
+    size_t bytes, struct archive_string_conv *sc)
 {
 	return (win_strncat_from_utf16(as, _p, bytes, sc, 1));
 }
 
 static int
-win_strncat_from_utf16le(struct archive_string *as, const void *_p, size_t bytes,
-    struct archive_string_conv *sc)
+win_strncat_from_utf16le(struct archive_string *as, const void *_p,
+    size_t bytes, struct archive_string_conv *sc)
 {
 	return (win_strncat_from_utf16(as, _p, bytes, sc, 0));
 }
@@ -3655,8 +3628,8 @@ is_big_endian(void)
  * Return -1 if conversion failes.
  */
 static int
-win_strncat_to_utf16(struct archive_string *as16, const void *_p, size_t length,
-    struct archive_string_conv *sc, int bigendian)
+win_strncat_to_utf16(struct archive_string *as16, const void *_p,
+    size_t length, struct archive_string_conv *sc, int bigendian)
 {
 	const char *s = (const char *)_p;
 	char *u16;
@@ -3689,12 +3662,12 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p, size_t length,
 	}
 	do {
 		count = MultiByteToWideChar(sc->from_cp,
-		    MB_PRECOMPOSED, s, length, (LPWSTR)u16, (int)avail>>1);
+		    MB_PRECOMPOSED, s, (int)length, (LPWSTR)u16, (int)avail>>1);
 		if (count == 0 &&
 		    GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
 			/* Need more buffer for UTF-16 string */
 			count = MultiByteToWideChar(sc->from_cp,
-			    MB_PRECOMPOSED, s, length, NULL, 0);
+			    MB_PRECOMPOSED, s, (int)length, NULL, 0);
 			if (archive_string_ensure(as16, (count +1) * 2)
 			    == NULL)
 				return (-1);
@@ -3732,15 +3705,15 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p, size_t length,
 }
 
 static int
-win_strncat_to_utf16be(struct archive_string *as16, const void *_p, size_t length,
-    struct archive_string_conv *sc)
+win_strncat_to_utf16be(struct archive_string *as16, const void *_p,
+    size_t length, struct archive_string_conv *sc)
 {
 	return (win_strncat_to_utf16(as16, _p, length, sc, 1));
 }
 
 static int
-win_strncat_to_utf16le(struct archive_string *as16, const void *_p, size_t length,
-    struct archive_string_conv *sc)
+win_strncat_to_utf16le(struct archive_string *as16, const void *_p,
+    size_t length, struct archive_string_conv *sc)
 {
 	return (win_strncat_to_utf16(as16, _p, length, sc, 0));
 }
@@ -3914,7 +3887,7 @@ archive_mstring_get_utf8(struct archive *a, struct archive_mstring *aes,
 		sc = archive_string_conversion_to_charset(a, "UTF-8", 1);
 		if (sc == NULL)
 			return (-1);/* Couldn't allocate memory for sc. */
-		r = archive_strncpy_in_locale(&(aes->aes_mbs), aes->aes_mbs.s,
+		r = archive_strncpy_l(&(aes->aes_mbs), aes->aes_mbs.s,
 		    aes->aes_mbs.length, sc);
 		if (a == NULL)
 			free_sconv_object(sc);
@@ -4043,7 +4016,7 @@ archive_mstring_get_mbs_l(struct archive_mstring *aes,
 				*length = aes->aes_mbs.length;
 			return (0);
 		}
-		ret = archive_strncpy_in_locale(&(aes->aes_mbs_in_locale),
+		ret = archive_strncpy_l(&(aes->aes_mbs_in_locale),
 		    aes->aes_mbs.s, aes->aes_mbs.length, sc);
 		*p = aes->aes_mbs_in_locale.s;
 		if (length != NULL)
@@ -4084,7 +4057,8 @@ archive_mstring_copy_mbs_len(struct archive_mstring *aes, const char *mbs,
 int
 archive_mstring_copy_wcs(struct archive_mstring *aes, const wchar_t *wcs)
 {
-	return archive_mstring_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs));
+	return archive_mstring_copy_wcs_len(aes, wcs,
+				wcs == NULL ? 0 : wcslen(wcs));
 }
 
 int
@@ -4143,7 +4117,7 @@ archive_mstring_copy_mbs_len_l(struct archive_mstring *aes,
 		 * Translate multi-bytes from some character-set to UTF-8.
 		 */ 
 		sc->cd = sc->cd_w;
-		r = archive_strncpy_in_locale(&(aes->aes_utf8), mbs, len, sc);
+		r = archive_strncpy_l(&(aes->aes_utf8), mbs, len, sc);
 		sc->cd = cd;
 		if (r != 0) {
 			aes->aes_set = 0;
@@ -4175,7 +4149,7 @@ archive_mstring_copy_mbs_len_l(struct archive_mstring *aes,
 			aes->aes_set = 0;
 	}
 #else
-	r = archive_strncpy_in_locale(&(aes->aes_mbs), mbs, len, sc);
+	r = archive_strncpy_l(&(aes->aes_mbs), mbs, len, sc);
 	if (r == 0)
 		aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */
 	else
@@ -4219,7 +4193,7 @@ archive_mstring_update_utf8(struct archive *a, struct archive_mstring *aes,
 	sc = archive_string_conversion_from_charset(a, "UTF-8", 1);
 	if (sc == NULL)
 		return (-1);/* Couldn't allocate memory for sc. */
-	r = archive_strcpy_in_locale(&(aes->aes_mbs), utf8, sc);
+	r = archive_strcpy_l(&(aes->aes_mbs), utf8, sc);
 	if (a == NULL)
 		free_sconv_object(sc);
 	if (r != 0)
diff --git a/libarchive/archive_string.h b/libarchive/archive_string.h
index 0e4c9b9..23f4916 100644
--- a/libarchive/archive_string.h
+++ b/libarchive/archive_string.h
@@ -110,18 +110,20 @@ archive_string_conversion_charset_name(struct archive_string_conv *);
 void
 archive_string_conversion_set_opt(struct archive_string_conv *, int);
 #define SCONV_SET_OPT_UTF8_LIBARCHIVE2X	1
+#define SCONV_SET_OPT_NORMALIZATION_C	2
+#define SCONV_SET_OPT_NORMALIZATION_D	4
 
 
 /* Copy one archive_string to another in locale conversion.
  * Return -1 if conversion failes. */
 int
-archive_strncpy_in_locale(struct archive_string *, const void *, size_t,
+archive_strncpy_l(struct archive_string *, const void *, size_t,
     struct archive_string_conv *);
 
 /* Copy one archive_string to another in locale conversion.
  * Return -1 if conversion failes. */
 int
-archive_strncat_in_locale(struct archive_string *, const void *, size_t,
+archive_strncat_l(struct archive_string *, const void *, size_t,
     struct archive_string_conv *);
 
 
@@ -162,8 +164,8 @@ archive_wstrcat(struct archive_wstring *, const wchar_t *);
 	archive_strncpy((as), (p), ((p) == NULL ? 0 : strlen(p)))
 #define	archive_wstrcpy(as,p) \
 	archive_wstrncpy((as), (p), ((p) == NULL ? 0 : wcslen(p)))
-#define	archive_strcpy_in_locale(as,p,lo) \
-	archive_strncpy_in_locale((as), (p), ((p) == NULL ? 0 : strlen(p)), (lo))
+#define	archive_strcpy_l(as,p,lo) \
+	archive_strncpy_l((as), (p), ((p) == NULL ? 0 : strlen(p)), (lo))
 
 /* Copy a C string to an archive_string with limit, resizing as necessary. */
 #define	archive_strncpy(as,p,l) \
diff --git a/libarchive/archive_string_composition.h b/libarchive/archive_string_composition.h
index cc4bf46..be41e33 100644
--- a/libarchive/archive_string_composition.h
+++ b/libarchive/archive_string_composition.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2011 libarchive Project
+ * Copyright (c) 2011-2012 libarchive Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
 /*
  * ATTENTION!
  *  This file is generated by build/utils/gen_archive_string_composition_h.sh
- *  from http://unicode.org/Public/UNIDATA/UnicodeData.txt
+ *  from http://unicode.org/Public/6.0.0/ucd/UnicodeData.txt
  *
  *  See also http://unicode.org/report/tr15/
  */
@@ -1348,4 +1348,945 @@ static const unsigned char ccc_index[] = {
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0, 0,37,38,};
 
+struct unicode_decomposition_table {
+	uint32_t nfc;
+	uint32_t cp1;
+	uint32_t cp2;
+};
+
+static const struct unicode_decomposition_table u_decomposition_table[] = {
+	{ 0x000C0 , 0x00041 , 0x00300 },
+	{ 0x000C1 , 0x00041 , 0x00301 },
+	{ 0x000C2 , 0x00041 , 0x00302 },
+	{ 0x000C3 , 0x00041 , 0x00303 },
+	{ 0x000C4 , 0x00041 , 0x00308 },
+	{ 0x000C5 , 0x00041 , 0x0030A },
+	{ 0x000C7 , 0x00043 , 0x00327 },
+	{ 0x000C8 , 0x00045 , 0x00300 },
+	{ 0x000C9 , 0x00045 , 0x00301 },
+	{ 0x000CA , 0x00045 , 0x00302 },
+	{ 0x000CB , 0x00045 , 0x00308 },
+	{ 0x000CC , 0x00049 , 0x00300 },
+	{ 0x000CD , 0x00049 , 0x00301 },
+	{ 0x000CE , 0x00049 , 0x00302 },
+	{ 0x000CF , 0x00049 , 0x00308 },
+	{ 0x000D1 , 0x0004E , 0x00303 },
+	{ 0x000D2 , 0x0004F , 0x00300 },
+	{ 0x000D3 , 0x0004F , 0x00301 },
+	{ 0x000D4 , 0x0004F , 0x00302 },
+	{ 0x000D5 , 0x0004F , 0x00303 },
+	{ 0x000D6 , 0x0004F , 0x00308 },
+	{ 0x000D9 , 0x00055 , 0x00300 },
+	{ 0x000DA , 0x00055 , 0x00301 },
+	{ 0x000DB , 0x00055 , 0x00302 },
+	{ 0x000DC , 0x00055 , 0x00308 },
+	{ 0x000DD , 0x00059 , 0x00301 },
+	{ 0x000E0 , 0x00061 , 0x00300 },
+	{ 0x000E1 , 0x00061 , 0x00301 },
+	{ 0x000E2 , 0x00061 , 0x00302 },
+	{ 0x000E3 , 0x00061 , 0x00303 },
+	{ 0x000E4 , 0x00061 , 0x00308 },
+	{ 0x000E5 , 0x00061 , 0x0030A },
+	{ 0x000E7 , 0x00063 , 0x00327 },
+	{ 0x000E8 , 0x00065 , 0x00300 },
+	{ 0x000E9 , 0x00065 , 0x00301 },
+	{ 0x000EA , 0x00065 , 0x00302 },
+	{ 0x000EB , 0x00065 , 0x00308 },
+	{ 0x000EC , 0x00069 , 0x00300 },
+	{ 0x000ED , 0x00069 , 0x00301 },
+	{ 0x000EE , 0x00069 , 0x00302 },
+	{ 0x000EF , 0x00069 , 0x00308 },
+	{ 0x000F1 , 0x0006E , 0x00303 },
+	{ 0x000F2 , 0x0006F , 0x00300 },
+	{ 0x000F3 , 0x0006F , 0x00301 },
+	{ 0x000F4 , 0x0006F , 0x00302 },
+	{ 0x000F5 , 0x0006F , 0x00303 },
+	{ 0x000F6 , 0x0006F , 0x00308 },
+	{ 0x000F9 , 0x00075 , 0x00300 },
+	{ 0x000FA , 0x00075 , 0x00301 },
+	{ 0x000FB , 0x00075 , 0x00302 },
+	{ 0x000FC , 0x00075 , 0x00308 },
+	{ 0x000FD , 0x00079 , 0x00301 },
+	{ 0x000FF , 0x00079 , 0x00308 },
+	{ 0x00100 , 0x00041 , 0x00304 },
+	{ 0x00101 , 0x00061 , 0x00304 },
+	{ 0x00102 , 0x00041 , 0x00306 },
+	{ 0x00103 , 0x00061 , 0x00306 },
+	{ 0x00104 , 0x00041 , 0x00328 },
+	{ 0x00105 , 0x00061 , 0x00328 },
+	{ 0x00106 , 0x00043 , 0x00301 },
+	{ 0x00107 , 0x00063 , 0x00301 },
+	{ 0x00108 , 0x00043 , 0x00302 },
+	{ 0x00109 , 0x00063 , 0x00302 },
+	{ 0x0010A , 0x00043 , 0x00307 },
+	{ 0x0010B , 0x00063 , 0x00307 },
+	{ 0x0010C , 0x00043 , 0x0030C },
+	{ 0x0010D , 0x00063 , 0x0030C },
+	{ 0x0010E , 0x00044 , 0x0030C },
+	{ 0x0010F , 0x00064 , 0x0030C },
+	{ 0x00112 , 0x00045 , 0x00304 },
+	{ 0x00113 , 0x00065 , 0x00304 },
+	{ 0x00114 , 0x00045 , 0x00306 },
+	{ 0x00115 , 0x00065 , 0x00306 },
+	{ 0x00116 , 0x00045 , 0x00307 },
+	{ 0x00117 , 0x00065 , 0x00307 },
+	{ 0x00118 , 0x00045 , 0x00328 },
+	{ 0x00119 , 0x00065 , 0x00328 },
+	{ 0x0011A , 0x00045 , 0x0030C },
+	{ 0x0011B , 0x00065 , 0x0030C },
+	{ 0x0011C , 0x00047 , 0x00302 },
+	{ 0x0011D , 0x00067 , 0x00302 },
+	{ 0x0011E , 0x00047 , 0x00306 },
+	{ 0x0011F , 0x00067 , 0x00306 },
+	{ 0x00120 , 0x00047 , 0x00307 },
+	{ 0x00121 , 0x00067 , 0x00307 },
+	{ 0x00122 , 0x00047 , 0x00327 },
+	{ 0x00123 , 0x00067 , 0x00327 },
+	{ 0x00124 , 0x00048 , 0x00302 },
+	{ 0x00125 , 0x00068 , 0x00302 },
+	{ 0x00128 , 0x00049 , 0x00303 },
+	{ 0x00129 , 0x00069 , 0x00303 },
+	{ 0x0012A , 0x00049 , 0x00304 },
+	{ 0x0012B , 0x00069 , 0x00304 },
+	{ 0x0012C , 0x00049 , 0x00306 },
+	{ 0x0012D , 0x00069 , 0x00306 },
+	{ 0x0012E , 0x00049 , 0x00328 },
+	{ 0x0012F , 0x00069 , 0x00328 },
+	{ 0x00130 , 0x00049 , 0x00307 },
+	{ 0x00134 , 0x0004A , 0x00302 },
+	{ 0x00135 , 0x0006A , 0x00302 },
+	{ 0x00136 , 0x0004B , 0x00327 },
+	{ 0x00137 , 0x0006B , 0x00327 },
+	{ 0x00139 , 0x0004C , 0x00301 },
+	{ 0x0013A , 0x0006C , 0x00301 },
+	{ 0x0013B , 0x0004C , 0x00327 },
+	{ 0x0013C , 0x0006C , 0x00327 },
+	{ 0x0013D , 0x0004C , 0x0030C },
+	{ 0x0013E , 0x0006C , 0x0030C },
+	{ 0x00143 , 0x0004E , 0x00301 },
+	{ 0x00144 , 0x0006E , 0x00301 },
+	{ 0x00145 , 0x0004E , 0x00327 },
+	{ 0x00146 , 0x0006E , 0x00327 },
+	{ 0x00147 , 0x0004E , 0x0030C },
+	{ 0x00148 , 0x0006E , 0x0030C },
+	{ 0x0014C , 0x0004F , 0x00304 },
+	{ 0x0014D , 0x0006F , 0x00304 },
+	{ 0x0014E , 0x0004F , 0x00306 },
+	{ 0x0014F , 0x0006F , 0x00306 },
+	{ 0x00150 , 0x0004F , 0x0030B },
+	{ 0x00151 , 0x0006F , 0x0030B },
+	{ 0x00154 , 0x00052 , 0x00301 },
+	{ 0x00155 , 0x00072 , 0x00301 },
+	{ 0x00156 , 0x00052 , 0x00327 },
+	{ 0x00157 , 0x00072 , 0x00327 },
+	{ 0x00158 , 0x00052 , 0x0030C },
+	{ 0x00159 , 0x00072 , 0x0030C },
+	{ 0x0015A , 0x00053 , 0x00301 },
+	{ 0x0015B , 0x00073 , 0x00301 },
+	{ 0x0015C , 0x00053 , 0x00302 },
+	{ 0x0015D , 0x00073 , 0x00302 },
+	{ 0x0015E , 0x00053 , 0x00327 },
+	{ 0x0015F , 0x00073 , 0x00327 },
+	{ 0x00160 , 0x00053 , 0x0030C },
+	{ 0x00161 , 0x00073 , 0x0030C },
+	{ 0x00162 , 0x00054 , 0x00327 },
+	{ 0x00163 , 0x00074 , 0x00327 },
+	{ 0x00164 , 0x00054 , 0x0030C },
+	{ 0x00165 , 0x00074 , 0x0030C },
+	{ 0x00168 , 0x00055 , 0x00303 },
+	{ 0x00169 , 0x00075 , 0x00303 },
+	{ 0x0016A , 0x00055 , 0x00304 },
+	{ 0x0016B , 0x00075 , 0x00304 },
+	{ 0x0016C , 0x00055 , 0x00306 },
+	{ 0x0016D , 0x00075 , 0x00306 },
+	{ 0x0016E , 0x00055 , 0x0030A },
+	{ 0x0016F , 0x00075 , 0x0030A },
+	{ 0x00170 , 0x00055 , 0x0030B },
+	{ 0x00171 , 0x00075 , 0x0030B },
+	{ 0x00172 , 0x00055 , 0x00328 },
+	{ 0x00173 , 0x00075 , 0x00328 },
+	{ 0x00174 , 0x00057 , 0x00302 },
+	{ 0x00175 , 0x00077 , 0x00302 },
+	{ 0x00176 , 0x00059 , 0x00302 },
+	{ 0x00177 , 0x00079 , 0x00302 },
+	{ 0x00178 , 0x00059 , 0x00308 },
+	{ 0x00179 , 0x0005A , 0x00301 },
+	{ 0x0017A , 0x0007A , 0x00301 },
+	{ 0x0017B , 0x0005A , 0x00307 },
+	{ 0x0017C , 0x0007A , 0x00307 },
+	{ 0x0017D , 0x0005A , 0x0030C },
+	{ 0x0017E , 0x0007A , 0x0030C },
+	{ 0x001A0 , 0x0004F , 0x0031B },
+	{ 0x001A1 , 0x0006F , 0x0031B },
+	{ 0x001AF , 0x00055 , 0x0031B },
+	{ 0x001B0 , 0x00075 , 0x0031B },
+	{ 0x001CD , 0x00041 , 0x0030C },
+	{ 0x001CE , 0x00061 , 0x0030C },
+	{ 0x001CF , 0x00049 , 0x0030C },
+	{ 0x001D0 , 0x00069 , 0x0030C },
+	{ 0x001D1 , 0x0004F , 0x0030C },
+	{ 0x001D2 , 0x0006F , 0x0030C },
+	{ 0x001D3 , 0x00055 , 0x0030C },
+	{ 0x001D4 , 0x00075 , 0x0030C },
+	{ 0x001D5 , 0x000DC , 0x00304 },
+	{ 0x001D6 , 0x000FC , 0x00304 },
+	{ 0x001D7 , 0x000DC , 0x00301 },
+	{ 0x001D8 , 0x000FC , 0x00301 },
+	{ 0x001D9 , 0x000DC , 0x0030C },
+	{ 0x001DA , 0x000FC , 0x0030C },
+	{ 0x001DB , 0x000DC , 0x00300 },
+	{ 0x001DC , 0x000FC , 0x00300 },
+	{ 0x001DE , 0x000C4 , 0x00304 },
+	{ 0x001DF , 0x000E4 , 0x00304 },
+	{ 0x001E0 , 0x00226 , 0x00304 },
+	{ 0x001E1 , 0x00227 , 0x00304 },
+	{ 0x001E2 , 0x000C6 , 0x00304 },
+	{ 0x001E3 , 0x000E6 , 0x00304 },
+	{ 0x001E6 , 0x00047 , 0x0030C },
+	{ 0x001E7 , 0x00067 , 0x0030C },
+	{ 0x001E8 , 0x0004B , 0x0030C },
+	{ 0x001E9 , 0x0006B , 0x0030C },
+	{ 0x001EA , 0x0004F , 0x00328 },
+	{ 0x001EB , 0x0006F , 0x00328 },
+	{ 0x001EC , 0x001EA , 0x00304 },
+	{ 0x001ED , 0x001EB , 0x00304 },
+	{ 0x001EE , 0x001B7 , 0x0030C },
+	{ 0x001EF , 0x00292 , 0x0030C },
+	{ 0x001F0 , 0x0006A , 0x0030C },
+	{ 0x001F4 , 0x00047 , 0x00301 },
+	{ 0x001F5 , 0x00067 , 0x00301 },
+	{ 0x001F8 , 0x0004E , 0x00300 },
+	{ 0x001F9 , 0x0006E , 0x00300 },
+	{ 0x001FA , 0x000C5 , 0x00301 },
+	{ 0x001FB , 0x000E5 , 0x00301 },
+	{ 0x001FC , 0x000C6 , 0x00301 },
+	{ 0x001FD , 0x000E6 , 0x00301 },
+	{ 0x001FE , 0x000D8 , 0x00301 },
+	{ 0x001FF , 0x000F8 , 0x00301 },
+	{ 0x00200 , 0x00041 , 0x0030F },
+	{ 0x00201 , 0x00061 , 0x0030F },
+	{ 0x00202 , 0x00041 , 0x00311 },
+	{ 0x00203 , 0x00061 , 0x00311 },
+	{ 0x00204 , 0x00045 , 0x0030F },
+	{ 0x00205 , 0x00065 , 0x0030F },
+	{ 0x00206 , 0x00045 , 0x00311 },
+	{ 0x00207 , 0x00065 , 0x00311 },
+	{ 0x00208 , 0x00049 , 0x0030F },
+	{ 0x00209 , 0x00069 , 0x0030F },
+	{ 0x0020A , 0x00049 , 0x00311 },
+	{ 0x0020B , 0x00069 , 0x00311 },
+	{ 0x0020C , 0x0004F , 0x0030F },
+	{ 0x0020D , 0x0006F , 0x0030F },
+	{ 0x0020E , 0x0004F , 0x00311 },
+	{ 0x0020F , 0x0006F , 0x00311 },
+	{ 0x00210 , 0x00052 , 0x0030F },
+	{ 0x00211 , 0x00072 , 0x0030F },
+	{ 0x00212 , 0x00052 , 0x00311 },
+	{ 0x00213 , 0x00072 , 0x00311 },
+	{ 0x00214 , 0x00055 , 0x0030F },
+	{ 0x00215 , 0x00075 , 0x0030F },
+	{ 0x00216 , 0x00055 , 0x00311 },
+	{ 0x00217 , 0x00075 , 0x00311 },
+	{ 0x00218 , 0x00053 , 0x00326 },
+	{ 0x00219 , 0x00073 , 0x00326 },
+	{ 0x0021A , 0x00054 , 0x00326 },
+	{ 0x0021B , 0x00074 , 0x00326 },
+	{ 0x0021E , 0x00048 , 0x0030C },
+	{ 0x0021F , 0x00068 , 0x0030C },
+	{ 0x00226 , 0x00041 , 0x00307 },
+	{ 0x00227 , 0x00061 , 0x00307 },
+	{ 0x00228 , 0x00045 , 0x00327 },
+	{ 0x00229 , 0x00065 , 0x00327 },
+	{ 0x0022A , 0x000D6 , 0x00304 },
+	{ 0x0022B , 0x000F6 , 0x00304 },
+	{ 0x0022C , 0x000D5 , 0x00304 },
+	{ 0x0022D , 0x000F5 , 0x00304 },
+	{ 0x0022E , 0x0004F , 0x00307 },
+	{ 0x0022F , 0x0006F , 0x00307 },
+	{ 0x00230 , 0x0022E , 0x00304 },
+	{ 0x00231 , 0x0022F , 0x00304 },
+	{ 0x00232 , 0x00059 , 0x00304 },
+	{ 0x00233 , 0x00079 , 0x00304 },
+	{ 0x00385 , 0x000A8 , 0x00301 },
+	{ 0x00386 , 0x00391 , 0x00301 },
+	{ 0x00388 , 0x00395 , 0x00301 },
+	{ 0x00389 , 0x00397 , 0x00301 },
+	{ 0x0038A , 0x00399 , 0x00301 },
+	{ 0x0038C , 0x0039F , 0x00301 },
+	{ 0x0038E , 0x003A5 , 0x00301 },
+	{ 0x0038F , 0x003A9 , 0x00301 },
+	{ 0x00390 , 0x003CA , 0x00301 },
+	{ 0x003AA , 0x00399 , 0x00308 },
+	{ 0x003AB , 0x003A5 , 0x00308 },
+	{ 0x003AC , 0x003B1 , 0x00301 },
+	{ 0x003AD , 0x003B5 , 0x00301 },
+	{ 0x003AE , 0x003B7 , 0x00301 },
+	{ 0x003AF , 0x003B9 , 0x00301 },
+	{ 0x003B0 , 0x003CB , 0x00301 },
+	{ 0x003CA , 0x003B9 , 0x00308 },
+	{ 0x003CB , 0x003C5 , 0x00308 },
+	{ 0x003CC , 0x003BF , 0x00301 },
+	{ 0x003CD , 0x003C5 , 0x00301 },
+	{ 0x003CE , 0x003C9 , 0x00301 },
+	{ 0x003D3 , 0x003D2 , 0x00301 },
+	{ 0x003D4 , 0x003D2 , 0x00308 },
+	{ 0x00400 , 0x00415 , 0x00300 },
+	{ 0x00401 , 0x00415 , 0x00308 },
+	{ 0x00403 , 0x00413 , 0x00301 },
+	{ 0x00407 , 0x00406 , 0x00308 },
+	{ 0x0040C , 0x0041A , 0x00301 },
+	{ 0x0040D , 0x00418 , 0x00300 },
+	{ 0x0040E , 0x00423 , 0x00306 },
+	{ 0x00419 , 0x00418 , 0x00306 },
+	{ 0x00439 , 0x00438 , 0x00306 },
+	{ 0x00450 , 0x00435 , 0x00300 },
+	{ 0x00451 , 0x00435 , 0x00308 },
+	{ 0x00453 , 0x00433 , 0x00301 },
+	{ 0x00457 , 0x00456 , 0x00308 },
+	{ 0x0045C , 0x0043A , 0x00301 },
+	{ 0x0045D , 0x00438 , 0x00300 },
+	{ 0x0045E , 0x00443 , 0x00306 },
+	{ 0x00476 , 0x00474 , 0x0030F },
+	{ 0x00477 , 0x00475 , 0x0030F },
+	{ 0x004C1 , 0x00416 , 0x00306 },
+	{ 0x004C2 , 0x00436 , 0x00306 },
+	{ 0x004D0 , 0x00410 , 0x00306 },
+	{ 0x004D1 , 0x00430 , 0x00306 },
+	{ 0x004D2 , 0x00410 , 0x00308 },
+	{ 0x004D3 , 0x00430 , 0x00308 },
+	{ 0x004D6 , 0x00415 , 0x00306 },
+	{ 0x004D7 , 0x00435 , 0x00306 },
+	{ 0x004DA , 0x004D8 , 0x00308 },
+	{ 0x004DB , 0x004D9 , 0x00308 },
+	{ 0x004DC , 0x00416 , 0x00308 },
+	{ 0x004DD , 0x00436 , 0x00308 },
+	{ 0x004DE , 0x00417 , 0x00308 },
+	{ 0x004DF , 0x00437 , 0x00308 },
+	{ 0x004E2 , 0x00418 , 0x00304 },
+	{ 0x004E3 , 0x00438 , 0x00304 },
+	{ 0x004E4 , 0x00418 , 0x00308 },
+	{ 0x004E5 , 0x00438 , 0x00308 },
+	{ 0x004E6 , 0x0041E , 0x00308 },
+	{ 0x004E7 , 0x0043E , 0x00308 },
+	{ 0x004EA , 0x004E8 , 0x00308 },
+	{ 0x004EB , 0x004E9 , 0x00308 },
+	{ 0x004EC , 0x0042D , 0x00308 },
+	{ 0x004ED , 0x0044D , 0x00308 },
+	{ 0x004EE , 0x00423 , 0x00304 },
+	{ 0x004EF , 0x00443 , 0x00304 },
+	{ 0x004F0 , 0x00423 , 0x00308 },
+	{ 0x004F1 , 0x00443 , 0x00308 },
+	{ 0x004F2 , 0x00423 , 0x0030B },
+	{ 0x004F3 , 0x00443 , 0x0030B },
+	{ 0x004F4 , 0x00427 , 0x00308 },
+	{ 0x004F5 , 0x00447 , 0x00308 },
+	{ 0x004F8 , 0x0042B , 0x00308 },
+	{ 0x004F9 , 0x0044B , 0x00308 },
+	{ 0x00622 , 0x00627 , 0x00653 },
+	{ 0x00623 , 0x00627 , 0x00654 },
+	{ 0x00624 , 0x00648 , 0x00654 },
+	{ 0x00625 , 0x00627 , 0x00655 },
+	{ 0x00626 , 0x0064A , 0x00654 },
+	{ 0x006C0 , 0x006D5 , 0x00654 },
+	{ 0x006C2 , 0x006C1 , 0x00654 },
+	{ 0x006D3 , 0x006D2 , 0x00654 },
+	{ 0x00929 , 0x00928 , 0x0093C },
+	{ 0x00931 , 0x00930 , 0x0093C },
+	{ 0x00934 , 0x00933 , 0x0093C },
+	{ 0x009CB , 0x009C7 , 0x009BE },
+	{ 0x009CC , 0x009C7 , 0x009D7 },
+	{ 0x00B48 , 0x00B47 , 0x00B56 },
+	{ 0x00B4B , 0x00B47 , 0x00B3E },
+	{ 0x00B4C , 0x00B47 , 0x00B57 },
+	{ 0x00B94 , 0x00B92 , 0x00BD7 },
+	{ 0x00BCA , 0x00BC6 , 0x00BBE },
+	{ 0x00BCB , 0x00BC7 , 0x00BBE },
+	{ 0x00BCC , 0x00BC6 , 0x00BD7 },
+	{ 0x00C48 , 0x00C46 , 0x00C56 },
+	{ 0x00CC0 , 0x00CBF , 0x00CD5 },
+	{ 0x00CC7 , 0x00CC6 , 0x00CD5 },
+	{ 0x00CC8 , 0x00CC6 , 0x00CD6 },
+	{ 0x00CCA , 0x00CC6 , 0x00CC2 },
+	{ 0x00CCB , 0x00CCA , 0x00CD5 },
+	{ 0x00D4A , 0x00D46 , 0x00D3E },
+	{ 0x00D4B , 0x00D47 , 0x00D3E },
+	{ 0x00D4C , 0x00D46 , 0x00D57 },
+	{ 0x00DDA , 0x00DD9 , 0x00DCA },
+	{ 0x00DDC , 0x00DD9 , 0x00DCF },
+	{ 0x00DDD , 0x00DDC , 0x00DCA },
+	{ 0x00DDE , 0x00DD9 , 0x00DDF },
+	{ 0x01026 , 0x01025 , 0x0102E },
+	{ 0x01B06 , 0x01B05 , 0x01B35 },
+	{ 0x01B08 , 0x01B07 , 0x01B35 },
+	{ 0x01B0A , 0x01B09 , 0x01B35 },
+	{ 0x01B0C , 0x01B0B , 0x01B35 },
+	{ 0x01B0E , 0x01B0D , 0x01B35 },
+	{ 0x01B12 , 0x01B11 , 0x01B35 },
+	{ 0x01B3B , 0x01B3A , 0x01B35 },
+	{ 0x01B3D , 0x01B3C , 0x01B35 },
+	{ 0x01B40 , 0x01B3E , 0x01B35 },
+	{ 0x01B41 , 0x01B3F , 0x01B35 },
+	{ 0x01B43 , 0x01B42 , 0x01B35 },
+	{ 0x01E00 , 0x00041 , 0x00325 },
+	{ 0x01E01 , 0x00061 , 0x00325 },
+	{ 0x01E02 , 0x00042 , 0x00307 },
+	{ 0x01E03 , 0x00062 , 0x00307 },
+	{ 0x01E04 , 0x00042 , 0x00323 },
+	{ 0x01E05 , 0x00062 , 0x00323 },
+	{ 0x01E06 , 0x00042 , 0x00331 },
+	{ 0x01E07 , 0x00062 , 0x00331 },
+	{ 0x01E08 , 0x000C7 , 0x00301 },
+	{ 0x01E09 , 0x000E7 , 0x00301 },
+	{ 0x01E0A , 0x00044 , 0x00307 },
+	{ 0x01E0B , 0x00064 , 0x00307 },
+	{ 0x01E0C , 0x00044 , 0x00323 },
+	{ 0x01E0D , 0x00064 , 0x00323 },
+	{ 0x01E0E , 0x00044 , 0x00331 },
+	{ 0x01E0F , 0x00064 , 0x00331 },
+	{ 0x01E10 , 0x00044 , 0x00327 },
+	{ 0x01E11 , 0x00064 , 0x00327 },
+	{ 0x01E12 , 0x00044 , 0x0032D },
+	{ 0x01E13 , 0x00064 , 0x0032D },
+	{ 0x01E14 , 0x00112 , 0x00300 },
+	{ 0x01E15 , 0x00113 , 0x00300 },
+	{ 0x01E16 , 0x00112 , 0x00301 },
+	{ 0x01E17 , 0x00113 , 0x00301 },
+	{ 0x01E18 , 0x00045 , 0x0032D },
+	{ 0x01E19 , 0x00065 , 0x0032D },
+	{ 0x01E1A , 0x00045 , 0x00330 },
+	{ 0x01E1B , 0x00065 , 0x00330 },
+	{ 0x01E1C , 0x00228 , 0x00306 },
+	{ 0x01E1D , 0x00229 , 0x00306 },
+	{ 0x01E1E , 0x00046 , 0x00307 },
+	{ 0x01E1F , 0x00066 , 0x00307 },
+	{ 0x01E20 , 0x00047 , 0x00304 },
+	{ 0x01E21 , 0x00067 , 0x00304 },
+	{ 0x01E22 , 0x00048 , 0x00307 },
+	{ 0x01E23 , 0x00068 , 0x00307 },
+	{ 0x01E24 , 0x00048 , 0x00323 },
+	{ 0x01E25 , 0x00068 , 0x00323 },
+	{ 0x01E26 , 0x00048 , 0x00308 },
+	{ 0x01E27 , 0x00068 , 0x00308 },
+	{ 0x01E28 , 0x00048 , 0x00327 },
+	{ 0x01E29 , 0x00068 , 0x00327 },
+	{ 0x01E2A , 0x00048 , 0x0032E },
+	{ 0x01E2B , 0x00068 , 0x0032E },
+	{ 0x01E2C , 0x00049 , 0x00330 },
+	{ 0x01E2D , 0x00069 , 0x00330 },
+	{ 0x01E2E , 0x000CF , 0x00301 },
+	{ 0x01E2F , 0x000EF , 0x00301 },
+	{ 0x01E30 , 0x0004B , 0x00301 },
+	{ 0x01E31 , 0x0006B , 0x00301 },
+	{ 0x01E32 , 0x0004B , 0x00323 },
+	{ 0x01E33 , 0x0006B , 0x00323 },
+	{ 0x01E34 , 0x0004B , 0x00331 },
+	{ 0x01E35 , 0x0006B , 0x00331 },
+	{ 0x01E36 , 0x0004C , 0x00323 },
+	{ 0x01E37 , 0x0006C , 0x00323 },
+	{ 0x01E38 , 0x01E36 , 0x00304 },
+	{ 0x01E39 , 0x01E37 , 0x00304 },
+	{ 0x01E3A , 0x0004C , 0x00331 },
+	{ 0x01E3B , 0x0006C , 0x00331 },
+	{ 0x01E3C , 0x0004C , 0x0032D },
+	{ 0x01E3D , 0x0006C , 0x0032D },
+	{ 0x01E3E , 0x0004D , 0x00301 },
+	{ 0x01E3F , 0x0006D , 0x00301 },
+	{ 0x01E40 , 0x0004D , 0x00307 },
+	{ 0x01E41 , 0x0006D , 0x00307 },
+	{ 0x01E42 , 0x0004D , 0x00323 },
+	{ 0x01E43 , 0x0006D , 0x00323 },
+	{ 0x01E44 , 0x0004E , 0x00307 },
+	{ 0x01E45 , 0x0006E , 0x00307 },
+	{ 0x01E46 , 0x0004E , 0x00323 },
+	{ 0x01E47 , 0x0006E , 0x00323 },
+	{ 0x01E48 , 0x0004E , 0x00331 },
+	{ 0x01E49 , 0x0006E , 0x00331 },
+	{ 0x01E4A , 0x0004E , 0x0032D },
+	{ 0x01E4B , 0x0006E , 0x0032D },
+	{ 0x01E4C , 0x000D5 , 0x00301 },
+	{ 0x01E4D , 0x000F5 , 0x00301 },
+	{ 0x01E4E , 0x000D5 , 0x00308 },
+	{ 0x01E4F , 0x000F5 , 0x00308 },
+	{ 0x01E50 , 0x0014C , 0x00300 },
+	{ 0x01E51 , 0x0014D , 0x00300 },
+	{ 0x01E52 , 0x0014C , 0x00301 },
+	{ 0x01E53 , 0x0014D , 0x00301 },
+	{ 0x01E54 , 0x00050 , 0x00301 },
+	{ 0x01E55 , 0x00070 , 0x00301 },
+	{ 0x01E56 , 0x00050 , 0x00307 },
+	{ 0x01E57 , 0x00070 , 0x00307 },
+	{ 0x01E58 , 0x00052 , 0x00307 },
+	{ 0x01E59 , 0x00072 , 0x00307 },
+	{ 0x01E5A , 0x00052 , 0x00323 },
+	{ 0x01E5B , 0x00072 , 0x00323 },
+	{ 0x01E5C , 0x01E5A , 0x00304 },
+	{ 0x01E5D , 0x01E5B , 0x00304 },
+	{ 0x01E5E , 0x00052 , 0x00331 },
+	{ 0x01E5F , 0x00072 , 0x00331 },
+	{ 0x01E60 , 0x00053 , 0x00307 },
+	{ 0x01E61 , 0x00073 , 0x00307 },
+	{ 0x01E62 , 0x00053 , 0x00323 },
+	{ 0x01E63 , 0x00073 , 0x00323 },
+	{ 0x01E64 , 0x0015A , 0x00307 },
+	{ 0x01E65 , 0x0015B , 0x00307 },
+	{ 0x01E66 , 0x00160 , 0x00307 },
+	{ 0x01E67 , 0x00161 , 0x00307 },
+	{ 0x01E68 , 0x01E62 , 0x00307 },
+	{ 0x01E69 , 0x01E63 , 0x00307 },
+	{ 0x01E6A , 0x00054 , 0x00307 },
+	{ 0x01E6B , 0x00074 , 0x00307 },
+	{ 0x01E6C , 0x00054 , 0x00323 },
+	{ 0x01E6D , 0x00074 , 0x00323 },
+	{ 0x01E6E , 0x00054 , 0x00331 },
+	{ 0x01E6F , 0x00074 , 0x00331 },
+	{ 0x01E70 , 0x00054 , 0x0032D },
+	{ 0x01E71 , 0x00074 , 0x0032D },
+	{ 0x01E72 , 0x00055 , 0x00324 },
+	{ 0x01E73 , 0x00075 , 0x00324 },
+	{ 0x01E74 , 0x00055 , 0x00330 },
+	{ 0x01E75 , 0x00075 , 0x00330 },
+	{ 0x01E76 , 0x00055 , 0x0032D },
+	{ 0x01E77 , 0x00075 , 0x0032D },
+	{ 0x01E78 , 0x00168 , 0x00301 },
+	{ 0x01E79 , 0x00169 , 0x00301 },
+	{ 0x01E7A , 0x0016A , 0x00308 },
+	{ 0x01E7B , 0x0016B , 0x00308 },
+	{ 0x01E7C , 0x00056 , 0x00303 },
+	{ 0x01E7D , 0x00076 , 0x00303 },
+	{ 0x01E7E , 0x00056 , 0x00323 },
+	{ 0x01E7F , 0x00076 , 0x00323 },
+	{ 0x01E80 , 0x00057 , 0x00300 },
+	{ 0x01E81 , 0x00077 , 0x00300 },
+	{ 0x01E82 , 0x00057 , 0x00301 },
+	{ 0x01E83 , 0x00077 , 0x00301 },
+	{ 0x01E84 , 0x00057 , 0x00308 },
+	{ 0x01E85 , 0x00077 , 0x00308 },
+	{ 0x01E86 , 0x00057 , 0x00307 },
+	{ 0x01E87 , 0x00077 , 0x00307 },
+	{ 0x01E88 , 0x00057 , 0x00323 },
+	{ 0x01E89 , 0x00077 , 0x00323 },
+	{ 0x01E8A , 0x00058 , 0x00307 },
+	{ 0x01E8B , 0x00078 , 0x00307 },
+	{ 0x01E8C , 0x00058 , 0x00308 },
+	{ 0x01E8D , 0x00078 , 0x00308 },
+	{ 0x01E8E , 0x00059 , 0x00307 },
+	{ 0x01E8F , 0x00079 , 0x00307 },
+	{ 0x01E90 , 0x0005A , 0x00302 },
+	{ 0x01E91 , 0x0007A , 0x00302 },
+	{ 0x01E92 , 0x0005A , 0x00323 },
+	{ 0x01E93 , 0x0007A , 0x00323 },
+	{ 0x01E94 , 0x0005A , 0x00331 },
+	{ 0x01E95 , 0x0007A , 0x00331 },
+	{ 0x01E96 , 0x00068 , 0x00331 },
+	{ 0x01E97 , 0x00074 , 0x00308 },
+	{ 0x01E98 , 0x00077 , 0x0030A },
+	{ 0x01E99 , 0x00079 , 0x0030A },
+	{ 0x01E9B , 0x0017F , 0x00307 },
+	{ 0x01EA0 , 0x00041 , 0x00323 },
+	{ 0x01EA1 , 0x00061 , 0x00323 },
+	{ 0x01EA2 , 0x00041 , 0x00309 },
+	{ 0x01EA3 , 0x00061 , 0x00309 },
+	{ 0x01EA4 , 0x000C2 , 0x00301 },
+	{ 0x01EA5 , 0x000E2 , 0x00301 },
+	{ 0x01EA6 , 0x000C2 , 0x00300 },
+	{ 0x01EA7 , 0x000E2 , 0x00300 },
+	{ 0x01EA8 , 0x000C2 , 0x00309 },
+	{ 0x01EA9 , 0x000E2 , 0x00309 },
+	{ 0x01EAA , 0x000C2 , 0x00303 },
+	{ 0x01EAB , 0x000E2 , 0x00303 },
+	{ 0x01EAC , 0x01EA0 , 0x00302 },
+	{ 0x01EAD , 0x01EA1 , 0x00302 },
+	{ 0x01EAE , 0x00102 , 0x00301 },
+	{ 0x01EAF , 0x00103 , 0x00301 },
+	{ 0x01EB0 , 0x00102 , 0x00300 },
+	{ 0x01EB1 , 0x00103 , 0x00300 },
+	{ 0x01EB2 , 0x00102 , 0x00309 },
+	{ 0x01EB3 , 0x00103 , 0x00309 },
+	{ 0x01EB4 , 0x00102 , 0x00303 },
+	{ 0x01EB5 , 0x00103 , 0x00303 },
+	{ 0x01EB6 , 0x01EA0 , 0x00306 },
+	{ 0x01EB7 , 0x01EA1 , 0x00306 },
+	{ 0x01EB8 , 0x00045 , 0x00323 },
+	{ 0x01EB9 , 0x00065 , 0x00323 },
+	{ 0x01EBA , 0x00045 , 0x00309 },
+	{ 0x01EBB , 0x00065 , 0x00309 },
+	{ 0x01EBC , 0x00045 , 0x00303 },
+	{ 0x01EBD , 0x00065 , 0x00303 },
+	{ 0x01EBE , 0x000CA , 0x00301 },
+	{ 0x01EBF , 0x000EA , 0x00301 },
+	{ 0x01EC0 , 0x000CA , 0x00300 },
+	{ 0x01EC1 , 0x000EA , 0x00300 },
+	{ 0x01EC2 , 0x000CA , 0x00309 },
+	{ 0x01EC3 , 0x000EA , 0x00309 },
+	{ 0x01EC4 , 0x000CA , 0x00303 },
+	{ 0x01EC5 , 0x000EA , 0x00303 },
+	{ 0x01EC6 , 0x01EB8 , 0x00302 },
+	{ 0x01EC7 , 0x01EB9 , 0x00302 },
+	{ 0x01EC8 , 0x00049 , 0x00309 },
+	{ 0x01EC9 , 0x00069 , 0x00309 },
+	{ 0x01ECA , 0x00049 , 0x00323 },
+	{ 0x01ECB , 0x00069 , 0x00323 },
+	{ 0x01ECC , 0x0004F , 0x00323 },
+	{ 0x01ECD , 0x0006F , 0x00323 },
+	{ 0x01ECE , 0x0004F , 0x00309 },
+	{ 0x01ECF , 0x0006F , 0x00309 },
+	{ 0x01ED0 , 0x000D4 , 0x00301 },
+	{ 0x01ED1 , 0x000F4 , 0x00301 },
+	{ 0x01ED2 , 0x000D4 , 0x00300 },
+	{ 0x01ED3 , 0x000F4 , 0x00300 },
+	{ 0x01ED4 , 0x000D4 , 0x00309 },
+	{ 0x01ED5 , 0x000F4 , 0x00309 },
+	{ 0x01ED6 , 0x000D4 , 0x00303 },
+	{ 0x01ED7 , 0x000F4 , 0x00303 },
+	{ 0x01ED8 , 0x01ECC , 0x00302 },
+	{ 0x01ED9 , 0x01ECD , 0x00302 },
+	{ 0x01EDA , 0x001A0 , 0x00301 },
+	{ 0x01EDB , 0x001A1 , 0x00301 },
+	{ 0x01EDC , 0x001A0 , 0x00300 },
+	{ 0x01EDD , 0x001A1 , 0x00300 },
+	{ 0x01EDE , 0x001A0 , 0x00309 },
+	{ 0x01EDF , 0x001A1 , 0x00309 },
+	{ 0x01EE0 , 0x001A0 , 0x00303 },
+	{ 0x01EE1 , 0x001A1 , 0x00303 },
+	{ 0x01EE2 , 0x001A0 , 0x00323 },
+	{ 0x01EE3 , 0x001A1 , 0x00323 },
+	{ 0x01EE4 , 0x00055 , 0x00323 },
+	{ 0x01EE5 , 0x00075 , 0x00323 },
+	{ 0x01EE6 , 0x00055 , 0x00309 },
+	{ 0x01EE7 , 0x00075 , 0x00309 },
+	{ 0x01EE8 , 0x001AF , 0x00301 },
+	{ 0x01EE9 , 0x001B0 , 0x00301 },
+	{ 0x01EEA , 0x001AF , 0x00300 },
+	{ 0x01EEB , 0x001B0 , 0x00300 },
+	{ 0x01EEC , 0x001AF , 0x00309 },
+	{ 0x01EED , 0x001B0 , 0x00309 },
+	{ 0x01EEE , 0x001AF , 0x00303 },
+	{ 0x01EEF , 0x001B0 , 0x00303 },
+	{ 0x01EF0 , 0x001AF , 0x00323 },
+	{ 0x01EF1 , 0x001B0 , 0x00323 },
+	{ 0x01EF2 , 0x00059 , 0x00300 },
+	{ 0x01EF3 , 0x00079 , 0x00300 },
+	{ 0x01EF4 , 0x00059 , 0x00323 },
+	{ 0x01EF5 , 0x00079 , 0x00323 },
+	{ 0x01EF6 , 0x00059 , 0x00309 },
+	{ 0x01EF7 , 0x00079 , 0x00309 },
+	{ 0x01EF8 , 0x00059 , 0x00303 },
+	{ 0x01EF9 , 0x00079 , 0x00303 },
+	{ 0x01F00 , 0x003B1 , 0x00313 },
+	{ 0x01F01 , 0x003B1 , 0x00314 },
+	{ 0x01F02 , 0x01F00 , 0x00300 },
+	{ 0x01F03 , 0x01F01 , 0x00300 },
+	{ 0x01F04 , 0x01F00 , 0x00301 },
+	{ 0x01F05 , 0x01F01 , 0x00301 },
+	{ 0x01F06 , 0x01F00 , 0x00342 },
+	{ 0x01F07 , 0x01F01 , 0x00342 },
+	{ 0x01F08 , 0x00391 , 0x00313 },
+	{ 0x01F09 , 0x00391 , 0x00314 },
+	{ 0x01F0A , 0x01F08 , 0x00300 },
+	{ 0x01F0B , 0x01F09 , 0x00300 },
+	{ 0x01F0C , 0x01F08 , 0x00301 },
+	{ 0x01F0D , 0x01F09 , 0x00301 },
+	{ 0x01F0E , 0x01F08 , 0x00342 },
+	{ 0x01F0F , 0x01F09 , 0x00342 },
+	{ 0x01F10 , 0x003B5 , 0x00313 },
+	{ 0x01F11 , 0x003B5 , 0x00314 },
+	{ 0x01F12 , 0x01F10 , 0x00300 },
+	{ 0x01F13 , 0x01F11 , 0x00300 },
+	{ 0x01F14 , 0x01F10 , 0x00301 },
+	{ 0x01F15 , 0x01F11 , 0x00301 },
+	{ 0x01F18 , 0x00395 , 0x00313 },
+	{ 0x01F19 , 0x00395 , 0x00314 },
+	{ 0x01F1A , 0x01F18 , 0x00300 },
+	{ 0x01F1B , 0x01F19 , 0x00300 },
+	{ 0x01F1C , 0x01F18 , 0x00301 },
+	{ 0x01F1D , 0x01F19 , 0x00301 },
+	{ 0x01F20 , 0x003B7 , 0x00313 },
+	{ 0x01F21 , 0x003B7 , 0x00314 },
+	{ 0x01F22 , 0x01F20 , 0x00300 },
+	{ 0x01F23 , 0x01F21 , 0x00300 },
+	{ 0x01F24 , 0x01F20 , 0x00301 },
+	{ 0x01F25 , 0x01F21 , 0x00301 },
+	{ 0x01F26 , 0x01F20 , 0x00342 },
+	{ 0x01F27 , 0x01F21 , 0x00342 },
+	{ 0x01F28 , 0x00397 , 0x00313 },
+	{ 0x01F29 , 0x00397 , 0x00314 },
+	{ 0x01F2A , 0x01F28 , 0x00300 },
+	{ 0x01F2B , 0x01F29 , 0x00300 },
+	{ 0x01F2C , 0x01F28 , 0x00301 },
+	{ 0x01F2D , 0x01F29 , 0x00301 },
+	{ 0x01F2E , 0x01F28 , 0x00342 },
+	{ 0x01F2F , 0x01F29 , 0x00342 },
+	{ 0x01F30 , 0x003B9 , 0x00313 },
+	{ 0x01F31 , 0x003B9 , 0x00314 },
+	{ 0x01F32 , 0x01F30 , 0x00300 },
+	{ 0x01F33 , 0x01F31 , 0x00300 },
+	{ 0x01F34 , 0x01F30 , 0x00301 },
+	{ 0x01F35 , 0x01F31 , 0x00301 },
+	{ 0x01F36 , 0x01F30 , 0x00342 },
+	{ 0x01F37 , 0x01F31 , 0x00342 },
+	{ 0x01F38 , 0x00399 , 0x00313 },
+	{ 0x01F39 , 0x00399 , 0x00314 },
+	{ 0x01F3A , 0x01F38 , 0x00300 },
+	{ 0x01F3B , 0x01F39 , 0x00300 },
+	{ 0x01F3C , 0x01F38 , 0x00301 },
+	{ 0x01F3D , 0x01F39 , 0x00301 },
+	{ 0x01F3E , 0x01F38 , 0x00342 },
+	{ 0x01F3F , 0x01F39 , 0x00342 },
+	{ 0x01F40 , 0x003BF , 0x00313 },
+	{ 0x01F41 , 0x003BF , 0x00314 },
+	{ 0x01F42 , 0x01F40 , 0x00300 },
+	{ 0x01F43 , 0x01F41 , 0x00300 },
+	{ 0x01F44 , 0x01F40 , 0x00301 },
+	{ 0x01F45 , 0x01F41 , 0x00301 },
+	{ 0x01F48 , 0x0039F , 0x00313 },
+	{ 0x01F49 , 0x0039F , 0x00314 },
+	{ 0x01F4A , 0x01F48 , 0x00300 },
+	{ 0x01F4B , 0x01F49 , 0x00300 },
+	{ 0x01F4C , 0x01F48 , 0x00301 },
+	{ 0x01F4D , 0x01F49 , 0x00301 },
+	{ 0x01F50 , 0x003C5 , 0x00313 },
+	{ 0x01F51 , 0x003C5 , 0x00314 },
+	{ 0x01F52 , 0x01F50 , 0x00300 },
+	{ 0x01F53 , 0x01F51 , 0x00300 },
+	{ 0x01F54 , 0x01F50 , 0x00301 },
+	{ 0x01F55 , 0x01F51 , 0x00301 },
+	{ 0x01F56 , 0x01F50 , 0x00342 },
+	{ 0x01F57 , 0x01F51 , 0x00342 },
+	{ 0x01F59 , 0x003A5 , 0x00314 },
+	{ 0x01F5B , 0x01F59 , 0x00300 },
+	{ 0x01F5D , 0x01F59 , 0x00301 },
+	{ 0x01F5F , 0x01F59 , 0x00342 },
+	{ 0x01F60 , 0x003C9 , 0x00313 },
+	{ 0x01F61 , 0x003C9 , 0x00314 },
+	{ 0x01F62 , 0x01F60 , 0x00300 },
+	{ 0x01F63 , 0x01F61 , 0x00300 },
+	{ 0x01F64 , 0x01F60 , 0x00301 },
+	{ 0x01F65 , 0x01F61 , 0x00301 },
+	{ 0x01F66 , 0x01F60 , 0x00342 },
+	{ 0x01F67 , 0x01F61 , 0x00342 },
+	{ 0x01F68 , 0x003A9 , 0x00313 },
+	{ 0x01F69 , 0x003A9 , 0x00314 },
+	{ 0x01F6A , 0x01F68 , 0x00300 },
+	{ 0x01F6B , 0x01F69 , 0x00300 },
+	{ 0x01F6C , 0x01F68 , 0x00301 },
+	{ 0x01F6D , 0x01F69 , 0x00301 },
+	{ 0x01F6E , 0x01F68 , 0x00342 },
+	{ 0x01F6F , 0x01F69 , 0x00342 },
+	{ 0x01F70 , 0x003B1 , 0x00300 },
+	{ 0x01F72 , 0x003B5 , 0x00300 },
+	{ 0x01F74 , 0x003B7 , 0x00300 },
+	{ 0x01F76 , 0x003B9 , 0x00300 },
+	{ 0x01F78 , 0x003BF , 0x00300 },
+	{ 0x01F7A , 0x003C5 , 0x00300 },
+	{ 0x01F7C , 0x003C9 , 0x00300 },
+	{ 0x01F80 , 0x01F00 , 0x00345 },
+	{ 0x01F81 , 0x01F01 , 0x00345 },
+	{ 0x01F82 , 0x01F02 , 0x00345 },
+	{ 0x01F83 , 0x01F03 , 0x00345 },
+	{ 0x01F84 , 0x01F04 , 0x00345 },
+	{ 0x01F85 , 0x01F05 , 0x00345 },
+	{ 0x01F86 , 0x01F06 , 0x00345 },
+	{ 0x01F87 , 0x01F07 , 0x00345 },
+	{ 0x01F88 , 0x01F08 , 0x00345 },
+	{ 0x01F89 , 0x01F09 , 0x00345 },
+	{ 0x01F8A , 0x01F0A , 0x00345 },
+	{ 0x01F8B , 0x01F0B , 0x00345 },
+	{ 0x01F8C , 0x01F0C , 0x00345 },
+	{ 0x01F8D , 0x01F0D , 0x00345 },
+	{ 0x01F8E , 0x01F0E , 0x00345 },
+	{ 0x01F8F , 0x01F0F , 0x00345 },
+	{ 0x01F90 , 0x01F20 , 0x00345 },
+	{ 0x01F91 , 0x01F21 , 0x00345 },
+	{ 0x01F92 , 0x01F22 , 0x00345 },
+	{ 0x01F93 , 0x01F23 , 0x00345 },
+	{ 0x01F94 , 0x01F24 , 0x00345 },
+	{ 0x01F95 , 0x01F25 , 0x00345 },
+	{ 0x01F96 , 0x01F26 , 0x00345 },
+	{ 0x01F97 , 0x01F27 , 0x00345 },
+	{ 0x01F98 , 0x01F28 , 0x00345 },
+	{ 0x01F99 , 0x01F29 , 0x00345 },
+	{ 0x01F9A , 0x01F2A , 0x00345 },
+	{ 0x01F9B , 0x01F2B , 0x00345 },
+	{ 0x01F9C , 0x01F2C , 0x00345 },
+	{ 0x01F9D , 0x01F2D , 0x00345 },
+	{ 0x01F9E , 0x01F2E , 0x00345 },
+	{ 0x01F9F , 0x01F2F , 0x00345 },
+	{ 0x01FA0 , 0x01F60 , 0x00345 },
+	{ 0x01FA1 , 0x01F61 , 0x00345 },
+	{ 0x01FA2 , 0x01F62 , 0x00345 },
+	{ 0x01FA3 , 0x01F63 , 0x00345 },
+	{ 0x01FA4 , 0x01F64 , 0x00345 },
+	{ 0x01FA5 , 0x01F65 , 0x00345 },
+	{ 0x01FA6 , 0x01F66 , 0x00345 },
+	{ 0x01FA7 , 0x01F67 , 0x00345 },
+	{ 0x01FA8 , 0x01F68 , 0x00345 },
+	{ 0x01FA9 , 0x01F69 , 0x00345 },
+	{ 0x01FAA , 0x01F6A , 0x00345 },
+	{ 0x01FAB , 0x01F6B , 0x00345 },
+	{ 0x01FAC , 0x01F6C , 0x00345 },
+	{ 0x01FAD , 0x01F6D , 0x00345 },
+	{ 0x01FAE , 0x01F6E , 0x00345 },
+	{ 0x01FAF , 0x01F6F , 0x00345 },
+	{ 0x01FB0 , 0x003B1 , 0x00306 },
+	{ 0x01FB1 , 0x003B1 , 0x00304 },
+	{ 0x01FB2 , 0x01F70 , 0x00345 },
+	{ 0x01FB3 , 0x003B1 , 0x00345 },
+	{ 0x01FB4 , 0x003AC , 0x00345 },
+	{ 0x01FB6 , 0x003B1 , 0x00342 },
+	{ 0x01FB7 , 0x01FB6 , 0x00345 },
+	{ 0x01FB8 , 0x00391 , 0x00306 },
+	{ 0x01FB9 , 0x00391 , 0x00304 },
+	{ 0x01FBA , 0x00391 , 0x00300 },
+	{ 0x01FBC , 0x00391 , 0x00345 },
+	{ 0x01FC1 , 0x000A8 , 0x00342 },
+	{ 0x01FC2 , 0x01F74 , 0x00345 },
+	{ 0x01FC3 , 0x003B7 , 0x00345 },
+	{ 0x01FC4 , 0x003AE , 0x00345 },
+	{ 0x01FC6 , 0x003B7 , 0x00342 },
+	{ 0x01FC7 , 0x01FC6 , 0x00345 },
+	{ 0x01FC8 , 0x00395 , 0x00300 },
+	{ 0x01FCA , 0x00397 , 0x00300 },
+	{ 0x01FCC , 0x00397 , 0x00345 },
+	{ 0x01FCD , 0x01FBF , 0x00300 },
+	{ 0x01FCE , 0x01FBF , 0x00301 },
+	{ 0x01FCF , 0x01FBF , 0x00342 },
+	{ 0x01FD0 , 0x003B9 , 0x00306 },
+	{ 0x01FD1 , 0x003B9 , 0x00304 },
+	{ 0x01FD2 , 0x003CA , 0x00300 },
+	{ 0x01FD6 , 0x003B9 , 0x00342 },
+	{ 0x01FD7 , 0x003CA , 0x00342 },
+	{ 0x01FD8 , 0x00399 , 0x00306 },
+	{ 0x01FD9 , 0x00399 , 0x00304 },
+	{ 0x01FDA , 0x00399 , 0x00300 },
+	{ 0x01FDD , 0x01FFE , 0x00300 },
+	{ 0x01FDE , 0x01FFE , 0x00301 },
+	{ 0x01FDF , 0x01FFE , 0x00342 },
+	{ 0x01FE0 , 0x003C5 , 0x00306 },
+	{ 0x01FE1 , 0x003C5 , 0x00304 },
+	{ 0x01FE2 , 0x003CB , 0x00300 },
+	{ 0x01FE4 , 0x003C1 , 0x00313 },
+	{ 0x01FE5 , 0x003C1 , 0x00314 },
+	{ 0x01FE6 , 0x003C5 , 0x00342 },
+	{ 0x01FE7 , 0x003CB , 0x00342 },
+	{ 0x01FE8 , 0x003A5 , 0x00306 },
+	{ 0x01FE9 , 0x003A5 , 0x00304 },
+	{ 0x01FEA , 0x003A5 , 0x00300 },
+	{ 0x01FEC , 0x003A1 , 0x00314 },
+	{ 0x01FED , 0x000A8 , 0x00300 },
+	{ 0x01FF2 , 0x01F7C , 0x00345 },
+	{ 0x01FF3 , 0x003C9 , 0x00345 },
+	{ 0x01FF4 , 0x003CE , 0x00345 },
+	{ 0x01FF6 , 0x003C9 , 0x00342 },
+	{ 0x01FF7 , 0x01FF6 , 0x00345 },
+	{ 0x01FF8 , 0x0039F , 0x00300 },
+	{ 0x01FFA , 0x003A9 , 0x00300 },
+	{ 0x01FFC , 0x003A9 , 0x00345 },
+	{ 0x0219A , 0x02190 , 0x00338 },
+	{ 0x0219B , 0x02192 , 0x00338 },
+	{ 0x021AE , 0x02194 , 0x00338 },
+	{ 0x021CD , 0x021D0 , 0x00338 },
+	{ 0x021CE , 0x021D4 , 0x00338 },
+	{ 0x021CF , 0x021D2 , 0x00338 },
+	{ 0x02204 , 0x02203 , 0x00338 },
+	{ 0x02209 , 0x02208 , 0x00338 },
+	{ 0x0220C , 0x0220B , 0x00338 },
+	{ 0x02224 , 0x02223 , 0x00338 },
+	{ 0x02226 , 0x02225 , 0x00338 },
+	{ 0x02241 , 0x0223C , 0x00338 },
+	{ 0x02244 , 0x02243 , 0x00338 },
+	{ 0x02247 , 0x02245 , 0x00338 },
+	{ 0x02249 , 0x02248 , 0x00338 },
+	{ 0x02260 , 0x0003D , 0x00338 },
+	{ 0x02262 , 0x02261 , 0x00338 },
+	{ 0x0226D , 0x0224D , 0x00338 },
+	{ 0x0226E , 0x0003C , 0x00338 },
+	{ 0x0226F , 0x0003E , 0x00338 },
+	{ 0x02270 , 0x02264 , 0x00338 },
+	{ 0x02271 , 0x02265 , 0x00338 },
+	{ 0x02274 , 0x02272 , 0x00338 },
+	{ 0x02275 , 0x02273 , 0x00338 },
+	{ 0x02278 , 0x02276 , 0x00338 },
+	{ 0x02279 , 0x02277 , 0x00338 },
+	{ 0x02280 , 0x0227A , 0x00338 },
+	{ 0x02281 , 0x0227B , 0x00338 },
+	{ 0x02284 , 0x02282 , 0x00338 },
+	{ 0x02285 , 0x02283 , 0x00338 },
+	{ 0x02288 , 0x02286 , 0x00338 },
+	{ 0x02289 , 0x02287 , 0x00338 },
+	{ 0x022AC , 0x022A2 , 0x00338 },
+	{ 0x022AD , 0x022A8 , 0x00338 },
+	{ 0x022AE , 0x022A9 , 0x00338 },
+	{ 0x022AF , 0x022AB , 0x00338 },
+	{ 0x022E0 , 0x0227C , 0x00338 },
+	{ 0x022E1 , 0x0227D , 0x00338 },
+	{ 0x022E2 , 0x02291 , 0x00338 },
+	{ 0x022E3 , 0x02292 , 0x00338 },
+	{ 0x022EA , 0x022B2 , 0x00338 },
+	{ 0x022EB , 0x022B3 , 0x00338 },
+	{ 0x022EC , 0x022B4 , 0x00338 },
+	{ 0x022ED , 0x022B5 , 0x00338 },
+	{ 0x0304C , 0x0304B , 0x03099 },
+	{ 0x0304E , 0x0304D , 0x03099 },
+	{ 0x03050 , 0x0304F , 0x03099 },
+	{ 0x03052 , 0x03051 , 0x03099 },
+	{ 0x03054 , 0x03053 , 0x03099 },
+	{ 0x03056 , 0x03055 , 0x03099 },
+	{ 0x03058 , 0x03057 , 0x03099 },
+	{ 0x0305A , 0x03059 , 0x03099 },
+	{ 0x0305C , 0x0305B , 0x03099 },
+	{ 0x0305E , 0x0305D , 0x03099 },
+	{ 0x03060 , 0x0305F , 0x03099 },
+	{ 0x03062 , 0x03061 , 0x03099 },
+	{ 0x03065 , 0x03064 , 0x03099 },
+	{ 0x03067 , 0x03066 , 0x03099 },
+	{ 0x03069 , 0x03068 , 0x03099 },
+	{ 0x03070 , 0x0306F , 0x03099 },
+	{ 0x03071 , 0x0306F , 0x0309A },
+	{ 0x03073 , 0x03072 , 0x03099 },
+	{ 0x03074 , 0x03072 , 0x0309A },
+	{ 0x03076 , 0x03075 , 0x03099 },
+	{ 0x03077 , 0x03075 , 0x0309A },
+	{ 0x03079 , 0x03078 , 0x03099 },
+	{ 0x0307A , 0x03078 , 0x0309A },
+	{ 0x0307C , 0x0307B , 0x03099 },
+	{ 0x0307D , 0x0307B , 0x0309A },
+	{ 0x03094 , 0x03046 , 0x03099 },
+	{ 0x0309E , 0x0309D , 0x03099 },
+	{ 0x030AC , 0x030AB , 0x03099 },
+	{ 0x030AE , 0x030AD , 0x03099 },
+	{ 0x030B0 , 0x030AF , 0x03099 },
+	{ 0x030B2 , 0x030B1 , 0x03099 },
+	{ 0x030B4 , 0x030B3 , 0x03099 },
+	{ 0x030B6 , 0x030B5 , 0x03099 },
+	{ 0x030B8 , 0x030B7 , 0x03099 },
+	{ 0x030BA , 0x030B9 , 0x03099 },
+	{ 0x030BC , 0x030BB , 0x03099 },
+	{ 0x030BE , 0x030BD , 0x03099 },
+	{ 0x030C0 , 0x030BF , 0x03099 },
+	{ 0x030C2 , 0x030C1 , 0x03099 },
+	{ 0x030C5 , 0x030C4 , 0x03099 },
+	{ 0x030C7 , 0x030C6 , 0x03099 },
+	{ 0x030C9 , 0x030C8 , 0x03099 },
+	{ 0x030D0 , 0x030CF , 0x03099 },
+	{ 0x030D1 , 0x030CF , 0x0309A },
+	{ 0x030D3 , 0x030D2 , 0x03099 },
+	{ 0x030D4 , 0x030D2 , 0x0309A },
+	{ 0x030D6 , 0x030D5 , 0x03099 },
+	{ 0x030D7 , 0x030D5 , 0x0309A },
+	{ 0x030D9 , 0x030D8 , 0x03099 },
+	{ 0x030DA , 0x030D8 , 0x0309A },
+	{ 0x030DC , 0x030DB , 0x03099 },
+	{ 0x030DD , 0x030DB , 0x0309A },
+	{ 0x030F4 , 0x030A6 , 0x03099 },
+	{ 0x030F7 , 0x030EF , 0x03099 },
+	{ 0x030F8 , 0x030F0 , 0x03099 },
+	{ 0x030F9 , 0x030F1 , 0x03099 },
+	{ 0x030FA , 0x030F2 , 0x03099 },
+	{ 0x030FE , 0x030FD , 0x03099 },
+	{ 0x1109A , 0x11099 , 0x110BA },
+	{ 0x1109C , 0x1109B , 0x110BA },
+	{ 0x110AB , 0x110A5 , 0x110BA },
+};
+
 #endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */
+
diff --git a/libarchive/archive_string_sprintf.c b/libarchive/archive_string_sprintf.c
index 7d7d971..964ea2b 100644
--- a/libarchive/archive_string_sprintf.c
+++ b/libarchive/archive_string_sprintf.c
@@ -38,7 +38,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_string_sprintf.c 189435 2009-03-
  * here.  This is only used to format error messages, so doesn't
  * require any floating-point support or field-width handling.
  */
-
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
 #include <stdio.h>
 
 #include "archive_string.h"
@@ -129,7 +131,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
 			break;
 		case 'c':
 			s = va_arg(ap, int);
-			archive_strappend_char(as, s);
+			archive_strappend_char(as, (char)s);
 			break;
 		case 'd':
 			switch(long_flag) {
@@ -146,7 +148,9 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
 				pw = va_arg(ap, wchar_t *);
 				if (pw == NULL)
 					pw = L"(null)";
-				archive_string_append_from_wcs(as, pw, wcslen(pw));
+				if (archive_string_append_from_wcs(as, pw,
+				    wcslen(pw)) != 0 && errno == ENOMEM)
+					__archive_errx(1, "Out of memory");
 				break;
 			default:
 				p2 = va_arg(ap, char *);
@@ -160,7 +164,9 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
 			pw = va_arg(ap, wchar_t *);
 			if (pw == NULL)
 				pw = L"(null)";
-			archive_string_append_from_wcs(as, pw, wcslen(pw));
+			if (archive_string_append_from_wcs(as, pw,
+			    wcslen(pw)) != 0 && errno == ENOMEM)
+				__archive_errx(1, "Out of memory");
 			break;
 		case 'o': case 'u': case 'x': case 'X':
 			/* Common handling for unsigned integer formats. */
diff --git a/libarchive/archive_util.3 b/libarchive/archive_util.3
index cd05d03..99ab842 100644
--- a/libarchive/archive_util.3
+++ b/libarchive/archive_util.3
@@ -22,9 +22,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/lib/libarchive/archive_util.3 201098 2009-12-28 02:58:14Z kientzle $
+.\" $FreeBSD$
 .\"
-.Dd January 8, 2005
+.Dd February 2, 2012
 .Dt ARCHIVE_UTIL 3
 .Os
 .Sh NAME
@@ -43,6 +43,8 @@
 .Nm archive_position ,
 .Nm archive_set_error
 .Nd libarchive utility functions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft void
diff --git a/libarchive/archive_util.c b/libarchive/archive_util.c
index e0852a3..34d8081 100644
--- a/libarchive/archive_util.c
+++ b/libarchive/archive_util.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2009,2010 Michihiro NAKAJIMA
+ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
  * Copyright (c) 2003-2007 Tim Kientzle
  * All rights reserved.
  *
@@ -50,6 +50,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1
 #include "archive_private.h"
 #include "archive_string.h"
 
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
+
 /* Generic initialization of 'struct archive' objects. */
 int
 __archive_clean(struct archive *a)
@@ -239,12 +243,13 @@ __archive_mktemp(const char *tmpdir)
 			errno = ENOMEM;
 			goto exit_tmpfile;
 		}
-		GetTempPathW(l, tmp);
+		GetTempPathW((DWORD)l, tmp);
 		archive_wstrcpy(&temp_name, tmp);
 		free(tmp);
 	} else {
-		archive_wstring_append_from_mbs(&temp_name, tmpdir,
-		    strlen(tmpdir));
+		if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
+		    strlen(tmpdir)) < 0)
+			goto exit_tmpfile;
 		if (temp_name.s[temp_name.length-1] != L'/')
 			archive_wstrappend_wchar(&temp_name, L'/');
 	}
@@ -292,7 +297,8 @@ __archive_mktemp(const char *tmpdir)
 
 		/* Generate a random file name through CryptGenRandom(). */
 		p = xp;
-		if (!CryptGenRandom(hProv, (ep - p)*sizeof(wchar_t), (BYTE*)p)) {
+		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
+		    (BYTE*)p)) {
 			la_dosmaperr(GetLastError());
 			goto exit_tmpfile;
 		}
@@ -384,6 +390,7 @@ __archive_mktemp(const char *tmpdir)
 	fd = mkstemp(temp_name.s);
 	if (fd < 0)
 		goto exit_tmpfile;
+	__archive_ensure_cloexec_flag(fd);
 	unlink(temp_name.s);
 exit_tmpfile:
 	archive_string_free(&temp_name);
@@ -437,7 +444,8 @@ __archive_mktemp(const char *tmpdir)
 	archive_strcat(&temp_name, "XXXXXXXXXX");
 	ep = temp_name.s + archive_strlen(&temp_name);
 
-	fd = open("/dev/random", O_RDONLY);
+	fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
+	__archive_ensure_cloexec_flag(fd);
 	if (fd < 0)
 		seed = time(NULL);
 	else {
@@ -451,10 +459,12 @@ __archive_mktemp(const char *tmpdir)
 		p = tp;
 		while (p < ep)
 			*p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
-		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600);
+		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
+			  0600);
 	} while (fd < 0 && errno == EEXIST);
 	if (fd < 0)
 		goto exit_tmpfile;
+	__archive_ensure_cloexec_flag(fd);
 	unlink(temp_name.s);
 exit_tmpfile:
 	archive_string_free(&temp_name);
@@ -463,3 +473,29 @@ exit_tmpfile:
 
 #endif /* HAVE_MKSTEMP */
 #endif /* !_WIN32 || __CYGWIN__ */
+
+/*
+ * Set FD_CLOEXEC flag to a file descriptor if it is not set.
+ * We have to set the flag if the platform does not provide O_CLOEXEC
+ * or F_DUPFD_CLOEXEC flags.
+ *
+ * Note: This function is absolutely called after creating a new file
+ * descriptor even if the platform seemingly provides O_CLOEXEC or
+ * F_DUPFD_CLOEXEC macros because it is possible that the platform
+ * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
+ */
+void
+__archive_ensure_cloexec_flag(int fd)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	(void)fd; /* UNSED */
+#else
+	int flags;
+
+	if (fd >= 0) {
+		flags = fcntl(fd, F_GETFD);
+		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
+			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+	}
+#endif
+}
diff --git a/libarchive/archive_virtual.c b/libarchive/archive_virtual.c
index 752dc17..0c4155f 100644
--- a/libarchive/archive_virtual.c
+++ b/libarchive/archive_virtual.c
@@ -67,8 +67,17 @@ archive_read_close(struct archive *a)
 }
 
 int
+archive_write_fail(struct archive *a)
+{
+	a->state = ARCHIVE_STATE_FATAL;
+	return a->state;
+}
+
+int
 archive_write_free(struct archive *a)
 {
+	if (a == NULL)
+		return (ARCHIVE_OK);
 	return ((a->vtable->archive_free)(a));
 }
 
@@ -77,13 +86,15 @@ archive_write_free(struct archive *a)
 int
 archive_write_finish(struct archive *a)
 {
-	return ((a->vtable->archive_free)(a));
+	return archive_write_free(a);
 }
 #endif
 
 int
 archive_read_free(struct archive *a)
 {
+	if (a == NULL)
+		return (ARCHIVE_OK);
 	return ((a->vtable->archive_free)(a));
 }
 
@@ -92,7 +103,7 @@ archive_read_free(struct archive *a)
 int
 archive_read_finish(struct archive *a)
 {
-	return ((a->vtable->archive_free)(a));
+	return archive_read_free(a);
 }
 #endif
 
diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c
index 0bb2a80..d3bf758 100644
--- a/libarchive/archive_windows.c
+++ b/libarchive/archive_windows.c
@@ -48,6 +48,7 @@
 
 #include "archive_platform.h"
 #include "archive_private.h"
+#include "archive_entry.h"
 #include <ctype.h>
 #include <errno.h>
 #include <stddef.h>
@@ -64,6 +65,23 @@
 
 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 
+#if defined(__LA_LSEEK_NEEDED)
+static BOOL SetFilePointerEx_perso(HANDLE hFile,
+				   LARGE_INTEGER liDistanceToMove,
+				   PLARGE_INTEGER lpNewFilePointer,
+				   DWORD dwMoveMethod)
+{
+	LARGE_INTEGER li;
+	li.QuadPart = liDistanceToMove.QuadPart;
+	li.LowPart = SetFilePointer(
+		hFile, li.LowPart, &li.HighPart, dwMoveMethod);
+	if(lpNewFilePointer) {
+		lpNewFilePointer->QuadPart = li.QuadPart;
+	}
+	return li.LowPart != -1 || GetLastError() == NO_ERROR;
+}
+#endif
+
 struct ustat {
 	int64_t		st_atime;
 	uint32_t	st_atime_nsec;
@@ -92,7 +110,7 @@ getino(struct ustat *ub)
 	ULARGE_INTEGER ino64;
 	ino64.QuadPart = ub->st_ino;
 	/* I don't know this hashing is correct way */
-	return (ino64.LowPart ^ (ino64.LowPart >> INOSIZE));
+	return ((ino_t)(ino64.LowPart ^ (ino64.LowPart >> INOSIZE)));
 }
 
 /*
@@ -136,7 +154,7 @@ __la_win_permissive_name_w(const wchar_t *wname)
 	if (l == 0)
 		return (NULL);
 	/* NOTE: GetFullPathNameW has a bug that if the length of the file
-	 * name is just one that return imcomplete buffer size. Thus, we 
+	 * name is just 1 then it returns incomplete buffer size. Thus, we
 	 * have to add three to the size to allocate a sufficient buffer
 	 * size for the full-pathname of the file name. */
 	l += 3;
@@ -234,6 +252,40 @@ la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
 	return (handle);
 }
 
+#if defined(__LA_LSEEK_NEEDED)
+__int64
+__la_lseek(int fd, __int64 offset, int whence)
+{
+	LARGE_INTEGER distance;
+	LARGE_INTEGER newpointer;
+	HANDLE handle;
+
+	if (fd < 0) {
+		errno = EBADF;
+		return (-1);
+	}
+	handle = (HANDLE)_get_osfhandle(fd);
+	if (GetFileType(handle) != FILE_TYPE_DISK) {
+		errno = EBADF;
+		return (-1);
+	}
+	distance.QuadPart = offset;
+	if (!SetFilePointerEx_perso(handle, distance, &newpointer, whence)) {
+		DWORD lasterr;
+
+		lasterr = GetLastError();
+		if (lasterr == ERROR_BROKEN_PIPE)
+			return (0);
+		if (lasterr == ERROR_ACCESS_DENIED)
+			errno = EBADF;
+		else
+			la_dosmaperr(lasterr);
+		return (-1);
+	}
+	return (newpointer.QuadPart);
+}
+#endif
+
 /* This can exceed MAX_PATH limitation. */
 int
 __la_open(const char *path, int flags, ...)
@@ -373,7 +425,7 @@ __la_read(int fd, void *buf, size_t nbytes)
 
 /* Convert Windows FILETIME to UTC */
 __inline static void
-fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns)
+fileTimeToUTC(const FILETIME *filetime, time_t *t, long *ns)
 {
 	ULARGE_INTEGER utc;
 
@@ -381,10 +433,10 @@ fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns)
 	utc.LowPart  = filetime->dwLowDateTime;
 	if (utc.QuadPart >= EPOC_TIME) {
 		utc.QuadPart -= EPOC_TIME;
-		*time = (time_t)(utc.QuadPart / 10000000);	/* milli seconds base */
+		*t = (time_t)(utc.QuadPart / 10000000);	/* milli seconds base */
 		*ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
 	} else {
-		*time = 0;
+		*t = 0;
 		*ns = 0;
 	}
 }
@@ -407,7 +459,7 @@ __hstat(HANDLE handle, struct ustat *st)
 	ULARGE_INTEGER ino64;
 	DWORD ftype;
 	mode_t mode;
-	time_t time;
+	time_t t;
 	long ns;
 
 	switch (ftype = GetFileType(handle)) {
@@ -464,14 +516,14 @@ __hstat(HANDLE handle, struct ustat *st)
 		mode |= S_IFREG;
 	st->st_mode = mode;
 	
-	fileTimeToUTC(&info.ftLastAccessTime, &time, &ns);
-	st->st_atime = time; 
+	fileTimeToUTC(&info.ftLastAccessTime, &t, &ns);
+	st->st_atime = t; 
 	st->st_atime_nsec = ns;
-	fileTimeToUTC(&info.ftLastWriteTime, &time, &ns);
-	st->st_mtime = time;
+	fileTimeToUTC(&info.ftLastWriteTime, &t, &ns);
+	st->st_mtime = t;
 	st->st_mtime_nsec = ns;
-	fileTimeToUTC(&info.ftCreationTime, &time, &ns);
-	st->st_ctime = time;
+	fileTimeToUTC(&info.ftCreationTime, &t, &ns);
+	st->st_ctime = t;
 	st->st_ctime_nsec = ns;
 	st->st_size = 
 	    ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))
@@ -507,7 +559,7 @@ copy_stat(struct stat *st, struct ustat *us)
 	st->st_ino = getino(us);
 	st->st_mode = us->st_mode;
 	st->st_nlink = us->st_nlink;
-	st->st_size = us->st_size;
+	st->st_size = (off_t)us->st_size;
 	st->st_uid = us->st_uid;
 	st->st_dev = us->st_dev;
 	st->st_rdev = us->st_rdev;
@@ -581,35 +633,22 @@ __la_stat(const char *path, struct stat *st)
  * This waitpid is limited implementation.
  */
 pid_t
-__la_waitpid(pid_t wpid, int *status, int option)
+__la_waitpid(HANDLE child, int *status, int option)
 {
-	HANDLE child;
-	DWORD cs, ret;
+	DWORD cs;
 
 	(void)option;/* UNUSED */
-	*status = 0;
-	child = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, wpid);
-	if (child == NULL) {
-		la_dosmaperr(GetLastError());
-		return (-1);
-	}
-	ret = WaitForSingleObject(child, INFINITE);
-	if (ret == WAIT_FAILED) {
-		CloseHandle(child);
-		la_dosmaperr(GetLastError());
-		return (-1);
-	}
-	if (GetExitCodeProcess(child, &cs) == 0) {
-		CloseHandle(child);
-		la_dosmaperr(GetLastError());
-		return (-1);
-	}
-	if (cs == STILL_ACTIVE)
-		*status = 0x100;
-	else
-		*status = (int)(cs & 0xff);
-	CloseHandle(child);
-	return (wpid);
+	do {
+		if (GetExitCodeProcess(child, &cs) == 0) {
+			CloseHandle(child);
+			la_dosmaperr(GetLastError());
+			*status = 0;
+			return (-1);
+		}
+	} while (cs == STILL_ACTIVE);
+
+	*status = (int)(cs & 0xff);
+	return (0);
 }
 
 ssize_t
@@ -640,6 +679,113 @@ __la_write(int fd, const void *buf, size_t nbytes)
 }
 
 /*
+ * Replace the Windows path separator '\' with '/'.
+ */
+static int
+replace_pathseparator(struct archive_wstring *ws, const wchar_t *wp)
+{
+	wchar_t *w;
+	size_t path_length;
+
+	if (wp == NULL)
+		return(0);
+	if (wcschr(wp, L'\\') == NULL)
+		return(0);
+	path_length = wcslen(wp);
+	if (archive_wstring_ensure(ws, path_length) == NULL)
+		return(-1);
+	archive_wstrncpy(ws, wp, path_length);
+	for (w = ws->s; *w; w++) {
+		if (*w == L'\\')
+			*w = L'/';
+	}
+	return(1);
+}
+
+static int
+fix_pathseparator(struct archive_entry *entry)
+{
+	struct archive_wstring ws;
+	const wchar_t *wp;
+	int ret = ARCHIVE_OK;
+
+	archive_string_init(&ws);
+	wp = archive_entry_pathname_w(entry);
+	switch (replace_pathseparator(&ws, wp)) {
+	case 0: /* Not replaced. */
+		break;
+	case 1: /* Replaced. */
+		archive_entry_copy_pathname_w(entry, ws.s);
+		break;
+	default:
+		ret = ARCHIVE_FAILED;
+	}
+	wp = archive_entry_hardlink_w(entry);
+	switch (replace_pathseparator(&ws, wp)) {
+	case 0: /* Not replaced. */
+		break;
+	case 1: /* Replaced. */
+		archive_entry_copy_hardlink_w(entry, ws.s);
+		break;
+	default:
+		ret = ARCHIVE_FAILED;
+	}
+	wp = archive_entry_symlink_w(entry);
+	switch (replace_pathseparator(&ws, wp)) {
+	case 0: /* Not replaced. */
+		break;
+	case 1: /* Replaced. */
+		archive_entry_copy_symlink_w(entry, ws.s);
+		break;
+	default:
+		ret = ARCHIVE_FAILED;
+	}
+	archive_wstring_free(&ws);
+	return(ret);
+}
+
+struct archive_entry *
+__la_win_entry_in_posix_pathseparator(struct archive_entry *entry)
+{
+	struct archive_entry *entry_main;
+	const wchar_t *wp;
+	int has_backslash = 0;
+	int ret;
+
+	wp = archive_entry_pathname_w(entry);
+	if (wp != NULL && wcschr(wp, L'\\') != NULL)
+		has_backslash = 1;
+	if (!has_backslash) {
+		wp = archive_entry_hardlink_w(entry);
+		if (wp != NULL && wcschr(wp, L'\\') != NULL)
+			has_backslash = 1;
+	}
+	if (!has_backslash) {
+		wp = archive_entry_symlink_w(entry);
+		if (wp != NULL && wcschr(wp, L'\\') != NULL)
+			has_backslash = 1;
+	}
+	/*
+	 * If there is no backslach chars, return the original.
+	 */
+	if (!has_backslash)
+		return (entry);
+
+	/* Copy entry so we can modify it as needed. */
+	entry_main = archive_entry_clone(entry);
+	if (entry_main == NULL)
+		return (NULL);
+	/* Replace the Windows path-separator '\' with '/'. */
+	ret = fix_pathseparator(entry_main);
+	if (ret < ARCHIVE_WARN) {
+		archive_entry_free(entry_main);
+		return (NULL);
+	}
+	return (entry_main);
+}
+
+
+/*
  * The following function was modified from PostgreSQL sources and is
  * subject to the copyright below.
  */
@@ -745,7 +891,7 @@ __la_dosmaperr(unsigned long e)
 		return;
 	}
 
-	for (i = 0; i < sizeof(doserrors); i++)
+	for (i = 0; i < (int)sizeof(doserrors); i++)
 	{
 		if (doserrors[i].winerr == e)
 		{
diff --git a/libarchive/archive_windows.h b/libarchive/archive_windows.h
index cfb3e97..c6f5bc5 100644
--- a/libarchive/archive_windows.h
+++ b/libarchive/archive_windows.h
@@ -49,6 +49,9 @@
 #define	LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED
 
 /* Start of configuration for native Win32  */
+#ifndef MINGW_HAS_SECURE_API
+#define MINGW_HAS_SECURE_API 1
+#endif
 
 #include <errno.h>
 #define	set_errno(val)	((errno)=val)
@@ -71,10 +74,6 @@
 #include <windows.h>
 //#define	EFTYPE 7
 
-#if defined(_MSC_VER)
-/* TODO: Fix the code, don't suppress the warnings. */
-#pragma warning(disable:4244)   /* 'conversion' conversion from 'type1' to 'type2', possible loss of data */
-#endif
 #if defined(__BORLANDC__)
 #pragma warn -8068	/* Constant out of range in comparison. */
 #pragma warn -8072	/* Suspicious pointer arithmetic. */
@@ -94,14 +93,28 @@
 #ifndef fileno
 #define	fileno		_fileno
 #endif
+#ifdef fstat
+#undef fstat
+#endif
 #define	fstat		__la_fstat
+#if !defined(__BORLANDC__)
+#ifdef lseek
+#undef lseek
+#endif
 #define	lseek		_lseeki64
+#else
+#define	lseek		__la_lseek
+#define __LA_LSEEK_NEEDED
+#endif
 #define	lstat		__la_stat
 #define	open		__la_open
 #define	read		__la_read
 #if !defined(__BORLANDC__)
 #define setmode		_setmode
 #endif
+#ifdef stat
+#undef stat
+#endif
 #define	stat(path,stref)		__la_stat(path,stref)
 #if !defined(__BORLANDC__)
 #define	strdup		_strdup
@@ -245,10 +258,13 @@
 /* Replacement POSIX function */
 extern int	 __la_fstat(int fd, struct stat *st);
 extern int	 __la_lstat(const char *path, struct stat *st);
+#if defined(__LA_LSEEK_NEEDED)
+extern __int64	 __la_lseek(int fd, __int64 offset, int whence);
+#endif
 extern int	 __la_open(const char *path, int flags, ...);
 extern ssize_t	 __la_read(int fd, void *buf, size_t nbytes);
 extern int	 __la_stat(const char *path, struct stat *st);
-extern pid_t	 __la_waitpid(pid_t wpid, int *status, int option);
+extern pid_t	 __la_waitpid(HANDLE child, int *status, int option);
 extern ssize_t	 __la_write(int fd, const void *buf, size_t nbytes);
 
 #define _stat64i32(path, st)	__la_stat(path, st)
@@ -261,6 +277,30 @@ extern wchar_t *__la_win_permissive_name(const char *name);
 extern wchar_t *__la_win_permissive_name_w(const wchar_t *wname);
 extern void __la_dosmaperr(unsigned long e);
 #define la_dosmaperr(e) __la_dosmaperr(e)
+extern struct archive_entry *__la_win_entry_in_posix_pathseparator(
+    struct archive_entry *);
 
+#if defined(HAVE_WCRTOMB) && defined(__BORLANDC__)
+typedef int mbstate_t;
+size_t wcrtomb(char *, wchar_t, mbstate_t *);
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1300
+WINBASEAPI BOOL WINAPI GetVolumePathNameW(
+       LPCWSTR lpszFileName,
+       LPWSTR lpszVolumePathName,
+       DWORD cchBufferLength
+       );
+# if _WIN32_WINNT < 0x0500 /* windows.h not providing 0x500 API */
+typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
+       LARGE_INTEGER FileOffset;
+       LARGE_INTEGER Length;
+} FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER;
+#  define FSCTL_SET_SPARSE \
+     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_WRITE_DATA)
+#  define FSCTL_QUERY_ALLOCATED_RANGES \
+     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51,  METHOD_NEITHER, FILE_READ_DATA)
+# endif
+#endif
 
 #endif /* LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */
diff --git a/libarchive/archive_write.3 b/libarchive/archive_write.3
index f87386a..228bc2c 100644
--- a/libarchive/archive_write.3
+++ b/libarchive/archive_write.3
@@ -22,14 +22,16 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $
+.\" $FreeBSD$
 .\"
-.Dd March 23, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_WRITE 3
 .Os
 .Sh NAME
 .Nm archive_write
 .Nd functions for creating archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Sh DESCRIPTION
diff --git a/libarchive/archive_write.c b/libarchive/archive_write.c
index c742d60..a3d1a33 100644
--- a/libarchive/archive_write.c
+++ b/libarchive/archive_write.c
@@ -232,6 +232,10 @@ __archive_write_filter(struct archive_write_filter *f,
 	int r;
 	if (length == 0)
 		return(ARCHIVE_OK);
+	if (f->write == NULL)
+		/* If unset, a fatal error has already ocuured, so this filter
+		 * didn't open. We cannot write anything. */
+		return(ARCHIVE_FATAL);
 	r = (f->write)(f, buff, length);
 	f->bytes_written += length;
 	return (r);
@@ -323,43 +327,43 @@ archive_write_client_write(struct archive_write_filter *f,
 {
 	struct archive_write *a = (struct archive_write *)f->archive;
         struct archive_none *state = (struct archive_none *)f->data;
-        const char *buff = (const char *)_buff;
-        ssize_t remaining, to_copy;
-        ssize_t bytes_written;
-
-        remaining = length;
-
-        /*
-         * If there is no buffer for blocking, just pass the data
-         * straight through to the client write callback.  In
-         * particular, this supports "no write delay" operation for
-         * special applications.  Just set the block size to zero.
-         */
-        if (state->buffer_size == 0) {
-                while (remaining > 0) {
-                        bytes_written = (a->client_writer)(&a->archive,
-                            a->client_data, buff, remaining);
-                        if (bytes_written <= 0)
-                                return (ARCHIVE_FATAL);
-                        remaining -= bytes_written;
-                        buff += bytes_written;
-                }
-                return (ARCHIVE_OK);
-        }
-
-        /* If the copy buffer isn't empty, try to fill it. */
-        if (state->avail < state->buffer_size) {
-                /* If buffer is not empty... */
-                /* ... copy data into buffer ... */
-                to_copy = ((size_t)remaining > state->avail) ?
+	const char *buff = (const char *)_buff;
+	ssize_t remaining, to_copy;
+	ssize_t bytes_written;
+
+	remaining = length;
+
+	/*
+	 * If there is no buffer for blocking, just pass the data
+	 * straight through to the client write callback.  In
+	 * particular, this supports "no write delay" operation for
+	 * special applications.  Just set the block size to zero.
+	 */
+	if (state->buffer_size == 0) {
+		while (remaining > 0) {
+			bytes_written = (a->client_writer)(&a->archive,
+			    a->client_data, buff, remaining);
+			if (bytes_written <= 0)
+				return (ARCHIVE_FATAL);
+			remaining -= bytes_written;
+			buff += bytes_written;
+		}
+		return (ARCHIVE_OK);
+	}
+
+	/* If the copy buffer isn't empty, try to fill it. */
+	if (state->avail < state->buffer_size) {
+		/* If buffer is not empty... */
+		/* ... copy data into buffer ... */
+		to_copy = ((size_t)remaining > state->avail) ?
 			state->avail : (size_t)remaining;
-                memcpy(state->next, buff, to_copy);
-                state->next += to_copy;
-                state->avail -= to_copy;
-                buff += to_copy;
-                remaining -= to_copy;
-                /* ... if it's full, write it out. */
-                if (state->avail == 0) {
+		memcpy(state->next, buff, to_copy);
+		state->next += to_copy;
+		state->avail -= to_copy;
+		buff += to_copy;
+		remaining -= to_copy;
+		/* ... if it's full, write it out. */
+		if (state->avail == 0) {
 			char *p = state->buffer;
 			size_t to_write = state->buffer_size;
 			while (to_write > 0) {
@@ -375,70 +379,72 @@ archive_write_client_write(struct archive_write_filter *f,
 				p += bytes_written;
 				to_write -= bytes_written;
 			}
-                        state->next = state->buffer;
-                        state->avail = state->buffer_size;
-                }
-        }
-
-        while ((size_t)remaining > state->buffer_size) {
-                /* Write out full blocks directly to client. */
-                bytes_written = (a->client_writer)(&a->archive,
-                    a->client_data, buff, state->buffer_size);
-                if (bytes_written <= 0)
-                        return (ARCHIVE_FATAL);
-                buff += bytes_written;
-                remaining -= bytes_written;
-        }
-
-        if (remaining > 0) {
-                /* Copy last bit into copy buffer. */
-                memcpy(state->next, buff, remaining);
-                state->next += remaining;
-                state->avail -= remaining;
-        }
-        return (ARCHIVE_OK);
+			state->next = state->buffer;
+			state->avail = state->buffer_size;
+		}
+	}
+
+	while ((size_t)remaining >= state->buffer_size) {
+		/* Write out full blocks directly to client. */
+		bytes_written = (a->client_writer)(&a->archive,
+		    a->client_data, buff, state->buffer_size);
+		if (bytes_written <= 0)
+			return (ARCHIVE_FATAL);
+		buff += bytes_written;
+		remaining -= bytes_written;
+	}
+
+	if (remaining > 0) {
+		/* Copy last bit into copy buffer. */
+		memcpy(state->next, buff, remaining);
+		state->next += remaining;
+		state->avail -= remaining;
+	}
+	return (ARCHIVE_OK);
 }
 
 static int
 archive_write_client_close(struct archive_write_filter *f)
 {
 	struct archive_write *a = (struct archive_write *)f->archive;
-        struct archive_none *state = (struct archive_none *)f->data;
-        ssize_t block_length;
-        ssize_t target_block_length;
-        ssize_t bytes_written;
-        int ret = ARCHIVE_OK;
-
-        /* If there's pending data, pad and write the last block */
-        if (state->next != state->buffer) {
-                block_length = state->buffer_size - state->avail;
-
-                /* Tricky calculation to determine size of last block */
-                if (a->bytes_in_last_block <= 0)
-                        /* Default or Zero: pad to full block */
-                        target_block_length = a->bytes_per_block;
-                else
-                        /* Round to next multiple of bytes_in_last_block. */
-                        target_block_length = a->bytes_in_last_block *
-                            ( (block_length + a->bytes_in_last_block - 1) /
-                                a->bytes_in_last_block);
-                if (target_block_length > a->bytes_per_block)
-                        target_block_length = a->bytes_per_block;
-                if (block_length < target_block_length) {
-                        memset(state->next, 0,
-                            target_block_length - block_length);
-                        block_length = target_block_length;
-                }
-                bytes_written = (a->client_writer)(&a->archive,
-                    a->client_data, state->buffer, block_length);
-                ret = bytes_written <= 0 ? ARCHIVE_FATAL : ARCHIVE_OK;
-        }
+	struct archive_none *state = (struct archive_none *)f->data;
+	ssize_t block_length;
+	ssize_t target_block_length;
+	ssize_t bytes_written;
+	int ret = ARCHIVE_OK;
+
+	/* If there's pending data, pad and write the last block */
+	if (state->next != state->buffer) {
+		block_length = state->buffer_size - state->avail;
+
+		/* Tricky calculation to determine size of last block */
+		if (a->bytes_in_last_block <= 0)
+			/* Default or Zero: pad to full block */
+			target_block_length = a->bytes_per_block;
+		else
+			/* Round to next multiple of bytes_in_last_block. */
+			target_block_length = a->bytes_in_last_block *
+			    ( (block_length + a->bytes_in_last_block - 1) /
+			        a->bytes_in_last_block);
+		if (target_block_length > a->bytes_per_block)
+			target_block_length = a->bytes_per_block;
+		if (block_length < target_block_length) {
+			memset(state->next, 0,
+			    target_block_length - block_length);
+			block_length = target_block_length;
+		}
+		bytes_written = (a->client_writer)(&a->archive,
+		    a->client_data, state->buffer, block_length);
+		ret = bytes_written <= 0 ? ARCHIVE_FATAL : ARCHIVE_OK;
+	}
 	if (a->client_closer)
 		(*a->client_closer)(&a->archive, a->client_data);
 	free(state->buffer);
-        free(state);
-        a->client_data = NULL;
-        return (ret);
+	free(state);
+	/* Clear the close handler myself not to be called again. */
+	f->close = NULL;
+	a->client_data = NULL;
+	return (ret);
 }
 
 /*
@@ -623,7 +629,7 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
 	if (a->skip_file_set &&
 	    archive_entry_dev_is_set(entry) &&
 	    archive_entry_ino_is_set(entry) &&
-	    archive_entry_dev(entry) == a->skip_file_dev &&
+	    archive_entry_dev(entry) == (dev_t)a->skip_file_dev &&
 	    archive_entry_ino64(entry) == a->skip_file_ino) {
 		archive_set_error(&a->archive, 0,
 		    "Can't add archive to itself");
diff --git a/libarchive/archive_read_disk_private.h b/libarchive/archive_write_add_filter.c
similarity index 50%
copy from libarchive/archive_read_disk_private.h
copy to libarchive/archive_write_add_filter.c
index 4446474..81dd683 100644
--- a/libarchive/archive_read_disk_private.h
+++ b/libarchive/archive_write_add_filter.c
@@ -1,13 +1,12 @@
 /*-
- * Copyright (c) 2003-2009 Tim Kientzle
+ * Copyright (c) 2012 Ondrej Holy
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer
- *    in this position and unchanged.
+ *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
@@ -22,50 +21,50 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (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
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
 
-struct tree;
-
-struct archive_read_disk {
-	struct archive	archive;
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
 
-	/*
-	 * 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;
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
 
-	/*
-	 * 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'. */
+#include "archive.h"
+#include "archive_private.h"
 
-	/* Directory traversals. */
-	struct tree *tree;
+/* A table that maps filter codes to functions. */
+static
+struct { int code; int (*setter)(struct archive *); } codes[] =
+{
+	{ ARCHIVE_FILTER_NONE,		archive_write_add_filter_none },
+	{ ARCHIVE_FILTER_GZIP,		archive_write_add_filter_gzip },
+	{ ARCHIVE_FILTER_BZIP2,		archive_write_add_filter_bzip2 },
+	{ ARCHIVE_FILTER_COMPRESS,	archive_write_add_filter_compress },
+	{ ARCHIVE_FILTER_GRZIP,		archive_write_add_filter_grzip },
+	{ ARCHIVE_FILTER_LRZIP,		archive_write_add_filter_lrzip },
+	{ ARCHIVE_FILTER_LZIP,		archive_write_add_filter_lzip },
+	{ ARCHIVE_FILTER_LZMA,		archive_write_add_filter_lzma },
+	{ ARCHIVE_FILTER_LZOP,		archive_write_add_filter_lzip },
+	{ ARCHIVE_FILTER_UU,		archive_write_add_filter_uuencode },
+	{ ARCHIVE_FILTER_XZ,		archive_write_add_filter_xz },
+	{ -1,			NULL }
+};
 
-	/* Set 1 if users request to restore atime . */
-	int		 restore_time;
-	int		 entry_wd_fd;
+int
+archive_write_add_filter(struct archive *a, int code)
+{
+	int i;
 
-	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;
-};
+	for (i = 0; codes[i].code != -1; i++) {
+		if (code == codes[i].code)
+			return ((codes[i].setter)(a));
+	}
 
-#endif
+	archive_set_error(a, EINVAL, "No such filter");
+	return (ARCHIVE_FATAL);
+}
diff --git a/libarchive/archive_write_add_filter_b64encode.c b/libarchive/archive_write_add_filter_b64encode.c
new file mode 100644
index 0000000..85eb087
--- /dev/null
+++ b/libarchive/archive_write_add_filter_b64encode.c
@@ -0,0 +1,314 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_string.h"
+#include "archive_write_private.h"
+
+#define LBYTES	57
+
+struct private_b64encode {
+	int			mode;
+	struct archive_string	name;
+	struct archive_string	encoded_buff;
+	size_t			bs;
+	size_t			hold_len;
+	unsigned char		hold[LBYTES];
+};
+
+static int archive_filter_b64encode_options(struct archive_write_filter *,
+    const char *, const char *);
+static int archive_filter_b64encode_open(struct archive_write_filter *);
+static int archive_filter_b64encode_write(struct archive_write_filter *,
+    const void *, size_t);
+static int archive_filter_b64encode_close(struct archive_write_filter *);
+static int archive_filter_b64encode_free(struct archive_write_filter *);
+static void b64_encode(struct archive_string *, const unsigned char *, size_t);
+static int64_t atol8(const char *, size_t);
+
+static const char base64[] = {
+	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+	'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+	'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+	'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+	'w', 'x', 'y', 'z', '0', '1', '2', '3',
+	'4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+/*
+ * Add a compress filter to this write handle.
+ */
+int
+archive_write_add_filter_b64encode(struct archive *_a)
+{
+	struct archive_write *a = (struct archive_write *)_a;
+	struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+	struct private_b64encode *state;
+
+	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");
+
+	state = (struct private_b64encode *)calloc(1, sizeof(*state));
+	if (state == NULL) {
+		archive_set_error(f->archive, ENOMEM,
+		    "Can't allocate data for b64encode filter");
+		return (ARCHIVE_FATAL);
+	}
+	archive_strcpy(&state->name, "-");
+	state->mode = 0644;
+
+	f->data = state;
+	f->name = "b64encode";
+	f->code = ARCHIVE_FILTER_UU;
+	f->open = archive_filter_b64encode_open;
+	f->options = archive_filter_b64encode_options;
+	f->write = archive_filter_b64encode_write;
+	f->close = archive_filter_b64encode_close;
+	f->free = archive_filter_b64encode_free;
+
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_filter_b64encode_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+	struct private_b64encode *state = (struct private_b64encode *)f->data;
+
+	if (strcmp(key, "mode") == 0) {
+		if (value == NULL) {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "mode option requires octal digits");
+			return (ARCHIVE_FAILED);
+		}
+		state->mode = (int)atol8(value, strlen(value)) & 0777;
+		return (ARCHIVE_OK);
+	} else if (strcmp(key, "name") == 0) {
+		if (value == NULL) {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "name option requires a string");
+			return (ARCHIVE_FAILED);
+		}
+		archive_strcpy(&state->name, value);
+		return (ARCHIVE_OK);
+	}
+
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_filter_b64encode_open(struct archive_write_filter *f)
+{
+	struct private_b64encode *state = (struct private_b64encode *)f->data;
+	size_t bs = 65536, bpb;
+	int ret;
+
+	ret = __archive_write_open_filter(f->next_filter);
+	if (ret != ARCHIVE_OK)
+		return (ret);
+
+	if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
+		/* Buffer size should be a multiple number of the of bytes
+		 * per block for performance. */
+		bpb = archive_write_get_bytes_per_block(f->archive);
+		if (bpb > bs)
+			bs = bpb;
+		else if (bpb != 0)
+			bs -= bs % bpb;
+	}
+
+	state->bs = bs;
+	if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
+		archive_set_error(f->archive, ENOMEM,
+		    "Can't allocate data for b64encode buffer");
+		return (ARCHIVE_FATAL);
+	}
+
+	archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n",
+	    state->mode, state->name.s);
+
+	f->data = state;
+	return (0);
+}
+
+static void
+b64_encode(struct archive_string *as, const unsigned char *p, size_t len)
+{
+	int c;
+
+	for (; len >= 3; p += 3, len -= 3) {
+		c = p[0] >> 2;
+		archive_strappend_char(as, base64[c]);
+		c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4);
+		archive_strappend_char(as, base64[c]);
+		c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6);
+		archive_strappend_char(as, base64[c]);
+		c = p[2] & 0x3f;
+		archive_strappend_char(as, base64[c]);
+	}
+	if (len > 0) {
+		c = p[0] >> 2;
+		archive_strappend_char(as, base64[c]);
+		c = (p[0] & 0x03) << 4;
+		if (len == 1) {
+			archive_strappend_char(as, base64[c]);
+			archive_strappend_char(as, '=');
+			archive_strappend_char(as, '=');
+		} else {
+			c |= (p[1] & 0xf0) >> 4;
+			archive_strappend_char(as, base64[c]);
+			c = (p[1] & 0x0f) << 2;
+			archive_strappend_char(as, base64[c]);
+			archive_strappend_char(as, '=');
+		}
+	}
+	archive_strappend_char(as, '\n');
+}
+
+/*
+ * Write data to the encoded stream.
+ */
+static int
+archive_filter_b64encode_write(struct archive_write_filter *f, const void *buff,
+    size_t length)
+{
+	struct private_b64encode *state = (struct private_b64encode *)f->data;
+	const unsigned char *p = buff;
+	int ret = ARCHIVE_OK;
+
+	if (length == 0)
+		return (ret);
+
+	if (state->hold_len) {
+		while (state->hold_len < LBYTES && length > 0) {
+			state->hold[state->hold_len++] = *p++;
+			length--;
+		}
+		if (state->hold_len < LBYTES)
+			return (ret);
+		b64_encode(&state->encoded_buff, state->hold, LBYTES);
+		state->hold_len = 0;
+	}
+
+	for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
+		b64_encode(&state->encoded_buff, p, LBYTES);
+
+	/* Save remaining bytes. */
+	if (length > 0) {
+		memcpy(state->hold, p, length);
+		state->hold_len = length;
+	}
+	while (archive_strlen(&state->encoded_buff) >= state->bs) {
+		ret = __archive_write_filter(f->next_filter,
+		    state->encoded_buff.s, state->bs);
+		memmove(state->encoded_buff.s,
+		    state->encoded_buff.s + state->bs,
+		    state->encoded_buff.length - state->bs);
+		state->encoded_buff.length -= state->bs;
+	}
+
+	return (ret);
+}
+
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_filter_b64encode_close(struct archive_write_filter *f)
+{
+	struct private_b64encode *state = (struct private_b64encode *)f->data;
+	int ret, ret2;
+
+	/* Flush remaining bytes. */
+	if (state->hold_len != 0)
+		b64_encode(&state->encoded_buff, state->hold, state->hold_len);
+	archive_string_sprintf(&state->encoded_buff, "====\n");
+	/* Write the last block */
+	archive_write_set_bytes_in_last_block(f->archive, 1);
+	ret = __archive_write_filter(f->next_filter,
+	    state->encoded_buff.s, archive_strlen(&state->encoded_buff));
+	ret2 = __archive_write_close_filter(f->next_filter);
+	if (ret > ret2)
+		ret = ret2;
+	return (ret);
+}
+
+static int
+archive_filter_b64encode_free(struct archive_write_filter *f)
+{
+	struct private_b64encode *state = (struct private_b64encode *)f->data;
+
+	archive_string_free(&state->name);
+	archive_string_free(&state->encoded_buff);
+	free(state);
+	return (ARCHIVE_OK);
+}
+
+static int64_t
+atol8(const char *p, size_t char_cnt)
+{
+	int64_t l;
+	int digit;
+        
+	l = 0;
+	while (char_cnt-- > 0) {
+		if (*p >= '0' && *p <= '7')
+			digit = *p - '0';
+		else
+			break;
+		p++;
+		l <<= 3;
+		l |= digit;
+	}
+	return (l);
+}
+
diff --git a/libarchive/archive_write_set_format_by_name.c b/libarchive/archive_write_add_filter_by_name.c
similarity index 58%
copy from libarchive/archive_write_set_format_by_name.c
copy to libarchive/archive_write_add_filter_by_name.c
index 9671f60..e4cba4a 100644
--- a/libarchive/archive_write_set_format_by_name.c
+++ b/libarchive/archive_write_add_filter_by_name.c
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -24,7 +25,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_by_name.c 201168 2009-12-29 06:15:32Z kientzle $");
+__FBSDID("$FreeBSD$");
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -44,34 +45,22 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_by_name.c 20116
 static
 struct { const char *name; int (*setter)(struct archive *); } names[] =
 {
-	{ "7zip",	archive_write_set_format_7zip },
-	{ "ar",		archive_write_set_format_ar_bsd },
-	{ "arbsd",	archive_write_set_format_ar_bsd },
-	{ "argnu",	archive_write_set_format_ar_svr4 },
-	{ "arsvr4",	archive_write_set_format_ar_svr4 },
-	{ "bsdtar",	archive_write_set_format_pax_restricted },
-	{ "cd9660",	archive_write_set_format_iso9660 },
-	{ "cpio",	archive_write_set_format_cpio },
-	{ "gnutar",	archive_write_set_format_gnutar },
-	{ "iso",	archive_write_set_format_iso9660 },
-	{ "iso9660",	archive_write_set_format_iso9660 },
-	{ "mtree",	archive_write_set_format_mtree },
-	{ "newc",	archive_write_set_format_cpio_newc },
-	{ "odc",	archive_write_set_format_cpio },
-	{ "pax",	archive_write_set_format_pax },
-	{ "paxr",	archive_write_set_format_pax_restricted },
-	{ "posix",	archive_write_set_format_pax },
-	{ "rpax",	archive_write_set_format_pax_restricted },
-	{ "shar",	archive_write_set_format_shar },
-	{ "shardump",	archive_write_set_format_shar_dump },
-	{ "ustar",	archive_write_set_format_ustar },
-	{ "xar",	archive_write_set_format_xar },
-	{ "zip",	archive_write_set_format_zip },
-	{ NULL,		NULL }
+	{ "b64encode",		archive_write_add_filter_b64encode },
+	{ "bzip2",		archive_write_add_filter_bzip2 },
+	{ "compress",		archive_write_add_filter_compress },
+	{ "grzip",		archive_write_add_filter_grzip },
+	{ "gzip",		archive_write_add_filter_gzip },
+	{ "lrzip",		archive_write_add_filter_lrzip },
+	{ "lzip",		archive_write_add_filter_lzip },
+	{ "lzma",		archive_write_add_filter_lzma },
+	{ "lzop",		archive_write_add_filter_lzop },
+	{ "uuencode",		archive_write_add_filter_uuencode },
+	{ "xz",			archive_write_add_filter_xz },
+	{ NULL,			NULL }
 };
 
 int
-archive_write_set_format_by_name(struct archive *a, const char *name)
+archive_write_add_filter_by_name(struct archive *a, const char *name)
 {
 	int i;
 
@@ -80,7 +69,7 @@ archive_write_set_format_by_name(struct archive *a, const char *name)
 			return ((names[i].setter)(a));
 	}
 
-	archive_set_error(a, EINVAL, "No such format '%s'", name);
+	archive_set_error(a, EINVAL, "No such filter '%s'", name);
 	a->state = ARCHIVE_STATE_FATAL;
 	return (ARCHIVE_FATAL);
 }
diff --git a/libarchive/archive_write_add_filter_bzip2.c b/libarchive/archive_write_add_filter_bzip2.c
index e0d07a9..88da803 100644
--- a/libarchive/archive_write_add_filter_bzip2.c
+++ b/libarchive/archive_write_add_filter_bzip2.c
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,32 +55,18 @@ archive_write_set_compression_bzip2(struct archive *a)
 }
 #endif
 
-#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
-int
-archive_write_add_filter_bzip2(struct archive *a)
-{
-	archive_set_error(a, ARCHIVE_ERRNO_MISC,
-	    "bzip2 compression not supported on this platform");
-	return (ARCHIVE_FATAL);
-}
-#else
-/* Don't compile this if we don't have bzlib. */
-
 struct private_data {
 	int		 compression_level;
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 	bz_stream	 stream;
 	int64_t		 total_in;
 	char		*compressed;
 	size_t		 compressed_buffer_size;
+#else
+	struct archive_write_program_data *pdata;
+#endif
 };
 
-/*
- * Yuck.  bzlib.h is not const-correct, so I need this one bit
- * of ugly hackery to convert a const * pointer to a non-const pointer.
- */
-#define	SET_NEXT_IN(st,src)					\
-	(st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
-
 static int archive_compressor_bzip2_close(struct archive_write_filter *);
 static int archive_compressor_bzip2_free(struct archive_write_filter *);
 static int archive_compressor_bzip2_open(struct archive_write_filter *);
@@ -87,8 +74,6 @@ static int archive_compressor_bzip2_options(struct archive_write_filter *,
 		    const char *, const char *);
 static int archive_compressor_bzip2_write(struct archive_write_filter *,
 		    const void *, size_t);
-static int drive_compressor(struct archive_write_filter *,
-		    struct private_data *, int finishing);
 
 /*
  * Add a bzip2 compression filter to this write handle.
@@ -115,11 +100,64 @@ archive_write_add_filter_bzip2(struct archive *_a)
 	f->close = &archive_compressor_bzip2_close;
 	f->free = &archive_compressor_bzip2_free;
 	f->open = &archive_compressor_bzip2_open;
-	f->code = ARCHIVE_COMPRESSION_BZIP2;
+	f->code = ARCHIVE_FILTER_BZIP2;
 	f->name = "bzip2";
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 	return (ARCHIVE_OK);
+#else
+	data->pdata = __archive_write_program_allocate();
+	if (data->pdata == NULL) {
+		free(data);
+		archive_set_error(&a->archive, ENOMEM, "Out of memory");
+		return (ARCHIVE_FATAL);
+	}
+	data->compression_level = 0;
+	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+	    "Using external bzip2 program");
+	return (ARCHIVE_WARN);
+#endif
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_compressor_bzip2_options(struct archive_write_filter *f,
+    const char *key, const char *value)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+	if (strcmp(key, "compression-level") == 0) {
+		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+		    value[1] != '\0')
+			return (ARCHIVE_WARN);
+		data->compression_level = value[0] - '0';
+		/* Make '0' be a synonym for '1'. */
+		/* This way, bzip2 compressor supports the same 0..9
+		 * range of levels as gzip. */
+		if (data->compression_level < 1)
+			data->compression_level = 1;
+		return (ARCHIVE_OK);
+	}
+
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
+#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
+/* Don't compile this if we don't have bzlib. */
+
+/*
+ * Yuck.  bzlib.h is not const-correct, so I need this one bit
+ * of ugly hackery to convert a const * pointer to a non-const pointer.
+ */
+#define	SET_NEXT_IN(st,src)					\
+	(st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
+static int drive_compressor(struct archive_write_filter *,
+		    struct private_data *, int finishing);
+
 /*
  * Setup callback.
  */
@@ -133,10 +171,18 @@ archive_compressor_bzip2_open(struct archive_write_filter *f)
 	if (ret != 0)
 		return (ret);
 
-	/* TODO: Find a better way to size this.  (Maybe look at the */
-	/* block size expected by the following filter?) */
 	if (data->compressed == NULL) {
-		data->compressed_buffer_size = 65536;
+		size_t bs = 65536, bpb;
+		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
+			/* Buffer size should be a multiple number of the of bytes
+			 * per block for performance. */
+			bpb = archive_write_get_bytes_per_block(f->archive);
+			if (bpb > bs)
+				bs = bpb;
+			else if (bpb != 0)
+				bs -= bs % bpb;
+		}
+		data->compressed_buffer_size = bs;
 		data->compressed
 		    = (char *)malloc(data->compressed_buffer_size);
 		if (data->compressed == NULL) {
@@ -187,31 +233,6 @@ archive_compressor_bzip2_open(struct archive_write_filter *f)
 }
 
 /*
- * Set write options.
- */
-static int
-archive_compressor_bzip2_options(struct archive_write_filter *f,
-    const char *key, const char *value)
-{
-	struct private_data *data = (struct private_data *)f->data;
-
-	if (strcmp(key, "compression-level") == 0) {
-		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
-		    value[1] != '\0')
-			return (ARCHIVE_WARN);
-		data->compression_level = value[0] - '0';
-		/* Make '0' be a synonym for '1'. */
-		/* This way, bzip2 compressor supports the same 0..9
-		 * range of levels as gzip. */
-		if (data->compression_level < 1)
-			data->compression_level = 1;
-		return (ARCHIVE_OK);
-	}
-
-	return (ARCHIVE_WARN);
-}
-
-/*
  * Write data to the compressed stream.
  *
  * Returns ARCHIVE_OK if all data written, error otherwise.
@@ -332,4 +353,55 @@ drive_compressor(struct archive_write_filter *f,
 	}
 }
 
+#else /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
+
+static int
+archive_compressor_bzip2_open(struct archive_write_filter *f)
+{
+	struct private_data *data = (struct private_data *)f->data;
+	struct archive_string as;
+	int r;
+
+	archive_string_init(&as);
+	archive_strcpy(&as, "bzip2");
+
+	/* Specify compression level. */
+	if (data->compression_level > 0) {
+		archive_strcat(&as, " -");
+		archive_strappend_char(&as, '0' + data->compression_level);
+	}
+	f->write = archive_compressor_bzip2_write;
+
+	r = __archive_write_program_open(f, data->pdata, as.s);
+	archive_string_free(&as);
+	return (r);
+}
+
+static int
+archive_compressor_bzip2_write(struct archive_write_filter *f, const void *buff,
+    size_t length)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+	return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_compressor_bzip2_close(struct archive_write_filter *f)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+	return __archive_write_program_close(f, data->pdata);
+}
+
+static int
+archive_compressor_bzip2_free(struct archive_write_filter *f)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+	__archive_write_program_free(data->pdata);
+	free(data);
+	return (ARCHIVE_OK);
+}
+
 #endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
diff --git a/libarchive/archive_write_add_filter_compress.c b/libarchive/archive_write_add_filter_compress.c
index 465ff0e..26fcef4 100644
--- a/libarchive/archive_write_add_filter_compress.c
+++ b/libarchive/archive_write_add_filter_compress.c
@@ -135,7 +135,7 @@ archive_write_add_filter_compress(struct archive *_a)
 	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_compress");
 	f->open = &archive_compressor_compress_open;
-	f->code = ARCHIVE_COMPRESSION_COMPRESS;
+	f->code = ARCHIVE_FILTER_COMPRESS;
 	f->name = "compress";
 	return (ARCHIVE_OK);
 }
@@ -148,8 +148,9 @@ archive_compressor_compress_open(struct archive_write_filter *f)
 {
 	int ret;
 	struct private_data *state;
+	size_t bs = 65536, bpb;
 
-	f->code = ARCHIVE_COMPRESSION_COMPRESS;
+	f->code = ARCHIVE_FILTER_COMPRESS;
 	f->name = "compress";
 
 	ret = __archive_write_open_filter(f->next_filter);
@@ -163,7 +164,16 @@ archive_compressor_compress_open(struct archive_write_filter *f)
 		return (ARCHIVE_FATAL);
 	}
 
-	state->compressed_buffer_size = 65536;
+	if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
+		/* Buffer size should be a multiple number of the of bytes
+		 * per block for performance. */
+		bpb = archive_write_get_bytes_per_block(f->archive);
+		if (bpb > bs)
+			bs = bpb;
+		else if (bpb != 0)
+			bs -= bs % bpb;
+	}
+	state->compressed_buffer_size = bs;
 	state->compressed = malloc(state->compressed_buffer_size);
 
 	if (state->compressed == NULL) {
@@ -386,12 +396,12 @@ archive_compressor_compress_write(struct archive_write_filter *f,
 
 		state->checkpoint = state->in_count + CHECK_GAP;
 
-		if (state->in_count <= 0x007fffff)
-			ratio = state->in_count * 256 / state->out_count;
-		else if ((ratio = state->out_count / 256) == 0)
+		if (state->in_count <= 0x007fffff && state->out_count != 0)
+			ratio = (int)(state->in_count * 256 / state->out_count);
+		else if ((ratio = (int)(state->out_count / 256)) == 0)
 			ratio = 0x7fffffff;
 		else
-			ratio = state->in_count / ratio;
+			ratio = (int)(state->in_count / ratio);
 
 		if (ratio > state->compress_ratio)
 			state->compress_ratio = ratio;
diff --git a/libarchive/archive_write_add_filter_grzip.c b/libarchive/archive_write_add_filter_grzip.c
new file mode 100644
index 0000000..8dc287e
--- /dev/null
+++ b/libarchive/archive_write_add_filter_grzip.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_write_private.h"
+
+struct write_grzip {
+	struct archive_write_program_data *pdata;
+};
+
+static int archive_write_grzip_open(struct archive_write_filter *);
+static int archive_write_grzip_options(struct archive_write_filter *,
+		    const char *, const char *);
+static int archive_write_grzip_write(struct archive_write_filter *,
+		    const void *, size_t);
+static int archive_write_grzip_close(struct archive_write_filter *);
+static int archive_write_grzip_free(struct archive_write_filter *);
+
+int
+archive_write_add_filter_grzip(struct archive *_a)
+{
+	struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+	struct write_grzip *data;
+
+	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_write_add_filter_grzip");
+
+	data = calloc(1, sizeof(*data));
+	if (data == NULL) {
+		archive_set_error(_a, ENOMEM, "Can't allocate memory");
+		return (ARCHIVE_FATAL);
+	}
+	data->pdata = __archive_write_program_allocate();
+	if (data->pdata == NULL) {
+		free(data);
+		archive_set_error(_a, ENOMEM, "Can't allocate memory");
+		return (ARCHIVE_FATAL);
+	}
+
+	f->name = "grzip";
+	f->code = ARCHIVE_FILTER_GRZIP;
+	f->data = data;
+	f->open = archive_write_grzip_open;
+	f->options = archive_write_grzip_options;
+	f->write = archive_write_grzip_write;
+	f->close = archive_write_grzip_close;
+	f->free = archive_write_grzip_free;
+
+	/* Note: This filter always uses an external program, so we
+	 * return "warn" to inform of the fact. */
+	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+	    "Using external grzip program for grzip compression");
+	return (ARCHIVE_WARN);
+}
+
+static int
+archive_write_grzip_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+	(void)f; /* UNUSED */
+	(void)key; /* UNUSED */
+	(void)value; /* UNUSED */
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
+}
+
+static int
+archive_write_grzip_open(struct archive_write_filter *f)
+{
+	struct write_grzip *data = (struct write_grzip *)f->data;
+
+	return __archive_write_program_open(f, data->pdata, "grzip");
+}
+
+static int
+archive_write_grzip_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+	struct write_grzip *data = (struct write_grzip *)f->data;
+
+	return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_write_grzip_close(struct archive_write_filter *f)
+{
+	struct write_grzip *data = (struct write_grzip *)f->data;
+
+	return __archive_write_program_close(f, data->pdata);
+}
+
+static int
+archive_write_grzip_free(struct archive_write_filter *f)
+{
+	struct write_grzip *data = (struct write_grzip *)f->data;
+
+	__archive_write_program_free(data->pdata);
+	free(data);
+	return (ARCHIVE_OK);
+}
diff --git a/libarchive/archive_write_add_filter_gzip.c b/libarchive/archive_write_add_filter_gzip.c
index 786ae98..da4607b 100644
--- a/libarchive/archive_write_add_filter_gzip.c
+++ b/libarchive/archive_write_add_filter_gzip.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_gzip.c 201
 
 #include "archive.h"
 #include "archive_private.h"
+#include "archive_string.h"
 #include "archive_write_private.h"
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
@@ -54,24 +55,20 @@ archive_write_set_compression_gzip(struct archive *a)
 }
 #endif
 
-#ifndef HAVE_ZLIB_H
-int
-archive_write_add_filter_gzip(struct archive *a)
-{
-	archive_set_error(a, ARCHIVE_ERRNO_MISC,
-	    "gzip compression not supported on this platform");
-	return (ARCHIVE_FATAL);
-}
-#else
 /* Don't compile this if we don't have zlib. */
 
 struct private_data {
 	int		 compression_level;
+	int		 timestamp;
+#ifdef HAVE_ZLIB_H
 	z_stream	 stream;
 	int64_t		 total_in;
 	unsigned char	*compressed;
 	size_t		 compressed_buffer_size;
 	unsigned long	 crc;
+#else
+	struct archive_write_program_data *pdata;
+#endif
 };
 
 /*
@@ -88,8 +85,10 @@ static int archive_compressor_gzip_write(struct archive_write_filter *,
 		    const void *, size_t);
 static int archive_compressor_gzip_close(struct archive_write_filter *);
 static int archive_compressor_gzip_free(struct archive_write_filter *);
+#ifdef HAVE_ZLIB_H
 static int drive_compressor(struct archive_write_filter *,
 		    struct private_data *, int finishing);
+#endif
 
 
 /*
@@ -110,16 +109,72 @@ archive_write_add_filter_gzip(struct archive *_a)
 		return (ARCHIVE_FATAL);
 	}
 	f->data = data;
-	data->compression_level = Z_DEFAULT_COMPRESSION;
 	f->open = &archive_compressor_gzip_open;
 	f->options = &archive_compressor_gzip_options;
 	f->close = &archive_compressor_gzip_close;
 	f->free = &archive_compressor_gzip_free;
-	f->code = ARCHIVE_COMPRESSION_GZIP;
+	f->code = ARCHIVE_FILTER_GZIP;
 	f->name = "gzip";
+#ifdef HAVE_ZLIB_H
+	data->compression_level = Z_DEFAULT_COMPRESSION;
 	return (ARCHIVE_OK);
+#else
+	data->pdata = __archive_write_program_allocate();
+	if (data->pdata == NULL) {
+		free(data);
+		archive_set_error(&a->archive, ENOMEM, "Out of memory");
+		return (ARCHIVE_FATAL);
+	}
+	data->compression_level = 0;
+	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+	    "Using external gzip program");
+	return (ARCHIVE_WARN);
+#endif
 }
 
+static int
+archive_compressor_gzip_free(struct archive_write_filter *f)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+#ifdef HAVE_ZLIB_H
+	free(data->compressed);
+#else
+	__archive_write_program_free(data->pdata);
+#endif
+	free(data);
+	f->data = NULL;
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+	if (strcmp(key, "compression-level") == 0) {
+		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+		    value[1] != '\0')
+			return (ARCHIVE_WARN);
+		data->compression_level = value[0] - '0';
+		return (ARCHIVE_OK);
+	}
+	if (strcmp(key, "timestamp") == 0) {
+		data->timestamp = (value == NULL)?-1:1;
+		return (ARCHIVE_OK);
+	}
+
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
+}
+
+#ifdef HAVE_ZLIB_H
 /*
  * Setup callback.
  */
@@ -128,14 +183,23 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
 {
 	struct private_data *data = (struct private_data *)f->data;
 	int ret;
-	time_t t;
 
 	ret = __archive_write_open_filter(f->next_filter);
 	if (ret != ARCHIVE_OK)
 		return (ret);
 
 	if (data->compressed == NULL) {
-		data->compressed_buffer_size = 65536;
+		size_t bs = 65536, bpb;
+		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
+			/* Buffer size should be a multiple number of
+			 * the of bytes per block for performance. */
+			bpb = archive_write_get_bytes_per_block(f->archive);
+			if (bpb > bs)
+				bs = bpb;
+			else if (bpb != 0)
+				bs -= bs % bpb;
+		}
+		data->compressed_buffer_size = bs;
 		data->compressed
 		    = (unsigned char *)malloc(data->compressed_buffer_size);
 		if (data->compressed == NULL) {
@@ -147,18 +211,21 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
 
 	data->crc = crc32(0L, NULL, 0);
 	data->stream.next_out = data->compressed;
-	data->stream.avail_out = data->compressed_buffer_size;
+	data->stream.avail_out = (uInt)data->compressed_buffer_size;
 
 	/* Prime output buffer with a gzip header. */
-	t = time(NULL);
 	data->compressed[0] = 0x1f; /* GZip signature bytes */
 	data->compressed[1] = 0x8b;
 	data->compressed[2] = 0x08; /* "Deflate" compression */
 	data->compressed[3] = 0; /* No options */
-	data->compressed[4] = (t)&0xff;  /* Timestamp */
-	data->compressed[5] = (t>>8)&0xff;
-	data->compressed[6] = (t>>16)&0xff;
-	data->compressed[7] = (t>>24)&0xff;
+	if (data->timestamp >= 0) {
+		time_t t = time(NULL);
+		data->compressed[4] = (uint8_t)(t)&0xff;  /* Timestamp */
+		data->compressed[5] = (uint8_t)(t>>8)&0xff;
+		data->compressed[6] = (uint8_t)(t>>16)&0xff;
+		data->compressed[7] = (uint8_t)(t>>24)&0xff;
+	} else
+		memset(&data->compressed[4], 0, 4);
 	data->compressed[8] = 0; /* No deflate options */
 	data->compressed[9] = 3; /* OS=Unix */
 	data->stream.next_out += 10;
@@ -191,8 +258,8 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
 		    "compression library: invalid setup parameter");
 		break;
 	case Z_MEM_ERROR:
-		archive_set_error(f->archive, ENOMEM, "Internal error initializing "
-		    "compression library");
+		archive_set_error(f->archive, ENOMEM,
+		    "Internal error initializing compression library");
 		break;
 	case Z_VERSION_ERROR:
 		archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
@@ -205,25 +272,6 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
 }
 
 /*
- * Set write options.
- */
-static int
-archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
-    const char *value)
-{
-	struct private_data *data = (struct private_data *)f->data;
-
-	if (strcmp(key, "compression-level") == 0) {
-		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
-		    value[1] != '\0')
-			return (ARCHIVE_WARN);
-		data->compression_level = value[0] - '0';
-		return (ARCHIVE_OK);
-	}
-	return (ARCHIVE_WARN);
-}
-
-/*
  * Write data to the compressed stream.
  */
 static int
@@ -234,12 +282,12 @@ archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
 	int ret;
 
 	/* Update statistics */
-	data->crc = crc32(data->crc, (const Bytef *)buff, length);
+	data->crc = crc32(data->crc, (const Bytef *)buff, (uInt)length);
 	data->total_in += length;
 
 	/* Compress input data to output buffer */
 	SET_NEXT_IN(data, buff);
-	data->stream.avail_in = length;
+	data->stream.avail_in = (uInt)length;
 	if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)
 		return (ret);
 
@@ -266,14 +314,14 @@ archive_compressor_gzip_close(struct archive_write_filter *f)
 	}
 	if (ret == ARCHIVE_OK) {
 		/* Build and write out 8-byte trailer. */
-		trailer[0] = (data->crc)&0xff;
-		trailer[1] = (data->crc >> 8)&0xff;
-		trailer[2] = (data->crc >> 16)&0xff;
-		trailer[3] = (data->crc >> 24)&0xff;
-		trailer[4] = (data->total_in)&0xff;
-		trailer[5] = (data->total_in >> 8)&0xff;
-		trailer[6] = (data->total_in >> 16)&0xff;
-		trailer[7] = (data->total_in >> 24)&0xff;
+		trailer[0] = (uint8_t)(data->crc)&0xff;
+		trailer[1] = (uint8_t)(data->crc >> 8)&0xff;
+		trailer[2] = (uint8_t)(data->crc >> 16)&0xff;
+		trailer[3] = (uint8_t)(data->crc >> 24)&0xff;
+		trailer[4] = (uint8_t)(data->total_in)&0xff;
+		trailer[5] = (uint8_t)(data->total_in >> 8)&0xff;
+		trailer[6] = (uint8_t)(data->total_in >> 16)&0xff;
+		trailer[7] = (uint8_t)(data->total_in >> 24)&0xff;
 		ret = __archive_write_filter(f->next_filter, trailer, 8);
 	}
 
@@ -289,16 +337,6 @@ archive_compressor_gzip_close(struct archive_write_filter *f)
 	return (r1 < ret ? r1 : ret);
 }
 
-static int
-archive_compressor_gzip_free(struct archive_write_filter *f)
-{
-	struct private_data *data = (struct private_data *)f->data;
-	free(data->compressed);
-	free(data);
-	f->data = NULL;
-	return (ARCHIVE_OK);
-}
-
 /*
  * Utility function to push input data through compressor,
  * writing full output blocks as necessary.
@@ -320,7 +358,8 @@ drive_compressor(struct archive_write_filter *f,
 			if (ret != ARCHIVE_OK)
 				return (ARCHIVE_FATAL);
 			data->stream.next_out = data->compressed;
-			data->stream.avail_out = data->compressed_buffer_size;
+			data->stream.avail_out =
+			    (uInt)data->compressed_buffer_size;
 		}
 
 		/* If there's nothing to do, we're done. */
@@ -353,4 +392,51 @@ drive_compressor(struct archive_write_filter *f,
 	}
 }
 
+#else /* HAVE_ZLIB_H */
+
+static int
+archive_compressor_gzip_open(struct archive_write_filter *f)
+{
+	struct private_data *data = (struct private_data *)f->data;
+	struct archive_string as;
+	int r;
+
+	archive_string_init(&as);
+	archive_strcpy(&as, "gzip");
+
+	/* Specify compression level. */
+	if (data->compression_level > 0) {
+		archive_strcat(&as, " -");
+		archive_strappend_char(&as, '0' + data->compression_level);
+	}
+	if (data->timestamp < 0)
+		/* Do not save timestamp. */
+		archive_strcat(&as, " -n");
+	else if (data->timestamp > 0)
+		/* Save timestamp. */
+		archive_strcat(&as, " -N");
+
+	f->write = archive_compressor_gzip_write;
+	r = __archive_write_program_open(f, data->pdata, as.s);
+	archive_string_free(&as);
+	return (r);
+}
+
+static int
+archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
+    size_t length)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+	return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_compressor_gzip_close(struct archive_write_filter *f)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+	return __archive_write_program_close(f, data->pdata);
+}
+
 #endif /* HAVE_ZLIB_H */
diff --git a/libarchive/archive_write_add_filter_lrzip.c b/libarchive/archive_write_add_filter_lrzip.c
new file mode 100644
index 0000000..85fdf6a
--- /dev/null
+++ b/libarchive/archive_write_add_filter_lrzip.c
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_string.h"
+#include "archive_write_private.h"
+
+struct write_lrzip {
+	struct archive_write_program_data *pdata;
+	int	compression_level;
+	enum { lzma = 0, bzip2, gzip, lzo, zpaq } compression;
+};
+
+static int archive_write_lrzip_open(struct archive_write_filter *);
+static int archive_write_lrzip_options(struct archive_write_filter *,
+		    const char *, const char *);
+static int archive_write_lrzip_write(struct archive_write_filter *,
+		    const void *, size_t);
+static int archive_write_lrzip_close(struct archive_write_filter *);
+static int archive_write_lrzip_free(struct archive_write_filter *);
+
+int
+archive_write_add_filter_lrzip(struct archive *_a)
+{
+	struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+	struct write_lrzip *data;
+
+	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_write_add_filter_lrzip");
+
+	data = calloc(1, sizeof(*data));
+	if (data == NULL) {
+		archive_set_error(_a, ENOMEM, "Can't allocate memory");
+		return (ARCHIVE_FATAL);
+	}
+	data->pdata = __archive_write_program_allocate();
+	if (data->pdata == NULL) {
+		free(data);
+		archive_set_error(_a, ENOMEM, "Can't allocate memory");
+		return (ARCHIVE_FATAL);
+	}
+
+	f->name = "lrzip";
+	f->code = ARCHIVE_FILTER_LRZIP;
+	f->data = data;
+	f->open = archive_write_lrzip_open;
+	f->options = archive_write_lrzip_options;
+	f->write = archive_write_lrzip_write;
+	f->close = archive_write_lrzip_close;
+	f->free = archive_write_lrzip_free;
+
+	/* Note: This filter always uses an external program, so we
+	 * return "warn" to inform of the fact. */
+	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+	    "Using external lrzip program for lrzip compression");
+	return (ARCHIVE_WARN);
+}
+
+static int
+archive_write_lrzip_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+	struct write_lrzip *data = (struct write_lrzip *)f->data;
+
+	if (strcmp(key, "compression") == 0) {
+		if (value == NULL)
+			return (ARCHIVE_WARN);
+		else if (strcmp(value, "bzip2") == 0)
+			data->compression = bzip2;
+		else if (strcmp(value, "gzip") == 0)
+			data->compression = gzip;
+		else if (strcmp(value, "lzo") == 0)
+			data->compression = lzo;
+		else if (strcmp(value, "zpaq") == 0)
+			data->compression = zpaq;
+		else
+			return (ARCHIVE_WARN);
+		return (ARCHIVE_OK);
+	} else if (strcmp(key, "compression-level") == 0) {
+		if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||
+		    value[1] != '\0')
+			return (ARCHIVE_WARN);
+		data->compression_level = value[0] - '0';
+		return (ARCHIVE_OK);
+	}
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
+}
+
+static int
+archive_write_lrzip_open(struct archive_write_filter *f)
+{
+	struct write_lrzip *data = (struct write_lrzip *)f->data;
+	struct archive_string as;
+	int r;
+
+	archive_string_init(&as);
+	archive_strcpy(&as, "lrzip -q");
+
+	/* Specify compression type. */
+	switch (data->compression) {
+	case lzma:/* default compression */
+		break;
+	case bzip2:
+		archive_strcat(&as, " -b");
+		break;
+	case gzip:
+		archive_strcat(&as, " -g");
+		break;
+	case lzo:
+		archive_strcat(&as, " -l");
+		break;
+	case zpaq:
+		archive_strcat(&as, " -z");
+		break;
+	}
+
+	/* Specify compression level. */
+	if (data->compression_level > 0) {
+		archive_strcat(&as, " -L ");
+		archive_strappend_char(&as, '0' + data->compression_level);
+	}
+
+	r = __archive_write_program_open(f, data->pdata, as.s);
+	archive_string_free(&as);
+	return (r);
+}
+
+static int
+archive_write_lrzip_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+	struct write_lrzip *data = (struct write_lrzip *)f->data;
+
+	return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_write_lrzip_close(struct archive_write_filter *f)
+{
+	struct write_lrzip *data = (struct write_lrzip *)f->data;
+
+	return __archive_write_program_close(f, data->pdata);
+}
+
+static int
+archive_write_lrzip_free(struct archive_write_filter *f)
+{
+	struct write_lrzip *data = (struct write_lrzip *)f->data;
+
+	__archive_write_program_free(data->pdata);
+	free(data);
+	return (ARCHIVE_OK);
+}
diff --git a/libarchive/archive_write_add_filter_lzop.c b/libarchive/archive_write_add_filter_lzop.c
new file mode 100644
index 0000000..088ecea
--- /dev/null
+++ b/libarchive/archive_write_add_filter_lzop.c
@@ -0,0 +1,486 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+//#undef HAVE_LZO_LZOCONF_H
+//#undef HAVE_LZO_LZO1X_H
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <time.h>
+#ifdef HAVE_LZO_LZOCONF_H
+#include <lzo/lzoconf.h>
+#endif
+#ifdef HAVE_LZO_LZO1X_H
+#include <lzo/lzo1x.h>
+#endif
+
+#include "archive.h"
+#include "archive_string.h"
+#include "archive_endian.h"
+#include "archive_write_private.h"
+
+enum lzo_method {
+	METHOD_LZO1X_1 = 1,
+	METHOD_LZO1X_1_15 = 2,
+	METHOD_LZO1X_999 = 3
+};
+struct write_lzop {
+	int compression_level;
+#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+	unsigned char	*uncompressed;
+	size_t		 uncompressed_buffer_size;
+	size_t		 uncompressed_avail_bytes;
+	unsigned char	*compressed;
+	size_t		 compressed_buffer_size;
+	enum lzo_method	 method;
+	unsigned char	 level;
+	lzo_voidp	 work_buffer;
+	lzo_uint32	 work_buffer_size;
+	char		 header_written;
+#else
+	struct archive_write_program_data *pdata;
+#endif
+};
+
+static int archive_write_lzop_open(struct archive_write_filter *);
+static int archive_write_lzop_options(struct archive_write_filter *,
+		    const char *, const char *);
+static int archive_write_lzop_write(struct archive_write_filter *,
+		    const void *, size_t);
+static int archive_write_lzop_close(struct archive_write_filter *);
+static int archive_write_lzop_free(struct archive_write_filter *);
+
+#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+/* Maximum block size. */
+#define BLOCK_SIZE			(256 * 1024)
+/* Block infomation is composed of uncompressed size(4 bytes),
+ * compressed size(4 bytes) and the checksum of uncompressed data(4 bytes)
+ * in this lzop writer. */
+#define BLOCK_INfO_SIZE			12
+
+#define HEADER_VERSION			9
+#define HEADER_LIBVERSION		11
+#define HEADER_METHOD			15
+#define HEADER_LEVEL			16
+#define HEADER_MTIME_LOW		25
+#define HEADER_MTIME_HIGH		29
+#define HEADER_H_CHECKSUM		34
+
+/*
+ * Header template.
+ */
+static const unsigned char header[] = {
+	/* LZOP Magic code 9 bytes */
+	0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a,
+	/* LZOP utility version(fake data) 2 bytes */
+	0x10, 0x30,
+	/* LZO library version 2 bytes */
+	0x09, 0x40,
+	/* Minimum required LZO library version 2 bytes */
+	0x09, 0x40,
+	/* Method */
+	1,
+	/* Level */
+	5,
+	/* Flags 4 bytes
+	 *  -OS Unix
+	 *  -Stdout
+	 *  -Stdin
+	 *  -Adler32 used for uncompressed data 4 bytes */
+	0x03, 0x00, 0x00, 0x0d,
+	/* Mode (AE_IFREG | 0644) 4 bytes */
+	0x00, 0x00, 0x81, 0xa4,
+	/* Mtime low 4 bytes */
+	0x00, 0x00, 0x00, 0x00,
+	/* Mtime high 4 bytes */
+	0x00, 0x00, 0x00, 0x00,
+	/* Filename length */
+	0x00,
+	/* Header checksum 4 bytes */
+	0x00, 0x00, 0x00, 0x00,
+};
+#endif
+
+int
+archive_write_add_filter_lzop(struct archive *_a)
+{
+	struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+	struct write_lzop *data;
+
+	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_write_add_filter_lzop");
+
+	data = calloc(1, sizeof(*data));
+	if (data == NULL) {
+		archive_set_error(_a, ENOMEM, "Can't allocate memory");
+		return (ARCHIVE_FATAL);
+	}
+
+	f->name = "lzop";
+	f->code = ARCHIVE_FILTER_LZOP;
+	f->data = data;
+	f->open = archive_write_lzop_open;
+	f->options = archive_write_lzop_options;
+	f->write = archive_write_lzop_write;
+	f->close = archive_write_lzop_close;
+	f->free = archive_write_lzop_free;
+#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+	if (lzo_init() != LZO_E_OK) {
+		free(data);
+		archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+		    "lzo_init(type check) failed");
+		return (ARCHIVE_FATAL);
+	}
+	if (lzo_version() < 0x940) {
+		free(data);
+		archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+		    "liblzo library is too old(%s < 0.940)",
+		    lzo_version_string());
+		return (ARCHIVE_FATAL);
+	}
+	data->compression_level = 5;
+	return (ARCHIVE_OK);
+#else
+	data->pdata = __archive_write_program_allocate();
+	if (data->pdata == NULL) {
+		free(data);
+		archive_set_error(_a, ENOMEM, "Can't allocate memory");
+		return (ARCHIVE_FATAL);
+	}
+	data->compression_level = 0;
+	/* Note: We return "warn" to inform of using an external lzop
+	 * program. */
+	archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+	    "Using external lzop program for lzop compression");
+	return (ARCHIVE_WARN);
+#endif
+}
+
+static int
+archive_write_lzop_free(struct archive_write_filter *f)
+{
+	struct write_lzop *data = (struct write_lzop *)f->data;
+
+#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+	free(data->uncompressed);
+	free(data->compressed);
+	free(data->work_buffer);
+#else
+	__archive_write_program_free(data->pdata);
+#endif
+	free(data);
+	return (ARCHIVE_OK);
+}
+
+static int
+archive_write_lzop_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+	struct write_lzop *data = (struct write_lzop *)f->data;
+
+	if (strcmp(key, "compression-level") == 0) {
+		if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||
+		    value[1] != '\0')
+			return (ARCHIVE_WARN);
+		data->compression_level = value[0] - '0';
+		return (ARCHIVE_OK);
+	}
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
+}
+
+#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+static int
+archive_write_lzop_open(struct archive_write_filter *f)
+{
+	struct write_lzop *data = (struct write_lzop *)f->data;
+	int ret;
+
+	ret = __archive_write_open_filter(f->next_filter);
+	if (ret != ARCHIVE_OK)
+		return (ret);
+
+	switch (data->compression_level) {
+	case 1:
+		data->method = METHOD_LZO1X_1_15; data->level = 1; break;
+	default:
+	case 2: case 3: case 4: case 5: case 6:
+		data->method = METHOD_LZO1X_1; data->level = 5; break;
+	case 7:
+		data->method = METHOD_LZO1X_999; data->level = 7; break;
+	case 8:
+		data->method = METHOD_LZO1X_999; data->level = 8; break;
+	case 9:
+		data->method = METHOD_LZO1X_999; data->level = 9; break;
+	}
+	switch (data->method) {
+	case METHOD_LZO1X_1:
+		data->work_buffer_size = LZO1X_1_MEM_COMPRESS; break;
+	case METHOD_LZO1X_1_15:
+		data->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break;
+	case METHOD_LZO1X_999:
+		data->work_buffer_size = LZO1X_999_MEM_COMPRESS; break;
+	}
+	if (data->work_buffer == NULL) {
+		data->work_buffer = (lzo_voidp)malloc(data->work_buffer_size);
+		if (data->work_buffer == NULL) {
+			archive_set_error(f->archive, ENOMEM,
+			    "Can't allocate data for compression buffer");
+			return (ARCHIVE_FATAL);
+		}
+	}
+	if (data->compressed == NULL) {
+		data->compressed_buffer_size = sizeof(header) +
+		    BLOCK_SIZE + (BLOCK_SIZE >> 4) + 64 + 3;
+		data->compressed = (unsigned char *)
+		    malloc(data->compressed_buffer_size);
+		if (data->compressed == NULL) {
+			archive_set_error(f->archive, ENOMEM,
+			    "Can't allocate data for compression buffer");
+			return (ARCHIVE_FATAL);
+		}
+	}
+	if (data->uncompressed == NULL) {
+		data->uncompressed_buffer_size = BLOCK_SIZE;
+		data->uncompressed = (unsigned char *)
+		    malloc(data->uncompressed_buffer_size);
+		if (data->uncompressed == NULL) {
+			archive_set_error(f->archive, ENOMEM,
+			    "Can't allocate data for compression buffer");
+			return (ARCHIVE_FATAL);
+		}
+		data->uncompressed_avail_bytes = BLOCK_SIZE;
+	}
+	return (ARCHIVE_OK);
+}
+
+static int
+make_header(struct archive_write_filter *f)
+{
+	struct write_lzop *data = (struct write_lzop *)f->data;
+	int64_t t;
+	uint32_t checksum;
+
+	memcpy(data->compressed, header, sizeof(header));
+	/* Overwrite library version. */
+	data->compressed[HEADER_LIBVERSION] = (unsigned char )
+	    (lzo_version() >> 8) & 0xff;
+	data->compressed[HEADER_LIBVERSION + 1] = (unsigned char )
+	    lzo_version() & 0xff;
+	/* Overwrite method and level. */
+	data->compressed[HEADER_METHOD] = (unsigned char)data->method;
+	data->compressed[HEADER_LEVEL] = data->level;
+	/* Overwrite mtime with current time. */
+	t = (int64_t)time(NULL);
+	archive_be32enc(&data->compressed[HEADER_MTIME_LOW],
+	    (uint32_t)(t & 0xffffffff));
+	archive_be32enc(&data->compressed[HEADER_MTIME_HIGH],
+	    (uint32_t)((t >> 32) & 0xffffffff));
+	/* Overwrite header checksum with calculated value. */
+	checksum = lzo_adler32(1, data->compressed + HEADER_VERSION,
+			(lzo_uint)(HEADER_H_CHECKSUM - HEADER_VERSION));
+	archive_be32enc(&data->compressed[HEADER_H_CHECKSUM], checksum);
+	return (sizeof(header));
+}
+
+static int
+drive_compressor(struct archive_write_filter *f)
+{
+	struct write_lzop *data = (struct write_lzop *)f->data;
+	unsigned char *p;
+	const int block_info_bytes = 12;
+	int header_bytes, r;
+	lzo_uint usize, csize;
+	uint32_t checksum;
+
+	if (!data->header_written) {
+		header_bytes = make_header(f);
+		data->header_written = 1;
+	} else
+		header_bytes = 0;
+	p = data->compressed;
+
+	usize = (lzo_uint)
+	    (data->uncompressed_buffer_size - data->uncompressed_avail_bytes);
+	csize = 0;
+	switch (data->method) {
+	default:
+	case METHOD_LZO1X_1:
+		r = lzo1x_1_compress(data->uncompressed, usize,
+			p + header_bytes + block_info_bytes, &csize,
+			data->work_buffer);
+		break;
+	case METHOD_LZO1X_1_15:
+		r = lzo1x_1_15_compress(data->uncompressed, usize,
+			p + header_bytes + block_info_bytes, &csize,
+			data->work_buffer);
+		break;
+	case METHOD_LZO1X_999:
+		r = lzo1x_999_compress_level(data->uncompressed, usize,
+			p + header_bytes + block_info_bytes, &csize,
+			data->work_buffer, NULL, 0, 0, data->level);
+		break;
+	}
+	if (r != LZO_E_OK) {
+		archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+		    "Lzop compression failed: returned status %d", r);
+		return (ARCHIVE_FATAL);
+	}
+
+	/* Store uncompressed size. */
+	archive_be32enc(p + header_bytes, (uint32_t)usize);
+	/* Store the checksum of the uncompressed data. */
+	checksum = lzo_adler32(1, data->uncompressed, usize);
+	archive_be32enc(p + header_bytes + 8, checksum);
+
+	if (csize < usize) {
+		/* Store compressed size. */
+		archive_be32enc(p + header_bytes + 4, (uint32_t)csize);
+		r = __archive_write_filter(f->next_filter, data->compressed,
+			header_bytes + block_info_bytes + csize);
+	} else {
+		/*
+		 * This case, we output uncompressed data instead.
+		 */
+		/* Store uncompressed size as compressed size. */
+		archive_be32enc(p + header_bytes + 4, (uint32_t)usize);
+		r = __archive_write_filter(f->next_filter, data->compressed,
+			header_bytes + block_info_bytes);
+		if (r != ARCHIVE_OK)
+			return (ARCHIVE_FATAL);
+		r = __archive_write_filter(f->next_filter, data->uncompressed,
+			usize);
+	}
+
+	if (r != ARCHIVE_OK)
+		return (ARCHIVE_FATAL);
+	return (ARCHIVE_OK);
+}
+
+static int
+archive_write_lzop_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+	struct write_lzop *data = (struct write_lzop *)f->data;
+	const char *p = buff;
+	int r;
+
+	do {
+		if (data->uncompressed_avail_bytes > length) {
+			memcpy(data->uncompressed
+				+ data->uncompressed_buffer_size
+				- data->uncompressed_avail_bytes,
+			    p, length);
+			data->uncompressed_avail_bytes -= length;
+			return (ARCHIVE_OK);
+		}
+
+		memcpy(data->uncompressed + data->uncompressed_buffer_size
+			- data->uncompressed_avail_bytes,
+		    p, data->uncompressed_avail_bytes);
+		length -= data->uncompressed_avail_bytes;
+		p += data->uncompressed_avail_bytes;
+		data->uncompressed_avail_bytes = 0;
+
+		r = drive_compressor(f);
+		if (r != ARCHIVE_OK) return (r);
+		data->uncompressed_avail_bytes = BLOCK_SIZE;
+	} while (length);
+
+	return (ARCHIVE_OK);
+}
+
+static int
+archive_write_lzop_close(struct archive_write_filter *f)
+{
+	struct write_lzop *data = (struct write_lzop *)f->data;
+	const uint32_t endmark = 0;
+	int r;
+
+	if (data->uncompressed_avail_bytes < BLOCK_SIZE) {
+		/* Compress and output remaining data. */
+		r = drive_compressor(f);
+		if (r != ARCHIVE_OK)
+			return (r);
+	}
+	/* Write a zero uncompressed size as the end mark of the series of
+	 * compressed block. */
+	r = __archive_write_filter(f->next_filter, &endmark, sizeof(endmark));
+	if (r != ARCHIVE_OK)
+		return (r);
+	return (__archive_write_close_filter(f->next_filter));
+}
+
+#else
+static int
+archive_write_lzop_open(struct archive_write_filter *f)
+{
+	struct write_lzop *data = (struct write_lzop *)f->data;
+	struct archive_string as;
+	int r;
+
+	archive_string_init(&as);
+	archive_strcpy(&as, "lzop");
+	/* Specify compression level. */
+	if (data->compression_level > 0) {
+		archive_strappend_char(&as, ' ');
+		archive_strappend_char(&as, '-');
+		archive_strappend_char(&as, '0' + data->compression_level);
+	}
+
+	r = __archive_write_program_open(f, data->pdata, as.s);
+	archive_string_free(&as);
+	return (r);
+}
+
+static int
+archive_write_lzop_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+	struct write_lzop *data = (struct write_lzop *)f->data;
+
+	return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_write_lzop_close(struct archive_write_filter *f)
+{
+	struct write_lzop *data = (struct write_lzop *)f->data;
+
+	return __archive_write_program_close(f, data->pdata);
+}
+#endif
diff --git a/libarchive/archive_write_add_filter_program.c b/libarchive/archive_write_add_filter_program.c
index 3dcc9df..fc232da 100644
--- a/libarchive/archive_write_add_filter_program.c
+++ b/libarchive/archive_write_add_filter_program.c
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2007 Joerg Sonnenberger
+ * Copyright (c) 2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,7 +45,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_program.c
 
 #include "archive.h"
 #include "archive_private.h"
+#include "archive_string.h"
 #include "archive_write_private.h"
+#include "filter_fork.h"
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
 int
@@ -55,36 +58,24 @@ archive_write_set_compression_program(struct archive *a, const char *cmd)
 }
 #endif
 
-/* This capability is only available on POSIX systems. */
-#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
-    !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && (!defined(_WIN32) || defined(__CYGWIN__))
-
-/*
- * On non-Posix systems, allow the program to build, but choke if
- * this function is actually invoked.
- */
-int
-archive_write_add_filter_program(struct archive *_a, const char *cmd)
-{
-	archive_set_error(_a, -1,
-	    "External compression programs not supported on this platform");
-	return (ARCHIVE_FATAL);
-}
-
+struct archive_write_program_data {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	HANDLE		 child;
 #else
-
-#include "filter_fork.h"
-
-struct private_data {
-	char		*cmd;
-	char		*description;
 	pid_t		 child;
+#endif
 	int		 child_stdin, child_stdout;
 
 	char		*child_buf;
 	size_t		 child_buf_len, child_buf_avail;
 };
 
+struct private_data {
+	struct archive_write_program_data *pdata;
+	struct archive_string description;
+	char		*cmd;
+};
+
 static int archive_compressor_program_open(struct archive_write_filter *);
 static int archive_compressor_program_write(struct archive_write_filter *,
 		    const void *, size_t);
@@ -99,35 +90,125 @@ int
 archive_write_add_filter_program(struct archive *_a, const char *cmd)
 {
 	struct archive_write_filter *f = __archive_write_allocate_filter(_a);
-	struct archive_write *a = (struct archive_write *)_a;
 	struct private_data *data;
 	static const char *prefix = "Program: ";
-	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+
+	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_program");
-	data = calloc(1, sizeof(*data));
-	if (data == NULL) {
-		archive_set_error(&a->archive, ENOMEM, "Out of memory");
-		return (ARCHIVE_FATAL);
-	}
+
+	f->data = calloc(1, sizeof(*data));
+	if (f->data == NULL)
+		goto memerr;
+	data = (struct private_data *)f->data;
+
 	data->cmd = strdup(cmd);
-	data->description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
-	strcpy(data->description, prefix);
-	strcat(data->description, cmd);
-
-	f->name = data->description;
-	f->data = data;
-	f->open = &archive_compressor_program_open;
-	f->code = ARCHIVE_COMPRESSION_PROGRAM;
+	if (data->cmd == NULL)
+		goto memerr;
+
+	data->pdata = __archive_write_program_allocate();
+	if (data->pdata == NULL)
+		goto memerr;
+
+	/* Make up a description string. */
+	if (archive_string_ensure(&data->description,
+	    strlen(prefix) + strlen(cmd) + 1) == NULL)
+		goto memerr;
+	archive_strcpy(&data->description, prefix);
+	archive_strcat(&data->description, cmd);
+
+	f->name = data->description.s;
+	f->code = ARCHIVE_FILTER_PROGRAM;
+	f->open = archive_compressor_program_open;
+	f->write = archive_compressor_program_write;
+	f->close = archive_compressor_program_close;
+	f->free = archive_compressor_program_free;
 	return (ARCHIVE_OK);
+memerr:
+	archive_compressor_program_free(f);
+	archive_set_error(_a, ENOMEM,
+	    "Can't allocate memory for filter program");
+	return (ARCHIVE_FATAL);
 }
 
-/*
- * Setup callback.
- */
 static int
 archive_compressor_program_open(struct archive_write_filter *f)
 {
 	struct private_data *data = (struct private_data *)f->data;
+
+	return __archive_write_program_open(f, data->pdata, data->cmd);
+}
+
+static int
+archive_compressor_program_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+	return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_compressor_program_close(struct archive_write_filter *f)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+	return __archive_write_program_close(f, data->pdata);
+}
+
+static int
+archive_compressor_program_free(struct archive_write_filter *f)
+{
+	struct private_data *data = (struct private_data *)f->data;
+
+	if (data) {
+		free(data->cmd);
+		archive_string_free(&data->description);
+		__archive_write_program_free(data->pdata);
+		free(data);
+		f->data = NULL;
+	}
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Allocate resources for executing an external program.
+ */
+struct archive_write_program_data *
+__archive_write_program_allocate(void)
+{
+	struct archive_write_program_data *data;
+
+	data = calloc(1, sizeof(struct archive_write_program_data));
+	if (data == NULL)
+		return (data);
+	data->child_stdin = -1;
+	data->child_stdout = -1;
+	return (data);
+}
+
+/*
+ * Release the resources.
+ */
+int
+__archive_write_program_free(struct archive_write_program_data *data)
+{
+
+	if (data) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+		if (data->child)
+			CloseHandle(data->child);
+#endif
+		free(data->child_buf);
+		free(data);
+	}
+	return (ARCHIVE_OK);
+}
+
+int
+__archive_write_program_open(struct archive_write_filter *f,
+    struct archive_write_program_data *data, const char *cmd)
+{
+	pid_t child;
 	int ret;
 
 	ret = __archive_write_open_filter(f->next_filter);
@@ -146,23 +227,34 @@ archive_compressor_program_open(struct archive_write_filter *f)
 		}
 	}
 
-	if ((data->child = __archive_create_child(data->cmd,
-		 &data->child_stdin, &data->child_stdout)) == -1) {
+	child = __archive_create_child(cmd, &data->child_stdin,
+		    &data->child_stdout);
+	if (child == -1) {
 		archive_set_error(f->archive, EINVAL,
 		    "Can't initialise filter");
 		return (ARCHIVE_FATAL);
 	}
-
-	f->write = archive_compressor_program_write;
-	f->close = archive_compressor_program_close;
-	f->free = archive_compressor_program_free;
-	return (0);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	data->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child);
+	if (data->child == NULL) {
+		close(data->child_stdin);
+		data->child_stdin = -1;
+		close(data->child_stdout);
+		data->child_stdout = -1;
+		archive_set_error(f->archive, EINVAL,
+		    "Can't initialise filter");
+		return (ARCHIVE_FATAL);
+	}
+#else
+	data->child = child;
+#endif
+	return (ARCHIVE_OK);
 }
 
 static ssize_t
-child_write(struct archive_write_filter *f, const char *buf, size_t buf_len)
+child_write(struct archive_write_filter *f,
+    struct archive_write_program_data *data, const char *buf, size_t buf_len)
 {
-	struct private_data *data = f->data;
 	ssize_t ret;
 
 	if (data->child_stdin == -1)
@@ -171,75 +263,75 @@ child_write(struct archive_write_filter *f, const char *buf, size_t buf_len)
 	if (buf_len == 0)
 		return (-1);
 
-restart_write:
-	do {
-		ret = write(data->child_stdin, buf, buf_len);
-	} while (ret == -1 && errno == EINTR);
-
-	if (ret > 0)
-		return (ret);
-	if (ret == 0) {
-		close(data->child_stdin);
-		data->child_stdin = -1;
-		fcntl(data->child_stdout, F_SETFL, 0);
-		return (0);
-	}
-	if (ret == -1 && errno != EAGAIN)
-		return (-1);
-
-	if (data->child_stdout == -1) {
-		fcntl(data->child_stdin, F_SETFL, 0);
-		__archive_check_child(data->child_stdin, data->child_stdout);
-		goto restart_write;
-	}
-
-	do {
-		ret = read(data->child_stdout,
-		    data->child_buf + data->child_buf_avail,
-		    data->child_buf_len - data->child_buf_avail);
-	} while (ret == -1 && errno == EINTR);
+	for (;;) {
+		do {
+			ret = write(data->child_stdin, buf, buf_len);
+		} while (ret == -1 && errno == EINTR);
+
+		if (ret > 0)
+			return (ret);
+		if (ret == 0) {
+			close(data->child_stdin);
+			data->child_stdin = -1;
+			fcntl(data->child_stdout, F_SETFL, 0);
+			return (0);
+		}
+		if (ret == -1 && errno != EAGAIN)
+			return (-1);
+
+		if (data->child_stdout == -1) {
+			fcntl(data->child_stdin, F_SETFL, 0);
+			__archive_check_child(data->child_stdin,
+				data->child_stdout);
+			continue;
+		}
 
-	if (ret == 0 || (ret == -1 && errno == EPIPE)) {
-		close(data->child_stdout);
-		data->child_stdout = -1;
-		fcntl(data->child_stdin, F_SETFL, 0);
-		goto restart_write;
-	}
-	if (ret == -1 && errno == EAGAIN) {
-		__archive_check_child(data->child_stdin, data->child_stdout);
-		goto restart_write;
-	}
-	if (ret == -1)
-		return (-1);
+		do {
+			ret = read(data->child_stdout,
+			    data->child_buf + data->child_buf_avail,
+			    data->child_buf_len - data->child_buf_avail);
+		} while (ret == -1 && errno == EINTR);
 
-	data->child_buf_avail += ret;
+		if (ret == 0 || (ret == -1 && errno == EPIPE)) {
+			close(data->child_stdout);
+			data->child_stdout = -1;
+			fcntl(data->child_stdin, F_SETFL, 0);
+			continue;
+		}
+		if (ret == -1 && errno == EAGAIN) {
+			__archive_check_child(data->child_stdin,
+				data->child_stdout);
+			continue;
+		}
+		if (ret == -1)
+			return (-1);
 
-	ret = __archive_write_filter(f->next_filter,
-	    data->child_buf, data->child_buf_avail);
-	if (ret <= 0)
-		return (-1);
+		data->child_buf_avail += ret;
 
-	if ((size_t)ret < data->child_buf_avail) {
-		memmove(data->child_buf, data->child_buf + ret,
-		    data->child_buf_avail - ret);
+		ret = __archive_write_filter(f->next_filter,
+		    data->child_buf, data->child_buf_avail);
+		if (ret != ARCHIVE_OK)
+			return (-1);
+		data->child_buf_avail = 0;
 	}
-	data->child_buf_avail -= ret;
-	goto restart_write;
 }
 
 /*
- * Write data to the compressed stream.
+ * Write data to the filter stream.
  */
-static int
-archive_compressor_program_write(struct archive_write_filter *f,
-    const void *buff, size_t length)
+int
+__archive_write_program_write(struct archive_write_filter *f,
+    struct archive_write_program_data *data, const void *buff, size_t length)
 {
 	ssize_t ret;
 	const char *buf;
 
+	if (data->child == 0)
+		return (ARCHIVE_OK);
+
 	buf = buff;
 	while (length > 0) {
-		ret = child_write(f, buf, length);
+		ret = child_write(f, data, buf, length);
 		if (ret == -1 || ret == 0) {
 			archive_set_error(f->archive, EIO,
 			    "Can't write to filter");
@@ -251,17 +343,19 @@ archive_compressor_program_write(struct archive_write_filter *f,
 	return (ARCHIVE_OK);
 }
 
-
 /*
- * Finish the compression...
+ * Finish the filtering...
  */
-static int
-archive_compressor_program_close(struct archive_write_filter *f)
+int
+__archive_write_program_close(struct archive_write_filter *f,
+    struct archive_write_program_data *data)
 {
-	struct private_data *data = (struct private_data *)f->data;
 	int ret, r1, status;
 	ssize_t bytes_read;
 
+	if (data->child == 0)
+		return __archive_write_close_filter(f->next_filter);
+
 	ret = 0;
 	close(data->child_stdin);
 	data->child_stdin = -1;
@@ -302,6 +396,10 @@ cleanup:
 		close(data->child_stdout);
 	while (waitpid(data->child, &status, 0) == -1 && errno == EINTR)
 		continue;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	CloseHandle(data->child);
+#endif
+	data->child = 0;
 
 	if (status != 0) {
 		archive_set_error(f->archive, EIO,
@@ -312,16 +410,3 @@ cleanup:
 	return (r1 < ret ? r1 : ret);
 }
 
-static int
-archive_compressor_program_free(struct archive_write_filter *f)
-{
-	struct private_data *data = (struct private_data *)f->data;
-	free(data->cmd);
-	free(data->description);
-	free(data->child_buf);
-	free(data);
-	f->data = NULL;
-	return (ARCHIVE_OK);
-}
-
-#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */
diff --git a/libarchive/archive_write_add_filter_uuencode.c b/libarchive/archive_write_add_filter_uuencode.c
new file mode 100644
index 0000000..23d9c15
--- /dev/null
+++ b/libarchive/archive_write_add_filter_uuencode.c
@@ -0,0 +1,305 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_string.h"
+#include "archive_write_private.h"
+
+#define LBYTES 45
+
+struct private_uuencode {
+	int			mode;
+	struct archive_string	name;
+	struct archive_string	encoded_buff;
+	size_t			bs;
+	size_t			hold_len;
+	unsigned char		hold[LBYTES];
+};
+
+static int archive_filter_uuencode_options(struct archive_write_filter *,
+    const char *, const char *);
+static int archive_filter_uuencode_open(struct archive_write_filter *);
+static int archive_filter_uuencode_write(struct archive_write_filter *,
+    const void *, size_t);
+static int archive_filter_uuencode_close(struct archive_write_filter *);
+static int archive_filter_uuencode_free(struct archive_write_filter *);
+static void uu_encode(struct archive_string *, const unsigned char *, size_t);
+static int64_t atol8(const char *, size_t);
+
+/*
+ * Add a compress filter to this write handle.
+ */
+int
+archive_write_add_filter_uuencode(struct archive *_a)
+{
+	struct archive_write *a = (struct archive_write *)_a;
+	struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+	struct private_uuencode *state;
+
+	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");
+
+	state = (struct private_uuencode *)calloc(1, sizeof(*state));
+	if (state == NULL) {
+		archive_set_error(f->archive, ENOMEM,
+		    "Can't allocate data for uuencode filter");
+		return (ARCHIVE_FATAL);
+	}
+	archive_strcpy(&state->name, "-");
+	state->mode = 0644;
+
+	f->data = state;
+	f->name = "uuencode";
+	f->code = ARCHIVE_FILTER_UU;
+	f->open = archive_filter_uuencode_open;
+	f->options = archive_filter_uuencode_options;
+	f->write = archive_filter_uuencode_write;
+	f->close = archive_filter_uuencode_close;
+	f->free = archive_filter_uuencode_free;
+
+	return (ARCHIVE_OK);
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+	struct private_uuencode *state = (struct private_uuencode *)f->data;
+
+	if (strcmp(key, "mode") == 0) {
+		if (value == NULL) {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "mode option requires octal digits");
+			return (ARCHIVE_FAILED);
+		}
+		state->mode = (int)atol8(value, strlen(value)) & 0777;
+		return (ARCHIVE_OK);
+	} else if (strcmp(key, "name") == 0) {
+		if (value == NULL) {
+			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+			    "name option requires a string");
+			return (ARCHIVE_FAILED);
+		}
+		archive_strcpy(&state->name, value);
+		return (ARCHIVE_OK);
+	}
+
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_filter_uuencode_open(struct archive_write_filter *f)
+{
+	struct private_uuencode *state = (struct private_uuencode *)f->data;
+	size_t bs = 65536, bpb;
+	int ret;
+
+	ret = __archive_write_open_filter(f->next_filter);
+	if (ret != ARCHIVE_OK)
+		return (ret);
+
+	if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
+		/* Buffer size should be a multiple number of the of bytes
+		 * per block for performance. */
+		bpb = archive_write_get_bytes_per_block(f->archive);
+		if (bpb > bs)
+			bs = bpb;
+		else if (bpb != 0)
+			bs -= bs % bpb;
+	}
+
+	state->bs = bs;
+	if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
+		archive_set_error(f->archive, ENOMEM,
+		    "Can't allocate data for uuencode buffer");
+		return (ARCHIVE_FATAL);
+	}
+
+	archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",
+	    state->mode, state->name.s);
+
+	f->data = state;
+	return (0);
+}
+
+static void
+uu_encode(struct archive_string *as, const unsigned char *p, size_t len)
+{
+	int c;
+
+	c = (int)len;
+	archive_strappend_char(as, c?c + 0x20:'`');
+	for (; len >= 3; p += 3, len -= 3) {
+		c = p[0] >> 2;
+		archive_strappend_char(as, c?c + 0x20:'`');
+		c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4);
+		archive_strappend_char(as, c?c + 0x20:'`');
+		c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6);
+		archive_strappend_char(as, c?c + 0x20:'`');
+		c = p[2] & 0x3f;
+		archive_strappend_char(as, c?c + 0x20:'`');
+	}
+	if (len > 0) {
+		c = p[0] >> 2;
+		archive_strappend_char(as, c?c + 0x20:'`');
+		c = (p[0] & 0x03) << 4;
+		if (len == 1) {
+			archive_strappend_char(as, c?c + 0x20:'`');
+			archive_strappend_char(as, '`');
+			archive_strappend_char(as, '`');
+		} else {
+			c |= (p[1] & 0xf0) >> 4;
+			archive_strappend_char(as, c?c + 0x20:'`');
+			c = (p[1] & 0x0f) << 2;
+			archive_strappend_char(as, c?c + 0x20:'`');
+			archive_strappend_char(as, '`');
+		}
+	}
+	archive_strappend_char(as, '\n');
+}
+
+/*
+ * Write data to the encoded stream.
+ */
+static int
+archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff,
+    size_t length)
+{
+	struct private_uuencode *state = (struct private_uuencode *)f->data;
+	const unsigned char *p = buff;
+	int ret = ARCHIVE_OK;
+
+	if (length == 0)
+		return (ret);
+
+	if (state->hold_len) {
+		while (state->hold_len < LBYTES && length > 0) {
+			state->hold[state->hold_len++] = *p++;
+			length--;
+		}
+		if (state->hold_len < LBYTES)
+			return (ret);
+		uu_encode(&state->encoded_buff, state->hold, LBYTES);
+		state->hold_len = 0;
+	}
+
+	for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
+		uu_encode(&state->encoded_buff, p, LBYTES);
+
+	/* Save remaining bytes. */
+	if (length > 0) {
+		memcpy(state->hold, p, length);
+		state->hold_len = length;
+	}
+	while (archive_strlen(&state->encoded_buff) >= state->bs) {
+		ret = __archive_write_filter(f->next_filter,
+		    state->encoded_buff.s, state->bs);
+		memmove(state->encoded_buff.s,
+		    state->encoded_buff.s + state->bs,
+		    state->encoded_buff.length - state->bs);
+		state->encoded_buff.length -= state->bs;
+	}
+
+	return (ret);
+}
+
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_filter_uuencode_close(struct archive_write_filter *f)
+{
+	struct private_uuencode *state = (struct private_uuencode *)f->data;
+	int ret, ret2;
+
+	/* Flush remaining bytes. */
+	if (state->hold_len != 0)
+		uu_encode(&state->encoded_buff, state->hold, state->hold_len);
+	archive_string_sprintf(&state->encoded_buff, "`\nend\n");
+	/* Write the last block */
+	archive_write_set_bytes_in_last_block(f->archive, 1);
+	ret = __archive_write_filter(f->next_filter,
+	    state->encoded_buff.s, archive_strlen(&state->encoded_buff));
+	ret2 = __archive_write_close_filter(f->next_filter);
+	if (ret > ret2)
+		ret = ret2;
+	return (ret);
+}
+
+static int
+archive_filter_uuencode_free(struct archive_write_filter *f)
+{
+	struct private_uuencode *state = (struct private_uuencode *)f->data;
+
+	archive_string_free(&state->name);
+	archive_string_free(&state->encoded_buff);
+	free(state);
+	return (ARCHIVE_OK);
+}
+
+static int64_t
+atol8(const char *p, size_t char_cnt)
+{
+	int64_t l;
+	int digit;
+        
+	l = 0;
+	while (char_cnt-- > 0) {
+		if (*p >= '0' && *p <= '7')
+			digit = *p - '0';
+		else
+			break;
+		p++;
+		l <<= 3;
+		l |= digit;
+	}
+	return (l);
+}
+
diff --git a/libarchive/archive_write_add_filter_xz.c b/libarchive/archive_write_add_filter_xz.c
index b067752..fa73311 100644
--- a/libarchive/archive_write_add_filter_xz.c
+++ b/libarchive/archive_write_add_filter_xz.c
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 2009,2010 Michihiro NAKAJIMA
  * Copyright (c) 2003-2010 Tim Kientzle
+ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -172,7 +172,7 @@ archive_write_add_filter_xz(struct archive *_a)
 	f = __archive_write_allocate_filter(_a);
 	r = common_setup(f);
 	if (r == ARCHIVE_OK) {
-		f->code = ARCHIVE_COMPRESSION_XZ;
+		f->code = ARCHIVE_FILTER_XZ;
 		f->name = "xz";
 	}
 	return (r);
@@ -192,7 +192,7 @@ archive_write_add_filter_lzma(struct archive *_a)
 	f = __archive_write_allocate_filter(_a);
 	r = common_setup(f);
 	if (r == ARCHIVE_OK) {
-		f->code = ARCHIVE_COMPRESSION_LZMA;
+		f->code = ARCHIVE_FILTER_LZMA;
 		f->name = "lzma";
 	}
 	return (r);
@@ -209,7 +209,7 @@ archive_write_add_filter_lzip(struct archive *_a)
 	f = __archive_write_allocate_filter(_a);
 	r = common_setup(f);
 	if (r == ARCHIVE_OK) {
-		f->code = ARCHIVE_COMPRESSION_LZIP;
+		f->code = ARCHIVE_FILTER_LZIP;
 		f->name = "lzip";
 	}
 	return (r);
@@ -225,12 +225,12 @@ archive_compressor_xz_init_stream(struct archive_write_filter *f,
 	data->stream = lzma_stream_init_data;
 	data->stream.next_out = data->compressed;
 	data->stream.avail_out = data->compressed_buffer_size;
-	if (f->code == ARCHIVE_COMPRESSION_XZ)
+	if (f->code == ARCHIVE_FILTER_XZ)
 		ret = lzma_stream_encoder(&(data->stream),
 		    data->lzmafilters, LZMA_CHECK_CRC64);
-	else if (f->code == ARCHIVE_COMPRESSION_LZMA)
+	else if (f->code == ARCHIVE_FILTER_LZMA)
 		ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt);
-	else {	/* ARCHIVE_COMPRESSION_LZIP */
+	else {	/* ARCHIVE_FILTER_LZIP */
 		int dict_size = data->lzma_opt.dict_size;
 		int ds, log2dic, wedges;
 
@@ -298,7 +298,17 @@ archive_compressor_xz_open(struct archive_write_filter *f)
 		return (ret);
 
 	if (data->compressed == NULL) {
-		data->compressed_buffer_size = 65536;
+		size_t bs = 65536, bpb;
+		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
+			/* Buffer size should be a multiple number of the of bytes
+			 * per block for performance. */
+			bpb = archive_write_get_bytes_per_block(f->archive);
+			if (bpb > bs)
+				bs = bpb;
+			else if (bpb != 0)
+				bs -= bs % bpb;
+		}
+		data->compressed_buffer_size = bs;
 		data->compressed
 		    = (unsigned char *)malloc(data->compressed_buffer_size);
 		if (data->compressed == NULL) {
@@ -311,7 +321,7 @@ archive_compressor_xz_open(struct archive_write_filter *f)
 	f->write = archive_compressor_xz_write;
 
 	/* Initialize compression library. */
-	if (f->code == ARCHIVE_COMPRESSION_LZIP) {
+	if (f->code == ARCHIVE_FILTER_LZIP) {
 		const struct option_value *val =
 		    &option_values[data->compression_level];
 
@@ -365,6 +375,9 @@ archive_compressor_xz_options(struct archive_write_filter *f,
 		return (ARCHIVE_OK);
 	}
 
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
 	return (ARCHIVE_WARN);
 }
 
@@ -380,7 +393,7 @@ archive_compressor_xz_write(struct archive_write_filter *f,
 
 	/* Update statistics */
 	data->total_in += length;
-	if (f->code == ARCHIVE_COMPRESSION_LZIP)
+	if (f->code == ARCHIVE_FILTER_LZIP)
 		data->crc32 = lzma_crc32(buff, length, data->crc32);
 
 	/* Compress input data to output buffer */
@@ -409,7 +422,7 @@ archive_compressor_xz_close(struct archive_write_filter *f)
 		ret = __archive_write_filter(f->next_filter,
 		    data->compressed,
 		    data->compressed_buffer_size - data->stream.avail_out);
-		if (f->code == ARCHIVE_COMPRESSION_LZIP && ret == ARCHIVE_OK) {
+		if (f->code == ARCHIVE_FILTER_LZIP && ret == ARCHIVE_OK) {
 			archive_le32enc(data->compressed, data->crc32);
 			archive_le64enc(data->compressed+4, data->total_in);
 			archive_le64enc(data->compressed+12, data->total_out + 20);
diff --git a/libarchive/archive_write_blocksize.3 b/libarchive/archive_write_blocksize.3
index 96c7538..afd84ea 100644
--- a/libarchive/archive_write_blocksize.3
+++ b/libarchive/archive_write_blocksize.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 23, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_WRITE_BLOCKSIZE 3
 .Os
 .Sh NAME
@@ -33,6 +33,8 @@
 .Nm archive_write_get_bytes_in_last_block ,
 .Nm archive_write_set_bytes_in_last_block
 .Nd functions for creating archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_write_data.3 b/libarchive/archive_write_data.3
index fc399bc..cfd5cd5 100644
--- a/libarchive/archive_write_data.3
+++ b/libarchive/archive_write_data.3
@@ -22,14 +22,16 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $
+.\" $FreeBSD$
 .\"
-.Dd March 23, 2011
-.Dt ARCHIVE_WRITE 3
+.Dd February 2, 2012
+.Dt ARCHIVE_WRITE_DATA 3
 .Os
 .Sh NAME
 .Nm archive_write_data
 .Nd functions for creating archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft ssize_t
diff --git a/libarchive/archive_write_disk.3 b/libarchive/archive_write_disk.3
index ffadb04..fa925cc 100644
--- a/libarchive/archive_write_disk.3
+++ b/libarchive/archive_write_disk.3
@@ -22,9 +22,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libarchive/archive_write_disk.3,v 1.4 2008/09/04 05:22:00 kientzle Exp $
+.\" $FreeBSD$
 .\"
-.Dd August 5, 2008
+.Dd February 2, 2012
 .Dt ARCHIVE_WRITE_DISK 3
 .Os
 .Sh NAME
@@ -42,6 +42,8 @@
 .Nm archive_write_finish
 .Nm archive_write_free
 .Nd functions for creating objects on disk
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft struct archive *
diff --git a/libarchive/archive_write_disk_acl.c b/libarchive/archive_write_disk_acl.c
new file mode 100644
index 0000000..9797203
--- /dev/null
+++ b/libarchive/archive_write_disk_acl.c
@@ -0,0 +1,249 @@
+/*-
+ * 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
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 05:35:40Z kientzle $");
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_ACL_H
+#define _ACL_PRIVATE /* For debugging */
+#include <sys/acl.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_acl_private.h"
+#include "archive_write_disk_private.h"
+
+#if !defined(HAVE_POSIX_ACL) || !defined(ACL_TYPE_NFS4)
+/* Default empty function body to satisfy mainline code. */
+int
+archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
+	 struct archive_acl *abstract_acl)
+{
+	(void)a; /* UNUSED */
+	(void)fd; /* UNUSED */
+	(void)name; /* UNUSED */
+	(void)abstract_acl; /* UNUSED */
+	return (ARCHIVE_OK);
+}
+
+#else
+
+static int	set_acl(struct archive *, int fd, const char *,
+			struct archive_acl *,
+			acl_type_t, int archive_entry_acl_type, const char *tn);
+
+/*
+ * XXX TODO: What about ACL types other than ACCESS and DEFAULT?
+ */
+int
+archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
+	 struct archive_acl *abstract_acl)
+{
+	int		 ret;
+
+	if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) > 0) {
+		ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_ACCESS,
+		    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
+		if (ret != ARCHIVE_OK)
+			return (ret);
+		ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT,
+		    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
+		return (ret);
+	} else if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0) {
+		ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_NFS4,
+		    ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
+		return (ret);
+	} else
+		return ARCHIVE_OK;
+}
+
+static struct {
+	int archive_perm;
+	int platform_perm;
+} acl_perm_map[] = {
+	{ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+	{ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
+	{ARCHIVE_ENTRY_ACL_READ, ACL_READ},
+	{ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+	{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+	{ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+	{ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+	{ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+	{ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+	{ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
+	{ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
+	{ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+	{ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+	{ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+	{ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+	{ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
+	{ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
+	{ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
+	{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+};
+
+static struct {
+	int archive_inherit;
+	int platform_inherit;
+} acl_inherit_map[] = {
+	{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+	{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+	{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
+	{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
+};
+
+static int
+set_acl(struct archive *a, int fd, const char *name,
+    struct archive_acl *abstract_acl,
+    acl_type_t acl_type, int ae_requested_type, const char *tname)
+{
+	acl_t		 acl;
+	acl_entry_t	 acl_entry;
+	acl_permset_t	 acl_permset;
+	acl_flagset_t	 acl_flagset;
+	int		 ret;
+	int		 ae_type, ae_permset, ae_tag, ae_id;
+	uid_t		 ae_uid;
+	gid_t		 ae_gid;
+	const char	*ae_name;
+	int		 entries;
+	int		 i;
+
+	ret = ARCHIVE_OK;
+	entries = archive_acl_reset(abstract_acl, ae_requested_type);
+	if (entries == 0)
+		return (ARCHIVE_OK);
+	acl = acl_init(entries);
+	while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
+		   &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
+		acl_create_entry(&acl, &acl_entry);
+
+		switch (ae_tag) {
+		case ARCHIVE_ENTRY_ACL_USER:
+			acl_set_tag_type(acl_entry, ACL_USER);
+			ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
+			acl_set_qualifier(acl_entry, &ae_uid);
+			break;
+		case ARCHIVE_ENTRY_ACL_GROUP:
+			acl_set_tag_type(acl_entry, ACL_GROUP);
+			ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
+			acl_set_qualifier(acl_entry, &ae_gid);
+			break;
+		case ARCHIVE_ENTRY_ACL_USER_OBJ:
+			acl_set_tag_type(acl_entry, ACL_USER_OBJ);
+			break;
+		case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+			acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
+			break;
+		case ARCHIVE_ENTRY_ACL_MASK:
+			acl_set_tag_type(acl_entry, ACL_MASK);
+			break;
+		case ARCHIVE_ENTRY_ACL_OTHER:
+			acl_set_tag_type(acl_entry, ACL_OTHER);
+			break;
+		case ARCHIVE_ENTRY_ACL_EVERYONE:
+			acl_set_tag_type(acl_entry, ACL_EVERYONE);
+			break;
+		default:
+			/* XXX */
+			break;
+		}
+
+		switch (ae_type) {
+		case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+			acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
+			break;
+		case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+			acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
+			break;
+		case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+			acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
+			break;
+		case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+			acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
+			break;
+		case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+		case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+			// These don't translate directly into the system ACL.
+			break;
+		default:
+			// XXX error handling here.
+			break;
+		}
+
+		acl_get_permset(acl_entry, &acl_permset);
+		acl_clear_perms(acl_permset);
+
+		for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
+			if (ae_permset & acl_perm_map[i].archive_perm)
+				acl_add_perm(acl_permset,
+					     acl_perm_map[i].platform_perm);
+		}
+
+		acl_get_flagset_np(acl_entry, &acl_flagset);
+		acl_clear_flags_np(acl_flagset);
+		for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
+			if (ae_permset & acl_inherit_map[i].archive_inherit)
+				acl_add_flag_np(acl_flagset,
+						acl_inherit_map[i].platform_inherit);
+		}
+	}
+
+	/* Try restoring the ACL through 'fd' if we can. */
+#if HAVE_ACL_SET_FD
+	if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
+		ret = ARCHIVE_OK;
+	else
+#else
+#if HAVE_ACL_SET_FD_NP
+	if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
+		ret = ARCHIVE_OK;
+	else
+#endif
+#endif
+#if HAVE_ACL_SET_LINK_NP
+	  if (acl_set_link_np(name, acl_type, acl) != 0) {
+		archive_set_error(a, errno, "Failed to set %s acl", tname);
+		ret = ARCHIVE_WARN;
+	  }
+#else
+	/* TODO: Skip this if 'name' is a symlink. */
+	if (acl_set_file(name, acl_type, acl) != 0) {
+		archive_set_error(a, errno, "Failed to set %s acl", tname);
+		ret = ARCHIVE_WARN;
+	}
+#endif
+	acl_free(acl);
+	return (ret);
+}
+#endif
diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c
index 99afab2..bbd50a6 100644
--- a/libarchive/archive_write_disk_posix.c
+++ b/libarchive/archive_write_disk_posix.c
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2003-2010 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,15 +39,14 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_SYS_EXTATTR_H
 #include <sys/extattr.h>
 #endif
-#ifdef HAVE_SYS_XATTR_H
+#if defined(HAVE_SYS_XATTR_H)
 #include <sys/xattr.h>
+#elif defined(HAVE_ATTR_XATTR_H)
+#include <attr/xattr.h>
 #endif
 #ifdef HAVE_SYS_EA_H
 #include <sys/ea.h>
 #endif
-#ifdef HAVE_ATTR_XATTR_H
-#include <attr/xattr.h>
-#endif
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
@@ -118,6 +118,10 @@ __FBSDID("$FreeBSD$");
 #endif
 #endif
 
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
 /* TODO: Support Mac OS 'quarantine' feature.  This is really just a
  * standard tag to mark files that have been downloaded as "tainted".
  * On Mac OS, we should mark the extracted files as tainted if the
@@ -127,12 +131,17 @@ __FBSDID("$FreeBSD$");
 #include "archive.h"
 #include "archive_acl_private.h"
 #include "archive_string.h"
+#include "archive_endian.h"
 #include "archive_entry.h"
 #include "archive_private.h"
+#include "archive_write_disk_private.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
 
 struct fixup_entry {
 	struct fixup_entry	*next;
@@ -172,6 +181,7 @@ struct fixup_entry {
 #define	TODO_SUID_CHECK		0x08000000
 #define	TODO_SGID		0x04000000
 #define	TODO_SGID_CHECK		0x02000000
+#define	TODO_APPLEDOUBLE	0x01000000
 #define	TODO_MODE		(TODO_MODE_BASE|TODO_SUID|TODO_SGID)
 #define	TODO_TIMES		ARCHIVE_EXTRACT_TIME
 #define	TODO_OWNER		ARCHIVE_EXTRACT_OWNER
@@ -179,6 +189,7 @@ struct fixup_entry {
 #define	TODO_ACLS		ARCHIVE_EXTRACT_ACL
 #define	TODO_XATTR		ARCHIVE_EXTRACT_XATTR
 #define	TODO_MAC_METADATA	ARCHIVE_EXTRACT_MAC_METADATA
+#define	TODO_HFS_COMPRESSION	ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED
 
 struct archive_write_disk {
 	struct archive	archive;
@@ -188,8 +199,8 @@ struct archive_write_disk {
 	struct fixup_entry	*current_fixup;
 	int64_t			 user_uid;
 	int			 skip_file_set;
-	dev_t			 skip_file_dev;
-	ino_t			 skip_file_ino;
+	int64_t			 skip_file_dev;
+	int64_t			 skip_file_ino;
 	time_t			 start_time;
 
 	int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid);
@@ -239,6 +250,36 @@ struct archive_write_disk {
 	/* UID/GID to use in restoring this entry. */
 	int64_t			 uid;
 	int64_t			 gid;
+	/*
+	 * HFS+ Compression.
+	 */
+	/* Xattr "com.apple.decmpfs". */
+	uint32_t		 decmpfs_attr_size;
+	unsigned char		*decmpfs_header_p;
+	/* ResourceFork set options used for fsetxattr. */
+	int			 rsrc_xattr_options;
+	/* Xattr "com.apple.ResourceFork". */
+	unsigned char		*resource_fork;
+	size_t			 resource_fork_allocated_size;
+	unsigned int		 decmpfs_block_count;
+	uint32_t		*decmpfs_block_info;
+	/* Buffer for compressed data. */
+	unsigned char		*compressed_buffer;
+	size_t			 compressed_buffer_size;
+	size_t			 compressed_buffer_remaining;
+	/* The offset of the ResourceFork where compressed data will
+	 * be placed. */
+	uint32_t		 compressed_rsrc_position;
+	uint32_t		 compressed_rsrc_position_v;
+	/* Buffer for uncompressed data. */
+	char			*uncompressed_buffer;
+	size_t			 block_remaining_bytes;
+	size_t			 file_remaining_bytes;
+#ifdef HAVE_ZLIB_H
+	z_stream		 stream;
+	int			 stream_valid;
+	int			 decmpfs_compression_level;
+#endif
 };
 
 /*
@@ -256,6 +297,35 @@ struct archive_write_disk {
 #define	MINIMUM_DIR_MODE 0700
 #define	MAXIMUM_DIR_MODE 0775
 
+/*
+ * Maxinum uncompressed size of a decmpfs block.
+ */
+#define MAX_DECMPFS_BLOCK_SIZE	(64 * 1024)
+/*
+ * HFS+ compression type.
+ */
+#define CMP_XATTR		3/* Compressed data in xattr. */
+#define CMP_RESOURCE_FORK	4/* Compressed data in resource fork. */
+/*
+ * HFS+ compression resource fork.
+ */
+#define RSRC_H_SIZE	260	/* Base size of Resource fork header. */
+#define RSRC_F_SIZE	50	/* Size of Resource fork footer. */
+/* Size to write compressed data to resource fork. */
+#define COMPRESSED_W_SIZE	(64 * 1024)
+/* decmpfs difinitions. */
+#define MAX_DECMPFS_XATTR_SIZE		3802
+#ifndef DECMPFS_XATTR_NAME
+#define DECMPFS_XATTR_NAME		"com.apple.decmpfs"
+#endif
+#define DECMPFS_MAGIC			0x636d7066
+#define DECMPFS_COMPRESSION_MAGIC	0
+#define DECMPFS_COMPRESSION_TYPE	4
+#define DECMPFS_UNCOMPRESSED_SIZE	8
+#define DECMPFS_HEADER_SIZE		16
+
+#define HFS_BLOCKS(s)	((s) >> 12)
+
 static int	check_symlinks(struct archive_write_disk *);
 static int	create_filesystem_object(struct archive_write_disk *);
 static struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname);
@@ -265,13 +335,11 @@ static void	edit_deep_directories(struct archive_write_disk *ad);
 static int	cleanup_pathname(struct archive_write_disk *);
 static int	create_dir(struct archive_write_disk *, char *);
 static int	create_parent_dir(struct archive_write_disk *, char *);
+static ssize_t	hfs_write_data_block(struct archive_write_disk *,
+		    const char *, size_t);
+static int	fixup_appledouble(struct archive_write_disk *, const char *);
 static int	older(struct stat *, struct archive_entry *);
 static int	restore_entry(struct archive_write_disk *);
-#ifdef HAVE_POSIX_ACL
-static int	set_acl(struct archive_write_disk *, int fd, const char *, struct archive_acl *,
-		    acl_type_t, int archive_entry_acl_type, const char *tn);
-#endif
-static int	set_acls(struct archive_write_disk *, int fd, const char *, struct archive_acl *);
 static int	set_mac_metadata(struct archive_write_disk *, const char *,
 				 const void *, size_t);
 static int	set_xattrs(struct archive_write_disk *);
@@ -485,6 +553,39 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 		else
 			a->todo |= TODO_MAC_METADATA;
 	}
+#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
+	if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) {
+		unsigned long set, clear;
+		archive_entry_fflags(a->entry, &set, &clear);
+		if ((set & ~clear) & UF_COMPRESSED) {
+			a->todo |= TODO_HFS_COMPRESSION;
+			a->decmpfs_block_count = (unsigned)-1;
+		}
+	}
+	if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 &&
+	    (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) {
+		a->todo |= TODO_HFS_COMPRESSION;
+		a->decmpfs_block_count = (unsigned)-1;
+	}
+	{
+		const char *p;
+
+		/* Check if the current file name is a type of the
+		 * resource fork file. */
+		p = strrchr(a->name, '/');
+		if (p == NULL)
+			p = a->name;
+		else
+			p++;
+		if (p[0] == '.' && p[1] == '_') {
+			/* Do not compress "._XXX" files. */
+			a->todo &= ~TODO_HFS_COMPRESSION;
+			if (a->filesize > 0)
+				a->todo |= TODO_APPLEDOUBLE;
+		}
+	}
+#endif
+
 	if (a->flags & ARCHIVE_EXTRACT_XATTR)
 		a->todo |= TODO_XATTR;
 	if (a->flags & ARCHIVE_EXTRACT_FFLAGS)
@@ -501,6 +602,25 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 
 	ret = restore_entry(a);
 
+#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
+	/*
+	 * Check if the filesystem the file is restoring on supports
+	 * HFS+ Compression. If not, cancel HFS+ Compression.
+	 */
+	if (a->todo | TODO_HFS_COMPRESSION) {
+		/*
+		 * NOTE: UF_COMPRESSED is ignored even if the filesystem
+		 * supports HFS+ Compression because the file should
+		 * have at least an extended attriute "com.apple.decmpfs"
+		 * before the flag is set to indicate that the file have
+		 * been compressed. If hte filesystem does not support
+		 * HFS+ Compression the system call will fail.
+		 */
+		if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0)
+			a->todo &= ~TODO_HFS_COMPRESSION;
+	}
+#endif
+
 	/*
 	 * TODO: There are rumours that some extended attributes must
 	 * be restored before file data is written.  If this is true,
@@ -532,6 +652,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 	 */
 	if (a->deferred & TODO_MODE) {
 		fe = current_fixup(a, archive_entry_pathname(entry));
+		if (fe == NULL)
+			return (ARCHIVE_FATAL);
 		fe->fixup |= TODO_MODE_BASE;
 		fe->mode = a->mode;
 	}
@@ -540,6 +662,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 		&& (archive_entry_mtime_is_set(entry)
 		    || archive_entry_atime_is_set(entry))) {
 		fe = current_fixup(a, archive_entry_pathname(entry));
+		if (fe == NULL)
+			return (ARCHIVE_FATAL);
 		fe->mode = a->mode;
 		fe->fixup |= TODO_TIMES;
 		if (archive_entry_atime_is_set(entry)) {
@@ -570,6 +694,9 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 
 	if (a->deferred & TODO_ACLS) {
 		fe = current_fixup(a, archive_entry_pathname(entry));
+		if (fe == NULL)
+			return (ARCHIVE_FATAL);
+		fe->fixup |= TODO_ACLS;
 		archive_acl_copy(&fe->acl, archive_entry_acl(entry));
 	}
 
@@ -579,6 +706,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 		metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
 		if (metadata != NULL && metadata_size > 0) {
 			fe = current_fixup(a, archive_entry_pathname(entry));
+			if (fe == NULL)
+				return (ARCHIVE_FATAL);
 			fe->mac_metadata = malloc(metadata_size);
 			if (fe->mac_metadata != NULL) {
 				memcpy(fe->mac_metadata, metadata, metadata_size);
@@ -590,6 +719,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 
 	if (a->deferred & TODO_FFLAGS) {
 		fe = current_fixup(a, archive_entry_pathname(entry));
+		if (fe == NULL)
+			return (ARCHIVE_FATAL);
 		fe->fixup |= TODO_FFLAGS;
 		/* TODO: Complete this.. defer fflags from below. */
 	}
@@ -707,6 +838,616 @@ write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
 	return (start_size - size);
 }
 
+#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
+	&& defined(HAVE_ZLIB_H)
+
+/*
+ * Set UF_COMPRESSED file flag.
+ * This have to be called after hfs_write_decmpfs() because if the
+ * file does not have "com.apple.decmpfs" xattr the flag is ignored.
+ */
+static int
+hfs_set_compressed_fflag(struct archive_write_disk *a)
+{
+	int r;
+
+	if ((r = lazy_stat(a)) != ARCHIVE_OK)
+		return (r);
+
+	a->st.st_flags |= UF_COMPRESSED;
+	if (fchflags(a->fd, a->st.st_flags) != 0) {
+		archive_set_error(&a->archive, errno,
+		    "Failed to set UF_COMPRESSED file flag");
+		return (ARCHIVE_WARN);
+	}
+	return (ARCHIVE_OK);
+}
+
+/*
+ * HFS+ Compression decmpfs
+ *
+ *     +------------------------------+ +0
+ *     |      Magic(LE 4 bytes)       |
+ *     +------------------------------+
+ *     |      Type(LE 4 bytes)        |
+ *     +------------------------------+
+ *     | Uncompressed size(LE 8 bytes)|
+ *     +------------------------------+ +16
+ *     |                              |
+ *     |       Compressed data        |
+ *     |  (Placed only if Type == 3)  |
+ *     |                              |
+ *     +------------------------------+  +3802 = MAX_DECMPFS_XATTR_SIZE
+ *
+ *  Type is 3: decmpfs has compressed data.
+ *  Type is 4: Resource Fork has compressed data.
+ */
+/*
+ * Write "com.apple.decmpfs"
+ */
+static int
+hfs_write_decmpfs(struct archive_write_disk *a)
+{
+	int r;
+	uint32_t compression_type;
+
+	r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p,
+	    a->decmpfs_attr_size, 0, 0);
+	if (r < 0) {
+		archive_set_error(&a->archive, errno,
+		    "Cannot restore xattr:%s", DECMPFS_XATTR_NAME);
+		compression_type = archive_le32dec(
+		    &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]);
+		if (compression_type == CMP_RESOURCE_FORK)
+			fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME,
+			    XATTR_SHOWCOMPRESSION);
+		return (ARCHIVE_WARN);
+	}
+	return (ARCHIVE_OK);
+}
+
+/*
+ * HFS+ Compression Resource Fork
+ *
+ *     +-----------------------------+
+ *     |     Header(260 bytes)       |
+ *     +-----------------------------+
+ *     |   Block count(LE 4 bytes)   |
+ *     +-----------------------------+  --+
+ * +-- |     Offset (LE 4 bytes)     |    |
+ * |   | [distance from Block count] |    | Block 0
+ * |   +-----------------------------+    |
+ * |   | Compressed size(LE 4 bytes) |    |
+ * |   +-----------------------------+  --+
+ * |   |                             |
+ * |   |      ..................     |
+ * |   |                             |
+ * |   +-----------------------------+  --+
+ * |   |     Offset (LE 4 bytes)     |    |
+ * |   +-----------------------------+    | Block (Block count -1)
+ * |   | Compressed size(LE 4 bytes) |    |
+ * +-> +-----------------------------+  --+
+ *     |   Compressed data(n bytes)  |  Block 0
+ *     +-----------------------------+
+ *     |                             |
+ *     |      ..................     |
+ *     |                             |
+ *     +-----------------------------+
+ *     |   Compressed data(n bytes)  |  Block (Block count -1)
+ *     +-----------------------------+
+ *     |      Footer(50 bytes)       |
+ *     +-----------------------------+
+ *
+ */
+/*
+ * Write the header of "com.apple.ResourceFork"
+ */
+static int
+hfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff,
+    size_t bytes, uint32_t position)
+{
+	int ret;
+
+	ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes,
+	    position, a->rsrc_xattr_options);
+	if (ret < 0) {
+		archive_set_error(&a->archive, errno,
+		    "Cannot restore xattr: %s at %u pos %u bytes",
+		    XATTR_RESOURCEFORK_NAME,
+		    (unsigned)position,
+		    (unsigned)bytes);
+		return (ARCHIVE_WARN);
+	}
+	a->rsrc_xattr_options &= ~XATTR_CREATE;
+	return (ARCHIVE_OK);
+}
+
+static int
+hfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed)
+{
+	int ret;
+
+	ret = hfs_write_resource_fork(a, a->compressed_buffer,
+	    bytes_compressed, a->compressed_rsrc_position);
+	if (ret == ARCHIVE_OK)
+		a->compressed_rsrc_position += bytes_compressed;
+	return (ret);
+}
+
+static int
+hfs_write_resource_fork_header(struct archive_write_disk *a)
+{
+	unsigned char *buff;
+	uint32_t rsrc_bytes;
+	uint32_t rsrc_header_bytes;
+
+	/*
+	 * Write resource fork header + block info.
+	 */
+	buff = a->resource_fork;
+	rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE;
+	rsrc_header_bytes =
+		RSRC_H_SIZE +		/* Header base size. */
+		4 +			/* Block count. */
+		(a->decmpfs_block_count * 8);/* Block info */
+	archive_be32enc(buff, 0x100);
+	archive_be32enc(buff + 4, rsrc_bytes);
+	archive_be32enc(buff + 8, rsrc_bytes - 256);
+	archive_be32enc(buff + 12, 0x32);
+	memset(buff + 16, 0, 240);
+	archive_be32enc(buff + 256, rsrc_bytes - 260);
+	return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0);
+}
+
+static size_t
+hfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size)
+{
+	static const char rsrc_footer[RSRC_F_SIZE] = {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c',  'm',
+		'p', 'f',   0x00, 0x00, 0x00, 0x0a, 0x00, 0x01,
+		0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00
+	};
+	if (buff_size < sizeof(rsrc_footer))
+		return (0);
+	memcpy(buff, rsrc_footer, sizeof(rsrc_footer));
+	return (sizeof(rsrc_footer));
+}
+
+static int
+hfs_reset_compressor(struct archive_write_disk *a)
+{
+	int ret;
+
+	if (a->stream_valid)
+		ret = deflateReset(&a->stream);
+	else
+		ret = deflateInit(&a->stream, a->decmpfs_compression_level);
+
+	if (ret != Z_OK) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+		    "Failed to initialize compressor");
+		return (ARCHIVE_FATAL);
+	} else
+		a->stream_valid = 1;
+
+	return (ARCHIVE_OK);
+}
+
+static int
+hfs_decompress(struct archive_write_disk *a)
+{
+	uint32_t *block_info;
+	unsigned int block_count;
+	uint32_t data_pos, data_size;
+	ssize_t r;
+	ssize_t bytes_written, bytes_to_write;
+	unsigned char *b;
+
+	block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE);
+	block_count = archive_le32dec(block_info++);
+	while (block_count--) {
+		data_pos = RSRC_H_SIZE + archive_le32dec(block_info++);
+		data_size = archive_le32dec(block_info++);
+		r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME,
+		    a->compressed_buffer, data_size, data_pos, 0);
+		if (r != data_size)  {
+			archive_set_error(&a->archive,
+			    (r < 0)?errno:ARCHIVE_ERRNO_MISC,
+			    "Failed to read resource fork");
+			return (ARCHIVE_WARN);
+		}
+		if (a->compressed_buffer[0] == 0xff) {
+			bytes_to_write = data_size -1;
+			b = a->compressed_buffer + 1;
+		} else {
+			uLong dest_len = MAX_DECMPFS_BLOCK_SIZE;
+			int zr;
+
+			zr = uncompress((Bytef *)a->uncompressed_buffer,
+			    &dest_len, a->compressed_buffer, data_size);
+			if (zr != Z_OK) {
+				archive_set_error(&a->archive,
+				    ARCHIVE_ERRNO_MISC,
+				    "Failed to decompress resource fork");
+				return (ARCHIVE_WARN);
+			}
+			bytes_to_write = dest_len;
+			b = (unsigned char *)a->uncompressed_buffer;
+		}
+		do {
+			bytes_written = write(a->fd, b, bytes_to_write);
+			if (bytes_written < 0) {
+				archive_set_error(&a->archive, errno,
+				    "Write failed");
+				return (ARCHIVE_WARN);
+			}
+			bytes_to_write -= bytes_written;
+			b += bytes_written;
+		} while (bytes_to_write > 0);
+	}
+	r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0);
+	if (r == -1)  {
+		archive_set_error(&a->archive, errno,
+		    "Failed to remove resource fork");
+		return (ARCHIVE_WARN);
+	}
+	return (ARCHIVE_OK);
+}
+
+static int
+hfs_drive_compressor(struct archive_write_disk *a, const char *buff,
+    size_t size)
+{
+	unsigned char *buffer_compressed;
+	size_t bytes_compressed;
+	size_t bytes_used;
+	int ret;
+
+	ret = hfs_reset_compressor(a);
+	if (ret != ARCHIVE_OK)
+		return (ret);
+
+	if (a->compressed_buffer == NULL) {
+		size_t block_size;
+
+		block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE +
+		    + compressBound(MAX_DECMPFS_BLOCK_SIZE);
+		a->compressed_buffer = malloc(block_size);
+		if (a->compressed_buffer == NULL) {
+			archive_set_error(&a->archive, ENOMEM,
+			    "Can't allocate memory for Resource Fork");
+			return (ARCHIVE_FATAL);
+		}
+		a->compressed_buffer_size = block_size;
+		a->compressed_buffer_remaining = block_size;
+	}
+
+	buffer_compressed = a->compressed_buffer +
+	    a->compressed_buffer_size - a->compressed_buffer_remaining;
+	a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff;
+	a->stream.avail_in = size;
+	a->stream.next_out = buffer_compressed;
+	a->stream.avail_out = a->compressed_buffer_remaining;
+	do {
+		ret = deflate(&a->stream, Z_FINISH);
+		switch (ret) {
+		case Z_OK:
+		case Z_STREAM_END:
+			break;
+		default:
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Failed to compress data");
+			return (ARCHIVE_FAILED);
+		}
+	} while (ret == Z_OK);
+	bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out;
+
+	/*
+	 * If the compressed size is larger than the original size,
+	 * throw away compressed data, use uncompressed data instead.
+	 */
+	if (bytes_compressed > size) {
+		buffer_compressed[0] = 0xFF;/* uncompressed marker. */
+		memcpy(buffer_compressed + 1, buff, size);
+		bytes_compressed = size + 1;
+	}
+	a->compressed_buffer_remaining -= bytes_compressed;
+
+	/*
+	 * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE
+	 * and the block count in the file is only one, store compressed
+	 * data to decmpfs xattr instead of the resource fork.
+	 */
+	if (a->decmpfs_block_count == 1 &&
+	    (a->decmpfs_attr_size + bytes_compressed)
+	      <= MAX_DECMPFS_XATTR_SIZE) {
+		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],
+		    CMP_XATTR);
+		memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE,
+		    buffer_compressed, bytes_compressed);
+		a->decmpfs_attr_size += bytes_compressed;
+		a->compressed_buffer_remaining = a->compressed_buffer_size;
+		/*
+		 * Finish HFS+ Compression.
+		 * - Write the decmpfs xattr.
+		 * - Set the UF_COMPRESSED file flag.
+		 */
+		ret = hfs_write_decmpfs(a);
+		if (ret == ARCHIVE_OK)
+			ret = hfs_set_compressed_fflag(a);
+		return (ret);
+	}
+
+	/* Update block info. */
+	archive_le32enc(a->decmpfs_block_info++,
+	    a->compressed_rsrc_position_v - RSRC_H_SIZE);
+	archive_le32enc(a->decmpfs_block_info++, bytes_compressed);
+	a->compressed_rsrc_position_v += bytes_compressed;
+
+	/*
+	 * Write the compressed data to the resource fork.
+	 */
+	bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining;
+	while (bytes_used >= COMPRESSED_W_SIZE) {
+		ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE);
+		if (ret != ARCHIVE_OK)
+			return (ret);
+		bytes_used -= COMPRESSED_W_SIZE;
+		if (bytes_used > COMPRESSED_W_SIZE)
+			memmove(a->compressed_buffer,
+			    a->compressed_buffer + COMPRESSED_W_SIZE,
+			    bytes_used);
+		else
+			memcpy(a->compressed_buffer,
+			    a->compressed_buffer + COMPRESSED_W_SIZE,
+			    bytes_used);
+	}
+	a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used;
+
+	/*
+	 * If the current block is the last block, write the remaining
+	 * compressed data and the resource fork footer.
+	 */
+	if (a->file_remaining_bytes == 0) {
+		size_t rsrc_size;
+		int64_t bk;
+
+		/* Append the resource footer. */
+		rsrc_size = hfs_set_resource_fork_footer(
+		    a->compressed_buffer + bytes_used,
+		    a->compressed_buffer_remaining);
+		ret = hfs_write_compressed_data(a, bytes_used + rsrc_size);
+		a->compressed_buffer_remaining = a->compressed_buffer_size;
+
+		/* If the compressed size is not enouph smaller than
+		 * the uncompressed size. cancel HFS+ compression.
+		 * TODO: study a behavior of ditto utility and improve
+		 * the condition to fall back into no HFS+ compression. */
+		bk = HFS_BLOCKS(a->compressed_rsrc_position);
+		bk += bk >> 7;
+		if (bk > HFS_BLOCKS(a->filesize))
+			return hfs_decompress(a);
+		/*
+		 * Write the resourcefork header.
+		 */
+		if (ret == ARCHIVE_OK)
+			ret = hfs_write_resource_fork_header(a);
+		/*
+		 * Finish HFS+ Compression.
+		 * - Write the decmpfs xattr.
+		 * - Set the UF_COMPRESSED file flag.
+		 */
+		if (ret == ARCHIVE_OK)
+			ret = hfs_write_decmpfs(a);
+		if (ret == ARCHIVE_OK)
+			ret = hfs_set_compressed_fflag(a);
+	}
+	return (ret);
+}
+
+static ssize_t
+hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,
+    size_t size)
+{
+	const char *buffer_to_write;
+	size_t bytes_to_write;
+	int ret;
+
+	if (a->decmpfs_block_count == (unsigned)-1) {
+		void *new_block;
+		size_t new_size;
+		unsigned int block_count;
+
+		if (a->decmpfs_header_p == NULL) {
+			new_block = malloc(MAX_DECMPFS_XATTR_SIZE
+			    + sizeof(uint32_t));
+			if (new_block == NULL) {
+				archive_set_error(&a->archive, ENOMEM,
+				    "Can't allocate memory for decmpfs");
+				return (ARCHIVE_FATAL);
+			}
+			a->decmpfs_header_p = new_block;
+		}
+		a->decmpfs_attr_size = DECMPFS_HEADER_SIZE;
+		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC],
+		    DECMPFS_MAGIC);
+		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],
+		    CMP_RESOURCE_FORK);
+		archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE],
+		    a->filesize);
+
+		/* Calculate a block count of the file. */
+		block_count =
+		    (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) /
+			MAX_DECMPFS_BLOCK_SIZE;
+		/*
+		 * Allocate buffer for resource fork.
+		 * Set up related pointers;
+		 */
+		new_size =
+		    RSRC_H_SIZE + /* header */
+		    4 + /* Block count */
+		    (block_count * sizeof(uint32_t) * 2) +
+		    RSRC_F_SIZE; /* footer */
+		if (new_size > a->resource_fork_allocated_size) {
+			new_block = realloc(a->resource_fork, new_size);
+			if (new_block == NULL) {
+				archive_set_error(&a->archive, ENOMEM,
+				    "Can't allocate memory for ResourceFork");
+				return (ARCHIVE_FATAL);
+			}
+			a->resource_fork_allocated_size = new_size;
+			a->resource_fork = new_block;
+		}
+
+		/* Allocate uncompressed buffer */
+		if (a->uncompressed_buffer == NULL) {
+			new_block = malloc(MAX_DECMPFS_BLOCK_SIZE);
+			if (new_block == NULL) {
+				archive_set_error(&a->archive, ENOMEM,
+				    "Can't allocate memory for decmpfs");
+				return (ARCHIVE_FATAL);
+			}
+			a->uncompressed_buffer = new_block;
+		}
+		a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;
+		a->file_remaining_bytes = a->filesize;
+		a->compressed_buffer_remaining = a->compressed_buffer_size;
+
+		/*
+		 * Set up a resource fork.
+		 */
+		a->rsrc_xattr_options = XATTR_CREATE;
+		/* Get the position where we are going to set a bunch
+		 * of block info. */
+		a->decmpfs_block_info =
+		    (uint32_t *)(a->resource_fork + RSRC_H_SIZE);
+		/* Set the block count to the resource fork. */
+		archive_le32enc(a->decmpfs_block_info++, block_count);
+		/* Get the position where we are goint to set compressed
+		 * data. */
+		a->compressed_rsrc_position =
+		    RSRC_H_SIZE + 4 + (block_count * 8);
+		a->compressed_rsrc_position_v = a->compressed_rsrc_position;
+		a->decmpfs_block_count = block_count;
+	}
+
+	/* Ignore redundant bytes. */
+	if (a->file_remaining_bytes == 0)
+		return ((ssize_t)size);
+
+	/* Do not overrun a block size. */
+	if (size > a->block_remaining_bytes)
+		bytes_to_write = a->block_remaining_bytes;
+	else
+		bytes_to_write = size;
+	/* Do not overrun the file size. */
+	if (bytes_to_write > a->file_remaining_bytes)
+		bytes_to_write = a->file_remaining_bytes;
+
+	/* For efficiency, if a copy length is full of the uncompressed
+	 * buffer size, do not copy writing data to it. */
+	if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE)
+		buffer_to_write = buff;
+	else {
+		memcpy(a->uncompressed_buffer +
+		    MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes,
+		    buff, bytes_to_write);
+		buffer_to_write = a->uncompressed_buffer;
+	}
+	a->block_remaining_bytes -= bytes_to_write;
+	a->file_remaining_bytes -= bytes_to_write;
+
+	if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) {
+		ret = hfs_drive_compressor(a, buffer_to_write,
+		    MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes);
+		if (ret < 0)
+			return (ret);
+		a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;
+	}
+	/* Ignore redundant bytes. */
+	if (a->file_remaining_bytes == 0)
+		return ((ssize_t)size);
+	return (bytes_to_write);
+}
+
+static ssize_t
+hfs_write_data_block(struct archive_write_disk *a, const char *buff,
+    size_t size)
+{
+	uint64_t start_size = size;
+	ssize_t bytes_written = 0;
+	ssize_t bytes_to_write;
+
+	if (size == 0)
+		return (ARCHIVE_OK);
+
+	if (a->filesize == 0 || a->fd < 0) {
+		archive_set_error(&a->archive, 0,
+		    "Attempt to write to an empty file");
+		return (ARCHIVE_WARN);
+	}
+
+	/* If this write would run beyond the file size, truncate it. */
+	if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
+		start_size = size = (size_t)(a->filesize - a->offset);
+
+	/* Write the data. */
+	while (size > 0) {
+		bytes_to_write = size;
+		/* Seek if necessary to the specified offset. */
+		if (a->offset < a->fd_offset) {
+			/* Can't support backword move. */
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Seek failed");
+			return (ARCHIVE_FATAL);
+		} else if (a->offset > a->fd_offset) {
+			int64_t skip = a->offset - a->fd_offset;
+			char nullblock[1024];
+
+			memset(nullblock, 0, sizeof(nullblock));
+			while (skip > 0) {
+				if (skip > (int64_t)sizeof(nullblock))
+					bytes_written = hfs_write_decmpfs_block(
+					    a, nullblock, sizeof(nullblock));
+				else
+					bytes_written = hfs_write_decmpfs_block(
+					    a, nullblock, skip);
+				if (bytes_written < 0) {
+					archive_set_error(&a->archive, errno,
+					    "Write failed");
+					return (ARCHIVE_WARN);
+				}
+				skip -= bytes_written;
+			}
+
+			a->fd_offset = a->offset;
+		}
+		bytes_written =
+		    hfs_write_decmpfs_block(a, buff, bytes_to_write);
+		if (bytes_written < 0)
+			return (bytes_written);
+		buff += bytes_written;
+		size -= bytes_written;
+		a->total_bytes_written += bytes_written;
+		a->offset += bytes_written;
+		a->fd_offset = a->offset;
+	}
+	return (start_size - size);
+}
+#else
+static ssize_t
+hfs_write_data_block(struct archive_write_disk *a, const char *buff,
+    size_t size)
+{
+	return (write_data_block(a, buff, size));
+}
+#endif
+
 static ssize_t
 _archive_write_disk_data_block(struct archive *_a,
     const void *buff, size_t size, int64_t offset)
@@ -718,7 +1459,10 @@ _archive_write_disk_data_block(struct archive *_a,
 	    ARCHIVE_STATE_DATA, "archive_write_data_block");
 
 	a->offset = offset;
-	r = write_data_block(a, buff, size);
+	if (a->todo & TODO_HFS_COMPRESSION)
+		r = hfs_write_data_block(a, buff, size);
+	else
+		r = write_data_block(a, buff, size);
 	if (r < ARCHIVE_OK)
 		return (r);
 	if ((size_t)r < size) {
@@ -737,6 +1481,8 @@ _archive_write_disk_data(struct archive *_a, const void *buff, size_t size)
 	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
 	    ARCHIVE_STATE_DATA, "archive_write_data");
 
+	if (a->todo & TODO_HFS_COMPRESSION)
+		return (hfs_write_data_block(a, buff, size));
 	return (write_data_block(a, buff, size));
 }
 
@@ -761,6 +1507,24 @@ _archive_write_disk_finish_entry(struct archive *_a)
 	} else if (a->fd_offset == a->filesize) {
 		/* Last write ended at exactly the filesize; we're done. */
 		/* Hopefully, this is the common case. */
+#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
+	} else if (a->todo & TODO_HFS_COMPRESSION) {
+		char null_d[1024];
+		ssize_t r;
+
+		if (a->file_remaining_bytes)
+			memset(null_d, 0, sizeof(null_d));
+		while (a->file_remaining_bytes) {
+			if (a->file_remaining_bytes > sizeof(null_d))
+				r = hfs_write_data_block(
+				    a, null_d, sizeof(null_d));
+			else
+				r = hfs_write_data_block(
+				    a, null_d, a->file_remaining_bytes);
+			if (r < 0)
+				return ((int)r);
+		}
+#endif
 	} else {
 #if HAVE_FTRUNCATE
 		if (ftruncate(a->fd, a->filesize) == -1 &&
@@ -799,6 +1563,22 @@ _archive_write_disk_finish_entry(struct archive *_a)
 	/* Restore metadata. */
 
 	/*
+	 * This is specific to Mac OS X.
+	 * If the current file is an AppleDouble file, it should be
+	 * linked with the data fork file and remove it.
+	 */
+	if (a->todo & TODO_APPLEDOUBLE) {
+		int r2 = fixup_appledouble(a, a->name);
+		if (r2 == ARCHIVE_EOF) {
+			/* The current file has been successfully linked
+			 * with the data fork file and removed. So there
+			 * is nothing to do on the current file.  */
+			goto finish_metadata;
+		}
+		if (r2 < ret) ret = r2;
+	}
+
+	/*
 	 * Look up the "real" UID only if we're going to need it.
 	 * TODO: the TODO_SGID condition can be dropped here, can't it?
 	 */
@@ -820,8 +1600,10 @@ _archive_write_disk_finish_entry(struct archive *_a)
 	 * bits.  If we set the owner, we know what it is and can skip
 	 * a stat() call to examine the ownership of the file on disk.
 	 */
-	if (a->todo & TODO_OWNER)
-		ret = set_ownership(a);
+	if (a->todo & TODO_OWNER) {
+		int r2 = set_ownership(a);
+		if (r2 < ret) ret = r2;
+	}
 
 	/*
 	 * set_mode must precede ACLs on systems such as Solaris and
@@ -868,7 +1650,8 @@ _archive_write_disk_finish_entry(struct archive *_a)
 		size_t metadata_size;
 		metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
 		if (metadata != NULL && metadata_size > 0) {
-			int r2 = set_mac_metadata(a, archive_entry_pathname(a->entry), metadata, metadata_size);
+			int r2 = set_mac_metadata(a, archive_entry_pathname(
+			    a->entry), metadata, metadata_size);
 			if (r2 < ret) ret = r2;
 		}
 	}
@@ -878,12 +1661,13 @@ _archive_write_disk_finish_entry(struct archive *_a)
 	 * ACLs that prevent attribute changes (including time).
 	 */
 	if (a->todo & TODO_ACLS) {
-		int r2 = set_acls(a, a->fd,
+		int r2 = archive_write_disk_set_acls(&a->archive, a->fd,
 				  archive_entry_pathname(a->entry),
 				  archive_entry_acl(a->entry));
 		if (r2 < ret) ret = r2;
 	}
 
+finish_metadata:
 	/* If there's an fd, we can close it now. */
 	if (a->fd >= 0) {
 		close(a->fd);
@@ -950,12 +1734,12 @@ archive_write_disk_gid(struct archive *_a, const char *name, int64_t id)
 int64_t
 archive_write_disk_uid(struct archive *_a, const char *name, int64_t id)
 {
-       struct archive_write_disk *a = (struct archive_write_disk *)_a;
-       archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
-           ARCHIVE_STATE_ANY, "archive_write_disk_uid");
-       if (a->lookup_uid)
-               return (a->lookup_uid)(a->lookup_uid_data, name, id);
-       return (id);
+	struct archive_write_disk *a = (struct archive_write_disk *)_a;
+	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
+	    ARCHIVE_STATE_ANY, "archive_write_disk_uid");
+	if (a->lookup_uid)
+		return (a->lookup_uid)(a->lookup_uid_data, name, id);
+	return (id);
 }
 
 /*
@@ -984,6 +1768,9 @@ archive_write_disk_new(void)
 		free(a);
 		return (NULL);
 	}
+#ifdef HAVE_ZLIB_H
+	a->decmpfs_compression_level = 5;
+#endif
 	return (&a->archive);
 }
 
@@ -1008,7 +1795,8 @@ edit_deep_directories(struct archive_write_disk *a)
 		return;
 
 	/* Try to record our starting dir. */
-	a->restore_pwd = open(".", O_RDONLY | O_BINARY);
+	a->restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC);
+	__archive_ensure_cloexec_flag(a->restore_pwd);
 	if (a->restore_pwd < 0)
 		return;
 
@@ -1143,9 +1931,10 @@ restore_entry(struct archive_write_disk *a)
 
 		/* If it's our archive, we're done. */
 		if (a->skip_file_set &&
-		    a->st.st_dev == a->skip_file_dev &&
-		    a->st.st_ino == a->skip_file_ino) {
-			archive_set_error(&a->archive, 0, "Refusing to overwrite archive");
+		    a->st.st_dev == (dev_t)a->skip_file_dev &&
+		    a->st.st_ino == (ino_t)a->skip_file_ino) {
+			archive_set_error(&a->archive, 0,
+			    "Refusing to overwrite archive");
 			return (ARCHIVE_FAILED);
 		}
 
@@ -1163,7 +1952,7 @@ restore_entry(struct archive_write_disk *a)
 			/* A dir is in the way of a non-dir, rmdir it. */
 			if (rmdir(a->name) != 0) {
 				archive_set_error(&a->archive, errno,
-				    "Can't remove already-existing dir");
+				    "Can't replace existing directory with non-directory");
 				return (ARCHIVE_FAILED);
 			}
 			/* Try again. */
@@ -1223,7 +2012,7 @@ create_filesystem_object(struct archive_write_disk *a)
 		 *
 		 * If the hardlink was successfully created and
 		 * the archive doesn't have carry data for it,
-		 * consider it to be non-authoritive for meta data.
+		 * consider it to be non-authoritative for meta data.
 		 * This is consistent with GNU tar and BSD pax.
 		 * If the hardlink does carry data, let the last
 		 * archive entry decide ownership.
@@ -1232,7 +2021,9 @@ create_filesystem_object(struct archive_write_disk *a)
 			a->todo = 0;
 			a->deferred = 0;
 		} else if (r == 0 && a->filesize > 0) {
-			a->fd = open(a->name, O_WRONLY | O_TRUNC | O_BINARY);
+			a->fd = open(a->name,
+				     O_WRONLY | O_TRUNC | O_BINARY | O_CLOEXEC);
+			__archive_ensure_cloexec_flag(a->fd);
 			if (a->fd < 0)
 				r = errno;
 		}
@@ -1261,7 +2052,7 @@ create_filesystem_object(struct archive_write_disk *a)
 	 * that SUID, SGID, etc, require additional work to ensure
 	 * security, so we never restore them at this point.
 	 */
-	mode = final_mode & 0777 & a->user_umask;
+	mode = final_mode & 0777 & ~a->user_umask;
 
 	switch (a->mode & AE_IFMT) {
 	default:
@@ -1269,7 +2060,8 @@ create_filesystem_object(struct archive_write_disk *a)
 		/* FALLTHROUGH */
 	case AE_IFREG:
 		a->fd = open(a->name,
-		    O_WRONLY | O_CREAT | O_EXCL | O_BINARY, mode);
+		    O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode);
+		__archive_ensure_cloexec_flag(a->fd);
 		r = (a->fd < 0);
 		break;
 	case AE_IFCHR:
@@ -1380,7 +2172,8 @@ _archive_write_disk_close(struct archive *_a)
 		if (p->fixup & TODO_MODE_BASE)
 			chmod(p->name, p->mode);
 		if (p->fixup & TODO_ACLS)
-			set_acls(a, -1, p->name, &p->acl);
+			archive_write_disk_set_acls(&a->archive,
+						    -1, p->name, &p->acl);
 		if (p->fixup & TODO_FFLAGS)
 			set_fflags_platform(a, -1, p->name,
 			    p->mode, p->fflags_set, 0);
@@ -1418,6 +2211,23 @@ _archive_write_disk_free(struct archive *_a)
 	archive_string_free(&a->path_safe);
 	a->archive.magic = 0;
 	__archive_clean(&a->archive);
+	free(a->decmpfs_header_p);
+	free(a->resource_fork);
+	free(a->compressed_buffer);
+	free(a->uncompressed_buffer);
+#ifdef HAVE_ZLIB_H
+	if (a->stream_valid) {
+		switch (deflateEnd(&a->stream)) {
+		case Z_OK:
+			break;
+		default:
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Failed to clean up compressor");
+			ret = ARCHIVE_FATAL;
+			break;
+		}
+	}
+#endif
 	free(a);
 	return (ret);
 }
@@ -1499,8 +2309,11 @@ new_fixup(struct archive_write_disk *a, const char *pathname)
 	struct fixup_entry *fe;
 
 	fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry));
-	if (fe == NULL)
+	if (fe == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate memory for a fixup");
 		return (NULL);
+	}
 	fe->next = a->fixup_list;
 	a->fixup_list = fe;
 	fe->fixup = 0;
@@ -1672,7 +2485,7 @@ cleanup_pathname_win(struct archive_write_disk *a)
 	p = a->name;
 	while (*p != '\0' && alen) {
 		l = mbtowc(&wc, p, alen);
-		if (l == -1) {
+		if (l == (size_t)-1) {
 			while (*p != '\0') {
 				if (*p == '\\')
 					*p = '/';
@@ -1887,6 +2700,8 @@ create_dir(struct archive_write_disk *a, char *path)
 	if (mkdir(path, mode) == 0) {
 		if (mode != mode_final) {
 			le = new_fixup(a, path);
+			if (le == NULL)
+				return (ARCHIVE_FATAL);
 			le->fixup |=TODO_MODE_BASE;
 			le->mode = mode_final;
 		}
@@ -1979,6 +2794,7 @@ set_time(int fd, int mode, const char *name,
 	 * on fds and symlinks.
 	 */
 	struct timespec ts[2];
+	(void)mode; /* UNUSED */
 	ts[0].tv_sec = atime;
 	ts[0].tv_nsec = atime_nsec;
 	ts[1].tv_sec = mtime;
@@ -2036,6 +2852,11 @@ set_time(int fd, int mode, const char *name,
 	/*
 	 * We don't know how to set the time on this platform.
 	 */
+	(void)fd; /* UNUSED */
+	(void)mode; /* UNUSED */
+	(void)name; /* UNUSED */
+	(void)atime_nsec; /* UNUSED */
+	(void)mtime_nsec; /* UNUSED */
 	return (ARCHIVE_WARN);
 #endif
 }
@@ -2068,7 +2889,7 @@ set_times(struct archive_write_disk *a,
     time_t atime, long atime_nanos,
     time_t birthtime, long birthtime_nanos,
     time_t mtime, long mtime_nanos,
-    time_t ctime, long ctime_nanos)
+    time_t cctime, long ctime_nanos)
 {
 	/* Note: set_time doesn't use libarchive return conventions!
 	 * It uses syscall conventions.  So 0 here instead of ARCHIVE_OK. */
@@ -2083,9 +2904,12 @@ set_times(struct archive_write_disk *a,
 	if (a->user_uid == 0 &&
 	    set_time_tru64(fd, mode, name,
 			   atime, atime_nanos, mtime,
-			   mtime_nanos, ctime, ctime_nanos) == 0) {
+			   mtime_nanos, cctime, ctime_nanos) == 0) {
 		return (ARCHIVE_OK);
 	}
+#else /* Tru64 */
+	(void)cctime; /* UNUSED */
+	(void)ctime_nanos; /* UNUSED */
 #endif /* Tru64 */
 
 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
@@ -2102,6 +2926,9 @@ set_times(struct archive_write_disk *a,
 		r1 = set_time(fd, mode, name,
 			      atime, atime_nanos,
 			      birthtime, birthtime_nanos);
+#else
+	(void)birthtime; /* UNUSED */
+	(void)birthtime_nanos; /* UNUSED */
 #endif
 	r2 = set_time(fd, mode, name,
 		      atime, atime_nanos,
@@ -2117,11 +2944,11 @@ set_times(struct archive_write_disk *a,
 static int
 set_times_from_entry(struct archive_write_disk *a)
 {
-	time_t atime, birthtime, mtime, ctime;
+	time_t atime, birthtime, mtime, cctime;
 	long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec;
 
 	/* Suitable defaults. */
-	atime = birthtime = mtime = ctime = a->start_time;
+	atime = birthtime = mtime = cctime = a->start_time;
 	atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0;
 
 	/* If no time was provided, we're done. */
@@ -2145,7 +2972,7 @@ set_times_from_entry(struct archive_write_disk *a)
 		mtime_nsec = archive_entry_mtime_nsec(a->entry);
 	}
 	if (archive_entry_ctime_is_set(a->entry)) {
-		ctime = archive_entry_ctime(a->entry);
+		cctime = archive_entry_ctime(a->entry);
 		ctime_nsec = archive_entry_ctime_nsec(a->entry);
 	}
 
@@ -2153,7 +2980,7 @@ set_times_from_entry(struct archive_write_disk *a)
 			 atime, atime_nsec,
 			 birthtime, birthtime_nsec,
 			 mtime, mtime_nsec,
-			 ctime, ctime_nsec);
+			 cctime, ctime_nsec);
 }
 
 static int
@@ -2312,6 +3139,8 @@ set_fflags(struct archive_write_disk *a)
 		 */
 		if ((critical_flags != 0)  &&  (set & critical_flags)) {
 			le = current_fixup(a, a->name);
+			if (le == NULL)
+				return (ARCHIVE_FATAL);
 			le->fixup |= TODO_FFLAGS;
 			le->fflags_set = set;
 			/* Store the mode if it's not already there. */
@@ -2390,8 +3219,8 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
 {
 	int		 ret;
 	int		 myfd = fd;
-	unsigned long newflags, oldflags;
-	unsigned long sf_mask = 0;
+	int newflags, oldflags;
+	int sf_mask = 0;
 
 	if (set == 0  && clear == 0)
 		return (ARCHIVE_OK);
@@ -2400,8 +3229,10 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
 		return (ARCHIVE_OK);
 
 	/* If we weren't given an fd, open it ourselves. */
-	if (myfd < 0)
-		myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY);
+	if (myfd < 0) {
+		myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC);
+		__archive_ensure_cloexec_flag(myfd);
+	}
 	if (myfd < 0)
 		return (ARCHIVE_OK);
 
@@ -2486,12 +3317,196 @@ set_mac_metadata(struct archive_write_disk *a, const char *pathname,
 	(void)metadata_size; /* UNUSED */
 	return (ARCHIVE_OK);
 }
+
+static int
+fixup_appledouble(struct archive_write_disk *a, const char *pathname)
+{
+	(void)a; /* UNUSED */
+	(void)pathname; /* UNUSED */
+	return (ARCHIVE_OK);
+}
 #else
 
 /*
  * On Mac OS, we use copyfile() to unpack the metadata and
  * apply it to the target file.
  */
+
+#if defined(HAVE_SYS_XATTR_H)
+static int
+copy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd)
+{
+	ssize_t xattr_size;
+	char *xattr_names = NULL, *xattr_val = NULL;
+	int ret = ARCHIVE_OK, xattr_i;
+
+	xattr_size = flistxattr(tmpfd, NULL, 0, 0);
+	if (xattr_size == -1) {
+		archive_set_error(&a->archive, errno,
+		    "Failed to read metadata(xattr)");
+		ret = ARCHIVE_WARN;
+		goto exit_xattr;
+	}
+	xattr_names = malloc(xattr_size);
+	if (xattr_names == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate memory for metadata(xattr)");
+		ret = ARCHIVE_FATAL;
+		goto exit_xattr;
+	}
+	xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0);
+	if (xattr_size == -1) {
+		archive_set_error(&a->archive, errno,
+		    "Failed to read metadata(xattr)");
+		ret = ARCHIVE_WARN;
+		goto exit_xattr;
+	}
+	for (xattr_i = 0; xattr_i < xattr_size;
+	    xattr_i += strlen(xattr_names + xattr_i) + 1) {
+		ssize_t s;
+		int f;
+
+		s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0);
+		if (s == -1) {
+			archive_set_error(&a->archive, errno,
+			    "Failed to get metadata(xattr)");
+			ret = ARCHIVE_WARN;
+			goto exit_xattr;
+		}
+		xattr_val = realloc(xattr_val, s);
+		if (xattr_val == NULL) {
+			archive_set_error(&a->archive, ENOMEM,
+			    "Failed to get metadata(xattr)");
+			ret = ARCHIVE_WARN;
+			goto exit_xattr;
+		}
+		s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0);
+		if (s == -1) {
+			archive_set_error(&a->archive, errno,
+			    "Failed to get metadata(xattr)");
+			ret = ARCHIVE_WARN;
+			goto exit_xattr;
+		}
+		f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0);
+		if (f == -1) {
+			archive_set_error(&a->archive, errno,
+			    "Failed to get metadata(xattr)");
+			ret = ARCHIVE_WARN;
+			goto exit_xattr;
+		}
+	}
+exit_xattr:
+	free(xattr_names);
+	free(xattr_val);
+	return (ret);
+}
+#endif
+
+static int
+copy_acls(struct archive_write_disk *a, int tmpfd, int dffd)
+{
+	acl_t acl, dfacl = NULL;
+	int acl_r, ret = ARCHIVE_OK;
+
+	acl = acl_get_fd(tmpfd);
+	if (acl == NULL) {
+		if (errno == ENOENT)
+			/* There are not any ACLs. */
+			return (ret);
+		archive_set_error(&a->archive, errno,
+		    "Failed to get metadata(acl)");
+		ret = ARCHIVE_WARN;
+		goto exit_acl;
+	}
+	dfacl = acl_dup(acl);
+	acl_r = acl_set_fd(dffd, dfacl);
+	if (acl_r == -1) {
+		archive_set_error(&a->archive, errno,
+		    "Failed to get metadata(acl)");
+		ret = ARCHIVE_WARN;
+		goto exit_acl;
+	}
+exit_acl:
+	if (acl)
+		acl_free(acl);
+	if (dfacl)
+		acl_free(dfacl);
+	return (ret);
+}
+
+static int
+create_tempdatafork(struct archive_write_disk *a, const char *pathname)
+{
+	struct archive_string tmpdatafork;
+	int tmpfd;
+
+	archive_string_init(&tmpdatafork);
+	archive_strcpy(&tmpdatafork, "tar.md.XXXXXX");
+	tmpfd = mkstemp(tmpdatafork.s);
+	if (tmpfd < 0) {
+		archive_set_error(&a->archive, errno,
+		    "Failed to mkstemp");
+		archive_string_free(&tmpdatafork);
+		return (-1);
+	}
+	if (copyfile(pathname, tmpdatafork.s, 0,
+	    COPYFILE_UNPACK | COPYFILE_NOFOLLOW
+	    | COPYFILE_ACL | COPYFILE_XATTR) < 0) {
+		archive_set_error(&a->archive, errno,
+		    "Failed to restore metadata");
+		close(tmpfd);
+		tmpfd = -1;
+	}
+	unlink(tmpdatafork.s);
+	archive_string_free(&tmpdatafork);
+	return (tmpfd);
+}
+
+static int
+copy_metadata(struct archive_write_disk *a, const char *metadata,
+    const char *datafork, int datafork_compressed)
+{
+	int ret = ARCHIVE_OK;
+
+	if (datafork_compressed) {
+		int dffd, tmpfd;
+
+		tmpfd = create_tempdatafork(a, metadata);
+		if (tmpfd == -1)
+			return (ARCHIVE_WARN);
+
+		/*
+		 * Do not open the data fork compressed by HFS+ compression
+		 * with at least a writing mode(O_RDWR or O_WRONLY). it
+		 * makes the data fork uncompressed.
+		 */
+		dffd = open(datafork, 0);
+		if (dffd == -1) {
+			archive_set_error(&a->archive, errno,
+			    "Failed to open the data fork for metadata");
+			close(tmpfd);
+			return (ARCHIVE_WARN);
+		}
+
+#if defined(HAVE_SYS_XATTR_H)
+		ret = copy_xattrs(a, tmpfd, dffd);
+		if (ret == ARCHIVE_OK)
+#endif
+			ret = copy_acls(a, tmpfd, dffd);
+		close(tmpfd);
+		close(dffd);
+	} else {
+		if (copyfile(metadata, datafork, 0,
+		    COPYFILE_UNPACK | COPYFILE_NOFOLLOW
+		    | COPYFILE_ACL | COPYFILE_XATTR) < 0) {
+			archive_set_error(&a->archive, errno,
+			    "Failed to restore metadata");
+			ret = ARCHIVE_WARN;
+		}
+	}
+	return (ret);
+}
+
 static int
 set_mac_metadata(struct archive_write_disk *a, const char *pathname,
 		 const void *metadata, size_t metadata_size)
@@ -2513,139 +3528,101 @@ set_mac_metadata(struct archive_write_disk *a, const char *pathname,
 	if (fd < 0) {
 		archive_set_error(&a->archive, errno,
 				  "Failed to restore metadata");
+		archive_string_free(&tmp);
 		return (ARCHIVE_WARN);
 	}
 	written = write(fd, metadata, metadata_size);
 	close(fd);
-	if (written != metadata_size
-	    || copyfile(tmp.s, pathname, 0,
-			COPYFILE_UNPACK | COPYFILE_NOFOLLOW
-			| COPYFILE_ACL | COPYFILE_XATTR)) {
+	if ((size_t)written != metadata_size) {
 		archive_set_error(&a->archive, errno,
 				  "Failed to restore metadata");
 		ret = ARCHIVE_WARN;
+	} else {
+		int compressed;
+
+#if defined(UF_COMPRESSED)
+		if ((a->todo & TODO_HFS_COMPRESSION) != 0 &&
+		    (ret = lazy_stat(a)) == ARCHIVE_OK)
+			compressed = a->st.st_flags & UF_COMPRESSED;
+		else
+#endif
+			compressed = 0;
+		ret = copy_metadata(a, tmp.s, pathname, compressed);
 	}
 	unlink(tmp.s);
+	archive_string_free(&tmp);
 	return (ret);
 }
-#endif
 
-#ifndef HAVE_POSIX_ACL
-/* Default empty function body to satisfy mainline code. */
 static int
-set_acls(struct archive_write_disk *a, int fd, const char *name,
-	 struct archive_acl *acl)
+fixup_appledouble(struct archive_write_disk *a, const char *pathname)
 {
-	(void)a; /* UNUSED */
-	(void)fd; /* UNUSED */
-	(void)name; /* UNUSED */
-	(void)acl; /* UNUSED */
-	return (ARCHIVE_OK);
-}
-
-#else
-
-/*
- * XXX TODO: What about ACL types other than ACCESS and DEFAULT?
- */
-static int
-set_acls(struct archive_write_disk *a, int fd, const char *name,
-	 struct archive_acl *abstract_acl)
-{
-	int		 ret;
-
-	ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_ACCESS,
-	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
-	if (ret != ARCHIVE_OK)
-		return (ret);
-	ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT,
-	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
-	return (ret);
-}
-
-
-static int
-set_acl(struct archive_write_disk *a, int fd, const char *name,
-    struct archive_acl *abstract_acl,
-    acl_type_t acl_type, int ae_requested_type, const char *tname)
-{
-	acl_t		 acl;
-	acl_entry_t	 acl_entry;
-	acl_permset_t	 acl_permset;
-	int		 ret;
-	int		 ae_type, ae_permset, ae_tag, ae_id;
-	uid_t		 ae_uid;
-	gid_t		 ae_gid;
-	const char	*ae_name;
-	int		 entries;
+	char buff[8];
+	struct stat st;
+	const char *p;
+	struct archive_string datafork;
+	int fd = -1, ret = ARCHIVE_OK;
+
+	archive_string_init(&datafork);
+	/* Check if the current file name is a type of the resource
+	 * fork file. */
+	p = strrchr(pathname, '/');
+	if (p == NULL)
+		p = pathname;
+	else
+		p++;
+	if (p[0] != '.' || p[1] != '_')
+		goto skip_appledouble;
 
-	ret = ARCHIVE_OK;
-	entries = archive_acl_reset(abstract_acl, ae_requested_type);
-	if (entries == 0)
-		return (ARCHIVE_OK);
-	acl = acl_init(entries);
-	while (archive_acl_next(&a->archive, abstract_acl,
-	    ae_requested_type, &ae_type, &ae_permset, &ae_tag, &ae_id,
-	    &ae_name) == ARCHIVE_OK) {
-		acl_create_entry(&acl, &acl_entry);
-
-		switch (ae_tag) {
-		case ARCHIVE_ENTRY_ACL_USER:
-			acl_set_tag_type(acl_entry, ACL_USER);
-			ae_uid = archive_write_disk_uid(&a->archive,
-			    ae_name, ae_id);
-			acl_set_qualifier(acl_entry, &ae_uid);
-			break;
-		case ARCHIVE_ENTRY_ACL_GROUP:
-			acl_set_tag_type(acl_entry, ACL_GROUP);
-			ae_gid = archive_write_disk_gid(&a->archive,
-			    ae_name, ae_id);
-			acl_set_qualifier(acl_entry, &ae_gid);
-			break;
-		case ARCHIVE_ENTRY_ACL_USER_OBJ:
-			acl_set_tag_type(acl_entry, ACL_USER_OBJ);
-			break;
-		case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
-			acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
-			break;
-		case ARCHIVE_ENTRY_ACL_MASK:
-			acl_set_tag_type(acl_entry, ACL_MASK);
-			break;
-		case ARCHIVE_ENTRY_ACL_OTHER:
-			acl_set_tag_type(acl_entry, ACL_OTHER);
-			break;
-		default:
-			/* XXX */
-			break;
-		}
+	/*
+	 * Check if the data fork file exists.
+	 *
+	 * TODO: Check if this write disk object has handled it.
+	 */
+	archive_strncpy(&datafork, pathname, p - pathname);
+	archive_strcat(&datafork, p + 2);
+	if (lstat(datafork.s, &st) == -1 ||
+	    (st.st_mode & AE_IFMT) != AE_IFREG)
+		goto skip_appledouble;
 
-		acl_get_permset(acl_entry, &acl_permset);
-		acl_clear_perms(acl_permset);
-		if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE)
-			acl_add_perm(acl_permset, ACL_EXECUTE);
-		if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE)
-			acl_add_perm(acl_permset, ACL_WRITE);
-		if (ae_permset & ARCHIVE_ENTRY_ACL_READ)
-			acl_add_perm(acl_permset, ACL_READ);
+	/*
+	 * Check if the file is in the AppleDouble form.
+	 */
+	fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC);
+	__archive_ensure_cloexec_flag(fd);
+	if (fd == -1) {
+		archive_set_error(&a->archive, errno,
+		    "Failed to open a restoring file");
+		ret = ARCHIVE_WARN;
+		goto skip_appledouble;
 	}
-
-	/* Try restoring the ACL through 'fd' if we can. */
-#if HAVE_ACL_SET_FD
-	if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
-		ret = ARCHIVE_OK;
-	else
+	if (read(fd, buff, 8) == -1) {
+		archive_set_error(&a->archive, errno,
+		    "Failed to read a restoring file");
+		close(fd);
+		ret = ARCHIVE_WARN;
+		goto skip_appledouble;
+	}
+	close(fd);
+	/* Check AppleDouble Magic Code. */
+	if (archive_be32dec(buff) != 0x00051607)
+		goto skip_appledouble;
+	/* Check AppleDouble Version. */
+	if (archive_be32dec(buff+4) != 0x00020000)
+		goto skip_appledouble;
+
+	ret = copy_metadata(a, pathname, datafork.s,
+#if defined(UF_COMPRESSED)
+	    st.st_flags & UF_COMPRESSED);
 #else
-#if HAVE_ACL_SET_FD_NP
-	if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
-		ret = ARCHIVE_OK;
-	else
-#endif
+	    0);
 #endif
-	if (acl_set_file(name, acl_type, acl) != 0) {
-		archive_set_error(&a->archive, errno, "Failed to set %s acl", tname);
-		ret = ARCHIVE_WARN;
+	if (ret == ARCHIVE_OK) {
+		unlink(pathname);
+		ret = ARCHIVE_EOF;
 	}
-	acl_free(acl);
+skip_appledouble:
+	archive_string_free(&datafork);
 	return (ret);
 }
 #endif
diff --git a/libarchive/archive_write_disk_private.h b/libarchive/archive_write_disk_private.h
index 707c0cf..d84e7e1 100644
--- a/libarchive/archive_write_disk_private.h
+++ b/libarchive/archive_write_disk_private.h
@@ -33,6 +33,11 @@
 #ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
 #define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
 
+#include "archive_acl_private.h"
+
 struct archive_write_disk;
 
+int
+archive_write_disk_set_acls(struct archive *, int /* fd */, const char * /* pathname */, struct archive_acl *);
+
 #endif
diff --git a/libarchive/archive_write_disk_set_standard_lookup.c b/libarchive/archive_write_disk_set_standard_lookup.c
index 5ee89a7..e79008e 100644
--- a/libarchive/archive_write_disk_set_standard_lookup.c
+++ b/libarchive/archive_write_disk_set_standard_lookup.c
@@ -122,6 +122,7 @@ lookup_gid(void *private_data, const char *gname, int64_t gid)
 		char _buffer[128];
 		size_t bufsize = 128;
 		char *buffer = _buffer;
+		char *allocated = NULL;
 		struct group	grent, *result;
 		int r;
 
@@ -133,16 +134,15 @@ lookup_gid(void *private_data, const char *gname, int64_t gid)
 			if (r != ERANGE)
 				break;
 			bufsize *= 2;
-			if (buffer != _buffer)
-				free(buffer);
-			buffer = malloc(bufsize);
-			if (buffer == NULL)
+			free(allocated);
+			allocated = malloc(bufsize);
+			if (allocated == NULL)
 				break;
+			buffer = allocated;
 		}
 		if (result != NULL)
 			gid = result->gr_gid;
-		if (buffer != _buffer)
-			free(buffer);
+		free(allocated);
 	}
 #  else /* HAVE_GETGRNAM_R */
 	{
@@ -158,7 +158,7 @@ lookup_gid(void *private_data, const char *gname, int64_t gid)
 #else
 	#error No way to perform gid lookups on this platform
 #endif
-	b->id = gid;
+	b->id = (gid_t)gid;
 
 	return (gid);
 }
@@ -192,6 +192,7 @@ lookup_uid(void *private_data, const char *uname, int64_t uid)
 		char _buffer[128];
 		size_t bufsize = 128;
 		char *buffer = _buffer;
+		char *allocated = NULL;
 		struct passwd	pwent, *result;
 		int r;
 
@@ -203,16 +204,15 @@ lookup_uid(void *private_data, const char *uname, int64_t uid)
 			if (r != ERANGE)
 				break;
 			bufsize *= 2;
-			if (buffer != _buffer)
-				free(buffer);
-			buffer = malloc(bufsize);
-			if (buffer == NULL)
+			free(allocated);
+			allocated = malloc(bufsize);
+			if (allocated == NULL)
 				break;
+			buffer = allocated;
 		}
 		if (result != NULL)
 			uid = result->pw_uid;
-		if (buffer != _buffer)
-			free(buffer);
+		free(allocated);
 	}
 #  else /* HAVE_GETPWNAM_R */
 	{
@@ -228,7 +228,7 @@ lookup_uid(void *private_data, const char *uname, int64_t uid)
 #else
 	#error No way to look up uids on this platform
 #endif
-	b->id = uid;
+	b->id = (uid_t)uid;
 
 	return (uid);
 }
diff --git a/libarchive/archive_write_disk_windows.c b/libarchive/archive_write_disk_windows.c
index 2dc2d92..0f0780a 100644
--- a/libarchive/archive_write_disk_windows.c
+++ b/libarchive/archive_write_disk_windows.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2003-2010 Tim Kientzle
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,9 +33,6 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
 #ifdef HAVE_SYS_UTIME_H
 #include <sys/utime.h>
 #endif
@@ -48,13 +45,9 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_LIMITS_H
 #include <limits.h>
 #endif
-#include <stdio.h>
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
 #include <winioctl.h>
 
 /* TODO: Support Mac OS 'quarantine' feature.  This is really just a
@@ -89,7 +82,7 @@ static BOOL SetFilePointerEx_perso(HANDLE hFile,
 	if(lpNewFilePointer) {
 		lpNewFilePointer->QuadPart = li.QuadPart;
 	}
-	return li.LowPart != -1 || GetLastError() == NO_ERROR;
+	return li.LowPart != (DWORD)-1 || GetLastError() == NO_ERROR;
 }
 
 struct fixup_entry {
@@ -144,8 +137,8 @@ struct archive_write_disk {
 	struct fixup_entry	*current_fixup;
 	int64_t			 user_uid;
 	int			 skip_file_set;
-	dev_t			 skip_file_dev;
-	ino_t			 skip_file_ino;
+	int64_t			 skip_file_dev;
+	int64_t			 skip_file_ino;
 	time_t			 start_time;
 
 	int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid);
@@ -214,26 +207,24 @@ struct archive_write_disk {
 
 static int	check_symlinks(struct archive_write_disk *);
 static int	create_filesystem_object(struct archive_write_disk *);
-static struct fixup_entry *current_fixup(struct archive_write_disk *, const wchar_t *pathname);
-#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
-static void	edit_deep_directories(struct archive_write_disk *ad);
-#endif
+static struct fixup_entry *current_fixup(struct archive_write_disk *,
+		    const wchar_t *pathname);
 static int	cleanup_pathname(struct archive_write_disk *);
 static int	create_dir(struct archive_write_disk *, wchar_t *);
 static int	create_parent_dir(struct archive_write_disk *, wchar_t *);
+static int	la_chmod(const wchar_t *, mode_t);
 static int	older(BY_HANDLE_FILE_INFORMATION *, struct archive_entry *);
+static int	permissive_name_w(struct archive_write_disk *);
 static int	restore_entry(struct archive_write_disk *);
-#ifdef HAVE_POSIX_ACL
-static int	set_acl(struct archive_write_disk *, int fd, const char *, struct archive_acl *,
-		    acl_type_t, int archive_entry_acl_type, const char *tn);
-#endif
-static int	set_acls(struct archive_write_disk *, HANDLE h, const wchar_t *, struct archive_acl *);
+static int	set_acls(struct archive_write_disk *, HANDLE h,
+		    const wchar_t *, struct archive_acl *);
 static int	set_xattrs(struct archive_write_disk *);
 static int	set_fflags(struct archive_write_disk *);
 static int	set_ownership(struct archive_write_disk *);
 static int	set_mode(struct archive_write_disk *, int mode);
-static int	set_times(struct archive_write_disk *, HANDLE, int, const wchar_t *,
-		    time_t, long, time_t, long, time_t, long, time_t, long);
+static int	set_times(struct archive_write_disk *, HANDLE, int,
+		    const wchar_t *, time_t, long, time_t, long, time_t,
+		    long, time_t, long);
 static int	set_times_from_entry(struct archive_write_disk *);
 static struct fixup_entry *sort_dir_list(struct fixup_entry *p);
 static ssize_t	write_data_block(struct archive_write_disk *,
@@ -243,11 +234,14 @@ static struct archive_vtable *archive_write_disk_vtable(void);
 
 static int	_archive_write_disk_close(struct archive *);
 static int	_archive_write_disk_free(struct archive *);
-static int	_archive_write_disk_header(struct archive *, struct archive_entry *);
+static int	_archive_write_disk_header(struct archive *,
+		    struct archive_entry *);
 static int64_t	_archive_write_disk_filter_bytes(struct archive *, int);
 static int	_archive_write_disk_finish_entry(struct archive *);
-static ssize_t	_archive_write_disk_data(struct archive *, const void *, size_t);
-static ssize_t	_archive_write_disk_data_block(struct archive *, const void *, size_t, int64_t);
+static ssize_t	_archive_write_disk_data(struct archive *, const void *,
+		    size_t);
+static ssize_t	_archive_write_disk_data_block(struct archive *, const void *,
+		    size_t, int64_t);
 
 #define bhfi_dev(bhfi)	((bhfi)->dwVolumeSerialNumber)
 /* Treat FileIndex as i-node. We should remove a sequence number
@@ -361,7 +355,7 @@ file_information(struct archive_write_disk *a, wchar_t *path,
  * So we have to make the full-pathname in another way, which does not
  * break "../" path string.
  */
-int
+static int
 permissive_name_w(struct archive_write_disk *a)
 {
 	wchar_t *wn, *wnp;
@@ -424,10 +418,12 @@ permissive_name_w(struct archive_write_disk *a)
 				wn = _wcsdup(wnp);
 				if (wn == NULL)
 					return (-1);
-				archive_wstring_ensure(&(a->_name_data), 8 + wcslen(wn) + 1);
+				archive_wstring_ensure(&(a->_name_data),
+					8 + wcslen(wn) + 1);
 				a->name = a->_name_data.s;
 				/* Prepend "\\?\UNC\" */
-				archive_wstrncpy(&(a->_name_data), L"\\\\?\\UNC\\", 8);
+				archive_wstrncpy(&(a->_name_data),
+					L"\\\\?\\UNC\\", 8);
 				archive_wstrcat(&(a->_name_data), wn+2);
 				free(wn);
 				return (0);
@@ -457,7 +453,8 @@ permissive_name_w(struct archive_write_disk *a)
 		wn = _wcsdup(wnp);
 		if (wn == NULL)
 			return (-1);
-		archive_wstring_ensure(&(a->_name_data), 4 + 2 + wcslen(wn) + 1);
+		archive_wstring_ensure(&(a->_name_data),
+			4 + 2 + wcslen(wn) + 1);
 		a->name = a->_name_data.s;
 		/* Prepend "\\?\" and drive name. */
 		archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
@@ -484,7 +481,7 @@ permissive_name_w(struct archive_write_disk *a)
 	return (0);
 }
 
-int
+static int
 la_chmod(const wchar_t *path, mode_t mode)
 {
 	DWORD attr;
@@ -610,7 +607,7 @@ lazy_stat(struct archive_write_disk *a)
 
 	/*
 	 * XXX At this point, symlinks should not be hit, otherwise
-	 * XXX a race occured.  Do we want to check explicitly for that?
+	 * XXX a race occurred.  Do we want to check explicitly for that?
 	 */
 	if (file_information(a, a->name, &a->st, NULL, 1) == 0) {
 		a->pst = &a->st;
@@ -917,6 +914,7 @@ archive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i)
 static ssize_t
 write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
 {
+	OVERLAPPED ol;
 	uint64_t start_size = size;
 	DWORD bytes_written = 0;
 	ssize_t block_size = 0, bytes_to_write;
@@ -968,26 +966,13 @@ write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
 			 * truncate it to the block boundary. */
 			bytes_to_write = size;
 			if (a->offset + bytes_to_write > block_end)
-				bytes_to_write = block_end - a->offset;
+				bytes_to_write = (DWORD)(block_end - a->offset);
 		}
-		/* Seek if necessary to the specified offset. */
-		if (a->offset != a->fd_offset) {
-			LARGE_INTEGER distance;
-			distance.QuadPart = a->offset;
-			if (SetFilePointerEx_perso(a->fh, distance, NULL, FILE_BEGIN) == 0) {
-				DWORD lasterr = GetLastError();
-				if (lasterr == ERROR_ACCESS_DENIED)
-					errno = EBADF;
-				else
-					la_dosmaperr(lasterr);
-				archive_set_error(&a->archive, errno,
-				    "Seek failed");
-				return (ARCHIVE_FATAL);
-			}
-			a->fd_offset = a->offset;
- 		}
+		memset(&ol, 0, sizeof(ol));
+		ol.Offset = (DWORD)(a->offset & 0xFFFFFFFF);
+		ol.OffsetHigh = (DWORD)(a->offset >> 32);
 		if (!WriteFile(a->fh, buff, (uint32_t)bytes_to_write,
-		    &bytes_written, NULL)) {
+		    &bytes_written, &ol)) {
 			DWORD lasterr;
 
 			lasterr = GetLastError();
@@ -1004,7 +989,7 @@ write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
 		a->offset += bytes_written;
 		a->fd_offset = a->offset;
 	}
-	return (start_size - size);
+	return ((ssize_t)(start_size - size));
 }
 
 static ssize_t
@@ -1062,48 +1047,11 @@ _archive_write_disk_finish_entry(struct archive *_a)
 		/* Last write ended at exactly the filesize; we're done. */
 		/* Hopefully, this is the common case. */
 	} else {
-		if (la_ftruncate(a->fh, a->filesize) == -1 &&
-		    a->filesize == 0) {
+		if (la_ftruncate(a->fh, a->filesize) == -1) {
 			archive_set_error(&a->archive, errno,
 			    "File size could not be restored");
 			return (ARCHIVE_FAILED);
 		}
-		/*
-		 * Not all platforms implement the XSI option to
-		 * extend files via ftruncate.  Stat() the file again
-		 * to see what happened.
-		 */
-		a->pst = NULL;
-		if ((ret = lazy_stat(a)) != ARCHIVE_OK)
-			return (ret);
-		/* We can use lseek()/write() to extend the file if
-		 * ftruncate didn't work or isn't available. */
-		if (bhfi_size(&(a->st)) < a->filesize) {
-			const char nul = '\0';
-			LARGE_INTEGER distance;
-			distance.QuadPart = a->filesize - 1;
-			if (!SetFilePointerEx_perso(a->fh, distance, NULL, FILE_BEGIN)) {
-				DWORD lasterr = GetLastError();
-				if (lasterr == ERROR_ACCESS_DENIED)
-					errno = EBADF;
-				else
-					la_dosmaperr(lasterr);
-				archive_set_error(&a->archive, errno,
-				    "Seek failed");
-				return (ARCHIVE_FATAL);
-			}
-			if (!WriteFile(a->fh, &nul, 1, NULL, NULL)) {
-				DWORD lasterr = GetLastError();
-				if (lasterr == ERROR_ACCESS_DENIED)
-					errno = EBADF;
-				else
-					la_dosmaperr(lasterr);
-				archive_set_error(&a->archive, errno,
-				    "Write to restore size failed");
-				return (ARCHIVE_FATAL);
-			}
-			a->pst = NULL;
-		}
 	}
 
 	/* Restore metadata. */
@@ -1430,7 +1378,8 @@ restore_entry(struct archive_write_disk *a)
 		if (a->skip_file_set &&
 		    bhfi_dev(&a->st) == a->skip_file_dev &&
 		    bhfi_ino(&a->st) == a->skip_file_ino) {
-			archive_set_error(&a->archive, 0, "Refusing to overwrite archive");
+			archive_set_error(&a->archive, 0,
+			    "Refusing to overwrite archive");
 			return (ARCHIVE_FAILED);
 		}
 
@@ -1471,7 +1420,7 @@ restore_entry(struct archive_write_disk *a)
 
 	if (en) {
 		/* Everything failed; give up here. */
-		archive_set_error(&a->archive, en, "Can't create '%s'",
+		archive_set_error(&a->archive, en, "Can't create '%ls'",
 		    a->name);
 		return (ARCHIVE_FAILED);
 	}
@@ -1520,7 +1469,7 @@ create_filesystem_object(struct archive_write_disk *a)
 		 *
 		 * If the hardlink was successfully created and
 		 * the archive doesn't have carry data for it,
-		 * consider it to be non-authoritive for meta data.
+		 * consider it to be non-authoritative for meta data.
 		 * This is consistent with GNU tar and BSD pax.
 		 * If the hardlink does carry data, let the last
 		 * archive entry decide ownership.
@@ -1562,7 +1511,7 @@ create_filesystem_object(struct archive_write_disk *a)
 	 * that SUID, SGID, etc, require additional work to ensure
 	 * security, so we never restore them at this point.
 	 */
-	mode = final_mode & 0777 & a->user_umask;
+	mode = final_mode & 0777 & ~a->user_umask;
 
 	switch (a->mode & AE_IFMT) {
 	default:
@@ -1881,7 +1830,7 @@ check_symlinks(struct archive_write_disk *a)
 				 */
 				if (disk_unlink(a->name)) {
 					archive_set_error(&a->archive, errno,
-					    "Could not remove symlink %s",
+					    "Could not remove symlink %ls",
 					    a->name);
 					pn[0] = c;
 					return (ARCHIVE_FAILED);
@@ -1895,7 +1844,7 @@ check_symlinks(struct archive_write_disk *a)
 				 */
 				if (!S_ISLNK(a->mode)) {
 					archive_set_error(&a->archive, 0,
-					    "Removing symlink %s",
+					    "Removing symlink %ls",
 					    a->name);
 				}
 				/* Symlink gone.  No more problem! */
@@ -1905,15 +1854,15 @@ check_symlinks(struct archive_write_disk *a)
 				/* User asked us to remove problems. */
 				if (disk_unlink(a->name) != 0) {
 					archive_set_error(&a->archive, 0,
-					    "Cannot remove intervening symlink %s",
-					    a->name);
+					    "Cannot remove intervening "
+					    "symlink %ls", a->name);
 					pn[0] = c;
 					return (ARCHIVE_FAILED);
 				}
 				a->pst = NULL;
 			} else {
 				archive_set_error(&a->archive, 0,
-				    "Cannot extract through symlink %s",
+				    "Cannot extract through symlink %ls",
 				    a->name);
 				pn[0] = c;
 				return (ARCHIVE_FAILED);
@@ -2184,19 +2133,20 @@ create_dir(struct archive_write_disk *a, wchar_t *path)
 			return (ARCHIVE_OK);
 		if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
 			archive_set_error(&a->archive, EEXIST,
-			    "Can't create directory '%s'", path);
+			    "Can't create directory '%ls'", path);
 			return (ARCHIVE_FAILED);
 		}
 		if (disk_unlink(path) != 0) {
 			archive_set_error(&a->archive, errno,
-			    "Can't create directory '%s': "
+			    "Can't create directory '%ls': "
 			    "Conflicting file cannot be removed",
 			    path);
 			return (ARCHIVE_FAILED);
 		}
 	} else if (errno != ENOENT && errno != ENOTDIR) {
 		/* Stat failed? */
-		archive_set_error(&a->archive, errno, "Can't test directory '%s'", path);
+		archive_set_error(&a->archive, errno,
+		    "Can't test directory '%ls'", path);
 		return (ARCHIVE_FAILED);
 	} else if (slash != NULL) {
 		*slash = '\0';
@@ -2245,10 +2195,11 @@ create_dir(struct archive_write_disk *a, wchar_t *path)
 	 * don't add it to the fixup list here, as it's already been
 	 * added.
 	 */
-	if (file_information(a, path, &st, &st_mode, 0) == 0 && S_ISDIR(st_mode))
+	if (file_information(a, path, &st, &st_mode, 0) == 0 &&
+	    S_ISDIR(st_mode))
 		return (ARCHIVE_OK);
 
-	archive_set_error(&a->archive, errno, "Failed to create dir '%s'",
+	archive_set_error(&a->archive, errno, "Failed to create dir '%ls'",
 	    path);
 	return (ARCHIVE_FAILED);
 }
@@ -2277,7 +2228,7 @@ set_ownership(struct archive_write_disk *a)
 	}
 
 	archive_set_error(&a->archive, errno,
-	    "Can't set user=%jd/group=%jd for %s",
+	    "Can't set user=%jd/group=%jd for %ls",
 	    (intmax_t)a->uid, (intmax_t)a->gid, a->name);
 	return (ARCHIVE_WARN);
 }
@@ -2288,7 +2239,7 @@ set_times(struct archive_write_disk *a,
     time_t atime, long atime_nanos,
     time_t birthtime, long birthtime_nanos,
     time_t mtime, long mtime_nanos,
-    time_t ctime, long ctime_nanos)
+    time_t ctime_sec, long ctime_nanos)
 {
 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 #define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\
@@ -2299,7 +2250,7 @@ set_times(struct archive_write_disk *a,
 	FILETIME *pfbtime;
 	FILETIME fatime, fbtime, fmtime;
 
-	(void)ctime; /* UNUSED */
+	(void)ctime_sec; /* UNUSED */
 	(void)ctime_nanos; /* UNUSED */
 
 	if (h != INVALID_HANDLE_VALUE) {
@@ -2350,11 +2301,11 @@ settimes_failed:
 static int
 set_times_from_entry(struct archive_write_disk *a)
 {
-	time_t atime, birthtime, mtime, ctime;
+	time_t atime, birthtime, mtime, ctime_sec;
 	long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec;
 
 	/* Suitable defaults. */
-	atime = birthtime = mtime = ctime = a->start_time;
+	atime = birthtime = mtime = ctime_sec = a->start_time;
 	atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0;
 
 	/* If no time was provided, we're done. */
@@ -2376,7 +2327,7 @@ set_times_from_entry(struct archive_write_disk *a)
 		mtime_nsec = archive_entry_mtime_nsec(a->entry);
 	}
 	if (archive_entry_ctime_is_set(a->entry)) {
-		ctime = archive_entry_ctime(a->entry);
+		ctime_sec = archive_entry_ctime(a->entry);
 		ctime_nsec = archive_entry_ctime_nsec(a->entry);
 	}
 
@@ -2384,7 +2335,7 @@ set_times_from_entry(struct archive_write_disk *a)
 			 atime, atime_nsec,
 			 birthtime, birthtime_nsec,
 			 mtime, mtime_nsec,
-			 ctime, ctime_nsec);
+			 ctime_sec, ctime_nsec);
 }
 
 static int
@@ -2507,7 +2458,7 @@ set_xattrs(struct archive_write_disk *a)
 }
 
 static void
-fileTimeToUtc(const FILETIME *filetime, time_t *time, long *ns)
+fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns)
 {
 	ULARGE_INTEGER utc;
 
@@ -2516,11 +2467,11 @@ fileTimeToUtc(const FILETIME *filetime, time_t *time, long *ns)
 	if (utc.QuadPart >= EPOC_TIME) {
 		utc.QuadPart -= EPOC_TIME;
 		/* milli seconds base */
-		*time = (time_t)(utc.QuadPart / 10000000);
+		*t = (time_t)(utc.QuadPart / 10000000);
 		/* nano seconds base */
 		*ns = (long)(utc.QuadPart % 10000000) * 100;
 	} else {
-		*time = 0;
+		*t = 0;
 		*ns = 0;
 	}
 }
diff --git a/libarchive/archive_write_filter.3 b/libarchive/archive_write_filter.3
index 00438d4..3ca248b 100644
--- a/libarchive/archive_write_filter.3
+++ b/libarchive/archive_write_filter.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 23, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_WRITE_FILTER 3
 .Os
 .Sh NAME
@@ -36,6 +36,8 @@
 .Nm archive_write_add_filter_none ,
 .Nm archive_write_add_filter_program ,
 .Nm archive_write_add_filter_xz
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_write_finish_entry.3 b/libarchive/archive_write_finish_entry.3
index 3add601..d881c80 100644
--- a/libarchive/archive_write_finish_entry.3
+++ b/libarchive/archive_write_finish_entry.3
@@ -22,14 +22,16 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $
+.\" $FreeBSD$
 .\"
-.Dd March 23, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_WRITE_FINISH_ENTRY 3
 .Os
 .Sh NAME
 .Nm archive_write_finish_entry
 .Nd functions for creating archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_write_format.3 b/libarchive/archive_write_format.3
index e12e7d8..dad2f7d 100644
--- a/libarchive/archive_write_format.3
+++ b/libarchive/archive_write_format.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 23, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_WRITE_FORMAT 3
 .Os
 .Sh NAME
@@ -35,6 +35,8 @@
 .Nm archive_write_set_format_shar_dump ,
 .Nm archive_write_set_format_ustar
 .Nd functions for creating archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_write_free.3 b/libarchive/archive_write_free.3
index 27efe18..1b2d071 100644
--- a/libarchive/archive_write_free.3
+++ b/libarchive/archive_write_free.3
@@ -24,17 +24,22 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 23, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_WRITE_FREE 3
 .Os
 .Sh NAME
+.Nm archive_write_fail ,
 .Nm archive_write_close ,
 .Nm archive_write_finish ,
 .Nm archive_write_free
 .Nd functions for creating archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
+.Fn archive_write_fail "struct archive *"
+.Ft int
 .Fn archive_write_close "struct archive *"
 .Ft int
 .Fn archive_write_finish "struct archive *"
@@ -42,6 +47,16 @@
 .Fn archive_write_free "struct archive *"
 .Sh DESCRIPTION
 .Bl -tag -width indent
+.It Fn archive_write_fail
+Always returns
+.Cm ARCHIVE_FATAL .
+This marks the archive object as being unusable;
+after calling this function, the only call that can succeed is
+.Fn archive_write_free
+to release the resources.
+This can be used to speed recovery when the archive creation
+must be aborted.
+Note that the created archive is likely to be malformed in this case; 
 .It Fn archive_write_close
 Complete the archive and invoke the close callback.
 .It Fn archive_write_finish
diff --git a/libarchive/archive_write_header.3 b/libarchive/archive_write_header.3
index 423b38e..4de58f3 100644
--- a/libarchive/archive_write_header.3
+++ b/libarchive/archive_write_header.3
@@ -24,12 +24,14 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 23, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_WRITE_HEADER 3
 .Os
 .Sh NAME
 .Nm archive_write_header
 .Nd functions for creating archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_write_new.3 b/libarchive/archive_write_new.3
index d626ccb..f05d269 100644
--- a/libarchive/archive_write_new.3
+++ b/libarchive/archive_write_new.3
@@ -24,12 +24,14 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 23, 2011
+.Dd February 2, 2012
 .Dt ARCHIVE_WRITE_NEW 3
 .Os
 .Sh NAME
 .Nm archive_write_new
 .Nd functions for creating archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft struct archive *
diff --git a/libarchive/archive_write_open.3 b/libarchive/archive_write_open.3
index 0d12cb3..4037248 100644
--- a/libarchive/archive_write_open.3
+++ b/libarchive/archive_write_open.3
@@ -22,10 +22,10 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $
+.\" $FreeBSD$
 .\"
-.Dd March 23, 2011
-.Dt ARCHIVE_WRITE 3
+.Dd February 2, 2012
+.Dt ARCHIVE_WRITE_OPEN 3
 .Os
 .Sh NAME
 .Nm archive_write_open ,
@@ -34,6 +34,8 @@
 .Nm archive_write_open_filename ,
 .Nm archive_write_open_memory
 .Nd functions for creating archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .In archive.h
 .Ft int
diff --git a/libarchive/archive_write_open_filename.c b/libarchive/archive_write_open_filename.c
index 8689866..196b770 100644
--- a/libarchive/archive_write_open_filename.c
+++ b/libarchive/archive_write_open_filename.c
@@ -46,24 +46,25 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_open_filename.c 191165 200
 #endif
 
 #include "archive.h"
+#include "archive_private.h"
 #include "archive_string.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC	0
+#endif
 
 struct write_file_data {
 	int		fd;
-	char		mbs_filename;
-	union {
-		char		m[1];
-		wchar_t		w[1];
-	} filename; /* Must be last! */
+	struct archive_mstring filename;
 };
 
 static int	file_close(struct archive *, void *);
 static int	file_open(struct archive *, void *);
 static ssize_t	file_write(struct archive *, void *, const void *buff, size_t);
+static int	open_filename(struct archive *, int, const void *);
 
 int
 archive_write_open_file(struct archive *a, const char *filename)
@@ -74,123 +75,122 @@ archive_write_open_file(struct archive *a, const char *filename)
 int
 archive_write_open_filename(struct archive *a, const char *filename)
 {
-	struct write_file_data *mine;
 
 	if (filename == NULL || filename[0] == '\0')
 		return (archive_write_open_fd(a, 1));
 
-	mine = (struct write_file_data *)malloc(sizeof(*mine) + strlen(filename));
-	if (mine == NULL) {
-		archive_set_error(a, ENOMEM, "No memory");
-		return (ARCHIVE_FATAL);
-	}
-	strcpy(mine->filename.m, filename);
-	mine->mbs_filename = 1;
-	mine->fd = -1;
-	return (archive_write_open(a, mine,
-		file_open, file_write, file_close));
+	return (open_filename(a, 1, filename));
 }
 
 int
 archive_write_open_filename_w(struct archive *a, const wchar_t *filename)
 {
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	struct write_file_data *mine;
 
 	if (filename == NULL || filename[0] == L'\0')
 		return (archive_write_open_fd(a, 1));
 
-	mine = malloc(sizeof(*mine) + wcslen(filename) * sizeof(wchar_t));
+	return (open_filename(a, 0, filename));
+}
+
+static int
+open_filename(struct archive *a, int mbs_fn, const void *filename)
+{
+	struct write_file_data *mine;
+	int r;
+
+	mine = (struct write_file_data *)calloc(1, sizeof(*mine));
 	if (mine == NULL) {
 		archive_set_error(a, ENOMEM, "No memory");
 		return (ARCHIVE_FATAL);
 	}
-	wcscpy(mine->filename.w, filename);
-	mine->mbs_filename = 0;
+	if (mbs_fn)
+		r = archive_mstring_copy_mbs(&mine->filename, filename);
+	else
+		r = archive_mstring_copy_wcs(&mine->filename, filename);
+	if (r < 0) {
+		if (errno == ENOMEM) {
+			archive_set_error(a, ENOMEM, "No memory");
+			return (ARCHIVE_FATAL);
+		}
+		if (mbs_fn)
+			archive_set_error(a, ARCHIVE_ERRNO_MISC,
+			    "Can't convert '%s' to WCS",
+			    (const char *)filename);
+		else
+			archive_set_error(a, ARCHIVE_ERRNO_MISC,
+			    "Can't convert '%S' to MBS",
+			    (const wchar_t *)filename);
+		return (ARCHIVE_FAILED);
+	}
 	mine->fd = -1;
 	return (archive_write_open(a, mine,
 		file_open, file_write, file_close));
-#else
-	/*
-	 * POSIX system does not support a wchar_t interface for
-	 * open() system call, so we have to translate a wchar_t
-	 * filename to multi-byte one and use it.
-	 */
-	struct archive_string fn;
-	int r;
-
-	if (filename == NULL || filename[0] == L'\0')
-		return (archive_write_open_fd(a, 1));
-
-	archive_string_init(&fn);
-	if (archive_string_append_from_wcs(&fn, filename,
-	    wcslen(filename)) != 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 = archive_write_open_filename(a, fn.s);
-	archive_string_free(&fn);
-	return (r);
-#endif
 }
 
-
 static int
 file_open(struct archive *a, void *client_data)
 {
 	int flags;
 	struct write_file_data *mine;
 	struct stat st;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	wchar_t *fullpath;
+#endif
+	const wchar_t *wcs;
+	const char *mbs;
 
 	mine = (struct write_file_data *)client_data;
-	flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
+	flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC;
 
 	/*
 	 * Open the file.
 	 */
-	if (mine->mbs_filename) {
-		mine->fd = open(mine->filename.m, flags, 0666);
-		if (mine->fd < 0) {
-			archive_set_error(a, errno, "Failed to open '%s'",
-			    mine->filename.m);
-			return (ARCHIVE_FATAL);
-		}
-
-		if (fstat(mine->fd, &st) != 0) {
-			archive_set_error(a, errno, "Couldn't stat '%s'",
-			    mine->filename.m);
-			return (ARCHIVE_FATAL);
-		}
-	} else {
+	mbs = NULL; wcs = NULL;
 #if defined(_WIN32) && !defined(__CYGWIN__)
-		mine->fd = _wopen(mine->filename.w, flags, 0666);
-		if (mine->fd < 0 && errno == ENOENT) {
-			wchar_t *fullpath;
-			fullpath = __la_win_permissive_name_w(mine->filename.w);
-			if (fullpath != NULL) {
-				mine->fd = _wopen(fullpath, flags, 0666);
-				free(fullpath);
-			}
-		}
-		if (mine->fd < 0) {
-			archive_set_error(a, errno, "Failed to open '%S'",
-			    mine->filename.w);
-			return (ARCHIVE_FATAL);
-		}
-
-		if (fstat(mine->fd, &st) != 0) {
-			archive_set_error(a, errno, "Couldn't stat '%S'",
-			    mine->filename.w);
-			return (ARCHIVE_FATAL);
+	if (archive_mstring_get_wcs(a, &mine->filename, &wcs) != 0) {
+		if (errno == ENOMEM)
+			archive_set_error(a, errno, "No memory");
+		else {
+			archive_mstring_get_mbs(a, &mine->filename, &mbs);
+			archive_set_error(a, errno,
+			    "Can't convert '%s' to WCS", mbs);
 		}
+		return (ARCHIVE_FATAL);
+	}
+	fullpath = __la_win_permissive_name_w(wcs);
+	if (fullpath != NULL) {
+		mine->fd = _wopen(fullpath, flags, 0666);
+		free(fullpath);
+	} else
+		mine->fd = _wopen(wcs, flags, 0666);
 #else
-		archive_set_error(a, ARCHIVE_ERRNO_MISC,
-		    "Unexpedted operation in archive_write_open_filename");
+	if (archive_mstring_get_mbs(a, &mine->filename, &mbs) != 0) {
+		if (errno == ENOMEM)
+			archive_set_error(a, errno, "No memory");
+		else {
+			archive_mstring_get_wcs(a, &mine->filename, &wcs);
+			archive_set_error(a, errno,
+			    "Can't convert '%S' to MBS", wcs);
+		}
 		return (ARCHIVE_FATAL);
+	}
+	mine->fd = open(mbs, flags, 0666);
+	__archive_ensure_cloexec_flag(mine->fd);
 #endif
+	if (mine->fd < 0) {
+		if (mbs != NULL)
+			archive_set_error(a, errno, "Failed to open '%s'", mbs);
+		else
+			archive_set_error(a, errno, "Failed to open '%S'", wcs);
+		return (ARCHIVE_FATAL);
+	}
+
+	if (fstat(mine->fd, &st) != 0) {
+		if (mbs != NULL)
+			archive_set_error(a, errno, "Couldn't stat '%s'", mbs);
+		else
+			archive_set_error(a, errno, "Couldn't stat '%S'", wcs);
+		return (ARCHIVE_FATAL);
 	}
 
 	/*
@@ -218,7 +218,8 @@ file_open(struct archive *a, void *client_data)
 }
 
 static ssize_t
-file_write(struct archive *a, void *client_data, const void *buff, size_t length)
+file_write(struct archive *a, void *client_data, const void *buff,
+    size_t length)
 {
 	struct write_file_data	*mine;
 	ssize_t	bytesWritten;
@@ -243,6 +244,7 @@ file_close(struct archive *a, void *client_data)
 
 	(void)a; /* UNUSED */
 	close(mine->fd);
+	archive_mstring_clean(&mine->filename);
 	free(mine);
 	return (ARCHIVE_OK);
 }
diff --git a/libarchive/archive_write_private.h b/libarchive/archive_write_private.h
index 91284cf..e600d54 100644
--- a/libarchive/archive_write_private.h
+++ b/libarchive/archive_write_private.h
@@ -72,7 +72,7 @@ struct archive_write {
 
 	/* Dev/ino of the archive being written. */
 	int		  skip_file_set;
-	dev_t		  skip_file_dev;
+	int64_t		  skip_file_dev;
 	int64_t		  skip_file_ino;
 
 	/* Utility:  Pointer to a block of nulls. */
@@ -133,4 +133,13 @@ __archive_write_format_header_ustar(struct archive_write *, char buff[512],
     struct archive_entry *, int tartype, int strict,
     struct archive_string_conv *);
 
+struct archive_write_program_data;
+struct archive_write_program_data * __archive_write_program_allocate(void);
+int	__archive_write_program_free(struct archive_write_program_data *);
+int	__archive_write_program_open(struct archive_write_filter *,
+	    struct archive_write_program_data *, const char *);
+int	__archive_write_program_close(struct archive_write_filter *,
+	    struct archive_write_program_data *);
+int	__archive_write_program_write(struct archive_write_filter *,
+	    struct archive_write_program_data *, const void *, size_t);
 #endif
diff --git a/libarchive/archive_write_set_format_7zip.c b/libarchive/archive_write_set_format_7zip.c
index 022b3a4..7847cb3 100644
--- a/libarchive/archive_write_set_format_7zip.c
+++ b/libarchive/archive_write_set_format_7zip.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -199,7 +199,7 @@ struct _7zip {
 	/*
 	 * Compressed data buffer.
 	 */
-	unsigned char		 wbuff[1024 * 64];
+	unsigned char		 wbuff[512 * 20 * 6];
 	size_t			 wbuff_remaining;
 
 	/*
@@ -385,7 +385,7 @@ _7z_options(struct archive_write *a, const char *key, const char *value)
 		else {
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
-			    "Unkonwn compression name: `%s'",
+			    "Unknown compression name: `%s'",
 			    value);
 			return (ARCHIVE_FAILED);
 		}
@@ -405,7 +405,7 @@ _7z_options(struct archive_write *a, const char *key, const char *value)
 		    value[1] != '\0') {
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
-			    "Illeagal value `%s'",
+			    "Illegal value `%s'",
 			    value);
 			return (ARCHIVE_FAILED);
 		}
@@ -413,7 +413,10 @@ _7z_options(struct archive_write *a, const char *key, const char *value)
 		return (ARCHIVE_OK);
 	}
 
-	return (ARCHIVE_FAILED);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 static int
@@ -439,6 +442,14 @@ _7z_write_header(struct archive_write *a, struct archive_entry *entry)
 		file_free(file);
 		return (r);
 	}
+	if (file->size == 0 && file->dir) {
+		if (!__archive_rb_tree_insert_node(&(zip->rbtree),
+		    (struct archive_rb_node *)file)) {
+			/* We have already had the same file. */
+			file_free(file);
+			return (ARCHIVE_OK);
+		}
+	}
 
 	if (file->flg & MTIME_IS_SET)
 		zip->total_number_time_defined[MTIME]++;
@@ -447,11 +458,6 @@ _7z_write_header(struct archive_write *a, struct archive_entry *entry)
 	if (file->flg & ATIME_IS_SET)
 		zip->total_number_time_defined[ATIME]++;
 
-	if (file->size == 0 && file->dir) {
-		if (!__archive_rb_tree_insert_node(&(zip->rbtree),
-		    (struct archive_rb_node *)file))
-			file_free(file);
-	}
 	zip->total_number_entry++;
 	zip->total_bytes_entry_name += file->name_len + 2;
 	if (file->size == 0) {
@@ -495,10 +501,10 @@ _7z_write_header(struct archive_write *a, struct archive_entry *entry)
 	if (archive_entry_filetype(entry) == AE_IFLNK) {
 		ssize_t bytes;
 		const void *p = (const void *)archive_entry_symlink(entry);
-		bytes = compress_out(a, p, file->size, ARCHIVE_Z_RUN);
+		bytes = compress_out(a, p, (size_t)file->size, ARCHIVE_Z_RUN);
 		if (bytes < 0)
 			return ((int)bytes);
-		zip->entry_crc32 = crc32(zip->entry_crc32, p, bytes);
+		zip->entry_crc32 = crc32(zip->entry_crc32, p, (unsigned)bytes);
 		zip->entry_bytes_remaining -= bytes;
 	}
 
@@ -512,7 +518,7 @@ static int
 write_to_temp(struct archive_write *a, const void *buff, size_t s)
 {
 	struct _7zip *zip;
-	unsigned char *p;
+	const unsigned char *p;
 	ssize_t ws;
 
 	zip = (struct _7zip *)a->format_data;
@@ -530,7 +536,7 @@ write_to_temp(struct archive_write *a, const void *buff, size_t s)
 		}
 	}
 
-	p = (unsigned char *)buff;
+	p = (const unsigned char *)buff;
 	while (s) {
 		ws = write(zip->temp_fd, p, s);
 		if (ws < 0) {
@@ -556,10 +562,11 @@ compress_out(struct archive_write *a, const void *buff, size_t s,
 		return (0);
 
 	if ((zip->crc32flg & PRECODE_CRC32) && s)
-		zip->precode_crc32 = crc32(zip->precode_crc32, buff, s);
+		zip->precode_crc32 = crc32(zip->precode_crc32, buff,
+		    (unsigned)s);
 	zip->stream.next_in = (const unsigned char *)buff;
 	zip->stream.avail_in = s;
-	do {
+	for (;;) {
 		/* Compress file data. */
 		r = compression_code(&(a->archive), &(zip->stream), run);
 		if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
@@ -573,15 +580,19 @@ compress_out(struct archive_write *a, const void *buff, size_t s,
 			if (zip->crc32flg & ENCODED_CRC32)
 				zip->encoded_crc32 = crc32(zip->encoded_crc32,
 				    zip->wbuff, sizeof(zip->wbuff));
+			if (run == ARCHIVE_Z_FINISH && r != ARCHIVE_EOF)
+				continue;
 		}
-	} while (zip->stream.avail_in);
+		if (zip->stream.avail_in == 0)
+			break;
+	}
 	if (run == ARCHIVE_Z_FINISH) {
 		uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out;
-		if (write_to_temp(a, zip->wbuff, bytes) != ARCHIVE_OK)
+		if (write_to_temp(a, zip->wbuff, (size_t)bytes) != ARCHIVE_OK)
 			return (ARCHIVE_FATAL);
 		if ((zip->crc32flg & ENCODED_CRC32) && bytes)
 			zip->encoded_crc32 = crc32(zip->encoded_crc32,
-			    zip->wbuff, bytes);
+			    zip->wbuff, (unsigned)bytes);
 	}
 
 	return (s);
@@ -596,13 +607,13 @@ _7z_write_data(struct archive_write *a, const void *buff, size_t s)
 	zip = (struct _7zip *)a->format_data;
 
 	if (s > zip->entry_bytes_remaining)
-		s = zip->entry_bytes_remaining;
+		s = (size_t)zip->entry_bytes_remaining;
 	if (s == 0 || zip->cur_file == NULL)
 		return (0);
 	bytes = compress_out(a, buff, s, ARCHIVE_Z_RUN);
 	if (bytes < 0)
 		return (bytes);
-	zip->entry_crc32 = crc32(zip->entry_crc32, buff, bytes);
+	zip->entry_crc32 = crc32(zip->entry_crc32, buff, (unsigned)bytes);
 	zip->entry_bytes_remaining -= bytes;
 	return (bytes);
 }
@@ -619,12 +630,12 @@ _7z_finish_entry(struct archive_write *a)
 		return (ARCHIVE_OK);
 
 	while (zip->entry_bytes_remaining > 0) {
-		s = zip->entry_bytes_remaining;
+		s = (size_t)zip->entry_bytes_remaining;
 		if (s > a->null_length)
 			s = a->null_length;
 		r = _7z_write_data(a, a->nulls, s);
 		if (r < 0)
-			return (r);
+			return ((int)r);
 	}
 	zip->total_bytes_compressed += zip->stream.total_in;
 	zip->total_bytes_uncompressed += zip->stream.total_out;
@@ -727,8 +738,10 @@ _7z_close(struct archive_write *a)
 		    zip->total_number_entry - zip->total_number_empty_entry;
 
 		/* Connect an empty file list. */
-		*zip->file_list.last = zip->empty_list.first;
-		zip->file_list.last = zip->empty_list.last;
+		if (zip->empty_list.first != NULL) {
+			*zip->file_list.last = zip->empty_list.first;
+			zip->file_list.last = zip->empty_list.last;
+		}
 		/* Connect a directory file list. */
 		ARCHIVE_RB_TREE_FOREACH(n, &(zip->rbtree)) {
 			file_register(zip, (struct file *)n);
@@ -844,7 +857,7 @@ enc_uint64(struct archive_write *a, uint64_t val)
 	int i;
 
 	numdata[0] = 0;
-	for (i = 1; i < sizeof(numdata); i++) {
+	for (i = 1; i < (int)sizeof(numdata); i++) {
 		if (val < mask) {
 			numdata[0] |= (uint8_t)val;
 			break;
@@ -854,7 +867,7 @@ enc_uint64(struct archive_write *a, uint64_t val)
 		numdata[0] |= mask;
 		mask >>= 1;
 	}
-	return (compress_out(a, numdata, i, ARCHIVE_Z_RUN));
+	return ((int)compress_out(a, numdata, i, ARCHIVE_Z_RUN));
 }
 
 static int
@@ -919,7 +932,7 @@ make_substreamsInfo(struct archive_write *a, struct coder *coders)
 		if (file->size == 0)
 			break;
 		archive_le32enc(crc, file->crc32);
-		r = compress_out(a, crc, 4, ARCHIVE_Z_RUN);
+		r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
 		if (r < 0)
 			return (r);
 	}
@@ -943,7 +956,7 @@ make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 	int i, r;
 
 	if (coders->codec == _7Z_COPY)
-		numFolders = zip->total_number_nonempty_entry;
+		numFolders = (int)zip->total_number_nonempty_entry;
 	else
 		numFolders = 1;
 
@@ -1039,7 +1052,7 @@ make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 
 			/* Write Codec ID. */
 			codec_size &= 0x0f;
-			r = compress_out(a, &codec_buff[8-codec_size],
+			r = (int)compress_out(a, &codec_buff[8-codec_size],
 				codec_size, ARCHIVE_Z_RUN);
 			if (r < 0)
 				return (r);
@@ -1051,7 +1064,7 @@ make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 					return (r);
 
 				/* Write Codec properties. */
-				r = compress_out(a, coders[i].props,
+				r = (int)compress_out(a, coders[i].props,
 					coders[i].prop_size, ARCHIVE_Z_RUN);
 				if (r < 0)
 					return (r);
@@ -1097,7 +1110,7 @@ make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 		if (r < 0)
 			return (r);
 		archive_le32enc(crc, header_crc);
-		r = compress_out(a, crc, 4, ARCHIVE_Z_RUN);
+		r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
 		if (r < 0)
 			return (r);
 	}
@@ -1128,11 +1141,11 @@ make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 
 #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
 static uint64_t
-utcToFiletime(time_t time, long ns)
+utcToFiletime(time_t t, long ns)
 {
 	uint64_t fileTime;
 
-	fileTime = time;
+	fileTime = t;
 	fileTime *= 10000000;
 	fileTime += ns / 100;
 	fileTime += EPOC_TIME;
@@ -1146,7 +1159,7 @@ make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
 	struct _7zip *zip = (struct _7zip *)a->format_data;
 	struct file *file;
 	int r;
-	uint8_t mask, byte;
+	uint8_t b, mask;
 
 	/*
 	 * Make Time Bools.
@@ -1183,23 +1196,23 @@ make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
 		if (r < 0)
 			return (r);
 
-		byte = 0;
+		b = 0;
 		mask = 0x80;
 		file = zip->file_list.first;
 		for (;file != NULL; file = file->next) {
 			if (file->flg & flg)
-				byte |= mask;
+				b |= mask;
 			mask >>= 1;
 			if (mask == 0) {
-				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
+				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 				if (r < 0)
 					return (r);
 				mask = 0x80;
-				byte = 0;
+				b = 0;
 			}
 		}
 		if (mask != 0x80) {
-			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
+			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 			if (r < 0)
 				return (r);
 		}
@@ -1220,7 +1233,7 @@ make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
 			continue;
 		archive_le64enc(filetime, utcToFiletime(file->times[ti].time,
 			file->times[ti].time_ns));
-		r = compress_out(a, filetime, 8, ARCHIVE_Z_RUN);
+		r = (int)compress_out(a, filetime, 8, ARCHIVE_Z_RUN);
 		if (r < 0)
 			return (r);
 	}
@@ -1235,7 +1248,7 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 	struct _7zip *zip = (struct _7zip *)a->format_data;
 	struct file *file;
 	int r;
-	uint8_t mask, byte;
+	uint8_t b, mask;
 
 	/*
 	 * Make FilesInfo.
@@ -1283,23 +1296,23 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 		if (r < 0)
 			return (r);
 
-		byte = 0;
+		b = 0;
 		mask = 0x80;
 		file = zip->file_list.first;
 		for (;file != NULL; file = file->next) {
 			if (file->size == 0)
-				byte |= mask;
+				b |= mask;
 			mask >>= 1;
 			if (mask == 0) {
-				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
+				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 				if (r < 0)
 					return (r);
 				mask = 0x80;
-				byte = 0;
+				b = 0;
 			}
 		}
 		if (mask != 0x80) {
-			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
+			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 			if (r < 0)
 				return (r);
 		}
@@ -1316,25 +1329,25 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 		if (r < 0)
 			return (r);
 
-		byte = 0;
+		b = 0;
 		mask = 0x80;
 		file = zip->file_list.first;
 		for (;file != NULL; file = file->next) {
 			if (file->size)
 				continue;
 			if (!file->dir)
-				byte |= mask;
+				b |= mask;
 			mask >>= 1;
 			if (mask == 0) {
-				r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
+				r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 				if (r < 0)
 					return (r);
 				mask = 0x80;
-				byte = 0;
+				b = 0;
 			}
 		}
 		if (mask != 0x80) {
-			r = compress_out(a, &byte, 1, ARCHIVE_Z_RUN);
+			r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
 			if (r < 0)
 				return (r);
 		}
@@ -1357,7 +1370,7 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 
 	file = zip->file_list.first;
 	for (;file != NULL; file = file->next) {
-		r = compress_out(a, file->utf16name, file->name_len+2,
+		r = (int)compress_out(a, file->utf16name, file->name_len+2,
 			ARCHIVE_Z_RUN);
 		if (r < 0)
 			return (r);
@@ -1413,7 +1426,7 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
 			attr |= 1;/* Read Only. */
 		attr |= ((uint32_t)file->mode) << 16;
 		archive_le32enc(&encattr, attr);
-		r = compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
+		r = (int)compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
 		if (r < 0)
 			return (r);
 	}
@@ -1449,8 +1462,8 @@ static int
 file_cmp_node(const struct archive_rb_node *n1,
     const struct archive_rb_node *n2)
 {
-	struct file *f1 = (struct file *)n1;
-	struct file *f2 = (struct file *)n2;
+	const struct file *f1 = (const struct file *)n1;
+	const struct file *f2 = (const struct file *)n2;
 
 	if (f1->name_len == f2->name_len)
 		return (memcmp(f1->utf16name, f2->utf16name, f1->name_len));
@@ -1460,7 +1473,7 @@ file_cmp_node(const struct archive_rb_node *n1,
 static int
 file_cmp_key(const struct archive_rb_node *n, const void *key)
 {
-	struct file *f = (struct file *)n;
+	const struct file *f = (const struct file *)n;
 
 	return (f->name_len - *(const char *)key);
 }
@@ -1487,6 +1500,7 @@ file_new(struct archive_write *a, struct archive_entry *entry,
 
 	if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) {
 		if (errno == ENOMEM) {
+			free(file);
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory for UTF-16LE");
 			return (ARCHIVE_FATAL);
@@ -1498,6 +1512,7 @@ file_new(struct archive_write *a, struct archive_entry *entry,
 	}
 	file->utf16name = malloc(u16len + 2);
 	if (file->utf16name == NULL) {
+		free(file);
 		archive_set_error(&a->archive, ENOMEM,
 		    "Can't allocate memory for Name");
 		return (ARCHIVE_FATAL);
@@ -1505,7 +1520,7 @@ file_new(struct archive_write *a, struct archive_entry *entry,
 	memcpy(file->utf16name, u16, u16len);
 	file->utf16name[u16len+0] = 0;
 	file->utf16name[u16len+1] = 0;
-	file->name_len = u16len;
+	file->name_len = (unsigned)u16len;
 	file->mode = archive_entry_mode(entry);
 	if (archive_entry_filetype(entry) == AE_IFREG)
 		file->size = archive_entry_size(entry);
@@ -1585,7 +1600,8 @@ file_init_register_empty(struct _7zip *zip)
 	zip->empty_list.last = &(zip->empty_list.first);
 }
 
-#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
+#if !defined(HAVE_ZLIB_H) || !defined(HAVE_BZLIB_H) ||\
+	 !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
 static int
 compression_unsupported_encoder(struct archive *a,
     struct la_zstream *lastrm, const char *name)
@@ -1669,11 +1685,11 @@ compression_init_encoder_deflate(struct archive *a,
 	 * of ugly hackery to convert a const * pointer to
 	 * a non-const pointer. */
 	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
-	strm->avail_in = lastrm->avail_in;
-	strm->total_in = lastrm->total_in;
+	strm->avail_in = (uInt)lastrm->avail_in;
+	strm->total_in = (uLong)lastrm->total_in;
 	strm->next_out = lastrm->next_out;
-	strm->avail_out = lastrm->avail_out;
-	strm->total_out = lastrm->total_out;
+	strm->avail_out = (uInt)lastrm->avail_out;
+	strm->total_out = (uLong)lastrm->total_out;
 	if (deflateInit2(strm, level, Z_DEFLATED,
 	    (withheader)?15:-15,
 	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
@@ -1702,11 +1718,11 @@ compression_code_deflate(struct archive *a,
 	 * of ugly hackery to convert a const * pointer to
 	 * a non-const pointer. */
 	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
-	strm->avail_in = lastrm->avail_in;
-	strm->total_in = lastrm->total_in;
+	strm->avail_in = (uInt)lastrm->avail_in;
+	strm->total_in = (uLong)lastrm->total_in;
 	strm->next_out = lastrm->next_out;
-	strm->avail_out = lastrm->avail_out;
-	strm->total_out = lastrm->total_out;
+	strm->avail_out = (uInt)lastrm->avail_out;
+	strm->total_out = (uLong)lastrm->total_out;
 	r = deflate(strm,
 	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
 	lastrm->next_in = strm->next_in;
@@ -1908,6 +1924,7 @@ compression_init_encoder_lzma(struct archive *a,
 	if (level > 6)
 		level = 6;
 	if (lzma_lzma_preset(&lzma_opt, level)) {
+		free(strm);
 		lastrm->real_stream = NULL;
 		archive_set_error(a, ENOMEM,
 		    "Internal error initializing compression library");
@@ -2177,6 +2194,8 @@ compression_code_ppmd(struct archive *a,
 {
 	struct ppmd_stream *strm;
 
+	(void)a; /* UNUSED */
+
 	strm = (struct ppmd_stream *)lastrm->real_stream;
 
 	/* Copy encoded data if there are remaining bytes from previous call. */
@@ -2217,6 +2236,8 @@ compression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
 {
 	struct ppmd_stream *strm;
 
+	(void)a; /* UNUSED */
+
 	strm = (struct ppmd_stream *)lastrm->real_stream;
 	__archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context, &g_szalloc);
 	free(strm->buff);
diff --git a/libarchive/archive_write_set_format_ar.c b/libarchive/archive_write_set_format_ar.c
index 956b932..9f17564 100644
--- a/libarchive/archive_write_set_format_ar.c
+++ b/libarchive/archive_write_set_format_ar.c
@@ -165,7 +165,7 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
 	 * Reject files with empty name.
 	 */
 	pathname = archive_entry_pathname(entry);
-	if (*pathname == '\0') {
+	if (pathname == NULL || *pathname == '\0') {
 		archive_set_error(&a->archive, EINVAL,
 		    "Invalid filename");
 		return (ARCHIVE_WARN);
@@ -366,7 +366,7 @@ archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)
 
 	ar = (struct ar_w *)a->format_data;
 	if (s > ar->entry_bytes_remaining)
-		s = ar->entry_bytes_remaining;
+		s = (size_t)ar->entry_bytes_remaining;
 
 	if (ar->is_strtab > 0) {
 		if (ar->has_strtab > 0) {
diff --git a/libarchive/archive_write_set_format_by_name.c b/libarchive/archive_write_set_format_by_name.c
index 9671f60..af3105e 100644
--- a/libarchive/archive_write_set_format_by_name.c
+++ b/libarchive/archive_write_set_format_by_name.c
@@ -56,8 +56,10 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
 	{ "iso",	archive_write_set_format_iso9660 },
 	{ "iso9660",	archive_write_set_format_iso9660 },
 	{ "mtree",	archive_write_set_format_mtree },
+	{ "mtree-classic",	archive_write_set_format_mtree_classic },
 	{ "newc",	archive_write_set_format_cpio_newc },
 	{ "odc",	archive_write_set_format_cpio },
+	{ "oldtar",	archive_write_set_format_v7tar },
 	{ "pax",	archive_write_set_format_pax },
 	{ "paxr",	archive_write_set_format_pax_restricted },
 	{ "posix",	archive_write_set_format_pax },
@@ -65,6 +67,8 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
 	{ "shar",	archive_write_set_format_shar },
 	{ "shardump",	archive_write_set_format_shar_dump },
 	{ "ustar",	archive_write_set_format_ustar },
+	{ "v7tar",	archive_write_set_format_v7tar },
+	{ "v7",		archive_write_set_format_v7tar },
 	{ "xar",	archive_write_set_format_xar },
 	{ "zip",	archive_write_set_format_zip },
 	{ NULL,		NULL }
diff --git a/libarchive/archive_write_set_format_cpio.c b/libarchive/archive_write_set_format_cpio.c
index 92b9bfb..3526493 100644
--- a/libarchive/archive_write_set_format_cpio.c
+++ b/libarchive/archive_write_set_format_cpio.c
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -147,11 +148,13 @@ archive_write_cpio_options(struct archive_write *a, const char *key,
 			else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "%s: unknown keyword ``%s''", a->format_name, key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 /*
@@ -186,7 +189,7 @@ synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
 
 	/* Don't store a mapping if we don't need to. */
 	if (archive_entry_nlink(entry) < 2) {
-		return ++cpio->ino_next;
+		return (int)(++cpio->ino_next);
 	}
 
 	/* Look up old ino; if we have it, this is a hardlink
@@ -197,7 +200,7 @@ synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
 	}
 
 	/* Assign a new index number. */
-	ino_new = ++cpio->ino_next;
+	ino_new = (int)(++cpio->ino_next);
 
 	/* Ensure space for the new mapping. */
 	if (cpio->ino_list_size <= cpio->ino_list_next) {
@@ -278,18 +281,37 @@ write_header(struct archive_write *a, struct archive_entry *entry)
 	int64_t	ino;
 	char h[76];
 	struct archive_string_conv *sconv;
+	struct archive_entry *entry_main;
 	size_t len;
 
 	cpio = (struct cpio *)a->format_data;
 	ret_final = ARCHIVE_OK;
 	sconv = get_sconv(a);
 
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	/* Make sure the path separators in pahtname, hardlink and symlink
+	 * are all slash '/', not the Windows path separator '\'. */
+	entry_main = __la_win_entry_in_posix_pathseparator(entry);
+	if (entry_main == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate ustar data");
+		return(ARCHIVE_FATAL);
+	}
+	if (entry != entry_main)
+		entry = entry_main;
+	else
+		entry_main = NULL;
+#else
+	entry_main = NULL;
+#endif
+
 	ret = archive_entry_pathname_l(entry, &path, &len, sconv);
 	if (ret != 0) {
 		if (errno == ENOMEM) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory for Pathname");
-			return (ARCHIVE_FATAL);
+			ret_final = ARCHIVE_FATAL;
+			goto exit_write_header;
 		}
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Can't translate pathname '%s' to %s",
@@ -308,11 +330,13 @@ write_header(struct archive_write *a, struct archive_entry *entry)
 	if (ino < 0) {
 		archive_set_error(&a->archive, ENOMEM,
 		    "No memory for ino translation table");
-		return (ARCHIVE_FATAL);
+		ret_final = ARCHIVE_FATAL;
+		goto exit_write_header;
 	} else if (ino > 0777777) {
 		archive_set_error(&a->archive, ERANGE,
 		    "Too many files for this cpio format");
-		return (ARCHIVE_FATAL);
+		ret_final = ARCHIVE_FATAL;
+		goto exit_write_header;
 	}
 	format_octal(ino & 0777777, h + c_ino_offset, c_ino_size);
 
@@ -339,7 +363,8 @@ write_header(struct archive_write *a, struct archive_entry *entry)
 		if (errno == ENOMEM) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory for Linkname");
-			return (ARCHIVE_FATAL);
+			ret_final = ARCHIVE_FATAL;
+			goto exit_write_header;
 		}
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Can't translate linkname '%s' to %s",
@@ -356,25 +381,35 @@ write_header(struct archive_write *a, struct archive_entry *entry)
 	if (ret) {
 		archive_set_error(&a->archive, ERANGE,
 		    "File is too large for cpio format.");
-		return (ARCHIVE_FAILED);
+		ret_final = ARCHIVE_FAILED;
+		goto exit_write_header;
 	}
 
 	ret = __archive_write_output(a, h, sizeof(h));
-	if (ret != ARCHIVE_OK)
-		return (ARCHIVE_FATAL);
+	if (ret != ARCHIVE_OK) {
+		ret_final = ARCHIVE_FATAL;
+		goto exit_write_header;
+	}
 
 	ret = __archive_write_output(a, path, pathlength);
-	if (ret != ARCHIVE_OK)
-		return (ARCHIVE_FATAL);
+	if (ret != ARCHIVE_OK) {
+		ret_final = ARCHIVE_FATAL;
+		goto exit_write_header;
+	}
 
 	cpio->entry_bytes_remaining = archive_entry_size(entry);
 
 	/* Write the symlink now. */
 	if (p != NULL  &&  *p != '\0') {
 		ret = __archive_write_output(a, p, strlen(p));
-		if (ret != ARCHIVE_OK)
-			return (ARCHIVE_FATAL);
+		if (ret != ARCHIVE_OK) {
+			ret_final = ARCHIVE_FATAL;
+			goto exit_write_header;
+		}
 	}
+exit_write_header:
+	if (entry_main)
+		archive_entry_free(entry_main);
 	return (ret_final);
 }
 
@@ -386,7 +421,7 @@ archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s)
 
 	cpio = (struct cpio *)a->format_data;
 	if (s > cpio->entry_bytes_remaining)
-		s = cpio->entry_bytes_remaining;
+		s = (size_t)cpio->entry_bytes_remaining;
 
 	ret = __archive_write_output(a, buff, s);
 	cpio->entry_bytes_remaining -= s;
@@ -422,7 +457,7 @@ format_octal_recursive(int64_t v, char *p, int s)
 	if (s == 0)
 		return (v);
 	v = format_octal_recursive(v, p+1, s-1);
-	*p = '0' + (v & 7);
+	*p = '0' + ((char)v & 7);
 	return (v >> 3);
 }
 
@@ -460,5 +495,6 @@ archive_write_cpio_finish_entry(struct archive_write *a)
 	struct cpio *cpio;
 
 	cpio = (struct cpio *)a->format_data;
-	return (__archive_write_nulls(a, cpio->entry_bytes_remaining));
+	return (__archive_write_nulls(a,
+		(size_t)cpio->entry_bytes_remaining));
 }
diff --git a/libarchive/archive_write_set_format_cpio_newc.c b/libarchive/archive_write_set_format_cpio_newc.c
index d06c391..a9bfa80 100644
--- a/libarchive/archive_write_set_format_cpio_newc.c
+++ b/libarchive/archive_write_set_format_cpio_newc.c
@@ -1,6 +1,7 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
  * Copyright (c) 2006 Rudolf Marek SYSGO s.r.o.
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -154,11 +155,13 @@ archive_write_newc_options(struct archive_write *a, const char *key,
 			else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "%s: unknown keyword ``%s''", a->format_name, key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 static struct archive_string_conv *
@@ -220,6 +223,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
 	int pathlength, ret, ret_final;
 	char h[c_header_size];
 	struct archive_string_conv *sconv;
+	struct archive_entry *entry_main;
 	size_t len;
 	int pad;
 
@@ -227,12 +231,30 @@ write_header(struct archive_write *a, struct archive_entry *entry)
 	ret_final = ARCHIVE_OK;
 	sconv = get_sconv(a);
 
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	/* Make sure the path separators in pahtname, hardlink and symlink
+	 * are all slash '/', not the Windows path separator '\'. */
+	entry_main = __la_win_entry_in_posix_pathseparator(entry);
+	if (entry_main == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate ustar data");
+		return(ARCHIVE_FATAL);
+	}
+	if (entry != entry_main)
+		entry = entry_main;
+	else
+		entry_main = NULL;
+#else
+	entry_main = NULL;
+#endif
+
 	ret = archive_entry_pathname_l(entry, &path, &len, sconv);
 	if (ret != 0) {
 		if (errno == ENOMEM) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory for Pathname");
-			return (ARCHIVE_FATAL);
+			ret_final = ARCHIVE_FATAL;
+			goto exit_write_header;
 		}
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Can't translate pathname '%s' to %s",
@@ -284,7 +306,8 @@ write_header(struct archive_write *a, struct archive_entry *entry)
 		if (errno == ENOMEM) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory for Likname");
-			return (ARCHIVE_FATAL);
+			ret_final = ARCHIVE_FATAL;
+			goto exit_write_header;
 		}
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Can't translate linkname '%s' to %s",
@@ -301,37 +324,51 @@ write_header(struct archive_write *a, struct archive_entry *entry)
 	if (ret) {
 		archive_set_error(&a->archive, ERANGE,
 		    "File is too large for this format.");
-		return (ARCHIVE_FAILED);
+		ret_final = ARCHIVE_FAILED;
+		goto exit_write_header;
 	}
 
 	ret = __archive_write_output(a, h, c_header_size);
-	if (ret != ARCHIVE_OK)
-		return (ARCHIVE_FATAL);
+	if (ret != ARCHIVE_OK) {
+		ret_final = ARCHIVE_FATAL;
+		goto exit_write_header;
+	}
 
 	/* Pad pathname to even length. */
 	ret = __archive_write_output(a, path, pathlength);
-	if (ret != ARCHIVE_OK)
-		return (ARCHIVE_FATAL);
+	if (ret != ARCHIVE_OK) {
+		ret_final = ARCHIVE_FATAL;
+		goto exit_write_header;
+	}
 	pad = PAD4(pathlength + c_header_size);
 	if (pad) {
 		ret = __archive_write_output(a, "\0\0\0", pad);
-		if (ret != ARCHIVE_OK)
-			return (ARCHIVE_FATAL);
+		if (ret != ARCHIVE_OK) {
+			ret_final = ARCHIVE_FATAL;
+			goto exit_write_header;
+		}
 	}
 
 	cpio->entry_bytes_remaining = archive_entry_size(entry);
-	cpio->padding = PAD4(cpio->entry_bytes_remaining);
+	cpio->padding = (int)PAD4(cpio->entry_bytes_remaining);
 
 	/* Write the symlink now. */
 	if (p != NULL  &&  *p != '\0') {
 		ret = __archive_write_output(a, p, strlen(p));
-		if (ret != ARCHIVE_OK)
-			return (ARCHIVE_FATAL);
+		if (ret != ARCHIVE_OK) {
+			ret_final = ARCHIVE_FATAL;
+			goto exit_write_header;
+		}
 		pad = PAD4(strlen(p));
 		ret = __archive_write_output(a, "\0\0\0", pad);
-		if (ret != ARCHIVE_OK)
-			return (ARCHIVE_FATAL);
+		if (ret != ARCHIVE_OK) {
+			ret_final = ARCHIVE_FATAL;
+			goto exit_write_header;
+		}
 	}
+exit_write_header:
+	if (entry_main)
+		archive_entry_free(entry_main);
 	return (ret_final);
 }
 
@@ -343,7 +380,7 @@ archive_write_newc_data(struct archive_write *a, const void *buff, size_t s)
 
 	cpio = (struct cpio *)a->format_data;
 	if (s > cpio->entry_bytes_remaining)
-		s = cpio->entry_bytes_remaining;
+		s = (size_t)cpio->entry_bytes_remaining;
 
 	ret = __archive_write_output(a, buff, s);
 	cpio->entry_bytes_remaining -= s;
@@ -416,5 +453,6 @@ archive_write_newc_finish_entry(struct archive_write *a)
 	struct cpio *cpio;
 
 	cpio = (struct cpio *)a->format_data;
-	return (__archive_write_nulls(a, cpio->entry_bytes_remaining + cpio->padding));
+	return (__archive_write_nulls(a,
+		(size_t)cpio->entry_bytes_remaining + cpio->padding));
 }
diff --git a/libarchive/archive_write_set_format_gnutar.c b/libarchive/archive_write_set_format_gnutar.c
index e091ed2..13942c1 100644
--- a/libarchive/archive_write_set_format_gnutar.c
+++ b/libarchive/archive_write_set_format_gnutar.c
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
  * Author: Jonas Gastal <jgastal at profusion.mobi>
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  *
  * All rights reserved.
  *
@@ -177,7 +177,8 @@ archive_write_set_format_gnutar(struct archive *_a)
 
 	gnutar = (struct gnutar *)calloc(1, sizeof(*gnutar));
 	if (gnutar == NULL) {
-		archive_set_error(&a->archive, ENOMEM, "Can't allocate gnutar data");
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate gnutar data");
 		return (ARCHIVE_FATAL);
 	}
 	a->format_data = gnutar;
@@ -213,11 +214,13 @@ archive_write_gnutar_options(struct archive_write *a, const char *key,
 			else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "%s: unknown keyword ``%s''", a->format_name, key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 static int
@@ -244,8 +247,8 @@ archive_write_gnutar_finish_entry(struct archive_write *a)
 	int ret;
 
 	gnutar = (struct gnutar *)a->format_data;
-	ret = __archive_write_nulls(a,
-	    gnutar->entry_bytes_remaining + gnutar->entry_padding);
+	ret = __archive_write_nulls(a, (size_t)
+	    (gnutar->entry_bytes_remaining + gnutar->entry_padding));
 	gnutar->entry_bytes_remaining = gnutar->entry_padding = 0;
 	return (ret);
 }
@@ -258,7 +261,7 @@ archive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s)
 
 	gnutar = (struct gnutar *)a->format_data;
 	if (s > gnutar->entry_bytes_remaining)
-		s = gnutar->entry_bytes_remaining;
+		s = (size_t)gnutar->entry_bytes_remaining;
 	ret = __archive_write_output(a, buff, s);
 	gnutar->entry_bytes_remaining -= s;
 	if (ret != ARCHIVE_OK)
@@ -275,6 +278,7 @@ archive_write_gnutar_header(struct archive_write *a,
 	int tartype;
 	struct gnutar *gnutar;
 	struct archive_string_conv *sconv;
+	struct archive_entry *entry_main;
 
 	gnutar = (struct gnutar *)a->format_data;
 
@@ -298,33 +302,95 @@ archive_write_gnutar_header(struct archive_write *a,
 
 	if (AE_IFDIR == archive_entry_filetype(entry)) {
 		const char *p;
-		char *t;
+		size_t path_length;
 		/*
 		 * Ensure a trailing '/'.  Modify the entry so
 		 * the client sees the change.
 		 */
-		p = archive_entry_pathname(entry);
-		if (p[strlen(p) - 1] != '/') {
-			t = (char *)malloc(strlen(p) + 2);
-			if (t == NULL) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+		const wchar_t *wp;
+
+		wp = archive_entry_pathname_w(entry);
+		if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
+			struct archive_wstring ws;
+
+			archive_string_init(&ws);
+			path_length = wcslen(wp);
+			if (archive_wstring_ensure(&ws,
+			    path_length + 2) == NULL) {
+				archive_set_error(&a->archive, ENOMEM,
+				    "Can't allocate ustar data");
+				archive_wstring_free(&ws);
+				return(ARCHIVE_FATAL);
+			}
+			/* Should we keep '\' ? */
+			if (wp[path_length -1] == L'\\')
+				path_length--;
+			archive_wstrncpy(&ws, wp, path_length);
+			archive_wstrappend_wchar(&ws, L'/');
+			archive_entry_copy_pathname_w(entry, ws.s);
+			archive_wstring_free(&ws);
+			p = NULL;
+		} else
+#endif
+			p = archive_entry_pathname(entry);
+		/*
+		 * On Windows, this is a backup operation just in
+		 * case getting WCS failed. On POSIX, this is a
+		 * normal operation.
+		 */
+		if (p != NULL && p[strlen(p) - 1] != '/') {
+			struct archive_string as;
+
+			archive_string_init(&as);
+			path_length = strlen(p);
+			if (archive_string_ensure(&as,
+			    path_length + 2) == NULL) {
 				archive_set_error(&a->archive, ENOMEM,
-				"Can't allocate gnutar data");
+				    "Can't allocate ustar data");
+				archive_string_free(&as);
 				return(ARCHIVE_FATAL);
 			}
-			strcpy(t, p);
-			strcat(t, "/");
-			archive_entry_copy_pathname(entry, t);
-			free(t);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+			/* NOTE: This might break the pathname
+			 * if the current code page is CP932 and
+			 * the pathname includes a character '\'
+			 * as a part of its multibyte pathname. */
+			if (p[strlen(p) -1] == '\\')
+				path_length--;
+			else
+#endif
+			archive_strncpy(&as, p, path_length);
+			archive_strappend_char(&as, '/');
+			archive_entry_copy_pathname(entry, as.s);
+			archive_string_free(&as);
 		}
 	}
 
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	/* Make sure the path separators in pahtname, hardlink and symlink
+	 * are all slash '/', not the Windows path separator '\'. */
+	entry_main = __la_win_entry_in_posix_pathseparator(entry);
+	if (entry_main == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate ustar data");
+		return(ARCHIVE_FATAL);
+	}
+	if (entry != entry_main)
+		entry = entry_main;
+	else
+		entry_main = NULL;
+#else
+	entry_main = NULL;
+#endif
 	r = archive_entry_pathname_l(entry, &(gnutar->pathname),
 	    &(gnutar->pathname_length), sconv);
 	if (r != 0) {
 		if (errno == ENOMEM) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory for Pathame");
-			return (ARCHIVE_FATAL);
+			ret = ARCHIVE_FATAL;
+			goto exit_write_header;
 		}
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Can't translate pathname '%s' to %s",
@@ -338,7 +404,8 @@ archive_write_gnutar_header(struct archive_write *a,
 		if (errno == ENOMEM) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory for Uname");
-			return (ARCHIVE_FATAL);
+			ret = ARCHIVE_FATAL;
+			goto exit_write_header;
 		}
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_FILE_FORMAT,
@@ -353,7 +420,8 @@ archive_write_gnutar_header(struct archive_write *a,
 		if (errno == ENOMEM) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory for Gname");
-			return (ARCHIVE_FATAL);
+			ret = ARCHIVE_FATAL;
+			goto exit_write_header;
 		}
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_FILE_FORMAT,
@@ -370,7 +438,8 @@ archive_write_gnutar_header(struct archive_write *a,
 		if (errno == ENOMEM) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory for Linkname");
-			return (ARCHIVE_FATAL);
+			ret = ARCHIVE_FATAL;
+			goto exit_write_header;
 		}
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_FILE_FORMAT,
@@ -386,7 +455,8 @@ archive_write_gnutar_header(struct archive_write *a,
 			if (errno == ENOMEM) {
 				archive_set_error(&a->archive, ENOMEM,
 				    "Can't allocate memory for Linkname");
-				return (ARCHIVE_FATAL);
+				ret = ARCHIVE_FATAL;
+				goto exit_write_header;
 			}
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_FILE_FORMAT,
@@ -400,7 +470,7 @@ archive_write_gnutar_header(struct archive_write *a,
 		size_t todo = gnutar->linkname_length;
 		struct archive_entry *temp = archive_entry_new2(&a->archive);
 
-		/* Uname/gname here don't really matter since noone reads them;
+		/* Uname/gname here don't really matter since no one reads them;
 		 * these are the values that GNU tar happens to use on FreeBSD. */
 		archive_entry_set_uname(temp, "root");
 		archive_entry_set_gname(temp, "wheel");
@@ -409,18 +479,18 @@ archive_write_gnutar_header(struct archive_write *a,
 		archive_entry_set_size(temp, gnutar->linkname_length + 1);
 		ret = archive_format_gnutar_header(a, buff, temp, 'K');
 		if (ret < ARCHIVE_WARN)
-			return (ret);
+			goto exit_write_header;
 		ret = __archive_write_output(a, buff, 512);
 		if(ret < ARCHIVE_WARN)
-			return (ret);
+			goto exit_write_header;
 		archive_entry_free(temp);
 		/* Write as many 512 bytes blocks as needed to write full name. */
 		ret = __archive_write_output(a, gnutar->linkname, todo);
 		if(ret < ARCHIVE_WARN)
-			return (ret);
+			goto exit_write_header;
 		ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo));
 		if (ret < ARCHIVE_WARN)
-			return (ret);
+			goto exit_write_header;
 	}
 
 	/* If pathname is longer than 100 chars we need to add an 'L' header. */
@@ -429,7 +499,7 @@ archive_write_gnutar_header(struct archive_write *a,
 		size_t todo = gnutar->pathname_length;
 		struct archive_entry *temp = archive_entry_new2(&a->archive);
 
-		/* Uname/gname here don't really matter since noone reads them;
+		/* Uname/gname here don't really matter since no one reads them;
 		 * these are the values that GNU tar happens to use on FreeBSD. */
 		archive_entry_set_uname(temp, "root");
 		archive_entry_set_gname(temp, "wheel");
@@ -438,18 +508,18 @@ archive_write_gnutar_header(struct archive_write *a,
 		archive_entry_set_size(temp, gnutar->pathname_length + 1);
 		ret = archive_format_gnutar_header(a, buff, temp, 'L');
 		if (ret < ARCHIVE_WARN)
-			return (ret);
+			goto exit_write_header;
 		ret = __archive_write_output(a, buff, 512);
 		if(ret < ARCHIVE_WARN)
-			return (ret);
+			goto exit_write_header;
 		archive_entry_free(temp);
 		/* Write as many 512 bytes blocks as needed to write full name. */
 		ret = __archive_write_output(a, pathname, todo);
 		if(ret < ARCHIVE_WARN)
-			return (ret);
+			goto exit_write_header;
 		ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo));
 		if (ret < ARCHIVE_WARN)
-			return (ret);
+			goto exit_write_header;
 	}
 
 	if (archive_entry_hardlink(entry) != NULL) {
@@ -466,28 +536,35 @@ archive_write_gnutar_header(struct archive_write *a,
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_FILE_FORMAT,
 			    "tar format cannot archive socket");
-			return (ARCHIVE_FAILED);
+			ret = ARCHIVE_FAILED;
+			goto exit_write_header;
 		default:
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_FILE_FORMAT,
 			    "tar format cannot archive this (mode=0%lo)",
 			    (unsigned long)archive_entry_mode(entry));
-			return (ARCHIVE_FAILED);
+			ret = ARCHIVE_FAILED;
+			goto exit_write_header;
 		}
 
 	ret = archive_format_gnutar_header(a, buff, entry, tartype);
 	if (ret < ARCHIVE_WARN)
-		return (ret);
+		goto exit_write_header;
 	if (ret2 < ret)
 		ret = ret2;
 	ret2 = __archive_write_output(a, buff, 512);
-	if (ret2 < ARCHIVE_WARN)
-		return (ret2);
+	if (ret2 < ARCHIVE_WARN) {
+		ret = ret2;
+		goto exit_write_header;
+	}
 	if (ret2 < ret)
 		ret = ret2;
 
 	gnutar->entry_bytes_remaining = archive_entry_size(entry);
 	gnutar->entry_padding = 0x1ff & (-(int64_t)gnutar->entry_bytes_remaining);
+exit_write_header:
+	if (entry_main)
+		archive_entry_free(entry_main);
 	return (ret);
 }
 
diff --git a/libarchive/archive_write_set_format_iso9660.c b/libarchive/archive_write_set_format_iso9660.c
index 4b01a64..5913702 100644
--- a/libarchive/archive_write_set_format_iso9660.c
+++ b/libarchive/archive_write_set_format_iso9660.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2009-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -994,7 +994,7 @@ static void	isoent_remove_child(struct isoent *, struct isoent *);
 static void	isoent_setup_directory_location(struct iso9660 *,
 		    int, struct vdd *);
 static void	isoent_setup_file_location(struct iso9660 *, int);
-static int	get_path_component(char *, int, const char *);
+static int	get_path_component(char *, size_t, const char *);
 static int	isoent_tree(struct archive_write *, struct isoent **);
 static struct isoent *isoent_find_child(struct isoent *, const char *);
 static struct isoent *isoent_find_entry(struct isoent *, const char *);
@@ -1507,6 +1507,11 @@ iso9660_options(struct archive_write *a, const char *key, const char *value)
 		break;
 	}
 
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
+
 invalid_value:
 	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 	    "Invalid value for option ``%s''", key);
@@ -1693,7 +1698,7 @@ wb_write_padding_to_temp(struct archive_write *a, int64_t csize)
 	size_t ns;
 	int ret;
 
-	ns = csize % LOGICAL_BLOCK_SIZE;
+	ns = (size_t)(csize % LOGICAL_BLOCK_SIZE);
 	if (ns != 0)
 		ret = write_null(a, LOGICAL_BLOCK_SIZE - ns);
 	else
@@ -1720,8 +1725,8 @@ write_iso9660_data(struct archive_write *a, const void *buff, size_t s)
 		struct content *con;
 		size_t ts;
 
-		ts = MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE -
-		    iso9660->cur_file->cur_content->size;
+		ts = (size_t)(MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE -
+		    iso9660->cur_file->cur_content->size);
 
 		if (iso9660->zisofs.detect_magic)
 			zisofs_detect_magic(a, buff, ts);
@@ -1741,9 +1746,9 @@ write_iso9660_data(struct archive_write *a, const void *buff, size_t s)
 			return (ARCHIVE_FATAL);
 
 		/* Compute the logical block number. */
-		iso9660->cur_file->cur_content->blocks =
-		    (iso9660->cur_file->cur_content->size
-		     + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS;
+		iso9660->cur_file->cur_content->blocks = (int)
+		    ((iso9660->cur_file->cur_content->size
+		     + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
 
 		/*
 		 * Make next extent.
@@ -1791,7 +1796,7 @@ iso9660_write_data(struct archive_write *a, const void *buff, size_t s)
 	if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
 		return (0);
 	if (s > iso9660->bytes_remaining)
-		s = iso9660->bytes_remaining;
+		s = (size_t)iso9660->bytes_remaining;
 	if (s == 0)
 		return (0);
 
@@ -1833,9 +1838,9 @@ iso9660_finish_entry(struct archive_write *a)
 		return (ARCHIVE_FATAL);
 
 	/* Compute the logical block number. */
-	iso9660->cur_file->cur_content->blocks =
-	    (iso9660->cur_file->cur_content->size
-	     + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS;
+	iso9660->cur_file->cur_content->blocks = (int)
+	    ((iso9660->cur_file->cur_content->size
+	     + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
 
 	/* Add the current file to data file list. */
 	isofile_add_data_file(iso9660, iso9660->cur_file);
@@ -1852,7 +1857,7 @@ iso9660_close(struct archive_write *a)
 	iso9660 = a->format_data;
 
 	/*
-	 * Write remaining data out to the temprary file.
+	 * Write remaining data out to the temporary file.
 	 */
 	if (wb_remaining(a) > 0) {
 		ret = wb_write_out(a);
@@ -1881,7 +1886,7 @@ iso9660_close(struct archive_write *a)
 		ret = zisofs_rewind_boot_file(a);
 		if (ret < 0)
 			return (ret);
-		/* Write remaining data out to the temprary file. */
+		/* Write remaining data out to the temporary file. */
 		if (wb_remaining(a) > 0) {
 			ret = wb_write_out(a);
 			if (ret < 0)
@@ -2239,7 +2244,7 @@ set_str_utf16be(struct archive_write *a, unsigned char *p, const char *s,
 		onepad = 0;
 	if (vdc == VDC_UCS2) {
 		struct iso9660 *iso9660 = a->format_data;
-		if (archive_strncpy_in_locale(&iso9660->utf16be, s, strlen(s),
+		if (archive_strncpy_l(&iso9660->utf16be, s, strlen(s),
 		    iso9660->sconv_to_utf16be) != 0 && errno == ENOMEM) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory for UTF-16BE");
@@ -2542,7 +2547,7 @@ set_date_time(unsigned char *p, time_t t)
 	set_digit(p+10, 2, tm.tm_min);
 	set_digit(p+12, 2, tm.tm_sec);
 	set_digit(p+14, 2, 0);
-	set_num_712(p+16, get_gmoffset(&tm)/(60*15));
+	set_num_712(p+16, (char)(get_gmoffset(&tm)/(60*15)));
 }
 
 static void
@@ -2564,7 +2569,7 @@ set_time_915(unsigned char *p, time_t t)
 	set_num_711(p+3, tm.tm_hour);
 	set_num_711(p+4, tm.tm_min);
 	set_num_711(p+5, tm.tm_sec);
-	set_num_712(p+6, get_gmoffset(&tm)/(60*15));
+	set_num_712(p+6, (char)(get_gmoffset(&tm)/(60*15)));
 }
 
 
@@ -2884,7 +2889,7 @@ set_directory_record_rr(unsigned char *bp, int dr_len,
 		if (nmmax > 0xff)
 			nmmax = 0xff;
 		while (nmlen + 5 > nmmax) {
-			length = nmmax;
+			length = (int)nmmax;
 			if (bp != NULL) {
 				bp[3] = length;
 				bp[5] = 0x01;/* Alternate Name continues
@@ -2907,7 +2912,7 @@ set_directory_record_rr(unsigned char *bp, int dr_len,
 				bp[4] = 1;    /* version */
 			}
 		}
-		length = 5 + nmlen;
+		length = 5 + (int)nmlen;
 		if (bp != NULL) {
 			bp[3] = length;
 			bp[5] = 0;
@@ -2936,8 +2941,8 @@ set_directory_record_rr(unsigned char *bp, int dr_len,
 			bp = extra_next_record(&ctl, length);
 		if (bp != NULL) {
 			mode_t mode;
-			uid_t uid;
-			gid_t gid;
+			int64_t uid;
+			int64_t gid;
 
 			mode = archive_entry_mode(file->entry);
 			uid = archive_entry_uid(file->entry);
@@ -2970,8 +2975,8 @@ set_directory_record_rr(unsigned char *bp, int dr_len,
 			/* file links (stat.st_nlink) */
 			set_num_733(bp+13,
 			    archive_entry_nlink(file->entry));
-			set_num_733(bp+21, uid);
-			set_num_733(bp+29, gid);
+			set_num_733(bp+21, (uint32_t)uid);
+			set_num_733(bp+29, (uint32_t)gid);
 			/* File Serial Number */
 			if (pxent->dir)
 				set_num_733(bp+37, pxent->dir_location);
@@ -3352,8 +3357,8 @@ set_directory_record_rr(unsigned char *bp, int dr_len,
 			bp[3] = length;
 			bp[4] = 1;	/* version	*/
 			dev = (uint64_t)archive_entry_rdev(file->entry);
-			set_num_733(bp + 5, dev >> 32);
-			set_num_733(bp + 13, dev & 0xFFFFFFFF);
+			set_num_733(bp + 5, (uint32_t)(dev >> 32));
+			set_num_733(bp + 13, (uint32_t)(dev & 0xFFFFFFFF));
 			bp += length;
 		}
 		extra_tell_used_size(&ctl, length);
@@ -3487,7 +3492,7 @@ set_directory_record(unsigned char *p, size_t n, struct isoent *isoent,
 			set_num_733(bp+11,
 			    xisoent->dir_block * LOGICAL_BLOCK_SIZE);
 		else
-			set_num_733(bp+11, file->cur_content->size);
+			set_num_733(bp+11, (uint32_t)file->cur_content->size);
 		/* Recording Date and Time */
 		/* NOTE:
 		 *  If a file type is symbolic link, you are seeing this
@@ -3506,7 +3511,7 @@ set_directory_record(unsigned char *p, size_t n, struct isoent *isoent,
 		/* Volume Sequence Number */
 		set_num_723(bp+29, iso9660->volume_sequence_number);
 		/* Length of File Identifier */
-		set_num_711(bp+33, fi_len);
+		set_num_711(bp+33, (unsigned char)fi_len);
 		/* File Identifier */
 		switch (t) {
 		case DIR_REC_VD:
@@ -3537,20 +3542,20 @@ set_directory_record(unsigned char *p, size_t n, struct isoent *isoent,
 	if (t == DIR_REC_VD) {
 		if (p != NULL)
 			/* Length of Directory Record */
-			set_num_711(p, dr_len);
+			set_num_711(p, (unsigned char)dr_len);
 		else
-			isoent->dr_len.vd = dr_len;
-		return (dr_len);
+			isoent->dr_len.vd = (int)dr_len;
+		return ((int)dr_len);
 	}
 
 	/* Rockridge */
 	if (iso9660->opt.rr && vdd_type != VDD_JOLIET)
-		dr_len = set_directory_record_rr(bp, dr_len,
+		dr_len = set_directory_record_rr(bp, (int)dr_len,
 		    isoent, iso9660, t);
 
 	if (p != NULL)
 		/* Length of Directory Record */
-		set_num_711(p, dr_len);
+		set_num_711(p, (unsigned char)dr_len);
 	else {
 		/*
 		 * Save the size which is needed to write this
@@ -3563,15 +3568,15 @@ set_directory_record(unsigned char *p, size_t n, struct isoent *isoent,
 			 *  in switch ....  */
 			break;
 		case DIR_REC_SELF:
-			isoent->dr_len.self = dr_len; break;
+			isoent->dr_len.self = (int)dr_len; break;
 		case DIR_REC_PARENT:
-			isoent->dr_len.parent = dr_len; break;
+			isoent->dr_len.parent = (int)dr_len; break;
 		case DIR_REC_NORMAL:
-			isoent->dr_len.normal = dr_len; break;
+			isoent->dr_len.normal = (int)dr_len; break;
 		}
 	}
 
-	return (dr_len);
+	return ((int)dr_len);
 }
 
 /*
@@ -3664,7 +3669,7 @@ wb_set_offset(struct archive_write *a, int64_t off)
 		iso9660->wbuff_tail = iso9660->wbuff_offset + used;
 	if (iso9660->wbuff_offset < iso9660->wbuff_written) {
 		if (used > 0 &&
-		    write_to_temp(a, iso9660->wbuff, used) != ARCHIVE_OK)
+		    write_to_temp(a, iso9660->wbuff, (size_t)used) != ARCHIVE_OK)
 			return (ARCHIVE_FATAL);
 		iso9660->wbuff_offset = iso9660->wbuff_written;
 		lseek(iso9660->temp_fd, iso9660->wbuff_offset, SEEK_SET);
@@ -3683,13 +3688,13 @@ wb_set_offset(struct archive_write *a, int64_t off)
 		iso9660->wbuff_offset = off;
 		iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
 	} else if (off <= iso9660->wbuff_tail) {
-		iso9660->wbuff_remaining =
-		    sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset);
+		iso9660->wbuff_remaining = (size_t)
+		    (sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset));
 	} else {
 		ext_bytes = off - iso9660->wbuff_tail;
-		iso9660->wbuff_remaining = sizeof(iso9660->wbuff)
-		   - (iso9660->wbuff_tail - iso9660->wbuff_offset);
-		while (ext_bytes >= iso9660->wbuff_remaining) {
+		iso9660->wbuff_remaining = (size_t)(sizeof(iso9660->wbuff)
+		   - (iso9660->wbuff_tail - iso9660->wbuff_offset));
+		while (ext_bytes >= (int64_t)iso9660->wbuff_remaining) {
 			if (write_null(a, (size_t)iso9660->wbuff_remaining)
 			    != ARCHIVE_OK)
 				return (ARCHIVE_FATAL);
@@ -4250,7 +4255,7 @@ _write_path_table(struct archive_write *a, int type_m, int depth,
 			bp = wb -1;
 		}
 		/* Length of Directory Identifier */
-		set_num_711(bp+1, len);
+		set_num_711(bp+1, (unsigned char)len);
 		/* Extended Attribute Record Length */
 		set_num_711(bp+2, 0);
 		/* Location of Extent */
@@ -4273,7 +4278,7 @@ _write_path_table(struct archive_write *a, int type_m, int depth,
 			bp[9+len] = 0;
 			len++;
 		}
-		wsize += 8 + len;
+		wsize += 8 + (int)len;
 		bp += 8 + len;
 	}
 	if ((bp + 1) > wb) {
@@ -4508,8 +4513,7 @@ write_file_descriptors(struct archive_write *a)
 
 	/* Write the boot file contents. */
 	if (iso9660->el_torito.boot != NULL) {
-		struct isofile *file = iso9660->el_torito.boot->file;
-
+		file = iso9660->el_torito.boot->file;
 		blocks = file->content.blocks;
 		offset = file->content.offset_of_temp;
 		if (offset != 0) {
@@ -4810,13 +4814,19 @@ isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
 		struct archive_wstring ws;
 
 		if (wp != NULL) {
+			int r;
 			archive_string_init(&ws);
 			archive_wstrcpy(&ws, wp);
 			cleanup_backslash_2(ws.s);
 			archive_string_empty(&(file->parentdir));
-			archive_string_append_from_wcs(&(file->parentdir),
+			r = archive_string_append_from_wcs(&(file->parentdir),
 			    ws.s, ws.length);
 			archive_wstring_free(&ws);
+			if (r < 0 && errno == ENOMEM) {
+				archive_set_error(&a->archive, ENOMEM,
+				    "Can't allocate memory");
+				return (ARCHIVE_FATAL);
+			}
 		}
 	}
 #endif
@@ -4919,14 +4929,20 @@ isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
 			struct archive_wstring ws;
 
 			if (wp != NULL) {
+				int r;
 				archive_string_init(&ws);
 				archive_wstrcpy(&ws, wp);
 				cleanup_backslash_2(ws.s);
 				archive_string_empty(&(file->symlink));
-				archive_string_append_from_wcs(
+				r = archive_string_append_from_wcs(
 				    &(file->symlink),
 				    ws.s, ws.length);
 				archive_wstring_free(&ws);
+				if (r < 0 && errno == ENOMEM) {
+					archive_set_error(&a->archive, ENOMEM,
+					    "Can't allocate memory");
+					return (ARCHIVE_FATAL);
+				}
 			}
 		}
 #endif
@@ -5422,8 +5438,8 @@ isoent_setup_file_location(struct iso9660 *iso9660, int location)
 	iso9660->total_file_block = 0;
 	if ((isoent = iso9660->el_torito.catalog) != NULL) {
 		isoent->file->content.location = location;
-		block = (archive_entry_size(isoent->file->entry) +
-		    LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS;
+		block = (int)((archive_entry_size(isoent->file->entry) +
+		    LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
 		location += block;
 		iso9660->total_file_block += block;
 	}
@@ -5431,8 +5447,9 @@ isoent_setup_file_location(struct iso9660 *iso9660, int location)
 		isoent->file->content.location = location;
 		size = fd_boot_image_size(iso9660->el_torito.media_type);
 		if (size == 0)
-			size = archive_entry_size(isoent->file->entry);
-		block = (size + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS;
+			size = (size_t)archive_entry_size(isoent->file->entry);
+		block = ((int)size + LOGICAL_BLOCK_SIZE -1)
+		    >> LOGICAL_BLOCK_BITS;
 		location += block;
 		iso9660->total_file_block += block;
 		isoent->file->content.blocks = block;
@@ -5493,10 +5510,10 @@ isoent_setup_file_location(struct iso9660 *iso9660, int location)
 }
 
 static int
-get_path_component(char *name, int n, const char *fn)
+get_path_component(char *name, size_t n, const char *fn)
 {
 	char *p;
-	int l;
+	size_t l;
 
 	p = strchr(fn, '/');
 	if (p == NULL) {
@@ -5509,7 +5526,7 @@ get_path_component(char *name, int n, const char *fn)
 	memcpy(name, fn, l);
 	name[l] = '\0';
 
-	return (l);
+	return ((int)l);
 }
 
 /*
@@ -5802,17 +5819,18 @@ idr_ensure_poolsize(struct archive_write *a, struct idr *idr,
 {
 
 	if (idr->pool_size < cnt) {
+		void *p;
 		const int bk = (1 << 7) - 1;
 		int psize;
 
 		psize = (cnt + bk) & ~bk;
-		idr->idrent_pool = realloc(idr->idrent_pool,
-		    sizeof(struct idrent) * psize);
-		if (idr->idrent_pool == NULL) {
+		p = realloc(idr->idrent_pool, sizeof(struct idrent) * psize);
+		if (p == NULL) {
 			archive_set_error(&a->archive, ENOMEM,
 			    "Can't allocate memory");
 			return (ARCHIVE_FATAL);
 		}
+		idr->idrent_pool = (struct idrent *)p;
 		idr->pool_size = psize;
 	}
 	return (ARCHIVE_OK);
@@ -6000,7 +6018,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
 		char *dot, *xdot;
 		int ext_off, noff, weight;
 
-		l = np->file->basename.length;
+		l = (int)np->file->basename.length;
 		p = malloc(l+31+2+1);
 		if (p == NULL) {
 			archive_set_error(&a->archive, ENOMEM,
@@ -6064,7 +6082,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
 				ext_off = l;
 		} else {
 			*dot = '.';
-			ext_off = dot - p;
+			ext_off = (int)(dot - p);
 
 			if (iso9660->opt.iso_level == 1) {
 				if (dot - p <= 8) {
@@ -6091,11 +6109,11 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
 						ext_off = dnmax;
 				}
 			} else if (l > ffmax) {
-				int extlen = strlen(dot);
+				int extlen = (int)strlen(dot);
 				int xdoff;
 
 				if (xdot != NULL)
-					xdoff = xdot - p;
+					xdoff = (int)(xdot - p);
 				else
 					xdoff = 0;
 
@@ -6132,7 +6150,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
 		}
 		/* Save an offset of a file name extension to sort files. */
 		np->ext_off = ext_off;
-		np->ext_len = strlen(&p[ext_off]);
+		np->ext_len = (int)strlen(&p[ext_off]);
 		np->id_len = l = ext_off + np->ext_len;
 
 		/* Make an offset of the number which is used to be set
@@ -6249,30 +6267,35 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
 			p += 2;
 			lt -= 2;
 		}
-		ext_off = dot - (unsigned char *)np->identifier;
+		ext_off = (int)(dot - (unsigned char *)np->identifier);
 		np->ext_off = ext_off;
-		np->ext_len = l - ext_off;
-		np->id_len = l;
+		np->ext_len = (int)l - ext_off;
+		np->id_len = (int)l;
 
 		/*
 		 * Get a length of MBS of a full-pathname.
 		 */
 		if ((int)np->file->basename_utf16.length > ffmax) {
-			archive_strncpy_in_locale(&iso9660->mbs,
+			if (archive_strncpy_l(&iso9660->mbs,
 			    (const char *)np->identifier, l,
-			    iso9660->sconv_from_utf16be);
-			np->mb_len = iso9660->mbs.length;
+				iso9660->sconv_from_utf16be) != 0 &&
+			    errno == ENOMEM) {
+				archive_set_error(&a->archive, errno,
+				    "No memory");
+				return (ARCHIVE_FATAL);
+			}
+			np->mb_len = (int)iso9660->mbs.length;
 			if (np->mb_len != (int)np->file->basename.length)
 				weight = np->mb_len;
 		} else
-			np->mb_len = np->file->basename.length;
+			np->mb_len = (int)np->file->basename.length;
 
 		/* If a length of full-pathname is longer than 240 bytes,
 		 * it violates Joliet extensions regulation. */
 		if (parent_len + np->mb_len > 240) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			    "The regulation of Joliet extensions;"
-			    " A lenght of a full-pathname of `%s' is "
+			    " A length of a full-pathname of `%s' is "
 			    "longer than 240 bytes, (p=%d, b=%d)",
 			    archive_entry_pathname(np->file->entry),
 			    (int)parent_len, (int)np->mb_len);
@@ -6280,7 +6303,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
 		}
 
 		/* Make an offset of the number which is used to be set
-		 * hexadecimal number to avoid duplicate identififier. */
+		 * hexadecimal number to avoid duplicate identifier. */
 		if ((int)l == ffmax)
 			noff = ext_off - 6;
 		else if ((int)l == ffmax-2)
@@ -6300,7 +6323,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
 }
 
 /*
- * This comparing rule is acording to ISO9660 Standard 9.3
+ * This comparing rule is according to ISO9660 Standard 9.3
  */
 static int
 isoent_cmp_iso9660_identifier(const struct isoent *p1, const struct isoent *p2)
@@ -6360,7 +6383,7 @@ isoent_cmp_iso9660_identifier(const struct isoent *p1, const struct isoent *p2)
 			if (0x20 != *s2++)
 				return (0x20
 				    - *(const unsigned char *)(s2 - 1));
-	} else if (p1->ext_len < p2->ext_len) {
+	} else if (p1->ext_len > p2->ext_len) {
 		s1 += l;
 		l = p1->ext_len - p2->ext_len;
 		while (l--)
@@ -6448,7 +6471,7 @@ isoent_cmp_joliet_identifier(const struct isoent *p1, const struct isoent *p2)
 		while (l--)
 			if (0 != *s2++)
 				return (- *(const unsigned char *)(s2 - 1));
-	} else if (p1->ext_len < p2->ext_len) {
+	} else if (p1->ext_len > p2->ext_len) {
 		s1 += l;
 		l = p1->ext_len - p2->ext_len;
 		while (l--)
@@ -6514,8 +6537,7 @@ isoent_traverse_tree(struct archive_write *a, struct vdd* vdd)
 	struct idr idr;
 	int depth;
 	int r;
-	int (*genid)(struct archive_write *a, struct isoent *isoent,
-	    struct idr *idr);
+	int (*genid)(struct archive_write *, struct isoent *, struct idr *);
 
 	idr_init(iso9660, vdd, &idr);
 	np = vdd->rootent;
@@ -6619,7 +6641,7 @@ isoent_collect_dirs(struct vdd *vdd, struct isoent *rootent, int depth)
  */
 static int
 isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,
-    struct isoent *isoent, struct isoent **newent)
+    struct isoent *curent, struct isoent **newent)
 {
 	struct iso9660 *iso9660 = a->format_data;
 	struct isoent *rrmoved, *mvent, *np;
@@ -6645,40 +6667,40 @@ isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,
 		*rr_moved = rrmoved;
 	}
 	/*
-	 * Make a clone of isoent which is going to be relocated
+	 * Make a clone of curent which is going to be relocated
 	 * to rr_moved.
 	 */
-	mvent = isoent_clone(isoent);
+	mvent = isoent_clone(curent);
 	if (mvent == NULL) {
 		archive_set_error(&a->archive, ENOMEM,
 		    "Can't allocate memory");
 		return (ARCHIVE_FATAL);
 	}
 	/* linking..  and use for creating "CL", "PL" and "RE" */
-	mvent->rr_parent = isoent->parent;
-	isoent->rr_child = mvent;
+	mvent->rr_parent = curent->parent;
+	curent->rr_child = mvent;
 	/*
-	 * Move subdirectories from the isoent to mvent
+	 * Move subdirectories from the curent to mvent
 	 */
-	if (isoent->children.first != NULL) {
-		*mvent->children.last = isoent->children.first;
-		mvent->children.last = isoent->children.last;
+	if (curent->children.first != NULL) {
+		*mvent->children.last = curent->children.first;
+		mvent->children.last = curent->children.last;
 	}
 	for (np = mvent->children.first; np != NULL; np = np->chnext)
 		np->parent = mvent;
-	mvent->children.cnt = isoent->children.cnt;
-	isoent->children.cnt = 0;
-	isoent->children.first = NULL;
-	isoent->children.last = &isoent->children.first;
+	mvent->children.cnt = curent->children.cnt;
+	curent->children.cnt = 0;
+	curent->children.first = NULL;
+	curent->children.last = &curent->children.first;
 
-	if (isoent->subdirs.first != NULL) {
-		*mvent->subdirs.last = isoent->subdirs.first;
-		mvent->subdirs.last = isoent->subdirs.last;
+	if (curent->subdirs.first != NULL) {
+		*mvent->subdirs.last = curent->subdirs.first;
+		mvent->subdirs.last = curent->subdirs.last;
 	}
-	mvent->subdirs.cnt = isoent->subdirs.cnt;
-	isoent->subdirs.cnt = 0;
-	isoent->subdirs.first = NULL;
-	isoent->subdirs.last = &isoent->subdirs.first;
+	mvent->subdirs.cnt = curent->subdirs.cnt;
+	curent->subdirs.cnt = 0;
+	curent->subdirs.first = NULL;
+	curent->subdirs.last = &curent->subdirs.first;
 
 	/*
 	 * The mvent becomes a child of the rr_moved entry.
@@ -6691,7 +6713,7 @@ isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,
 	 * has to set the flag as a file.
 	 * See also RRIP 4.1.5.1 Description of the "CL" System Use Entry.
 	 */
-	isoent->dir = 0;
+	curent->dir = 0;
 
 	*newent = mvent;
 
@@ -6896,12 +6918,22 @@ isoent_make_path_table_2(struct archive_write *a, struct vdd *vdd,
 	switch (vdd->vdd_type) {
 	case VDD_PRIMARY:
 	case VDD_ENHANCED:
+#ifdef __COMPAR_FN_T
+		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
+		    (__compar_fn_t)_compare_path_table);
+#else
 		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
 		    _compare_path_table);
+#endif
 		break;
 	case VDD_JOLIET:
+#ifdef __COMPAR_FN_T
+		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
+		    (__compar_fn_t)_compare_path_table_joliet);
+#else
 		qsort(enttbl, pt->cnt, sizeof(struct isoent *),
 		    _compare_path_table_joliet);
+#endif
 		break;
 	}
 	for (i = 0; i < pt->cnt; i++)
@@ -7284,7 +7316,7 @@ setup_boot_information(struct archive_write *a)
 		size_t rsize;
 		ssize_t i, rs;
 
-		if (size > sizeof(buff))
+		if (size > (int64_t)sizeof(buff))
 			rsize = sizeof(buff);
 		else
 			rsize = (size_t)size;
@@ -7370,7 +7402,7 @@ zisofs_init(struct archive_write *a,  struct isofile *file)
 	struct iso9660 *iso9660 = a->format_data;
 #ifdef HAVE_ZLIB_H
 	uint64_t tsize;
-	size_t ceil, bpsize;
+	size_t _ceil, bpsize;
 	int r;
 #endif
 
@@ -7405,12 +7437,13 @@ zisofs_init(struct archive_write *a,  struct isofile *file)
 	/* Mark file->zisofs to create RRIP 'ZF' Use Entry. */
 	file->zisofs.header_size = ZF_HEADER_SIZE >> 2;
 	file->zisofs.log2_bs = ZF_LOG2_BS;
-	file->zisofs.uncompressed_size = archive_entry_size(file->entry);
+	file->zisofs.uncompressed_size =
+		(uint32_t)archive_entry_size(file->entry);
 
 	/* Calculate a size of Block Pointers of zisofs. */
-	ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)
+	_ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)
 		>> file->zisofs.log2_bs;
-	iso9660->zisofs.block_pointers_cnt = ceil + 1;
+	iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1;
 	iso9660->zisofs.block_pointers_idx = 0;
 
 	/* Ensure a buffer size used for Block Pointers */
@@ -7433,13 +7466,14 @@ zisofs_init(struct archive_write *a,  struct isofile *file)
 	 * file.
 	 */
 	tsize = ZF_HEADER_SIZE + bpsize;
-	if (write_null(a, tsize) != ARCHIVE_OK)
+	if (write_null(a, (size_t)tsize) != ARCHIVE_OK)
 		return (ARCHIVE_FATAL);
 
 	/*
 	 * Initialize some variables to make zisofs.
 	 */
-	archive_le32enc(&(iso9660->zisofs.block_pointers[0]), tsize);
+	archive_le32enc(&(iso9660->zisofs.block_pointers[0]),
+		(uint32_t)tsize);
 	iso9660->zisofs.remaining = file->zisofs.uncompressed_size;
 	iso9660->zisofs.making = 1;
 	iso9660->zisofs.allzero = 1;
@@ -7461,14 +7495,14 @@ zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)
 	uint32_t uncompressed_size;
 	unsigned char header_size;
 	unsigned char log2_bs;
-	size_t ceil, doff;
+	size_t _ceil, doff;
 	uint32_t bst, bed;
 	int magic_max;
 	int64_t entry_size;
 
 	entry_size = archive_entry_size(file->entry);
-	if (sizeof(iso9660->zisofs.magic_buffer) > entry_size)
-		magic_max = entry_size;
+	if ((int64_t)sizeof(iso9660->zisofs.magic_buffer) > entry_size)
+		magic_max = (int)entry_size;
 	else
 		magic_max = sizeof(iso9660->zisofs.magic_buffer);
 
@@ -7485,7 +7519,7 @@ zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)
 				l = s;
 			memcpy(iso9660->zisofs.magic_buffer
 			    + iso9660->zisofs.magic_cnt, buff, l);
-			iso9660->zisofs.magic_cnt += l;
+			iso9660->zisofs.magic_cnt += (int)l;
 			if (iso9660->zisofs.magic_cnt < magic_max)
 				return;
 		}
@@ -7509,16 +7543,16 @@ zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)
 		return;/* Invalid or not supported header. */
 
 	/* Calculate a size of Block Pointers of zisofs. */
-	ceil = (uncompressed_size +
+	_ceil = (uncompressed_size +
 	        (ARCHIVE_LITERAL_LL(1) << log2_bs) -1) >> log2_bs;
-	doff = (ceil + 1) * 4 + 16;
-	if (entry_size < doff)
+	doff = (_ceil + 1) * 4 + 16;
+	if (entry_size < (int64_t)doff)
 		return;/* Invalid data. */
 
 	/* Check every Block Pointer has valid value. */
 	p = magic_buff + 16;
 	endp = magic_buff + magic_max;
-	while (ceil && p + 8 <= endp) {
+	while (_ceil && p + 8 <= endp) {
 		bst = archive_le32dec(p);
 		if (bst != doff)
 			return;/* Invalid data. */
@@ -7527,7 +7561,7 @@ zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)
 		if (bed < bst || bed > entry_size)
 			return;/* Invalid data. */
 		doff += bed - bst;
-		ceil--;
+		_ceil--;
 	}
 
 	file->zisofs.uncompressed_size = uncompressed_size;
@@ -7555,7 +7589,7 @@ zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
 
 	zstrm = &(iso9660->zisofs.stream);
 	zstrm->next_out = wb_buffptr(a);
-	zstrm->avail_out = wb_remaining(a);
+	zstrm->avail_out = (uInt)wb_remaining(a);
 	b = (const unsigned char *)buff;
 	do {
 		avail = ZF_BLOCK_SIZE - zstrm->total_in;
@@ -7569,7 +7603,7 @@ zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
 			flush = Z_FINISH;
 
 		zstrm->next_in = (Bytef *)(uintptr_t)(const void *)b;
-		zstrm->avail_in = avail;
+		zstrm->avail_in = (uInt)avail;
 
 		/*
 		 * Check if current data block are all zero.
@@ -7625,7 +7659,7 @@ zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
 				iso9660->zisofs.total_size += csize;
 				iso9660->cur_file->cur_content->size += csize;
 				zstrm->next_out = wb_buffptr(a);
-				zstrm->avail_out = wb_remaining(a);
+				zstrm->avail_out = (uInt)wb_remaining(a);
 				break;
 			default:
 				archive_set_error(&a->archive,
@@ -7644,7 +7678,7 @@ zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
 			iso9660->zisofs.block_pointers_idx ++;
 			archive_le32enc(&(iso9660->zisofs.block_pointers[
 			    iso9660->zisofs.block_pointers_idx]),
-				iso9660->zisofs.total_size);
+				(uint32_t)iso9660->zisofs.total_size);
 			r = zisofs_init_zstream(a);
 			if (r != ARCHIVE_OK)
 				return (ARCHIVE_FATAL);
@@ -7770,13 +7804,13 @@ zisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs,
     const unsigned char *p, size_t bytes)
 {
 	size_t avail = bytes;
-	size_t ceil, xsize;
+	size_t _ceil, xsize;
 
 	/* Allocate block pointers buffer. */
-	ceil = (zisofs->pz_uncompressed_size +
-		(1LL << zisofs->pz_log2_bs) - 1)
-		>> zisofs->pz_log2_bs;
-	xsize = (ceil + 1) * 4;
+	_ceil = (size_t)((zisofs->pz_uncompressed_size +
+		(((int64_t)1) << zisofs->pz_log2_bs) - 1)
+		>> zisofs->pz_log2_bs);
+	xsize = (_ceil + 1) * 4;
 	if (zisofs->block_pointers == NULL) {
 		size_t alloc = ((xsize >> 10) + 1) << 10;
 		zisofs->block_pointers = malloc(alloc);
@@ -7789,7 +7823,7 @@ zisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs,
 	zisofs->block_pointers_size = xsize;
 
 	/* Allocate uncompressed data buffer. */
-	zisofs->uncompressed_buffer_size = 1UL << zisofs->pz_log2_bs;
+	zisofs->uncompressed_buffer_size = (size_t)1UL << zisofs->pz_log2_bs;
 
 	/*
 	 * Read the file header, and check the magic code of zisofs.
@@ -7859,7 +7893,7 @@ zisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs,
 			return (rs);
 		if (!zisofs->initialized) {
 			/* We need more data. */
-			zisofs->pz_offset += bytes;
+			zisofs->pz_offset += (uint32_t)bytes;
 			return (bytes);
 		}
 		avail = rs;
@@ -7942,9 +7976,9 @@ zisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs,
 		if (avail > zisofs->block_avail)
 			zisofs->stream.avail_in = zisofs->block_avail;
 		else
-			zisofs->stream.avail_in = avail;
+			zisofs->stream.avail_in = (uInt)avail;
 		zisofs->stream.next_out = wb_buffptr(a);
-		zisofs->stream.avail_out = wb_remaining(a);
+		zisofs->stream.avail_out = (uInt)wb_remaining(a);
 
 		r = inflate(&zisofs->stream, 0);
 		switch (r) {
@@ -7957,12 +7991,12 @@ zisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs,
 			return (ARCHIVE_FATAL);
 		}
 		avail -= zisofs->stream.next_in - p;
-		zisofs->block_avail -= zisofs->stream.next_in - p;
+		zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);
 		r = wb_consume(a, wb_remaining(a) - zisofs->stream.avail_out);
 		if (r < 0)
 			return (r);
 	}
-	zisofs->pz_offset += bytes;
+	zisofs->pz_offset += (uint32_t)bytes;
 	return (bytes - avail);
 }
 
@@ -7996,7 +8030,7 @@ zisofs_rewind_boot_file(struct archive_write *a)
 	fd = iso9660->temp_fd;
 	new_offset = wb_offset(a);
 	read_offset = file->content.offset_of_temp;
-	remaining = file->content.size;
+	remaining = (size_t)file->content.size;
 	if (remaining > 1024 * 32)
 		rbuff_size = 1024 * 32;
 	else
diff --git a/libarchive/archive_write_set_format_mtree.c b/libarchive/archive_write_set_format_mtree.c
index 3802a25..9c0613c 100644
--- a/libarchive/archive_write_set_format_mtree.c
+++ b/libarchive/archive_write_set_format_mtree.c
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 2009,2011 Michihiro NAKAJIMA
  * Copyright (c) 2008 Joerg Sonnenberger
+ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,8 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171
 #include "archive_crypto_private.h"
 #include "archive_entry.h"
 #include "archive_private.h"
+#include "archive_rb.h"
+#include "archive_string.h"
 #include "archive_write_private.h"
 
 #define INDENTNAMELEN	15
@@ -45,27 +47,39 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171
 #define SET_KEYS	\
 	(F_FLAGS | F_GID | F_GNAME | F_MODE | F_TYPE | F_UID | F_UNAME)
 
-struct mtree_entry {
-	struct mtree_entry *next;
+struct attr_counter {
+	struct attr_counter *prev;
+	struct attr_counter *next;
+	struct mtree_entry *m_entry;
+	int count;
+};
 
-	char *pathname;
-	char *symlink;
-	unsigned int nlink;
-	mode_t filetype;
-	mode_t mode;
-	int64_t uid;
-	int64_t gid;
-	char *uname;
-	char *gname;
-	char *fflags_text;
-	unsigned long fflags_set;
-	unsigned long fflags_clear;
-	time_t mtime;
-	long mtime_nsec;
-	dev_t rdevmajor;
-	dev_t rdevminor;
-	int64_t size;
+struct att_counter_set {
+	struct attr_counter *uid_list;
+	struct attr_counter *gid_list;
+	struct attr_counter *mode_list;
+	struct attr_counter *flags_list;
+};
+
+struct mtree_chain {
+	struct mtree_entry *first;
+	struct mtree_entry **last;
+};
+
+/*
+ * The Data only for a directory file.
+ */
+struct dir_info {
+	struct archive_rb_tree rbtree;
+	struct mtree_chain children;
+	struct mtree_entry *chnext;
+	int virtual;
+};
 
+/*
+ * The Data only for a regular file.
+ */
+struct reg_info {
 	int compute_sum;
 	uint32_t crc;
 #ifdef ARCHIVE_HAS_MD5
@@ -88,23 +102,51 @@ struct mtree_entry {
 #endif
 };
 
-struct attr_counter {
-	struct attr_counter *prev;
-	struct attr_counter *next;
-	int count;
-	struct mtree_entry *m_entry;
+struct mtree_entry {
+	struct archive_rb_node rbnode;
+	struct mtree_entry *next;
+	struct mtree_entry *parent;
+	struct dir_info *dir_info;
+	struct reg_info *reg_info;
+
+	struct archive_string parentdir;
+	struct archive_string basename;
+	struct archive_string pathname;
+	struct archive_string symlink;
+	struct archive_string uname;
+	struct archive_string gname;
+	struct archive_string fflags_text;
+	unsigned int nlink;
+	mode_t filetype;
+	mode_t mode;
+	int64_t size;
+	int64_t uid;
+	int64_t gid;
+	time_t mtime;
+	long mtime_nsec;
+	unsigned long fflags_set;
+	unsigned long fflags_clear;
+	dev_t rdevmajor;
+	dev_t rdevminor;
 };
 
 struct mtree_writer {
 	struct mtree_entry *mtree_entry;
+	struct mtree_entry *root;
+	struct mtree_entry *cur_dirent;
+	struct archive_string cur_dirstr;
+	struct mtree_chain file_list;
+
 	struct archive_string ebuf;
 	struct archive_string buf;
 	int first;
 	uint64_t entry_bytes_remaining;
+
+	/*
+	 * Set global value.
+	 */
 	struct {
-		int		output;
-		int		processed;
-		struct archive_string parent;
+		int		processing;
 		mode_t		type;
 		int		keys;
 		int64_t		uid;
@@ -112,14 +154,11 @@ struct mtree_writer {
 		mode_t		mode;
 		unsigned long	fflags_set;
 		unsigned long	fflags_clear;
-
-		struct attr_counter *uid_list;
-		struct attr_counter *gid_list;
-		struct attr_counter *mode_list;
-		struct attr_counter *flags_list;
-		struct mtree_entry *me_first;
-		struct mtree_entry **me_last;
 	} set;
+	struct att_counter_set	acs;
+	int classic;
+	int depth;
+
 	/* check sum */
 	int compute_sum;
 	uint32_t crc;
@@ -173,27 +212,51 @@ struct mtree_writer {
 #define	F_SHA512	0x02000000		/* SHA-512 digest */
 
 	/* Options */
-	int dironly;		/* if the dironly is 1, ignore everything except
-				 * directory type files. like mtree(8) -d option.
-				 */
-	int indent;		/* if the indent is 1, indent writing data. */
+	int dironly;		/* If it is set, ignore all files except
+				 * directory files, like mtree(8) -d option. */
+	int indent;		/* If it is set, indent output data. */
+	int output_global_set;	/* If it is set, use /set keyword to set
+				 * global values. When generating mtree
+				 * classic format, it is set by default. */
 };
 
 #define DEFAULT_KEYS	(F_DEV | F_FLAGS | F_GID | F_GNAME | F_SLINK | F_MODE\
 			 | F_NLINK | F_SIZE | F_TIME | F_TYPE | F_UID\
 			 | F_UNAME)
+#define attr_counter_set_reset	attr_counter_set_free
 
-static struct attr_counter * new_attr_count(struct mtree_entry *,
-	struct attr_counter *);
-static void free_attr_count(struct attr_counter **);
-static int inc_attr_count(struct attr_counter **, struct attr_counter *,
+static void attr_counter_free(struct attr_counter **);
+static int attr_counter_inc(struct attr_counter **, struct attr_counter *,
 	struct attr_counter *, struct mtree_entry *);
-static int collect_set_values(struct mtree_writer *, struct mtree_entry *);
-static int get_keys(struct mtree_writer *, struct mtree_entry *);
+static struct attr_counter * attr_counter_new(struct mtree_entry *,
+	struct attr_counter *);
+static int attr_counter_set_collect(struct mtree_writer *,
+	struct mtree_entry *);
+static void attr_counter_set_free(struct mtree_writer *);
+static int get_global_set_keys(struct mtree_writer *, struct mtree_entry *);
+static int mtree_entry_add_child_tail(struct mtree_entry *,
+	struct mtree_entry *);
+static int mtree_entry_create_virtual_dir(struct archive_write *, const char *,
+	struct mtree_entry **);
+static int mtree_entry_cmp_node(const struct archive_rb_node *,
+	const struct archive_rb_node *);
+static int mtree_entry_cmp_key(const struct archive_rb_node *, const void *);
+static int mtree_entry_exchange_same_entry(struct archive_write *,
+    struct mtree_entry *, struct mtree_entry *);
+static void mtree_entry_free(struct mtree_entry *);
+static int mtree_entry_new(struct archive_write *, struct archive_entry *,
+	struct mtree_entry **);
+static void mtree_entry_register_free(struct mtree_writer *);
+static void mtree_entry_register_init(struct mtree_writer *);
+static int mtree_entry_setup_filenames(struct archive_write *,
+	struct mtree_entry *, struct archive_entry *);
+static int mtree_entry_tree_add(struct archive_write *, struct mtree_entry **);
 static void sum_init(struct mtree_writer *);
 static void sum_update(struct mtree_writer *, const void *, size_t);
-static void sum_final(struct mtree_writer *, struct mtree_entry *);
-static void sum_write(struct archive_string *, struct mtree_entry *);
+static void sum_final(struct mtree_writer *, struct reg_info *);
+static void sum_write(struct archive_string *, struct reg_info *);
+static int write_mtree_entry(struct archive_write *, struct mtree_entry *);
+static int write_dot_dot_entry(struct archive_write *, struct mtree_entry *);
 
 #define	COMPUTE_CRC(var, ch)	(var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
 static const uint32_t crctab[] = {
@@ -251,26 +314,30 @@ static const uint32_t crctab[] = {
 	0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
 };
 
-static int
-mtree_safe_char(char c)
-{
-	if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
-		return 1;
-	if (c >= '0' && c <= '9')
-		return 1;
-	if (c == 35 || c == 61 || c == 92)
-		return 0; /* #, = and \ are always quoted */
-	
-	if (c >= 33 && c <= 47) /* !"$%&'()*+,-./ */
-		return 1;
-	if (c >= 58 && c <= 64) /* :;<>?@ */
-		return 1;
-	if (c >= 91 && c <= 96) /* []^_` */
-		return 1;
-	if (c >= 123 && c <= 126) /* {|}~ */
-		return 1;
-	return 0;
-}
+static const unsigned char safe_char[256] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
+	/* !"$%&'()*+,-./  EXCLUSION:0x20( ) 0x23(#) */
+	0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
+	/* 0123456789:;<>?  EXCLUSION:0x3d(=) */
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */
+	/* @ABCDEFGHIJKLMNO */
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
+	/* PQRSTUVWXYZ[]^_ EXCLUSION:0x5c(\)  */
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 50 - 5F */
+	/* `abcdefghijklmno */
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
+	/* pqrstuvwxyz{|}~ */
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
+};
 
 static void
 mtree_quote(struct archive_string *s, const char *str)
@@ -280,7 +347,7 @@ mtree_quote(struct archive_string *s, const char *str)
 	unsigned char c;
 
 	for (start = str; *str != '\0'; ++str) {
-		if (mtree_safe_char(*str))
+		if (safe_char[*(const unsigned char *)str])
 			continue;
 		if (start != str)
 			archive_strncat(s, start, str - start);
@@ -303,9 +370,19 @@ mtree_quote(struct archive_string *s, const char *str)
 static void
 mtree_indent(struct mtree_writer *mtree)
 {
-	int i, fn;
+	int i, fn, nd, pd;
 	const char *r, *s, *x;
 
+	if (mtree->classic) {
+		if (mtree->indent) {
+			nd = 0;
+			pd = mtree->depth * 4;
+		} else {
+			nd = mtree->depth?4:0;
+			pd = 0;
+		}
+	} else
+		nd = pd = 0;
 	fn = 1;
 	s = r = mtree->ebuf.s;
 	x = NULL;
@@ -314,37 +391,46 @@ mtree_indent(struct mtree_writer *mtree)
 	while ((r = strchr(r, ' ')) != NULL) {
 		if (fn) {
 			fn = 0;
+			for (i = 0; i < nd + pd; i++)
+				archive_strappend_char(&mtree->buf, ' ');
 			archive_strncat(&mtree->buf, s, r - s);
-			if (r -s > INDENTNAMELEN) {
+			if (nd + (r -s) > INDENTNAMELEN) {
 				archive_strncat(&mtree->buf, " \\\n", 3);
-				for (i = 0; i < (INDENTNAMELEN + 1); i++)
+				for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
 					archive_strappend_char(&mtree->buf, ' ');
 			} else {
-				for (i = r -s; i < (INDENTNAMELEN + 1); i++)
+				for (i = (int)(r -s + nd);
+				    i < (INDENTNAMELEN + 1); i++)
 					archive_strappend_char(&mtree->buf, ' ');
 			}
 			s = ++r;
 			x = NULL;
 			continue;
 		}
-		if (r - s <= MAXLINELEN - 3 - INDENTNAMELEN)
+		if (pd + (r - s) <= MAXLINELEN - 3 - INDENTNAMELEN)
 			x = r++;
 		else {
 			if (x == NULL)
 				x = r;
 			archive_strncat(&mtree->buf, s, x - s);
 			archive_strncat(&mtree->buf, " \\\n", 3);
-			for (i = 0; i < (INDENTNAMELEN + 1); i++)
+			for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
 				archive_strappend_char(&mtree->buf, ' ');
 			s = r = ++x;
 			x = NULL;
 		}
 	}
-	if (x != NULL && strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) {
+	if (fn) {
+		for (i = 0; i < nd + pd; i++)
+			archive_strappend_char(&mtree->buf, ' ');
+		archive_strcat(&mtree->buf, s);
+		s += strlen(s);
+	}
+	if (x != NULL && pd + strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) {
 		/* Last keyword is longer. */
 		archive_strncat(&mtree->buf, s, x - s);
 		archive_strncat(&mtree->buf, " \\\n", 3);
-		for (i = 0; i < (INDENTNAMELEN + 1); i++)
+		for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
 			archive_strappend_char(&mtree->buf, ' ');
 		s = ++x;
 	}
@@ -352,163 +438,70 @@ mtree_indent(struct mtree_writer *mtree)
 	archive_string_empty(&mtree->ebuf);
 }
 
-#if !defined(_WIN32) || defined(__CYGWIN__)
-static size_t
-dir_len(struct mtree_entry *me)
-{
-	const char *path, *r;
-
-	path = me->pathname;
-	r = strrchr(path, '/');
-	if (r == NULL)
-		return (0);
-	/* Include a separator size */
-	return (r - path + 1);
-}
-
-#else /* _WIN32 && !__CYGWIN__ */
-/*
- * Note: We should use wide-character for findng '\' character,
- * a directory separator on Windows, because some character-set have
- * been using the '\' character for a part of its multibyte character
- * code.
- */
-static size_t
-dir_len(struct mtree_entry *me)
-{
-	wchar_t wc;
-	const char *path;
-	const char *p, *rp;
-	size_t al, l, size;
-
-	path = me->pathname;
-	al = l = -1;
-	for (p = path; *p != '\0'; ++p) {
-		if (*p == '\\')
-			al = l = p - path;
-		else if (*p == '/')
-			al = p - path;
-	}
-	if (l == -1)
-		goto alen;
-	size = p - path;
-	rp = p = path;
-	while (*p != '\0') {
-		l = mbtowc(&wc, p, size);
-		if (l == -1)
-			goto alen;
-		if (l == 1 && (wc == L'/' || wc == L'\\'))
-			rp = p;
-		p += l;
-		size -= l;
-	}
-	return (rp - path + 1);
-alen:
-	if (al == -1)
-		return (0);
-	return (al + 1);
-}
-#endif /* _WIN32 && !__CYGWIN__ */
-
-/*
- * Test if a parent directory of the current entry is changed.
- */
-static int
-parent_dir_changed(struct archive_string *dir, struct mtree_entry *me)
-{
-	const char *path;
-	size_t l;
-
-	l = dir_len(me);
-	path = me->pathname;
-	if (archive_strlen(dir) > 0) {
-		if (l == 0) {
-			archive_string_empty(dir);
-			return (1);
-		}
-		if (strncmp(dir->s, path, l) == 0)
-			return (0); /* The parent directory is the same. */
-	} else if (l == 0)
-		return (0);	    /* The parent directory is the same. */
-	archive_strncpy(dir, path, l);
-	return (1);
-}
-
 /*
  * Write /set keyword.
  * Set most used value of uid,gid,mode and fflags, which are
- * collected by collect_set_values() function.
+ * collected by attr_counter_set_collect() function.
  */
 static void
 write_global(struct mtree_writer *mtree)
 {
 	struct archive_string setstr;
 	struct archive_string unsetstr;
-	const char *name;
+	struct att_counter_set *acs;
 	int keys, oldkeys, effkeys;
-	struct attr_counter *ac;
 
 	archive_string_init(&setstr);
 	archive_string_init(&unsetstr);
 	keys = mtree->keys & SET_KEYS;
 	oldkeys = mtree->set.keys;
 	effkeys = keys;
-	if (mtree->set.processed) {
+	acs = &mtree->acs;
+	if (mtree->set.processing) {
 		/*
 		 * Check if the global data needs updating.
 		 */
 		effkeys &= ~F_TYPE;
-		if (oldkeys & (F_UNAME | F_UID)) {
-			ac = mtree->set.uid_list;
-			do {
-				if (mtree->set.uid == ac->m_entry->uid) {
-					effkeys &= ~(F_UNAME | F_UID);
-					break;
-				}
-				if (ac->next != NULL &&
-				    ac->next->count == ac->count)
-					continue;
-			} while (0);
+		if (acs->uid_list == NULL)
+			effkeys &= ~(F_UNAME | F_UID);
+		else if (oldkeys & (F_UNAME | F_UID)) {
+			if (acs->uid_list->count < 2 ||
+			    mtree->set.uid == acs->uid_list->m_entry->uid)
+				effkeys &= ~(F_UNAME | F_UID);
 		}
-		if (oldkeys & (F_GNAME | F_GID)) {
-			ac = mtree->set.gid_list;
-			do {
-				if (mtree->set.gid == ac->m_entry->gid) {
-					effkeys &= ~(F_GNAME | F_GID);
-					break;
-				}
-				if (ac->next != NULL &&
-				    ac->next->count == ac->count)
-					continue;
-			} while (0);
+		if (acs->gid_list == NULL)
+			effkeys &= ~(F_GNAME | F_GID);
+		else if (oldkeys & (F_GNAME | F_GID)) {
+			if (acs->gid_list->count < 2 ||
+			    mtree->set.gid == acs->gid_list->m_entry->gid)
+				effkeys &= ~(F_GNAME | F_GID);
 		}
-		if (oldkeys & F_MODE) {
-			ac = mtree->set.mode_list;
-			do {
-				if (mtree->set.mode == ac->m_entry->mode) {
-					effkeys &= ~F_MODE;
-					break;
-				}
-				if (ac->next != NULL &&
-				    ac->next->count == ac->count)
-					continue;
-			} while (0);
+		if (acs->mode_list == NULL)
+			effkeys &= ~F_MODE;
+		else if (oldkeys & F_MODE) {
+			if (acs->mode_list->count < 2 ||
+			    mtree->set.mode == acs->mode_list->m_entry->mode)
+				effkeys &= ~F_MODE;
 		}
-		if ((oldkeys & F_FLAGS) != 0) {
-			ac = mtree->set.flags_list;
-			do {
-				if (ac->m_entry->fflags_set ==
-					mtree->set.fflags_set &&
-				    ac->m_entry->fflags_clear ==
-					mtree->set.fflags_clear) {
-					effkeys &= ~F_FLAGS;
-					break;
-				}
-				if (ac->next != NULL &&
-				    ac->next->count == ac->count)
-					continue;
-			} while (0);
+		if (acs->flags_list == NULL)
+			effkeys &= ~F_FLAGS;
+		else if ((oldkeys & F_FLAGS) != 0) {
+			if (acs->flags_list->count < 2 ||
+			    (acs->flags_list->m_entry->fflags_set ==
+				mtree->set.fflags_set &&
+			     acs->flags_list->m_entry->fflags_clear ==
+				mtree->set.fflags_clear))
+				effkeys &= ~F_FLAGS;
 		}
+	} else {
+		if (acs->uid_list == NULL)
+			keys &= ~(F_UNAME | F_UID);
+		if (acs->gid_list == NULL)
+			keys &= ~(F_GNAME | F_GID);
+		if (acs->mode_list == NULL)
+			keys &= ~F_MODE;
+		if (acs->flags_list == NULL)
+			keys &= ~F_FLAGS;
 	}
 	if ((keys & effkeys & F_TYPE) != 0) {
 		if (mtree->dironly) {
@@ -520,10 +513,9 @@ write_global(struct mtree_writer *mtree)
 		}
 	}
 	if ((keys & effkeys & F_UNAME) != 0) {
-		name = mtree->set.uid_list->m_entry->uname;
-		if (name != NULL) {
+		if (archive_strlen(&(acs->uid_list->m_entry->uname)) > 0) {
 			archive_strcat(&setstr, " uname=");
-			mtree_quote(&setstr, name);
+			mtree_quote(&setstr, acs->uid_list->m_entry->uname.s);
 		} else {
 			keys &= ~F_UNAME;
 			if ((oldkeys & F_UNAME) != 0)
@@ -531,15 +523,14 @@ write_global(struct mtree_writer *mtree)
 		}
 	}
 	if ((keys & effkeys & F_UID) != 0) {
-		mtree->set.uid = mtree->set.uid_list->m_entry->uid;
+		mtree->set.uid = acs->uid_list->m_entry->uid;
 		archive_string_sprintf(&setstr, " uid=%jd",
 		    (intmax_t)mtree->set.uid);
 	}
 	if ((keys & effkeys & F_GNAME) != 0) {
-		name = mtree->set.gid_list->m_entry->gname;
-		if (name != NULL) {
+		if (archive_strlen(&(acs->gid_list->m_entry->gname)) > 0) {
 			archive_strcat(&setstr, " gname=");
-			mtree_quote(&setstr, name);
+			mtree_quote(&setstr, acs->gid_list->m_entry->gname.s);
 		} else {
 			keys &= ~F_GNAME;
 			if ((oldkeys & F_GNAME) != 0)
@@ -547,24 +538,25 @@ write_global(struct mtree_writer *mtree)
 		}
 	}
 	if ((keys & effkeys & F_GID) != 0) {
-		mtree->set.gid = mtree->set.gid_list->m_entry->gid;
+		mtree->set.gid = acs->gid_list->m_entry->gid;
 		archive_string_sprintf(&setstr, " gid=%jd",
 		    (intmax_t)mtree->set.gid);
 	}
 	if ((keys & effkeys & F_MODE) != 0) {
-		mtree->set.mode = mtree->set.mode_list->m_entry->mode;
+		mtree->set.mode = acs->mode_list->m_entry->mode;
 		archive_string_sprintf(&setstr, " mode=%o",
 		    (unsigned int)mtree->set.mode);
 	}
 	if ((keys & effkeys & F_FLAGS) != 0) {
-		name = mtree->set.flags_list->m_entry->fflags_text;
-		if (name != NULL) {
+		if (archive_strlen(
+		    &(acs->flags_list->m_entry->fflags_text)) > 0) {
 			archive_strcat(&setstr, " flags=");
-			mtree_quote(&setstr, name);
+			mtree_quote(&setstr,
+			    acs->flags_list->m_entry->fflags_text.s);
 			mtree->set.fflags_set =
-			    mtree->set.flags_list->m_entry->fflags_set;
+			    acs->flags_list->m_entry->fflags_set;
 			mtree->set.fflags_clear =
-			    mtree->set.flags_list->m_entry->fflags_clear;
+			    acs->flags_list->m_entry->fflags_clear;
 		} else {
 			keys &= ~F_FLAGS;
 			if ((oldkeys & F_FLAGS) != 0)
@@ -578,16 +570,11 @@ write_global(struct mtree_writer *mtree)
 		archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s);
 	archive_string_free(&setstr);
 	mtree->set.keys = keys;
-	mtree->set.processed = 1;
-
-	free_attr_count(&mtree->set.uid_list);
-	free_attr_count(&mtree->set.gid_list);
-	free_attr_count(&mtree->set.mode_list);
-	free_attr_count(&mtree->set.flags_list);
+	mtree->set.processing = 1;
 }
 
 static struct attr_counter *
-new_attr_count(struct mtree_entry *me, struct attr_counter *prev)
+attr_counter_new(struct mtree_entry *me, struct attr_counter *prev)
 {
 	struct attr_counter *ac;
 
@@ -602,7 +589,7 @@ new_attr_count(struct mtree_entry *me, struct attr_counter *prev)
 }
 
 static void
-free_attr_count(struct attr_counter **top)
+attr_counter_free(struct attr_counter **top)
 {
 	struct attr_counter *ac, *tac;
 
@@ -618,7 +605,7 @@ free_attr_count(struct attr_counter **top)
 }
 
 static int
-inc_attr_count(struct attr_counter **top, struct attr_counter *ac,
+attr_counter_inc(struct attr_counter **top, struct attr_counter *ac,
     struct attr_counter *last, struct mtree_entry *me)
 {
 	struct attr_counter *pac;
@@ -647,7 +634,7 @@ inc_attr_count(struct attr_counter **top, struct attr_counter *ac,
 			ac->next->prev = ac;
 		}
 	} else {
-		ac = new_attr_count(me, last);
+		ac = attr_counter_new(me, last);
 		if (ac == NULL)
 			return (-1);
 		last->next = ac;
@@ -655,93 +642,99 @@ inc_attr_count(struct attr_counter **top, struct attr_counter *ac,
 	return (0);
 }
 
+/*
+ * Tabulate uid,gid,mode and fflags of a entry in order to be used for /set.
+ */
 static int
-collect_set_values(struct mtree_writer *mtree, struct mtree_entry *me)
+attr_counter_set_collect(struct mtree_writer *mtree, struct mtree_entry *me)
 {
-	int keys = mtree->keys;
 	struct attr_counter *ac, *last;
+	struct att_counter_set *acs = &mtree->acs;
+	int keys = mtree->keys;
 
 	if (keys & (F_UNAME | F_UID)) {
-		if (mtree->set.uid_list == NULL) {
-			mtree->set.uid_list = new_attr_count(me, NULL);
-			if (mtree->set.uid_list == NULL)
+		if (acs->uid_list == NULL) {
+			acs->uid_list = attr_counter_new(me, NULL);
+			if (acs->uid_list == NULL)
 				return (-1);
 		} else {
 			last = NULL;
-			for (ac = mtree->set.uid_list; ac; ac = ac->next) {
+			for (ac = acs->uid_list; ac; ac = ac->next) {
 				if (ac->m_entry->uid == me->uid)
 					break;
 				last = ac;
 			}
-			if (inc_attr_count(
-			    &mtree->set.uid_list, ac, last, me) < 0)
+			if (attr_counter_inc(&acs->uid_list, ac, last, me) < 0)
 				return (-1);
 		}
 	}
 	if (keys & (F_GNAME | F_GID)) {
-		if (mtree->set.gid_list == NULL) {
-			mtree->set.gid_list = new_attr_count(me, NULL);
-			if (mtree->set.gid_list == NULL)
+		if (acs->gid_list == NULL) {
+			acs->gid_list = attr_counter_new(me, NULL);
+			if (acs->gid_list == NULL)
 				return (-1);
 		} else {
 			last = NULL;
-			for (ac = mtree->set.gid_list; ac; ac = ac->next) {
+			for (ac = acs->gid_list; ac; ac = ac->next) {
 				if (ac->m_entry->gid == me->gid)
 					break;
 				last = ac;
 			}
-			if (inc_attr_count(
-			    &mtree->set.gid_list, ac, last, me) < 0)
+			if (attr_counter_inc(&acs->gid_list, ac, last, me) < 0)
 				return (-1);
 		}
 	}
 	if (keys & F_MODE) {
-		if (mtree->set.mode_list == NULL) {
-			mtree->set.mode_list = new_attr_count(me, NULL);
-			if (mtree->set.mode_list == NULL)
+		if (acs->mode_list == NULL) {
+			acs->mode_list = attr_counter_new(me, NULL);
+			if (acs->mode_list == NULL)
 				return (-1);
 		} else {
 			last = NULL;
-			for (ac = mtree->set.mode_list; ac; ac = ac->next) {
+			for (ac = acs->mode_list; ac; ac = ac->next) {
 				if (ac->m_entry->mode == me->mode)
 					break;
 				last = ac;
 			}
-			if (inc_attr_count(
-			    &mtree->set.mode_list, ac, last, me) < 0)
+			if (attr_counter_inc(&acs->mode_list, ac, last, me) < 0)
 				return (-1);
 		}
 	}
 	if (keys & F_FLAGS) {
-		if (mtree->set.flags_list == NULL) {
-			mtree->set.flags_list = new_attr_count(me, NULL);
-			if (mtree->set.flags_list == NULL)
+		if (acs->flags_list == NULL) {
+			acs->flags_list = attr_counter_new(me, NULL);
+			if (acs->flags_list == NULL)
 				return (-1);
 		} else {
 			last = NULL;
-			for (ac = mtree->set.flags_list; ac; ac = ac->next) {
+			for (ac = acs->flags_list; ac; ac = ac->next) {
 				if (ac->m_entry->fflags_set == me->fflags_set &&
-				    ac->m_entry->fflags_clear == me->fflags_clear)
+				    ac->m_entry->fflags_clear ==
+							me->fflags_clear)
 					break;
 				last = ac;
 			}
-			if (inc_attr_count(
-			    &mtree->set.flags_list, ac, last, me) < 0)
+			if (attr_counter_inc(&acs->flags_list, ac, last, me) < 0)
 				return (-1);
 		}
 	}
 
-	/*
-	 * Save a entry.
-	 */
-	me->next = NULL;
-	*mtree->set.me_last = me;
-	mtree->set.me_last = &me->next;
 	return (0);
 }
 
+static void
+attr_counter_set_free(struct mtree_writer *mtree)
+{
+	struct att_counter_set *acs = &mtree->acs;
+
+	attr_counter_free(&acs->uid_list);
+	attr_counter_free(&acs->gid_list);
+	attr_counter_free(&acs->mode_list);
+	attr_counter_free(&acs->flags_list);
+}
+
 static int
-get_keys(struct mtree_writer *mtree, struct mtree_entry *me)
+get_global_set_keys(struct mtree_writer *mtree, struct mtree_entry *me)
 {
 	int keys;
 
@@ -788,56 +781,92 @@ get_keys(struct mtree_writer *mtree, struct mtree_entry *me)
 	return (keys);
 }
 
-static struct mtree_entry *
-new_mtree_entry(struct archive_entry *entry)
+static int
+mtree_entry_new(struct archive_write *a, struct archive_entry *entry,
+    struct mtree_entry **m_entry)
 {
 	struct mtree_entry *me;
 	const char *s;
+	int r;
+	static const struct archive_rb_tree_ops rb_ops = {
+		mtree_entry_cmp_node, mtree_entry_cmp_key
+	};
 
 	me = calloc(1, sizeof(*me));
-	if (me == NULL)
-		return (NULL);
-	me->pathname = strdup(archive_entry_pathname(entry));
+	if (me == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate memory for a mtree entry");
+		*m_entry = NULL;
+		return (ARCHIVE_FATAL);
+	}
+
+	r = mtree_entry_setup_filenames(a, me, entry);
+	if (r < ARCHIVE_WARN) {
+		mtree_entry_free(me);
+		*m_entry = NULL;
+		return (r);
+	}
+
 	if ((s = archive_entry_symlink(entry)) != NULL)
-		me->symlink = strdup(s);
-	else
-		me->symlink = NULL;
+		archive_strcpy(&me->symlink, s);
 	me->nlink = archive_entry_nlink(entry);
 	me->filetype = archive_entry_filetype(entry);
 	me->mode = archive_entry_mode(entry) & 07777;
 	me->uid = archive_entry_uid(entry);
 	me->gid = archive_entry_gid(entry);
 	if ((s = archive_entry_uname(entry)) != NULL)
-		me->uname = strdup(s);
-	else
-		me->uname = NULL;
+		archive_strcpy(&me->uname, s);
 	if ((s = archive_entry_gname(entry)) != NULL)
-		me->gname = strdup(s);
-	else
-		me->gname = NULL;
+		archive_strcpy(&me->gname, s);
 	if ((s = archive_entry_fflags_text(entry)) != NULL)
-		me->fflags_text = strdup(s);
-	else
-		me->fflags_text = NULL;
+		archive_strcpy(&me->fflags_text, s);
 	archive_entry_fflags(entry, &me->fflags_set, &me->fflags_clear);
 	me->mtime = archive_entry_mtime(entry);
 	me->mtime_nsec = archive_entry_mtime_nsec(entry);
 	me->rdevmajor =	archive_entry_rdevmajor(entry);
 	me->rdevminor = archive_entry_rdevminor(entry);
 	me->size = archive_entry_size(entry);
-	me->compute_sum = 0;
+	if (me->filetype == AE_IFDIR) {
+		me->dir_info = calloc(1, sizeof(*me->dir_info));
+		if (me->dir_info == NULL) {
+			mtree_entry_free(me);
+			archive_set_error(&a->archive, ENOMEM,
+			    "Can't allocate memory for a mtree entry");
+			*m_entry = NULL;
+			return (ARCHIVE_FATAL);
+		}
+		__archive_rb_tree_init(&me->dir_info->rbtree, &rb_ops);
+		me->dir_info->children.first = NULL;
+		me->dir_info->children.last = &(me->dir_info->children.first);
+		me->dir_info->chnext = NULL;
+	} else if (me->filetype == AE_IFREG) {
+		me->reg_info = calloc(1, sizeof(*me->reg_info));
+		if (me->reg_info == NULL) {
+			mtree_entry_free(me);
+			archive_set_error(&a->archive, ENOMEM,
+			    "Can't allocate memory for a mtree entry");
+			*m_entry = NULL;
+			return (ARCHIVE_FATAL);
+		}
+		me->reg_info->compute_sum = 0;
+	}
 
-	return (me);
+	*m_entry = me;
+	return (ARCHIVE_OK);
 }
 
 static void
-free_mtree_entry(struct mtree_entry *me)
+mtree_entry_free(struct mtree_entry *me)
 {
-	free(me->pathname);
-	free(me->symlink);
-	free(me->uname);
-	free(me->gname);
-	free(me->fflags_text);
+	archive_string_free(&me->parentdir);
+	archive_string_free(&me->basename);
+	archive_string_free(&me->pathname);
+	archive_string_free(&me->symlink);
+	archive_string_free(&me->uname);
+	archive_string_free(&me->gname);
+	archive_string_free(&me->fflags_text);
+	free(me->dir_info);
+	free(me->reg_info);
 	free(me);
 }
 
@@ -846,66 +875,100 @@ archive_write_mtree_header(struct archive_write *a,
     struct archive_entry *entry)
 {
 	struct mtree_writer *mtree= a->format_data;
+	struct mtree_entry *mtree_entry;
+	int r, r2;
 
 	if (mtree->first) {
 		mtree->first = 0;
 		archive_strcat(&mtree->buf, "#mtree\n");
 		if ((mtree->keys & SET_KEYS) == 0)
-			mtree->set.output = 0;/* Disalbed. */
+			mtree->output_global_set = 0;/* Disalbed. */
 	}
 
 	mtree->entry_bytes_remaining = archive_entry_size(entry);
+
+	/* While directory only mode, we do not handle non directory files. */
 	if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR)
 		return (ARCHIVE_OK);
 
-	mtree->mtree_entry = new_mtree_entry(entry);
-	if (mtree->mtree_entry == NULL) {
-		archive_set_error(&a->archive, ENOMEM,
-		    "Can't allocate mtree entry");
-		return (ARCHIVE_FATAL);
+	r2 = mtree_entry_new(a, entry, &mtree_entry);
+	if (r2 < ARCHIVE_WARN)
+		return (r2);
+	r = mtree_entry_tree_add(a, &mtree_entry);
+	if (r < ARCHIVE_WARN) {
+		mtree_entry_free(mtree_entry);
+		return (r);
 	}
+	mtree->mtree_entry = mtree_entry;
 
-	mtree->compute_sum = 0;
-
-	/* If current file is not a regular file, we do not have to
-	 * compute the sum of its content. */ 
-	if (archive_entry_filetype(entry) != AE_IFREG)
-		return (ARCHIVE_OK);
-		
-	/* Initialize a bunch of sum check context. */
-	sum_init(mtree);
+	/* If the current file is a regular file, we have to
+	 * compute the sum of its content.
+	 * Initialize a bunch of sum check context. */
+	if (mtree_entry->reg_info)
+		sum_init(mtree);
 
-	return (ARCHIVE_OK);
+	return (r2);
 }
 
 static int
-write_entry(struct archive_write *a, struct mtree_entry *me)
+write_mtree_entry(struct archive_write *a, struct mtree_entry *me)
 {
 	struct mtree_writer *mtree = a->format_data;
 	struct archive_string *str;
 	int keys, ret;
 
+	if (me->dir_info) {
+		if (mtree->classic) {
+			/*
+			 * Output a comment line to describe the full
+			 * pathname of the entry as mtree utility does
+			 * while generating classic format.
+			 */
+			if (!mtree->dironly)
+				archive_strappend_char(&mtree->buf, '\n');
+			if (me->parentdir.s)
+				archive_string_sprintf(&mtree->buf,
+				    "# %s/%s\n",
+				    me->parentdir.s, me->basename.s);
+			else
+				archive_string_sprintf(&mtree->buf,
+				    "# %s\n",
+				    me->basename.s);
+		}
+		if (mtree->output_global_set)
+			write_global(mtree);
+	}
 	archive_string_empty(&mtree->ebuf);
-	str = (mtree->indent)? &mtree->ebuf : &mtree->buf;
-	mtree_quote(str, me->pathname);
-	keys = get_keys(mtree, me);
+	str = (mtree->indent || mtree->classic)? &mtree->ebuf : &mtree->buf;
+
+	if (!mtree->classic && me->parentdir.s) {
+		/*
+		 * If generating format is not classic one(v1), output
+		 * a full pathname.
+		 */
+		mtree_quote(str, me->parentdir.s);
+		archive_strappend_char(str, '/');
+	}
+	mtree_quote(str, me->basename.s);
+
+	keys = get_global_set_keys(mtree, me);
 	if ((keys & F_NLINK) != 0 &&
 	    me->nlink != 1 && me->filetype != AE_IFDIR)
 		archive_string_sprintf(str, " nlink=%u", me->nlink);
 
-	if ((keys & F_GNAME) != 0 && me->gname != NULL) {
+	if ((keys & F_GNAME) != 0 && archive_strlen(&me->gname) > 0) {
 		archive_strcat(str, " gname=");
-		mtree_quote(str, me->gname);
+		mtree_quote(str, me->gname.s);
 	}
-	if ((keys & F_UNAME) != 0 && me->uname != NULL) {
+	if ((keys & F_UNAME) != 0 && archive_strlen(&me->uname) > 0) {
 		archive_strcat(str, " uname=");
-		mtree_quote(str, me->uname);
+		mtree_quote(str, me->uname.s);
 	}
 	if ((keys & F_FLAGS) != 0) {
-		if (me->fflags_text != NULL) {
+		if (archive_strlen(&me->fflags_text) > 0) {
 			archive_strcat(str, " flags=");
-			mtree_quote(str, me->fflags_text);
-		} else if (mtree->set.processed &&
+			mtree_quote(str, me->fflags_text.s);
+		} else if (mtree->set.processing &&
 		    (mtree->set.keys & F_FLAGS) != 0)
 			/* Overwrite the global parameter. */
 			archive_strcat(str, " flags=none");
@@ -926,7 +989,7 @@ write_entry(struct archive_write *a, struct mtree_entry *me)
 			archive_strcat(str, " type=link");
 		if ((keys & F_SLINK) != 0) {
 			archive_strcat(str, " link=");
-			mtree_quote(str, me->symlink);
+			mtree_quote(str, me->symlink.s);
 		}
 		break;
 	case AE_IFSOCK:
@@ -972,15 +1035,48 @@ write_entry(struct archive_write *a, struct mtree_entry *me)
 	}
 
 	/* Write a bunch of sum. */
-	if (me->filetype == AE_IFREG)
-		sum_write(str, me);
+	if (me->reg_info)
+		sum_write(str, me->reg_info);
+
+	archive_strappend_char(str, '\n');
+	if (mtree->indent || mtree->classic)
+		mtree_indent(mtree);
+
+	if (mtree->buf.length > 32768) {
+		ret = __archive_write_output(
+			a, mtree->buf.s, mtree->buf.length);
+		archive_string_empty(&mtree->buf);
+	} else
+		ret = ARCHIVE_OK;
+	return (ret);
+}
 
-	archive_strcat(str, "\n");
-	if (mtree->indent)
+static int
+write_dot_dot_entry(struct archive_write *a, struct mtree_entry *n)
+{
+	struct mtree_writer *mtree = a->format_data;
+	int ret;
+
+	if (n->parentdir.s) {
+		if (mtree->indent) {
+			int i, pd = mtree->depth * 4;
+			for (i = 0; i < pd; i++)
+				archive_strappend_char(&mtree->buf, ' ');
+		}
+		archive_string_sprintf(&mtree->buf, "# %s/%s\n",
+			n->parentdir.s, n->basename.s);
+	}
+
+	if (mtree->indent) {
+		archive_string_empty(&mtree->ebuf);
+		archive_strncat(&mtree->ebuf, "..\n\n", (mtree->dironly)?3:4);
 		mtree_indent(mtree);
+	} else
+		archive_strncat(&mtree->buf, "..\n\n", (mtree->dironly)?3:4);
 
 	if (mtree->buf.length > 32768) {
-		ret = __archive_write_output(a, mtree->buf.s, mtree->buf.length);
+		ret = __archive_write_output(
+			a, mtree->buf.s, mtree->buf.length);
 		archive_string_empty(&mtree->buf);
 	} else
 		ret = ARCHIVE_OK;
@@ -988,29 +1084,106 @@ write_entry(struct archive_write *a, struct mtree_entry *me)
 }
 
 /*
- * Write mtree entries saved at collect_set_values() function.
+ * Write mtree entries saved at attr_counter_set_collect() function.
  */
 static int
-write_mtree_entries(struct archive_write *a)
+write_mtree_entry_tree(struct archive_write *a)
 {
 	struct mtree_writer *mtree = a->format_data;
-	struct mtree_entry *me, *tme;
+	struct mtree_entry *np = mtree->root;
+	struct archive_rb_node *n;
 	int ret;
 
-	for (me = mtree->set.me_first; me; me = me->next) {
-		ret = write_entry(a, me);
-		if (ret != ARCHIVE_OK)
-			return (ARCHIVE_FATAL);
-	}
+	do {
+		if (mtree->output_global_set) {
+			/*
+			 * Collect attribute infomation to know which value
+			 * is frequently used among the children.
+			 */
+			attr_counter_set_reset(mtree);
+			ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) {
+				struct mtree_entry *e = (struct mtree_entry *)n;
+				if (attr_counter_set_collect(mtree, e) < 0) {
+					archive_set_error(&a->archive, ENOMEM,
+					    "Can't allocate memory");
+					return (ARCHIVE_FATAL);
+				}
+			}
+		}
+		if (!np->dir_info->virtual || mtree->classic) {
+			ret = write_mtree_entry(a, np);
+			if (ret != ARCHIVE_OK)
+				return (ARCHIVE_FATAL);
+		} else {
+			/* Whenever output_global_set is enabled
+			 * output global value(/set keywords)
+			 * even if the directory entry is not allowd
+			 * to be written because the global values
+			 * can be used for the children. */
+			if (mtree->output_global_set)
+				write_global(mtree);
+		}
+		/*
+		 * Output the attribute of all files except directory files.
+		 */
+		mtree->depth++;
+		ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) {
+			struct mtree_entry *e = (struct mtree_entry *)n;
+
+			if (e->dir_info)
+				mtree_entry_add_child_tail(np, e);
+			else {
+				ret = write_mtree_entry(a, e);
+				if (ret != ARCHIVE_OK)
+					return (ARCHIVE_FATAL);
+			}
+		}
+		mtree->depth--;
+
+		if (np->dir_info->children.first != NULL) {
+			/*
+			 * Descend the tree.
+			 */
+			np = np->dir_info->children.first;
+			if (mtree->indent)
+				mtree->depth++;
+			continue;
+		} else if (mtree->classic) {
+			/*
+			 * While printing mtree classic, if there are not
+			 * any directory files(except "." and "..") in the
+			 * directory, output two dots ".." as returning
+			 * the parent directory.
+			 */
+			ret = write_dot_dot_entry(a, np);
+			if (ret != ARCHIVE_OK)
+				return (ARCHIVE_FATAL);
+		}
+
+		while (np != np->parent) {
+			if (np->dir_info->chnext == NULL) {
+				/*
+				 * Ascend the tree; go back to the parent.
+				 */
+				if (mtree->indent)
+					mtree->depth--;
+				if (mtree->classic) {
+					ret = write_dot_dot_entry(a,
+						np->parent);
+					if (ret != ARCHIVE_OK)
+						return (ARCHIVE_FATAL);
+				}
+				np = np->parent;
+			} else {
+				/*
+				 * Switch to next mtree entry in the directory.
+				 */
+				np = np->dir_info->chnext;
+				break;
+			}
+		}
+	} while (np != np->parent); 
 
-	me = mtree->set.me_first;
-	while (me != NULL) {
-		tme = me->next;
-		free_mtree_entry(me);
-		me = tme;
-	}
-	mtree->set.me_first = NULL;
-	mtree->set.me_last = &mtree->set.me_first;
 	return (ARCHIVE_OK);
 }
 
@@ -1019,40 +1192,15 @@ archive_write_mtree_finish_entry(struct archive_write *a)
 {
 	struct mtree_writer *mtree = a->format_data;
 	struct mtree_entry *me;
-	int ret;
 
 	if ((me = mtree->mtree_entry) == NULL)
 		return (ARCHIVE_OK);
 	mtree->mtree_entry = NULL;
 
-	if (me->filetype == AE_IFREG)
-		sum_final(mtree, me);
+	if (me->reg_info)
+		sum_final(mtree, me->reg_info);
 
-	if (mtree->set.output) {
-		if (!mtree->dironly) {
-			if (archive_strlen(&mtree->set.parent) == 0)
-				parent_dir_changed(&mtree->set.parent, me);
-			if (parent_dir_changed(&mtree->set.parent, me)) {
-				/* Write /set keyword */
-				write_global(mtree);
-				/* Write entries saved by
-				 * collect_set_values() function. */
-				ret = write_mtree_entries(a);
-				if (ret != ARCHIVE_OK)
-					return (ARCHIVE_FATAL);
-			}
-		}
-		/* Tabulate uid,gid,mode and fflags of a entry
-		 * in order to be used for /set. and, at this time
-		 * we do not write a entry.  */
-		collect_set_values(mtree, me);
-		return (ARCHIVE_OK);
-	} else {
-		/* Write the current entry and free it. */
-		ret = write_entry(a, me);
-		free_mtree_entry(me);
-	}
-	return (ret == ARCHIVE_OK ? ret : ARCHIVE_FATAL);
+	return (ARCHIVE_OK);
 }
 
 static int
@@ -1061,9 +1209,8 @@ archive_write_mtree_close(struct archive_write *a)
 	struct mtree_writer *mtree= a->format_data;
 	int ret;
 
-	if (mtree->set.output && mtree->set.me_first != NULL) {
-		write_global(mtree);
-		ret = write_mtree_entries(a);
+	if (mtree->root != NULL) {
+		ret = write_mtree_entry_tree(a);
 		if (ret != ARCHIVE_OK)
 			return (ARCHIVE_FATAL);
 	}
@@ -1079,7 +1226,7 @@ archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
 	struct mtree_writer *mtree= a->format_data;
 
 	if (n > mtree->entry_bytes_remaining)
-		n = mtree->entry_bytes_remaining;
+		n = (size_t)mtree->entry_bytes_remaining;
 	mtree->entry_bytes_remaining -= n;
 
 	/* We don't need to compute a regular file sum */
@@ -1096,25 +1243,16 @@ static int
 archive_write_mtree_free(struct archive_write *a)
 {
 	struct mtree_writer *mtree= a->format_data;
-	struct mtree_entry *me, *tme;
 
 	if (mtree == NULL)
 		return (ARCHIVE_OK);
 
 	/* Make sure we dot not leave any entries. */
-	me = mtree->set.me_first;
-	while (me != NULL) {
-		tme = me->next;
-		free_mtree_entry(me);
-		me = tme;
-	}
+	mtree_entry_register_free(mtree);
+	archive_string_free(&mtree->cur_dirstr);
 	archive_string_free(&mtree->ebuf);
 	archive_string_free(&mtree->buf);
-	archive_string_free(&mtree->set.parent);
-	free_attr_count(&mtree->set.uid_list);
-	free_attr_count(&mtree->set.gid_list);
-	free_attr_count(&mtree->set.mode_list);
-	free_attr_count(&mtree->set.flags_list);
+	attr_counter_set_free(mtree);
 	free(mtree);
 	a->format_data = NULL;
 	return (ARCHIVE_OK);
@@ -1209,7 +1347,7 @@ archive_write_mtree_options(struct archive_write *a, const char *key,
 		else if (strcmp(key, "uname") == 0)
 			keybit = F_UNAME;
 		else if (strcmp(key, "use-set") == 0) {
-			mtree->set.output = (value != NULL)? 1: 0;
+			mtree->output_global_set = (value != NULL)? 1: 0;
 			return (ARCHIVE_OK);
 		}
 		break;
@@ -1222,17 +1360,19 @@ archive_write_mtree_options(struct archive_write *a, const char *key,
 		return (ARCHIVE_OK);
 	}
 
-	return (ARCHIVE_FAILED);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
-int
-archive_write_set_format_mtree(struct archive *_a)
+static int
+archive_write_set_format_mtree_default(struct archive *_a, const char *fn)
 {
 	struct archive_write *a = (struct archive_write *)_a;
 	struct mtree_writer *mtree;
 
-	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
-	    ARCHIVE_STATE_NEW, "archive_write_set_format_mtree");
+	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, fn);
 
 	if (a->format_free != NULL)
 		(a->format_free)(a);
@@ -1246,14 +1386,12 @@ archive_write_set_format_mtree(struct archive *_a)
 	mtree->mtree_entry = NULL;
 	mtree->first = 1;
 	memset(&(mtree->set), 0, sizeof(mtree->set));
-	archive_string_init(&mtree->set.parent);
 	mtree->keys = DEFAULT_KEYS;
 	mtree->dironly = 0;
 	mtree->indent = 0;
 	archive_string_init(&mtree->ebuf);
 	archive_string_init(&mtree->buf);
-	mtree->set.me_first = NULL;
-	mtree->set.me_last = &mtree->set.me_first;
+	mtree_entry_register_init(mtree);
 	a->format_data = mtree;
 	a->format_free = archive_write_mtree_free;
 	a->format_name = "mtree";
@@ -1268,9 +1406,41 @@ archive_write_set_format_mtree(struct archive *_a)
 	return (ARCHIVE_OK);
 }
 
+int
+archive_write_set_format_mtree(struct archive *_a)
+{
+	return archive_write_set_format_mtree_default(_a,
+		"archive_write_set_format_mtree");
+}
+
+int
+archive_write_set_format_mtree_classic(struct archive *_a)
+{
+	int r;
+
+	r = archive_write_set_format_mtree_default(_a,
+		"archive_write_set_format_mtree_classic");
+	if (r == ARCHIVE_OK) {
+		struct archive_write *a = (struct archive_write *)_a;
+		struct mtree_writer *mtree;
+
+		mtree = (struct mtree_writer *)a->format_data;
+
+		/* Set to output a mtree archive in classic format. */
+		mtree->classic = 1;
+		/* Basically, mtree classic format uses '/set' global
+		 * value. */
+		mtree->output_global_set = 1;
+	}
+	return (r);
+}
+
 static void
 sum_init(struct mtree_writer *mtree)
 {
+
+	mtree->compute_sum = 0;
+
 	if (mtree->keys & F_CKSUM) {
 		mtree->compute_sum |= F_CKSUM;
 		mtree->crc = 0;
@@ -1367,7 +1537,7 @@ sum_update(struct mtree_writer *mtree, const void *buff, size_t n)
 }
 
 static void
-sum_final(struct mtree_writer *mtree, struct mtree_entry *me)
+sum_final(struct mtree_writer *mtree, struct reg_info *reg)
 {
 
 	if (mtree->compute_sum & F_CKSUM) {
@@ -1375,34 +1545,34 @@ sum_final(struct mtree_writer *mtree, struct mtree_entry *me)
 		/* Include the length of the file. */
 		for (len = mtree->crc_len; len != 0; len >>= 8)
 			COMPUTE_CRC(mtree->crc, len & 0xff);
-		me->crc = ~mtree->crc;
+		reg->crc = ~mtree->crc;
 	}
 #ifdef ARCHIVE_HAS_MD5
 	if (mtree->compute_sum & F_MD5)
-		archive_md5_final(&mtree->md5ctx, me->buf_md5);
+		archive_md5_final(&mtree->md5ctx, reg->buf_md5);
 #endif
 #ifdef ARCHIVE_HAS_RMD160
 	if (mtree->compute_sum & F_RMD160)
-		archive_rmd160_final(&mtree->rmd160ctx, me->buf_rmd160);
+		archive_rmd160_final(&mtree->rmd160ctx, reg->buf_rmd160);
 #endif
 #ifdef ARCHIVE_HAS_SHA1
 	if (mtree->compute_sum & F_SHA1)
-		archive_sha1_final(&mtree->sha1ctx, me->buf_sha1);
+		archive_sha1_final(&mtree->sha1ctx, reg->buf_sha1);
 #endif
 #ifdef ARCHIVE_HAS_SHA256
 	if (mtree->compute_sum & F_SHA256)
-		archive_sha256_final(&mtree->sha256ctx, me->buf_sha256);
+		archive_sha256_final(&mtree->sha256ctx, reg->buf_sha256);
 #endif
 #ifdef ARCHIVE_HAS_SHA384
 	if (mtree->compute_sum & F_SHA384)
-		archive_sha384_final(&mtree->sha384ctx, me->buf_sha384);
+		archive_sha384_final(&mtree->sha384ctx, reg->buf_sha384);
 #endif
 #ifdef ARCHIVE_HAS_SHA512
 	if (mtree->compute_sum & F_SHA512)
-		archive_sha512_final(&mtree->sha512ctx, me->buf_sha512);
+		archive_sha512_final(&mtree->sha512ctx, reg->buf_sha512);
 #endif
 	/* Save what types of sum are computed. */
-	me->compute_sum = mtree->compute_sum;
+	reg->compute_sum = mtree->compute_sum;
 }
 
 #if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \
@@ -1422,47 +1592,612 @@ strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
 #endif
 
 static void
-sum_write(struct archive_string *str, struct mtree_entry *me)
+sum_write(struct archive_string *str, struct reg_info *reg)
 {
 
-	if (me->compute_sum & F_CKSUM) {
+	if (reg->compute_sum & F_CKSUM) {
 		archive_string_sprintf(str, " cksum=%ju",
-		    (uintmax_t)me->crc);
+		    (uintmax_t)reg->crc);
 	}
 #ifdef ARCHIVE_HAS_MD5
-	if (me->compute_sum & F_MD5) {
+	if (reg->compute_sum & F_MD5) {
 		archive_strcat(str, " md5digest=");
-		strappend_bin(str, me->buf_md5, sizeof(me->buf_md5));
+		strappend_bin(str, reg->buf_md5, sizeof(reg->buf_md5));
 	}
 #endif
 #ifdef ARCHIVE_HAS_RMD160
-	if (me->compute_sum & F_RMD160) {
+	if (reg->compute_sum & F_RMD160) {
 		archive_strcat(str, " rmd160digest=");
-		strappend_bin(str, me->buf_rmd160, sizeof(me->buf_rmd160));
+		strappend_bin(str, reg->buf_rmd160, sizeof(reg->buf_rmd160));
 	}
 #endif
 #ifdef ARCHIVE_HAS_SHA1
-	if (me->compute_sum & F_SHA1) {
+	if (reg->compute_sum & F_SHA1) {
 		archive_strcat(str, " sha1digest=");
-		strappend_bin(str, me->buf_sha1, sizeof(me->buf_sha1));
+		strappend_bin(str, reg->buf_sha1, sizeof(reg->buf_sha1));
 	}
 #endif
 #ifdef ARCHIVE_HAS_SHA256
-	if (me->compute_sum & F_SHA256) {
+	if (reg->compute_sum & F_SHA256) {
 		archive_strcat(str, " sha256digest=");
-		strappend_bin(str, me->buf_sha256, sizeof(me->buf_sha256));
+		strappend_bin(str, reg->buf_sha256, sizeof(reg->buf_sha256));
 	}
 #endif
 #ifdef ARCHIVE_HAS_SHA384
-	if (me->compute_sum & F_SHA384) {
+	if (reg->compute_sum & F_SHA384) {
 		archive_strcat(str, " sha384digest=");
-		strappend_bin(str, me->buf_sha384, sizeof(me->buf_sha384));
+		strappend_bin(str, reg->buf_sha384, sizeof(reg->buf_sha384));
 	}
 #endif
 #ifdef ARCHIVE_HAS_SHA512
-	if (me->compute_sum & F_SHA512) {
+	if (reg->compute_sum & F_SHA512) {
 		archive_strcat(str, " sha512digest=");
-		strappend_bin(str, me->buf_sha512, sizeof(me->buf_sha512));
+		strappend_bin(str, reg->buf_sha512, sizeof(reg->buf_sha512));
+	}
+#endif
+}
+
+static int
+mtree_entry_cmp_node(const struct archive_rb_node *n1,
+    const struct archive_rb_node *n2)
+{
+	const struct mtree_entry *e1 = (const struct mtree_entry *)n1;
+	const struct mtree_entry *e2 = (const struct mtree_entry *)n2;
+
+	return (strcmp(e2->basename.s, e1->basename.s));
+}
+
+static int
+mtree_entry_cmp_key(const struct archive_rb_node *n, const void *key)
+{
+	const struct mtree_entry *e = (const struct mtree_entry *)n;
+
+	return (strcmp((const char *)key, e->basename.s));
+}
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+static int
+cleanup_backslash_1(char *p)
+{
+	int mb, dos;
+
+	mb = dos = 0;
+	while (*p) {
+		if (*(unsigned char *)p > 127)
+			mb = 1;
+		if (*p == '\\') {
+			/* If we have not met any multi-byte characters,
+			 * we can replace '\' with '/'. */
+			if (!mb)
+				*p = '/';
+			dos = 1;
+		}
+		p++;
+	}
+	if (!mb || !dos)
+		return (0);
+	return (-1);
+}
+
+static void
+cleanup_backslash_2(wchar_t *p)
+{
+
+	/* Convert a path-separator from '\' to  '/' */
+	while (*p != L'\0') {
+		if (*p == L'\\')
+			*p = L'/';
+		p++;
+	}
+}
+#endif
+
+/*
+ * Generate a parent directory name and a base name from a pathname.
+ */
+static int
+mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file,
+    struct archive_entry *entry)
+{
+	const char *pathname;
+	char *p, *dirname, *slash;
+	size_t len;
+	int ret = ARCHIVE_OK;
+
+	archive_strcpy(&file->pathname, archive_entry_pathname(entry));
+#if defined(_WIN32) || defined(__CYGWIN__)
+	/*
+	 * Convert a path-separator from '\' to  '/'
+	 */
+	if (cleanup_backslash_1(file->pathname.s) != 0) {
+		const wchar_t *wp = archive_entry_pathname_w(entry);
+		struct archive_wstring ws;
+
+		if (wp != NULL) {
+			int r;
+			archive_string_init(&ws);
+			archive_wstrcpy(&ws, wp);
+			cleanup_backslash_2(ws.s);
+			archive_string_empty(&(file->pathname));
+			r = archive_string_append_from_wcs(&(file->pathname),
+			    ws.s, ws.length);
+			archive_wstring_free(&ws);
+			if (r < 0 && errno == ENOMEM) {
+				archive_set_error(&a->archive, ENOMEM,
+				    "Can't allocate memory");
+				return (ARCHIVE_FATAL);
+			}
+		}
+	}
+#else
+	(void)a; /* UNUSED */
+#endif
+	pathname =  file->pathname.s;
+	if (strcmp(pathname, ".") == 0) {
+		archive_strcpy(&file->basename, ".");
+		return (ARCHIVE_OK);
+	}
+
+	archive_strcpy(&(file->parentdir), pathname);
+
+	len = file->parentdir.length;
+	p = dirname = file->parentdir.s;
+
+	/*
+	 * Remove leading '/' and '../' elements
+	 */
+	while (*p) {
+		if (p[0] == '/') {
+			p++;
+			len--;
+		} else if (p[0] != '.')
+			break;
+		else if (p[1] == '.' && p[2] == '/') {
+			p += 3;
+			len -= 3;
+		} else
+			break;
+	}
+	if (p != dirname) {
+		memmove(dirname, p, len+1);
+		p = dirname;
+	}
+	/*
+	 * Remove "/","/." and "/.." elements from tail.
+	 */
+	while (len > 0) {
+		size_t ll = len;
+
+		if (len > 0 && p[len-1] == '/') {
+			p[len-1] = '\0';
+			len--;
+		}
+		if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
+			p[len-2] = '\0';
+			len -= 2;
+		}
+		if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
+		    p[len-1] == '.') {
+			p[len-3] = '\0';
+			len -= 3;
+		}
+		if (ll == len)
+			break;
+	}
+	while (*p) {
+		if (p[0] == '/') {
+			if (p[1] == '/')
+				/* Convert '//' --> '/' */
+				strcpy(p, p+1);
+			else if (p[1] == '.' && p[2] == '/')
+				/* Convert '/./' --> '/' */
+				strcpy(p, p+2);
+			else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
+				/* Convert 'dir/dir1/../dir2/'
+				 *     --> 'dir/dir2/'
+				 */
+				char *rp = p -1;
+				while (rp >= dirname) {
+					if (*rp == '/')
+						break;
+					--rp;
+				}
+				if (rp > dirname) {
+					strcpy(rp, p+3);
+					p = rp;
+				} else {
+					strcpy(dirname, p+4);
+					p = dirname;
+				}
+			} else
+				p++;
+		} else
+			p++;
+	}
+	p = dirname;
+	len = strlen(p);
+
+	/*
+	 * Add "./" prefiex.
+	 * NOTE: If the pathname does not have a path separator, we have
+	 * to add "./" to the head of the pathename because mtree reader
+	 * will suppose that it is v1(a.k.a classic) mtree format and
+	 * change the directory unexpectedly and so it will make a wrong
+	 * path.
+	 */
+	if (strcmp(p, ".") != 0 && strncmp(p, "./", 2) != 0) {
+		struct archive_string as;
+		archive_string_init(&as);
+		archive_strcpy(&as, "./");
+		archive_strncat(&as, p, len);
+		archive_string_empty(&file->parentdir);
+		archive_string_concat(&file->parentdir, &as);
+		archive_string_free(&as);
+		p = file->parentdir.s;
+		len = archive_strlen(&file->parentdir);
+	}
+
+	/*
+	 * Find out the position which points the last position of
+	 * path separator('/').
+	 */
+	slash = NULL;
+	for (; *p != '\0'; p++) {
+		if (*p == '/')
+			slash = p;
+	}
+	if (slash == NULL) {
+		/* The pathname doesn't have a parent directory. */
+		file->parentdir.length = len;
+		archive_string_copy(&(file->basename), &(file->parentdir));
+		archive_string_empty(&(file->parentdir));
+		*file->parentdir.s = '\0';
+		return (ret);
+	}
+
+	/* Make a basename from dirname and slash */
+	*slash  = '\0';
+	file->parentdir.length = slash - dirname;
+	archive_strcpy(&(file->basename),  slash + 1);
+	return (ret);
+}
+
+static int
+mtree_entry_create_virtual_dir(struct archive_write *a, const char *pathname,
+    struct mtree_entry **m_entry)
+{
+	struct archive_entry *entry;
+	struct mtree_entry *file;
+	int r;
+
+	entry = archive_entry_new();
+	if (entry == NULL) {
+		*m_entry = NULL;
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate memory");
+		return (ARCHIVE_FATAL);
 	}
+	archive_entry_copy_pathname(entry, pathname);
+	archive_entry_set_mode(entry, AE_IFDIR | 0755);
+	archive_entry_set_mtime(entry, time(NULL), 0);
+
+	r = mtree_entry_new(a, entry, &file);
+	archive_entry_free(entry);
+	if (r < ARCHIVE_WARN) {
+		*m_entry = NULL;
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate memory");
+		return (ARCHIVE_FATAL);
+	}
+
+	file->dir_info->virtual = 1;
+
+	*m_entry = file;
+	return (ARCHIVE_OK);
+}
+
+static void
+mtree_entry_register_add(struct mtree_writer *mtree, struct mtree_entry *file)
+{
+        file->next = NULL;
+        *mtree->file_list.last = file;
+        mtree->file_list.last = &(file->next);
+}
+
+static void
+mtree_entry_register_init(struct mtree_writer *mtree)
+{
+	mtree->file_list.first = NULL;
+	mtree->file_list.last = &(mtree->file_list.first);
+}
+
+static void
+mtree_entry_register_free(struct mtree_writer *mtree)
+{
+	struct mtree_entry *file, *file_next;
+
+	file = mtree->file_list.first;
+	while (file != NULL) {
+		file_next = file->next;
+		mtree_entry_free(file);
+		file = file_next;
+	}
+}
+
+static int
+mtree_entry_add_child_tail(struct mtree_entry *parent,
+    struct mtree_entry *child)
+{
+	child->dir_info->chnext = NULL;
+	*parent->dir_info->children.last = child;
+	parent->dir_info->children.last = &(child->dir_info->chnext);
+	return (1);
+}
+
+/*
+ * Find a entry from a parent entry with the name.
+ */
+static struct mtree_entry *
+mtree_entry_find_child(struct mtree_entry *parent, const char *child_name)
+{
+	struct mtree_entry *np;
+
+	if (parent == NULL)
+		return (NULL);
+	np = (struct mtree_entry *)__archive_rb_tree_find_node(
+	    &(parent->dir_info->rbtree), child_name);
+	return (np);
+}
+
+static int
+get_path_component(char *name, size_t n, const char *fn)
+{
+	char *p;
+	size_t l;
+
+	p = strchr(fn, '/');
+	if (p == NULL) {
+		if ((l = strlen(fn)) == 0)
+			return (0);
+	} else
+		l = p - fn;
+	if (l > n -1)
+		return (-1);
+	memcpy(name, fn, l);
+	name[l] = '\0';
+
+	return ((int)l);
+}
+
+/*
+ * Add a new entry into the tree.
+ */
+static int
+mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	char name[_MAX_FNAME];/* Included null terminator size. */
+#elif defined(NAME_MAX) && NAME_MAX >= 255
+	char name[NAME_MAX+1];
+#else
+	char name[256];
 #endif
+	struct mtree_writer *mtree = (struct mtree_writer *)a->format_data;
+	struct mtree_entry *dent, *file, *np;
+	const char *fn, *p;
+	int l, r;
+
+	file = *filep;
+	if (file->parentdir.length == 0 && file->basename.length == 1 &&
+	    file->basename.s[0] == '.') {
+		file->parent = file;
+		if (mtree->root != NULL) {
+			np = mtree->root;
+			goto same_entry;
+		}
+		mtree->root = file;
+		mtree_entry_register_add(mtree, file);
+		return (ARCHIVE_OK);
+	}
+
+	if (file->parentdir.length == 0) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+		    "Internal programing error "
+		    "in generating canonical name for %s",
+		    file->pathname.s);
+		return (ARCHIVE_FAILED);
+	}
+
+	fn = p = file->parentdir.s;
+
+	/*
+	 * If the path of the parent directory of `file' entry is
+	 * the same as the path of `cur_dirent', add `file' entry to
+	 * `cur_dirent'.
+	 */
+	if (archive_strlen(&(mtree->cur_dirstr))
+	      == archive_strlen(&(file->parentdir)) &&
+	    strcmp(mtree->cur_dirstr.s, fn) == 0) {
+		if (!__archive_rb_tree_insert_node(
+		    &(mtree->cur_dirent->dir_info->rbtree),
+		    (struct archive_rb_node *)file)) {
+			/* There is the same name in the tree. */
+			np = (struct mtree_entry *)__archive_rb_tree_find_node(
+			    &(mtree->cur_dirent->dir_info->rbtree),
+			    file->basename.s);
+			goto same_entry;
+		}
+		file->parent = mtree->cur_dirent;
+		mtree_entry_register_add(mtree, file);
+		return (ARCHIVE_OK);
+	}
+
+	dent = mtree->root;
+	for (;;) {
+		l = get_path_component(name, sizeof(name), fn);
+		if (l == 0) {
+			np = NULL;
+			break;
+		}
+		if (l < 0) {
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_MISC,
+			    "A name buffer is too small");
+			return (ARCHIVE_FATAL);
+		}
+		if (l == 1 && name[0] == '.' && dent != NULL &&
+		    dent == mtree->root) {
+			fn += l;
+			if (fn[0] == '/')
+				fn++;
+			continue;
+		}
+
+		np = mtree_entry_find_child(dent, name);
+		if (np == NULL || fn[0] == '\0')
+			break;
+
+		/* Find next sub directory. */
+		if (!np->dir_info) {
+			/* NOT Directory! */
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_MISC,
+			    "`%s' is not directory, we cannot insert `%s' ",
+			    np->pathname.s, file->pathname.s);
+			return (ARCHIVE_FAILED);
+		}
+		fn += l;
+		if (fn[0] == '/')
+			fn++;
+		dent = np;
+	}
+	if (np == NULL) {
+		/*
+		 * Create virtual parent directories.
+		 */
+		while (fn[0] != '\0') {
+			struct mtree_entry *vp;
+			struct archive_string as;
+
+			archive_string_init(&as);
+			archive_strncat(&as, p, fn - p + l);
+			if (as.s[as.length-1] == '/') {
+				as.s[as.length-1] = '\0';
+				as.length--;
+			}
+			r = mtree_entry_create_virtual_dir(a, as.s, &vp);
+			archive_string_free(&as);
+			if (r < ARCHIVE_WARN)
+				return (r);
+
+			if (strcmp(vp->pathname.s, ".") == 0) {
+				vp->parent = vp;
+				mtree->root = vp;
+			} else {
+				__archive_rb_tree_insert_node(
+				    &(dent->dir_info->rbtree),
+				    (struct archive_rb_node *)vp);
+				vp->parent = dent;
+			}
+			mtree_entry_register_add(mtree, vp);
+			np = vp;
+
+			fn += l;
+			if (fn[0] == '/')
+				fn++;
+			l = get_path_component(name, sizeof(name), fn);
+			if (l < 0) {
+				archive_string_free(&as);
+				archive_set_error(&a->archive,
+				    ARCHIVE_ERRNO_MISC,
+				    "A name buffer is too small");
+				return (ARCHIVE_FATAL);
+			}
+			dent = np;
+		}
+
+		/* Found out the parent directory where `file' can be
+		 * inserted. */
+		mtree->cur_dirent = dent;
+		archive_string_empty(&(mtree->cur_dirstr));
+		archive_string_ensure(&(mtree->cur_dirstr),
+		    archive_strlen(&(dent->parentdir)) +
+		    archive_strlen(&(dent->basename)) + 2);
+		if (archive_strlen(&(dent->parentdir)) +
+		    archive_strlen(&(dent->basename)) == 0)
+			mtree->cur_dirstr.s[0] = 0;
+		else {
+			if (archive_strlen(&(dent->parentdir)) > 0) {
+				archive_string_copy(&(mtree->cur_dirstr),
+				    &(dent->parentdir));
+				archive_strappend_char(
+				    &(mtree->cur_dirstr), '/');
+			}
+			archive_string_concat(&(mtree->cur_dirstr),
+			    &(dent->basename));
+		}
+
+		if (!__archive_rb_tree_insert_node(
+		    &(dent->dir_info->rbtree),
+		    (struct archive_rb_node *)file)) {
+			np = (struct mtree_entry *)__archive_rb_tree_find_node(
+			    &(dent->dir_info->rbtree), file->basename.s);
+			goto same_entry;
+		}
+		file->parent = dent;
+		mtree_entry_register_add(mtree, file);
+		return (ARCHIVE_OK);
+	}
+
+same_entry:
+	/*
+	 * We have already has the entry the filename of which is
+	 * the same.
+	 */
+	r = mtree_entry_exchange_same_entry(a, np, file);
+	if (r < ARCHIVE_WARN)
+		return (r);
+	if (np->dir_info)
+		np->dir_info->virtual = 0;
+	*filep = np;
+	mtree_entry_free(file);
+	return (ARCHIVE_WARN);
+}
+
+static int
+mtree_entry_exchange_same_entry(struct archive_write *a, struct mtree_entry *np,
+    struct mtree_entry *file)
+{
+
+	if ((np->mode & AE_IFMT) != (file->mode & AE_IFMT)) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+		    "Found duplicate entries `%s' and its file type is "
+		    "different",
+		    np->pathname.s);
+		return (ARCHIVE_FAILED);
+	}
+
+	/* Update the existent mtree entry's attributes by the new one's. */
+	archive_string_empty(&np->symlink);
+	archive_string_concat(&np->symlink, &file->symlink);
+	archive_string_empty(&np->uname);
+	archive_string_concat(&np->uname, &file->uname);
+	archive_string_empty(&np->gname);
+	archive_string_concat(&np->gname, &file->gname);
+	archive_string_empty(&np->fflags_text);
+	archive_string_concat(&np->fflags_text, &file->fflags_text);
+	np->nlink = file->nlink;
+	np->filetype = file->filetype;
+	np->mode = file->mode;
+	np->size = file->size;
+	np->uid = file->uid;
+	np->gid = file->gid;
+	np->fflags_set = file->fflags_set;
+	np->fflags_clear = file->fflags_clear;
+	np->mtime = file->mtime;
+	np->mtime_nsec = file->mtime_nsec;
+	np->rdevmajor = file->rdevmajor;
+	np->rdevminor = file->rdevminor;
+
+	return (ARCHIVE_WARN);
 }
diff --git a/libarchive/archive_write_set_format_pax.c b/libarchive/archive_write_set_format_pax.c
index 8affb2c..687f8e4 100644
--- a/libarchive/archive_write_set_format_pax.c
+++ b/libarchive/archive_write_set_format_pax.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2010-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -187,11 +187,13 @@ archive_write_pax_options(struct archive_write *a, const char *key,
 		} else
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			    "pax: invalid charset name");
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "pax: unknown keyword ``%s''", key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 /*
@@ -332,8 +334,7 @@ archive_write_pax_header_xattrs(struct archive_write *a,
 		url_encoded_name = url_encode(name);
 		if (url_encoded_name != NULL) {
 			/* Convert narrow-character to UTF-8. */
-			r = archive_strcpy_in_locale(
-			    &(pax->l_url_encoded_name),
+			r = archive_strcpy_l(&(pax->l_url_encoded_name),
 			    url_encoded_name, pax->sconv_utf8);
 			free(url_encoded_name); /* Done with this. */
 			if (r == 0)
@@ -463,7 +464,6 @@ archive_write_pax_header(struct archive_write *a,
 {
 	struct archive_entry *entry_main;
 	const char *p;
-	char *t;
 	const char *suffix;
 	int need_extension, r, ret;
 	int sparse_count;
@@ -541,24 +541,73 @@ archive_write_pax_header(struct archive_write *a,
 		case AE_IFREG:
 			break;
 		case AE_IFDIR:
+		{
 			/*
 			 * Ensure a trailing '/'.  Modify the original
 			 * entry so the client sees the change.
 			 */
-			p = archive_entry_pathname(entry_original);
-			if (p[strlen(p) - 1] != '/') {
-				t = (char *)malloc(strlen(p) + 2);
-				if (t == NULL) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+			const wchar_t *wp;
+
+			wp = archive_entry_pathname_w(entry_original);
+			if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
+				struct archive_wstring ws;
+
+				archive_string_init(&ws);
+				path_length = wcslen(wp);
+				if (archive_wstring_ensure(&ws,
+				    path_length + 2) == NULL) {
 					archive_set_error(&a->archive, ENOMEM,
-					"Can't allocate pax data");
+					    "Can't allocate pax data");
+					archive_wstring_free(&ws);
 					return(ARCHIVE_FATAL);
 				}
-				strcpy(t, p);
-				strcat(t, "/");
-				archive_entry_copy_pathname(entry_original, t);
-				free(t);
+				/* Should we keep '\' ? */
+				if (wp[path_length -1] == L'\\')
+					path_length--;
+				archive_wstrncpy(&ws, wp, path_length);
+				archive_wstrappend_wchar(&ws, L'/');
+				archive_entry_copy_pathname_w(
+				    entry_original, ws.s);
+				archive_wstring_free(&ws);
+				p = NULL;
+			} else
+#endif
+				p = archive_entry_pathname(entry_original);
+			/*
+			 * On Windows, this is a backup operation just in
+			 * case getting WCS failed. On POSIX, this is a
+			 * normal operation.
+			 */
+			if (p != NULL && p[strlen(p) - 1] != '/') {
+				struct archive_string as;
+
+				archive_string_init(&as);
+				path_length = strlen(p);
+				if (archive_string_ensure(&as,
+				    path_length + 2) == NULL) {
+					archive_set_error(&a->archive, ENOMEM,
+					    "Can't allocate pax data");
+					archive_string_free(&as);
+					return(ARCHIVE_FATAL);
+				}
+#if defined(_WIN32) && !defined(__CYGWIN__)
+				/* NOTE: This might break the pathname
+				 * if the current code page is CP932 and
+				 * the pathname includes a character '\'
+				 * as a part of its multibyte pathname. */
+				if (p[strlen(p) -1] == '\\')
+					path_length--;
+				else
+#endif
+				archive_strncpy(&as, p, path_length);
+				archive_strappend_char(&as, '/');
+				archive_entry_copy_pathname(
+				    entry_original, as.s);
+				archive_string_free(&as);
 			}
 			break;
+		}
 		case AE_IFSOCK:
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_FILE_FORMAT,
@@ -576,7 +625,7 @@ archive_write_pax_header(struct archive_write *a,
 
 	/*
 	 * If Mac OS metadata blob is here, recurse to write that
-	 * as a separate entry.  This is realy a pretty poor design:
+	 * as a separate entry.  This is really a pretty poor design:
 	 * In particular, it doubles the overhead for long filenames.
 	 * TODO: Help Apple folks design something better and figure
 	 * out how to transition from this legacy format.
@@ -598,8 +647,10 @@ archive_write_pax_header(struct archive_write *a,
 		oname = archive_entry_pathname(entry_original);
 		name_length = strlen(oname);
 		name = malloc(name_length + 3);
-		if (name == NULL) {
+		if (name == NULL || extra == NULL) {
 			/* XXX error message */
+			archive_entry_free(extra);
+			free(name);
 			return (ARCHIVE_FAILED);
 		}
 		strcpy(name, oname);
@@ -638,11 +689,13 @@ archive_write_pax_header(struct archive_write *a,
 
 		/* Recurse to write the special copyfile entry. */
 		r = archive_write_pax_header(a, extra);
+		archive_entry_free(extra);
 		if (r < ARCHIVE_WARN)
 			return (r);
 		if (r < ret)
 			ret = r;
-		r = archive_write_pax_data(a, mac_metadata, mac_metadata_size);
+		r = (int)archive_write_pax_data(a, mac_metadata,
+		    mac_metadata_size);
 		if (r < ARCHIVE_WARN)
 			return (r);
 		if (r < ret)
@@ -655,7 +708,20 @@ archive_write_pax_header(struct archive_write *a,
 	}
 
 	/* Copy entry so we can modify it as needed. */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	/* Make sure the path separators in pahtname, hardlink and symlink
+	 * are all slash '/', not the Windows path separator '\'. */
+	entry_main = __la_win_entry_in_posix_pathseparator(entry_original);
+	if (entry_main == entry_original)
+		entry_main = archive_entry_clone(entry_original);
+#else
 	entry_main = archive_entry_clone(entry_original);
+#endif
+	if (entry_main == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate pax data");
+		return(ARCHIVE_FATAL);
+	}
 	archive_string_empty(&(pax->pax_header)); /* Blank our work area. */
 	archive_string_empty(&(pax->sparse_map));
 	sparse_total = 0;
@@ -1261,7 +1327,7 @@ archive_write_pax_header(struct archive_write *a,
 			return (ARCHIVE_FATAL);
 		}
 		/* Pad out the end of the entry. */
-		r = __archive_write_nulls(a, pax->entry_padding);
+		r = __archive_write_nulls(a, (size_t)pax->entry_padding);
 		if (r != ARCHIVE_OK) {
 			/* If a write fails, we're pretty much toast. */
 			return (ARCHIVE_FATAL);
@@ -1439,7 +1505,7 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length,
  *
  * Joerg Schilling has argued that this is unnecessary because, in
  * practice, if the pax extended attributes get extracted as regular
- * files, noone is going to bother reading those attributes to
+ * files, no one is going to bother reading those attributes to
  * manually restore them.  Based on this, 'star' uses
  * /tmp/PaxHeader/'basename' as the ustar header name.  This is a
  * tempting argument, in part because it's simpler than the SUSv3
@@ -1596,13 +1662,14 @@ archive_write_pax_finish_entry(struct archive_write *a)
 	if (remaining == 0) {
 		while (pax->sparse_list) {
 			struct sparse_block *sb;
-			remaining += pax->sparse_list->remaining;
+			if (!pax->sparse_list->is_hole)
+				remaining += pax->sparse_list->remaining;
 			sb = pax->sparse_list->next;
 			free(pax->sparse_list);
 			pax->sparse_list = sb;
 		}
 	}
-	ret = __archive_write_nulls(a, remaining + pax->entry_padding);
+	ret = __archive_write_nulls(a, (size_t)(remaining + pax->entry_padding));
 	pax->entry_bytes_remaining = pax->entry_padding = 0;
 	return (ret);
 }
@@ -1647,9 +1714,9 @@ archive_write_pax_data(struct archive_write *a, const void *buff, size_t s)
 			return (total);
 
 		p = ((const unsigned char *)buff) + total;
-		ws = s;
+		ws = s - total;
 		if (ws > pax->sparse_list->remaining)
-			ws = pax->sparse_list->remaining;
+			ws = (size_t)pax->sparse_list->remaining;
 
 		if (pax->sparse_list->is_hole) {
 			/* Current block is hole thus we do not write
@@ -1799,7 +1866,7 @@ _sparse_list_add_block(struct pax *pax, int64_t offset, int64_t length,
 	sb->is_hole = is_hole;
 	sb->offset = offset;
 	sb->remaining = length;
-	if (pax->sparse_list == NULL)
+	if (pax->sparse_list == NULL || pax->sparse_tail == NULL)
 		pax->sparse_list = pax->sparse_tail = sb;
 	else {
 		pax->sparse_tail->next = sb;
diff --git a/libarchive/archive_write_set_format_ustar.c b/libarchive/archive_write_set_format_ustar.c
index 4b96ac2..484ab34 100644
--- a/libarchive/archive_write_set_format_ustar.c
+++ b/libarchive/archive_write_set_format_ustar.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -224,11 +224,13 @@ archive_write_ustar_options(struct archive_write *a, const char *key,
 			else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "%s: unknown keyword ``%s''", a->format_name, key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 static int
@@ -237,6 +239,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
 	char buff[512];
 	int ret, ret2;
 	struct ustar *ustar;
+	struct archive_entry *entry_main;
 	struct archive_string_conv *sconv;
 
 	ustar = (struct ustar *)a->format_data;
@@ -267,37 +270,106 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
 
 	if (AE_IFDIR == archive_entry_filetype(entry)) {
 		const char *p;
-		char *t;
+		size_t path_length;
 		/*
 		 * Ensure a trailing '/'.  Modify the entry so
 		 * the client sees the change.
 		 */
-		p = archive_entry_pathname(entry);
-		if (p[strlen(p) - 1] != '/') {
-			t = (char *)malloc(strlen(p) + 2);
-			if (t == NULL) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+		const wchar_t *wp;
+
+		wp = archive_entry_pathname_w(entry);
+		if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
+			struct archive_wstring ws;
+
+			archive_string_init(&ws);
+			path_length = wcslen(wp);
+			if (archive_wstring_ensure(&ws,
+			    path_length + 2) == NULL) {
+				archive_set_error(&a->archive, ENOMEM,
+				    "Can't allocate ustar data");
+				archive_wstring_free(&ws);
+				return(ARCHIVE_FATAL);
+			}
+			/* Should we keep '\' ? */
+			if (wp[path_length -1] == L'\\')
+				path_length--;
+			archive_wstrncpy(&ws, wp, path_length);
+			archive_wstrappend_wchar(&ws, L'/');
+			archive_entry_copy_pathname_w(entry, ws.s);
+			archive_wstring_free(&ws);
+			p = NULL;
+		} else
+#endif
+			p = archive_entry_pathname(entry);
+		/*
+		 * On Windows, this is a backup operation just in
+		 * case getting WCS failed. On POSIX, this is a
+		 * normal operation.
+		 */
+		if (p != NULL && p[strlen(p) - 1] != '/') {
+			struct archive_string as;
+
+			archive_string_init(&as);
+			path_length = strlen(p);
+			if (archive_string_ensure(&as,
+			    path_length + 2) == NULL) {
 				archive_set_error(&a->archive, ENOMEM,
-				"Can't allocate ustar data");
+				    "Can't allocate ustar data");
+				archive_string_free(&as);
 				return(ARCHIVE_FATAL);
 			}
-			strcpy(t, p);
-			strcat(t, "/");
-			archive_entry_copy_pathname(entry, t);
-			free(t);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+			/* NOTE: This might break the pathname
+			 * if the current code page is CP932 and
+			 * the pathname includes a character '\'
+			 * as a part of its multibyte pathname. */
+			if (p[strlen(p) -1] == '\\')
+				path_length--;
+			else
+#endif
+			archive_strncpy(&as, p, path_length);
+			archive_strappend_char(&as, '/');
+			archive_entry_copy_pathname(entry, as.s);
+			archive_string_free(&as);
 		}
 	}
 
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	/* Make sure the path separators in pahtname, hardlink and symlink
+	 * are all slash '/', not the Windows path separator '\'. */
+	entry_main = __la_win_entry_in_posix_pathseparator(entry);
+	if (entry_main == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate ustar data");
+		return(ARCHIVE_FATAL);
+	}
+	if (entry != entry_main)
+		entry = entry_main;
+	else
+		entry_main = NULL;
+#else
+	entry_main = NULL;
+#endif
 	ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1, sconv);
-	if (ret < ARCHIVE_WARN)
+	if (ret < ARCHIVE_WARN) {
+		if (entry_main)
+			archive_entry_free(entry_main);
 		return (ret);
+	}
 	ret2 = __archive_write_output(a, buff, 512);
-	if (ret2 < ARCHIVE_WARN)
+	if (ret2 < ARCHIVE_WARN) {
+		if (entry_main)
+			archive_entry_free(entry_main);
 		return (ret2);
+	}
 	if (ret2 < ret)
 		ret = ret2;
 
 	ustar->entry_bytes_remaining = archive_entry_size(entry);
 	ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining);
+	if (entry_main)
+		archive_entry_free(entry_main);
 	return (ret);
 }
 
@@ -670,7 +742,7 @@ archive_write_ustar_finish_entry(struct archive_write *a)
 
 	ustar = (struct ustar *)a->format_data;
 	ret = __archive_write_nulls(a,
-	    ustar->entry_bytes_remaining + ustar->entry_padding);
+	    (size_t)(ustar->entry_bytes_remaining + ustar->entry_padding));
 	ustar->entry_bytes_remaining = ustar->entry_padding = 0;
 	return (ret);
 }
@@ -683,7 +755,7 @@ archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
 
 	ustar = (struct ustar *)a->format_data;
 	if (s > ustar->entry_bytes_remaining)
-		s = ustar->entry_bytes_remaining;
+		s = (size_t)ustar->entry_bytes_remaining;
 	ret = __archive_write_output(a, buff, s);
 	ustar->entry_bytes_remaining -= s;
 	if (ret != ARCHIVE_OK)
diff --git a/libarchive/archive_write_set_format_ustar.c b/libarchive/archive_write_set_format_v7tar.c
similarity index 53%
copy from libarchive/archive_write_set_format_ustar.c
copy to libarchive/archive_write_set_format_v7tar.c
index 4b96ac2..17efbaf 100644
--- a/libarchive/archive_write_set_format_ustar.c
+++ b/libarchive/archive_write_set_format_v7tar.c
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_ustar.c 191579 2009-04-27 18:35:03Z kientzle $");
+__FBSDID("$FreeBSD$");
 
 
 #ifdef HAVE_ERRNO_H
@@ -45,7 +45,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_ustar.c 191579
 #include "archive_private.h"
 #include "archive_write_private.h"
 
-struct ustar {
+struct v7tar {
 	uint64_t	entry_bytes_remaining;
 	uint64_t	entry_padding;
 
@@ -55,49 +55,33 @@ struct ustar {
 };
 
 /*
- * Define structure of POSIX 'ustar' tar header.
+ * Define structure of POSIX 'v7tar' tar header.
  */
-#define	USTAR_name_offset 0
-#define	USTAR_name_size 100
-#define	USTAR_mode_offset 100
-#define	USTAR_mode_size 6
-#define	USTAR_mode_max_size 8
-#define	USTAR_uid_offset 108
-#define	USTAR_uid_size 6
-#define	USTAR_uid_max_size 8
-#define	USTAR_gid_offset 116
-#define	USTAR_gid_size 6
-#define	USTAR_gid_max_size 8
-#define	USTAR_size_offset 124
-#define	USTAR_size_size 11
-#define	USTAR_size_max_size 12
-#define	USTAR_mtime_offset 136
-#define	USTAR_mtime_size 11
-#define	USTAR_mtime_max_size 11
-#define	USTAR_checksum_offset 148
-#define	USTAR_checksum_size 8
-#define	USTAR_typeflag_offset 156
-#define	USTAR_typeflag_size 1
-#define	USTAR_linkname_offset 157
-#define	USTAR_linkname_size 100
-#define	USTAR_magic_offset 257
-#define	USTAR_magic_size 6
-#define	USTAR_version_offset 263
-#define	USTAR_version_size 2
-#define	USTAR_uname_offset 265
-#define	USTAR_uname_size 32
-#define	USTAR_gname_offset 297
-#define	USTAR_gname_size 32
-#define	USTAR_rdevmajor_offset 329
-#define	USTAR_rdevmajor_size 6
-#define	USTAR_rdevmajor_max_size 8
-#define	USTAR_rdevminor_offset 337
-#define	USTAR_rdevminor_size 6
-#define	USTAR_rdevminor_max_size 8
-#define	USTAR_prefix_offset 345
-#define	USTAR_prefix_size 155
-#define	USTAR_padding_offset 500
-#define	USTAR_padding_size 12
+#define	V7TAR_name_offset 0
+#define	V7TAR_name_size 100
+#define	V7TAR_mode_offset 100
+#define	V7TAR_mode_size 6
+#define	V7TAR_mode_max_size 8
+#define	V7TAR_uid_offset 108
+#define	V7TAR_uid_size 6
+#define	V7TAR_uid_max_size 8
+#define	V7TAR_gid_offset 116
+#define	V7TAR_gid_size 6
+#define	V7TAR_gid_max_size 8
+#define	V7TAR_size_offset 124
+#define	V7TAR_size_size 11
+#define	V7TAR_size_max_size 12
+#define	V7TAR_mtime_offset 136
+#define	V7TAR_mtime_size 11
+#define	V7TAR_mtime_max_size 12
+#define	V7TAR_checksum_offset 148
+#define	V7TAR_checksum_size 8
+#define	V7TAR_typeflag_offset 156
+#define	V7TAR_typeflag_size 1
+#define	V7TAR_linkname_offset 157
+#define	V7TAR_linkname_size 100
+#define	V7TAR_padding_offset 257
+#define	V7TAR_padding_size 255
 
 /*
  * A filled-in copy of the header for initialization.
@@ -121,56 +105,49 @@ static const char template_header[] = {
 	/* Initial checksum value: 8 spaces */
 	' ',' ',' ',' ',' ',' ',' ',' ',
 	/* Typeflag: 1 byte */
-	'0',			/* '0' = regular file */
+	0,
 	/* Linkname: 100 bytes */
 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 	0,0,0,0,
-	/* Magic: 6 bytes, Version: 2 bytes */
-	'u','s','t','a','r','\0', '0','0',
-	/* Uname: 32 bytes */
+	/* Padding: 255 bytes */
+	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
-	/* Gname: 32 bytes */
 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
-	/* rdevmajor + space/null padding: 8 bytes */
-	'0','0','0','0','0','0', ' ','\0',
-	/* rdevminor + space/null padding: 8 bytes */
-	'0','0','0','0','0','0', ' ','\0',
-	/* Prefix: 155 bytes */
 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,
-	/* Padding: 12 bytes */
-	0,0,0,0,0,0,0,0, 0,0,0,0
+	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0
 };
 
-static ssize_t	archive_write_ustar_data(struct archive_write *a, const void *buff,
+static ssize_t	archive_write_v7tar_data(struct archive_write *a, const void *buff,
 		    size_t s);
-static int	archive_write_ustar_free(struct archive_write *);
-static int	archive_write_ustar_close(struct archive_write *);
-static int	archive_write_ustar_finish_entry(struct archive_write *);
-static int	archive_write_ustar_header(struct archive_write *,
+static int	archive_write_v7tar_free(struct archive_write *);
+static int	archive_write_v7tar_close(struct archive_write *);
+static int	archive_write_v7tar_finish_entry(struct archive_write *);
+static int	archive_write_v7tar_header(struct archive_write *,
 		    struct archive_entry *entry);
-static int	archive_write_ustar_options(struct archive_write *,
+static int	archive_write_v7tar_options(struct archive_write *,
 		    const char *, const char *);
 static int	format_256(int64_t, char *, int);
 static int	format_number(int64_t, char *, int size, int max, int strict);
 static int	format_octal(int64_t, char *, int);
+static int	format_header_v7tar(struct archive_write *, char h[512],
+		    struct archive_entry *, int, struct archive_string_conv *);
 
 /*
- * Set output format to 'ustar' format.
+ * Set output format to 'v7tar' format.
  */
 int
-archive_write_set_format_ustar(struct archive *_a)
+archive_write_set_format_v7tar(struct archive *_a)
 {
 	struct archive_write *a = (struct archive_write *)_a;
-	struct ustar *ustar;
+	struct v7tar *v7tar;
 
 	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
-	    ARCHIVE_STATE_NEW, "archive_write_set_format_ustar");
+	    ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar");
 
 	/* If someone else was already registered, unregister them. */
 	if (a->format_free != NULL)
@@ -184,31 +161,31 @@ archive_write_set_format_ustar(struct archive *_a)
 		return (ARCHIVE_FATAL);
 	}
 
-	ustar = (struct ustar *)malloc(sizeof(*ustar));
-	if (ustar == NULL) {
+	v7tar = (struct v7tar *)malloc(sizeof(*v7tar));
+	if (v7tar == NULL) {
 		archive_set_error(&a->archive, ENOMEM,
-		    "Can't allocate ustar data");
+		    "Can't allocate v7tar data");
 		return (ARCHIVE_FATAL);
 	}
-	memset(ustar, 0, sizeof(*ustar));
-	a->format_data = ustar;
-	a->format_name = "ustar";
-	a->format_options = archive_write_ustar_options;
-	a->format_write_header = archive_write_ustar_header;
-	a->format_write_data = archive_write_ustar_data;
-	a->format_close = archive_write_ustar_close;
-	a->format_free = archive_write_ustar_free;
-	a->format_finish_entry = archive_write_ustar_finish_entry;
-	a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR;
-	a->archive.archive_format_name = "POSIX ustar";
+	memset(v7tar, 0, sizeof(*v7tar));
+	a->format_data = v7tar;
+	a->format_name = "tar (non-POSIX)";
+	a->format_options = archive_write_v7tar_options;
+	a->format_write_header = archive_write_v7tar_header;
+	a->format_write_data = archive_write_v7tar_data;
+	a->format_close = archive_write_v7tar_close;
+	a->format_free = archive_write_v7tar_free;
+	a->format_finish_entry = archive_write_v7tar_finish_entry;
+	a->archive.archive_format = ARCHIVE_FORMAT_TAR;
+	a->archive.archive_format_name = "tar (non-POSIX)";
 	return (ARCHIVE_OK);
 }
 
 static int
-archive_write_ustar_options(struct archive_write *a, const char *key,
+archive_write_v7tar_options(struct archive_write *a, const char *key,
     const char *val)
 {
-	struct ustar *ustar = (struct ustar *)a->format_data;
+	struct v7tar *v7tar = (struct v7tar *)a->format_data;
 	int ret = ARCHIVE_FAILED;
 
 	if (strcmp(key, "hdrcharset")  == 0) {
@@ -217,40 +194,44 @@ archive_write_ustar_options(struct archive_write *a, const char *key,
 			    "%s: hdrcharset option needs a character-set name",
 			    a->format_name);
 		else {
-			ustar->opt_sconv = archive_string_conversion_to_charset(
+			v7tar->opt_sconv = archive_string_conversion_to_charset(
 			    &a->archive, val, 0);
-			if (ustar->opt_sconv != NULL)
+			if (v7tar->opt_sconv != NULL)
 				ret = ARCHIVE_OK;
 			else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "%s: unknown keyword ``%s''", a->format_name, key);
+		return (ret);
+	}
 
-	return (ret);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 static int
-archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
+archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)
 {
 	char buff[512];
 	int ret, ret2;
-	struct ustar *ustar;
+	struct v7tar *v7tar;
+	struct archive_entry *entry_main;
 	struct archive_string_conv *sconv;
 
-	ustar = (struct ustar *)a->format_data;
+	v7tar = (struct v7tar *)a->format_data;
 
 	/* Setup default string conversion. */
-	if (ustar->opt_sconv == NULL) {
-		if (!ustar->init_default_conversion) {
-			ustar->sconv_default =
-			    archive_string_default_conversion_for_write(&(a->archive));
-			ustar->init_default_conversion = 1;
+	if (v7tar->opt_sconv == NULL) {
+		if (!v7tar->init_default_conversion) {
+			v7tar->sconv_default =
+			    archive_string_default_conversion_for_write(
+				&(a->archive));
+			v7tar->init_default_conversion = 1;
 		}
-		sconv = ustar->sconv_default;
+		sconv = v7tar->sconv_default;
 	} else
-		sconv = ustar->opt_sconv;
+		sconv = v7tar->opt_sconv;
 
 	/* Sanity check. */
 	if (archive_entry_pathname(entry) == NULL) {
@@ -267,53 +248,121 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
 
 	if (AE_IFDIR == archive_entry_filetype(entry)) {
 		const char *p;
-		char *t;
+		size_t path_length;
 		/*
 		 * Ensure a trailing '/'.  Modify the entry so
 		 * the client sees the change.
 		 */
-		p = archive_entry_pathname(entry);
-		if (p[strlen(p) - 1] != '/') {
-			t = (char *)malloc(strlen(p) + 2);
-			if (t == NULL) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+		const wchar_t *wp;
+
+		wp = archive_entry_pathname_w(entry);
+		if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
+			struct archive_wstring ws;
+
+			archive_string_init(&ws);
+			path_length = wcslen(wp);
+			if (archive_wstring_ensure(&ws,
+			    path_length + 2) == NULL) {
 				archive_set_error(&a->archive, ENOMEM,
-				"Can't allocate ustar data");
+				    "Can't allocate v7tar data");
+				archive_wstring_free(&ws);
 				return(ARCHIVE_FATAL);
 			}
-			strcpy(t, p);
-			strcat(t, "/");
-			archive_entry_copy_pathname(entry, t);
-			free(t);
+			/* Should we keep '\' ? */
+			if (wp[path_length -1] == L'\\')
+				path_length--;
+			archive_wstrncpy(&ws, wp, path_length);
+			archive_wstrappend_wchar(&ws, L'/');
+			archive_entry_copy_pathname_w(entry, ws.s);
+			archive_wstring_free(&ws);
+			p = NULL;
+		} else
+#endif
+			p = archive_entry_pathname(entry);
+		/*
+		 * On Windows, this is a backup operation just in
+		 * case getting WCS failed. On POSIX, this is a
+		 * normal operation.
+		 */
+		if (p != NULL && p[strlen(p) - 1] != '/') {
+			struct archive_string as;
+
+			archive_string_init(&as);
+			path_length = strlen(p);
+			if (archive_string_ensure(&as,
+			    path_length + 2) == NULL) {
+				archive_set_error(&a->archive, ENOMEM,
+				    "Can't allocate v7tar data");
+				archive_string_free(&as);
+				return(ARCHIVE_FATAL);
+			}
+#if defined(_WIN32) && !defined(__CYGWIN__)
+			/* NOTE: This might break the pathname
+			 * if the current code page is CP932 and
+			 * the pathname includes a character '\'
+			 * as a part of its multibyte pathname. */
+			if (p[strlen(p) -1] == '\\')
+				path_length--;
+			else
+#endif
+			archive_strncpy(&as, p, path_length);
+			archive_strappend_char(&as, '/');
+			archive_entry_copy_pathname(entry, as.s);
+			archive_string_free(&as);
 		}
 	}
 
-	ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1, sconv);
-	if (ret < ARCHIVE_WARN)
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	/* Make sure the path separators in pahtname, hardlink and symlink
+	 * are all slash '/', not the Windows path separator '\'. */
+	entry_main = __la_win_entry_in_posix_pathseparator(entry);
+	if (entry_main == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate v7tar data");
+		return(ARCHIVE_FATAL);
+	}
+	if (entry != entry_main)
+		entry = entry_main;
+	else
+		entry_main = NULL;
+#else
+	entry_main = NULL;
+#endif
+	ret = format_header_v7tar(a, buff, entry, 1, sconv);
+	if (ret < ARCHIVE_WARN) {
+		if (entry_main)
+			archive_entry_free(entry_main);
 		return (ret);
+	}
 	ret2 = __archive_write_output(a, buff, 512);
-	if (ret2 < ARCHIVE_WARN)
+	if (ret2 < ARCHIVE_WARN) {
+		if (entry_main)
+			archive_entry_free(entry_main);
 		return (ret2);
+	}
 	if (ret2 < ret)
 		ret = ret2;
 
-	ustar->entry_bytes_remaining = archive_entry_size(entry);
-	ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining);
+	v7tar->entry_bytes_remaining = archive_entry_size(entry);
+	v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);
+	if (entry_main)
+		archive_entry_free(entry_main);
 	return (ret);
 }
 
 /*
- * Format a basic 512-byte "ustar" header.
+ * Format a basic 512-byte "v7tar" header.
  *
  * Returns -1 if format failed (due to field overflow).
  * Note that this always formats as much of the header as possible.
  * If "strict" is set to zero, it will extend numeric fields as
  * necessary (overwriting terminators or using base-256 extensions).
  *
- * This is exported so that other 'tar' formats can use it.
  */
-int
-__archive_write_format_header_ustar(struct archive_write *a, char h[512],
-    struct archive_entry *entry, int tartype, int strict,
+static int
+format_header_v7tar(struct archive_write *a, char h[512],
+    struct archive_entry *entry, int strict,
     struct archive_string_conv *sconv)
 {
 	unsigned int checksum;
@@ -325,7 +374,7 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
 	ret = 0;
 	mytartype = -1;
 	/*
-	 * The "template header" already includes the "ustar"
+	 * The "template header" already includes the "v7tar"
 	 * signature, various end-of-field markers and other required
 	 * elements.
 	 */
@@ -348,45 +397,15 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
 		    pp, archive_string_conversion_charset_name(sconv));
 		ret = ARCHIVE_WARN;
 	}
-	if (copy_length <= USTAR_name_size)
-		memcpy(h + USTAR_name_offset, pp, copy_length);
+	if (strict && copy_length < V7TAR_name_size)
+		memcpy(h + V7TAR_name_offset, pp, copy_length);
+	else if (!strict && copy_length <= V7TAR_name_size)
+		memcpy(h + V7TAR_name_offset, pp, copy_length);
 	else {
-		/* Store in two pieces, splitting at a '/'. */
-		p = strchr(pp + copy_length - USTAR_name_size - 1, '/');
-		/*
-		 * Look for the next '/' if we chose the first character
-		 * as the separator.  (ustar format doesn't permit
-		 * an empty prefix.)
-		 */
-		if (p == pp)
-			p = strchr(p + 1, '/');
-		/* Fail if the name won't fit. */
-		if (!p) {
-			/* No separator. */
-			archive_set_error(&a->archive, ENAMETOOLONG,
-			    "Pathname too long");
-			ret = ARCHIVE_FAILED;
-		} else if (p[1] == '\0') {
-			/*
-			 * The only feasible separator is a final '/';
-			 * this would result in a non-empty prefix and
-			 * an empty name, which POSIX doesn't
-			 * explicitly forbid, but it just feels wrong.
-			 */
-			archive_set_error(&a->archive, ENAMETOOLONG,
-			    "Pathname too long");
-			ret = ARCHIVE_FAILED;
-		} else if (p  > pp + USTAR_prefix_size) {
-			/* Prefix is too long. */
-			archive_set_error(&a->archive, ENAMETOOLONG,
-			    "Pathname too long");
-			ret = ARCHIVE_FAILED;
-		} else {
-			/* Copy prefix and remainder to appropriate places */
-			memcpy(h + USTAR_prefix_offset, pp, p - pp);
-			memcpy(h + USTAR_name_offset, p + 1,
-			    pp + copy_length - p - 1);
-		}
+		/* Prefix is too long. */
+		archive_set_error(&a->archive, ENAMETOOLONG,
+		    "Pathname too long");
+		ret = ARCHIVE_FAILED;
 	}
 
 	r = archive_entry_hardlink_l(entry, &p, &copy_length, sconv);
@@ -420,127 +439,77 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
 		}
 	}
 	if (copy_length > 0) {
-		if (copy_length > USTAR_linkname_size) {
+		if (copy_length >= V7TAR_linkname_size) {
 			archive_set_error(&a->archive, ENAMETOOLONG,
 			    "Link contents too long");
 			ret = ARCHIVE_FAILED;
-			copy_length = USTAR_linkname_size;
-		}
-		memcpy(h + USTAR_linkname_offset, p, copy_length);
-	}
-
-	r = archive_entry_uname_l(entry, &p, &copy_length, sconv);
-	if (r != 0) {
-		if (errno == ENOMEM) {
-			archive_set_error(&a->archive, ENOMEM,
-			    "Can't allocate memory for Uname");
-			return (ARCHIVE_FATAL);
-		}
-		archive_set_error(&a->archive,
-		    ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Can't translate uname '%s' to %s",
-		    p, archive_string_conversion_charset_name(sconv));
-		ret = ARCHIVE_WARN;
-	}
-	if (copy_length > 0) {
-		if (copy_length > USTAR_uname_size) {
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Username too long");
-			ret = ARCHIVE_FAILED;
-			copy_length = USTAR_uname_size;
-		}
-		memcpy(h + USTAR_uname_offset, p, copy_length);
-	}
-
-	r = archive_entry_gname_l(entry, &p, &copy_length, sconv);
-	if (r != 0) {
-		if (errno == ENOMEM) {
-			archive_set_error(&a->archive, ENOMEM,
-			    "Can't allocate memory for Gname");
-			return (ARCHIVE_FATAL);
-		}
-		archive_set_error(&a->archive,
-		    ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Can't translate gname '%s' to %s",
-		    p, archive_string_conversion_charset_name(sconv));
-		ret = ARCHIVE_WARN;
-	}
-	if (copy_length > 0) {
-		if (strlen(p) > USTAR_gname_size) {
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			    "Group name too long");
-			ret = ARCHIVE_FAILED;
-			copy_length = USTAR_gname_size;
+			copy_length = V7TAR_linkname_size;
 		}
-		memcpy(h + USTAR_gname_offset, p, copy_length);
+		memcpy(h + V7TAR_linkname_offset, p, copy_length);
 	}
 
 	if (format_number(archive_entry_mode(entry) & 07777,
-	    h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {
+	    h + V7TAR_mode_offset, V7TAR_mode_size,
+	    V7TAR_mode_max_size, strict)) {
 		archive_set_error(&a->archive, ERANGE,
 		    "Numeric mode too large");
 		ret = ARCHIVE_FAILED;
 	}
 
 	if (format_number(archive_entry_uid(entry),
-	    h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {
+	    h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {
 		archive_set_error(&a->archive, ERANGE,
 		    "Numeric user ID too large");
 		ret = ARCHIVE_FAILED;
 	}
 
 	if (format_number(archive_entry_gid(entry),
-	    h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {
+	    h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {
 		archive_set_error(&a->archive, ERANGE,
 		    "Numeric group ID too large");
 		ret = ARCHIVE_FAILED;
 	}
 
 	if (format_number(archive_entry_size(entry),
-	    h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {
+	    h + V7TAR_size_offset, V7TAR_size_size,
+	    V7TAR_size_max_size, strict)) {
 		archive_set_error(&a->archive, ERANGE,
 		    "File size out of range");
 		ret = ARCHIVE_FAILED;
 	}
 
 	if (format_number(archive_entry_mtime(entry),
-	    h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {
+	    h + V7TAR_mtime_offset, V7TAR_mtime_size,
+	    V7TAR_mtime_max_size, strict)) {
 		archive_set_error(&a->archive, ERANGE,
 		    "File modification time too large");
 		ret = ARCHIVE_FAILED;
 	}
 
-	if (archive_entry_filetype(entry) == AE_IFBLK
-	    || archive_entry_filetype(entry) == AE_IFCHR) {
-		if (format_number(archive_entry_rdevmajor(entry),
-		    h + USTAR_rdevmajor_offset, USTAR_rdevmajor_size,
-		    USTAR_rdevmajor_max_size, strict)) {
-			archive_set_error(&a->archive, ERANGE,
-			    "Major device number too large");
-			ret = ARCHIVE_FAILED;
-		}
-
-		if (format_number(archive_entry_rdevminor(entry),
-		    h + USTAR_rdevminor_offset, USTAR_rdevminor_size,
-		    USTAR_rdevminor_max_size, strict)) {
-			archive_set_error(&a->archive, ERANGE,
-			    "Minor device number too large");
-			ret = ARCHIVE_FAILED;
-		}
-	}
-
-	if (tartype >= 0) {
-		h[USTAR_typeflag_offset] = tartype;
-	} else if (mytartype >= 0) {
-		h[USTAR_typeflag_offset] = mytartype;
+	if (mytartype >= 0) {
+		h[V7TAR_typeflag_offset] = mytartype;
 	} else {
 		switch (archive_entry_filetype(entry)) {
-		case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break;
-		case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break;
-		case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break;
-		case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break;
-		case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break;
-		case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break;
+		case AE_IFREG: case AE_IFDIR:
+			break;
+		case AE_IFLNK:
+			h[V7TAR_typeflag_offset] = '2';
+			break;
+		case AE_IFCHR:
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_FILE_FORMAT,
+			    "tar format cannot archive character device");
+			return (ARCHIVE_FAILED);
+		case AE_IFBLK:
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_FILE_FORMAT,
+			    "tar format cannot archive block device");
+			return (ARCHIVE_FAILED);
+		case AE_IFIFO:
+			archive_set_error(&a->archive,
+			    ARCHIVE_ERRNO_FILE_FORMAT,
+			    "tar format cannot archive fifo");
+			return (ARCHIVE_FAILED);
 		case AE_IFSOCK:
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_FILE_FORMAT,
@@ -558,9 +527,9 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
 	checksum = 0;
 	for (i = 0; i < 512; i++)
 		checksum += 255 & (unsigned int)h[i];
-	h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */
-	/* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */
-	format_octal(checksum, h + USTAR_checksum_offset, 6);
+	format_octal(checksum, h + V7TAR_checksum_offset, 6);
+	/* Can't be pre-set in the template. */
+	h[V7TAR_checksum_offset + 6] = '\0';
 	return (ret);
 }
 
@@ -646,46 +615,46 @@ format_octal(int64_t v, char *p, int s)
 }
 
 static int
-archive_write_ustar_close(struct archive_write *a)
+archive_write_v7tar_close(struct archive_write *a)
 {
 	return (__archive_write_nulls(a, 512*2));
 }
 
 static int
-archive_write_ustar_free(struct archive_write *a)
+archive_write_v7tar_free(struct archive_write *a)
 {
-	struct ustar *ustar;
+	struct v7tar *v7tar;
 
-	ustar = (struct ustar *)a->format_data;
-	free(ustar);
+	v7tar = (struct v7tar *)a->format_data;
+	free(v7tar);
 	a->format_data = NULL;
 	return (ARCHIVE_OK);
 }
 
 static int
-archive_write_ustar_finish_entry(struct archive_write *a)
+archive_write_v7tar_finish_entry(struct archive_write *a)
 {
-	struct ustar *ustar;
+	struct v7tar *v7tar;
 	int ret;
 
-	ustar = (struct ustar *)a->format_data;
+	v7tar = (struct v7tar *)a->format_data;
 	ret = __archive_write_nulls(a,
-	    ustar->entry_bytes_remaining + ustar->entry_padding);
-	ustar->entry_bytes_remaining = ustar->entry_padding = 0;
+	    (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
+	v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
 	return (ret);
 }
 
 static ssize_t
-archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
+archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
 {
-	struct ustar *ustar;
+	struct v7tar *v7tar;
 	int ret;
 
-	ustar = (struct ustar *)a->format_data;
-	if (s > ustar->entry_bytes_remaining)
-		s = ustar->entry_bytes_remaining;
+	v7tar = (struct v7tar *)a->format_data;
+	if (s > v7tar->entry_bytes_remaining)
+		s = (size_t)v7tar->entry_bytes_remaining;
 	ret = __archive_write_output(a, buff, s);
-	ustar->entry_bytes_remaining -= s;
+	v7tar->entry_bytes_remaining -= s;
 	if (ret != ARCHIVE_OK)
 		return (ret);
 	return (s);
diff --git a/libarchive/archive_write_set_format_xar.c b/libarchive/archive_write_set_format_xar.c
index bb9b551..79667e5 100644
--- a/libarchive/archive_write_set_format_xar.c
+++ b/libarchive/archive_write_set_format_xar.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2010-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -97,6 +97,8 @@ archive_write_set_format_xar(struct archive *_a)
 
 /*#define DEBUG_PRINT_TOC		1 */
 
+#define BAD_CAST_CONST (const xmlChar *)
+
 #define HEADER_MAGIC	0x78617221
 #define HEADER_SIZE	28
 #define HEADER_VERSION	1
@@ -414,7 +416,7 @@ xar_options(struct archive_write *a, const char *key, const char *value)
 		else {
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
-			    "Unkonwn checksum name: `%s'",
+			    "Unknown checksum name: `%s'",
 			    value);
 			return (ARCHIVE_FAILED);
 		}
@@ -448,7 +450,7 @@ xar_options(struct archive_write *a, const char *key, const char *value)
 		else {
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
-			    "Unkonwn compression name: `%s'",
+			    "Unknown compression name: `%s'",
 			    value);
 			return (ARCHIVE_FAILED);
 		}
@@ -468,7 +470,7 @@ xar_options(struct archive_write *a, const char *key, const char *value)
 		    value[1] != '\0') {
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
-			    "Illeagal value `%s'",
+			    "Illegal value `%s'",
 			    value);
 			return (ARCHIVE_FAILED);
 		}
@@ -485,14 +487,17 @@ xar_options(struct archive_write *a, const char *key, const char *value)
 		else {
 			archive_set_error(&(a->archive),
 			    ARCHIVE_ERRNO_MISC,
-			    "Unkonwn checksum name: `%s'",
+			    "Unknown checksum name: `%s'",
 			    value);
 			return (ARCHIVE_FAILED);
 		}
 		return (ARCHIVE_OK);
 	}
 
-	return (ARCHIVE_FAILED);
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
 }
 
 static int
@@ -621,11 +626,11 @@ static int
 write_to_temp(struct archive_write *a, const void *buff, size_t s)
 {
 	struct xar *xar;
-	unsigned char *p;
+	const unsigned char *p;
 	ssize_t ws;
 
 	xar = (struct xar *)a->format_data;
-	p = (unsigned char *)buff;
+	p = (const unsigned char *)buff;
 	while (s) {
 		ws = write(xar->temp_fd, p, s);
 		if (ws < 0) {
@@ -651,7 +656,7 @@ xar_write_data(struct archive_write *a, const void *buff, size_t s)
 	xar = (struct xar *)a->format_data;
 
 	if (s > xar->bytes_remaining)
-		s = xar->bytes_remaining;
+		s = (size_t)xar->bytes_remaining;
 	if (s == 0 || xar->cur_file == NULL)
 		return (0);
 	if (xar->cur_file->data.compression == NONE) {
@@ -676,7 +681,7 @@ xar_write_data(struct archive_write *a, const void *buff, size_t s)
 	}
 #if !defined(_WIN32) || defined(__CYGWIN__)
 	if (xar->bytes_remaining ==
-	    archive_entry_size(xar->cur_file->entry)) {
+	    (uint64_t)archive_entry_size(xar->cur_file->entry)) {
 		/*
 		 * Get the path of a shell script if so.
 		 */
@@ -732,7 +737,7 @@ xar_finish_entry(struct archive_write *a)
 		return (ARCHIVE_OK);
 
 	while (xar->bytes_remaining > 0) {
-		s = xar->bytes_remaining;
+		s = (size_t)xar->bytes_remaining;
 		if (s > a->null_length)
 			s = a->null_length;
 		w = xar_write_data(a, a->nulls, s);
@@ -756,7 +761,7 @@ xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,
 {
 	int r;
 
-	r = xmlTextWriterStartElement(writer, BAD_CAST(key));
+	r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
 	if (r < 0) {
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_MISC,
@@ -765,7 +770,7 @@ xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,
 	}
 	if (attrkey != NULL && attrvalue != NULL) {
 		r = xmlTextWriterWriteAttribute(writer,
-		    BAD_CAST(attrkey), BAD_CAST(attrvalue));
+		    BAD_CAST_CONST(attrkey), BAD_CAST_CONST(attrvalue));
 		if (r < 0) {
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_MISC,
@@ -774,7 +779,7 @@ xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,
 		}
 	}
 	if (value != NULL) {
-		r = xmlTextWriterWriteString(writer, BAD_CAST(value));
+		r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
 		if (r < 0) {
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_MISC,
@@ -801,7 +806,7 @@ xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,
 	if (value == NULL)
 		return (ARCHIVE_OK);
 	
-	r = xmlTextWriterStartElement(writer, BAD_CAST(key));
+	r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
 	if (r < 0) {
 		archive_set_error(&a->archive,
 		    ARCHIVE_ERRNO_MISC,
@@ -809,7 +814,7 @@ xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,
 		return (ARCHIVE_FATAL);
 	}
 	if (value != NULL) {
-		r = xmlTextWriterWriteString(writer, BAD_CAST(value));
+		r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
 		if (r < 0) {
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_MISC,
@@ -1062,7 +1067,7 @@ make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer,
 	} while (p != NULL);
 
 	if (n > 0) {
-		r = xmlTextWriterStartElement(writer, BAD_CAST(element));
+		r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(element));
 		if (r < 0) {
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_MISC,
@@ -1557,7 +1562,7 @@ make_toc(struct archive_write *a)
 			goto exit_toc;
 		}
 		r = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"),
-		    BAD_CAST(getalgname(xar->opt_toc_sumalg)));
+		    BAD_CAST_CONST(getalgname(xar->opt_toc_sumalg)));
 		if (r < 0) {
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_MISC,
@@ -1865,8 +1870,8 @@ static int
 file_cmp_node(const struct archive_rb_node *n1,
     const struct archive_rb_node *n2)
 {
-	struct file *f1 = (struct file *)n1;
-	struct file *f2 = (struct file *)n2;
+	const struct file *f1 = (const struct file *)n1;
+	const struct file *f2 = (const struct file *)n2;
 
 	return (strcmp(f1->basename.s, f2->basename.s));
 }
@@ -1874,7 +1879,7 @@ file_cmp_node(const struct archive_rb_node *n1,
 static int
 file_cmp_key(const struct archive_rb_node *n, const void *key)
 {
-	struct file *f = (struct file *)n;
+	const struct file *f = (const struct file *)n;
 
 	return (strcmp(f->basename.s, (const char *)key));
 }
@@ -1938,6 +1943,8 @@ file_create_virtual_dir(struct archive_write *a, struct xar *xar,
 {
 	struct file *file;
 
+	(void)xar; /* UNUSED */
+
 	file = file_new(a, NULL);
 	if (file == NULL)
 		return (NULL);
@@ -2464,8 +2471,8 @@ static int
 file_hd_cmp_node(const struct archive_rb_node *n1,
     const struct archive_rb_node *n2)
 {
-	struct hardlink *h1 = (struct hardlink *)n1;
-	struct hardlink *h2 = (struct hardlink *)n2;
+	const struct hardlink *h1 = (const struct hardlink *)n1;
+	const struct hardlink *h2 = (const struct hardlink *)n2;
 
 	return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
 		       archive_entry_pathname(h2->file_list.first->entry)));
@@ -2474,7 +2481,7 @@ file_hd_cmp_node(const struct archive_rb_node *n1,
 static int
 file_hd_cmp_key(const struct archive_rb_node *n, const void *key)
 {
-	struct hardlink *h = (struct hardlink *)n;
+	const struct hardlink *h = (const struct hardlink *)n;
 
 	return (strcmp(archive_entry_pathname(h->file_list.first->entry),
 		       (const char *)key));
@@ -2589,10 +2596,10 @@ compression_init_encoder_gzip(struct archive *a,
 	 * a non-const pointer. */
 	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
 	strm->avail_in = lastrm->avail_in;
-	strm->total_in = lastrm->total_in;
+	strm->total_in = (uLong)lastrm->total_in;
 	strm->next_out = lastrm->next_out;
 	strm->avail_out = lastrm->avail_out;
-	strm->total_out = lastrm->total_out;
+	strm->total_out = (uLong)lastrm->total_out;
 	if (deflateInit2(strm, level, Z_DEFLATED,
 	    (withheader)?15:-15,
 	    8, Z_DEFAULT_STRATEGY) != Z_OK) {
@@ -2622,10 +2629,10 @@ compression_code_gzip(struct archive *a,
 	 * a non-const pointer. */
 	strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
 	strm->avail_in = lastrm->avail_in;
-	strm->total_in = lastrm->total_in;
+	strm->total_in = (uLong)lastrm->total_in;
 	strm->next_out = lastrm->next_out;
 	strm->avail_out = lastrm->avail_out;
-	strm->total_out = lastrm->total_out;
+	strm->total_out = (uLong)lastrm->total_out;
 	r = deflate(strm,
 	    (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
 	lastrm->next_in = strm->next_in;
@@ -2861,6 +2868,7 @@ compression_init_encoder_xz(struct archive *a,
 	if (level > 6)
 		level = 6;
 	if (lzma_lzma_preset(&lzma_opt, level)) {
+		free(strm);
 		lastrm->real_stream = NULL;
 		archive_set_error(a, ENOMEM,
 		    "Internal error initializing compression library");
@@ -3082,8 +3090,10 @@ save_xattrs(struct archive_write *a, struct file *file)
 			checksum_update(&(xar->a_sumwrk), value, size);
 			checksum_final(&(xar->a_sumwrk), &(heap->a_sum));
 			if (write_to_temp(a, value, size)
-			    != ARCHIVE_OK)
+			    != ARCHIVE_OK) {
+				free(heap);
 				return (ARCHIVE_FATAL);
+			}
 			heap->length = size;
 			/* Add heap to the tail of file->xattr. */
 			heap->next = NULL;
diff --git a/libarchive/archive_write_set_format_zip.c b/libarchive/archive_write_set_format_zip.c
index f07a14f..3d8b3b5 100644
--- a/libarchive/archive_write_set_format_zip.c
+++ b/libarchive/archive_write_set_format_zip.c
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 2008 Anselm Strauss
  * Copyright (c) 2009 Joerg Sonnenberger
- * Copyright (c) 2011 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -109,69 +109,75 @@ static unsigned int dos_time(const time_t);
 static size_t path_length(struct archive_entry *);
 static int write_path(struct archive_entry *, struct archive_write *);
 
-struct zip_local_file_header {
-	char signature[4];
-	char version[2];
-	char flags[2];
-	char compression[2];
-	char timedate[4];
-	char crc32[4];
-	char compressed_size[4];
-	char uncompressed_size[4];
-	char filename_length[2];
-	char extra_length[2];
-};
-
-struct zip_file_header {
-	char signature[4];
-	char version_by[2];
-	char version_extract[2];
-	char flags[2];
-	char compression[2];
-	char timedate[4];
-	char crc32[4];
-	char compressed_size[4];
-	char uncompressed_size[4];
-	char filename_length[2];
-	char extra_length[2];
-	char comment_length[2];
-	char disk_number[2];
-	char attributes_internal[2];
-	char attributes_external[4];
-	char offset[4];
-};
-
-struct zip_data_descriptor {
-	char signature[4]; /* Not mandatory, but recommended by specification. */
-	char crc32[4];
-	char compressed_size[4];
-	char uncompressed_size[4];
-};
-
-struct zip_extra_data_local {
-	char time_id[2];
-	char time_size[2];
-	char time_flag[1];
-	char mtime[4];
-	char atime[4];
-	char ctime[4];
-	char unix_id[2];
-	char unix_size[2];
-	char unix_version;
-	char unix_uid_size;
-	char unix_uid[4];
-	char unix_gid_size;
-	char unix_gid[4];
-};
-
-struct zip_extra_data_central {
-	char time_id[2];
-	char time_size[2];
-	char time_flag[1];
-	char mtime[4];
-	char unix_id[2];
-	char unix_size[2];
-};
+#define LOCAL_FILE_HEADER_SIGNATURE		0
+#define LOCAL_FILE_HEADER_VERSION		4
+#define LOCAL_FILE_HEADER_FLAGS			6
+#define LOCAL_FILE_HEADER_COMPRESSION		8
+#define LOCAL_FILE_HEADER_TIMEDATE		10
+#define LOCAL_FILE_HEADER_CRC32			14
+#define LOCAL_FILE_HEADER_COMPRESSED_SIZE	18
+#define LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE	22
+#define LOCAL_FILE_HEADER_FILENAME_LENGTH	26
+#define LOCAL_FILE_HEADER_EXTRA_LENGTH		28
+#define SIZE_LOCAL_FILE_HEADER			30
+
+#define FILE_HEADER_SIGNATURE			0
+#define FILE_HEADER_VERSION_BY			4
+#define FILE_HEADER_VERSION_EXTRACT		6
+#define FILE_HEADER_FLAGS			8
+#define FILE_HEADER_COMPRESSION			10
+#define FILE_HEADER_TIMEDATE			12
+#define FILE_HEADER_CRC32			16
+#define FILE_HEADER_COMPRESSED_SIZE		20
+#define FILE_HEADER_UNCOMPRESSED_SIZE		24
+#define FILE_HEADER_FILENAME_LENGTH		28
+#define FILE_HEADER_EXTRA_LENGTH		30
+#define FILE_HEADER_COMMENT_LENGTH		32
+#define FILE_HEADER_DISK_NUMBER			34
+#define FILE_HEADER_ATTRIBUTES_INTERNAL		36
+#define FILE_HEADER_ATTRIBUTES_EXTERNAL		38
+#define FILE_HEADER_OFFSET			42
+#define SIZE_FILE_HEADER			46
+
+	/* Not mandatory, but recommended by specification. */
+#define DATA_DESCRIPTOR_SIGNATURE		0
+#define DATA_DESCRIPTOR_CRC32			4
+#define DATA_DESCRIPTOR_COMPRESSED_SIZE		8
+#define DATA_DESCRIPTOR_UNCOMPRESSED_SIZE	12
+#define SIZE_DATA_DESCRIPTOR			16
+
+#define EXTRA_DATA_LOCAL_TIME_ID		0
+#define EXTRA_DATA_LOCAL_TIME_SIZE		2
+#define EXTRA_DATA_LOCAL_TIME_FLAG		4
+#define EXTRA_DATA_LOCAL_MTIME			5
+#define EXTRA_DATA_LOCAL_ATIME			9
+#define EXTRA_DATA_LOCAL_CTIME			13
+#define EXTRA_DATA_LOCAL_UNIX_ID		17
+#define EXTRA_DATA_LOCAL_UNIX_SIZE		19
+#define EXTRA_DATA_LOCAL_UNIX_VERSION		21
+#define EXTRA_DATA_LOCAL_UNIX_UID_SIZE		22
+#define EXTRA_DATA_LOCAL_UNIX_UID		23
+#define EXTRA_DATA_LOCAL_UNIX_GID_SIZE		27
+#define EXTRA_DATA_LOCAL_UNIX_GID		28
+#define SIZE_EXTRA_DATA_LOCAL			32
+
+#define EXTRA_DATA_CENTRAL_TIME_ID		0
+#define EXTRA_DATA_CENTRAL_TIME_SIZE		2
+#define EXTRA_DATA_CENTRAL_TIME_FLAG		4
+#define EXTRA_DATA_CENTRAL_MTIME		5
+#define EXTRA_DATA_CENTRAL_UNIX_ID		9
+#define EXTRA_DATA_CENTRAL_UNIX_SIZE		11
+#define SIZE_EXTRA_DATA_CENTRAL			13
+
+#define CENTRAL_DIRECTORY_END_SIGNATURE		0
+#define CENTRAL_DIRECTORY_END_DISK		4
+#define CENTRAL_DIRECTORY_END_START_DISK	6
+#define CENTRAL_DIRECTORY_END_ENTRIES_DISK	8
+#define CENTRAL_DIRECTORY_END_ENTRIES		10
+#define CENTRAL_DIRECTORY_END_SIZE		12
+#define CENTRAL_DIRECTORY_END_OFFSET		16
+#define CENTRAL_DIRECTORY_END_COMMENT_LENGTH	20
+#define SIZE_CENTRAL_DIRECTORY_END		22
 
 struct zip_file_header_link {
 	struct zip_file_header_link *next;
@@ -184,7 +190,7 @@ struct zip_file_header_link {
 };
 
 struct zip {
-	struct zip_data_descriptor data_descriptor;
+	uint8_t data_descriptor[SIZE_DATA_DESCRIPTOR];
 	struct zip_file_header_link *central_directory;
 	struct zip_file_header_link *central_directory_end;
 	int64_t offset;
@@ -203,17 +209,6 @@ struct zip {
 #endif
 };
 
-struct zip_central_directory_end {
-	char signature[4];
-	char disk[2];
-	char start_disk[2];
-	char entries_disk[2];
-	char entries[2];
-	char size[4];
-	char offset[4];
-	char comment_length[2];
-};
-
 static int
 archive_write_zip_options(struct archive_write *a, const char *key,
     const char *val)
@@ -238,6 +233,7 @@ archive_write_zip_options(struct archive_write *a, const char *key,
 			zip->compression = COMPRESSION_STORE;
 			ret = ARCHIVE_OK;
 		}
+		return (ret);
 	} else if (strcmp(key, "hdrcharset")  == 0) {
 		if (val == NULL || val[0] == 0) {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -251,9 +247,61 @@ archive_write_zip_options(struct archive_write *a, const char *key,
 			else
 				ret = ARCHIVE_FATAL;
 		}
-	} else
+		return (ret);
+	}
+
+	/* Note: The "warn" return is just to inform the options
+	 * supervisor that we didn't handle it.  It will generate
+	 * a suitable error if no one used this option. */
+	return (ARCHIVE_WARN);
+}
+
+int
+archive_write_zip_set_compression_deflate(struct archive *_a)
+{
+	struct archive_write *a = (struct archive_write *)_a;
+	int ret = ARCHIVE_FAILED;
+	
+	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+		ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER,
+		"archive_write_zip_set_compression_deflate");
+	if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+		"Can only use archive_write_zip_set_compression_deflate"
+		" with zip format");
+		ret = ARCHIVE_FATAL;
+	} else {
+#ifdef HAVE_ZLIB_H
+		struct zip *zip = a->format_data;
+		zip->compression = COMPRESSION_DEFLATE;
+		ret = ARCHIVE_OK;
+#else
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-		    "%s: unknown keyword ``%s''", a->format_name, key);
+			"deflate compression not supported");
+#endif
+	}
+	return (ret);
+}
+
+int
+archive_write_zip_set_compression_store(struct archive *_a)
+{
+	struct archive_write *a = (struct archive_write *)_a;
+	struct zip *zip = a->format_data;
+	int ret = ARCHIVE_FAILED;
+	
+	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+		ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER,
+		"archive_write_zip_set_compression_deflate");
+	if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			"Can only use archive_write_zip_set_compression_store"
+			" with zip format");
+		ret = ARCHIVE_FATAL;
+	} else {
+		zip->compression = COMPRESSION_STORE;
+		ret = ARCHIVE_OK;
+	}
 	return (ret);
 }
 
@@ -287,6 +335,7 @@ archive_write_set_format_zip(struct archive *_a)
 	zip->len_buf = 65536;
 	zip->buf = malloc(zip->len_buf);
 	if (zip->buf == NULL) {
+		free(zip);
 		archive_set_error(&a->archive, ENOMEM,
 		    "Can't allocate compression buffer");
 		return (ARCHIVE_FATAL);
@@ -306,7 +355,7 @@ archive_write_set_format_zip(struct archive *_a)
 	a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
 	a->archive.archive_format_name = "ZIP";
 
-	archive_le32enc(&zip->data_descriptor.signature,
+	archive_le32enc(&zip->data_descriptor[DATA_DESCRIPTOR_SIGNATURE],
 	    ZIP_SIGNATURE_DATA_DESCRIPTOR);
 
 	return (ARCHIVE_OK);
@@ -328,9 +377,9 @@ static int
 archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 {
 	struct zip *zip;
-	struct zip_local_file_header h;
-	struct zip_extra_data_local e;
-	struct zip_data_descriptor *d;
+	uint8_t h[SIZE_LOCAL_FILE_HEADER];
+	uint8_t e[SIZE_EXTRA_DATA_LOCAL];
+	uint8_t *d;
 	struct zip_file_header_link *l;
 	struct archive_string_conv *sconv;
 	int ret, ret2 = ARCHIVE_OK;
@@ -343,7 +392,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "Filetype not supported");
 		return ARCHIVE_FAILED;
-	}; 
+	};
 
 	/* Directory entries should have a size of 0. */
 	if (type == AE_IFDIR)
@@ -370,7 +419,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 #endif
 		}
 	}
-	d = &zip->data_descriptor;
+	d = zip->data_descriptor;
 	size = archive_entry_size(entry);
 	zip->remaining_data_bytes = size;
 
@@ -381,7 +430,21 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 		    "Can't allocate zip header data");
 		return (ARCHIVE_FATAL);
 	}
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	/* Make sure the path separators in pahtname, hardlink and symlink
+	 * are all slash '/', not the Windows path separator '\'. */
+	l->entry = __la_win_entry_in_posix_pathseparator(entry);
+	if (l->entry == entry)
+		l->entry = archive_entry_clone(entry);
+#else
 	l->entry = archive_entry_clone(entry);
+#endif
+	if (l->entry == NULL) {
+		archive_set_error(&a->archive, ENOMEM,
+		    "Can't allocate zip header data");
+		free(l);
+		return (ARCHIVE_FATAL);
+	}
 	l->flags = zip->flags;
 	if (zip->opt_sconv != NULL)
 		sconv = zip->opt_sconv;
@@ -393,21 +456,47 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 
 		if (archive_entry_pathname_l(entry, &p, &len, sconv) != 0) {
 			if (errno == ENOMEM) {
+				archive_entry_free(l->entry);
+				free(l);
 				archive_set_error(&a->archive, ENOMEM,
 				    "Can't allocate memory for Pathname");
 				return (ARCHIVE_FATAL);
 			}
 			archive_set_error(&a->archive,
 			    ARCHIVE_ERRNO_FILE_FORMAT,
-			    "Can't translate pathname '%s' to %s",
+			    "Can't translate Pathname '%s' to %s",
 			    archive_entry_pathname(entry),
 			    archive_string_conversion_charset_name(sconv));
 			ret2 = ARCHIVE_WARN;
 		}
 		if (len > 0)
 			archive_entry_set_pathname(l->entry, p);
+
+		/*
+		 * Although there is no character-set regulation for Symlink,
+		 * it is suitable to convert a character-set of Symlinke to
+		 * what those of the Pathname has been converted to.
+		 */
+		if (type == AE_IFLNK) {
+			if (archive_entry_symlink_l(entry, &p, &len, sconv)) {
+				if (errno == ENOMEM) {
+					archive_entry_free(l->entry);
+					free(l);
+					archive_set_error(&a->archive, ENOMEM,
+					    "Can't allocate memory "
+					    " for Symlink");
+					return (ARCHIVE_FATAL);
+				}
+				/*
+				 * Even if the strng conversion failed,
+				 * we should not report the error since
+				 * thre is no regulation for.
+				 */
+			} else if (len > 0)
+				archive_entry_set_symlink(l->entry, p);
+		}
 	}
-	/* If all character of a filename is ASCII, Reset UTF-8 Name flag. */
+	/* If all characters in a filename are ASCII, Reset UTF-8 Name flag. */
 	if ((l->flags & ZIP_FLAGS_UTF8_NAME) != 0 &&
 	    is_all_ascii(archive_entry_pathname(l->entry)))
 		l->flags &= ~ZIP_FLAGS_UTF8_NAME;
@@ -440,13 +529,16 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 	 * directory. */
 	l->offset = zip->written_bytes;
 
-	memset(&h, 0, sizeof(h));
-	archive_le32enc(&h.signature, ZIP_SIGNATURE_LOCAL_FILE_HEADER);
-	archive_le16enc(&h.version, ZIP_VERSION_EXTRACT);
-	archive_le16enc(&h.flags, l->flags);
-	archive_le16enc(&h.compression, l->compression);
-	archive_le32enc(&h.timedate, dos_time(archive_entry_mtime(entry)));
-	archive_le16enc(&h.filename_length, (uint16_t)path_length(l->entry));
+	memset(h, 0, sizeof(h));
+	archive_le32enc(&h[LOCAL_FILE_HEADER_SIGNATURE],
+		ZIP_SIGNATURE_LOCAL_FILE_HEADER);
+	archive_le16enc(&h[LOCAL_FILE_HEADER_VERSION], ZIP_VERSION_EXTRACT);
+	archive_le16enc(&h[LOCAL_FILE_HEADER_FLAGS], l->flags);
+	archive_le16enc(&h[LOCAL_FILE_HEADER_COMPRESSION], l->compression);
+	archive_le32enc(&h[LOCAL_FILE_HEADER_TIMEDATE],
+		dos_time(archive_entry_mtime(entry)));
+	archive_le16enc(&h[LOCAL_FILE_HEADER_FILENAME_LENGTH],
+		(uint16_t)path_length(l->entry));
 
 	switch (l->compression) {
 	case COMPRESSION_STORE:
@@ -454,18 +546,21 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 		 * specification says to set to zero when using data
 		 * descriptors. Otherwise the end of the data for an
 		 * entry is rather difficult to find. */
-		archive_le32enc(&h.compressed_size, size);
-		archive_le32enc(&h.uncompressed_size, size);
+		archive_le32enc(&h[LOCAL_FILE_HEADER_COMPRESSED_SIZE],
+		    (uint32_t)size);
+		archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
+		    (uint32_t)size);
 		break;
 #ifdef HAVE_ZLIB_H
 	case COMPRESSION_DEFLATE:
-		archive_le32enc(&h.uncompressed_size, size);
+		archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
+		    (uint32_t)size);
 
 		zip->stream.zalloc = Z_NULL;
 		zip->stream.zfree = Z_NULL;
 		zip->stream.opaque = Z_NULL;
 		zip->stream.next_out = zip->buf;
-		zip->stream.avail_out = zip->len_buf;
+		zip->stream.avail_out = (uInt)zip->len_buf;
 		if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION,
 		    Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
 			archive_set_error(&a->archive, ENOMEM,
@@ -477,28 +572,33 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 	}
 
 	/* Formatting extra data. */
-	archive_le16enc(&h.extra_length, sizeof(e));
-	archive_le16enc(&e.time_id, ZIP_SIGNATURE_EXTRA_TIMESTAMP);
-	archive_le16enc(&e.time_size, sizeof(e.time_flag) +
-	    sizeof(e.mtime) + sizeof(e.atime) + sizeof(e.ctime));
-	e.time_flag[0] = 0x07;
-	archive_le32enc(&e.mtime, archive_entry_mtime(entry));
-	archive_le32enc(&e.atime, archive_entry_atime(entry));
-	archive_le32enc(&e.ctime, archive_entry_ctime(entry));
-
-	archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_NEW_UNIX);
-	archive_le16enc(&e.unix_size, sizeof(e.unix_version) +
-	    sizeof(e.unix_uid_size) + sizeof(e.unix_uid) +
-	    sizeof(e.unix_gid_size) + sizeof(e.unix_gid));
-	e.unix_version = 1;
-	e.unix_uid_size = 4;
-	archive_le32enc(&e.unix_uid, archive_entry_uid(entry));
-	e.unix_gid_size = 4;
-	archive_le32enc(&e.unix_gid, archive_entry_gid(entry));
-
-	archive_le32enc(&d->uncompressed_size, size);
-
-	ret = __archive_write_output(a, &h, sizeof(h));
+	archive_le16enc(&h[LOCAL_FILE_HEADER_EXTRA_LENGTH], sizeof(e));
+	archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_ID],
+		ZIP_SIGNATURE_EXTRA_TIMESTAMP);
+	archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_SIZE], 1 + 4 * 3);
+	e[EXTRA_DATA_LOCAL_TIME_FLAG] = 0x07;
+	archive_le32enc(&e[EXTRA_DATA_LOCAL_MTIME],
+	    (uint32_t)archive_entry_mtime(entry));
+	archive_le32enc(&e[EXTRA_DATA_LOCAL_ATIME],
+	    (uint32_t)archive_entry_atime(entry));
+	archive_le32enc(&e[EXTRA_DATA_LOCAL_CTIME],
+	    (uint32_t)archive_entry_ctime(entry));
+
+	archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_ID],
+		ZIP_SIGNATURE_EXTRA_NEW_UNIX);
+	archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_SIZE], 1 + (1 + 4) * 2);
+	e[EXTRA_DATA_LOCAL_UNIX_VERSION] = 1;
+	e[EXTRA_DATA_LOCAL_UNIX_UID_SIZE] = 4;
+	archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_UID],
+		(uint32_t)archive_entry_uid(entry));
+	e[EXTRA_DATA_LOCAL_UNIX_GID_SIZE] = 4;
+	archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_GID],
+		(uint32_t)archive_entry_gid(entry));
+
+	archive_le32enc(&d[DATA_DESCRIPTOR_UNCOMPRESSED_SIZE],
+	    (uint32_t)size);
+
+	ret = __archive_write_output(a, h, sizeof(h));
 	if (ret != ARCHIVE_OK)
 		return (ARCHIVE_FATAL);
 	zip->written_bytes += sizeof(h);
@@ -508,7 +608,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 		return (ARCHIVE_FATAL);
 	zip->written_bytes += ret;
 
-	ret = __archive_write_output(a, &e, sizeof(e));
+	ret = __archive_write_output(a, e, sizeof(e));
 	if (ret != ARCHIVE_OK)
 		return (ARCHIVE_FATAL);
 	zip->written_bytes += sizeof(e);
@@ -517,11 +617,11 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 		const unsigned char *p;
 
 		p = (const unsigned char *)archive_entry_symlink(l->entry);
-		ret = __archive_write_output(a, p, size);
+		ret = __archive_write_output(a, p, (size_t)size);
 		if (ret != ARCHIVE_OK)
 			return (ARCHIVE_FATAL);
 		zip->written_bytes += size;
-		l->crc32 = crc32(l->crc32, p, size);
+		l->crc32 = crc32(l->crc32, p, (unsigned)size);
 	}
 
 	if (ret2 != ARCHIVE_OK)
@@ -548,12 +648,12 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
 		zip->written_bytes += s;
 		zip->remaining_data_bytes -= s;
 		l->compressed_size += s;
-		l->crc32 = crc32(l->crc32, buff, s);
+		l->crc32 = crc32(l->crc32, buff, (unsigned)s);
 		return (s);
 #if HAVE_ZLIB_H
 	case COMPRESSION_DEFLATE:
 		zip->stream.next_in = (unsigned char*)(uintptr_t)buff;
-		zip->stream.avail_in = s;
+		zip->stream.avail_in = (uInt)s;
 		do {
 			ret = deflate(&zip->stream, Z_NO_FLUSH);
 			if (ret == Z_STREAM_ERROR)
@@ -566,12 +666,12 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
 				l->compressed_size += zip->len_buf;
 				zip->written_bytes += zip->len_buf;
 				zip->stream.next_out = zip->buf;
-				zip->stream.avail_out = zip->len_buf;
+				zip->stream.avail_out = (uInt)zip->len_buf;
 			}
 		} while (zip->stream.avail_in != 0);
 		zip->remaining_data_bytes -= s;
 		/* If we have it, use zlib's fast crc32() */
-		l->crc32 = crc32(l->crc32, buff, s);
+		l->crc32 = crc32(l->crc32, buff, (uInt)s);
 		return (s);
 #endif
 
@@ -588,7 +688,7 @@ archive_write_zip_finish_entry(struct archive_write *a)
 	/* Write the data descripter after file data has been written. */
 	int ret;
 	struct zip *zip = a->format_data;
-	struct zip_data_descriptor *d = &zip->data_descriptor;
+	uint8_t *d = zip->data_descriptor;
 	struct zip_file_header_link *l = zip->central_directory_end;
 #if HAVE_ZLIB_H
 	size_t reminder;
@@ -612,19 +712,20 @@ archive_write_zip_finish_entry(struct archive_write *a)
 			zip->stream.next_out = zip->buf;
 			if (zip->stream.avail_out != 0)
 				break;
-			zip->stream.avail_out = zip->len_buf;
+			zip->stream.avail_out = (uInt)zip->len_buf;
 		}
 		deflateEnd(&zip->stream);
 		break;
 #endif
 	}
 
-	archive_le32enc(&d->crc32, l->crc32);
-	archive_le32enc(&d->compressed_size, l->compressed_size);
-	ret = __archive_write_output(a, d, sizeof(*d));
+	archive_le32enc(&d[DATA_DESCRIPTOR_CRC32], l->crc32);
+	archive_le32enc(&d[DATA_DESCRIPTOR_COMPRESSED_SIZE],
+		(uint32_t)l->compressed_size);
+	ret = __archive_write_output(a, d, SIZE_DATA_DESCRIPTOR);
 	if (ret != ARCHIVE_OK)
 		return (ARCHIVE_FATAL);
-	zip->written_bytes += sizeof(*d);
+	zip->written_bytes += SIZE_DATA_DESCRIPTOR;
 	return (ARCHIVE_OK);
 }
 
@@ -633,9 +734,9 @@ archive_write_zip_close(struct archive_write *a)
 {
 	struct zip *zip;
 	struct zip_file_header_link *l;
-	struct zip_file_header h;
-	struct zip_central_directory_end end;
-	struct zip_extra_data_central e;
+	uint8_t h[SIZE_FILE_HEADER];
+	uint8_t end[SIZE_CENTRAL_DIRECTORY_END];
+	uint8_t e[SIZE_EXTRA_DATA_CENTRAL];
 	int64_t offset_start, offset_end;
 	int entries;
 	int ret;
@@ -652,10 +753,10 @@ archive_write_zip_close(struct archive_write *a)
 	 *   - disk_number
 	 *   - attributes_internal
 	 */
-	memset(&h, 0, sizeof(h));
-	archive_le32enc(&h.signature, ZIP_SIGNATURE_FILE_HEADER);
-	archive_le16enc(&h.version_by, ZIP_VERSION_BY);
-	archive_le16enc(&h.version_extract, ZIP_VERSION_EXTRACT);
+	memset(h, 0, sizeof(h));
+	archive_le32enc(&h[FILE_HEADER_SIGNATURE], ZIP_SIGNATURE_FILE_HEADER);
+	archive_le16enc(&h[FILE_HEADER_VERSION_BY], ZIP_VERSION_BY);
+	archive_le16enc(&h[FILE_HEADER_VERSION_EXTRACT], ZIP_VERSION_EXTRACT);
 
 	entries = 0;
 	offset_start = zip->written_bytes;
@@ -663,31 +764,34 @@ archive_write_zip_close(struct archive_write *a)
 	/* Formatting individual header fields per entry and
 	 * writing each entry. */
 	while (l != NULL) {
-		archive_le16enc(&h.flags, l->flags);
-		archive_le16enc(&h.compression, l->compression);
-		archive_le32enc(&h.timedate,
+		archive_le16enc(&h[FILE_HEADER_FLAGS], l->flags);
+		archive_le16enc(&h[FILE_HEADER_COMPRESSION], l->compression);
+		archive_le32enc(&h[FILE_HEADER_TIMEDATE],
 			dos_time(archive_entry_mtime(l->entry)));
-		archive_le32enc(&h.crc32, l->crc32);
-		archive_le32enc(&h.compressed_size, l->compressed_size);
-		archive_le32enc(&h.uncompressed_size,
-			archive_entry_size(l->entry));
-		archive_le16enc(&h.filename_length,
+		archive_le32enc(&h[FILE_HEADER_CRC32], l->crc32);
+		archive_le32enc(&h[FILE_HEADER_COMPRESSED_SIZE],
+			(uint32_t)l->compressed_size);
+		archive_le32enc(&h[FILE_HEADER_UNCOMPRESSED_SIZE],
+			(uint32_t)archive_entry_size(l->entry));
+		archive_le16enc(&h[FILE_HEADER_FILENAME_LENGTH],
 			(uint16_t)path_length(l->entry));
-		archive_le16enc(&h.extra_length, sizeof(e));
-		archive_le16enc(&h.attributes_external[2],
+		archive_le16enc(&h[FILE_HEADER_EXTRA_LENGTH], sizeof(e));
+		archive_le16enc(&h[FILE_HEADER_ATTRIBUTES_EXTERNAL+2],
 			archive_entry_mode(l->entry));
-		archive_le32enc(&h.offset, l->offset);
+		archive_le32enc(&h[FILE_HEADER_OFFSET], (uint32_t)l->offset);
 
 		/* Formatting extra data. */
-		archive_le16enc(&e.time_id, ZIP_SIGNATURE_EXTRA_TIMESTAMP);
-		archive_le16enc(&e.time_size,
-			sizeof(e.mtime) + sizeof(e.time_flag));
-		e.time_flag[0] = 0x07;
-		archive_le32enc(&e.mtime, archive_entry_mtime(l->entry));
-		archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_NEW_UNIX);
-		archive_le16enc(&e.unix_size, 0x0000);
-
-		ret = __archive_write_output(a, &h, sizeof(h));
+		archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_ID],
+			ZIP_SIGNATURE_EXTRA_TIMESTAMP);
+		archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_SIZE], 1 + 4);
+		e[EXTRA_DATA_CENTRAL_TIME_FLAG] = 0x07;
+		archive_le32enc(&e[EXTRA_DATA_CENTRAL_MTIME],
+			(uint32_t)archive_entry_mtime(l->entry));
+		archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_ID],
+			ZIP_SIGNATURE_EXTRA_NEW_UNIX);
+		archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_SIZE], 0x0000);
+
+		ret = __archive_write_output(a, h, sizeof(h));
 		if (ret != ARCHIVE_OK)
 			return (ARCHIVE_FATAL);
 		zip->written_bytes += sizeof(h);
@@ -697,7 +801,7 @@ archive_write_zip_close(struct archive_write *a)
 			return (ARCHIVE_FATAL);
 		zip->written_bytes += ret;
 
-		ret = __archive_write_output(a, &e, sizeof(e));
+		ret = __archive_write_output(a, e, sizeof(e));
 		if (ret != ARCHIVE_OK)
 			return (ARCHIVE_FATAL);
 		zip->written_bytes += sizeof(e);
@@ -708,15 +812,18 @@ archive_write_zip_close(struct archive_write *a)
 	offset_end = zip->written_bytes;
 
 	/* Formatting end of central directory. */
-	memset(&end, 0, sizeof(end));
-	archive_le32enc(&end.signature, ZIP_SIGNATURE_CENTRAL_DIRECTORY_END);
-	archive_le16enc(&end.entries_disk, entries);
-	archive_le16enc(&end.entries, entries);
-	archive_le32enc(&end.size, offset_end - offset_start);
-	archive_le32enc(&end.offset, offset_start);
+	memset(end, 0, sizeof(end));
+	archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIGNATURE],
+		ZIP_SIGNATURE_CENTRAL_DIRECTORY_END);
+	archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES_DISK], entries);
+	archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES], entries);
+	archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIZE],
+		(uint32_t)(offset_end - offset_start));
+	archive_le32enc(&end[CENTRAL_DIRECTORY_END_OFFSET],
+		(uint32_t)offset_start);
 
 	/* Writing end of central directory. */
-	ret = __archive_write_output(a, &end, sizeof(end));
+	ret = __archive_write_output(a, end, sizeof(end));
 	if (ret != ARCHIVE_OK)
 		return (ARCHIVE_FATAL);
 	zip->written_bytes += sizeof(end);
@@ -784,7 +891,10 @@ path_length(struct archive_entry *entry)
 	type = archive_entry_filetype(entry);
 	path = archive_entry_pathname(entry);
 
-	if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
+	if (path == NULL)
+		return (0);
+	if (type == AE_IFDIR &&
+	    (path[0] == '\0' || path[strlen(path) - 1] != '/')) {
 		return strlen(path) + 1;
 	} else {
 		return strlen(path);
diff --git a/libarchive/archive_write_set_options.3 b/libarchive/archive_write_set_options.3
index 9a8ea3d..9d60515 100644
--- a/libarchive/archive_write_set_options.3
+++ b/libarchive/archive_write_set_options.3
@@ -22,9 +22,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/lib/libarchive/archive_write.3 201110 2009-12-28 03:31:29Z kientzle $
+.\" $FreeBSD$
 .\"
-.Dd Feb 27, 2010
+.Dd February 2, 2012
 .Dt ARCHIVE_WRITE_OPTIONS 3
 .Os
 .Sh NAME
@@ -33,8 +33,8 @@
 .Nm archive_write_set_option ,
 .Nm archive_write_set_options
 .Nd functions controlling options for reading archives
-.Sh SYNOPSIS
-.\"
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
 .Sh SYNOPSIS
 .Ft int
 .Fo archive_write_set_filter_option
diff --git a/libarchive/archive_write_set_options.c b/libarchive/archive_write_set_options.c
index a8c2d23..962309a 100644
--- a/libarchive/archive_write_set_options.c
+++ b/libarchive/archive_write_set_options.c
@@ -78,11 +78,13 @@ archive_set_format_option(struct archive *_a, const char *m, const char *o,
 	struct archive_write *a = (struct archive_write *)_a;
 
 	if (a->format_name == NULL)
-		return (ARCHIVE_FAILED);
+		return (m == NULL)?ARCHIVE_FAILED:ARCHIVE_WARN - 1;
+	/* If the format name didn't match, return a special code for
+	 * _archive_set_option[s]. */
 	if (m != NULL && strcmp(m, a->format_name) != 0)
-		return (ARCHIVE_FAILED);
+		return (ARCHIVE_WARN - 1);
 	if (a->format_options == NULL)
-		return (ARCHIVE_FAILED);
+		return (ARCHIVE_WARN);
 	return a->format_options(a, o, v);
 }
 
@@ -92,7 +94,7 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o,
 {
 	struct archive_write *a = (struct archive_write *)_a;
 	struct archive_write_filter *filter;
-	int r, rv = ARCHIVE_FAILED;
+	int r, rv = ARCHIVE_WARN;
 
 	for (filter = a->filter_first; filter != NULL; filter = filter->next_filter) {
 		if (filter->options == NULL)
@@ -111,6 +113,10 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o,
 		if (r == ARCHIVE_OK)
 			rv = ARCHIVE_OK;
 	}
+	/* If the filter name didn't match, return a special code for
+	 * _archive_set_option[s]. */
+	if (rv == ARCHIVE_WARN && m != NULL)
+		rv = ARCHIVE_WARN - 1;
 	return (rv);
 }
 
diff --git a/libarchive/cpio.5 b/libarchive/cpio.5
index 13a4445..1a2886f 100644
--- a/libarchive/cpio.5
+++ b/libarchive/cpio.5
@@ -22,9 +22,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libarchive/cpio.5,v 1.2 2008/05/26 17:00:23 kientzle Exp $
+.\" $FreeBSD$
 .\"
-.Dd October 5, 2007
+.Dd December 23, 2011
 .Dt CPIO 5
 .Os
 .Sh NAME
diff --git a/libarchive/filter_fork.h b/libarchive/filter_fork.h
index 453d032..a28272b 100644
--- a/libarchive/filter_fork.h
+++ b/libarchive/filter_fork.h
@@ -33,7 +33,7 @@
 #define FILTER_FORK_H
 
 pid_t
-__archive_create_child(const char *path, int *child_stdin, int *child_stdout);
+__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout);
 
 void
 __archive_check_child(int in, int out);
diff --git a/libarchive/filter_fork.c b/libarchive/filter_fork_posix.c
similarity index 62%
rename from libarchive/filter_fork.c
rename to libarchive/filter_fork_posix.c
index d160524..02dbd4b 100644
--- a/libarchive/filter_fork.c
+++ b/libarchive/filter_fork_posix.c
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2007 Joerg Sonnenberger
+ * Copyright (c) 2012 Michihiro NAKAJIMA 
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,10 +28,19 @@
 
 /* This capability is only available on POSIX systems. */
 #if defined(HAVE_PIPE) && defined(HAVE_FCNTL) && \
-    (defined(HAVE_FORK) || defined(HAVE_VFORK))
+    (defined(HAVE_FORK) || defined(HAVE_VFORK) || defined(HAVE_POSIX_SPAWNP))
 
 __FBSDID("$FreeBSD: head/lib/libarchive/filter_fork.c 182958 2008-09-12 05:33:00Z kientzle $");
 
+#if defined(HAVE_SYS_TYPES_H)
+#  include <sys/types.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#  include <errno.h>
+#endif
+#ifdef HAVE_STRING_H
+#  include <string.h>
+#endif
 #if defined(HAVE_POLL) && (defined(HAVE_POLL_H) || defined(HAVE_SYS_POLL_H))
 #  if defined(HAVE_POLL_H)
 #    include <poll.h>
@@ -47,17 +57,37 @@ __FBSDID("$FreeBSD: head/lib/libarchive/filter_fork.c 182958 2008-09-12 05:33:00
 #ifdef HAVE_FCNTL_H
 #  include <fcntl.h>
 #endif
+#ifdef HAVE_SPAWN_H
+#  include <spawn.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+#endif
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
 
+#include "archive.h"
+#include "archive_cmdline_private.h"
+
 #include "filter_fork.h"
 
 pid_t
-__archive_create_child(const char *path, int *child_stdin, int *child_stdout)
+__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
 {
 	pid_t child;
 	int stdin_pipe[2], stdout_pipe[2], tmp;
+#if HAVE_POSIX_SPAWNP
+	posix_spawn_file_actions_t actions;
+	int r;
+#endif
+	struct archive_cmdline *cmdline;
+
+	cmdline = __archive_cmdline_allocate();
+	if (cmdline == NULL)
+		goto state_allocated;
+	if (__archive_cmdline_parse(cmdline, cmd) != ARCHIVE_OK)
+		goto state_allocated;
 
 	if (pipe(stdin_pipe) == -1)
 		goto state_allocated;
@@ -76,14 +106,53 @@ __archive_create_child(const char *path, int *child_stdin, int *child_stdout)
 		stdout_pipe[1] = tmp;
 	}
 
+#if HAVE_POSIX_SPAWNP
+
+	r = posix_spawn_file_actions_init(&actions);
+	if (r != 0) {
+		errno = r;
+		goto stdout_opened;
+	}
+	r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[1]);
+	if (r != 0)
+		goto actions_inited;
+	r = posix_spawn_file_actions_addclose(&actions, stdout_pipe[0]);
+	if (r != 0)
+		goto actions_inited;
+	/* Setup for stdin. */
+	r = posix_spawn_file_actions_adddup2(&actions, stdin_pipe[0], 0);
+	if (r != 0)
+		goto actions_inited;
+	if (stdin_pipe[0] != 0 /* stdin */) {
+		r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[0]);
+		if (r != 0)
+			goto actions_inited;
+	}
+	/* Setup for stdout. */
+	r = posix_spawn_file_actions_adddup2(&actions, stdout_pipe[1], 1);
+	if (r != 0)
+		goto actions_inited;
+	if (stdout_pipe[1] != 1 /* stdout */) {
+		r = posix_spawn_file_actions_addclose(&actions, stdout_pipe[1]);
+		if (r != 0)
+			goto actions_inited;
+	}
+	r = posix_spawnp(&child, cmdline->path, &actions, NULL,
+		cmdline->argv, NULL);
+	if (r != 0)
+		goto actions_inited;
+	posix_spawn_file_actions_destroy(&actions);
+
+#else /* HAVE_POSIX_SPAWNP */
+
 #if HAVE_VFORK
-	switch ((child = vfork())) {
+	child = vfork();
 #else
-	switch ((child = fork())) {
+	child = fork();
 #endif
-	case -1:
+	if (child == -1)
 		goto stdout_opened;
-	case 0:
+	if (child == 0) {
 		close(stdin_pipe[1]);
 		close(stdout_pipe[0]);
 		if (dup2(stdin_pipe[0], 0 /* stdin */) == -1)
@@ -94,20 +163,27 @@ __archive_create_child(const char *path, int *child_stdin, int *child_stdout)
 			_exit(254);
 		if (stdout_pipe[1] != 1 /* stdout */)
 			close(stdout_pipe[1]);
-		execlp(path, path, (char *)NULL);
+		execvp(cmdline->path, cmdline->argv);
 		_exit(254);
-	default:
-		close(stdin_pipe[0]);
-		close(stdout_pipe[1]);
-
-		*child_stdin = stdin_pipe[1];
-		fcntl(*child_stdin, F_SETFL, O_NONBLOCK);
-		*child_stdout = stdout_pipe[0];
-		fcntl(*child_stdout, F_SETFL, O_NONBLOCK);
 	}
+#endif /* HAVE_POSIX_SPAWNP */
+
+	close(stdin_pipe[0]);
+	close(stdout_pipe[1]);
+
+	*child_stdin = stdin_pipe[1];
+	fcntl(*child_stdin, F_SETFL, O_NONBLOCK);
+	*child_stdout = stdout_pipe[0];
+	fcntl(*child_stdout, F_SETFL, O_NONBLOCK);
+	__archive_cmdline_free(cmdline);
 
 	return child;
 
+#if HAVE_POSIX_SPAWNP
+actions_inited:
+	errno = r;
+	posix_spawn_file_actions_destroy(&actions);
+#endif
 stdout_opened:
 	close(stdout_pipe[0]);
 	close(stdout_pipe[1]);
@@ -115,6 +191,7 @@ stdin_opened:
 	close(stdin_pipe[0]);
 	close(stdin_pipe[1]);
 state_allocated:
+	__archive_cmdline_free(cmdline);
 	return -1;
 }
 
diff --git a/libarchive/filter_fork_windows.c b/libarchive/filter_fork_windows.c
index 272e56c..fa59cc9 100644
--- a/libarchive/filter_fork_windows.c
+++ b/libarchive/filter_fork_windows.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2009 Michihiro NAKAJIMA
+ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,17 +26,100 @@
 #include "archive_platform.h"
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
+#include "archive_cmdline_private.h"
+#include "archive_string.h"
 
 #include "filter_fork.h"
 
 pid_t
-__archive_create_child(const char *path, int *child_stdin, int *child_stdout)
+__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
 {
 	HANDLE childStdout[2], childStdin[2],childStderr;
 	SECURITY_ATTRIBUTES secAtts;
 	STARTUPINFO staInfo;
 	PROCESS_INFORMATION childInfo;
-	char cmd[MAX_PATH];
+	struct archive_string cmdline;
+	struct archive_string fullpath;
+	struct archive_cmdline *acmd;
+	char *arg0, *ext;
+	int i, l;
+	DWORD fl, fl_old;
+
+	childStdout[0] = childStdout[1] = INVALID_HANDLE_VALUE;
+	childStdin[0] = childStdin[1] = INVALID_HANDLE_VALUE;
+	childStderr = INVALID_HANDLE_VALUE;
+	archive_string_init(&cmdline);
+	archive_string_init(&fullpath);
+
+	acmd = __archive_cmdline_allocate();
+	if (acmd == NULL)
+		goto fail;
+	if (__archive_cmdline_parse(acmd, cmd) != ARCHIVE_OK)
+		goto fail;
+
+	/*
+	 * Search the full path of 'path'.
+	 * NOTE: This does not need if we give CreateProcessA 'path' as
+	 * a part of the cmdline and give CreateProcessA NULL as first
+	 * parameter, but I do not like that way.
+	 */
+	ext = strrchr(acmd->path, '.');
+	if (ext == NULL || strlen(ext) > 4)
+		/* 'path' does not have a proper extension, so we have to
+		 * give SearchPath() ".exe" as the extension. */
+		ext = ".exe";
+	else
+		ext = NULL;/* 'path' has an extension. */
+
+	fl = MAX_PATH;
+	do {
+		if (archive_string_ensure(&fullpath, fl) == NULL)
+			goto fail;
+		fl_old = fl;
+		fl = SearchPathA(NULL, acmd->path, ext, fl, fullpath.s,
+			&arg0);
+	} while (fl != 0 && fl > fl_old);
+	if (fl == 0)
+		goto fail;
+
+	/*
+	 * Make a command line.
+	 */
+	for (l = 0, i = 0;  acmd->argv[i] != NULL; i++) {
+		if (i == 0)
+			continue;
+		l += (int)strlen(acmd->argv[i]) + 1;
+	}
+	if (archive_string_ensure(&cmdline, l + 1) == NULL)
+		goto fail;
+	for (i = 0;  acmd->argv[i] != NULL; i++) {
+		if (i == 0) {
+			const char *p, *sp;
+
+			if ((p = strchr(acmd->argv[i], '/')) != NULL ||
+			    (p = strchr(acmd->argv[i], '\\')) != NULL)
+				p++;
+			else
+				p = acmd->argv[i];
+			if ((sp = strchr(p, ' ')) != NULL)
+				archive_strappend_char(&cmdline, '"');
+			archive_strcat(&cmdline, p);
+			if (sp != NULL)
+				archive_strappend_char(&cmdline, '"');
+		} else {
+			archive_strappend_char(&cmdline, ' ');
+			archive_strcat(&cmdline, acmd->argv[i]);
+		}
+	}
+	if (i <= 1) {
+		const char *sp;
+
+		if ((sp = strchr(arg0, ' ')) != NULL)
+			archive_strappend_char(&cmdline, '"');
+		archive_strcat(&cmdline, arg0);
+		if (sp != NULL)
+			archive_strappend_char(&cmdline, '"');
+	}
 
 	secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
 	secAtts.bInheritHandle = TRUE;
@@ -44,33 +127,15 @@ __archive_create_child(const char *path, int *child_stdin, int *child_stdout)
 	if (CreatePipe(&childStdout[0], &childStdout[1], &secAtts, 0) == 0)
 		goto fail;
 	if (!SetHandleInformation(childStdout[0], HANDLE_FLAG_INHERIT, 0))
-	{
-		CloseHandle(childStdout[0]);
-		CloseHandle(childStdout[1]);
 		goto fail;
-	}
-	if (CreatePipe(&childStdin[0], &childStdin[1], &secAtts, 0) == 0) {
-		CloseHandle(childStdout[0]);
-		CloseHandle(childStdout[1]);
+	if (CreatePipe(&childStdin[0], &childStdin[1], &secAtts, 0) == 0)
 		goto fail;
-	}
 	if (!SetHandleInformation(childStdin[1], HANDLE_FLAG_INHERIT, 0))
-	{
-		CloseHandle(childStdout[0]);
-		CloseHandle(childStdout[1]);
-		CloseHandle(childStdin[0]);
-		CloseHandle(childStdin[1]);
 		goto fail;
-	}
 	if (DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE),
 	    GetCurrentProcess(), &childStderr, 0, TRUE,
-	    DUPLICATE_SAME_ACCESS) == 0) {
-		CloseHandle(childStdout[0]);
-		CloseHandle(childStdout[1]);
-		CloseHandle(childStdin[0]);
-		CloseHandle(childStdin[1]);
+	    DUPLICATE_SAME_ACCESS) == 0)
 		goto fail;
-	}
 
 	memset(&staInfo, 0, sizeof(staInfo));
 	staInfo.cb = sizeof(staInfo);
@@ -79,17 +144,9 @@ __archive_create_child(const char *path, int *child_stdin, int *child_stdout)
 	staInfo.hStdInput = childStdin[0];
 	staInfo.wShowWindow = SW_HIDE;
 	staInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-	strncpy(cmd, path, sizeof(cmd)-1);
-	cmd[sizeof(cmd)-1] = '\0';
-	if (CreateProcessA(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL,
-	    &staInfo, &childInfo) == 0) {
-		CloseHandle(childStdout[0]);
-		CloseHandle(childStdout[1]);
-		CloseHandle(childStdin[0]);
-		CloseHandle(childStdin[1]);
-		CloseHandle(childStderr);
+	if (CreateProcessA(fullpath.s, cmdline.s, NULL, NULL, TRUE, 0,
+	      NULL, NULL, &staInfo, &childInfo) == 0)
 		goto fail;
-	}
 	WaitForInputIdle(childInfo.hProcess, INFINITE);
 	CloseHandle(childInfo.hProcess);
 	CloseHandle(childInfo.hThread);
@@ -100,17 +157,33 @@ __archive_create_child(const char *path, int *child_stdin, int *child_stdout)
 	CloseHandle(childStdout[1]);
 	CloseHandle(childStdin[0]);
 
+	archive_string_free(&cmdline);
+	archive_string_free(&fullpath);
+	__archive_cmdline_free(acmd);
 	return (childInfo.dwProcessId);
 
 fail:
+	if (childStdout[0] != INVALID_HANDLE_VALUE)
+		CloseHandle(childStdout[0]);
+	if (childStdout[1] != INVALID_HANDLE_VALUE)
+		CloseHandle(childStdout[1]);
+	if (childStdin[0] != INVALID_HANDLE_VALUE)
+		CloseHandle(childStdin[0]);
+	if (childStdin[1] != INVALID_HANDLE_VALUE)
+		CloseHandle(childStdin[1]);
+	if (childStderr != INVALID_HANDLE_VALUE)
+		CloseHandle(childStderr);
+	archive_string_free(&cmdline);
+	archive_string_free(&fullpath);
+	__archive_cmdline_free(acmd);
 	return (-1);
 }
 
 void
 __archive_check_child(int in, int out)
 {
-	(void)in; /* UNSED */
-	(void)out; /* UNSED */
+	(void)in; /* UNUSED */
+	(void)out; /* UNUSED */
 	Sleep(100);
 }
 
diff --git a/libarchive/libarchive-formats.5 b/libarchive/libarchive-formats.5
index d223bf8..4a709b3 100644
--- a/libarchive/libarchive-formats.5
+++ b/libarchive/libarchive-formats.5
@@ -22,9 +22,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/lib/libarchive/libarchive-formats.5 201077 2009-12-28 01:50:23Z kientzle $
+.\" $FreeBSD$
 .\"
-.Dd December 27, 2009
+.Dd March 18, 2012
 .Dt LIBARCHIVE-FORMATS 5
 .Os
 .Sh NAME
@@ -51,11 +51,11 @@ functions to enable all supported formats.
 The
 .Xr libarchive 3
 library can read most tar archives.
-However, it only writes POSIX-standard
+It can write POSIX-standard
 .Dq ustar
 and
 .Dq pax interchange
-formats.
+formats and a subset of the legacy GNU tar format.
 .Pp
 All tar formats store each entry in one or more 512-byte records.
 The first record is used for file metadata, including filename,
@@ -70,13 +70,18 @@ subsequent entries.
 .It Cm gnutar
 The
 .Xr libarchive 3
-library can read GNU-format tar archives.
+library can read most GNU-format tar archives.
 It currently supports the most popular GNU extensions, including
 modern long filename and linkname support, as well as atime and ctime data.
 The libarchive library does not support multi-volume
 archives, nor the old GNU long filename format.
 It can read GNU sparse file entries, including the new POSIX-based
-formats, but cannot write GNU sparse file entries.
+formats.
+.Pp
+The
+.Xr libarchive 3
+library can write GNU tar format, including long filename
+and linkname support, as well as atime and ctime data.
 .It Cm pax
 The
 .Xr libarchive 3
@@ -98,6 +103,14 @@ archiver and a few LIBARCHIVE keys.
 The libarchive library can read most of the SCHILY keys
 and most of the GNU keys introduced by GNU tar.
 It silently ignores any keywords that it does not understand.
+.Pp
+The pax interchange format converts filenames to Unicode
+and stores them using the UTF-8 encoding.
+Prior to libarchive 3.0, libarchive erroneously assumed
+that the system wide-character routines natively supported
+Unicode.
+This caused it to mis-handle non-ASCII filenames on systems
+that did not satisfy this assumption.
 .It Cm restricted pax
 The libarchive library can also write pax archives in which it
 attempts to suppress the extended attributes entry whenever
@@ -135,6 +148,8 @@ security information cannot be stored.
 Archive entries are limited to 8 gigabytes in size.
 .El
 Note that the pax interchange format has none of these restrictions.
+The ustar format is old and widely supported.
+It is recommended when compatibility is the primary concern.
 .El
 .Pp
 The libarchive library also reads a variety of commonly-used extensions to
@@ -268,19 +283,68 @@ If both extensions are present, the Joliet extensions will be
 used and the Rockridge extensions will be ignored.
 In particular, this can create problems with hardlinks and symlinks,
 which are supported by Rockridge but not by Joliet.
+.Pp
+Libarchive reads ISO9660 images using a streaming strategy.
+This allows it to read compressed images directly
+(decompressing on the fly) and allows it to read images
+directly from network sockets, pipes, and other non-seekable
+data sources.
+This strategy works well for optimized ISO9660 images created
+by many popular programs.
+Such programs collect all directory information at the beginning
+of the ISO9660 image so it can be read from a physical disk
+with a minimum of seeking.
+However, not all ISO9660 images can be read in this fashion.
+.Pp
+Libarchive can also write ISO9660 images.
+Such images are fully optimized with the directory information
+preceding all file data.
+This is done by storing all file data to a temporary file
+while collecting directory information in memory.
+When the image is finished, libarchive writes out the
+directory structure followed by the file data.
+The location used for the temporary file can be changed
+by the usual environment variables.
 .Ss Zip format
 Libarchive can read and write zip format archives that have
 uncompressed entries and entries compressed with the
 .Dq deflate
 algorithm.
-Older zip compression algorithms are not supported.
-It can extract jar archives, archives that use Zip64 extensions and many
+Other zip compression algorithms are not supported.
+It can extract jar archives, archives that use Zip64 extensions and
 self-extracting zip archives.
-Libarchive reads Zip archives as they are being streamed,
-which allows it to read archives of arbitrary size.
-It currently does not use the central directory; this
-limits libarchive's ability to support some self-extracting
-archives and ones that have been modified in certain ways.
+Libarchive can use either of two different strategies for
+reading Zip archives:
+a streaming strategy which is fast and can handle extremely
+large archives, and a seeking strategy which can correctly
+process self-extracting Zip archives and archives with
+deleted members or other in-place modifications.
+.Pp
+The streaming reader processes Zip archives as they are read.
+It can read archives of arbitrary size from tape or
+network sockets, and can decode Zip archives that have
+been separately compressed or encoded.
+However, self-extracting Zip archives and archives with
+certain types of modifications cannot be correctly
+handled.
+Such archives require that the reader first process the
+Central Directory, which is ordinarily located
+at the end of a Zip archive and is thus inaccessible
+to the streaming reader.
+If the program using libarchive has enabled seek support, then
+libarchive will use this to processes the central directory first.
+.Pp
+In particular, the seeking reader must be used to
+correctly handle self-extracting archives.
+Such archives consist of a program followed by a regular
+Zip archive.
+The streaming reader cannot parse the initial program
+portion, but the seeking reader starts by reading the
+Central Directory from the end of the archive.
+Similarly, Zip archives that have been modified in-place
+can have deleted entries or other garbage data that
+can only be accurately detected by first reading the
+Central Directory.
 .Ss Archive (library) file format
 The Unix archive format (commonly created by the
 .Xr ar 1
@@ -315,7 +379,7 @@ of a file hierarchy in which each line specifies the name of a file and
 provides specific metadata about that file.
 Libarchive can read all of the keywords supported by both
 the NetBSD and FreeBSD versions of
-.Xr mtree 1 ,
+.Xr mtree 8 ,
 although many of the keywords cannot currently be stored in an
 .Tn archive_entry
 object.
@@ -342,12 +406,18 @@ using libarchive.
 If it cannot locate and open the file on disk, libarchive
 will return an error for any attempt to read the entry
 body.
+.Ss LHA
+XXX Information about libarchive's LHA support XXX
+.Ss CAB
+XXX Information about libarchive's CAB support XXX
+.Ss XAR
+XXX Information about libarchive's XAR support XXX
 .Ss RAR
-libarchive has limited support to read files in RAR format. Currently,
-libarchive can read single RAR files in RARv3 format which have been either
-created uncompressed, or compressed using any of the compression methods
-supported by the RARv3 format. libarchive can also extract RAR files which have
-been created as self-extracting RAR files.
+Libarchive has limited support for reading RAR format archives.
+Currently, libarchive can read RARv3 format archives
+which have been either created uncompressed, or compressed using
+any of the compression methods supported by the RARv3 format.
+Libarchive can also read self-extracting RAR archives.
 .Sh SEE ALSO
 .Xr ar 1 ,
 .Xr cpio 1 ,
diff --git a/libarchive/libarchive.3 b/libarchive/libarchive.3
index d655404..3a9a841 100644
--- a/libarchive/libarchive.3
+++ b/libarchive/libarchive.3
@@ -22,16 +22,14 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libarchive/libarchive.3,v 1.11 2007/01/09 08:05:56 kientzle Exp $
+.\" $FreeBSD$
 .\"
-.Dd February 6, 2010
+.Dd March 18, 2012
 .Dt LIBARCHIVE 3
 .Os
 .Sh NAME
 .Nm libarchive
 .Nd functions for reading and writing streaming archives
-.Sh LIBRARY
-.Lb libarchive
 .Sh OVERVIEW
 The
 .Nm
@@ -66,15 +64,33 @@ most common cpio archive formats,
 .It
 ISO9660 CD images (including RockRidge and Joliet extensions),
 .It
-Zip archives.
+Zip archives,
+.It
+ar archives (including GNU/SysV and BSD extensions),
+.It
+Microsoft CAB archives,
+.It
+LHA archives,
+.It
+mtree file tree descriptions,
+.It
+RAR archives,
+.It
+XAR archives.
 .El
 The library automatically detects archives compressed with
 .Xr gzip 1 ,
 .Xr bzip2 1 ,
 .Xr xz 1 ,
+.Xr lzip 1 ,
 or
 .Xr compress 1
 and decompresses them transparently.
+It can similarly detect and decode archives processed with
+.Xr uuencode 1
+or which have an
+.Xr rpm 1
+header.
 .Pp
 When writing an archive, you can specify the compression
 to be used and the format to use.
@@ -93,7 +109,17 @@ POSIX octet-oriented cpio archives,
 .It
 Zip archive,
 .It
-two different variants of shar archives.
+two different variants of shar archives,
+.It
+ISO9660 CD images,
+.It
+7-Zip archives,
+.It
+ar archives,
+.It
+mtree file tree descriptions,
+.It
+XAR archives.
 .El
 Pax interchange format is an extension of the tar archive format that
 eliminates essentially all of the limitations of historic tar formats
@@ -145,9 +171,21 @@ operations.
 .Sh READING ENTRIES FROM DISK
 The
 .Xr archive_read_disk 3
-provides some support for populating
+supports for populating
 .Xr archive_entry 3
 objects from information in the filesystem.
+This includes the information accessible from the
+.Xr stat 2
+system call as well as ACLs, extended attributes,
+and other metadata.
+The
+.Xr archive_read_disk 3
+API also supports iterating over directory trees,
+which allows directories of files to be read using
+an API compatible with
+the
+.Xr archive_read 3
+API.
 .Sh DESCRIPTION
 Detailed descriptions of each function are provided by the
 corresponding manual pages.
@@ -227,7 +265,7 @@ library first appeared in
 .An -nosplit
 The
 .Nm libarchive
-library was written by
+library was originally written by
 .An Tim Kientzle Aq kientzle at acm.org .
 .Sh BUGS
 Some archive formats support information that is not supported by
@@ -244,13 +282,8 @@ is supported by all formats.
 For example, cpio formats do not support nanosecond timestamps;
 old tar formats do not support large device numbers.
 .Pp
-The
-.Xr archive_read_disk 3
-API should support iterating over filesystems;
-that would make it possible to share code among
-disk-to-archive, archive-to-archive, archive-to-disk,
-and disk-to-disk operations.
-Currently, it only supports reading the
-information for a single file.
-(Which is still quite useful, as it hides a lot
-of system-specific details.)
+The ISO9660 reader cannot yet read all ISO9660 images;
+it should learn how to seek.
+.Pp
+The AR writer requires the client program to use
+two passes, unlike all other libarchive writers.
diff --git a/libarchive/libarchive_changes.3 b/libarchive/libarchive_changes.3
index 6ee6af2..bacd6e1 100644
--- a/libarchive/libarchive_changes.3
+++ b/libarchive/libarchive_changes.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 27, 2011
+.Dd December 23, 2011
 .Dt LIBARCHIVE_CHANGES 3
 .Os
 .Sh NAME
diff --git a/libarchive/libarchive_internals.3 b/libarchive/libarchive_internals.3
index 776f4c3..4aa09f9 100644
--- a/libarchive/libarchive_internals.3
+++ b/libarchive/libarchive_internals.3
@@ -22,10 +22,10 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libarchive/libarchive_internals.3,v 1.2 2007/12/30 04:58:22 kientzle Exp $
+.\" $FreeBSD$
 .\"
-.Dd April 16, 2007
-.Dt LIBARCHIVE 3
+.Dd January 26, 2011
+.Dt LIBARCHIVE_INTERNALS 3
 .Os
 .Sh NAME
 .Nm libarchive_internals
diff --git a/libarchive/mtree.5 b/libarchive/mtree.5
index b6637d6..983fff7 100644
--- a/libarchive/mtree.5
+++ b/libarchive/mtree.5
@@ -28,7 +28,7 @@
 .\"     From: @(#)mtree.8       8.2 (Berkeley) 12/11/93
 .\" $FreeBSD$
 .\"
-.Dd August 20, 2007
+.Dd May 6, 2008
 .Dt MTREE 5
 .Os
 .Sh NAME
diff --git a/libarchive/tar.5 b/libarchive/tar.5
index 65875bd..688bb92 100644
--- a/libarchive/tar.5
+++ b/libarchive/tar.5
@@ -22,9 +22,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/lib/libarchive/tar.5 201077 2009-12-28 01:50:23Z kientzle $
+.\" $FreeBSD$
 .\"
-.Dd December 27, 2009
+.Dd December 23, 2011
 .Dt TAR 5
 .Os
 .Sh NAME

-----------------------------------------------------------------------

Summary of changes:


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list