Browse Source

Merge topic 'update-libarchive'

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)
Brad King 12 years ago
parent
commit
0cecc7b485
100 changed files with 11642 additions and 2391 deletions
  1. 263 63
      Utilities/cmlibarchive/CMakeLists.txt
  2. 4 4
      Utilities/cmlibarchive/README-CMake.txt
  3. 22 0
      Utilities/cmlibarchive/build/cmake/FindLibGCC.cmake
  4. 23 0
      Utilities/cmlibarchive/build/cmake/FindNettle.cmake
  5. 34 0
      Utilities/cmlibarchive/build/cmake/FindPCREPOSIX.cmake
  6. 45 6
      Utilities/cmlibarchive/build/cmake/config.h.in
  7. 42 5
      Utilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh
  8. 1 1
      Utilities/cmlibarchive/build/version
  9. 22 1
      Utilities/cmlibarchive/libarchive/CMakeLists.txt
  10. 263 45
      Utilities/cmlibarchive/libarchive/archive.h
  11. 48 34
      Utilities/cmlibarchive/libarchive/archive_acl.c
  12. 1 0
      Utilities/cmlibarchive/libarchive/archive_check_magic.c
  13. 227 0
      Utilities/cmlibarchive/libarchive/archive_cmdline.c
  14. 47 0
      Utilities/cmlibarchive/libarchive/archive_cmdline_private.h
  15. 5 3
      Utilities/cmlibarchive/libarchive/archive_crypto.c
  16. 4 4
      Utilities/cmlibarchive/libarchive/archive_endian.h
  17. 4 2
      Utilities/cmlibarchive/libarchive/archive_entry.3
  18. 71 10
      Utilities/cmlibarchive/libarchive/archive_entry.c
  19. 20 25
      Utilities/cmlibarchive/libarchive/archive_entry.h
  20. 4 2
      Utilities/cmlibarchive/libarchive/archive_entry_acl.3
  21. 3 3
      Utilities/cmlibarchive/libarchive/archive_entry_copy_bhfi.c
  22. 4 1
      Utilities/cmlibarchive/libarchive/archive_entry_link_resolver.c
  23. 2 2
      Utilities/cmlibarchive/libarchive/archive_entry_linkify.3
  24. 3 1
      Utilities/cmlibarchive/libarchive/archive_entry_paths.3
  25. 3 1
      Utilities/cmlibarchive/libarchive/archive_entry_perms.3
  26. 4 2
      Utilities/cmlibarchive/libarchive/archive_entry_stat.3
  27. 5 5
      Utilities/cmlibarchive/libarchive/archive_entry_stat.c
  28. 4 2
      Utilities/cmlibarchive/libarchive/archive_entry_time.3
  29. 1037 0
      Utilities/cmlibarchive/libarchive/archive_getdate.c
  30. 1841 0
      Utilities/cmlibarchive/libarchive/archive_match.c
  31. 50 3
      Utilities/cmlibarchive/libarchive/archive_options.c
  32. 459 0
      Utilities/cmlibarchive/libarchive/archive_pathmatch.c
  33. 52 0
      Utilities/cmlibarchive/libarchive/archive_pathmatch.h
  34. 3 4
      Utilities/cmlibarchive/libarchive/archive_ppmd7.c
  35. 2 2
      Utilities/cmlibarchive/libarchive/archive_ppmd_private.h
  36. 2 0
      Utilities/cmlibarchive/libarchive/archive_private.h
  37. 16 8
      Utilities/cmlibarchive/libarchive/archive_rb.c
  38. 4 2
      Utilities/cmlibarchive/libarchive/archive_read.3
  39. 360 62
      Utilities/cmlibarchive/libarchive/archive_read.c
  40. 198 0
      Utilities/cmlibarchive/libarchive/archive_read_append_filter.c
  41. 3 1
      Utilities/cmlibarchive/libarchive/archive_read_data.3
  42. 1 1
      Utilities/cmlibarchive/libarchive/archive_read_data_into_fd.c
  43. 4 2
      Utilities/cmlibarchive/libarchive/archive_read_disk.3
  44. 347 129
      Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c
  45. 434 146
      Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
  46. 22 1
      Utilities/cmlibarchive/libarchive/archive_read_disk_private.h
  47. 479 180
      Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
  48. 3 1
      Utilities/cmlibarchive/libarchive/archive_read_extract.3
  49. 1 1
      Utilities/cmlibarchive/libarchive/archive_read_extract.c
  50. 3 1
      Utilities/cmlibarchive/libarchive/archive_read_filter.3
  51. 4 2
      Utilities/cmlibarchive/libarchive/archive_read_format.3
  52. 4 2
      Utilities/cmlibarchive/libarchive/archive_read_free.3
  53. 3 1
      Utilities/cmlibarchive/libarchive/archive_read_header.3
  54. 4 2
      Utilities/cmlibarchive/libarchive/archive_read_new.3
  55. 4 2
      Utilities/cmlibarchive/libarchive/archive_read_open.3
  56. 4 3
      Utilities/cmlibarchive/libarchive/archive_read_open_fd.c
  57. 2 2
      Utilities/cmlibarchive/libarchive/archive_read_open_file.c
  58. 122 55
      Utilities/cmlibarchive/libarchive/archive_read_open_filename.c
  59. 1 0
      Utilities/cmlibarchive/libarchive/archive_read_open_memory.c
  60. 39 5
      Utilities/cmlibarchive/libarchive/archive_read_private.h
  61. 105 0
      Utilities/cmlibarchive/libarchive/archive_read_set_format.c
  62. 3 1
      Utilities/cmlibarchive/libarchive/archive_read_set_options.3
  63. 10 2
      Utilities/cmlibarchive/libarchive/archive_read_set_options.c
  64. 7 1
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c
  65. 5 4
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_bzip2.c
  66. 2 1
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c
  67. 121 0
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_grzip.c
  68. 11 10
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_gzip.c
  69. 132 0
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_lrzip.c
  70. 486 0
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
  71. 114 74
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c
  72. 3 2
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_rpm.c
  73. 21 7
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c
  74. 18 15
      Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c
  75. 151 109
      Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
  76. 1 0
      Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c
  77. 158 125
      Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
  78. 44 26
      Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c
  79. 1 0
      Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c
  80. 238 218
      Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
  81. 24 21
      Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c
  82. 179 51
      Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
  83. 376 92
      Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
  84. 2 1
      Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c
  85. 129 131
      Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
  86. 13 6
      Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
  87. 561 84
      Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
  88. 380 407
      Utilities/cmlibarchive/libarchive/archive_string.c
  89. 6 4
      Utilities/cmlibarchive/libarchive/archive_string.h
  90. 943 2
      Utilities/cmlibarchive/libarchive/archive_string_composition.h
  91. 10 4
      Utilities/cmlibarchive/libarchive/archive_string_sprintf.c
  92. 4 2
      Utilities/cmlibarchive/libarchive/archive_util.3
  93. 43 7
      Utilities/cmlibarchive/libarchive/archive_util.c
  94. 13 2
      Utilities/cmlibarchive/libarchive/archive_virtual.c
  95. 135 40
      Utilities/cmlibarchive/libarchive/archive_windows.c
  96. 21 8
      Utilities/cmlibarchive/libarchive/archive_windows.h
  97. 4 2
      Utilities/cmlibarchive/libarchive/archive_write.3
  98. 98 92
      Utilities/cmlibarchive/libarchive/archive_write.c
  99. 70 0
      Utilities/cmlibarchive/libarchive/archive_write_add_filter.c
  100. 314 0
      Utilities/cmlibarchive/libarchive/archive_write_add_filter_b64encode.c

+ 263 - 63
Utilities/cmlibarchive/CMakeLists.txt

@@ -1,8 +1,5 @@
-#
-#
 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)
@@ -39,13 +36,24 @@ 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(${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.
+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)$")
@@ -125,7 +133,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")
+        CHECK_C_SOURCE_COMPILES("${SAMPLE_SOURCE}" ${VAR})
+      ELSEIF("${TRY_TYPE}" MATCHES "RUNS")
+        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,13 +211,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)
-    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")
@@ -192,11 +245,21 @@ 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)
-
-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
 #
@@ -206,12 +269,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)
 ENDIF()
 
 #
@@ -261,6 +357,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)
@@ -311,14 +408,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)
 
 #
@@ -332,12 +432,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
@@ -345,13 +449,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)
@@ -364,7 +463,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
@@ -372,6 +471,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)
@@ -379,10 +480,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\"
@@ -392,10 +498,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;
 }
 ")
@@ -404,10 +510,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)
@@ -415,6 +527,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
@@ -433,6 +546,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)
 
@@ -448,6 +562,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 "")
@@ -467,9 +582,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>
 
@@ -484,15 +604,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")
@@ -504,6 +631,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)
@@ -517,6 +645,20 @@ ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
 #
 MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
   IF(NOT HAVE_ICONV)
+    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)
+    #
     CHECK_C_SOURCE_COMPILES(
       "#include <stdlib.h>
        #include <iconv.h>
@@ -532,10 +674,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)
   MARK_AS_ADVANCED(ICONV_INCLUDE_DIR)
   IF(ICONV_INCLUDE_DIR)
@@ -547,9 +691,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)
@@ -561,19 +726,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).
@@ -585,6 +767,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)
 
 IF(0) # CMake does not need XML support in libarchive
@@ -593,6 +779,7 @@ IF(0) # CMake does not need XML support in libarchive
 #
 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)
@@ -600,31 +787,45 @@ 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)
 ENDIF()
 
 #
 # 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)
@@ -632,6 +833,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)
@@ -663,7 +865,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)
@@ -673,6 +874,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)
@@ -697,7 +899,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)
@@ -714,10 +915,7 @@ 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.
@@ -1036,6 +1234,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

+ 4 - 4
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='[email protected]' \
- 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

+ 22 - 0
Utilities/cmlibarchive/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)

+ 23 - 0
Utilities/cmlibarchive/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)

+ 34 - 0
Utilities/cmlibarchive/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)

+ 45 - 6
Utilities/cmlibarchive/build/cmake/config.h.in

@@ -393,6 +393,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
 
@@ -579,12 +582,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
 
@@ -615,6 +633,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
 
@@ -664,12 +685,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
 
@@ -691,6 +715,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
 
@@ -700,6 +733,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
 
@@ -709,6 +745,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
 
@@ -742,6 +781,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
 
@@ -952,9 +994,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
 

+ 42 - 5
Utilities/cmlibarchive/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}

+ 1 - 1
Utilities/cmlibarchive/build/version

@@ -1 +1 @@
-3000002
+3001002

+ 22 - 1
Utilities/cmlibarchive/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
 )
 

+ 263 - 45
Utilities/cmlibarchive/libarchive/archive.h

@@ -63,13 +63,6 @@
 # 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__)
@@ -78,8 +71,6 @@
 #  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
 
 /*
@@ -113,6 +104,9 @@
 #define	__LA_PRINTF(fmtarg, firstvararg)	/* nothing */
 #endif
 
+/* CMake uses some deprecated APIs to build with old libarchive versions.  */
+#define __LA_DEPRECATED
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -134,13 +128,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. */
@@ -210,6 +204,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.
  */
@@ -223,6 +224,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
@@ -235,6 +239,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
 
 /*
@@ -307,37 +312,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 *);
@@ -359,6 +376,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 *);
@@ -370,8 +398,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 *);
 
@@ -391,11 +434,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);
@@ -427,6 +474,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
@@ -510,6 +560,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);
@@ -530,7 +586,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
 
 /*-
@@ -563,25 +619,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 *);
 
 
@@ -598,14 +670,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 *);
@@ -614,7 +690,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. */
@@ -636,12 +713,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
 
 /*
@@ -765,11 +846,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
@@ -789,13 +901,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 *);
@@ -809,14 +925,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 */

+ 48 - 34
Utilities/cmlibarchive/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);

+ 1 - 0
Utilities/cmlibarchive/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;
 	}
 }

+ 227 - 0
Utilities/cmlibarchive/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);
+}
+

+ 47 - 0
Utilities/cmlibarchive/libarchive/archive_cmdline_private.h

@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#ifndef __LIBARCHIVE_TEST
+#error This header is only to be used internally to libarchive.
+#endif
+#endif
+
+#ifndef ARCHIVE_CMDLINE_PRIVATE_H
+#define ARCHIVE_CMDLINE_PRIVATE_H
+
+struct archive_cmdline {
+        char            *path;
+        char            **argv;
+        int              argc;
+};
+
+struct archive_cmdline *__archive_cmdline_allocate(void);
+int __archive_cmdline_parse(struct archive_cmdline *, const char *);
+int __archive_cmdline_free(struct archive_cmdline *);
+
+#endif

+ 5 - 3
Utilities/cmlibarchive/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 =
 {

+ 4 - 4
Utilities/cmlibarchive/libarchive/archive_endian.h

@@ -160,8 +160,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
@@ -189,8 +189,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

+ 4 - 2
Utilities/cmlibarchive/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 *"

+ 71 - 10
Utilities/cmlibarchive/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

+ 20 - 25
Utilities/cmlibarchive/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) || defined(__osf__)
@@ -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,6 +137,10 @@ struct archive_entry;
  * 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)
@@ -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 *);

+ 4 - 2
Utilities/cmlibarchive/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

+ 3 - 3
Utilities/cmlibarchive/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;
 	}
 }

+ 4 - 1
Utilities/cmlibarchive/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. */

+ 2 - 2
Utilities/cmlibarchive/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 *

+ 3 - 1
Utilities/cmlibarchive/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 *

+ 3 - 1
Utilities/cmlibarchive/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

+ 4 - 2
Utilities/cmlibarchive/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 *

+ 5 - 5
Utilities/cmlibarchive/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;
 

+ 4 - 2
Utilities/cmlibarchive/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

+ 1037 - 0
Utilities/cmlibarchive/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 <[email protected]> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <[email protected]> and Jim Berets <[email protected]> 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) */

+ 1841 - 0
Utilities/cmlibarchive/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);
+}
+

+ 50 - 3
Utilities/cmlibarchive/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

+ 459 - 0
Utilities/cmlibarchive/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));
+}

+ 52 - 0
Utilities/cmlibarchive/libarchive/archive_pathmatch.h

@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    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
+#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. */
+
+int __archive_pathmatch(const char *p, const char *s, int flags);
+int __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags);
+
+#define archive_pathmatch(p, s, f)	__archive_pathmatch(p, s, f)
+#define archive_pathmatch_w(p, s, f)	__archive_pathmatch_w(p, s, f)
+
+#endif

+ 3 - 4
Utilities/cmlibarchive/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)

+ 2 - 2
Utilities/cmlibarchive/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

+ 2 - 0
Utilities/cmlibarchive/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 *);

+ 16 - 8
Utilities/cmlibarchive/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);
 		}

+ 4 - 2
Utilities/cmlibarchive/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

+ 360 - 62
Utilities/cmlibarchive/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)
@@ -305,22 +352,110 @@ archive_read_set_close_callback(struct archive *_a,
 	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");
@@ -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

+ 198 - 0
Utilities/cmlibarchive/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;
+}

+ 3 - 1
Utilities/cmlibarchive/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

+ 1 - 1
Utilities/cmlibarchive/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) {

+ 4 - 2
Utilities/cmlibarchive/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 *

+ 347 - 129
Utilities/cmlibarchive/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
@@ -104,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.
@@ -114,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,
@@ -190,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);
 		}
@@ -213,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");
@@ -232,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;
 
@@ -265,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);
@@ -284,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) {
@@ -299,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");
@@ -340,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);
 }
 
@@ -354,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 */
@@ -364,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)
@@ -381,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);
@@ -397,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);
 	}
@@ -406,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);
 		}
@@ -415,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 */
@@ -571,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;
@@ -581,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
@@ -614,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
@@ -640,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);
@@ -701,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);
@@ -714,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;
@@ -726,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
@@ -749,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
@@ -772,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;
 	}
 
@@ -787,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 */
@@ -816,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
@@ -831,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;
@@ -856,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. */
@@ -899,8 +1106,6 @@ setup_sparse(struct archive_read_disk *a,
 			break;
 	}
 exit_setup_sparse:
-	if (initial_fd != fd)
-		close(fd);
 	return (exit_sts);
 }
 
@@ -912,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;
@@ -926,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 */
@@ -961,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 */
 			}
@@ -980,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);
 }
 
@@ -994,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 */

+ 434 - 146
Utilities/cmlibarchive/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 directory 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)
@@ -1434,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");
@@ -1452,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)
@@ -1463,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)
@@ -1536,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");
@@ -1553,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));
@@ -1562,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, ".");
@@ -1622,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 */
@@ -1653,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__)
@@ -1704,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.
  */
@@ -1785,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;
@@ -1797,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;
@@ -1829,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);
 }
 
@@ -1863,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);
@@ -1914,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);
 }
@@ -1937,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);
 }
@@ -2045,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;
@@ -2075,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;
@@ -2118,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;
@@ -2138,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;
@@ -2159,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,
@@ -2193,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
@@ -2221,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);
@@ -2238,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);
 }
 

+ 22 - 1
Utilities/cmlibarchive/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

File diff suppressed because it is too large
+ 479 - 180
Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c


+ 3 - 1
Utilities/cmlibarchive/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

+ 1 - 1
Utilities/cmlibarchive/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) {

+ 3 - 1
Utilities/cmlibarchive/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

+ 4 - 2
Utilities/cmlibarchive/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

+ 4 - 2
Utilities/cmlibarchive/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

+ 3 - 1
Utilities/cmlibarchive/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

+ 4 - 2
Utilities/cmlibarchive/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 *

+ 4 - 2
Utilities/cmlibarchive/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

+ 4 - 3
Utilities/cmlibarchive/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)

+ 2 - 2
Utilities/cmlibarchive/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);

+ 122 - 55
Utilities/cmlibarchive/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,78 @@ int
 archive_read_open_filename(struct archive *a, const char *filename,
     size_t block_size)
 {
-	enum fnt_e filename_type;
+	const char *filenames[2];
+	filenames[0] = filename;
+	filenames[1] = NULL;
+	return archive_read_open_filenames(a, filenames, block_size);
+}
+
+int
+archive_read_open_filenames(struct archive *a, const char **filenames,
+    size_t block_size)
+{
+	struct read_file_data *mine;
+	const char *filename = NULL;
+	if (filenames)
+		filename = *(filenames++);
+
+	archive_clear_error(a);
+	do
+	{
+		if (filename == NULL)
+			filename = "";
+		mine = (struct read_file_data *)calloc(1,
+			sizeof(*mine) + strlen(filename));
+		if (mine == NULL)
+			goto no_memory;
+		strcpy(mine->filename.m, filename);
+		mine->block_size = block_size;
+		mine->fd = -1;
+		mine->buffer = NULL;
+		mine->st_mode = mine->use_lseek = 0;
+		if (filename == NULL || filename[0] == '\0') {
+			mine->filename_type = FNT_STDIN;
+		} else
+			mine->filename_type = FNT_MBS;
+		if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK))
+			return (ARCHIVE_FATAL);
+		if (filenames == NULL)
+			break;
+		filename = *(filenames++);
+	} while (filename != NULL && filename[0] != '\0');
+	archive_read_set_open_callback(a, file_open);
+	archive_read_set_read_callback(a, file_read);
+	archive_read_set_skip_callback(a, file_skip);
+	archive_read_set_close_callback(a, file_close);
+	archive_read_set_switch_callback(a, file_switch);
+	archive_read_set_seek_callback(a, file_seek);
 
-	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 +182,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 +233,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 +248,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 +259,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 +281,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 +346,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 +449,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 +500,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 +521,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 +554,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);
+}

+ 1 - 0
Utilities/cmlibarchive/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;

+ 39 - 5
Utilities/cmlibarchive/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

+ 105 - 0
Utilities/cmlibarchive/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;
+}

+ 3 - 1
Utilities/cmlibarchive/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

+ 10 - 2
Utilities/cmlibarchive/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);
 }
 

+ 7 - 1
Utilities/cmlibarchive/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

+ 5 - 4
Utilities/cmlibarchive/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);

+ 2 - 1
Utilities/cmlibarchive/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);

+ 121 - 0
Utilities/cmlibarchive/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);
+}

+ 11 - 10
Utilities/cmlibarchive/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);

+ 132 - 0
Utilities/cmlibarchive/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);
+}

+ 486 - 0
Utilities/cmlibarchive/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 <cm_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

+ 114 - 74
Utilities/cmlibarchive/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) */

+ 3 - 2
Utilities/cmlibarchive/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;

+ 21 - 7
Utilities/cmlibarchive/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;

+ 18 - 15
Utilities/cmlibarchive/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);
 }

+ 151 - 109
Utilities/cmlibarchive/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;

+ 1 - 0
Utilities/cmlibarchive/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) {

+ 158 - 125
Utilities/cmlibarchive/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;

+ 44 - 26
Utilities/cmlibarchive/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 =

+ 1 - 0
Utilities/cmlibarchive/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);

+ 238 - 218
Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c

@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
  * Copyright (c) 2009 Andreas Henriksson <[email protected]>
- * 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) {
@@ -587,6 +590,23 @@ archive_read_format_iso9660_options(struct archive_read *a,
 	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)
 {
@@ -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 +
+		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;
@@ -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

+ 24 - 21
Utilities/cmlibarchive/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);
 }

+ 179 - 51
Utilities/cmlibarchive/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
@@ -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);

+ 376 - 92
Utilities/cmlibarchive/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;
+}

+ 2 - 1
Utilities/cmlibarchive/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);
 	}
 }
 

+ 129 - 131
Utilities/cmlibarchive/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;

+ 13 - 6
Utilities/cmlibarchive/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);
 		}

File diff suppressed because it is too large
+ 561 - 84
Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c


File diff suppressed because it is too large
+ 380 - 407
Utilities/cmlibarchive/libarchive/archive_string.c


+ 6 - 4
Utilities/cmlibarchive/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) \

+ 943 - 2
Utilities/cmlibarchive/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 */
+

+ 10 - 4
Utilities/cmlibarchive/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. */

+ 4 - 2
Utilities/cmlibarchive/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

+ 43 - 7
Utilities/cmlibarchive/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
+}

+ 13 - 2
Utilities/cmlibarchive/libarchive/archive_virtual.c

@@ -66,9 +66,18 @@ archive_read_close(struct archive *a)
 	return ((a->vtable->archive_close)(a));
 }
 
+int
+archive_write_fail(struct archive *a)
+{
+	a->state = ARCHIVE_STATE_FATAL;
+	return a->state;
+}
+
 int
 archive_write_free(struct archive *a)
 {
+	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
 

+ 135 - 40
Utilities/cmlibarchive/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>
@@ -109,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)));
 }
 
 /*
@@ -153,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;
@@ -424,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;
 
@@ -432,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;
 	}
 }
@@ -458,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)) {
@@ -515,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))
@@ -558,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;
@@ -632,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
@@ -690,6 +678,113 @@ __la_write(int fd, const void *buf, size_t nbytes)
 	return (bytes_written);
 }
 
+/*
+ * Replace the Windows path separator '\' with '/'.
+ */
+static int
+replace_pathseparator(struct archive_wstring *ws, const wchar_t *wp)
+{
+	wchar_t *w;
+	size_t path_length;
+
+	if (wp == NULL)
+		return(0);
+	if (wcschr(wp, L'\\') == NULL)
+		return(0);
+	path_length = wcslen(wp);
+	if (archive_wstring_ensure(ws, path_length) == NULL)
+		return(-1);
+	archive_wstrncpy(ws, wp, path_length);
+	for (w = ws->s; *w; w++) {
+		if (*w == L'\\')
+			*w = L'/';
+	}
+	return(1);
+}
+
+static int
+fix_pathseparator(struct archive_entry *entry)
+{
+	struct archive_wstring ws;
+	const wchar_t *wp;
+	int ret = ARCHIVE_OK;
+
+	archive_string_init(&ws);
+	wp = archive_entry_pathname_w(entry);
+	switch (replace_pathseparator(&ws, wp)) {
+	case 0: /* Not replaced. */
+		break;
+	case 1: /* Replaced. */
+		archive_entry_copy_pathname_w(entry, ws.s);
+		break;
+	default:
+		ret = ARCHIVE_FAILED;
+	}
+	wp = archive_entry_hardlink_w(entry);
+	switch (replace_pathseparator(&ws, wp)) {
+	case 0: /* Not replaced. */
+		break;
+	case 1: /* Replaced. */
+		archive_entry_copy_hardlink_w(entry, ws.s);
+		break;
+	default:
+		ret = ARCHIVE_FAILED;
+	}
+	wp = archive_entry_symlink_w(entry);
+	switch (replace_pathseparator(&ws, wp)) {
+	case 0: /* Not replaced. */
+		break;
+	case 1: /* Replaced. */
+		archive_entry_copy_symlink_w(entry, ws.s);
+		break;
+	default:
+		ret = ARCHIVE_FAILED;
+	}
+	archive_wstring_free(&ws);
+	return(ret);
+}
+
+struct archive_entry *
+__la_win_entry_in_posix_pathseparator(struct archive_entry *entry)
+{
+	struct archive_entry *entry_main;
+	const wchar_t *wp;
+	int has_backslash = 0;
+	int ret;
+
+	wp = archive_entry_pathname_w(entry);
+	if (wp != NULL && wcschr(wp, L'\\') != NULL)
+		has_backslash = 1;
+	if (!has_backslash) {
+		wp = archive_entry_hardlink_w(entry);
+		if (wp != NULL && wcschr(wp, L'\\') != NULL)
+			has_backslash = 1;
+	}
+	if (!has_backslash) {
+		wp = archive_entry_symlink_w(entry);
+		if (wp != NULL && wcschr(wp, L'\\') != NULL)
+			has_backslash = 1;
+	}
+	/*
+	 * If there is no 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.
@@ -796,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)
 		{

+ 21 - 8
Utilities/cmlibarchive/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)
@@ -72,7 +75,6 @@
 //#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
@@ -95,8 +97,14 @@
 #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
@@ -108,6 +116,9 @@
 #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
@@ -257,7 +268,7 @@ extern __int64	 __la_lseek(int fd, __int64 offset, int whence);
 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)
@@ -270,6 +281,8 @@ 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;
@@ -278,14 +291,14 @@ size_t wcrtomb(char *, wchar_t, mbstate_t *);
 
 #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)

+ 4 - 2
Utilities/cmlibarchive/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

+ 98 - 92
Utilities/cmlibarchive/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");

+ 70 - 0
Utilities/cmlibarchive/libarchive/archive_write_add_filter.c

@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2012 Ondrej Holy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+
+/* A table that maps filter codes to functions. */
+static
+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 }
+};
+
+int
+archive_write_add_filter(struct archive *a, int code)
+{
+	int i;
+
+	for (i = 0; codes[i].code != -1; i++) {
+		if (code == codes[i].code)
+			return ((codes[i].setter)(a));
+	}
+
+	archive_set_error(a, EINVAL, "No such filter");
+	return (ARCHIVE_FATAL);
+}

+ 314 - 0
Utilities/cmlibarchive/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);
+}
+

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